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

Side by Side Diff: lib/src/compiler/compiler.dart

Issue 2249233002: fix #626, add AMD module format and make it default (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: merged Created 4 years, 3 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/compiler/command.dart ('k') | lib/src/compiler/module_builder.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) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 import 'dart:collection' show HashSet, Queue; 5 import 'dart:collection' show HashSet, Queue;
6 import 'dart:convert' show JSON;
7 import 'dart:io' show File;
6 import 'package:analyzer/dart/element/element.dart' show LibraryElement; 8 import 'package:analyzer/dart/element/element.dart' show LibraryElement;
7 import 'package:analyzer/analyzer.dart' 9 import 'package:analyzer/analyzer.dart'
8 show AnalysisError, CompilationUnit, ErrorSeverity; 10 show AnalysisError, CompilationUnit, ErrorSeverity;
9 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; 11 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
10 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
11 import 'package:analyzer/src/generated/source.dart' show DartUriResolver; 13 import 'package:analyzer/src/generated/source.dart' show DartUriResolver;
12 import 'package:analyzer/src/generated/source_io.dart' 14 import 'package:analyzer/src/generated/source_io.dart'
13 show Source, SourceKind, UriResolver; 15 show Source, SourceKind, UriResolver;
14 import 'package:analyzer/src/summary/package_bundle_reader.dart' 16 import 'package:analyzer/src/summary/package_bundle_reader.dart'
15 show InSummarySource; 17 show InSummarySource;
16 import 'package:args/args.dart' show ArgParser, ArgResults; 18 import 'package:args/args.dart' show ArgParser, ArgResults;
17 import 'package:args/src/usage_exception.dart' show UsageException; 19 import 'package:args/src/usage_exception.dart' show UsageException;
18 import 'package:func/func.dart' show Func1; 20 import 'package:func/func.dart' show Func1;
19 import 'package:path/path.dart' as path; 21 import 'package:path/path.dart' as path;
22 import 'package:source_maps/source_maps.dart';
20 23
21 import '../analyzer/context.dart' 24 import '../analyzer/context.dart'
22 show AnalyzerOptions, createAnalysisContextWithSources; 25 show AnalyzerOptions, createAnalysisContextWithSources;
23 import 'extension_types.dart' show ExtensionTypeSet; 26 import '../js_ast/js_ast.dart' as JS;
24 import 'code_generator.dart' show CodeGenerator; 27 import 'code_generator.dart' show CodeGenerator;
25 import 'error_helpers.dart' show errorSeverity, formatError, sortErrors; 28 import 'error_helpers.dart' show errorSeverity, formatError, sortErrors;
29 import 'extension_types.dart' show ExtensionTypeSet;
30 import 'js_names.dart' as JS;
31 import 'module_builder.dart' show transformModuleFormat, ModuleFormat;
32 import 'source_map_printer.dart' show SourceMapPrintingContext;
26 33
27 /// Compiles a set of Dart files into a single JavaScript module. 34 /// Compiles a set of Dart files into a single JavaScript module.
28 /// 35 ///
29 /// For a single [BuildUnit] definition, this will produce a [JSModuleFile]. 36 /// For a single [BuildUnit] definition, this will produce a [JSModuleFile].
30 /// Those objects are record types that record the data consumed and produced 37 /// Those objects are record types that record the data consumed and produced
31 /// for a single compile. 38 /// for a single compile.
32 /// 39 ///
33 /// This class exists to cache global state associated with a single in-memory 40 /// This class exists to cache global state associated with a single in-memory
34 /// AnalysisContext, such as information about extension types in the Dart SDK. 41 /// AnalysisContext, such as information about extension types in the Dart SDK.
35 /// It can be used once to produce a single module, or reused to save warm-up 42 /// It can be used once to produce a single module, or reused to save warm-up
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 135
129 sortErrors(context, errors); 136 sortErrors(context, errors);
130 var messages = <String>[]; 137 var messages = <String>[];
131 for (var e in errors) { 138 for (var e in errors) {
132 var m = formatError(context, e); 139 var m = formatError(context, e);
133 if (m != null) messages.add(m); 140 if (m != null) messages.add(m);
134 } 141 }
135 142
136 if (!options.unsafeForceCompile && 143 if (!options.unsafeForceCompile &&
137 errors.any((e) => errorSeverity(context, e) == ErrorSeverity.ERROR)) { 144 errors.any((e) => errorSeverity(context, e) == ErrorSeverity.ERROR)) {
138 return new JSModuleFile.invalid(unit.name, messages); 145 return new JSModuleFile.invalid(unit.name, messages, options);
139 } 146 }
140 147
141 var codeGenerator = new CodeGenerator(context, options, _extensionTypes); 148 var codeGenerator = new CodeGenerator(context, options, _extensionTypes);
142 return codeGenerator.compile(unit, trees, messages); 149 return codeGenerator.compile(unit, trees, messages);
143 } 150 }
144 } 151 }
145 152
146 enum ModuleFormat { es6, legacy, node }
147
148 ModuleFormat parseModuleFormat(String s) => {
149 'es6': ModuleFormat.es6,
150 'node': ModuleFormat.node,
151 'legacy': ModuleFormat.legacy
152 }[s];
153
154 class CompilerOptions { 153 class CompilerOptions {
155 /// Whether to emit the source mapping file. 154 /// Whether to emit the source mapping file.
156 /// 155 ///
157 /// This supports debugging the original source code instead of the generated 156 /// This supports debugging the original source code instead of the generated
158 /// code. 157 /// code.
159 final bool sourceMap; 158 final bool sourceMap;
160 159
161 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment 160 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment
162 /// into the output JavaScript module. 161 /// into the output JavaScript module.
163 final bool sourceMapComment; 162 final bool sourceMapComment;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 /// Supporting the syntax: 201 /// Supporting the syntax:
203 /// * Chrome Canary (51) 202 /// * Chrome Canary (51)
204 /// * Firefox 203 /// * Firefox
205 /// 204 ///
206 /// Not yet supporting: 205 /// Not yet supporting:
207 /// * Atom (1.5.4) 206 /// * Atom (1.5.4)
208 /// * Electron (0.36.3) 207 /// * Electron (0.36.3)
209 // TODO(ochafik): Simplify this code when our target platforms catch up. 208 // TODO(ochafik): Simplify this code when our target platforms catch up.
210 final bool destructureNamedParams; 209 final bool destructureNamedParams;
211 210
212 /// Which module format to support.
213 /// Currently 'es6' and 'legacy' are supported.
214 final ModuleFormat moduleFormat;
215
216 const CompilerOptions( 211 const CompilerOptions(
217 {this.sourceMap: true, 212 {this.sourceMap: true,
218 this.sourceMapComment: true, 213 this.sourceMapComment: true,
219 this.summarizeApi: true, 214 this.summarizeApi: true,
220 this.summaryExtension: 'sum', 215 this.summaryExtension: 'sum',
221 this.unsafeForceCompile: false, 216 this.unsafeForceCompile: false,
222 this.emitMetadata: false, 217 this.emitMetadata: false,
223 this.closure: false, 218 this.closure: false,
224 this.destructureNamedParams: false, 219 this.destructureNamedParams: false,
225 this.moduleFormat: ModuleFormat.legacy,
226 this.hoistInstanceCreation: true, 220 this.hoistInstanceCreation: true,
227 this.hoistSignatureTypes: false, 221 this.hoistSignatureTypes: false,
228 this.nameTypeTests: true, 222 this.nameTypeTests: true,
229 this.hoistTypeTests: true, 223 this.hoistTypeTests: true,
230 this.useAngular2Whitelist: false}); 224 this.useAngular2Whitelist: false});
231 225
232 CompilerOptions.fromArguments(ArgResults args) 226 CompilerOptions.fromArguments(ArgResults args)
233 : sourceMap = args['source-map'], 227 : sourceMap = args['source-map'],
234 sourceMapComment = args['source-map-comment'], 228 sourceMapComment = args['source-map-comment'],
235 summarizeApi = args['summarize'], 229 summarizeApi = args['summarize'],
236 summaryExtension = args['summary-extension'], 230 summaryExtension = args['summary-extension'],
237 unsafeForceCompile = args['unsafe-force-compile'], 231 unsafeForceCompile = args['unsafe-force-compile'],
238 emitMetadata = args['emit-metadata'], 232 emitMetadata = args['emit-metadata'],
239 closure = args['closure-experimental'], 233 closure = args['closure-experimental'],
240 destructureNamedParams = args['destructure-named-params'], 234 destructureNamedParams = args['destructure-named-params'],
241 moduleFormat = parseModuleFormat(args['modules']),
242 hoistInstanceCreation = args['hoist-instance-creation'], 235 hoistInstanceCreation = args['hoist-instance-creation'],
243 hoistSignatureTypes = args['hoist-signature-types'], 236 hoistSignatureTypes = args['hoist-signature-types'],
244 nameTypeTests = args['name-type-tests'], 237 nameTypeTests = args['name-type-tests'],
245 hoistTypeTests = args['hoist-type-tests'], 238 hoistTypeTests = args['hoist-type-tests'],
246 useAngular2Whitelist = args['unsafe-angular2-whitelist']; 239 useAngular2Whitelist = args['unsafe-angular2-whitelist'];
247 240
248 static void addArguments(ArgParser parser) { 241 static void addArguments(ArgParser parser) {
249 parser 242 parser
250 ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true) 243 ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true)
251 ..addOption('summary-extension', 244 ..addOption('summary-extension',
252 help: 'file extension for Dart summary files', 245 help: 'file extension for Dart summary files',
253 defaultsTo: 'sum', 246 defaultsTo: 'sum',
254 hide: true) 247 hide: true)
255 ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true) 248 ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true)
256 ..addFlag('source-map-comment', 249 ..addFlag('source-map-comment',
257 help: 'adds a sourceMappingURL comment to the end of the JS,\n' 250 help: 'adds a sourceMappingURL comment to the end of the JS,\n'
258 'disable if using X-SourceMap header', 251 'disable if using X-SourceMap header',
259 defaultsTo: true, 252 defaultsTo: true,
260 hide: true) 253 hide: true)
261 ..addOption('modules',
262 help: 'module pattern to emit',
263 allowed: ['es6', 'legacy', 'node'],
264 allowedHelp: {
265 'es6': 'es6 modules',
266 'legacy': 'a custom format used by dartdevc, similar to AMD',
267 'node': 'node.js modules (https://nodejs.org/api/modules.html)'
268 },
269 defaultsTo: 'legacy')
270 ..addFlag('emit-metadata', 254 ..addFlag('emit-metadata',
271 help: 'emit metadata annotations queriable via mirrors', 255 help: 'emit metadata annotations queriable via mirrors',
272 defaultsTo: false) 256 defaultsTo: false)
273 ..addFlag('closure-experimental', 257 ..addFlag('closure-experimental',
274 help: 'emit Closure Compiler-friendly code (experimental)', 258 help: 'emit Closure Compiler-friendly code (experimental)',
275 defaultsTo: false) 259 defaultsTo: false)
276 ..addFlag('destructure-named-params', 260 ..addFlag('destructure-named-params',
277 help: 'Destructure named parameters', defaultsTo: false, hide: true) 261 help: 'Destructure named parameters', defaultsTo: false, hide: true)
278 ..addFlag('unsafe-force-compile', 262 ..addFlag('unsafe-force-compile',
279 help: 'Compile code even if it has errors. ಠ_ಠ\n' 263 help: 'Compile code even if it has errors. ಠ_ಠ\n'
(...skipping 14 matching lines...) Expand all
294 help: 'Hoist types used in type tests', defaultsTo: true, hide: true) 278 help: 'Hoist types used in type tests', defaultsTo: true, hide: true)
295 ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true); 279 ..addFlag('unsafe-angular2-whitelist', defaultsTo: false, hide: true);
296 } 280 }
297 } 281 }
298 282
299 /// A unit of Dart code that can be built into a single JavaScript module. 283 /// A unit of Dart code that can be built into a single JavaScript module.
300 class BuildUnit { 284 class BuildUnit {
301 /// The name of this module. 285 /// The name of this module.
302 final String name; 286 final String name;
303 287
304 /// Library root. All library names are relative to this path/prefix. 288 /// All library names are relative to this path/prefix.
305 final String libraryRoot; 289 final String libraryRoot;
306 290
307 /// The list of sources in this module. 291 /// The list of sources in this module.
308 /// 292 ///
309 /// The set of Dart files can be arbitrarily large, but it must contain 293 /// The set of Dart files can be arbitrarily large, but it must contain
310 /// complete libraries including all of their parts, as well as all libraries 294 /// complete libraries including all of their parts, as well as all libraries
311 /// that are part of a library cycle. 295 /// that are part of a library cycle.
312 final List<String> sources; 296 final List<String> sources;
313 297
314 /// Given an imported library URI, this will determine to what Dart/JS module 298 /// Given an imported library URI, this will determine to what Dart/JS module
315 /// it belongs to. 299 /// it belongs to.
316 // TODO(jmesserly): we should replace this with another way of tracking 300 // TODO(jmesserly): we should replace this with another way of tracking
317 // build units. 301 // build units.
318 final Func1<Source, String> libraryToModule; 302 final Func1<Source, String> libraryToModule;
319 303
320 BuildUnit(this.name, this.libraryRoot, this.sources, this.libraryToModule); 304 BuildUnit(this.name, this.libraryRoot, this.sources, this.libraryToModule);
321 } 305 }
322 306
323 /// The output of Dart->JS compilation. 307 /// The output of Dart->JS compilation.
324 /// 308 ///
325 /// This contains the file contents of the JS module, as well as a list of 309 /// This contains the file contents of the JS module, as well as a list of
326 /// Dart libraries that are contained in this module. 310 /// Dart libraries that are contained in this module.
327 class JSModuleFile { 311 class JSModuleFile {
328 /// The name of this module. 312 /// The name of this module.
329 final String name; 313 final String name;
330 314
331 /// The list of messages (errors and warnings) 315 /// The list of messages (errors and warnings)
332 final List<String> errors; 316 final List<String> errors;
333 317
318 /// The AST that will be used to generate the [code] and [sourceMap] for this
319 /// module.
320 final JS.Program moduleTree;
321
322 /// The compiler options used to generate this module.
323 final CompilerOptions options;
324
325 /// The binary contents of the API summary file, including APIs from each of
326 /// the libraries in this module.
327 final List<int> summaryBytes;
328
329 JSModuleFile(
330 this.name, this.errors, this.options, this.moduleTree, this.summaryBytes);
331
332 JSModuleFile.invalid(this.name, this.errors, this.options)
333 : moduleTree = null,
334 summaryBytes = null;
335
336 /// True if this library was successfully compiled.
337 bool get isValid => moduleTree != null;
338
339 /// Gets the source code and source map for this JS module, given the
340 /// locations where the JS file and map file will be served from.
341 ///
342 /// Relative URLs will be used to point from the .js file to the .map file
343 //
344 // TODO(jmesserly): this should match our old logic, but I'm not sure we are
345 // correctly handling the pointer from the .js file to the .map file.
346 JSModuleCode getCode(ModuleFormat format, String jsUrl, String mapUrl) {
347 var opts = new JS.JavaScriptPrintingOptions(
348 emitTypes: options.closure,
349 allowKeywordsInProperties: true,
350 allowSingleLineIfStatements: true);
351 JS.SimpleJavaScriptPrintingContext printer;
352 SourceMapBuilder sourceMap;
353 if (options.sourceMap) {
354 var sourceMapContext = new SourceMapPrintingContext();
355 sourceMap = sourceMapContext.sourceMap;
356 printer = sourceMapContext;
357 } else {
358 printer = new JS.SimpleJavaScriptPrintingContext();
359 }
360
361 var tree = transformModuleFormat(format, moduleTree);
362 tree.accept(
363 new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree)));
364
365 if (options.sourceMap && options.sourceMapComment) {
366 printer.emit('\n//# sourceMappingURL=$mapUrl\n');
367 }
368
369 Map builtMap;
370 if (sourceMap != null) {
371 builtMap = placeSourceMap(sourceMap.build(jsUrl), mapUrl);
372 }
373 return new JSModuleCode(printer.getText(), builtMap);
374 }
375
376 /// Similar to [getCode] but immediately writes the resulting files.
377 ///
378 /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath
379 /// will default to [jsPath].map.
380 void writeCodeSync(ModuleFormat format, String jsPath, [String mapPath]) {
381 if (mapPath == null) mapPath = jsPath + '.map';
382 var code = getCode(format, jsPath, mapPath);
383 new File(jsPath).writeAsStringSync(code.code);
384 if (code.sourceMap != null) {
385 new File(mapPath).writeAsStringSync(JSON.encode(code.sourceMap));
386 }
387 }
388 }
389
390 /// The output of compiling a JavaScript module in a particular format.
391 class JSModuleCode {
334 /// The JavaScript code for this module. 392 /// The JavaScript code for this module.
335 /// 393 ///
336 /// If a [sourceMap] is available, this will include the `sourceMappingURL` 394 /// If a [sourceMap] is available, this will include the `sourceMappingURL`
337 /// comment at end of the file. 395 /// comment at end of the file.
338 final String code; 396 final String code;
339 397
340 /// The JSON of the source map, if generated, otherwise `null`. 398 /// The JSON of the source map, if generated, otherwise `null`.
341 /// 399 ///
342 /// The source paths will initially be absolute paths. They can be adjusted 400 /// The source paths will initially be absolute paths. They can be adjusted
343 /// using [placeSourceMap]. 401 /// using [placeSourceMap].
344 final Map sourceMap; 402 final Map sourceMap;
345 403
346 /// The binary contents of the API summary file, including APIs from each of 404 JSModuleCode(this.code, this.sourceMap);
347 /// the [libraries] in this module. 405 }
348 final List<int> summaryBytes;
349 406
350 JSModuleFile( 407 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
351 this.name, this.errors, this.code, this.sourceMap, this.summaryBytes); 408 /// and returns the new map.
409 // TODO(jmesserly): find a new home for this.
410 Map placeSourceMap(Map sourceMap, String sourceMapPath) {
411 var dir = path.dirname(sourceMapPath);
352 412
353 JSModuleFile.invalid(this.name, this.errors) 413 var map = new Map.from(sourceMap);
354 : code = null, 414 List list = new List.from(map['sources']);
355 sourceMap = null, 415 map['sources'] = list;
356 summaryBytes = null; 416 for (int i = 0; i < list.length; i++) {
357 417 list[i] =
358 /// True if this library was successfully compiled. 418 path.toUri(path.relative(path.fromUri(list[i]), from: dir)).toString();
359 bool get isValid => code != null;
360
361 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
362 /// and returns the new map.
363 ///
364 /// See also [writeSourceMap].
365 Map placeSourceMap(String sourceMapPath) {
366 var dir = path.dirname(sourceMapPath);
367
368 var map = new Map.from(this.sourceMap);
369 List list = new List.from(map['sources']);
370 map['sources'] = list;
371 for (int i = 0; i < list.length; i++) {
372 list[i] = path.relative(list[i], from: dir);
373 }
374 return map;
375 } 419 }
420 return map;
376 } 421 }
OLDNEW
« no previous file with comments | « lib/src/compiler/command.dart ('k') | lib/src/compiler/module_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698