Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(325)

Side by Side Diff: lib/src/codegen/module_builder.dart

Issue 1633003002: Add --modules=node support (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: merged master Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/codegen/js_codegen.dart ('k') | lib/src/compiler.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dev_compiler.src.codegen.module_builder; 5 library dev_compiler.src.codegen.module_builder;
6 6
7 import 'package:path/path.dart' as path; 7 import 'package:path/path.dart' as path;
8 8
9 import '../js/js_ast.dart' as JS; 9 import '../js/js_ast.dart' as JS;
10 import '../js/js_ast.dart' show js; 10 import '../js/js_ast.dart' show js;
11 import '../options.dart' show ModuleFormat; 11 import '../options.dart' show ModuleFormat;
12 12
13 /// Helper that builds JS modules in a given [ModuleFormat]. 13 /// Helper that builds JS modules in a given [ModuleFormat].
14 abstract class ModuleBuilder { 14 abstract class ModuleBuilder {
15 final List<String> _exports = <String>[]; 15 final _exports = <String, String>{};
16 final List<_ModuleImport> _imports = <_ModuleImport>[]; 16 final _imports = <_ModuleImport>[];
17 17
18 ModuleBuilder._(); 18 ModuleBuilder._();
19 19
20 /// Returns a [format]-specific [ModuleBuilder]. 20 /// Returns a [format]-specific [ModuleBuilder].
21 /// - [jsPath] is the path of the module being built. 21 /// - [jsPath] is the path of the module being built.
22 /// - [jsModuleValue] is the default value to use for the library, in case of 22 /// - [jsModuleValue] is the default value to use for the library, in case of
23 /// js interop (comes from the @js.JS(jsModuleValue) annotation on the 23 /// js interop (comes from the @js.JS(jsModuleValue) annotation on the
24 /// library directive). It is null in any other case. 24 /// library directive). It is null in any other case.
25 /// - [exportsVar] is the name of the object on which items are exported. Lazy 25 /// - [exportsVar] is the name of the object on which items are exported. Lazy
26 /// variables and constants are assumed to be declared on this instance. 26 /// variables and constants are assumed to be declared on this instance.
27 factory ModuleBuilder(ModuleFormat format) { 27 factory ModuleBuilder(ModuleFormat format) {
28 switch (format) { 28 switch (format) {
29 case ModuleFormat.legacy: 29 case ModuleFormat.legacy:
30 return new LegacyModuleBuilder(); 30 return new LegacyModuleBuilder();
31 case ModuleFormat.es6: 31 case ModuleFormat.es6:
32 return new ES6ModuleBuilder(); 32 return new ES6ModuleBuilder();
33 case ModuleFormat.node:
34 return new NodeModuleBuilder();
33 } 35 }
34 } 36 }
35 37
36 /// Adds [name] to the list of names to be exported from the module. 38 /// Adds [name] to the list of names to be exported from the module.
37 void addExport(String name) { 39 void addExport(String name, String exportName) {
38 _exports.add(name); 40 _exports[name] = exportName;
39 } 41 }
40 42
41 /// Adds an import from a module named [name] and locally aliased as [libVar]. 43 /// Adds an import from a module named [name] and locally aliased as [libVar].
42 /// When [isLazy] is true, the import should be lazy (i.e. there is some 44 /// When [isLazy] is `true`, the import should be lazy (i.e. there is some
43 /// cyclic dependency of imports). 45 /// cyclic dependency of imports).
46 /// When [libVar] is `null`, the import is there just to force the import
47 /// order.
44 void addImport(String name, JS.Identifier libVar, {bool isLazy: false}) { 48 void addImport(String name, JS.Identifier libVar, {bool isLazy: false}) {
45 _imports.add(new _ModuleImport(name, libVar, isLazy)); 49 _imports.add(new _ModuleImport(name, libVar, isLazy));
46 } 50 }
47 51
48 /// Builds a program out of menu items. 52 /// Builds a program out of menu items.
49 JS.Program build(String jsPath, String jsModuleValue, 53 JS.Program build(String jsPath, String jsModuleValue,
50 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems); 54 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems);
51 } 55 }
52 56
53 class _ModuleImport { 57 class _ModuleImport {
54 final String name; 58 final String name;
55 final JS.Identifier libVar; 59 final JS.Identifier libVar;
56 // TODO(jmesserly): Assess whether we can remove this (we shouldn't need it 60 // TODO(jmesserly): Assess whether we can remove this (we shouldn't need it
57 // even in our legacy module format, but it might still be useful for Closure 61 // even in our legacy module format, but it might still be useful for Closure
58 // with ES6 modules). 62 // with ES6 modules).
59 final bool isLazy; 63 final bool isLazy;
60 _ModuleImport(this.name, this.libVar, this.isLazy); 64 _ModuleImport(this.name, this.libVar, this.isLazy);
61 } 65 }
62 66
63 /// Generates modules for with DDC's `dart_library.js` loading mechanism. 67 /// Generates modules for with DDC's `dart_library.js` loading mechanism.
64 class LegacyModuleBuilder extends ModuleBuilder { 68 class LegacyModuleBuilder extends ModuleBuilder {
65 LegacyModuleBuilder() : super._(); 69 LegacyModuleBuilder() : super._();
66 70
67 JS.Program build(String jsPath, String jsModuleValue, 71 JS.Program build(String jsPath, String jsModuleValue,
68 JS.Identifier exportsVar, List<JS.ModuleItem> moduleItems) { 72 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
69 // TODO(jmesserly): it would be great to run the renamer on the body, 73 // TODO(jmesserly): it would be great to run the renamer on the body,
70 // then figure out if we really need each of these parameters. 74 // then figure out if we really need each of these parameters.
71 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 75 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
72 var params = [exportsVar]; 76 var params = [exportsVar];
73 var lazyParams = []; 77 var lazyParams = [];
74 78
75 var imports = <JS.Expression>[]; 79 var imports = <JS.Expression>[];
76 var lazyImports = <JS.Expression>[]; 80 var lazyImports = <JS.Expression>[];
77 var moduleStatements = <JS.Statement>[]; 81 var moduleStatements = <JS.Statement>[];
78 82
79 for (var i in _imports) { 83 for (var i in _imports) {
84 // No need to force the import order for the legacy library mechanism.
85 if (i.libVar == null) continue;
80 (i.isLazy ? lazyImports : imports).add(js.string(i.name, "'")); 86 (i.isLazy ? lazyImports : imports).add(js.string(i.name, "'"));
81 (i.isLazy ? lazyParams : params).add(i.libVar); 87 (i.isLazy ? lazyParams : params).add(i.libVar);
82 } 88 }
83 params.addAll(lazyParams); 89 params.addAll(lazyParams);
84 90
85 moduleStatements.addAll(_flattenBlocks(moduleItems)); 91 moduleStatements.addAll(_flattenBlocks(moduleItems));
86 92
87 if (_exports.isNotEmpty) { 93 if (_exports.isNotEmpty) {
88 moduleStatements.add(js.comment('Exports:')); 94 moduleStatements.add(js.comment('Exports:'));
89 // TODO(jmesserly): make these immutable in JS? 95 // TODO(jmesserly): make these immutable in JS?
90 for (var name in _exports) { 96 _exports.forEach((name, exportName) {
91 moduleStatements 97 moduleStatements
92 .add(js.statement('#.# = #;', [exportsVar, name, name])); 98 .add(js.statement('#.# = #;', [exportsVar, exportName, name]));
93 } 99 });
94 } 100 }
95 101
96 var module = 102 var module =
97 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]); 103 js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
98 104
99 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [ 105 var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
100 js.string(jsPath, "'"), 106 js.string(jsPath, "'"),
101 jsModuleValue ?? new JS.LiteralNull(), 107 jsModuleValue ?? new JS.LiteralNull(),
102 js.commentExpression( 108 js.commentExpression(
103 "Imports", new JS.ArrayInitializer(imports, multiline: true)), 109 "Imports", new JS.ArrayInitializer(imports, multiline: true)),
(...skipping 12 matching lines...) Expand all
116 } 122 }
117 123
118 /// Generates ES6 modules. 124 /// Generates ES6 modules.
119 // TODO(ochafik): Break strong dep cycles to accommodate the Closure Compiler. 125 // TODO(ochafik): Break strong dep cycles to accommodate the Closure Compiler.
120 class ES6ModuleBuilder extends ModuleBuilder { 126 class ES6ModuleBuilder extends ModuleBuilder {
121 ES6ModuleBuilder() : super._(); 127 ES6ModuleBuilder() : super._();
122 128
123 JS.Program build(String jsPath, String jsModuleValue, 129 JS.Program build(String jsPath, String jsModuleValue,
124 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) { 130 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
125 var moduleStatements = <JS.ModuleItem>[ 131 var moduleStatements = <JS.ModuleItem>[
126 // Lazy declarations may reference exports.
127 js.statement("const # = {};", [exportsVar]) 132 js.statement("const # = {};", [exportsVar])
128 ]; 133 ];
129 134
130 // TODO(jmesserly): it would be great to run the renamer on the body, 135 // TODO(jmesserly): it would be great to run the renamer on the body,
131 // then figure out if we really need each of these parameters. 136 // then figure out if we really need each of these parameters.
132 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34 137 // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
133 for (var i in _imports) { 138 for (var i in _imports) {
134 var moduleName = js.string(_relativeModuleName(i.name, from: jsPath)); 139 var moduleName = js.string(_relativeModuleName(i.name, from: jsPath));
135 // TODO(ochafik): laziness, late binding, etc, to support Closure... 140 // TODO(ochafik): laziness, late binding, etc, to support Closure...
136 moduleStatements.add( 141 if (i.libVar == null) {
137 new JS.ImportDeclaration(defaultBinding: i.libVar, from: moduleName)); 142 moduleStatements
143 .add(new JS.ImportDeclaration(namedImports: [], from: moduleName));
144 } else {
145 moduleStatements.add(new JS.ImportDeclaration(
146 defaultBinding: i.libVar, from: moduleName));
147 }
138 } 148 }
139 149
140 moduleStatements.addAll(_flattenBlocks(moduleItems)); 150 moduleStatements.addAll(_flattenBlocks(moduleItems));
141 151
142 if (_exports.isNotEmpty) { 152 if (_exports.isNotEmpty) {
143 moduleStatements.add(js.comment('Exports:')); 153 moduleStatements.add(js.comment('Exports:'));
144 // TODO(jmesserly): make these immutable in JS? 154 // TODO(jmesserly): make these immutable in JS?
145 for (var name in _exports) { 155 _exports.forEach((name, exportName) {
146 moduleStatements 156 moduleStatements
147 .add(js.statement('#.# = #;', [exportsVar, name, name])); 157 .add(js.statement('#.# = #;', [exportsVar, exportName, name]));
148 } 158 });
149 moduleStatements 159 moduleStatements
150 .add(new JS.ExportDeclaration(exportsVar, isDefault: true)); 160 .add(new JS.ExportDeclaration(exportsVar, isDefault: true));
151 } 161 }
152 // TODO(ochafik): What to do of jsModuleValue? 162 // TODO(ochafik): What to do with jsModuleValue?
153 return new JS.Program(moduleStatements); 163 return new JS.Program(moduleStatements);
154 } 164 }
155 } 165 }
166
167 /// Generates node modules.
168 class NodeModuleBuilder extends ModuleBuilder {
169 NodeModuleBuilder() : super._();
170
171 JS.Program build(String jsPath, String jsModuleValue,
172 JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
173 var moduleStatements = <JS.ModuleItem>[js.statement("'use strict';"),];
174
175 for (var i in _imports) {
176 if (i.libVar == null) {
177 moduleStatements.add(js.statement('require(#);', [js.string(i.name)]));
178 } else {
179 moduleStatements.add(
180 js.statement('let # = require(#);', [i.libVar, js.string(i.name)]));
181 }
182 }
183
184 moduleStatements.addAll(_flattenBlocks(moduleItems));
185
186 if (_exports.isNotEmpty) {
187 moduleStatements.add(js.comment('Exports:'));
188 _exports.forEach((name, exportName) {
189 moduleStatements
190 .add(js.statement('#.# = #;', [exportsVar, exportName, name]));
191 });
192 }
193 // TODO(ochafik): What to do with jsModuleValue?
194 // (something like `let exports = jsModuleValue;`?)
195 return new JS.Program(moduleStatements);
196 }
197 }
156 198
157 /// Flattens blocks in [stats] to a single list of module items. 199 /// Flattens blocks in [stats] to a single list of module items.
158 /// Note that in general, blocks should not be flattened, because it can 200 /// Note that in general, blocks should not be flattened, because it can
159 /// mess up with block-level scoping (let, const). 201 /// mess up with block-level scoping (let, const).
160 // TODO(ochafik): Remove this / find better pattern (adding statements as they 202 // TODO(ochafik): Remove this / find better pattern (adding statements as they
161 // are generated from [JSCodegenVisitor], instead of composing them with 203 // are generated from [JSCodegenVisitor], instead of composing them with
162 // [_statements]). 204 // [_statements]).
163 Iterable<JS.ModuleItem> _flattenBlocks(List<JS.ModuleItem> stats) => 205 Iterable<JS.ModuleItem> _flattenBlocks(List<JS.ModuleItem> stats) =>
164 stats.expand( 206 stats.expand(
165 (item) => item is JS.Block ? _flattenBlocks(item.statements) : [item]); 207 (item) => item is JS.Block ? _flattenBlocks(item.statements) : [item]);
OLDNEW
« no previous file with comments | « lib/src/codegen/js_codegen.dart ('k') | lib/src/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698