1515 */
1616package com .google .javascript .jscomp ;
1717
18+ import static com .google .javascript .jscomp .parsing .parser .FeatureSet .Feature .MODULES ;
19+
1820import com .google .common .base .Preconditions ;
1921import com .google .common .base .Splitter ;
2022import com .google .common .collect .ImmutableSet ;
3436import java .util .Set ;
3537
3638/**
37- * Rewrites a ES6 module into a form that can be safely concatenated.
38- * Note that we treat a file as an ES6 module if it has at least one import or
39- * export statement.
39+ * Rewrites a ES6 module into a form that can be safely concatenated. Note that we treat a file as
40+ * an ES6 module if it has at least one import or export statement.
4041 *
4142 * @author moz@google.com (Michael Zhou)
4243 */
43- public final class Es6RewriteModules extends AbstractPostOrderCallback {
44+ public final class Es6RewriteModules extends AbstractPostOrderCallback
45+ implements HotSwapCompilerPass {
4446 private static final String DEFAULT_EXPORT_NAME = "$jscompDefaultExport" ;
4547
4648 static final DiagnosticType LHS_OF_GOOG_REQUIRE_MUST_BE_CONST =
@@ -54,13 +56,13 @@ public final class Es6RewriteModules extends AbstractPostOrderCallback {
5456 "Namespace imports ('goog:some.Namespace') cannot use import * as. "
5557 + "Did you mean to import {0} from ''{1}'';?" );
5658
57- private final Compiler compiler ;
58- private int scriptNodeCount = 0 ;
59+ private final AbstractCompiler compiler ;
60+ private int scriptNodeCount ;
5961
6062 /**
6163 * Maps exported names to their names in current module.
6264 */
63- private Map <String , NameNodePair > exportMap = new LinkedHashMap <>() ;
65+ private Map <String , NameNodePair > exportMap ;
6466
6567 /**
6668 * Maps symbol names to a pair of (moduleName, originalName). The original
@@ -69,12 +71,12 @@ public final class Es6RewriteModules extends AbstractPostOrderCallback {
6971 * object. Eg: "import {foo as f} from 'm'" maps 'f' to the pair ('m', 'foo').
7072 * In the entry for "import * as ns", the originalName will be the empty string.
7173 */
72- private Map <String , ModuleOriginalNamePair > importMap = new HashMap <>() ;
74+ private Map <String , ModuleOriginalNamePair > importMap ;
7375
74- private Set <String > classes = new HashSet <>() ;
75- private Set <String > typedefs = new HashSet <>() ;
76+ private Set <String > classes ;
77+ private Set <String > typedefs ;
7678
77- private Set <String > alreadyRequired = new HashSet <>() ;
79+ private Set <String > alreadyRequired ;
7880
7981 private boolean forceRewrite ;
8082
@@ -84,7 +86,7 @@ public final class Es6RewriteModules extends AbstractPostOrderCallback {
8486 * Creates a new Es6RewriteModules instance which can be used to rewrite
8587 * ES6 modules to a concatenable form.
8688 */
87- public Es6RewriteModules (Compiler compiler ) {
89+ public Es6RewriteModules (AbstractCompiler compiler ) {
8890 this .compiler = compiler ;
8991 }
9092
@@ -104,6 +106,8 @@ public static boolean isEs6ModuleRoot(Node scriptNode) {
104106 * "import" or "export" statements. Fails if the file contains a goog.provide or goog.module.
105107 *
106108 * @return True, if the file is now an ES6 module. False, if the file must remain a script.
109+ * TODO(blickly): Move this logic out of this pass, since it is independent of whether or
110+ * not we are actually transpiling modules
107111 */
108112 public boolean forceToEs6Module (Node root ) {
109113 if (isEs6ModuleRoot (root )) {
@@ -120,15 +124,42 @@ public boolean forceToEs6Module(Node root) {
120124 return true ;
121125 }
122126
127+ @ Override
128+ public void process (Node externs , Node root ) {
129+ Preconditions .checkState (compiler .getOptions ().getLanguageIn ().toFeatureSet ().has (MODULES ));
130+ for (Node file = root .getFirstChild (); file != null ; file = file .getNext ()) {
131+ hotSwapScript (file , null );
132+ }
133+ compiler .setFeatureSet (compiler .getFeatureSet ().without (MODULES ));
134+ }
135+
136+ @ Override
137+ public void hotSwapScript (Node scriptNode , Node originalRoot ) {
138+ if (isEs6ModuleRoot (scriptNode )) {
139+ processFile (scriptNode );
140+ }
141+ }
142+
123143 /**
124144 * Rewrite a single ES6 module file to a global script version.
125145 */
126- public void processFile (Node root ) {
146+ private void processFile (Node root ) {
127147 Preconditions .checkArgument (isEs6ModuleRoot (root ), root );
128- this . forceRewrite = true ;
148+ clearState () ;
129149 NodeTraversal .traverseEs6 (compiler , root , this );
130150 }
131151
152+ public void clearState () {
153+ this .scriptNodeCount = 0 ;
154+ this .exportMap = new LinkedHashMap <>();
155+ this .importMap = new HashMap <>();
156+ this .classes = new HashSet <>();
157+ this .typedefs = new HashSet <>();
158+ this .alreadyRequired = new HashSet <>();
159+ this .forceRewrite = true ;
160+ this .googRequireInsertSpot = null ;
161+ }
162+
132163 /**
133164 * Avoid processing if we find the appearance of goog.provide or goog.module.
134165 *
@@ -284,8 +315,7 @@ private void visitExport(NodeTraversal t, Node export, Node parent) {
284315 }
285316
286317 if (name != null ) {
287- Node decl = child .cloneTree ();
288- decl .setJSDocInfo (child .getJSDocInfo ());
318+ Node decl = child .detach ();
289319 parent .replaceChild (export , decl );
290320 exportMap .put ("default" , new NameNodePair (name , child ));
291321 } else {
@@ -556,6 +586,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
556586 n .setString (newName );
557587 n .setOriginalName (name );
558588 }
589+ t .reportCodeChange (n );
559590 } else if (var == null && importMap .containsKey (name )) {
560591 // Change to property access on the imported module object.
561592 if (parent .isCall () && parent .getFirstChild () == n ) {
@@ -571,6 +602,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
571602 IR .getprop (moduleAccess , IR .string (pair .originalName ))
572603 .useSourceInfoIfMissingFromForTree (n ));
573604 }
605+ t .reportCodeChange (moduleAccess );
574606 }
575607 }
576608 }
0 commit comments