diff --git a/src/com/google/javascript/jscomp/AbstractCommandLineRunner.java b/src/com/google/javascript/jscomp/AbstractCommandLineRunner.java index 3354e8569ac..701dda154e7 100644 --- a/src/com/google/javascript/jscomp/AbstractCommandLineRunner.java +++ b/src/com/google/javascript/jscomp/AbstractCommandLineRunner.java @@ -111,7 +111,6 @@ * * @author bolinfest@google.com (Michael Bolin) */ -@GwtIncompatible("Unnecessary") public abstract class AbstractCommandLineRunner { @@ -145,13 +144,22 @@ public abstract class AbstractCommandLineRunner> externsSupplierForTesting = null; + + @GwtIncompatible("Unnecessary") private Supplier> inputsSupplierForTesting = null; + + @GwtIncompatible("Unnecessary") private Supplier> modulesSupplierForTesting = null; + + @GwtIncompatible("Unnecessary") private Function exitCodeReceiver = SystemExitCodeReceiver.INSTANCE; + + @GwtIncompatible("Unnecessary") private Map rootRelativePathsMap = null; + @GwtIncompatible("Unnecessary") private Map parsedModuleWrappers = null; + @GwtIncompatible("Unnecessary") private final Gson gson; static final String OUTPUT_MARKER = "%output%"; private static final String OUTPUT_MARKER_JS_STRING = "%output|jsstring%"; + @GwtIncompatible("Unnecessary") private final List filesToStreamOut = new ArrayList<>(); + @GwtIncompatible("Unnecessary") AbstractCommandLineRunner() { this(System.in, System.out, System.err); } + @GwtIncompatible("Unnecessary") AbstractCommandLineRunner(PrintStream out, PrintStream err) { this(System.in, out, err); } + @GwtIncompatible("Unnecessary") AbstractCommandLineRunner(InputStream in, PrintStream out, PrintStream err) { this.config = new CommandLineConfig(); this.in = checkNotNull(in); @@ -197,16 +225,17 @@ public abstract class AbstractCommandLineRunner> externsSupplier, Supplier> inputsSupplier, @@ -221,52 +250,47 @@ void enableTestMode( } /** - * @param newExitCodeReceiver receives a non-zero integer to indicate a - * problem during execution or 0i to indicate success. + * @param newExitCodeReceiver receives a non-zero integer to indicate a problem during execution + * or 0i to indicate success. */ + @GwtIncompatible("Unnecessary") public void setExitCodeReceiver(Function newExitCodeReceiver) { this.exitCodeReceiver = checkNotNull(newExitCodeReceiver); } - /** - * Returns whether we're in test mode. - */ + /** Returns whether we're in test mode. */ + @GwtIncompatible("Unnecessary") protected boolean isInTestMode() { return testMode; } - /** - * Returns whether output should be a JSON stream. - */ + /** Returns whether output should be a JSON stream. */ + @GwtIncompatible("Unnecessary") private boolean isOutputInJson() { return config.jsonStreamMode == JsonStreamMode.OUT || config.jsonStreamMode == JsonStreamMode.BOTH; } - - /** - * Get the command line config, so that it can be initialized. - */ + /** Get the command line config, so that it can be initialized. */ + @GwtIncompatible("Unnecessary") protected CommandLineConfig getCommandLineConfig() { return config; } - /** - * Returns the instance of the Compiler to use when {@link #run()} is - * called. - */ + /** Returns the instance of the Compiler to use when {@link #run()} is called. */ + @GwtIncompatible("Unnecessary") protected abstract A createCompiler(); /** * Performs any transformation needed on the given compiler input and appends it to the given * output bundle. */ + @GwtIncompatible("Unnecessary") protected abstract void prepForBundleAndAppendTo( Appendable out, CompilerInput input, String content) throws IOException; - /** - * Writes whatever runtime libraries are needed to bundle. - */ + /** Writes whatever runtime libraries are needed to bundle. */ + @GwtIncompatible("Unnecessary") protected abstract void appendRuntimeTo(Appendable out) throws IOException; /** @@ -274,11 +298,11 @@ protected abstract void prepForBundleAndAppendTo( * called before createOptions(), so getCompiler() will not return null when createOptions() is * called. */ + @GwtIncompatible("Unnecessary") protected abstract B createOptions(); - /** - * The warning classes that are available from the command-line. - */ + /** The warning classes that are available from the command-line. */ + @GwtIncompatible("Unnecessary") protected DiagnosticGroups getDiagnosticGroups() { if (compiler == null) { return new DiagnosticGroups(); @@ -286,12 +310,9 @@ protected DiagnosticGroups getDiagnosticGroups() { return compiler.getDiagnosticGroups(); } - /** - * A helper function for creating the dependency options object. - */ - static DependencyOptions createDependencyOptions( - CompilerOptions.DependencyMode dependencyMode, - List entryPoints) { + /** A helper function for creating the dependency options object. */ + public static DependencyOptions createDependencyOptions( + CompilerOptions.DependencyMode dependencyMode, List entryPoints) { if (dependencyMode == CompilerOptions.DependencyMode.STRICT) { if (entryPoints.isEmpty()) { throw new FlagUsageException( @@ -313,9 +334,10 @@ static DependencyOptions createDependencyOptions( return null; } - protected abstract void addWhitelistWarningsGuard( - CompilerOptions options, File whitelistFile); + @GwtIncompatible("Unnecessary") + protected abstract void addWhitelistWarningsGuard(CompilerOptions options, File whitelistFile); + @GwtIncompatible("Unnecessary") protected static void setWarningGuardOptions( CompilerOptions options, ArrayList> warningGuards, @@ -337,11 +359,11 @@ protected static void setWarningGuardOptions( } /** - * Sets options based on the configurations set flags API. - * Called during the run() run() method. - * If you want to ignore the flags API, or interpret flags your own way, - * then you should override this method. + * Sets options based on the configurations set flags API. Called during the run() run() method. + * If you want to ignore the flags API, or interpret flags your own way, then you should override + * this method. */ + @GwtIncompatible("Unnecessary") protected void setRunOptions(CompilerOptions options) throws IOException { DiagnosticGroups diagnosticGroups = getDiagnosticGroups(); @@ -458,6 +480,7 @@ protected void setRunOptions(CompilerOptions options) throws IOException { } } + @GwtIncompatible("Unnecessary") protected final A getCompiler() { return compiler; } @@ -466,6 +489,7 @@ protected final A getCompiler() { * @return a mutable list * @throws IOException */ + @GwtIncompatible("Unnecessary") public static List getBuiltinExterns(CompilerOptions.Environment env) throws IOException { InputStream input = AbstractCommandLineRunner.class.getResourceAsStream( @@ -506,10 +530,8 @@ public static List getBuiltinExterns(CompilerOptions.Environment env return DefaultExterns.prepareExterns(env, mapFromExternsZip); } - /** - * Runs the Compiler and calls System.exit() with the exit status of the - * compiler. - */ + /** Runs the Compiler and calls System.exit() with the exit status of the compiler. */ + @GwtIncompatible("Unnecessary") public final void run() { int result; try { @@ -525,10 +547,8 @@ public final void run() { exitCodeReceiver.apply(result); } - /** - * Returns the PrintStream for writing errors associated with this - * AbstractCommandLineRunner. - */ + /** Returns the PrintStream for writing errors associated with this AbstractCommandLineRunner. */ + @GwtIncompatible("Unnecessary") protected final PrintStream getErrorPrintStream() { return err; } @@ -544,6 +564,7 @@ public FlagUsageException(String message) { } } + @GwtIncompatible("Unnecessary") public List parseJsonFilesFromInputStream() throws IOException { List jsonFiles = new ArrayList<>(); try (JsonReader reader = new JsonReader(new InputStreamReader(this.in, inputCharset))) { @@ -560,15 +581,15 @@ public List parseJsonFilesFromInputStream() throws IOException { /** * Creates inputs from a list of files. * - * Can be overridden by subclasses who want to pull files from different - * places. + *

Can be overridden by subclasses who want to pull files from different places. * * @param files A list of flag entries indicates js and zip file names. - * @param allowStdIn Whether '-' is allowed appear as a filename to represent - * stdin. If true, '-' is only allowed to appear once. + * @param allowStdIn Whether '-' is allowed appear as a filename to represent stdin. If true, '-' + * is only allowed to appear once. * @param jsModuleSpecs A list js module specs. * @return An array of inputs */ + @GwtIncompatible("Unnecessary") protected List createInputs( List> files, boolean allowStdIn, List jsModuleSpecs) throws IOException { @@ -578,14 +599,14 @@ protected List createInputs( /** * Creates inputs from a list of source files and json files. * - * Can be overridden by subclasses who want to pull files from different - * places. + *

Can be overridden by subclasses who want to pull files from different places. * * @param files A list of flag entries indicates js and zip file names. * @param jsonFiles A list of json encoded files. * @param jsModuleSpecs A list js module specs. * @return An array of inputs */ + @GwtIncompatible("Unnecessary") protected List createInputs( List> files, List jsonFiles, @@ -606,6 +627,7 @@ protected List createInputs( * @param jsModuleSpecs A list js module specs. * @return An array of inputs */ + @GwtIncompatible("Unnecessary") protected List createInputs( List> files, List jsonFiles, @@ -617,7 +639,7 @@ protected List createInputs( int jsModuleIndex = 0; JsModuleSpec jsModuleSpec = Iterables.getFirst(jsModuleSpecs, null); int cumulatedInputFilesExpected = - jsModuleSpec == null ? Integer.MAX_VALUE : jsModuleSpec.numInputs; + jsModuleSpec == null ? Integer.MAX_VALUE : jsModuleSpec.getNumInputs(); for (int i = 0; i < files.size(); i++) { FlagEntry file = files.get(i); String filename = file.value; @@ -668,7 +690,7 @@ protected List createInputs( jsModuleIndex++; if (jsModuleIndex < jsModuleSpecs.size()) { jsModuleSpec = jsModuleSpecs.get(jsModuleIndex); - cumulatedInputFilesExpected += jsModuleSpec.numInputs; + cumulatedInputFilesExpected += jsModuleSpec.getNumInputs(); } } } @@ -688,6 +710,7 @@ protected List createInputs( * inside different zips are considered duplicate inputs. Parameter {@code sourceFiles} may be * modified if duplicates are removed. */ + @GwtIncompatible("Unnecessary") public static ImmutableList removeDuplicateZipEntries( List sourceFiles, List jsModuleSpecs) throws IOException { ImmutableList.Builder errors = ImmutableList.builder(); @@ -733,9 +756,8 @@ public static ImmutableList removeDuplicateZipEntries( return errors.build(); } - /** - * Creates JS source code inputs from a list of files. - */ + /** Creates JS source code inputs from a list of files. */ + @GwtIncompatible("Unnecessary") private List createSourceInputs( List jsModuleSpecs, List> files, @@ -761,9 +783,8 @@ private List createSourceInputs( } } - /** - * Creates JS extern inputs from a list of files. - */ + /** Creates JS extern inputs from a list of files. */ + @GwtIncompatible("Unnecessary") private List createExternInputs(List files) throws IOException { if (files.isEmpty()) { return ImmutableList.of(SourceFile.fromCode("/dev/null", "")); @@ -786,12 +807,8 @@ private List createExternInputs(List files) throws IOExcepti * @param inputs A list of JS file paths, not null * @return An array of module objects */ - List createJsModules(List specs, List inputs) + public static List createJsModules(List specs, List inputs) throws IOException { - if (isInTestMode()) { - return modulesSupplierForTesting.get(); - } - checkState(specs != null); checkState(!specs.isEmpty()); checkState(inputs != null); @@ -802,7 +819,6 @@ List createJsModules(List specs, List inputs int numJsFilesExpected = 0; int minJsFilesRequired = 0; for (JsModuleSpec spec : specs) { - checkModuleName(spec.name); if (modulesByName.containsKey(spec.name)) { throw new FlagUsageException("Duplicate module name: " + spec.name); } @@ -811,9 +827,12 @@ List createJsModules(List specs, List inputs for (String dep : spec.deps) { JSModule other = modulesByName.get(dep); if (other == null) { - throw new FlagUsageException("Module '" + spec.name - + "' depends on unknown module '" + dep - + "'. Be sure to list modules in dependency order."); + throw new FlagUsageException( + "Module '" + + spec.name + + "' depends on unknown module '" + + dep + + "'. Be sure to list modules in dependency order."); } module.addDependency(other); } @@ -825,7 +844,6 @@ List createJsModules(List specs, List inputs minJsFilesRequired += spec.numJsFiles; } - if (numJsFilesExpected >= 0) { numJsFilesExpected += spec.numJsFiles; } @@ -846,11 +864,17 @@ List createJsModules(List specs, List inputs } if (numJsFilesExpected > totalNumJsFiles) { - throw new FlagUsageException("Not enough JS files specified. Expected " - + numJsFilesExpected + " but found " + totalNumJsFiles); + throw new FlagUsageException( + "Not enough JS files specified. Expected " + + numJsFilesExpected + + " but found " + + totalNumJsFiles); } else if (numJsFilesExpected < totalNumJsFiles) { - throw new FlagUsageException("Too many JS files specified. Expected " - + numJsFilesExpected + " but found " + totalNumJsFiles); + throw new FlagUsageException( + "Too many JS files specified. Expected " + + numJsFilesExpected + + " but found " + + totalNumJsFiles); } } @@ -866,8 +890,7 @@ List createJsModules(List specs, List inputs numJsFiles = numJsFilesLeft; } - List moduleFiles = - inputs.subList(numJsFilesLeft - numJsFiles, numJsFilesLeft); + List moduleFiles = inputs.subList(numJsFilesLeft - numJsFiles, numJsFilesLeft); for (SourceFile input : moduleFiles) { module.add(input); } @@ -880,8 +903,10 @@ List createJsModules(List specs, List inputs /** * Validates the module name. Can be overridden by subclasses. + * * @param name The module name */ + @GwtIncompatible("Unnecessary") protected void checkModuleName(String name) { if (!TokenStream.isJSIdentifier(name)) { throw new FlagUsageException("Invalid module name: '" + name + "'"); @@ -891,29 +916,28 @@ protected void checkModuleName(String name) { /** * Parses module wrapper specifications. * - * @param specs A list of module wrapper specifications, not null. The spec - * format is: name:wrapper. Wrappers. - * @param modules The JS modules whose wrappers are specified - * @return A map from module name to module wrapper. Modules with no wrapper - * will have the empty string as their value in this map. + * @param specs A list of module wrapper specifications, not null. The spec format is: + * name:wrapper. Wrappers. + * @param chunks The JS chunks whose wrappers are specified + * @return A map from module name to module wrapper. Modules with no wrapper will have the empty + * string as their value in this map. */ - static Map parseModuleWrappers(List specs, List modules) { + public static Map parseModuleWrappers(List specs, List chunks) { checkState(specs != null); - Map wrappers = Maps.newHashMapWithExpectedSize(modules.size()); + Map wrappers = Maps.newHashMapWithExpectedSize(chunks.size()); // Prepopulate the map with module names. - for (JSModule m : modules) { - wrappers.put(m.getName(), ""); + for (JSModule c : chunks) { + wrappers.put(c.getName(), ""); } for (String spec : specs) { - // Format is ":". int pos = spec.indexOf(':'); if (pos == -1) { - throw new FlagUsageException("Expected module wrapper to have " - + ": format: " + spec); + throw new FlagUsageException( + "Expected module wrapper to have " + ": format: " + spec); } // Parse module name. @@ -925,8 +949,7 @@ static Map parseModuleWrappers(List specs, List parseModuleWrappers(List specs, List escaper) throws IOException { if (compiler.getOptions().outputJs == OutputJs.SENTINEL) { @@ -974,11 +1005,16 @@ void writeOutput(Appendable out, Compiler compiler, @Nullable JSModule module, } /** - * Writes code to an output stream, optionally wrapping it in an arbitrary - * wrapper that contains a placeholder where the code should be inserted. + * Writes code to an output stream, optionally wrapping it in an arbitrary wrapper that contains a + * placeholder where the code should be inserted. */ - void writeOutput(Appendable out, Compiler compiler, String code, - String wrapper, String codePlaceholder, + @GwtIncompatible("Unnecessary") + void writeOutput( + Appendable out, + Compiler compiler, + String code, + String wrapper, + String codePlaceholder, @Nullable Function escaper) throws IOException { int pos = wrapper.indexOf(codePlaceholder); @@ -1012,10 +1048,8 @@ void writeOutput(Appendable out, Compiler compiler, String code, } } - /** - * Creates any directories necessary to write a file that will have a given - * path prefix. - */ + /** Creates any directories necessary to write a file that will have a given path prefix. */ + @GwtIncompatible("Unnecessary") private static void maybeCreateDirsForPath(String pathPrefix) { if (!Strings.isNullOrEmpty(pathPrefix)) { String dirName = @@ -1028,6 +1062,7 @@ private static void maybeCreateDirsForPath(String pathPrefix) { } } + @GwtIncompatible("Unnecessary") private Appendable createDefaultOutput() throws IOException { boolean writeOutputToFile = !config.jsOutputFile.isEmpty(); if (writeOutputToFile) { @@ -1037,6 +1072,7 @@ private Appendable createDefaultOutput() throws IOException { } } + @GwtIncompatible("Unnecessary") private static void closeAppendable(Appendable output) throws IOException { if (output instanceof Flushable) { ((Flushable) output).flush(); @@ -1051,6 +1087,7 @@ private static void closeAppendable(Appendable output) throws IOException { * * @return system exit status */ + @GwtIncompatible("Unnecessary") protected int doRun() throws IOException { Compiler.setLoggingLevel(Level.parse(config.loggingLevel)); @@ -1122,7 +1159,14 @@ protected int doRun() throws IOException { List inputs = createSourceInputs(jsModuleSpecs, config.mixedJsSources, jsonFiles); if (!jsModuleSpecs.isEmpty()) { - modules = createJsModules(jsModuleSpecs, inputs); + if (isInTestMode()) { + modules = modulesSupplierForTesting.get(); + } else { + for (JsModuleSpec m : jsModuleSpecs) { + checkModuleName(m.getName()); + } + modules = createJsModules(jsModuleSpecs, inputs); + } for (JSModule m : modules) { outputFileNames.add(getModuleOutputFileName(m)); } @@ -1179,6 +1223,7 @@ protected int doRun() throws IOException { return processResults(result, modules, options); } + @GwtIncompatible("Unnecessary") private Result performStage1andSave(String filename) { Result result; try (BufferedOutputStream serializedOutputStream = @@ -1202,6 +1247,7 @@ private Result performStage1andSave(String filename) { return result; } + @GwtIncompatible("Unnecessary") private Result restoreAndPerformStage2(String filename) { Result result; try (BufferedInputStream serializedInputStream = @@ -1222,6 +1268,7 @@ private Result restoreAndPerformStage2(String filename) { return result; } + @GwtIncompatible("Unnecessary") private Result performFullCompilation() { Result result; try { @@ -1242,6 +1289,7 @@ private Result performFullCompilation() { return result; } + @GwtIncompatible("Unnecessary") private Result instrumentForCoverage() { Result result; try { @@ -1256,9 +1304,8 @@ private Result instrumentForCoverage() { return result; } - /** - * Processes the results of the compile job, and returns an error code. - */ + /** Processes the results of the compile job, and returns an error code. */ + @GwtIncompatible("Unnecessary") int processResults(Result result, List modules, B options) throws IOException { if (config.printPassGraph) { if (compiler.getRoot() == null) { @@ -1351,10 +1398,12 @@ int processResults(Result result, List modules, B options) throws IOEx return Math.min(result.errors.length, 0x7f); } + @GwtIncompatible("Unnecessary") Function getJavascriptEscaper() { return SourceCodeEscapers.javascriptEscaper().asFunction(); } + @GwtIncompatible("Unnecessary") void outputSingleBinary(B options) throws IOException { Function escaper = null; String marker = OUTPUT_MARKER; @@ -1378,12 +1427,10 @@ void outputSingleBinary(B options) throws IOException { } } - /** - * Save the compiler output to a JsonFileSpec to be later written to - * stdout - */ - JsonFileSpec createJsonFile(B options, String outputMarker, - Function escaper) throws IOException { + /** Save the compiler output to a JsonFileSpec to be later written to stdout */ + @GwtIncompatible("Unnecessary") + JsonFileSpec createJsonFile(B options, String outputMarker, Function escaper) + throws IOException { Appendable jsOutput = new StringBuilder(); writeOutput( jsOutput, compiler, (JSModule) null, config.outputWrapper, @@ -1402,6 +1449,7 @@ JsonFileSpec createJsonFile(B options, String outputMarker, return jsonOutput; } + @GwtIncompatible("Unnecessary") void outputJsonStream() throws IOException { try (JsonWriter jsonWriter = new JsonWriter(new BufferedWriter(new OutputStreamWriter(defaultJsOutput, "UTF-8")))) { @@ -1419,6 +1467,7 @@ void outputJsonStream() throws IOException { } } + @GwtIncompatible("Unnecessary") private DiagnosticType outputModuleBinaryAndSourceMaps(List modules, B options) throws IOException { parsedModuleWrappers = parseModuleWrappers( @@ -1473,6 +1522,7 @@ private DiagnosticType outputModuleBinaryAndSourceMaps(List modules, B } /** Given an output module, convert it to a JSONFileSpec with associated sourcemap */ + @GwtIncompatible("Unnecessary") private JsonFileSpec createJsonFileFromModule(JSModule module) throws IOException { compiler.getSourceMap().reset(); @@ -1493,12 +1543,12 @@ private JsonFileSpec createJsonFileFromModule(JSModule module) throws IOExceptio } /** - * Query the flag for the input charset, and return a Charset object - * representing the selection. + * Query the flag for the input charset, and return a Charset object representing the selection. * * @return Charset to use when reading inputs * @throws FlagUsageException if flag is not a valid Charset name. */ + @GwtIncompatible("Unnecessary") private Charset getInputCharset() { if (!config.charset.isEmpty()) { if (!Charset.isSupported(config.charset)) { @@ -1513,15 +1563,14 @@ private Charset getInputCharset() { /** * Query the flag for the output charset. * - * Let the outputCharset be the same as the input charset... except if - * we're reading in UTF-8 by default. By tradition, we've always - * output ASCII to avoid various hiccups with different browsers, - * proxies and firewalls. + *

Let the outputCharset be the same as the input charset... except if we're reading in UTF-8 + * by default. By tradition, we've always output ASCII to avoid various hiccups with different + * browsers, proxies and firewalls. * - * @return Name of the charset to use when writing outputs. Guaranteed to - * be a supported charset. + * @return Name of the charset to use when writing outputs. Guaranteed to be a supported charset. * @throws FlagUsageException if flag is not a valid Charset name. */ + @GwtIncompatible("Unnecessary") private Charset getLegacyOutputCharset() { if (!config.charset.isEmpty()) { if (!Charset.isSupported(config.charset)) { @@ -1534,8 +1583,10 @@ private Charset getLegacyOutputCharset() { /** * Query the flag for the output charset. Defaults to UTF-8. + * * @throws FlagUsageException if flag is not a valid Charset name. */ + @GwtIncompatible("Unnecessary") private Charset getOutputCharset2() { if (!config.charset.isEmpty()) { if (!Charset.isSupported(config.charset)) { @@ -1547,15 +1598,17 @@ private Charset getOutputCharset2() { return UTF_8; } + @GwtIncompatible("Unnecessary") protected List createExterns(CompilerOptions options) throws IOException { return isInTestMode() ? externsSupplierForTesting.get() : createExternInputs(config.externs); } /** - * Returns true if and only if a source map file should be generated for each - * module, as opposed to one unified map. This is specified by having the - * source map pattern include the %outname% variable. + * Returns true if and only if a source map file should be generated for each module, as opposed + * to one unified map. This is specified by having the source map pattern include the %outname% + * variable. */ + @GwtIncompatible("Unnecessary") private boolean shouldGenerateMapPerModule(B options) { return options.sourceMapOutputPath != null && options.sourceMapOutputPath.contains("%outname%"); @@ -1566,11 +1619,10 @@ private boolean shouldGenerateMapPerModule(B options) { * * @param options The options to the Compiler. * @param path The path of the generated JS source file. - * * @return The stream or null if no extern-ed exports are being generated. */ - private Writer openExternExportsStream(B options, - String path) throws IOException { + @GwtIncompatible("Unnecessary") + private Writer openExternExportsStream(B options, String path) throws IOException { if (options.externExportsPath == null) { return null; } @@ -1588,20 +1640,18 @@ private Writer openExternExportsStream(B options, /** * Expand a file path specified on the command-line. * - * Most file paths on the command-line allow an %outname% placeholder. - * The placeholder will expand to a different value depending on - * the current output mode. There are three scenarios: + *

Most file paths on the command-line allow an %outname% placeholder. The placeholder will + * expand to a different value depending on the current output mode. There are three scenarios: * - * 1) Single JS output, single extra output: sub in jsOutputPath. - * 2) Multiple JS output, single extra output: sub in the base module name. - * 3) Multiple JS output, multiple extra output: sub in the module output - * file. + *

1) Single JS output, single extra output: sub in jsOutputPath. 2) Multiple JS output, single + * extra output: sub in the base module name. 3) Multiple JS output, multiple extra output: sub in + * the module output file. * - * Passing a JSModule to this function automatically triggers case #3. - * Otherwise, we'll use strategy #1 or #2 based on the current output mode. + *

Passing a JSModule to this function automatically triggers case #3. Otherwise, we'll use + * strategy #1 or #2 based on the current output mode. */ - private String expandCommandLinePath( - String path, JSModule forModule) { + @GwtIncompatible("Unnecessary") + private String expandCommandLinePath(String path, JSModule forModule) { String sub; if (forModule != null) { sub = config.moduleOutputPathPrefix + forModule.getName() + ".js"; @@ -1615,6 +1665,7 @@ private String expandCommandLinePath( /** Expansion function for source map. */ @VisibleForTesting + @GwtIncompatible("Unnecessary") String expandSourceMapPath(B options, JSModule forModule) { if (Strings.isNullOrEmpty(options.sourceMapOutputPath)) { return null; @@ -1623,11 +1674,11 @@ String expandSourceMapPath(B options, JSModule forModule) { } /** - * Converts a file name into a Writer taking in account the output charset. - * Returns null if the file name is null. + * Converts a file name into a Writer taking in account the output charset. Returns null if the + * file name is null. */ - private Writer fileNameToLegacyOutputWriter(String fileName) - throws IOException { + @GwtIncompatible("Unnecessary") + private Writer fileNameToLegacyOutputWriter(String fileName) throws IOException { if (fileName == null) { return null; } @@ -1639,9 +1690,10 @@ private Writer fileNameToLegacyOutputWriter(String fileName) } /** - * Converts a file name into a Writer taking in account the output charset. - * Returns null if the file name is null. + * Converts a file name into a Writer taking in account the output charset. Returns null if the + * file name is null. */ + @GwtIncompatible("Unnecessary") private Writer fileNameToOutputWriter2(String fileName) throws IOException { if (fileName == null) { return null; @@ -1653,23 +1705,18 @@ private Writer fileNameToOutputWriter2(String fileName) throws IOException { return streamToOutputWriter2(filenameToOutputStream(fileName)); } - /** - * Converts a file name into a Outputstream. - * Returns null if the file name is null. - */ - protected OutputStream filenameToOutputStream(String fileName) - throws IOException { + /** Converts a file name into a Outputstream. Returns null if the file name is null. */ + @GwtIncompatible("Unnecessary") + protected OutputStream filenameToOutputStream(String fileName) throws IOException { if (fileName == null){ return null; } return new FileOutputStream(fileName); } - /** - * Create a writer with the legacy output charset. - */ - private Writer streamToLegacyOutputWriter(OutputStream stream) - throws IOException { + /** Create a writer with the legacy output charset. */ + @GwtIncompatible("Unnecessary") + private Writer streamToLegacyOutputWriter(OutputStream stream) throws IOException { if (legacyOutputCharset == null) { return new BufferedWriter(new OutputStreamWriter(stream, UTF_8)); } else { @@ -1678,9 +1725,8 @@ private Writer streamToLegacyOutputWriter(OutputStream stream) } } - /** - * Create a writer with the newer output charset. - */ + /** Create a writer with the newer output charset. */ + @GwtIncompatible("Unnecessary") private Writer streamToOutputWriter2(OutputStream stream) { if (outputCharset2 == null) { return new BufferedWriter(new OutputStreamWriter(stream, UTF_8)); @@ -1691,13 +1737,12 @@ private Writer streamToOutputWriter2(OutputStream stream) { } /** - * Outputs the source map found in the compiler to the proper path if one - * exists. + * Outputs the source map found in the compiler to the proper path if one exists. * * @param options The options to the Compiler. */ - private void outputSourceMap(B options, String associatedName) - throws IOException { + @GwtIncompatible("Unnecessary") + private void outputSourceMap(B options, String associatedName) throws IOException { if (Strings.isNullOrEmpty(options.sourceMapOutputPath) || options.sourceMapOutputPath.equals("/dev/null")) { return; @@ -1711,11 +1756,12 @@ private void outputSourceMap(B options, String associatedName) } /** - * Returns the path at which to output map file(s) based on the path at which - * the JS binary will be placed. + * Returns the path at which to output map file(s) based on the path at which the JS binary will + * be placed. * * @return The path in which to place the generated map file(s). */ + @GwtIncompatible("Unnecessary") private String getMapPath(String outputFile) { String basePath = ""; @@ -1751,9 +1797,10 @@ private String getMapPath(String outputFile) { } /** - * Outputs the variable and property name maps for the specified compiler if - * the proper FLAGS are set. + * Outputs the variable and property name maps for the specified compiler if the proper FLAGS are + * set. */ + @GwtIncompatible("Unnecessary") private void outputNameMaps() throws IOException { String propertyMapOutputPath = null; @@ -1810,6 +1857,7 @@ private void outputNameMaps() throws IOException { /** * Outputs the string map generated by the {@link ReplaceStrings} pass if an output path exists. */ + @GwtIncompatible("Unnecessary") private void outputStringMap() throws IOException { if (!config.stringMapOutputPath.isEmpty()) { if (compiler.getStringMap() == null) { @@ -1825,16 +1873,15 @@ private void outputStringMap() throws IOException { } /** - * Create a map of constant names to constant values from a textual - * description of the map. + * Create a map of constant names to constant values from a textual description of the map. * - * @param definitions A list of overriding definitions for defines in - * the form {@code [=]}, where {@code } is a number, boolean, or - * single-quoted string without single quotes. + * @param definitions A list of overriding definitions for defines in the form {@code + * [=]}, where {@code } is a number, boolean, or single-quoted string without + * single quotes. */ @VisibleForTesting - static void createDefineOrTweakReplacements(List definitions, - CompilerOptions options, boolean tweaks) { + public static void createDefineOrTweakReplacements( + List definitions, CompilerOptions options, boolean tweaks) { // Parse the definitions for (String override : definitions) { String[] assignment = override.split("=", 2); @@ -1903,28 +1950,32 @@ static void createDefineOrTweakReplacements(List definitions, } /** - * Returns true if and only if a manifest or bundle should be generated - * for each module, as opposed to one unified manifest. + * Returns true if and only if a manifest or bundle should be generated for each module, as + * opposed to one unified manifest. */ + @GwtIncompatible("Unnecessary") private boolean shouldGenerateOutputPerModule(String output) { return !config.module.isEmpty() && output != null && output.contains("%outname%"); } + @GwtIncompatible("Unnecessary") private void outputManifest() throws IOException { outputManifestOrBundle(config.outputManifests, true); } + @GwtIncompatible("Unnecessary") private void outputBundle() throws IOException { outputManifestOrBundle(config.outputBundles, false); } /** - * Writes the manifest or bundle of all compiler input files that were included - * as controlled by --dependency_mode, if requested. + * Writes the manifest or bundle of all compiler input files that were included as controlled by + * --dependency_mode, if requested. */ - private void outputManifestOrBundle(List outputFiles, - boolean isManifest) throws IOException { + @GwtIncompatible("Unnecessary") + private void outputManifestOrBundle(List outputFiles, boolean isManifest) + throws IOException { if (outputFiles.isEmpty()) { return; } @@ -1965,9 +2016,8 @@ private void outputManifestOrBundle(List outputFiles, } } - /** - * Creates a file containing the current module graph in JSON serialization. - */ + /** Creates a file containing the current module graph in JSON serialization. */ + @GwtIncompatible("Unnecessary") private void outputModuleGraphJson() throws IOException { if (config.outputModuleDependencies != null && config.outputModuleDependencies.length() != 0) { @@ -1977,20 +2027,18 @@ private void outputModuleGraphJson() throws IOException { } } - /** - * Prints the current module graph as JSON. - */ + /** Prints the current module graph as JSON. */ @VisibleForTesting + @GwtIncompatible("Unnecessary") void printModuleGraphJsonTo(Appendable out) throws IOException { out.append(compiler.getDegenerateModuleGraph().toJson().toString()); } - /** - * Prints a set of modules to the manifest or bundle file. - */ + /** Prints a set of modules to the manifest or bundle file. */ @VisibleForTesting - void printModuleGraphManifestOrBundleTo(JSModuleGraph graph, - Appendable out, boolean isManifest) throws IOException { + @GwtIncompatible("Unnecessary") + void printModuleGraphManifestOrBundleTo(JSModuleGraph graph, Appendable out, boolean isManifest) + throws IOException { Joiner commas = Joiner.on(","); boolean requiresNewline = false; for (JSModule module : graph.getAllModules()) { @@ -2015,12 +2063,12 @@ void printModuleGraphManifestOrBundleTo(JSModuleGraph graph, } /** - * Prints a list of input names (using root-relative paths), delimited by - * newlines, to the manifest file. + * Prints a list of input names (using root-relative paths), delimited by newlines, to the + * manifest file. */ @VisibleForTesting - void printManifestTo(Iterable inputs, Appendable out) - throws IOException { + @GwtIncompatible("Unnecessary") + void printManifestTo(Iterable inputs, Appendable out) throws IOException { for (CompilerInput input : inputs) { String rootRelativePath = rootRelativePathsMap.get(input.getName()); String displayName = rootRelativePath != null @@ -2032,12 +2080,12 @@ void printManifestTo(Iterable inputs, Appendable out) } /** - * Prints all the input contents, starting with a comment that specifies - * the input file name (using root-relative paths) before each file. + * Prints all the input contents, starting with a comment that specifies the input file name + * (using root-relative paths) before each file. */ @VisibleForTesting - void printBundleTo(Iterable inputs, Appendable out) - throws IOException { + @GwtIncompatible("Unnecessary") + void printBundleTo(Iterable inputs, Appendable out) throws IOException { if (!compiler.getOptions().preventLibraryInjection) { // ES6 modules will need a runtime in a bundle. Skip appending this runtime if there are no // ES6 modules to cut down on size. @@ -2082,9 +2130,10 @@ void printBundleTo(Iterable inputs, Appendable out) } /** - * Construct and return the input root path map. The key is the exec path of - * each input file, and the value is the corresponding root relative path. + * Construct and return the input root path map. The key is the exec path of each input file, and + * the value is the corresponding root relative path. */ + @GwtIncompatible("Unnecessary") private Map constructRootRelativePathsMap() { Map rootRelativePathsMap = new LinkedHashMap<>(); for (String mapString : config.manifestMaps) { @@ -2099,13 +2148,12 @@ private Map constructRootRelativePathsMap() { } /** - * Configurations for the command line configs. Designed for easy - * building, so that we can decouple the flags-parsing library from - * the actual configuration options. + * Configurations for the command line configs. Designed for easy building, so that we can + * decouple the flags-parsing library from the actual configuration options. * - * By design, these configurations must match one-to-one with - * command-line flags. + *

By design, these configurations must match one-to-one with command-line flags. */ + @GwtIncompatible("Unnecessary") protected static class CommandLineConfig { private boolean printTree = false; @@ -2725,10 +2773,9 @@ public CommandLineConfig setErrorFormat(ErrorFormatOption errorFormat) { } } - /** - * Representation of a source file from an encoded json stream input - */ - protected static class JsonFileSpec { + /** Representation of a source file from an encoded json stream input */ + @GwtIncompatible("Unnecessary") + public static class JsonFileSpec { private final String src; private final String path; private String sourceMap; @@ -2771,9 +2818,8 @@ public void setSourceMap(String map) { } } - /** - * Flag types for js source files. - */ + /** Flag types for js source files. */ + @GwtIncompatible("Unnecessary") protected enum JsSourceType { EXTERN("extern"), JS("js"), @@ -2787,9 +2833,8 @@ private JsSourceType(String flagName) { } } - /** - * A pair from flag to its value. - */ + /** A pair from flag to its value. */ + @GwtIncompatible("Unnecessary") protected static class FlagEntry { private final T flag; private final String value; @@ -2842,14 +2887,12 @@ private JsModuleSpec(String name, int numInputs, ImmutableList deps) { } /** - * - * @param specString The spec format is: - * name:num-js-files[:[dep,...][:]]. Module names must - * not contain the ':' character. + * @param specString The spec format is: name:num-js-files[:[dep,...][:]]. Module + * names must not contain the ':' character. * @param isFirstModule Whether the spec is for the first module. * @return A parsed js module spec. */ - static JsModuleSpec create(String specString, boolean isFirstModule) { + public static JsModuleSpec create(String specString, boolean isFirstModule) { // Format is ":[:[,...][:]]". String[] parts = specString.split(":"); if (parts.length < 2 || parts.length > 4) { @@ -2909,7 +2952,7 @@ public int getNumJsFiles() { } } - + @GwtIncompatible("Unnecessary") static final class SystemExitCodeReceiver implements Function { static final SystemExitCodeReceiver INSTANCE = new SystemExitCodeReceiver(); diff --git a/src/com/google/javascript/jscomp/Compiler.java b/src/com/google/javascript/jscomp/Compiler.java index b0eadd75c3a..46181e907b5 100644 --- a/src/com/google/javascript/jscomp/Compiler.java +++ b/src/com/google/javascript/jscomp/Compiler.java @@ -2722,15 +2722,15 @@ protected Config createConfig(Config.LanguageMode mode, Config.StrictMode strict return config; } - //------------------------------------------------------------------------ + // ------------------------------------------------------------------------ // Error reporting - //------------------------------------------------------------------------ + // ------------------------------------------------------------------------ /** - * The warning classes that are available from the command-line, and - * are suppressible by the {@code @suppress} annotation. + * The warning classes that are available from the command-line, and are suppressible by the + * {@code @suppress} annotation. */ - protected DiagnosticGroups getDiagnosticGroups() { + public DiagnosticGroups getDiagnosticGroups() { return new DiagnosticGroups(); } @@ -3481,7 +3481,7 @@ private void renameModules(List newModules, List deserialize return; } - void initWebpackMap(ImmutableMap inputPathByWebpackId) { + public void initWebpackMap(ImmutableMap inputPathByWebpackId) { this.inputPathByWebpackId = inputPathByWebpackId; } diff --git a/src/com/google/javascript/jscomp/CompilerOptions.java b/src/com/google/javascript/jscomp/CompilerOptions.java index 51c9e952c17..58b3e8769ae 100644 --- a/src/com/google/javascript/jscomp/CompilerOptions.java +++ b/src/com/google/javascript/jscomp/CompilerOptions.java @@ -836,7 +836,8 @@ public void setAppNameStr(String appNameStr) { boolean checksOnly; - static enum OutputJs { + /** What type of JS file should be output by this compilation */ + public static enum OutputJs { // Don't output anything. NONE, // Output a "sentinel" file containing just a comment. @@ -1757,7 +1758,7 @@ public void setChecksOnly(boolean checksOnly) { this.checksOnly = checksOnly; } - void setOutputJs(OutputJs outputJs) { + public void setOutputJs(OutputJs outputJs) { this.outputJs = outputJs; } @@ -2856,6 +2857,10 @@ public void setConformanceConfigs(List configs) { .build(); } + public void clearConformanceConfigs() { + this.conformanceConfigs = ImmutableList.of(); + } + /** * Whether the output should contain a 'use strict' directive. */ diff --git a/src/com/google/javascript/jscomp/DiagnosticGroups.java b/src/com/google/javascript/jscomp/DiagnosticGroups.java index fbed7cc431b..3f289b3e085 100644 --- a/src/com/google/javascript/jscomp/DiagnosticGroups.java +++ b/src/com/google/javascript/jscomp/DiagnosticGroups.java @@ -682,11 +682,8 @@ public DiagnosticGroup forName(String name) { DiagnosticGroups.registerDeprecatedGroup("duplicateZipContents"); } - /** - * Adds warning levels by name. - */ - void setWarningLevel(CompilerOptions options, - String name, CheckLevel level) { + /** Adds warning levels by name. */ + public void setWarningLevel(CompilerOptions options, String name, CheckLevel level) { DiagnosticGroup group = forName(name); Preconditions.checkNotNull(group, "No warning class for name: %s", name); options.setWarningLevel(group, level); diff --git a/src/com/google/javascript/jscomp/gwt/client/GwtRunner.java b/src/com/google/javascript/jscomp/gwt/client/GwtRunner.java index cd9b2fbd93b..f44fa23e9b8 100644 --- a/src/com/google/javascript/jscomp/gwt/client/GwtRunner.java +++ b/src/com/google/javascript/jscomp/gwt/client/GwtRunner.java @@ -18,13 +18,19 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Strings.nullToEmpty; +import static com.google.javascript.jscomp.AbstractCommandLineRunner.createDefineOrTweakReplacements; +import static com.google.javascript.jscomp.AbstractCommandLineRunner.createDependencyOptions; +import static com.google.javascript.jscomp.AbstractCommandLineRunner.createJsModules; +import static com.google.javascript.jscomp.AbstractCommandLineRunner.parseModuleWrappers; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.gwt.core.client.JavaScriptObject; +import com.google.javascript.jscomp.AbstractCommandLineRunner.JsModuleSpec; import com.google.javascript.jscomp.BasicErrorManager; import com.google.javascript.jscomp.CheckLevel; +import com.google.javascript.jscomp.ClosureCodingConvention; import com.google.javascript.jscomp.CompilationLevel; import com.google.javascript.jscomp.Compiler; import com.google.javascript.jscomp.CompilerOptions; @@ -33,10 +39,13 @@ import com.google.javascript.jscomp.CompilerOptions.TracerMode; import com.google.javascript.jscomp.DefaultExterns; import com.google.javascript.jscomp.DependencyOptions; +import com.google.javascript.jscomp.DiagnosticGroups; import com.google.javascript.jscomp.DiagnosticType; import com.google.javascript.jscomp.JSError; +import com.google.javascript.jscomp.JSModule; import com.google.javascript.jscomp.ModuleIdentifier; import com.google.javascript.jscomp.PropertyRenamingPolicy; +import com.google.javascript.jscomp.ShowByPathWarningsGuard; import com.google.javascript.jscomp.SourceFile; import com.google.javascript.jscomp.SourceMap; import com.google.javascript.jscomp.SourceMapInput; @@ -44,12 +53,14 @@ import com.google.javascript.jscomp.WarningLevel; import com.google.javascript.jscomp.deps.ModuleLoader.ResolutionMode; import com.google.javascript.jscomp.deps.SourceCodeEscapers; +import com.google.javascript.jscomp.parsing.parser.FeatureSet; import com.google.javascript.jscomp.resources.ResourceLoader; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -75,21 +86,35 @@ private static class Flags { boolean angularPass; boolean applyInputSourceMaps; boolean assumeFunctionWrapper; + boolean checksOnly; + String[] chunk; + String[] chunkWrapper; + String chunkOutputPathPrefix; String compilationLevel; boolean dartPass; + boolean debug; JsMap defines; + String[] define; String dependencyMode; String[] entryPoint; String env; boolean exportLocalPropertyDefinitions; String[] extraAnnotationNames; + String[] formatting; boolean generateExports; + String[] hideWarningsFor; + String isolationMode; + String[] jscompError; + String[] jscompOff; + String[] jscompWarning; + String[] jsModuleRoot; + String jsOutputFile; String languageIn; String languageOut; - boolean checksOnly; + String moduleResolution; boolean newTypeInf; - String isolationMode; String outputWrapper; + boolean parseInlineSourceMaps; @Deprecated boolean polymerPass; Double polymerVersion; // nb. nullable JS number represented by java.lang.Double in GWT. @@ -97,16 +122,12 @@ private static class Flags { boolean processClosurePrimitives; boolean processCommonJsModules; boolean renaming; - public String renamePrefixNamespace; + String renamePrefixNamespace; boolean rewritePolyfills; - String warningLevel; - boolean useTypesForOptimization; - String tracerMode; - String moduleResolutionMode; - String jsOutputFile; - String[] formatting; boolean sourceMapIncludeContent; - boolean parseInlineSourceMaps; + String tracerMode; + boolean useTypesForOptimization; + String warningLevel; // These flags do not match the Java compiler JAR. @Deprecated @@ -135,20 +156,37 @@ private static Flags getDefaultFlags() { defaultFlags.applyInputSourceMaps = true; defaultFlags.assumeFunctionWrapper = false; defaultFlags.checksOnly = false; + defaultFlags.chunk = null; + defaultFlags.chunkWrapper = null; + defaultFlags.chunkOutputPathPrefix = "./"; defaultFlags.compilationLevel = "SIMPLE"; + defaultFlags.createSourceMap = true; defaultFlags.dartPass = false; + defaultFlags.debug = false; + defaultFlags.define = null; defaultFlags.defines = null; defaultFlags.dependencyMode = null; defaultFlags.entryPoint = null; defaultFlags.env = "BROWSER"; defaultFlags.exportLocalPropertyDefinitions = false; defaultFlags.extraAnnotationNames = null; + defaultFlags.externs = null; + defaultFlags.formatting = null; defaultFlags.generateExports = false; + defaultFlags.hideWarningsFor = null; + defaultFlags.jsCode = null; + defaultFlags.jscompError = null; + defaultFlags.jscompOff = null; + defaultFlags.jscompWarning = null; + defaultFlags.jsModuleRoot = null; + defaultFlags.jsOutputFile = "compiled.js"; defaultFlags.languageIn = "ECMASCRIPT_2017"; defaultFlags.languageOut = "ECMASCRIPT5"; + defaultFlags.moduleResolution = "BROWSER"; defaultFlags.newTypeInf = false; defaultFlags.isolationMode = "NONE"; defaultFlags.outputWrapper = null; + defaultFlags.parseInlineSourceMaps = true; defaultFlags.polymerPass = false; defaultFlags.polymerVersion = null; defaultFlags.preserveTypeAnnotations = false; @@ -157,17 +195,11 @@ private static Flags getDefaultFlags() { defaultFlags.renamePrefixNamespace = null; defaultFlags.renaming = true; defaultFlags.rewritePolyfills = true; + defaultFlags.sourceMapIncludeContent = false; + defaultFlags.tracerMode = "OFF"; defaultFlags.warningLevel = "DEFAULT"; defaultFlags.useTypesForOptimization = true; - defaultFlags.jsCode = null; - defaultFlags.externs = null; - defaultFlags.createSourceMap = false; - defaultFlags.tracerMode = "OFF"; - defaultFlags.moduleResolutionMode = "BROWSER"; - defaultFlags.jsOutputFile = "compiled.js"; - defaultFlags.formatting = null; - defaultFlags.sourceMapIncludeContent = false; - defaultFlags.parseInlineSourceMaps = true; + return defaultFlags; } @@ -181,7 +213,7 @@ private static class File { } @JsType(namespace = JsPackage.GLOBAL, name = "Object", isNative = true) - private static class ModuleOutput { + private static class ChunkOutput { @JsProperty @Deprecated String compiledCode; @JsProperty @Deprecated String sourceMap; @JsProperty File[] compiledFiles; @@ -258,12 +290,84 @@ private static JavaScriptObject[] toNativeErrorArray(List errors) { return out; } - /** - * Generates the output code, taking into account the passed {@code flags}. - */ - private static ModuleOutput writeOutput(Compiler compiler, Flags flags) { + /** Generates the output code, taking into account the passed {@code flags}. */ + private static ChunkOutput writeChunkOutput( + Compiler compiler, Flags flags, List chunks) { + ArrayList outputFiles = new ArrayList<>(); + ChunkOutput output = new ChunkOutput(); + + Map parsedModuleWrappers = + parseModuleWrappers(Arrays.asList(getStringArray(flags, "chunkWrapper")), chunks); + + for (JSModule c : chunks) { + if (flags.createSourceMap) { + compiler.getSourceMap().reset(); + } + + File file = new File(); + file.path = flags.chunkOutputPathPrefix + c.getName() + ".js"; + + String code = compiler.toSource(c); + + int lastSeparatorIndex = file.path.lastIndexOf('/'); + if (lastSeparatorIndex < 0) { + lastSeparatorIndex = file.path.lastIndexOf('\\'); + } + String baseName = file.path.substring(Math.max(0, lastSeparatorIndex)); + String wrapper = parsedModuleWrappers.get(c.getName()).replace("%basename%", baseName); + StringBuilder out = new StringBuilder(); + int pos = wrapper.indexOf("%s"); + if (pos != -1) { + String prefix = ""; + + if (pos > 0) { + prefix = wrapper.substring(0, pos); + out.append(prefix); + } + + out.append(code); + + int suffixStart = pos + "%s".length(); + if (suffixStart != wrapper.length()) { + // Something after placeholder? + out.append(wrapper, suffixStart, wrapper.length()); + } + // Make sure we always end output with a line feed. + out.append('\n'); + + // If we have a source map, adjust its offsets to match + // the code WITHIN the wrapper. + if (compiler != null && compiler.getSourceMap() != null) { + compiler.getSourceMap().setWrapperPrefix(prefix); + } + + } else { + out.append(code); + out.append('\n'); + } + + file.src = out.toString(); + + if (flags.createSourceMap) { + StringBuilder b = new StringBuilder(); + try { + compiler.getSourceMap().appendTo(b, file.path); + } catch (IOException e) { + // ignore + } + file.sourceMap = b.toString(); + } + outputFiles.add(file); + } + + output.compiledFiles = outputFiles.toArray(new File[0]); + return output; + } + + /** Generates the output code, taking into account the passed {@code flags}. */ + private static ChunkOutput writeOutput(Compiler compiler, Flags flags) { ArrayList outputFiles = new ArrayList<>(); - ModuleOutput output = new ModuleOutput(); + ChunkOutput output = new ChunkOutput(); File file = new File(); file.path = flags.jsOutputFile; @@ -337,38 +441,48 @@ private static ImmutableList createEntryPoints(String[] entryP return builder.build(); } - private static DependencyOptions createDependencyOptions( - CompilerOptions.DependencyMode dependencyMode, - List entryPoints) { - // Copied from from AbstractCommandLineRunner.java. - if (dependencyMode == CompilerOptions.DependencyMode.STRICT) { - if (entryPoints.isEmpty()) { - throw new RuntimeException( - "When dependencyMode=STRICT, you must specify at least one entry point"); + private static void applyWarnings( + String[] warningGuards, + CompilerOptions options, + DiagnosticGroups diagnosticGroups, + CheckLevel checkLevel) { + for (String warningGuardName : warningGuards) { + if ("*".equals(warningGuardName)) { + for (String groupName : diagnosticGroups.getRegisteredGroups().keySet()) { + if (!DiagnosticGroups.wildcardExcludedGroups.contains(groupName)) { + diagnosticGroups.setWarningLevel(options, groupName, checkLevel); + } + } + } else { + diagnosticGroups.setWarningLevel(options, warningGuardName, checkLevel); } - return new DependencyOptions() - .setDependencyPruning(true) - .setDependencySorting(true) - .setMoocherDropping(true) - .setEntryPoints(entryPoints); - } else if (dependencyMode == CompilerOptions.DependencyMode.LOOSE || !entryPoints.isEmpty()) { - return new DependencyOptions() - .setDependencyPruning(true) - .setDependencySorting(true) - .setMoocherDropping(false) - .setEntryPoints(entryPoints); - } - return null; + } } - private static void applyDefaultOptions(CompilerOptions options) { - CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options); - WarningLevel.DEFAULT.setOptionsForWarningLevel(options); - options.setLanguageIn(LanguageMode.ECMASCRIPT_2017); - options.setLanguageOut(LanguageMode.ECMASCRIPT5); - } + private static void applyOptionsFromFlags( + CompilerOptions options, Flags flags, DiagnosticGroups diagnosticGroups) { + + // order matches createOptions in CommandLineRunner.java + + LanguageMode languageIn = LanguageMode.fromString(flags.languageIn); + if (languageIn != null) { + options.setLanguageIn(languageIn); + } else { + throw new RuntimeException("Bad value for languageIn: " + flags.languageIn); + } + LanguageMode languageOut = LanguageMode.fromString(flags.languageOut); + if (languageOut != null) { + options.setLanguageOut(languageOut); + } else { + throw new RuntimeException("Bad value for languageOut: " + flags.languageOut); + } + + options.setCodingConvention(new ClosureCodingConvention()); + + if (flags.extraAnnotationNames != null) { + options.setExtraAnnotationNames(Arrays.asList(flags.extraAnnotationNames)); + } - private static void applyOptionsFromFlags(CompilerOptions options, Flags flags) { CompilationLevel level = DEFAULT_COMPILATION_LEVEL; if (flags.compilationLevel != null) { level = CompilationLevel.fromString(Ascii.toUpperCase(flags.compilationLevel)); @@ -382,18 +496,9 @@ private static void applyOptionsFromFlags(CompilerOptions options, Flags flags) "renaming cannot be disabled when ADVANCED_OPTIMIZATIONS is used"); } level.setOptionsForCompilationLevel(options); - if (flags.assumeFunctionWrapper) { - level.setWrappedOutputOptimizations(options); - } - if (flags.useTypesForOptimization) { - level.setTypeBasedOptimizationOptions(options); - } - - WarningLevel warningLevel = WarningLevel.DEFAULT; - if (flags.warningLevel != null) { - warningLevel = WarningLevel.valueOf(flags.warningLevel); + if (flags.debug) { + level.setDebugOptionsForCompilationLevel(options); } - warningLevel.setOptionsForWarningLevel(options); CompilerOptions.Environment environment = CompilerOptions.Environment.BROWSER; if (flags.env != null) { @@ -401,47 +506,13 @@ private static void applyOptionsFromFlags(CompilerOptions options, Flags flags) } options.setEnvironment(environment); - CompilerOptions.DependencyMode dependencyMode = CompilerOptions.DependencyMode.NONE; - if (flags.dependencyMode != null) { - dependencyMode = - CompilerOptions.DependencyMode.valueOf(Ascii.toUpperCase(flags.dependencyMode)); - } - List entryPoints = createEntryPoints(getStringArray(flags, "entryPoint")); - DependencyOptions dependencyOptions = createDependencyOptions(dependencyMode, entryPoints); - if (dependencyOptions != null) { - options.setDependencyOptions(dependencyOptions); - } - - LanguageMode languageIn = LanguageMode.fromString(flags.languageIn); - if (languageIn != null) { - options.setLanguageIn(languageIn); - } - LanguageMode languageOut = LanguageMode.fromString(flags.languageOut); - if (languageOut != null) { - options.setLanguageOut(languageOut); - } - - if (flags.createSourceMap) { - options.setSourceMapOutputPath("%output%.map"); - } - - if (flags.defines != null) { - // CompilerOptions also validates types, but uses Preconditions and therefore won't generate - // a useful exception. - flags.defines.validatePrimitiveTypes(); - options.setDefineReplacements(flags.defines.asMap()); - } - - if (flags.extraAnnotationNames != null) { - options.setExtraAnnotationNames(Arrays.asList(flags.extraAnnotationNames)); - } - - if (flags.tracerMode != null) { - options.setTracerMode(TracerMode.valueOf(flags.tracerMode)); + options.setChecksOnly(flags.checksOnly); + if (flags.checksOnly) { + options.setOutputJs(CompilerOptions.OutputJs.NONE); } - if (flags.moduleResolutionMode != null) { - options.setModuleResolutionMode(ResolutionMode.valueOf(flags.moduleResolutionMode)); + if (flags.useTypesForOptimization) { + level.setTypeBasedOptimizationOptions(options); } if (flags.isolationMode != null @@ -449,6 +520,18 @@ private static void applyOptionsFromFlags(CompilerOptions options, Flags flags) flags.outputWrapper = "(function(){%output%}).call(this);"; flags.assumeFunctionWrapper = true; } + if (flags.assumeFunctionWrapper) { + level.setWrappedOutputOptimizations(options); + } + + options.setGenerateExports(flags.generateExports); + options.setExportLocalPropertyDefinitions(flags.exportLocalPropertyDefinitions); + + WarningLevel warningLevel = WarningLevel.DEFAULT; + if (flags.warningLevel != null) { + warningLevel = WarningLevel.valueOf(flags.warningLevel); + } + warningLevel.setOptionsForWarningLevel(options); if (flags.formatting != null) { List formattingOptions = Arrays.asList(getStringArray(flags, "formatting")); @@ -469,32 +552,92 @@ private static void applyOptionsFromFlags(CompilerOptions options, Flags flags) } } - options.setSourceMapIncludeSourcesContent(flags.sourceMapIncludeContent); - options.setParseInlineSourceMaps(flags.parseInlineSourceMaps); + options.setClosurePass(flags.processClosurePrimitives); + options.setAngularPass(flags.angularPass); - options.setApplyInputSourceMaps(flags.applyInputSourceMaps); - options.setChecksOnly(flags.checksOnly); - options.setDartPass(flags.dartPass); - options.setExportLocalPropertyDefinitions(flags.exportLocalPropertyDefinitions); - options.setGenerateExports(flags.generateExports); + if (flags.polymerPass) { options.setPolymerVersion(1); } else if (flags.polymerVersion != null) { options.setPolymerVersion(flags.polymerVersion.intValue()); } - options.setPreserveTypeAnnotations(flags.preserveTypeAnnotations); - options.setClosurePass(flags.processClosurePrimitives); - options.setProcessCommonJSModules(flags.processCommonJsModules); + + options.setDartPass(flags.dartPass); + options.setRenamePrefixNamespace(flags.renamePrefixNamespace); + + options.setPreserveTypeAnnotations(flags.preserveTypeAnnotations); + + options.setRewritePolyfills( + flags.rewritePolyfills && options.getLanguageIn().toFeatureSet().contains(FeatureSet.ES6)); + + // We don't support conformance configs + options.clearConformanceConfigs(); + + if (flags.tracerMode != null) { + options.setTracerMode(TracerMode.valueOf(flags.tracerMode)); + } + + options.setSourceMapIncludeSourcesContent(flags.sourceMapIncludeContent); + + if (flags.moduleResolution != null) { + options.setModuleResolutionMode(ResolutionMode.valueOf(flags.moduleResolution)); + } + if (!flags.renaming) { options.setVariableRenaming(VariableRenamingPolicy.OFF); options.setPropertyRenaming(PropertyRenamingPolicy.OFF); } - options.setRewritePolyfills(flags.rewritePolyfills); - } - private static void disableUnsupportedOptions(CompilerOptions options) { - options.getDependencyOptions().setDependencySorting(false); + // order matches setRunOptions in AbstractCommandLineRunner.java + + applyWarnings(getStringArray(flags, "jscompOff"), options, diagnosticGroups, CheckLevel.OFF); + applyWarnings( + getStringArray(flags, "jscompWarning"), options, diagnosticGroups, CheckLevel.WARNING); + applyWarnings( + getStringArray(flags, "jscompError"), options, diagnosticGroups, CheckLevel.ERROR); + + if (flags.hideWarningsFor != null) { + options.addWarningsGuard( + new ShowByPathWarningsGuard( + getStringArray(flags, "hideWarningsFor"), ShowByPathWarningsGuard.ShowType.EXCLUDE)); + } + + if (flags.define != null) { + createDefineOrTweakReplacements( + Arrays.asList(getStringArray(flags, "define")), options, false); + } + + if (flags.defines != null) { + // CompilerOptions also validates types, but uses Preconditions and therefore won't generate + // a useful exception. + flags.defines.validatePrimitiveTypes(); + options.setDefineReplacements(flags.defines.asMap()); + } + + CompilerOptions.DependencyMode dependencyMode = CompilerOptions.DependencyMode.NONE; + if (flags.dependencyMode != null) { + dependencyMode = + CompilerOptions.DependencyMode.valueOf(Ascii.toUpperCase(flags.dependencyMode)); + } + List entryPoints = createEntryPoints(getStringArray(flags, "entryPoint")); + DependencyOptions dependencyOptions = createDependencyOptions(dependencyMode, entryPoints); + if (dependencyOptions != null) { + options.setDependencyOptions(dependencyOptions); + } + + options.setTrustedStrings(true); + + if (flags.createSourceMap) { + options.setSourceMapOutputPath("%output%.map"); + } + options.setSourceMapIncludeSourcesContent(flags.sourceMapIncludeContent); + options.setParseInlineSourceMaps(flags.parseInlineSourceMaps); + options.setApplyInputSourceMaps(flags.applyInputSourceMaps); + + options.setProcessCommonJSModules(flags.processCommonJsModules); + + options.setModuleRoots(Arrays.asList(getStringArray(flags, "jsModuleRoot"))); } private static List fromFileArray(File[] src, String unknownPrefix) { @@ -551,11 +694,9 @@ private static native String[] updateFlags(Flags dst, Flags src) /*-{ return unhandled; }-*/; - /** - * Public compiler call. Exposed in {@link #exportCompile}. - */ + /** Public compiler call. Exposed in {@link #exportCompile}. */ @JsMethod(namespace = "jscomp") - public static ModuleOutput compile(Flags flags, File[] inputs) { + public static ChunkOutput compile(Flags flags, File[] inputs) throws IOException { String[] unhandled = updateFlags(flags, getDefaultFlags()); if (unhandled.length > 0) { throw new RuntimeException("Unhandled flag: " + unhandled[0]); @@ -568,6 +709,7 @@ public static ModuleOutput compile(Flags flags, File[] inputs) { sourceMaps = buildSourceMaps(flags.jsCode, "Input_"); } + ImmutableMap.Builder inputPathByWebpackId = new ImmutableMap.Builder<>(); if (inputs != null) { List sourceFiles = fromFileArray(inputs, "Input_"); ImmutableMap inputSourceMaps = buildSourceMaps(inputs, "Input_"); @@ -584,23 +726,45 @@ public static ModuleOutput compile(Flags flags, File[] inputs) { tempMaps.putAll(inputSourceMaps); sourceMaps = ImmutableMap.copyOf(tempMaps); } + + for (GwtRunner.File element : inputs) { + if (element.webpackId != null && element.path != null) { + inputPathByWebpackId.put(element.webpackId, element.path); + } + } } + Compiler compiler = new Compiler(new NodePrintStream()); CompilerOptions options = new CompilerOptions(); - applyDefaultOptions(options); - applyOptionsFromFlags(options, flags); + applyOptionsFromFlags(options, flags, compiler.getDiagnosticGroups()); options.setInputSourceMaps(sourceMaps); - disableUnsupportedOptions(options); List externs = fromFileArray(flags.externs, "Extern_"); externs.addAll(createExterns(options.getEnvironment())); NodeErrorManager errorManager = new NodeErrorManager(); - Compiler compiler = new Compiler(new NodePrintStream()); + compiler.initWebpackMap(inputPathByWebpackId.build()); compiler.setErrorManager(errorManager); - compiler.compile(externs, jsCode, options); - ModuleOutput output = writeOutput(compiler, flags); + List chunkSpecs = new ArrayList<>(); + if (flags.chunk != null) { + Collections.addAll(chunkSpecs, flags.chunk); + } + List jsChunkSpecs = new ArrayList<>(); + for (int i = 0; i < chunkSpecs.size(); i++) { + jsChunkSpecs.add(JsModuleSpec.create(chunkSpecs.get(i), i == 0)); + } + ChunkOutput output; + if (!jsChunkSpecs.isEmpty()) { + List chunks = createJsModules(jsChunkSpecs, jsCode); + + compiler.compileModules(externs, chunks, options); + output = writeChunkOutput(compiler, flags, chunks); + } else { + compiler.compile(externs, jsCode, options); + output = writeOutput(compiler, flags); + } + output.errors = toNativeErrorArray(errorManager.errors); output.warnings = toNativeErrorArray(errorManager.warnings);