From e889ec8335011ef7d478efdbebc9141d146a0613 Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Mon, 14 Sep 2015 17:16:34 -0700 Subject: [PATCH] refactor(dart/transform): Use a protobufs representation during transform To simplify processing and testing in the future, use protobufs to represent of `.ng_deps.dart` files rather than always dealing directly in Dart code. This update does not actually use the protobuf representation, but this is a step towards moving all phases to parse and use protobufs rather than Dart code. --- .../common/code/annotation_code.dart | 92 +++++ .../src/transform/common/code/constify.dart | 64 ++++ .../common/code/import_export_code.dart | 98 +++++ .../transform/common/code/ng_deps_code.dart | 167 +++++++++ .../transform/common/code/parameter_code.dart | 138 +++++++ .../common/code/reflection_info_code.dart | 181 ++++++++++ .../lib/src/transform/common/names.dart | 2 + .../directive_processor/inliner.dart | 143 ++++++++ .../directive_processor/rewriter.dart | 309 ++-------------- .../directive_processor/visitors.dart | 341 ------------------ .../test/transform/common/convert_spec.dart | 81 +++-- .../all_tests.dart | 3 +- .../expected/hello.ng_deps.dart | 6 +- .../expected/package_soup.ng_deps.dart | 2 +- .../expected/relative_soup.ng_deps.dart | 2 +- .../expected/hello.ng_deps.dart | 8 +- .../expected/hello.ng_deps.dart | 2 +- .../expected/soup.ng_deps.dart | 2 +- .../expected/soup.ng_deps.dart | 99 +++++ .../expected/soup.ng_deps.dart | 5 +- .../expected/hello.ng_deps.dart | 6 +- .../expected/soup.ng_deps.dart | 6 +- .../expected/main.ng_deps.dart | 2 +- .../expected/hello.ng_deps.dart | 13 +- .../expected/hello.ng_deps.dart | 12 +- .../expected/soup.ng_deps.dart | 4 +- .../parameter_metadata/soup.dart | 2 +- .../part_files/expected/main.ng_deps.dart | 2 +- .../expected/soup.ng_deps.dart | 2 +- .../expected/hello.ng_deps.dart | 4 +- .../expected/hello.ng_deps.dart | 2 +- .../expected/soup.ng_deps.dart | 2 +- .../expected/soup.ng_deps.dart | 8 +- .../expected/hello.ng_deps.dart | 4 +- .../test/transform/integration/all_tests.dart | 8 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/index.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 31 +- .../two_deps_files/expected/bar.ng_deps.dart | 2 +- 41 files changed, 1152 insertions(+), 711 deletions(-) create mode 100644 modules_dart/transform/lib/src/transform/common/code/annotation_code.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/constify.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/import_export_code.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/parameter_code.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/reflection_info_code.dart create mode 100644 modules_dart/transform/lib/src/transform/directive_processor/inliner.dart delete mode 100644 modules_dart/transform/lib/src/transform/directive_processor/visitors.dart create mode 100644 modules_dart/transform/test/transform/directive_processor/interface_lifecycle_files/expected/soup.ng_deps.dart diff --git a/modules_dart/transform/lib/src/transform/common/code/annotation_code.dart b/modules_dart/transform/lib/src/transform/common/code/annotation_code.dart new file mode 100644 index 0000000000..76e10fc6d7 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/annotation_code.dart @@ -0,0 +1,92 @@ +library angular2.transform.common.code.annotation_code; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; +import 'package:angular2/src/transform/common/model/annotation_model.pb.dart'; +import 'package:barback/barback.dart' show AssetId; + +import 'constify.dart' show constify; + +/// Visitor responsible for parsing [Annotation]s into [AnnotationModel]s. +class AnnotationVisitor extends SimpleAstVisitor { + /// The file we are processing. + final AssetId assetId; + + /// Responsible for testing whether [Annotation]s are those recognized by + /// Angular 2, for example `@Component`. + final AnnotationMatcher _annotationMatcher; + + AnnotationVisitor(this.assetId, this._annotationMatcher); + + @override + AnnotationModel visitAnnotation(Annotation node) { + var name = constify(node.name); + if (node.constructorName != null) { + name += '.${constify(node.constructorName)}'; + } + var isComponent = _annotationMatcher.isComponent(node, assetId); + var isDirective = + isComponent || _annotationMatcher.isDirective(node, assetId); + var isInjectable = + isDirective || _annotationMatcher.isInjectable(node, assetId); + var isView = _annotationMatcher.isView(node, assetId); + var model = new AnnotationModel() + ..name = name + ..isComponent = isComponent + ..isDirective = isDirective + ..isInjectable = isInjectable + ..isView = isView; + + if (node.arguments != null) { + for (var arg in node.arguments.arguments) { + if (arg is NamedExpression) { + model.namedParameters.add(new NamedParameter() + ..name = constify(arg.name.label) + ..value = constify(arg.expression)); + } else { + model.parameters.add(constify(arg)); + } + } + } + + return model; + } +} + +/// Defines the format in which an [AnnotationModel] is expressed as Dart code +/// in a `.ng_deps.dart` file. +abstract class AnnotationWriterMixin { + StringBuffer get buffer; + + void writeAnnotationModel(AnnotationModel model) { + if (model.parameters != null || model.namedParameters != null) { + buffer.write('const ${model.name}('); + var first = true; + for (var param in model.parameters) { + if (!first) { + buffer.write(', '); + } + first = false; + buffer.write(param); + } + // TODO(kegluneq): We are currently outputting these sorted to ensure we + // have repeatable output for testing purposes. + // Remove this sorting once we are not testing output code directly. + var namedParameters = model.namedParameters.toList(); + namedParameters.sort((a, b) => a.name.compareTo(b.name)); + for (var param in namedParameters) { + if (!first) { + buffer.write(', '); + } + first = false; + buffer.write('${param.name}: ${param.value}'); + } + buffer.write(')'); + } else { + // This is a const instance, not a ctor invocation and does not need a + // const instance creation expression. + buffer.write(model.name); + } + } +} diff --git a/modules_dart/transform/lib/src/transform/common/code/constify.dart b/modules_dart/transform/lib/src/transform/common/code/constify.dart new file mode 100644 index 0000000000..83e3e1dfcb --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/constify.dart @@ -0,0 +1,64 @@ +library angular2.transform.common.code.constify; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/java_core.dart'; + +/// Serializes the provided [AstNode] to Dart source, replacing `new` in +/// [InstanceCreationExpression]s and the `@` in [Annotation]s with `const`. +String constify(AstNode node) { + var writer = new PrintStringWriter(); + node.accept(new _ConstifyingVisitor(writer)); + return '$writer'; +} + +class _ConstifyingVisitor extends ToSourceVisitor { + final PrintWriter writer; + + _ConstifyingVisitor(PrintWriter writer) + : this.writer = writer, + super(writer); + + @override + Object visitInstanceCreationExpression(InstanceCreationExpression node) { + if (node.keyword.lexeme == 'const') { + return super.visitInstanceCreationExpression(node); + } else if (node.keyword.lexeme == 'new') { + writer.print('const '); + if (node.constructorName != null) { + node.constructorName.accept(this); + } + if (node.argumentList != null) { + node.argumentList.accept(this); + } + } + return null; + } + + @override + Object visitAnnotation(Annotation node) { + var hasArguments = + node.arguments != null && node.arguments.arguments != null; + if (hasArguments) { + writer.print('const '); + } + if (node.name != null) { + node.name.accept(this); + } + if (node.constructorName != null) { + writer.print('.'); + node.constructorName.accept(this); + } + if (hasArguments) { + var args = node.arguments.arguments; + writer.print('('); + for (var i = 0, iLen = args.length; i < iLen; ++i) { + if (i != 0) { + writer.print(', '); + } + args[i].accept(this); + } + writer.print(')'); + } + return null; + } +} diff --git a/modules_dart/transform/lib/src/transform/common/code/import_export_code.dart b/modules_dart/transform/lib/src/transform/common/code/import_export_code.dart new file mode 100644 index 0000000000..aa76610254 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/import_export_code.dart @@ -0,0 +1,98 @@ +library angular2.transform.common.code.import_export_code; + +import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; + +/// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s. +class ImportVisitor extends SimpleAstVisitor { + @override + ImportModel visitImportDirective(ImportDirective node) { + if (node.isSynthetic) return null; + + var model = new ImportModel() + ..uri = stringLiteralToString(node.uri) + ..isDeferred = node.deferredKeyword != null; + if (node.prefix != null) { + model.prefix = node.prefix.name; + } + _populateCombinators(node, model); + return model; + } +} + +/// Visitor responsible for parsing [ExportDirective]s into [ExportModel]s. +class ExportVisitor extends SimpleAstVisitor { + @override + ExportModel visitExportDirective(ExportDirective node) { + if (node.isSynthetic) return null; + + var model = new ExportModel()..uri = stringLiteralToString(node.uri); + _populateCombinators(node, model); + return model; + } +} + +/// Parses `combinators` in `node` and adds them to `model`, which should be +/// either an [ImportModel] or an [ExportModel]. +void _populateCombinators(NamespaceDirective node, dynamic model) { + if (node.combinators != null) { + node.combinators.forEach((c) { + if (c is ShowCombinator) { + model.showCombinators.addAll(c.shownNames.map((id) => '$id')); + } else if (c is HideCombinator) { + model.hideCombinators.addAll(c.hiddenNames.map((id) => '$id')); + } + }); + } +} + +/// Defines the format in which an [ImportModel] is expressed as Dart code in a +/// `.ng_deps.dart` file. +abstract class ImportWriterMixin { + StringBuffer get buffer; + + void writeImportModel(ImportModel model) { + buffer.write("import '${model.uri}'"); + if (model.isDeferred) { + buffer.write(' deferred'); + } + if (model.prefix != null && model.prefix.isNotEmpty) { + buffer.write(' as ${model.prefix}'); + } + _writeCombinators(buffer, model); + buffer.writeln(';'); + } +} + +/// Defines the format in which an [ExportModel] is expressed as Dart code in a +/// `.ng_deps.dart` file. +abstract class ExportWriterMixin { + StringBuffer get buffer; + + void writeExportModel(ExportModel model) { + buffer.write("export '${model.uri}'"); + _writeCombinators(buffer, model); + buffer.writeln(';'); + } +} + +void _writeCombinators(StringBuffer buffer, dynamic model) { + if (model.showCombinators != null && model.showCombinators.isNotEmpty) { + buffer.write(' show '); + for (var i = 0; i < model.showCombinators.length; ++i) { + if (i != 0) { + buffer.write(', '); + } + buffer.write(model.showCombinators[i]); + } + } + if (model.hideCombinators != null && model.hideCombinators.isNotEmpty) { + buffer.write(' hide '); + for (var i = 0; i < model.hideCombinators.length; ++i) { + if (i != 0) { + buffer.write(', '); + } + buffer.write(model.hideCombinators[i]); + } + } +} diff --git a/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart b/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart new file mode 100644 index 0000000000..c9bfa08ad4 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart @@ -0,0 +1,167 @@ +library angular2.transform.common.code.ng_deps_code; + +import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; +import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; +import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; +import 'package:angular2/src/transform/common/names.dart'; +import 'package:barback/barback.dart' show AssetId; +import 'package:path/path.dart' as path; + +import 'annotation_code.dart'; +import 'import_export_code.dart'; +import 'reflection_info_code.dart'; +import 'parameter_code.dart'; + +/// Visitor responsible for parsing source Dart files (that is, not +/// `.ng_deps.dart` files) into [NgDepsModel] objects. +class NgDepsVisitor extends RecursiveAstVisitor { + final AssetId processedFile; + final ImportVisitor _importVisitor = new ImportVisitor(); + final ExportVisitor _exportVisitor = new ExportVisitor(); + final ReflectionInfoVisitor _reflectableVisitor; + + bool _isPart = false; + NgDepsModel _model = null; + + NgDepsVisitor(AssetId processedFile, AnnotationMatcher annotationMatcher) + : this.processedFile = processedFile, + _reflectableVisitor = + new ReflectionInfoVisitor(processedFile, annotationMatcher); + + bool get isPart => _isPart; + NgDepsModel get model { + if (_model == null) { + _createModel(''); + } + return _model; + } + + void _createModel(String libraryUri) { + _model = new NgDepsModel()..libraryUri = libraryUri; + + // We need to import & export the original file. + var origDartFile = path.basename(processedFile.path); + _model.imports.add(new ImportModel()..uri = origDartFile); + _model.exports.add(new ExportModel()..uri = origDartFile); + + // Used to register reflective information. + _model.imports.add(new ImportModel() + ..uri = REFLECTOR_IMPORT + ..prefix = REFLECTOR_PREFIX); + } + + @override + Object visitClassDeclaration(ClassDeclaration node) { + var reflectableModel = _reflectableVisitor.visitClassDeclaration(node); + if (reflectableModel != null) { + model.reflectables.add(reflectableModel); + } + return null; + } + + @override + Object visitExportDirective(ExportDirective node) { + var export = _exportVisitor.visitExportDirective(node); + if (export != null) { + model.exports.add(export); + } + return null; + } + + @override + Object visitImportDirective(ImportDirective node) { + var import = _importVisitor.visitImportDirective(node); + if (import != null) { + model.imports.add(import); + } + return null; + } + + @override + Object visitLibraryDirective(LibraryDirective node) { + if (node != null) { + assert(_model == null); + _createModel('${node.name}'); + } + return null; + } + + @override + Object visitPartDirective(PartDirective node) { + model.partUris.add(stringLiteralToString(node.uri)); + return null; + } + + @override + Object visitPartOfDirective(PartOfDirective node) { + _isPart = true; + return null; + } + + @override + Object visitFunctionDeclaration(FunctionDeclaration node) { + var reflectableModel = _reflectableVisitor.visitFunctionDeclaration(node); + if (reflectableModel != null) { + model.reflectables.add(reflectableModel); + } + return null; + } +} + +/// Defines the format in which an [NgDepsModel] is expressed as Dart code +/// in a `.ng_deps.dart` file. +class NgDepsWriter extends Object + with + AnnotationWriterMixin, + ExportWriterMixin, + ImportWriterMixin, + NgDepsWriterMixin, + ParameterWriterMixin, + ReflectionWriterMixin { + final StringBuffer buffer; + + NgDepsWriter([StringBuffer buffer]) + : this.buffer = buffer != null ? buffer : new StringBuffer(); +} + +abstract class NgDepsWriterMixin + implements + AnnotationWriterMixin, + ExportWriterMixin, + ImportWriterMixin, + ParameterWriterMixin, + ReflectionWriterMixin { + StringBuffer get buffer; + + void writeNgDepsModel(NgDepsModel model) { + if (model.libraryUri.isNotEmpty) { + buffer.writeln('library ${model.libraryUri}${DEPS_EXTENSION};\n'); + } + + // We do not support `partUris`, so skip outputting them. + model.imports.forEach((importModel) { + // Ignore deferred imports here so as to not load the deferred libraries + // code in the current library causing much of the code to not be + // deferred. Instead `DeferredRewriter` will rewrite the code as to load + // `ng_deps` in a deferred way. + if (importModel.isDeferred) return; + + writeImportModel(importModel); + }); + model.exports.forEach(writeExportModel); + + buffer + ..writeln('var _visited = false;') + ..writeln('void ${SETUP_METHOD_NAME}() {') + ..writeln('if (_visited) return; _visited = true;'); + + if (model.reflectables != null && model.reflectables.isNotEmpty) { + buffer.writeln('$REFLECTOR_PREFIX.$REFLECTOR_VAR_NAME'); + model.reflectables.forEach(writeRegistration); + buffer.writeln(';'); + } + + buffer.writeln('}'); + } +} diff --git a/modules_dart/transform/lib/src/transform/common/code/parameter_code.dart b/modules_dart/transform/lib/src/transform/common/code/parameter_code.dart new file mode 100644 index 0000000000..4a2b5cf985 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/parameter_code.dart @@ -0,0 +1,138 @@ +library angular2.transform.common.code.parameter_code; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/model/parameter_model.pb.dart'; + +import 'constify.dart'; + +/// Visitor responsible for parsing [FormalParameter]s into +/// [ParameterModel]s. +class ParameterVisitor extends SimpleAstVisitor { + /// Maps field names to their declared types. See `_populateFieldMap` + final Map _fieldNameToType = {}; + final Set _seen = new Set(); + + void _populateFieldMap(AstNode node) { + ClassDeclaration clazz = + node.getAncestor((node) => node is ClassDeclaration); + if (_seen.contains(clazz)) return; + _seen.add(clazz); + + clazz.members + .where((member) => member is FieldDeclaration) + .forEach((FieldDeclaration field) { + var type = field.fields.type; + if (type != null) { + field.fields.variables.forEach((VariableDeclaration decl) { + var key = '${decl.name}'; + if (_fieldNameToType.containsKey(key)) { + // Need to clear our `seen` list as the type for a var name has + // changed and could be incorrect. + _seen.clear(); + } + _fieldNameToType[key] = type; + }); + } + }); + } + + ParameterModel _visitNormalFormalParameter( + NodeList metadata, TypeName type, SimpleIdentifier name) { + var model = new ParameterModel(); + if (name != null && name.name != null && name.name.isNotEmpty) { + model.paramName = '$name'; + } + if (type != null) { + var sTypeName = '${type.name}'; + if (sTypeName.isNotEmpty) { + model.typeName = sTypeName; + } + if (type.typeArguments != null) { + model.typeArgs = '${type.typeArguments}'; + } + } + if (metadata != null) { + model.metadata.addAll(metadata.map(constify)); + } + return model; + } + + @override + ParameterModel visitSimpleFormalParameter(SimpleFormalParameter node) { + return _visitNormalFormalParameter( + node.metadata, node.type, node.identifier); + } + + @override + ParameterModel visitFieldFormalParameter(FieldFormalParameter node) { + if (node.parameters != null) { + logger.error('Parameters in ctor not supported ' + '(${node.toSource()})'); + } + var type = node.type; + if (type == null) { + _populateFieldMap(node); + type = _fieldNameToType[node.identifier.toString()]; + } + return _visitNormalFormalParameter(node.metadata, type, node.identifier); + } + + @override + ParameterModel visitFunctionTypedFormalParameter( + FunctionTypedFormalParameter node) { + logger.error('Function typed formal parameters not supported ' + '(${node.toSource()})'); + return _visitNormalFormalParameter(node.metadata, null, node.identifier); + } + + @override + ParameterModel visitDefaultFormalParameter(DefaultFormalParameter node) { + // Ignore the declared default value. + return node.parameter != null ? node.parameter.accept(this) : null; + } +} + +/// Defines the format in which a [ParameterModel] is expressed as Dart code +/// in a `.ng_deps.dart` file. +abstract class ParameterWriterMixin { + StringBuffer get buffer; + + void writeParameterModelForList(ParameterModel model) { + buffer.write('const ['); + var first = true; + if (model.typeName != null && model.typeName.isNotEmpty) { + if (!first) { + buffer.write(', '); + } + first = false; + buffer.write('${model.typeName}'); + } + for (var meta in model.metadata) { + if (!first) { + buffer.write(', '); + } + first = false; + buffer.write('$meta'); + } + buffer.write(']'); + } + + void writeParameterModelForDeclaration(ParameterModel model) { + if (model.typeName != null && model.typeName.isNotEmpty) { + buffer.write(model.typeName); + if (model.typeArgs != null && model.typeArgs.isNotEmpty) { + buffer.write(model.typeArgs); + } + buffer.write(' '); + } + if (model.paramName != null && model.paramName.isNotEmpty) { + buffer.write(model.paramName); + } + } + + void writeParameterModelForImpl(ParameterModel model) { + buffer.write(model.paramName); + } +} diff --git a/modules_dart/transform/lib/src/transform/common/code/reflection_info_code.dart b/modules_dart/transform/lib/src/transform/common/code/reflection_info_code.dart new file mode 100644 index 0000000000..3a14d8b880 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/reflection_info_code.dart @@ -0,0 +1,181 @@ +library angular2.transform.common.code.reflection_info_code; + +import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; +import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart'; +import 'package:angular2/src/transform/common/names.dart'; +import 'package:barback/barback.dart' show AssetId; + +import 'annotation_code.dart'; +import 'parameter_code.dart'; + +/// Visitor responsible for parsing [ClassDeclaration]s into +/// [ReflectionInfoModel]s. +class ReflectionInfoVisitor extends RecursiveAstVisitor { + /// The file we are processing. + final AssetId assetId; + + final AnnotationVisitor _annotationVisitor; + final ParameterVisitor _parameterVisitor = new ParameterVisitor(); + + /// Whether an Angular 2 `Reflection` has been found. + bool _foundNgReflection = false; + + /// Responsible for testing whether [Annotation]s are those recognized by + /// Angular 2, for example `@Component`. + final AnnotationMatcher _annotationMatcher; + + ReflectionInfoVisitor(AssetId assetId, AnnotationMatcher annotationMatcher) + : this.assetId = assetId, + _annotationMatcher = annotationMatcher, + _annotationVisitor = new AnnotationVisitor(assetId, annotationMatcher); + + bool get shouldCreateNgDeps => _foundNgReflection; + + ConstructorDeclaration _getCtor(ClassDeclaration node) { + int numCtorsFound = 0; + var ctor = null; + + for (ClassMember classMember in node.members) { + if (classMember is ConstructorDeclaration) { + numCtorsFound++; + ConstructorDeclaration constructor = classMember; + + // Use the unnnamed constructor if it is present. + // Otherwise, use the first encountered. + if (ctor == null) { + ctor = constructor; + } else if (constructor.name == null) { + ctor = constructor; + } + } + } + if (numCtorsFound > 1) { + var ctorName = ctor.name; + if (ctorName != null) { + logger.warning('Found ${numCtorsFound} ctors for class ${node.name},' + 'Using constructor ${ctorName}.'); + } + } + return ctor; + } + + @override + ReflectionInfoModel visitClassDeclaration(ClassDeclaration node) { + if (!node.metadata + .any((a) => _annotationMatcher.hasMatch(a.name, assetId))) { + return null; + } + + var ctor = _getCtor(node); + var model = new ReflectionInfoModel()..name = '${node.name}'; + if (ctor != null && ctor.name != null) { + model.ctorName = '${ctor.name}'; + } + + if (node.metadata != null) { + node.metadata.forEach((node) { + model.annotations.add(_annotationVisitor.visitAnnotation(node)); + }); + } + if (ctor != null && + ctor.parameters != null && + ctor.parameters.parameters != null) { + ctor.parameters.parameters.forEach((node) { + model.parameters.add(node.accept(_parameterVisitor)); + }); + } + if (node.implementsClause != null && + node.implementsClause.interfaces != null && + node.implementsClause.interfaces.isNotEmpty) { + model.interfaces.addAll(node.implementsClause.interfaces + .map((interface) => '${interface.name}')); + } + return model; + } + + @override + ReflectionInfoModel visitFunctionDeclaration(FunctionDeclaration node) { + if (!node.metadata + .any((a) => _annotationMatcher.hasMatch(a.name, assetId))) { + return null; + } + + var model = new ReflectionInfoModel() + ..name = '${node.name}' + ..isFunction = true; + if (node.metadata != null) { + node.metadata.forEach((node) { + var annotation = _annotationVisitor.visitAnnotation(node); + if (annotation != null) { + model.annotations.add(annotation); + } + }); + } + if (node.functionExpression.parameters != null && + node.functionExpression.parameters.parameters != null) { + node.functionExpression.parameters.parameters.forEach((node) { + var param = node.accept(_parameterVisitor); + if (param != null) { + model.parameters.add(param); + } + }); + } + return model; + } +} + +/// Defines the format in which an [ReflectionInfoModel] is expressed as Dart +/// code in a `.ng_deps.dart` file. +abstract class ReflectionWriterMixin + implements AnnotationWriterMixin, ParameterWriterMixin { + StringBuffer get buffer; + + void _writeListWithSeparator(List l, Function writeFn, + {String prefix, String suffix, String separator: ', '}) { + buffer.write(prefix); + for (var i = 0, iLen = l.length; i < iLen; ++i) { + if (i != 0) { + buffer.write(', '); + } + writeFn(l[i]); + } + buffer.write(suffix); + } + + void writeRegistration(ReflectionInfoModel model) { + buffer.write('..register'); + if (model.isFunction) { + buffer.write('Function'); + } else { + buffer.write('Type'); + } + buffer.writeln('(${model.name}, new $REFLECTOR_PREFIX.ReflectionInfo('); + + // Annotations + _writeListWithSeparator(model.annotations, writeAnnotationModel, + prefix: 'const [', suffix: ']'); + // Parameters + _writeListWithSeparator(model.parameters, writeParameterModelForList, + prefix: ',\nconst [', suffix: ']'); + if (!model.isFunction) { + // Factory + _writeListWithSeparator( + model.parameters, writeParameterModelForDeclaration, + prefix: ',\n(', suffix: ')'); + buffer.write(' => new ${model.name}'); + if (model.ctorName != null && model.ctorName.isNotEmpty) { + buffer.write('.${model.ctorName}'); + } + _writeListWithSeparator(model.parameters, writeParameterModelForImpl, + prefix: '(', suffix: ')'); + // Interfaces + if (model.interfaces != null && model.interfaces.isNotEmpty) { + _writeListWithSeparator(model.interfaces, buffer.write, + prefix: ',\nconst [', suffix: ']'); + } + } + buffer.writeln(')\n)'); + } +} diff --git a/modules_dart/transform/lib/src/transform/common/names.dart b/modules_dart/transform/lib/src/transform/common/names.dart index 66d506c080..300ab9eaa0 100644 --- a/modules_dart/transform/lib/src/transform/common/names.dart +++ b/modules_dart/transform/lib/src/transform/common/names.dart @@ -10,6 +10,8 @@ const META_EXTENSION = '.ng_meta.json'; // upfront (rather than extracting it from ng_deps). const ALIAS_EXTENSION = '.aliases.json'; const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities'; +const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart'; +const REFLECTOR_PREFIX = '_ngRef'; const REGISTER_TYPE_METHOD_NAME = 'registerType'; const REGISTER_GETTERS_METHOD_NAME = 'registerGetters'; const REGISTER_SETTERS_METHOD_NAME = 'registerSetters'; diff --git a/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart b/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart new file mode 100644 index 0000000000..1f7989a86c --- /dev/null +++ b/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart @@ -0,0 +1,143 @@ +library angular2.transform.directive_processor.inliner; + +import 'dart:async'; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:analyzer/src/generated/error.dart'; +import 'package:analyzer/src/generated/parser.dart'; +import 'package:analyzer/src/generated/scanner.dart'; +import 'package:analyzer/src/string_source.dart'; +import 'package:angular2/src/core/render/xhr.dart' show XHR; +import 'package:angular2/src/transform/common/async_string_writer.dart'; +import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/model/annotation_model.pb.dart'; +import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; + +Future inlineViewProps(XHR xhr, NgDepsModel model) { + var toWait = []; + for (var reflectable in model.reflectables) { + for (var annotation in reflectable.annotations) { + if (annotation.isView) { + var rawTemplateUrl = _getTemplateUrlValue(annotation); + if (rawTemplateUrl != null) { + if (_hasTemplateValue(annotation)) { + logger.warning('Both template url and template are specified. ' + 'Ignoring `templateUrl` value.'); + } else { + var url = _dumbEval(rawTemplateUrl); + if (url is String) { + toWait.add(_readOrEmptyString(xhr, url).then((templateText) { + _setTemplateValue(annotation, "r'''$templateText'''"); + })); + } else { + logger.warning('template url is not a String ($rawTemplateUrl)'); + } + } + } + var rawStyleUrls = _getStyleUrlsValue(annotation); + if (rawStyleUrls != null) { + if (_hasStylesValue(annotation)) { + logger.warning('Both styleUrls and styles are specified. ' + 'Ignoring `styleUrls` value.'); + } else { + var urls = _dumbEval(rawStyleUrls); + if (urls is List) { + var writer = new AsyncStringWriter(); + for (var url in urls) { + if (url is String) { + writer.print("r'''"); + writer.asyncPrint(_readOrEmptyString(xhr, url)); + writer.print("''', "); + } else { + logger.warning('style url is not a String (${url})'); + } + } + toWait.add(writer.asyncToString().then((styleUrlText) { + _setStylesValue(annotation, 'const [$styleUrlText]'); + _removeStyleUrlsValue(annotation); + })); + } else { + logger.warning( + 'styleUrls is not a List of strings ($rawStyleUrls)'); + } + } + } + } + } + } + return Future.wait(toWait); +} + +String _getNamedArgValue(AnnotationModel model, String argName) { + var value = null; + if (model.namedParameters != null) { + var match = model.namedParameters + .firstWhere((p) => p.name == argName, orElse: () => null); + value = match != null ? match.value : null; + } + return value; +} + +String _getTemplateUrlValue(AnnotationModel model) => + _getNamedArgValue(model, 'templateUrl'); +String _getStyleUrlsValue(AnnotationModel model) => + _getNamedArgValue(model, 'styleUrls'); + +bool _hasTemplateValue(AnnotationModel model) => + _getNamedArgValue(model, 'template') != null; +bool _hasStylesValue(AnnotationModel model) => + _getNamedArgValue(model, 'styles') != null; + +void _setNamedArgValue(AnnotationModel model, String argName, String argValue) { + var matchedArg = model.namedParameters + .firstWhere((p) => p.name == argName, orElse: () => null); + if (matchedArg == null) { + matchedArg = new NamedParameter()..name = argName; + model.namedParameters.add(matchedArg); + } + matchedArg.value = argValue; +} + +void _setTemplateValue(AnnotationModel model, String template) => + _setNamedArgValue(model, 'template', template); +void _setStylesValue(AnnotationModel model, String styles) => + _setNamedArgValue(model, 'styles', styles); + +void _removeNamedArg(AnnotationModel model, String argName) { + model.namedParameters.removeWhere((p) => p.name == argName); +} + +void _removeStyleUrlsValue(AnnotationModel model) => + _removeNamedArg(model, 'styleUrls'); + +final _constantEvaluator = new ConstantEvaluator(); + +/// Attempts to read the content from {@link url}, if it returns null then +/// just return the empty string. +Future _readOrEmptyString(XHR xhr, String url) async { + var content = await xhr.get(url); + if (content == null) { + content = ''; + } + return content; +} + +dynamic _dumbEval(String code) { + var source = new StringSource(code, code); + // TODO(kegluneq): Report errors. + var errorCollector = AnalysisErrorListener.NULL_LISTENER; + + var reader = new CharSequenceReader(code); + var scanner = new Scanner(source, reader, errorCollector); + var parser = new Parser(source, errorCollector) + ..currentToken = scanner.tokenize(); + var expr = parser.parseExpression2(); + var val = null; + if (expr is SimpleStringLiteral) { + val = stringLiteralToString(expr); + } else { + val = expr.accept(_constantEvaluator); + } + return val != ConstantEvaluator.NOT_A_CONSTANT ? val : null; +} diff --git a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart index 876c81c02e..7ae4a0af15 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart @@ -3,13 +3,11 @@ library angular2.transform.directive_processor.rewriter; import 'dart:async'; import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/java_core.dart'; -import 'package:angular2/src/core/render/xhr.dart' show XHR; import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/async_string_writer.dart'; +import 'package:angular2/src/transform/common/code/ng_deps_code.dart'; import 'package:angular2/src/transform/common/logging.dart'; -import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/xhr_impl.dart'; import 'package:angular2/src/transform/common/ng_meta.dart'; import 'package:barback/barback.dart' show AssetId; @@ -17,7 +15,7 @@ import 'package:code_transformers/assets.dart'; import 'package:path/path.dart' as path; import 'package:source_span/source_span.dart'; -import 'visitors.dart'; +import 'inliner.dart'; /// Generates a file registering all Angular 2 `Directive`s found in `code` in /// ngDeps format [TODO(kegluneq): documentation reference needed]. `assetId` is @@ -42,31 +40,34 @@ Future createNgDeps(AssetReader reader, AssetId assetId, // parent, so it does not need its own `.ng_deps.dart` file. if (directivesVisitor.isPart) return null; - var writer = new AsyncStringWriter(); - directivesVisitor.writeTo(writer, assetId); - - writer - ..println('var _visited = false;') - ..println('void ${SETUP_METHOD_NAME}() {') - ..println('if (_visited) return; _visited = true;'); - - var declarationsCode = + var codeWithParts = await _getAllDeclarations(reader, assetId, code, directivesVisitor); - var declarationsVisitor = new _NgDepsDeclarationsVisitor( - assetId, writer, new XhrImpl(reader, assetId), annotationMatcher, ngMeta, - inlineViews: inlineViews); - parseCompilationUnit(declarationsCode, name: '${assetId.path} and parts') - .declarations - .accept(declarationsVisitor); - if (declarationsVisitor.shouldCreateNgDeps) { - writer.println(';'); + var parsedCode = + parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts'); + + var ngDepsVisitor = new NgDepsVisitor(assetId, annotationMatcher); + // TODO(kegluneq): Parse `declarations` in the NgDepsModel as well. + parsedCode.accept(ngDepsVisitor); + var ngDepsModel = ngDepsVisitor.model; + + // If this file imports only dart: libraries and does not define any + // reflectables of its own, it doesn't need a .ng_deps.dart file. + if (!directivesVisitor.usesNonLangLibs && + (ngDepsModel.reflectables == null || ngDepsModel.reflectables.isEmpty)) { + return null; } - writer.println('}'); - if (!directivesVisitor.shouldCreateNgDeps && - !declarationsVisitor.shouldCreateNgDeps) return null; + var ngMetaVisitor = new _NgMetaVisitor(ngMeta); + parsedCode.accept(ngMetaVisitor); - return writer.asyncToString(); + if (inlineViews) { + await inlineViewProps(new XhrImpl(reader, assetId), ngDepsModel); + } + + var buffer = new StringBuffer(); + var ngDepsWriter = new NgDepsWriter(buffer); + ngDepsWriter.writeNgDepsModel(ngDepsModel); + return '$buffer'; } /// Processes `visitor.parts`, reading and appending their contents to the @@ -78,8 +79,8 @@ Future createNgDeps(AssetReader reader, AssetId assetId, /// part 'lib1.dart' /// part 'lib2.dart' /// ``` -/// The output will first have the entirety of the original file, followed by -/// the contents of lib1.dart followed by the contents of lib2.dart. +/// The output will first have the contents of lib1 followed by the contents of +/// lib2.dart, followed by the original code in the library. Future _getAllDeclarations(AssetReader reader, AssetId assetId, String code, _NgDepsDirectivesVisitor visitor) { if (visitor.parts.isEmpty) return new Future.value(code); @@ -127,241 +128,50 @@ class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor { /// visited a `part of` directive. bool _isPart = false; - // TODO(kegluneq): Support an intermediate representation of NgDeps and use it - // instead of storing generated code. - LibraryDirective _library = null; - ScriptTag _scriptTag = null; - final List _importAndExports = []; final List _parts = []; - bool get shouldCreateNgDeps { - // If this library does not define an `@Injectable` and it does not import - // any libaries that could, then we do not need to generate a `.ng_deps - // .dart` file for it. - if (!_usesNonLangLibs) return false; - if (_isPart) return false; - - return true; - } - bool get usesNonLangLibs => _usesNonLangLibs; bool get isPart => _isPart; /// In the order encountered in the source. Iterable get parts => _parts; - @override - Object visitScriptTag(ScriptTag node) { - _scriptTag = node; - return null; - } - - @override - Object visitCompilationUnit(CompilationUnit node) { - node.directives.accept(this); - return null; - } - - void _updateUsesNonLangLibs(UriBasedDirective directive) { + Object _updateUsesNonLangLibs(UriBasedDirective directive) { _usesNonLangLibs = _usesNonLangLibs || !stringLiteralToString(directive.uri).startsWith('dart:'); - } - - @override - Object visitImportDirective(ImportDirective node) { - _updateUsesNonLangLibs(node); - _importAndExports.add(node); return null; } @override - Object visitExportDirective(ExportDirective node) { - _updateUsesNonLangLibs(node); - _importAndExports.add(node); - return null; - } + Object visitExportDirective(ExportDirective node) => + _updateUsesNonLangLibs(node); @override - Object visitLibraryDirective(LibraryDirective node) { - if (node != null) { - _library = node; - } - return null; - } + Object visitImportDirective(ImportDirective node) => + _updateUsesNonLangLibs(node); @override Object visitPartDirective(PartDirective node) { _parts.add(node); return null; } - - @override - Object visitPartOfDirective(PartOfDirective node) { - _isPart = true; - return null; - } - - /// Write the directives for the .ng_deps.dart for `processedFile` to - /// `writer`. The .ng_deps.dart file has the same directives as - /// `processedFile` with some exceptions (mentioned below). - void writeTo(PrintWriter writer, AssetId processedFile) { - var copyVisitor = new ToSourceVisitor(writer); - - if (_scriptTag != null) { - _scriptTag.accept(copyVisitor); - writer.newLine(); - } - - if (_library != null && _library.name != null) { - writer.print('library '); - _library.name.accept(copyVisitor); - writer.println('$DEPS_EXTENSION;'); - } - - // We do not output [PartDirective]s, which would not be valid now that we - // have changed the library. - - // We need to import & export the original file. - var origDartFile = path.basename(processedFile.path); - writer.println('''import '$origDartFile';'''); - writer.println('''export '$origDartFile';'''); - - // Used to register reflective information. - writer.println("import '$_REFLECTOR_IMPORT' as $_REF_PREFIX;"); - - _importAndExports.forEach((node) { - if (node.isSynthetic) return; - - // Ignore deferred imports here so as to not load the deferred libraries - // code in the current library causing much of the code to not be - // deferred. Instead `DeferredRewriter` will rewrite the code as to load - // `ng_deps` in a deferred way. - if (node is ImportDirective && node.deferredKeyword != null) return; - - node.accept(copyVisitor); - }); - } } /// Visitor responsible for visiting a file's [Declaration]s and outputting the /// code necessary to register the file with the Angular 2 system. -class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor { - final AsyncStringWriter writer; - - /// The file we are processing. - final AssetId assetId; - +class _NgMetaVisitor extends Object with SimpleAstVisitor { /// Output ngMeta information about aliases. // TODO(sigmund): add more to ngMeta. Currently this only contains aliasing // information, but we could produce here all the metadata we need and avoid // parsing the ngdeps files later. final NgMeta ngMeta; - /// Whether an Angular 2 `Injectable` has been found. - bool _foundNgInjectable = false; - - /// Visitor that writes out code for AstNodes visited. - final ToSourceVisitor _copyVisitor; - final FactoryTransformVisitor _factoryVisitor; - final ParameterTransformVisitor _paramsVisitor; - final AnnotationsTransformVisitor _metaVisitor; - - /// Responsible for testing whether [Annotation]s are those recognized by - /// Angular 2, for example `@Component`. - final AnnotationMatcher _annotationMatcher; - - /// Used to fetch linked files. - final XHR _xhr; - - _NgDepsDeclarationsVisitor(AssetId assetId, AsyncStringWriter writer, XHR xhr, - AnnotationMatcher annotationMatcher, this.ngMeta, - {bool inlineViews}) - : writer = writer, - _copyVisitor = new ToSourceVisitor(writer), - _factoryVisitor = new FactoryTransformVisitor(writer), - _paramsVisitor = new ParameterTransformVisitor(writer), - _metaVisitor = new AnnotationsTransformVisitor( - writer, xhr, annotationMatcher, assetId, - inlineViews: inlineViews), - _annotationMatcher = annotationMatcher, - this.assetId = assetId, - _xhr = xhr; - - bool get shouldCreateNgDeps => _foundNgInjectable; - - ConstructorDeclaration _getCtor(ClassDeclaration node) { - int numCtorsFound = 0; - var ctor = null; - - for (ClassMember classMember in node.members) { - if (classMember is ConstructorDeclaration) { - numCtorsFound++; - ConstructorDeclaration constructor = classMember; - - // Use the unnnamed constructor if it is present. - // Otherwise, use the first encountered. - if (ctor == null) { - ctor = constructor; - } else if (constructor.name == null) { - ctor = constructor; - } - } - } - if (numCtorsFound > 1) { - var ctorName = ctor.name; - ctorName = ctorName == null - ? 'the unnamed constructor' - : 'constructor "${ctorName}"'; - logger.warning('Found ${numCtorsFound} ctors for class ${node.name},' - 'Using ${ctorName}.'); - } - return ctor; - } - - void _generateEmptyFactory(String typeName) { - writer.print('() => new ${typeName}()'); - } - - void _generateEmptyParams() => writer.print('const []'); + _NgMetaVisitor(this.ngMeta); @override - Object visitClassDeclaration(ClassDeclaration node) { - if (!node.metadata - .any((a) => _annotationMatcher.hasMatch(a.name, assetId))) { - return null; - } - - var ctor = _getCtor(node); - - _maybeWriteReflector(); - writer.print('..registerType('); - node.name.accept(this); - writer.print(', new ${_REF_PREFIX}.ReflectionInfo('); - node.accept(_metaVisitor); - writer.print(', '); - if (ctor == null) { - _generateEmptyParams(); - } else { - ctor.accept(_paramsVisitor); - } - writer.print(', '); - if (ctor == null) { - _generateEmptyFactory(node.name.toString()); - } else { - ctor.accept(_factoryVisitor); - } - if (node.implementsClause != null && - node.implementsClause.interfaces != null && - node.implementsClause.interfaces.isNotEmpty) { - writer - ..print(', const [') - ..print(node.implementsClause.interfaces - .map((interface) => interface.name) - .join(', ')) - ..print(']'); - } - writer.print('))'); - return null; + Object visitCompilationUnit(CompilationUnit node) { + if (node == null || node.declarations == null) return null; + return node.declarations.accept(this); } @override @@ -386,47 +196,4 @@ class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor { } return null; } - - Object _nodeToSource(AstNode node) { - if (node == null) return null; - return node.accept(_copyVisitor); - } - - @override - Object visitPrefixedIdentifier(PrefixedIdentifier node) => - _nodeToSource(node); - - @override - Object visitSimpleIdentifier(SimpleIdentifier node) => _nodeToSource(node); - - @override - bool visitFunctionDeclaration(FunctionDeclaration node) { - if (!node.metadata - .any((a) => _annotationMatcher.hasMatch(a.name, assetId))) { - return null; - } - - _maybeWriteReflector(); - writer.print('..registerFunction('); - node.name.accept(this); - writer.print(', new ${_REF_PREFIX}.ReflectionInfo(const ['); - node.metadata.accept(_metaVisitor); - writer.print('], const ['); - node.functionExpression.parameters.accept(_paramsVisitor); - writer.print(']))'); - return null; - } - - /// Writes out the reflector variable the first time it is called. - void _maybeWriteReflector() { - if (_foundNgInjectable) return; - _foundNgInjectable = true; - - // The receiver for cascaded calls. - writer.print('$_REF_PREFIX.$REFLECTOR_VAR_NAME'); - } } - -const _REF_PREFIX = '_ngRef'; -const _REFLECTOR_IMPORT = - 'package:angular2/src/core/reflection/reflection.dart'; diff --git a/modules_dart/transform/lib/src/transform/directive_processor/visitors.dart b/modules_dart/transform/lib/src/transform/directive_processor/visitors.dart deleted file mode 100644 index de614747ba..0000000000 --- a/modules_dart/transform/lib/src/transform/directive_processor/visitors.dart +++ /dev/null @@ -1,341 +0,0 @@ -library angular2.transform.directive_processor.visitors; - -import 'dart:async'; -import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/java_core.dart'; -import 'package:angular2/src/core/render/xhr.dart' show XHR; -import 'package:angular2/src/transform/common/annotation_matcher.dart'; -import 'package:angular2/src/transform/common/async_string_writer.dart'; -import 'package:angular2/src/transform/common/logging.dart'; -import 'package:barback/barback.dart'; - -/// `ToSourceVisitor` designed to accept {@link ConstructorDeclaration} nodes. -class _CtorTransformVisitor extends ToSourceVisitor { - bool _withParameterAnnotations = true; - bool _withParameterTypes = true; - bool _withParameterNames = true; - final PrintWriter writer; - - /// Maps field names to their declared types. This is populated whenever - /// the listener visits a {@link ConstructorDeclaration} node. - final Map _fieldNameToType = {}; - - _CtorTransformVisitor(PrintWriter writer) - : this.writer = writer, - super(writer); - - void _visitNodeWithPrefix(String prefix, AstNode node) { - if (node != null) { - writer.print(prefix); - node.accept(this); - } - } - - void _visitNodeWithSuffix(AstNode node, String suffix) { - if (node != null) { - node.accept(this); - writer.print(suffix); - } - } - - void _visitNode(AstNode node) { - if (node != null) { - node.accept(this); - } - } - - /// If `_withParameterTypes` is true, this method outputs `node`'s type. If - /// `_withParameterNames` is true, this method outputs `node`'s identifier. - Object _visitNormalFormalParameter( - NodeList metadata, TypeName type, SimpleIdentifier name) { - var needCompileTimeConstants = !_withParameterNames; - var needType = _withParameterTypes && type != null; - if (needType) { - _visitNodeWithSuffix(type.name, ' '); - if (!needCompileTimeConstants) { - // Types with arguments are not compile-time constants. - _visitNodeWithSuffix(type.typeArguments, ' '); - } - } - if (_withParameterNames) { - _visitNode(name); - } - if (_withParameterAnnotations && metadata != null) { - assert(_withParameterTypes); - for (var i = 0, iLen = metadata.length; i < iLen; ++i) { - if (i != 0 || needType) { - writer.print(', '); - } - metadata[i].accept(this); - } - } - return null; - } - - void _buildFieldMap(ConstructorDeclaration node) { - ClassDeclaration clazz = - node.getAncestor((node) => node is ClassDeclaration); - _fieldNameToType.clear(); - clazz.members - .where((member) => member is FieldDeclaration) - .forEach((FieldDeclaration field) { - var type = field.fields.type; - if (type != null) { - field.fields.variables.forEach((VariableDeclaration decl) { - _fieldNameToType[decl.name.toString()] = type; - }); - } - }); - } - - @override - Object visitSimpleFormalParameter(SimpleFormalParameter node) { - return _visitNormalFormalParameter( - node.metadata, node.type, node.identifier); - } - - @override - Object visitFieldFormalParameter(FieldFormalParameter node) { - if (node.parameters != null) { - logger.error('Parameters in ctor not supported ' - '(${node.toSource()})'); - } - var type = node.type; - if (type == null) { - type = _fieldNameToType[node.identifier.toString()]; - } - return _visitNormalFormalParameter(node.metadata, type, node.identifier); - } - - @override - Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { - logger.error('Function typed formal parameters not supported ' - '(${node.toSource()})'); - return _visitNormalFormalParameter(node.metadata, null, node.identifier); - } - - @override - Object visitDefaultFormalParameter(DefaultFormalParameter node) { - _visitNode(node.parameter); - // Ignore the declared default value. - return null; - } - - @override - - /// Overridden to avoid outputting grouping operators for default parameters. - Object visitFormalParameterList(FormalParameterList node) { - writer.print('('); - NodeList parameters = node.parameters; - int size = parameters.length; - for (int i = 0; i < size; i++) { - if (i > 0) { - writer.print(', '); - } - parameters[i].accept(this); - } - writer.print(')'); - return null; - } - - @override - Object visitAnnotation(Annotation node) { - var prefix = - node.arguments != null && node.arguments.length > 0 ? 'const ' : ''; - _visitNodeWithPrefix(prefix, node.name); - _visitNodeWithPrefix(".", node.constructorName); - _visitNode(node.arguments); - return null; - } -} - -/// ToSourceVisitor designed to print 'parameters' values for Angular2's -/// `registerType` calls. -class ParameterTransformVisitor extends _CtorTransformVisitor { - ParameterTransformVisitor(PrintWriter writer) : super(writer) { - _withParameterNames = false; - _withParameterTypes = true; - _withParameterAnnotations = true; - } - - @override - Object visitConstructorDeclaration(ConstructorDeclaration node) { - _buildFieldMap(node); - writer.print('const ['); - _visitNode(node.parameters); - writer.print(']'); - return null; - } - - @override - Object visitFormalParameterList(FormalParameterList node) { - NodeList parameters = node.parameters; - for (int i = 0, iLen = parameters.length; i < iLen; i++) { - if (i > 0) { - writer.print(', '); - } - // TODO(kegluneq): Include annotations on parameters. - writer.print('const ['); - parameters[i].accept(this); - writer.print(']'); - } - return null; - } -} - -/// ToSourceVisitor designed to print 'factory' values for Angular2's -/// `registerType` calls. -class FactoryTransformVisitor extends _CtorTransformVisitor { - FactoryTransformVisitor(PrintWriter writer) : super(writer) { - _withParameterAnnotations = false; - } - - @override - Object visitConstructorDeclaration(ConstructorDeclaration node) { - _buildFieldMap(node); - _withParameterNames = true; - _withParameterTypes = true; - _visitNode(node.parameters); - writer.print(' => new '); - _visitNode(node.returnType); - _visitNodeWithPrefix(".", node.name); - - _withParameterTypes = false; - _visitNode(node.parameters); - return null; - } -} - -/// ToSourceVisitor designed to print a `ClassDeclaration` node as a -/// 'annotations' value for Angular2's `registerType` calls. -class AnnotationsTransformVisitor extends ToSourceVisitor { - final AsyncStringWriter writer; - final XHR _xhr; - final AnnotationMatcher _annotationMatcher; - final AssetId _assetId; - final bool _inlineViews; - final ConstantEvaluator _evaluator = new ConstantEvaluator(); - bool _isProcessingView = false; - bool _isProcessingDirective = false; - - AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr, - this._annotationMatcher, this._assetId, {bool inlineViews}) - : writer = writer, - _inlineViews = inlineViews, - super(writer); - - void _resetState() { - _isProcessingView = _isProcessingDirective = false; - } - - @override - Object visitClassDeclaration(ClassDeclaration node) { - writer.print('const ['); - var size = node.metadata.length; - for (var i = 0; i < size; ++i) { - if (i > 0) { - writer.print(', '); - } - node.metadata[i].accept(this); - } - writer.print(']'); - - _resetState(); - return null; - } - - @override - Object visitAnnotation(Annotation node) { - writer.print('const '); - if (node.name != null) { - _isProcessingDirective = _annotationMatcher.isDirective(node, _assetId); - _isProcessingView = _annotationMatcher.isView(node, _assetId); - node.name.accept(this); - } else { - _isProcessingDirective = false; - _isProcessingView = false; - } - if (node.constructorName != null) { - writer.print('.'); - node.constructorName.accept(this); - } - if (node.arguments != null && node.arguments.arguments != null) { - var args = node.arguments.arguments; - writer.print('('); - for (var i = 0, iLen = args.length; i < iLen; ++i) { - if (i != 0) { - writer.print(', '); - } - args[i].accept(this); - } - writer.print(')'); - } - return null; - } - - /// These correspond to the annotation parameters. - @override - Object visitNamedExpression(NamedExpression node) { - if (!_isProcessingView && !_isProcessingDirective) { - return super.visitNamedExpression(node); - } - // TODO(kegluneq): Remove this limitation. - if (node.name is! Label || node.name.label is! SimpleIdentifier) { - return super.visitNamedExpression(node); - } - var keyString = '${node.name.label}'; - if (_isProcessingView && _inlineViews) { - var isSuccess = this._inlineView(keyString, node.expression); - if (isSuccess) return null; - } - return super.visitNamedExpression(node); - } - - /// Inlines the template and/or style refered to by `keyString`. - /// Returns whether the `keyString` value was successfully processed. - bool _inlineView(String keyString, AstNode node) { - if (keyString == 'templateUrl') { - // Inline the templateUrl - var url = node.accept(_evaluator); - if (url is String) { - writer.print("template: r'''"); - writer.asyncPrint(_readOrEmptyString(url)); - writer.print("'''"); - - // We keep the templateUrl in case the body of the template includes - // relative urls that might be inlined later on (e.g. @import - // directives or url() css values in style tags). - writer.print(", templateUrl: r'$url'"); - return true; - } else { - logger.warning('template url is not a String $url'); - } - } else if (keyString == 'styleUrls') { - // Inline the styleUrls - var urls = node.accept(_evaluator); - writer.print('styles: const ['); - for (var url in urls) { - if (url is String) { - writer.print("r'''"); - writer.asyncPrint(_readOrEmptyString(url)); - writer.print("''', "); - } else { - logger.warning('style url is not a String ${url}'); - } - } - writer.print(']'); - return true; - } - return false; - } - - /// Attempts to read the content from {@link url}, if it returns null then - /// just return the empty string. - Future _readOrEmptyString(String url) async { - var content = await _xhr.get(url); - if (content == null) { - content = ''; - } - return content; - } -} diff --git a/modules_dart/transform/test/transform/common/convert_spec.dart b/modules_dart/transform/test/transform/common/convert_spec.dart index 4117bc732a..9a307e52e5 100644 --- a/modules_dart/transform/test/transform/common/convert_spec.dart +++ b/modules_dart/transform/test/transform/common/convert_spec.dart @@ -13,9 +13,15 @@ main() { it("directiveMetadataToMap", () { var someComponent = new RenderDirectiveMetadata( compileChildren: false, - hostListeners: MapWrapper.createFromPairs([["LKey", "LVal"]]), - hostProperties: MapWrapper.createFromPairs([["PKey", "PVal"]]), - hostAttributes: MapWrapper.createFromPairs([["AtKey", "AtVal"]]), + hostListeners: MapWrapper.createFromPairs([ + ["LKey", "LVal"] + ]), + hostProperties: MapWrapper.createFromPairs([ + ["PKey", "PVal"] + ]), + hostAttributes: MapWrapper.createFromPairs([ + ["AtKey", "AtVal"] + ]), id: "someComponent", properties: ["propKey: propVal"], readAttributes: ["read1", "read2"], @@ -34,12 +40,15 @@ main() { changeDetection: ChangeDetectionStrategy.CheckOnce); var map = directiveMetadataToMap(someComponent); expect(map["compileChildren"]).toEqual(false); - expect(map["hostListeners"]) - .toEqual(MapWrapper.createFromPairs([["LKey", "LVal"]])); - expect(map["hostProperties"]) - .toEqual(MapWrapper.createFromPairs([["PKey", "PVal"]])); - expect(map["hostAttributes"]) - .toEqual(MapWrapper.createFromPairs([["AtKey", "AtVal"]])); + expect(map["hostListeners"]).toEqual(MapWrapper.createFromPairs([ + ["LKey", "LVal"] + ])); + expect(map["hostProperties"]).toEqual(MapWrapper.createFromPairs([ + ["PKey", "PVal"] + ])); + expect(map["hostAttributes"]).toEqual(MapWrapper.createFromPairs([ + ["AtKey", "AtVal"] + ])); expect(map["id"]).toEqual("someComponent"); expect(map["properties"]).toEqual(["propKey: propVal"]); expect(map["readAttributes"]).toEqual(["read1", "read2"]); @@ -55,17 +64,39 @@ main() { expect(map["callAfterViewChecked"]).toEqual(true); expect(map["exportAs"]).toEqual("aaa"); expect(map["events"]).toEqual(["onFoo", "onBar"]); - expect(map["changeDetection"]).toEqual(ChangeDetectionStrategy.CheckOnce.index); + expect(map["changeDetection"]) + .toEqual(ChangeDetectionStrategy.CheckOnce.index); }); it("mapToDirectiveMetadata", () { var map = MapWrapper.createFromPairs([ ["compileChildren", false], - ["hostProperties", MapWrapper.createFromPairs([["PKey", "testVal"]])], - ["hostListeners", MapWrapper.createFromPairs([["LKey", "testVal"]])], - ["hostAttributes", MapWrapper.createFromPairs([["AtKey", "testVal"]])], + [ + "hostProperties", + MapWrapper.createFromPairs([ + ["PKey", "testVal"] + ]) + ], + [ + "hostListeners", + MapWrapper.createFromPairs([ + ["LKey", "testVal"] + ]) + ], + [ + "hostAttributes", + MapWrapper.createFromPairs([ + ["AtKey", "testVal"] + ]) + ], ["id", "testId"], - ["properties", ["propKey: propVal"]], - ["readAttributes", ["readTest1", "readTest2"]], + [ + "properties", + ["propKey: propVal"] + ], + [ + "readAttributes", + ["readTest1", "readTest2"] + ], ["selector", "testSelector"], ["type", RenderDirectiveMetadata.DIRECTIVE_TYPE], ["exportAs", "aaa"], @@ -77,17 +108,23 @@ main() { ["callAfterContentChecked", true], ["callAfterViewInit", true], ["callAfterViewChecked", true], - ["events", ["onFoo", "onBar"]], + [ + "events", + ["onFoo", "onBar"] + ], ["changeDetection", ChangeDetectionStrategy.CheckOnce.index] ]); var meta = directiveMetadataFromMap(map); expect(meta.compileChildren).toEqual(false); - expect(meta.hostProperties) - .toEqual(MapWrapper.createFromPairs([["PKey", "testVal"]])); - expect(meta.hostListeners) - .toEqual(MapWrapper.createFromPairs([["LKey", "testVal"]])); - expect(meta.hostAttributes) - .toEqual(MapWrapper.createFromPairs([["AtKey", "testVal"]])); + expect(meta.hostProperties).toEqual(MapWrapper.createFromPairs([ + ["PKey", "testVal"] + ])); + expect(meta.hostListeners).toEqual(MapWrapper.createFromPairs([ + ["LKey", "testVal"] + ])); + expect(meta.hostAttributes).toEqual(MapWrapper.createFromPairs([ + ["AtKey", "testVal"] + ])); expect(meta.id).toEqual("testId"); expect(meta.properties).toEqual(["propKey: propVal"]); expect(meta.readAttributes).toEqual(["readTest1", "readTest2"]); diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart index c1831108e2..047c853829 100644 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart +++ b/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart @@ -121,7 +121,8 @@ void allTests() { it('should parse changeDetection.', () async { var metadata = await readMetadata('directive_metadata_extractor/' 'directive_metadata_files/changeDetection.ng_deps.dart'); - expect(metadata.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce); + expect(metadata.changeDetection) + .toEqual(ChangeDetectionStrategy.CheckOnce); }); it('should fail when a class is annotated with multiple Directives.', diff --git a/modules_dart/transform/test/transform/directive_processor/absolute_url_expression_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/absolute_url_expression_files/expected/hello.ng_deps.dart index f3d3bbf549..7b8240b498 100644 --- a/modules_dart/transform/test/transform/directive_processor/absolute_url_expression_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/absolute_url_expression_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.absolute_url_expression_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -16,9 +16,9 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), const View( + styles: const [r'''.greeting { .color: blue; }''',], template: r'''{{greeting}}''', - templateUrl: r'package:other_package/template.html', - styles: const [r'''.greeting { .color: blue; }''',]) + templateUrl: 'package:other_package/template.html') ], const [], () => new HelloCmp())) ..registerFunction( hello, new _ngRef.ReflectionInfo(const [const Injectable()], const [])); diff --git a/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart index eef81b8b42..64742ce501 100644 --- a/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart @@ -1,9 +1,9 @@ library dinner.package_soup.ng_deps.dart; import 'package_soup.dart'; -export 'package_soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:soup/soup.dart'; +export 'package_soup.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart index 0a42db0821..1e3b1ea817 100644 --- a/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart @@ -1,9 +1,9 @@ library dinner.relative_soup.ng_deps.dart; import 'relative_soup.dart'; -export 'relative_soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'annotations/soup.dart'; +export 'relative_soup.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/directive_aliases_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/directive_aliases_files/expected/hello.ng_deps.dart index 663bff3da9..d3686bfd8a 100644 --- a/modules_dart/transform/test/transform/directive_processor/directive_aliases_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/directive_aliases_files/expected/hello.ng_deps.dart @@ -1,12 +1,12 @@ library examples.src.hello_world.absolute_url_expression_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show bootstrap, Component, Directive, View, NgElement; -export 'a.dart' show alias3; import 'b.dart' as b; +export 'hello.dart'; +export 'a.dart' show alias3; var _visited = false; void initReflector() { @@ -18,8 +18,8 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), const View( + styles: const [r'''.greeting { .color: blue; }''',], template: r'''{{greeting}}''', - templateUrl: r'template.html', - styles: const [r'''.greeting { .color: blue; }''',]) + templateUrl: 'template.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/directive_processor/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/expected/hello.ng_deps.dart index 435ccb9b55..c6c89b83a3 100644 --- a/modules_dart/transform/test/transform/directive_processor/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.index_common_dart.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/interface_chain_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/interface_chain_files/expected/soup.ng_deps.dart index de56149629..11125c249b 100644 --- a/modules_dart/transform/test/transform/directive_processor/interface_chain_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/interface_chain_files/expected/soup.ng_deps.dart @@ -1,9 +1,9 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/interface_lifecycle_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/interface_lifecycle_files/expected/soup.ng_deps.dart new file mode 100644 index 0000000000..b94882d72d --- /dev/null +++ b/modules_dart/transform/test/transform/directive_processor/interface_lifecycle_files/expected/soup.ng_deps.dart @@ -0,0 +1,99 @@ +library dinner.soup.ng_deps.dart; + +import 'soup.dart'; +import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; +import 'package:angular2/metadata.dart'; +export 'soup.dart'; + +var _visited = false; +void initReflector() { + if (_visited) return; + _visited = true; + _ngRef.reflector + ..registerType( + OnChangeSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.OnChanges]) + ], + const [], + () => new OnChangeSoupComponent(), + const [OnChanges])) + ..registerType( + OnDestroySoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.OnDestroy]) + ], + const [], + () => new OnDestroySoupComponent(), + const [OnDestroy])) + ..registerType( + OnCheckSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', lifecycle: const [LifecycleEvent.DoCheck]) + ], + const [], + () => new OnCheckSoupComponent(), + const [DoCheck])) + ..registerType( + OnInitSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', lifecycle: const [LifecycleEvent.OnInit]) + ], + const [], + () => new OnInitSoupComponent(), + const [OnInit])) + ..registerType( + AfterContentInitSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.AfterContentInit]) + ], + const [], + () => new AfterContentInitSoupComponent(), + const [AfterContentInit])) + ..registerType( + AfterContentCheckedSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.AfterContentChecked]) + ], + const [], + () => new AfterContentCheckedSoupComponent(), + const [AfterContentChecked])) + ..registerType( + AfterViewInitSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.AfterViewInit]) + ], + const [], + () => new AfterViewInitSoupComponent(), + const [AfterViewInit])) + ..registerType( + AfterViewCheckedSoupComponent, + new _ngRef.ReflectionInfo( + const [ + const Component( + selector: '[soup]', + lifecycle: const [LifecycleEvent.AfterViewChecked]) + ], + const [], + () => new AfterViewCheckedSoupComponent(), + const [AfterViewChecked])); +} diff --git a/modules_dart/transform/test/transform/directive_processor/interfaces_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/interfaces_files/expected/soup.ng_deps.dart index 01996b2bc0..47e5762d18 100644 --- a/modules_dart/transform/test/transform/directive_processor/interfaces_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/interfaces_files/expected/soup.ng_deps.dart @@ -1,10 +1,10 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; import 'package:angular2/src/core/compiler.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { @@ -14,8 +14,7 @@ void initReflector() { ..registerType( ChangingSoupComponent, new _ngRef.ReflectionInfo( - const [ - const Component(selector: '[soup]')], + const [const Component(selector: '[soup]')], const [], () => new ChangingSoupComponent(), const [OnChanges, AnotherInterface])); diff --git a/modules_dart/transform/test/transform/directive_processor/invalid_url_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/invalid_url_files/expected/hello.ng_deps.dart index d1fefa49ef..8eb198dffd 100644 --- a/modules_dart/transform/test/transform/directive_processor/invalid_url_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/invalid_url_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library test.transform.directive_processor.invalid_url_files.hello.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -16,8 +16,8 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), const View( + styles: const [r'''''', r'''''',], template: r'''''', - templateUrl: r'/bad/absolute/url.html', - styles: const [r'''''', r'''''',]) + templateUrl: '/bad/absolute/url.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/expected/soup.ng_deps.dart index 70d538f7ed..7340342dd9 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/expected/soup.ng_deps.dart @@ -1,10 +1,10 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; import 'package:angular2/src/core/compiler.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { @@ -14,9 +14,7 @@ void initReflector() { ..registerType( MultiSoupComponent, new _ngRef.ReflectionInfo( - const [ - const Component(selector: '[soup]') - ], + const [const Component(selector: '[soup]')], const [], () => new MultiSoupComponent(), const [OnChanges, OnDestroy, OnInit])); diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/expected/main.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/expected/main.ng_deps.dart index 07a8e854c0..b3487d2187 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/expected/main.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/expected/main.ng_deps.dart @@ -1,9 +1,9 @@ library main.ng_deps.dart; import 'main.dart'; -export 'main.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'main.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/expected/hello.ng_deps.dart index b794919fa5..1224ae0b91 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.multiple_style_urls_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -15,12 +15,9 @@ void initReflector() { HelloCmp, new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), - const View( - template: r'''{{greeting}}''', - templateUrl: r'template.html', - styles: const [ - r'''.greeting { .color: blue; }''', - r'''.hello { .color: red; }''', - ]) + const View(styles: const [ + r'''.greeting { .color: blue; }''', + r'''.hello { .color: red; }''', + ], template: r'''{{greeting}}''', templateUrl: 'template.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/expected/hello.ng_deps.dart index 96f9ea6036..d66d30edc1 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.multiple_style_urls_not_inlined_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -15,11 +15,9 @@ void initReflector() { HelloCmp, new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), - const View( - templateUrl: 'package:a/template.html', - styleUrls: const [ - 'package:a/template.css', - 'package:a/template_other.css' - ]) + const View(styleUrls: const [ + 'package:a/template.css', + 'package:a/template_other.css' + ], templateUrl: 'package:a/template.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart index 0f04c85ad2..9f5bff77cb 100644 --- a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/expected/soup.ng_deps.dart @@ -1,9 +1,9 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { @@ -15,7 +15,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]') ], const [ - const [String, Tasty], + const [String,const Tasty()], const [const Inject(Salt)] ], (String description, salt) => new SoupComponent(description, salt))); } diff --git a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart index 8603449f21..077afbf388 100644 --- a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart @@ -4,5 +4,5 @@ import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') class SoupComponent { - SoupComponent(@Tasty String description, @Inject(Salt) salt); + SoupComponent(@Tasty() String description, @Inject(Salt) salt); } diff --git a/modules_dart/transform/test/transform/directive_processor/part_files/expected/main.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/part_files/expected/main.ng_deps.dart index fb4a9816ae..64cde91181 100644 --- a/modules_dart/transform/test/transform/directive_processor/part_files/expected/main.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/part_files/expected/main.ng_deps.dart @@ -1,9 +1,9 @@ library main.ng_deps.dart; import 'main.dart'; -export 'main.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'main.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/expected/soup.ng_deps.dart index c9afa4529e..fcb48f2ba9 100644 --- a/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/expected/soup.ng_deps.dart @@ -1,10 +1,10 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/compiler.dart' as prefix; import 'package:angular2/src/core/metadata.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/expected/hello.ng_deps.dart index 729787d93a..2501e8032b 100644 --- a/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.split_url_expression_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -16,6 +16,6 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), const View( - template: r'''{{greeting}}''', templateUrl: r'template.html') + template: r'''{{greeting}}''', templateUrl: 'templ' 'ate.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart index cf8b144f0f..a0e1f6540c 100644 --- a/modules_dart/transform/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart @@ -1,9 +1,9 @@ library static_function_files.hello.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart'; +export 'hello.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/superclass_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/superclass_files/expected/soup.ng_deps.dart index 9053640c79..7e2bd283f4 100644 --- a/modules_dart/transform/test/transform/directive_processor/superclass_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/superclass_files/expected/soup.ng_deps.dart @@ -1,9 +1,9 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/expected/soup.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/expected/soup.ng_deps.dart index b5e5dd2328..6862c8422c 100644 --- a/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/expected/soup.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/expected/soup.ng_deps.dart @@ -1,10 +1,10 @@ library dinner.soup.ng_deps.dart; import 'soup.dart'; -export 'soup.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/compiler.dart'; import 'package:angular2/src/core/metadata.dart'; +export 'soup.dart'; var _visited = false; void initReflector() { @@ -13,8 +13,6 @@ void initReflector() { _ngRef.reflector ..registerType( OnChangeSoupComponent, - new _ngRef.ReflectionInfo(const [ - const Component( - selector: '[soup]') - ], const [], () => new OnChangeSoupComponent())); + new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')], + const [], () => new OnChangeSoupComponent())); } diff --git a/modules_dart/transform/test/transform/directive_processor/url_expression_files/expected/hello.ng_deps.dart b/modules_dart/transform/test/transform/directive_processor/url_expression_files/expected/hello.ng_deps.dart index 39c0f51489..902eacfff0 100644 --- a/modules_dart/transform/test/transform/directive_processor/url_expression_files/expected/hello.ng_deps.dart +++ b/modules_dart/transform/test/transform/directive_processor/url_expression_files/expected/hello.ng_deps.dart @@ -1,10 +1,10 @@ library examples.src.hello_world.url_expression_files.ng_deps.dart; import 'hello.dart'; -export 'hello.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/angular2.dart' show Component, Directive, View, NgElement; +export 'hello.dart'; var _visited = false; void initReflector() { @@ -16,6 +16,6 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'hello-app'), const View( - template: r'''{{greeting}}''', templateUrl: r'template.html') + template: r'''{{greeting}}''', templateUrl: 'template.html') ], const [], () => new HelloCmp())); } diff --git a/modules_dart/transform/test/transform/integration/all_tests.dart b/modules_dart/transform/test/transform/integration/all_tests.dart index f4bea6378a..5839cc8dbd 100644 --- a/modules_dart/transform/test/transform/integration/all_tests.dart +++ b/modules_dart/transform/test/transform/integration/all_tests.dart @@ -12,9 +12,8 @@ main() { } var formatter = new DartFormatter(); -var transform = new AngularTransformerGroup(new TransformerOptions( - ['web/index.dart'], - formatCode: true)); +var transform = new AngularTransformerGroup( + new TransformerOptions(['web/index.dart'], formatCode: true)); class IntegrationTestConfig { final String name; @@ -96,7 +95,8 @@ void allTests() { new IntegrationTestConfig('should preserve multiple annotations.', inputs: { 'a|web/index.dart': 'two_annotations_files/index.dart', 'a|web/bar.dart': 'two_annotations_files/bar.dart', - 'angular2|lib/src/core/metadata.dart': '../../../lib/src/core/metadata.dart' + 'angular2|lib/src/core/metadata.dart': + '../../../lib/src/core/metadata.dart' }, outputs: { 'a|web/bar.ng_deps.dart': 'two_annotations_files/expected/bar.ng_deps.dart' diff --git a/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart index 6322dc644d..45c76dd7ff 100644 --- a/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart @@ -1,10 +1,10 @@ library bar.ng_deps.dart; import 'bar.dart'; -export 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; import 'foo.dart'; +export 'bar.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart index 542e1d1011..d2d5b35c27 100644 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart @@ -1,9 +1,9 @@ library bar.ng_deps.dart; import 'bar.dart'; -export 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'bar.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart index 41597dac28..1ba4fe342a 100644 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart @@ -1,13 +1,13 @@ library web_foo.ng_deps.dart; import 'index.dart'; -export 'index.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/bootstrap_static.dart'; import 'index.ng_deps.dart' as ngStaticInit; import 'package:angular2/src/core/reflection/reflection.dart'; import 'bar.dart'; import 'bar.ng_deps.dart' as i0; +export 'index.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart index 542e1d1011..d2d5b35c27 100644 --- a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart @@ -1,9 +1,9 @@ library bar.ng_deps.dart; import 'bar.dart'; -export 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'bar.dart'; var _visited = false; void initReflector() { diff --git a/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart index e3a153f8e9..f64eb38b4d 100644 --- a/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart @@ -4,19 +4,21 @@ import 'package:angular2/src/core/change_detection/pregen_proto_change_detector. as _gen; import 'bar.dart'; -export 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; +export 'bar.dart'; var _visited = false; void initReflector() { if (_visited) return; _visited = true; _ngRef.reflector - ..registerType(MyComponent, new _ngRef.ReflectionInfo(const [ - const Component(selector: '[soup]'), - const View(template: 'Salad: {{myNum}} is awesome') - ], const [], () => new MyComponent())) + ..registerType( + MyComponent, + new _ngRef.ReflectionInfo(const [ + const Component(selector: '[soup]'), + const View(template: 'Salad: {{myNum}} is awesome') + ], const [], () => new MyComponent())) ..registerGetters({'myNum': (o) => o.myNum}); _gen.preGeneratedProtoDetectors['MyComponent_comp_0'] = _MyComponent_ChangeDetector0.newProtoChangeDetector; @@ -26,18 +28,19 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector { var myNum0, interpolate1; - _MyComponent_ChangeDetector0(dispatcher) : super( - "MyComponent_comp_0", dispatcher, 2, - _MyComponent_ChangeDetector0.gen_propertyBindingTargets, - _MyComponent_ChangeDetector0.gen_directiveIndices,null) { + _MyComponent_ChangeDetector0(dispatcher) + : super( + "MyComponent_comp_0", + dispatcher, + 2, + _MyComponent_ChangeDetector0.gen_propertyBindingTargets, + _MyComponent_ChangeDetector0.gen_directiveIndices, + null) { dehydrateDirectives(false); } void detectChangesInRecordsInternal(throwOnChange) { - var l_context = this.context, - l_myNum0, - c_myNum0, - l_interpolate1; + var l_context = this.context, l_myNum0, c_myNum0, l_interpolate1; c_myNum0 = false; var isChanged = false; var changes = null; @@ -88,4 +91,4 @@ class _MyComponent_ChangeDetector0 return new _gen.PregenProtoChangeDetector( (a) => new _MyComponent_ChangeDetector0(a), def); } -} \ No newline at end of file +} diff --git a/modules_dart/transform/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart index 0edeea6251..63f94d0327 100644 --- a/modules_dart/transform/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/two_deps_files/expected/bar.ng_deps.dart @@ -1,10 +1,10 @@ library bar.ng_deps.dart; import 'bar.dart'; -export 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; import 'foo.dart' as prefix; +export 'bar.dart'; var _visited = false; void initReflector() {