From a5db18c6d4aa2e226f7aac084f6f90b766e01f9a Mon Sep 17 00:00:00 2001 From: Chad Killingsworth Date: Mon, 25 Jun 2018 15:24:29 -0700 Subject: [PATCH] Add support for code splitting and many other flags to the GWT version. All of AbstractCommandLineRunner was marked as GWTIncompatible. Adds GwtIncompatible annotations to each instance method and field and refactors others to be static so they are usable in the GWT runner. In addition, flag logic in the GWT runner was audited and made to much more closely match the logic of the CommandLineRunner. Closes https://github.com/google/closure-compiler/pull/2979 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=202029643 --- .../jscomp/AbstractCommandLineRunner.java | 489 ++++++++++-------- .../google/javascript/jscomp/Compiler.java | 12 +- .../javascript/jscomp/CompilerOptions.java | 9 +- .../javascript/jscomp/DiagnosticGroups.java | 7 +- .../jscomp/gwt/client/GwtRunner.java | 418 ++++++++++----- 5 files changed, 572 insertions(+), 363 deletions(-) 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);