All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.deps.ClosureBundler Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20240317
Show newest version
/*
 * Copyright 2014 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.javascript.jscomp.deps;

import com.google.common.io.CharSource;
import com.google.common.io.Files;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;


/**
 * A utility class to assist in creating JS bundle files.
 */
public class ClosureBundler {
  private boolean useEval = false;
  private String sourceUrl = null;
  private String path = "unknown_source";

  public ClosureBundler() {
  }

  public final ClosureBundler useEval(boolean useEval) {
    this.useEval = useEval;
    return this;
  }

  public final ClosureBundler withSourceUrl(String sourceUrl) {
    this.sourceUrl = sourceUrl;
    return this;
  }

  public final ClosureBundler withPath(String path) {
    this.path = path;
    return this;
  }

  /** Append the contents of the string to the supplied appendable. */
  public static void appendInput(
      Appendable out,
      DependencyInfo info,
      String contents) throws IOException {
    new ClosureBundler().appendTo(out, info, contents);
  }

  /** Append the contents of the string to the supplied appendable. */
  public void appendTo(
      Appendable out,
      DependencyInfo info,
      String content) throws IOException {
    appendTo(out, info, CharSource.wrap(content));
  }

  /** Append the contents of the file to the supplied appendable. */
  public void appendTo(
      Appendable out,
      DependencyInfo info,
      File content, Charset contentCharset) throws IOException {
    appendTo(out, info, Files.asCharSource(content, contentCharset));
  }

  /** Append the contents of the CharSource to the supplied appendable. */
  public void appendTo(
      Appendable out,
      DependencyInfo info,
      CharSource content) throws IOException {
    if (info.isModule()) {
      appendGoogModule(out, content);
    } else {
      appendTraditional(out, content);
    }
  }

  private void appendTraditional(Appendable out, CharSource contents)
      throws IOException {
    if (useEval) {
      out.append("(0,eval(\"");
      append(out, Mode.ESCAPED, contents);
      appendSourceUrl(out, Mode.ESCAPED);
      out.append("\"));");
    } else {
      append(out, Mode.NORMAL, contents);
      appendSourceUrl(out, Mode.NORMAL);
    }
  }

  private void appendGoogModule(Appendable out, CharSource contents)
      throws IOException {
    if (useEval) {
      out.append("goog.loadModule(\"");
      append(out, Mode.ESCAPED, contents);
      appendSourceUrl(out, Mode.ESCAPED);
      out.append("\");");
    } else {
      // add the prefix on the first line so the line numbers aren't affected.
      out.append(
          "goog.loadModule(function(exports) {"
          + "'use strict';");
      append(out, Mode.NORMAL, contents);
      out.append(
          "\n" // terminate any trailing single line comment.
          + ";" // terminate any trailing expression.
          + "return exports;});\n");
      appendSourceUrl(out, Mode.NORMAL);
    }
  }

  private enum Mode {
    ESCAPED {
      @Override void append(String s, Appendable out) throws IOException {
        out.append(SourceCodeEscapers.javascriptEscaper().escape(s));
      }
    },
    NORMAL {
      @Override void append(String s, Appendable out) throws IOException {
        out.append(s);
      }
    };

    abstract void append(String s, Appendable out) throws IOException;
  }

  private void append(Appendable out, Mode mode, String s) throws IOException {
    String transformed = transformInput(s, path);
    mode.append(transformed, out);
  }

  private void append(Appendable out, Mode mode, CharSource cs)
      throws IOException {
    append(out, mode, cs.read());
  }

  private void appendSourceUrl(Appendable out, Mode mode) throws IOException {
    if (sourceUrl == null) {
      return;
    }
    String toAppend = "\n//# sourceURL=" + sourceUrl + "\n";
    // Don't go through #append. That method relies on #transformInput,
    // but source URLs generally aren't valid JS inputs.
    mode.append(toAppend, out);
  }

  /**
   * Template method. Subclasses that need to transform the inputs should override this method.
   */
  protected String transformInput(String input, String path) {
    return input;
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy