fix #626, add AMD module format and make it default

R=nweiz@google.com, vsm@google.com

Review URL: https://codereview.chromium.org/2249233002 .
This commit is contained in:
John Messerly 2016-08-25 09:39:36 -07:00
parent 87577db2b2
commit c1139934a7
36 changed files with 256754 additions and 3784 deletions

View file

@ -17,8 +17,8 @@ doc/api/
# Generated files go here.
gen/
# Ignore generated summary.
lib/runtime/dart_sdk.sum
# Ignore generated SDK summary.
lib/js/*/*.sum
# Created by ./tool/dependency_overrides.sh.
dependency_overrides/

View file

@ -1,5 +1,10 @@
# dev_compiler changelog
## next release
- add support for AMD modules and make it the default.
- precompile the SDK in AMD, CommonJS, and ES6 flavors.
- legacy module format is deprecated.
## 0.1.24
- workaround breaking change on requestAnimationFrame

View file

@ -13,26 +13,17 @@ module.exports = function(config) {
// list of files / patterns to load in the browser
files: [
'lib/runtime/dart_*.js',
// {pattern: 'test/browser/*.js', included: false}
'gen/codegen_output/pkg/*.js',
'gen/codegen_output/language/**.js',
'gen/codegen_output/language/**.err',
'gen/codegen_output/corelib/**.js',
'gen/codegen_output/corelib/**.err',
'gen/codegen_output/lib/convert/**.js',
'gen/codegen_output/lib/html/**.js',
'gen/codegen_output/lib/math/**.js',
'gen/codegen_output/lib/mirrors/**.js',
'gen/codegen_output/lib/typed_data/**.js',
'gen/codegen_output/lib/*/**.err',
'test/browser/*.js',
{pattern: 'lib/js/amd/dart_sdk.js', included: false},
{pattern: 'gen/codegen_output/pkg/*.js', included: false},
{pattern: 'gen/codegen_output/language/**/*.js', included: false},
{pattern: 'gen/codegen_output/corelib/**/*.js', included: false},
{pattern: 'gen/codegen_output/lib/**/*.js', included: false},
{pattern: 'test/browser/*.js', included: false},
'test-main.js',
],
// list of files to exclude
exclude: [
],
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1466,7 +1466,7 @@ dart_library.library('dart_sdk', null, /* Imports */[
let src = '';
for (let i = 2; i < dart.notNull(stack[dartx.length]); ++i) {
let frame = stack[dartx.get](i);
if (!dart.test(frame[dartx.contains]('dev_compiler/lib/runtime/dart_sdk.js'))) {
if (!dart.test(frame[dartx.contains]('dart_sdk.js'))) {
src = frame;
break;
}

View file

@ -23,7 +23,6 @@ import 'package:analyzer/src/summary/summarize_elements.dart'
show PackageBundleAssembler;
import 'package:analyzer/src/task/strong/ast_properties.dart'
show isDynamicInvoke, setIsDynamicInvoke;
import 'package:source_maps/source_maps.dart';
import 'package:path/path.dart' show separator;
import '../closure/closure_annotator.dart' show ClosureAnnotator;
@ -31,7 +30,7 @@ import '../js_ast/js_ast.dart' as JS;
import '../js_ast/js_ast.dart' show js;
import 'ast_builder.dart' show AstBuilder;
import 'compiler.dart'
show BuildUnit, CompilerOptions, JSModuleFile, ModuleFormat;
show BuildUnit, CompilerOptions, JSModuleFile;
import 'element_helpers.dart';
import 'element_loader.dart' show ElementLoader;
import 'extension_types.dart' show ExtensionTypeSet;
@ -40,12 +39,10 @@ import 'js_interop.dart';
import 'js_metalet.dart' as JS;
import 'js_names.dart' as JS;
import 'js_typeref_codegen.dart' show JsTypeRefCodegen;
import 'module_builder.dart'
show LegacyModuleBuilder, NodeModuleBuilder, pathToJSIdentifier;
import 'module_builder.dart' show pathToJSIdentifier;
import 'nullable_type_inference.dart' show NullableTypeInference;
import 'reify_coercions.dart' show CoercionReifier;
import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless;
import 'source_map_printer.dart' show SourceMapPrintingContext;
import 'type_utilities.dart';
class CodeGenerator extends GeneralizingAstVisitor
@ -173,46 +170,21 @@ class CodeGenerator extends GeneralizingAstVisitor
_libraryRoot = '$_libraryRoot${separator}';
}
var jsTree = _emitModule(compilationUnits);
var codeAndSourceMap = _writeJSText(unit, jsTree);
var module = _emitModule(compilationUnits);
var dartApiSummary = _summarizeModule(compilationUnits);
List<int> summary;
if (options.summarizeApi) {
var assembler = new PackageBundleAssembler();
compilationUnits
.map((u) => u.element.library)
.toSet()
.forEach(assembler.serializeLibraryElement);
summary = assembler.assemble().toBuffer();
}
return new JSModuleFile(
unit.name, errors, codeAndSourceMap.e0, codeAndSourceMap.e1, summary);
return new JSModuleFile(unit.name, errors, options, module, dartApiSummary);
}
Tuple2<String, Map> _writeJSText(BuildUnit unit, JS.Program jsTree) {
var opts = new JS.JavaScriptPrintingOptions(
emitTypes: options.closure,
allowKeywordsInProperties: true,
allowSingleLineIfStatements: true);
JS.SimpleJavaScriptPrintingContext printer;
SourceMapBuilder sourceMap;
if (options.sourceMap) {
var sourceMapContext = new SourceMapPrintingContext();
sourceMap = sourceMapContext.sourceMap;
printer = sourceMapContext;
} else {
printer = new JS.SimpleJavaScriptPrintingContext();
}
List<int> _summarizeModule(List<CompilationUnit> compilationUnits) {
if (!options.summarizeApi) return null;
jsTree.accept(new JS.Printer(opts, printer,
localNamer: new JS.TemporaryNamer(jsTree)));
if (options.sourceMap && options.sourceMapComment) {
printer.emit('\n//# sourceMappingURL=${unit.name}.js.map\n');
}
return new Tuple2(printer.getText(), sourceMap?.build(unit.name + '.js'));
var assembler = new PackageBundleAssembler();
compilationUnits
.map((u) => u.element.library)
.toSet()
.forEach(assembler.serializeLibraryElement);
return assembler.assemble().toBuffer();
}
JS.Program _emitModule(List<CompilationUnit> compilationUnits) {
@ -284,18 +256,7 @@ class CodeGenerator extends GeneralizingAstVisitor
_copyAndFlattenBlocks(items, _moduleItems);
// Build the module.
var module = new JS.Program(items, name: _buildUnit.name);
// Optional: lower module format. Otherwise just return it.
switch (options.moduleFormat) {
case ModuleFormat.legacy:
return new LegacyModuleBuilder().build(module);
case ModuleFormat.node:
return new NodeModuleBuilder().build(module);
case ModuleFormat.es6:
return module;
}
return null; // unreachable. It is here to suppress a bogus Analyzer message
return new JS.Program(items, name: _buildUnit.name);
}
List<String> _getJSName(Element e) {
@ -1750,6 +1711,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var e = js.call('() => #', o);
return new JS.Property(_propertyName(name), e);
}
var sigFields = <JS.Property>[];
if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors));
if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods));
@ -3262,8 +3224,12 @@ class CodeGenerator extends GeneralizingAstVisitor
var vars = <JS.MetaLetVariable, JS.Expression>{};
var l = _visit(_bindValue(vars, 'l', target));
jsTarget = new JS.MetaLet(vars, [
js.call('(#[(#[dart._extensionType]) ? dartx[#] : #])',
[l, l, memberName, memberName,])
js.call('(#[(#[dart._extensionType]) ? dartx[#] : #])', [
l,
l,
memberName,
memberName,
])
]);
if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs);
return new JS.Call(jsTarget, args);
@ -3806,6 +3772,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var args = _visit(argumentList) as List<JS.Expression>;
return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args);
}
if (element != null && _isObjectLiteral(element.enclosingElement)) {
return _emitObjectLiteral(argumentList);
}
@ -4047,6 +4014,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
return null;
}
if (expr is SimpleIdentifier) {
return finishIdentifier(expr);
} else if (expr is PrefixedIdentifier && !expr.isDeferred) {
@ -4134,6 +4102,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (value != null) return value.bitLength;
return MAX;
}
return bitWidth(expr, 0) < 32;
}
@ -4924,6 +4893,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var name = js.string(node.components.join('.'), "'");
return js.call('#.new(#)', [_emitType(types.symbolType), name]);
}
return _emitConst(emitSymbol);
}
@ -4952,6 +4922,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
return list;
}
if (isConst) return _cacheConst(emitList);
return emitList();
}
@ -4990,6 +4961,7 @@ class CodeGenerator extends GeneralizingAstVisitor
}
return js.call('dart.map(#, #)', [mapArguments, types]);
}
if (node.constKeyword != null) return _emitConst(emitMap);
return emitMap();
}
@ -5066,6 +5038,7 @@ class CodeGenerator extends GeneralizingAstVisitor
JS.Expression finish(JS.Expression result) {
return annotate(result, node);
}
if (node is PrefixExpression && node.operator.lexeme == '!') {
return finish(js.call('!#', _visitTest(node.operand)));
}
@ -5077,6 +5050,7 @@ class CodeGenerator extends GeneralizingAstVisitor
return finish(js.call(code,
[_visitTest(node.leftOperand), _visitTest(node.rightOperand)]));
}
var op = node.operator.type.lexeme;
if (op == '&&') return shortCircuit('# && #');
if (op == '||') return shortCircuit('# || #');
@ -5141,7 +5115,7 @@ class CodeGenerator extends GeneralizingAstVisitor
/// x.get('hi')
/// x.set('hi', 123)
///
/// This follows the same pattern as EcmaScript 6 Map:
/// This follows the same pattern as ECMAScript 6 Map:
/// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map>
///
/// Unary minus looks like: `x['unary-']()`. Note that [unary] must be passed
@ -5294,8 +5268,16 @@ class CodeGenerator extends GeneralizingAstVisitor
/// within the file.
///
/// If the value is null, the entire file is whitelisted.
///
// TODO(jmesserly): why is this here, and what can we do to remove it?
//
// Hard coded lists are completely unnecessary -- if a feature is needed,
// metadata, type system features, or command line options are the right way
// to express it.
//
// As it is this is completely unsound and unmaintainable.
static Map<String, List<String>> _uncheckedWhitelist = {
'dom_renderer.dart': ['moveNodesAfterSibling',],
'dom_renderer.dart': ['moveNodesAfterSibling'],
'template_ref.dart': ['createEmbeddedView'],
'ng_class.dart': ['_applyIterableChanges'],
'ng_for.dart': ['_bulkRemove', '_bulkInsert'],
@ -5335,7 +5317,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
/// Choose a canonical name from the library element.
/// Choose a canonical name from the [library] element.
///
/// This never uses the library's name (the identifier in the `library`
/// declaration) as it doesn't have any meaningful rules enforced.
String jsLibraryName(String libraryRoot, LibraryElement library) {

View file

@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert' show JSON;
import 'dart:io';
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/summary/package_bundle_reader.dart'
@ -11,14 +10,16 @@ import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:args/command_runner.dart' show UsageException;
import 'package:path/path.dart' as path;
import '../analyzer/context.dart' show AnalyzerOptions;
import 'compiler.dart'
show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
import '../analyzer/context.dart' show AnalyzerOptions;
import 'module_builder.dart';
final ArgParser _argParser = () {
var argParser = new ArgParser()
..addFlag('help', abbr: 'h', help: 'Display this message.')
..addOption('out', abbr: 'o', help: 'Output file (required).')
..addOption('out',
abbr: 'o', allowMultiple: true, help: 'Output file (required).')
..addOption('module-root',
help: 'Root module directory.\n'
'Generated module paths are relative to this root.')
@ -27,6 +28,7 @@ final ArgParser _argParser = () {
'Generated library names are relative to this root.')
..addOption('build-root',
help: 'Deprecated in favor of --library-root', hide: true);
addModuleFormatOptions(argParser, allowMultiple: true);
AnalyzerOptions.addArguments(argParser);
CompilerOptions.addArguments(argParser);
return argParser;
@ -88,13 +90,21 @@ void _compile(ArgResults argResults, void printFn(Object obj)) {
printFn(_usageMessage);
return;
}
var outPath = argResults['out'];
var outPaths = argResults['out'] as List<String>;
var moduleFormats = parseModuleFormatOption(argResults);
if (outPath == null) {
if (outPaths.isEmpty) {
_usageException('Please include the output file location. For example:\n'
' -o PATH/TO/OUTPUT_FILE.js');
} else if (outPaths.length != moduleFormats.length) {
_usageException('Number of output files (${outPaths.length}) must match '
'number of module formats (${moduleFormats.length}).');
}
// TODO(jmesserly): for now the first one is special. This will go away once
// we've removed the "root" and "module name" variables.
var outPath = outPaths[0];
var libraryRoot = argResults['library-root'] as String;
libraryRoot ??= argResults['build-root'] as String;
if (libraryRoot != null) {
@ -126,17 +136,15 @@ void _compile(ArgResults argResults, void printFn(Object obj)) {
if (!module.isValid) throw new CompileErrorException();
// Write JS file, as well as source map and summary (if requested).
new File(outPath).writeAsStringSync(module.code);
if (module.sourceMap != null) {
var mapPath = outPath + '.map';
new File(mapPath)
.writeAsStringSync(JSON.encode(module.placeSourceMap(mapPath)));
}
if (module.summaryBytes != null) {
var summaryPath =
path.withoutExtension(outPath) + '.${compilerOpts.summaryExtension}';
new File(summaryPath).writeAsBytesSync(module.summaryBytes);
for (var i = 0; i < outPaths.length; i++) {
module.writeCodeSync(moduleFormats[i], outPaths[i]);
if (module.summaryBytes != null) {
var summaryPath =
path.withoutExtension(outPath) + '.${compilerOpts.summaryExtension}';
new File(summaryPath).writeAsBytesSync(module.summaryBytes);
}
}
}
String _moduleForLibrary(

View file

@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection' show HashSet, Queue;
import 'dart:convert' show JSON;
import 'dart:io' show File;
import 'package:analyzer/dart/element/element.dart' show LibraryElement;
import 'package:analyzer/analyzer.dart'
show AnalysisError, CompilationUnit, ErrorSeverity;
@ -17,12 +19,17 @@ import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:args/src/usage_exception.dart' show UsageException;
import 'package:func/func.dart' show Func1;
import 'package:path/path.dart' as path;
import 'package:source_maps/source_maps.dart';
import '../analyzer/context.dart'
show AnalyzerOptions, createAnalysisContextWithSources;
import 'extension_types.dart' show ExtensionTypeSet;
import '../js_ast/js_ast.dart' as JS;
import 'code_generator.dart' show CodeGenerator;
import 'error_helpers.dart' show errorSeverity, formatError, sortErrors;
import 'extension_types.dart' show ExtensionTypeSet;
import 'js_names.dart' as JS;
import 'module_builder.dart' show transformModuleFormat, ModuleFormat;
import 'source_map_printer.dart' show SourceMapPrintingContext;
/// Compiles a set of Dart files into a single JavaScript module.
///
@ -135,7 +142,7 @@ class ModuleCompiler {
if (!options.unsafeForceCompile &&
errors.any((e) => errorSeverity(context, e) == ErrorSeverity.ERROR)) {
return new JSModuleFile.invalid(unit.name, messages);
return new JSModuleFile.invalid(unit.name, messages, options);
}
var codeGenerator = new CodeGenerator(context, options, _extensionTypes);
@ -143,14 +150,6 @@ class ModuleCompiler {
}
}
enum ModuleFormat { es6, legacy, node }
ModuleFormat parseModuleFormat(String s) => {
'es6': ModuleFormat.es6,
'node': ModuleFormat.node,
'legacy': ModuleFormat.legacy
}[s];
class CompilerOptions {
/// Whether to emit the source mapping file.
///
@ -209,10 +208,6 @@ class CompilerOptions {
// TODO(ochafik): Simplify this code when our target platforms catch up.
final bool destructureNamedParams;
/// Which module format to support.
/// Currently 'es6' and 'legacy' are supported.
final ModuleFormat moduleFormat;
const CompilerOptions(
{this.sourceMap: true,
this.sourceMapComment: true,
@ -222,7 +217,6 @@ class CompilerOptions {
this.emitMetadata: false,
this.closure: false,
this.destructureNamedParams: false,
this.moduleFormat: ModuleFormat.legacy,
this.hoistInstanceCreation: true,
this.hoistSignatureTypes: false,
this.nameTypeTests: true,
@ -238,7 +232,6 @@ class CompilerOptions {
emitMetadata = args['emit-metadata'],
closure = args['closure-experimental'],
destructureNamedParams = args['destructure-named-params'],
moduleFormat = parseModuleFormat(args['modules']),
hoistInstanceCreation = args['hoist-instance-creation'],
hoistSignatureTypes = args['hoist-signature-types'],
nameTypeTests = args['name-type-tests'],
@ -258,15 +251,6 @@ class CompilerOptions {
'disable if using X-SourceMap header',
defaultsTo: true,
hide: true)
..addOption('modules',
help: 'module pattern to emit',
allowed: ['es6', 'legacy', 'node'],
allowedHelp: {
'es6': 'es6 modules',
'legacy': 'a custom format used by dartdevc, similar to AMD',
'node': 'node.js modules (https://nodejs.org/api/modules.html)'
},
defaultsTo: 'legacy')
..addFlag('emit-metadata',
help: 'emit metadata annotations queriable via mirrors',
defaultsTo: false)
@ -301,7 +285,7 @@ class BuildUnit {
/// The name of this module.
final String name;
/// Library root. All library names are relative to this path/prefix.
/// All library names are relative to this path/prefix.
final String libraryRoot;
/// The list of sources in this module.
@ -331,6 +315,80 @@ class JSModuleFile {
/// The list of messages (errors and warnings)
final List<String> errors;
/// The AST that will be used to generate the [code] and [sourceMap] for this
/// module.
final JS.Program moduleTree;
/// The compiler options used to generate this module.
final CompilerOptions options;
/// The binary contents of the API summary file, including APIs from each of
/// the libraries in this module.
final List<int> summaryBytes;
JSModuleFile(
this.name, this.errors, this.options, this.moduleTree, this.summaryBytes);
JSModuleFile.invalid(this.name, this.errors, this.options)
: moduleTree = null,
summaryBytes = null;
/// True if this library was successfully compiled.
bool get isValid => moduleTree != null;
/// Gets the source code and source map for this JS module, given the
/// locations where the JS file and map file will be served from.
///
/// Relative URLs will be used to point from the .js file to the .map file
//
// TODO(jmesserly): this should match our old logic, but I'm not sure we are
// correctly handling the pointer from the .js file to the .map file.
JSModuleCode getCode(ModuleFormat format, String jsUrl, String mapUrl) {
var opts = new JS.JavaScriptPrintingOptions(
emitTypes: options.closure,
allowKeywordsInProperties: true,
allowSingleLineIfStatements: true);
JS.SimpleJavaScriptPrintingContext printer;
SourceMapBuilder sourceMap;
if (options.sourceMap) {
var sourceMapContext = new SourceMapPrintingContext();
sourceMap = sourceMapContext.sourceMap;
printer = sourceMapContext;
} else {
printer = new JS.SimpleJavaScriptPrintingContext();
}
var tree = transformModuleFormat(format, moduleTree);
tree.accept(
new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree)));
if (options.sourceMap && options.sourceMapComment) {
printer.emit('\n//# sourceMappingURL=$mapUrl\n');
}
Map builtMap;
if (sourceMap != null) {
builtMap = placeSourceMap(sourceMap.build(jsUrl), mapUrl);
}
return new JSModuleCode(printer.getText(), builtMap);
}
/// Similar to [getCode] but immediately writes the resulting files.
///
/// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath
/// will default to [jsPath].map.
void writeCodeSync(ModuleFormat format, String jsPath, [String mapPath]) {
if (mapPath == null) mapPath = jsPath + '.map';
var code = getCode(format, jsPath, mapPath);
new File(jsPath).writeAsStringSync(code.code);
if (code.sourceMap != null) {
new File(mapPath).writeAsStringSync(JSON.encode(code.sourceMap));
}
}
}
/// The output of compiling a JavaScript module in a particular format.
class JSModuleCode {
/// The JavaScript code for this module.
///
/// If a [sourceMap] is available, this will include the `sourceMappingURL`
@ -343,34 +401,21 @@ class JSModuleFile {
/// using [placeSourceMap].
final Map sourceMap;
/// The binary contents of the API summary file, including APIs from each of
/// the [libraries] in this module.
final List<int> summaryBytes;
JSModuleFile(
this.name, this.errors, this.code, this.sourceMap, this.summaryBytes);
JSModuleFile.invalid(this.name, this.errors)
: code = null,
sourceMap = null,
summaryBytes = null;
/// True if this library was successfully compiled.
bool get isValid => code != null;
/// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
/// and returns the new map.
///
/// See also [writeSourceMap].
Map placeSourceMap(String sourceMapPath) {
var dir = path.dirname(sourceMapPath);
var map = new Map.from(this.sourceMap);
List list = new List.from(map['sources']);
map['sources'] = list;
for (int i = 0; i < list.length; i++) {
list[i] = path.relative(list[i], from: dir);
}
return map;
}
JSModuleCode(this.code, this.sourceMap);
}
/// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
/// and returns the new map.
// TODO(jmesserly): find a new home for this.
Map placeSourceMap(Map sourceMap, String sourceMapPath) {
var dir = path.dirname(sourceMapPath);
var map = new Map.from(sourceMap);
List list = new List.from(map['sources']);
map['sources'] = list;
for (int i = 0; i < list.length; i++) {
list[i] =
path.toUri(path.relative(path.fromUri(list[i]), from: dir)).toString();
}
return map;
}

View file

@ -2,11 +2,91 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:path/path.dart' as path;
import '../js_ast/js_ast.dart';
import 'js_names.dart';
/// The module format to emit.
enum ModuleFormat {
/// ECMAScript 6 module using import and export.
es6,
/// CommonJS module (used in Node.js)
common,
/// Asynchronous Module Definition (AMD, used in browsers)
amd,
/// Dart Dev Compiler's legacy format (deprecated).
legacy
}
/// Parses a string into a [ModuleFormat].
ModuleFormat parseModuleFormat(String s) => {
'es6': ModuleFormat.es6,
'common': ModuleFormat.common,
'amd': ModuleFormat.amd,
// Deprecated:
'node': ModuleFormat.common,
'legacy': ModuleFormat.legacy
}[s];
/// Parse the module format option added by [addModuleFormatOptions].
List<ModuleFormat> parseModuleFormatOption(ArgResults argResults) {
var format = argResults['modules'];
if (format is String) {
return [parseModuleFormat(format)];
}
return (format as List<String>).map(parseModuleFormat).toList();
}
/// Adds an option to the [argParser] for choosing the module format, optionally
/// [allowMultiple] formats to be specified, with each emitted into a separate
/// file.
void addModuleFormatOptions(ArgParser argParser, {bool allowMultiple: false}) {
argParser.addOption('modules',
help: 'module pattern to emit',
allowed: [
'es6',
'common',
'amd',
'legacy', // deprecated
'node', // renamed to commonjs
'all' // to emit all flavors for the SDK
],
allowedHelp: {
'es6': 'ECMAScript 6 modules',
'common': 'CommonJS/Node.js modules',
'amd': 'AMD/RequireJS modules'
},
allowMultiple: allowMultiple,
defaultsTo: 'amd');
}
/// Transforms an ES6 [module] into a given module [format].
///
/// If the format is [ModuleFormat.es6] this will return [module] unchanged.
///
/// Because JS ASTs are immutable the resulting module will share as much
/// structure as possible with the original. The transformation is a shallow one
/// that affects the top-level module items, especially [ImportDeclaration]s and
/// [ExportDeclaration]s.
Program transformModuleFormat(ModuleFormat format, Program module) {
switch (format) {
case ModuleFormat.legacy:
return new LegacyModuleBuilder().build(module);
case ModuleFormat.common:
return new CommonJSModuleBuilder().build(module);
case ModuleFormat.amd:
return new AmdModuleBuilder().build(module);
case ModuleFormat.es6:
return module;
}
return null; // unreachable. suppresses a bogus analyzer message
}
/// Base class for compiling ES6 modules into various ES5 module patterns.
///
/// This is a helper class for utilities and state that is shared by several
@ -61,7 +141,7 @@ class LegacyModuleBuilder extends _ModuleBuilder {
var importStatements = <Statement>[];
for (var import in imports) {
importNames.add(import.from);
// TODO(jmesserly): we could use destructuring once Atom supports it.
// TODO(jmesserly): we could use destructuring here.
var moduleVar =
new TemporaryId(pathToJSIdentifier(import.from.valueWithoutQuotes));
parameters.add(moduleVar);
@ -105,8 +185,8 @@ class LegacyModuleBuilder extends _ModuleBuilder {
}
}
/// Generates node modules.
class NodeModuleBuilder extends _ModuleBuilder {
/// Generates CommonJS modules (used by Node.js).
class CommonJSModuleBuilder extends _ModuleBuilder {
Program build(Program module) {
var importStatements = <Statement>[];
@ -114,7 +194,7 @@ class NodeModuleBuilder extends _ModuleBuilder {
visitProgram(module);
for (var import in imports) {
// TODO(jmesserly): we could use destructuring once Atom supports it.
// TODO(jmesserly): we could use destructuring here.
var moduleVar =
new TemporaryId(pathToJSIdentifier(import.from.valueWithoutQuotes));
importStatements
@ -122,7 +202,8 @@ class NodeModuleBuilder extends _ModuleBuilder {
// TODO(jmesserly): optimize for the common case of a single import.
for (var importName in import.namedImports) {
assert(!importName.isStar); // import * not supported yet.
// import * is not emitted by the compiler, so we don't support it here.
assert(!importName.isStar);
var asName = importName.asName ?? importName.name;
importStatements.add(js.statement(
'const # = #.#', [asName, moduleVar, importName.name.name]));
@ -135,7 +216,8 @@ class NodeModuleBuilder extends _ModuleBuilder {
statements.add(js.comment('Exports:'));
for (var export in exports) {
var names = export.exportedNames;
assert(names != null); // export * not supported in legacy modules.
// export * is not emitted by the compiler, so we don't handle it here.
assert(names != null);
for (var name in names) {
statements
.add(js.statement('#.# = #;', [exportsVar, name.name, name]));
@ -152,6 +234,56 @@ class NodeModuleBuilder extends _ModuleBuilder {
}
}
/// Generates AMD modules (used in browsers with RequireJS).
class AmdModuleBuilder extends _ModuleBuilder {
Program build(Program module) {
var importStatements = <Statement>[];
// Collect imports/exports/statements.
visitProgram(module);
var dependencies = <LiteralString>[];
var fnParams = <Parameter>[];
for (var import in imports) {
// TODO(jmesserly): we could use destructuring once Atom supports it.
var moduleVar =
new TemporaryId(pathToJSIdentifier(import.from.valueWithoutQuotes));
fnParams.add(moduleVar);
dependencies.add(import.from);
// TODO(jmesserly): optimize for the common case of a single import.
for (var importName in import.namedImports) {
// import * is not emitted by the compiler, so we don't handle it here.
assert(!importName.isStar);
var asName = importName.asName ?? importName.name;
importStatements.add(js.statement(
'const # = #.#', [asName, moduleVar, importName.name.name]));
}
}
statements.insertAll(0, importStatements);
if (exports.isNotEmpty) {
var exportedProps = <Property>[];
for (var export in exports) {
var names = export.exportedNames;
// export * is not emitted by the compiler, so we don't handle it here.
assert(names != null);
for (var name in names) {
exportedProps.add(new Property(js.string(name.name), name));
}
}
statements.add(js.comment('Exports:'));
statements.add(
new Return(new ObjectInitializer(exportedProps, multiline: true)));
}
var block = js.statement("define(#, function(#) { 'use strict'; #; });",
[new ArrayInitializer(dependencies), fnParams, statements]);
return new Program([block]);
}
}
/// Escape [name] to make it into a valid identifier.
String pathToJSIdentifier(String name) {
return toJSIdentifier(path.basenameWithoutExtension(name));

View file

@ -5,7 +5,7 @@
part of js_ast;
/**
* Transforms EcmaScript 6 modules to an ES 5 file using a module pattern.
* Transforms ECMAScript 6 modules to an ES 5 file using a module pattern.
*
* There are various module patterns in JavaScript, see
* <http://babeljs.io/docs/usage/modules/> for some examples.

View file

@ -304,6 +304,7 @@ abstract class Node {
}
}
// TODO(jmesserly): rename to Module.
class Program extends Node {
/// Script tag hash-bang, e.g. `#!/usr/bin/env node`
final String scriptTag;

View file

@ -1,21 +1,52 @@
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var TEST_REGEXP = /(_test|_multi)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
var testsToSkip = [
// syntax error:
'/base/gen/codegen_output/language/execute_finally6_test.js',
'/base/gen/codegen_output/language/switch_label2_test.js',
'/base/gen/codegen_output/language/infinite_switch_label_test.js',
'/base/gen/codegen_output/language/switch_label_test.js',
'/base/gen/codegen_output/language/nested_switch_label_test.js',
'/base/gen/codegen_output/language/switch_try_catch_test.js',
// module code execution error:
'/base/gen/codegen_output/language/f_bounded_quantification3_test.js',
'/base/gen/codegen_output/language/regress_16640_test.js',
'/base/gen/codegen_output/language/regress_22666_test.js',
'/base/gen/codegen_output/language/cyclic_type2_test.js',
'/base/gen/codegen_output/language/mixin_regress_13688_test.js',
];
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
if (TEST_REGEXP.test(file) && testsToSkip.indexOf(file) == -1) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
allTestFiles.push('test/browser/language_tests');
allTestFiles.push('test/browser/runtime_tests');
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base',
paths: {
dart_sdk: 'lib/js/amd/dart_sdk',
async_helper: 'gen/codegen_output/pkg/async_helper',
expect: 'gen/codegen_output/pkg/expect',
js: 'gen/codegen_output/pkg/js',
matcher: 'gen/codegen_output/pkg/matcher',
path: 'gen/codegen_output/pkg/path',
stack_trace: 'gen/codegen_output/pkg/stack_trace',
unittest: 'gen/codegen_output/pkg/unittest',
},
// dynamically load all test files
deps: allTestFiles,

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1536,11 +1536,12 @@ main() {
});
// Equality and identity.
test("Identical and equals", () {
// TODO(jmesserly): https://github.com/dart-lang/dev_compiler/issues/265
skip_test("Identical and equals", () {
expect(async.instanceMethod, equals(async.instanceMethod));
expect(Async.staticMethod, same(Async.staticMethod));
expect(topMethod, same(topMethod));
}, skip: 'https://github.com/dart-lang/dev_compiler/issues/265');
});
});
group("await expression", () {
@ -1623,13 +1624,14 @@ main() {
return expect42(f());
});
test("suffix operator + pre-increment", () {
// TODO(jmesserly): https://github.com/dart-lang/dev_compiler/issues/265
skip_test("suffix operator + pre-increment", () {
f() async {
var v = [41];
return await ++v[0];
}
return expect42(f());
}, skip: 'https://github.com/dart-lang/dev_compiler/issues/267');
});
test("assignment operator", () {
f() async {
@ -1963,8 +1965,8 @@ Future syncInAsync(f) async {
class FakeValueFuture implements Future {
final _value;
FakeValueFuture(this._value);
Future/*<S>*/ then/*<S>*/(/*=S*/ callback(value), {Function onError}) {
return new Future<dynamic /*=S*/>.microtask(() => callback(_value));
Future/*<S>*/ then/*<S>*/(callback(value), {Function onError}) {
return new Future/*<S>*/.microtask(() => callback(_value));
}
Future whenComplete(callback()) {
return new Future.microtask(() { callback(); });
@ -1982,7 +1984,7 @@ typedef BinaryFunction(a, b);
class FakeErrorFuture implements Future {
final _error;
FakeErrorFuture(this._error);
Future/*<S>*/ then/*<S>*/(/*=S*/ callback(value), {Function onError}) {
Future/*<S>*/ then/*<S>*/(callback(value), {Function onError}) {
if (onError != null) {
if (onError is BinaryFunction) {
return new Future/*<S>*/.microtask(() => onError(_error, null));

View file

@ -31,10 +31,18 @@
<!--
<script type="application/dart" src="sunflower.dart"></script>
-->
<script src="../../../lib/runtime/dart_library.js"></script>
<script src="../../../lib/runtime/dart_sdk.js"></script>
<script src="../expect/js/js.js"></script>
<script src="../expect/sunflower/sunflower.js"></script>
<script>dart_library.start('sunflower')</script>
<script src="../../../node_modules/requirejs/require.js"></script>
<script>
require.config({
paths: {
dart_sdk: "../../../lib/js/amd/dart_sdk",
js: "../../../gen/codegen_output/pkg/js",
}
});
require(["../../../gen/codegen_output/sunflower/sunflower"],
(sunflower) => {
sunflower.sunflower.main();
});
</script>
</body>
</html>

View file

@ -1,6 +1,4 @@
dart_library.library('BenchmarkBase', null, /* Imports */[
'dart_sdk'
], function load__BenchmarkBase(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -92,5 +90,7 @@ dart_library.library('BenchmarkBase', null, /* Imports */[
names: ['measureFor']
});
// Exports:
exports.BenchmarkBase = BenchmarkBase$;
return {
BenchmarkBase: BenchmarkBase$
};
});

View file

@ -1,6 +1,4 @@
dart_library.library('async_helper', null, /* Imports */[
'dart_sdk'
], function load__async_helper(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -72,5 +70,7 @@ dart_library.library('async_helper', null, /* Imports */[
};
dart.fn(async_helper.asyncTest, FnTovoid());
// Exports:
exports.async_helper = async_helper;
return {
async_helper: async_helper
};
});

View file

@ -1,6 +1,4 @@
dart_library.library('destructuring', null, /* Imports */[
'dart_sdk'
], function load__destructuring(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -86,6 +84,8 @@ dart_library.library('destructuring', null, /* Imports */[
};
dart.fn(src__varargs.spread, dynamicTodynamic());
// Exports:
exports.destructuring = destructuring;
exports.src__varargs = src__varargs;
return {
destructuring: destructuring,
src__varargs: src__varargs
};
});

View file

@ -1,6 +1,4 @@
dart_library.library('expect', null, /* Imports */[
'dart_sdk'
], function load__expect(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -300,5 +298,7 @@ dart_library.library('expect', null, /* Imports */[
constructors: () => ({new: dart.definiteFunctionType(expect.AssumeDynamic, [])})
});
// Exports:
exports.expect = expect;
return {
expect: expect
};
});

View file

@ -1,6 +1,4 @@
dart_library.library('map_keys', null, /* Imports */[
'dart_sdk'
], function load__map_keys(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const math = dart_sdk.math;
@ -18,7 +16,9 @@ dart_library.library('map_keys', null, /* Imports */[
};
dart.fn(map_keys.main, VoidTodynamic());
// Exports:
exports.map_keys = map_keys;
return {
map_keys: map_keys
};
});
//# sourceMappingURL=map_keys.js.map
//# sourceMappingURL=/Users/jmesserly/src/dev_compiler/test/codegen_expected/map_keys.js.map

View file

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../gen/codegen_tests/map_keys.dart"],"names":["print","x"],"mappings":";;;;;;;;AAKA,kBAAI,WAAG;AAEL,IAAA,AAAAA,UAAK,CAAC,eAAO,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAE,CAAC;AAAC,AAElC,IAAA,AAAAA,UAAK,CAAC,UAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,sBAAE,CAAC;AAAC,AAE5B,IAAA,AAAAA,UAAK,CAAC,eAAO,CAAC,GAAE,WAAC,aAAE,AAAA,iBAAY,SAAS,CAAC,CAAC,IAAG,CAAC,AAAC,EAAC,GAAE,CAAC,OAAO,CAAC,yBAAE,CAAC;AAAC,AAC/D,YAAW,GAAG;AAAC,AAEf,IAAA,AAAAA,UAAK,CAAC,UAAE,GAAG,EAAE,CAAC,EAAEC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,yBAAE,CAAC;AAAC,AAEhC,IAAA,AAAAD,UAAK,CAAC,UAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,yBAAE,CAAC;AAAC,GAErC,AAAA;AAAA","file":"/Users/jmesserly/src/dev_compiler/test/codegen_expected/map_keys.js"}

View file

@ -1,6 +1,4 @@
dart_library.library('script', null, /* Imports */[
'dart_sdk'
], function load__script(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -15,5 +13,7 @@ dart_library.library('script', null, /* Imports */[
};
dart.fn(script.main, ListOfStringTovoid());
// Exports:
exports.script = script;
return {
script: script
};
});

View file

@ -1,6 +1,4 @@
dart_library.library('sunflower', null, /* Imports */[
'dart_sdk'
], function load__sunflower(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const html = dart_sdk.html;
@ -124,9 +122,11 @@ dart_library.library('sunflower', null, /* Imports */[
}
});
// Exports:
exports.sunflower = sunflower;
exports.circle = circle;
exports.painter = painter;
return {
sunflower: sunflower,
circle: circle,
painter: painter
};
});
//# sourceMappingURL=sunflower.js.map
//# sourceMappingURL=/Users/jmesserly/src/dev_compiler/test/codegen_expected/sunflower/sunflower.js.map

View file

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../codegen/sunflower/sunflower.dart","../../codegen/sunflower/circle.dart","../../codegen/sunflower/painter.dart"],"names":["MAX_D","centerX","document","selector","querySelector","canvas","sqrt","slider","draw","seeds","int","context","i","TAU","PHI","SCALE_FACTOR","r","cos","theta","centerY","sin","x","y","SEED_RADIUS","notes","ORANGE","color","radius","PI"],"mappings":"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","file":"/Users/jmesserly/src/dev_compiler/test/codegen_expected/sunflower/sunflower.js"}

View file

@ -1,6 +1,4 @@
dart_library.library('varargs', null, /* Imports */[
'dart_sdk'
], function load__varargs(exports, dart_sdk) {
define(['dart_sdk'], function(dart_sdk) {
'use strict';
const core = dart_sdk.core;
const dart = dart_sdk.dart;
@ -32,6 +30,8 @@ dart_library.library('varargs', null, /* Imports */[
};
dart.fn(src__varargs.spread, dynamicTodynamic());
// Exports:
exports.varargs = varargs;
exports.src__varargs = src__varargs;
return {
varargs: varargs,
src__varargs: src__varargs
};
});

View file

@ -12,12 +12,7 @@ library dev_compiler.test.codegen_test;
// compiles stuff. This should be changed to not use unittest and just be a
// regular program that outputs files.
import 'dart:convert' show JSON;
import 'dart:io' show Directory, File, Platform;
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:path/path.dart' as path;
import 'package:test/test.dart' show test;
import 'package:analyzer/analyzer.dart'
show
ExportDirective,
@ -26,13 +21,23 @@ import 'package:analyzer/analyzer.dart'
UriBasedDirective,
parseDirectives;
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions;
import 'package:dev_compiler/src/compiler/compiler.dart'
show BuildUnit, CompilerOptions, ModuleCompiler;
show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
import 'package:dev_compiler/src/compiler/module_builder.dart'
show
ModuleFormat,
addModuleFormatOptions,
parseModuleFormatOption,
pathToJSIdentifier;
import 'package:path/path.dart' as path;
import 'package:test/test.dart' show expect, isFalse, isTrue, test;
import '../tool/build_sdk.dart' as build_sdk;
import 'testing.dart' show repoDirectory, testDirectory;
import 'multitest.dart' show extractTestsFromMultitest, isMultiTest;
import '../tool/build_sdk.dart' as build_sdk;
import 'package:dev_compiler/src/compiler/compiler.dart';
import 'not_yet_strong_tests.dart';
final ArgParser argParser = new ArgParser()
..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null);
@ -67,7 +72,7 @@ main(List<String> arguments) {
var sdkDir = path.join(repoDirectory, 'gen', 'patched_sdk');
var sdkSummaryFile =
path.join(testDirectory, '..', 'lib', 'runtime', 'dart_sdk.sum');
path.join(testDirectory, '..', 'lib', 'js', 'amd', 'dart_sdk.sum');
var summaryPaths = new Directory(path.join(codegenOutputDir, 'pkg'))
.listSync()
@ -97,6 +102,7 @@ main(List<String> arguments) {
var defaultOptions = ['--no-source-map', '--no-summarize'];
var compilerArgParser = new ArgParser();
CompilerOptions.addArguments(compilerArgParser);
addModuleFormatOptions(compilerArgParser);
// Compile each test file to JS and put the result in gen/codegen_output.
for (var testFile in testFiles) {
@ -117,8 +123,10 @@ main(List<String> arguments) {
if (match != null) {
args.addAll(match.group(1).split(' '));
}
var options =
new CompilerOptions.fromArguments(compilerArgParser.parse(args));
var argResults = compilerArgParser.parse(args);
var options = new CompilerOptions.fromArguments(argResults);
var moduleFormat = parseModuleFormatOption(argResults).first;
// Collect any other files we've imported.
var files = new Set<String>();
@ -126,13 +134,29 @@ main(List<String> arguments) {
var unit = new BuildUnit(
name, path.dirname(testFile), files.toList(), _moduleForLibrary);
var module = compiler.compile(unit, options);
_writeModule(path.join(codegenOutputDir, name),
isTopLevelTest ? path.join(codegenExpectDir, name) : null, module);
bool notStrong = notYetStrongTests.contains(name);
if (module.isValid) {
_writeModule(
path.join(codegenOutputDir, name),
isTopLevelTest ? path.join(codegenExpectDir, name) : null,
moduleFormat,
module);
expect(notStrong, isFalse,
reason: "test $name expected strong mode errors, but compiled.");
} else {
expect(notStrong, isTrue,
reason: "test $name failed to compile due to strong mode errors:"
"\n\n${module.errors.join('\n')}.");
}
});
}
if (filePattern.hasMatch('sunflower')) {
_buildSunflower(compiler, codegenOutputDir, codegenExpectDir);
test('sunflower', () {
_buildSunflower(compiler, codegenOutputDir, codegenExpectDir);
});
}
if (codeCoverage) {
@ -142,56 +166,18 @@ main(List<String> arguments) {
}
}
void _writeModule(String outPath, String expectPath, JSModuleFile result) {
void _writeModule(String outPath, String expectPath, ModuleFormat format,
JSModuleFile result) {
_ensureDirectory(path.dirname(outPath));
String errors = result.errors.join('\n');
if (errors.isNotEmpty && !errors.endsWith('\n')) errors += '\n';
new File(outPath + '.txt').writeAsStringSync(errors);
var jsFile = new File(outPath + '.js');
var summaryFile = new File(outPath + '.sum');
var errorFile = new File(outPath + '.err');
result.writeCodeSync(format, outPath + '.js');
if (result.isValid) {
jsFile.writeAsStringSync(result.code);
if (result.summaryBytes != null) {
summaryFile.writeAsBytesSync(result.summaryBytes);
}
if (result.sourceMap != null) {
var mapPath = outPath + '.js.map';
new File(mapPath)
.writeAsStringSync(JSON.encode(result.placeSourceMap(mapPath)));
}
// There are no errors, so delete any stale ".err" file.
if (errorFile.existsSync()) {
errorFile.deleteSync();
}
} else {
// Also write the errors to a '.err' file for easy counting.
var moduleName = result.name;
var libraryName = path.split(moduleName).last;
var count = "[error]".allMatches(errors).length;
var text = '''
dart_library.library('$moduleName', null, [
'dart_sdk',
'expect'
], function(exports, dart_sdk, expect) {
const message = `DDC Compilation Error: $moduleName has $count errors`;
const error = new Error(message);
exports.$libraryName = Object.create(null);
exports.$libraryName.main = function() {
throw error;
}
});
''';
errorFile.writeAsStringSync(text);
// There are errors, so delete any stale ".js" file.
if (jsFile.existsSync()) {
jsFile.deleteSync();
}
if (result.summaryBytes != null) {
new File(outPath + '.sum').writeAsBytesSync(result.summaryBytes);
}
// Write the expectation file if needed.
@ -202,12 +188,8 @@ dart_library.library('$moduleName', null, [
var expectFile = new File(expectPath + '.js');
if (result.isValid) {
expectFile.writeAsStringSync(result.code);
result.writeCodeSync(format, expectFile.path);
} else {
// There are errors, so delete any stale expect ".js" file.
if (expectFile.existsSync()) {
expectFile.deleteSync();
}
expectFile.writeAsStringSync("//FAILED TO COMPILE");
}
}
@ -224,7 +206,7 @@ void _buildSunflower(
var built = compiler.compile(input, options);
_writeModule(path.join(outputDir, 'sunflower', 'sunflower'),
path.join(expectDir, 'sunflower', 'sunflower'), built);
path.join(expectDir, 'sunflower', 'sunflower'), ModuleFormat.amd, built);
}
String _moduleForLibrary(Source source) {

File diff suppressed because it is too large Load diff

View file

@ -9,14 +9,14 @@ dart -c tool/patch_sdk.dart tool/input_sdk gen/patched_sdk
echo "*** Compiling SDK to JavaScript"
# TODO(jmesserly): break out dart:html & friends.
#
# Right now we can't summarize our SDK, so we can't treat it as a normal
# explicit input (instead we're implicitly compiling against the user's SDK).
#
# Another possible approach is to hard code the dart:* library->module mapping
# into the compiler itself, so it can emit the correct import.
#
dart -c tool/build_sdk.dart \
--dart-sdk gen/patched_sdk \
-o lib/runtime/dart_sdk.js \
--modules=amd \
-o lib/js/amd/dart_sdk.js \
--modules=es6 \
-o lib/js/es6/dart_sdk.js \
--modules=common \
-o lib/js/common/dart_sdk.js \
--modules=legacy \
-o lib/js/legacy/dart_sdk.js \
"$@" > tool/sdk_expected_errors.txt

View file

@ -5,7 +5,7 @@ cd $( dirname "${BASH_SOURCE[0]}" )/..
mkdir -p gen/codegen_output/pkg/
SDK=--dart-sdk-summary=lib/runtime/dart_sdk.sum
SDK=--dart-sdk-summary=lib/js/amd/dart_sdk.sum
./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/expect.js \
--url-mapping=package:expect/expect.dart,test/codegen/expect.dart \
@ -29,6 +29,9 @@ SDK=--dart-sdk-summary=lib/runtime/dart_sdk.sum
package:stack_trace/stack_trace.dart
./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/unittest.js \
-s gen/codegen_output/pkg/matcher.sum \
-s gen/codegen_output/pkg/path.sum \
-s gen/codegen_output/pkg/stack_trace.sum \
package:unittest/unittest.dart \
package:unittest/html_config.dart \
package:unittest/html_individual_config.dart \

View file

@ -213,7 +213,7 @@ _trackCall(obj, name) {
var src = '';
for (int i = 2; i < stack.length; ++i) {
var frame = stack[i];
if (!frame.contains('dev_compiler/lib/runtime/dart_sdk.js')) {
if (!frame.contains('dart_sdk.js')) {
src = frame;
break;
}

View file

@ -8,20 +8,18 @@ import 'dart:async';
import 'dart:html' show HttpRequest;
import 'dart:convert' show BASE64;
import 'package:analyzer/file_system/file_system.dart'
show ResourceUriResolver;
import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
import 'package:analyzer/file_system/memory_file_system.dart'
show MemoryResourceProvider;
import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
import 'package:analyzer/src/generated/source.dart'
show DartUriResolver;
import 'package:analyzer/src/generated/source.dart' show DartUriResolver;
import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
import 'package:analyzer/src/summary/package_bundle_reader.dart'
show
SummaryDataStore,
InSummaryPackageUriResolver,
InputPackagesResultProvider,
InSummarySource;
SummaryDataStore,
InSummaryPackageUriResolver,
InputPackagesResultProvider,
InSummarySource;
import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
import 'package:args/command_runner.dart';
@ -30,6 +28,7 @@ import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions;
import 'package:dev_compiler/src/compiler/compiler.dart'
show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
import 'package:dev_compiler/src/compiler/module_builder.dart';
import 'package:js/js.dart';
typedef void MessageHandler(Object message);
@ -104,7 +103,7 @@ class WebCompileCommand extends Command {
resourceProvider: resourceProvider);
(compiler.context as AnalysisContextImpl).resultProvider =
new InputPackagesResultProvider(compiler.context, summaryDataStore);
new InputPackagesResultProvider(compiler.context, summaryDataStore);
var compilerOptions = new CompilerOptions.fromArguments(argResults);
@ -119,7 +118,10 @@ class WebCompileCommand extends Command {
module.errors.forEach(messageHandler);
if (!module.isValid) throw new CompileErrorException();
return module.code;
var code =
module.getCode(ModuleFormat.amd, unit.name, unit.name + '.map');
return code.code;
};
return allowInterop(compileFn);