From 01d5c2951376c9279e5913fb37d45341513b8ba0 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Fri, 8 May 2015 15:03:08 -0700 Subject: [PATCH] fix(transformer): remove classDefParser in favor of hardcoded strings to speed up build --- .../transform/common/annotation_matcher.dart | 157 ++++++++++++++++++ .../src/transform/common/options.dart | 15 +- .../src/transform/common/options_reader.dart | 49 +++++- .../directive_processor/rewriter.dart | 127 +++++--------- .../directive_processor/transformer.dart | 7 +- .../directive_processor/all_tests.dart | 38 +++-- .../custom_metadata/bad_soup.dart | 8 + .../expected/bad_soup.ng_deps.dart | 9 + .../expected/package_soup.ng_deps.dart | 16 ++ .../expected/relative_soup.ng_deps.dart | 16 ++ .../custom_metadata/package_soup.dart | 8 + .../custom_metadata/relative_soup.dart | 8 + 12 files changed, 353 insertions(+), 105 deletions(-) create mode 100644 modules/angular2/src/transform/common/annotation_matcher.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/bad_soup.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/expected/bad_soup.ng_deps.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/package_soup.dart create mode 100644 modules/angular2/test/transform/directive_processor/custom_metadata/relative_soup.dart diff --git a/modules/angular2/src/transform/common/annotation_matcher.dart b/modules/angular2/src/transform/common/annotation_matcher.dart new file mode 100644 index 0000000000..2afb70ae83 --- /dev/null +++ b/modules/angular2/src/transform/common/annotation_matcher.dart @@ -0,0 +1,157 @@ +library angular2.transform.common.annotation_matcher; + +import 'package:analyzer/src/generated/ast.dart'; +import 'package:barback/barback.dart' show AssetId; +import 'package:code_transformers/assets.dart'; +import 'package:path/path.dart' as path; +import 'logging.dart' show logger; + +/// [AnnotationDescriptor]s for the default angular annotations that can appear +/// on a class. These classes are re-exported in many places so this covers all +/// the possible libraries which could provide them. +const INJECTABLES = const [ + const AnnotationDescriptor( + 'Injectable', 'package:angular2/src/di/annotations.dart', null), + const AnnotationDescriptor( + 'Injectable', 'package:angular2/src/di/annotations_impl.dart', null), + const AnnotationDescriptor( + 'Injectable', 'package:angular2/src/di/decorators.dart', null), + const AnnotationDescriptor('Injectable', 'package:angular2/di.dart', null), + const AnnotationDescriptor( + 'Injectable', 'package:angular2/angular2.dart', null), +]; + +const DIRECTIVES = const [ + const AnnotationDescriptor('Directive', + 'package:angular2/src/core/annotations/annotations.dart', 'Injectable'), + const AnnotationDescriptor('Directive', + 'package:angular2/src/core/annotations_impl/annotations.dart', + 'Injectable'), + const AnnotationDescriptor( + 'Directive', 'package:angular2/annotations.dart', 'Injectable'), + const AnnotationDescriptor( + 'Directive', 'package:angular2/angular2.dart', 'Injectable'), + const AnnotationDescriptor( + 'Directive', 'package:angular2/core.dart', 'Injectable'), +]; + +const COMPONENTS = const [ + const AnnotationDescriptor('Component', + 'package:angular2/src/core/annotations/annotations.dart', 'Directive'), + const AnnotationDescriptor('Component', + 'package:angular2/src/core/annotations_impl/annotations.dart', + 'Directive'), + const AnnotationDescriptor( + 'Component', 'package:angular2/annotations.dart', 'Directive'), + const AnnotationDescriptor( + 'Component', 'package:angular2/angular2.dart', 'Directive'), + const AnnotationDescriptor( + 'Component', 'package:angular2/core.dart', 'Directive'), +]; + +const VIEWS = const [ + const AnnotationDescriptor('View', 'package:angular2/view.dart', null), + const AnnotationDescriptor('View', 'package:angular2/angular2.dart', null), + const AnnotationDescriptor('View', 'package:angular2/core.dart', null), + const AnnotationDescriptor( + 'View', 'package:angular2/src/core/annotations/view.dart', null), + const AnnotationDescriptor( + 'View', 'package:angular2/src/core/annotations_impl/view.dart', null), +]; + +/// Checks if a given [Annotation] matches any of the given +/// [AnnotationDescriptors]. +class AnnotationMatcher { + /// Always start out with the default angular [AnnotationDescriptor]s. + final List _annotations = [] + ..addAll(VIEWS) + ..addAll(COMPONENTS) + ..addAll(INJECTABLES) + ..addAll(DIRECTIVES); + + AnnotationMatcher(); + + /// Adds a new [AnnotationDescriptor]. + void add(AnnotationDescriptor annotation) => _annotations.add(annotation); + + /// Adds a number of [AnnotationDescriptor]s. + void addAll(Iterable annotations) => + _annotations.addAll(annotations); + + /// Returns the first [AnnotationDescriptor] that matches the given + /// [Annotation] node which appears in `assetId`. + AnnotationDescriptor firstMatch(Annotation annotation, AssetId assetId) => + _annotations.firstWhere((a) => _matchAnnotation(annotation, a, assetId), + orElse: () => null); + + /// Checks whether an [Annotation] node matches any [AnnotationDescriptor]. + bool hasMatch(Annotation annotation, AssetId assetId) => + _annotations.any((a) => _matchAnnotation(annotation, a, assetId)); + + /// Checks if an [Annotation] node implements [Injectable]. + bool isInjectable(Annotation annotation, AssetId assetId) => + _implements(firstMatch(annotation, assetId), INJECTABLES); + + /// Checks if an [Annotation] node implements [Directive]. + bool isDirective(Annotation annotation, AssetId assetId) => + _implements(firstMatch(annotation, assetId), DIRECTIVES); + + /// Checks if an [Annotation] node implements [Component]. + bool isComponent(Annotation annotation, AssetId assetId) => + _implements(firstMatch(annotation, assetId), COMPONENTS); + + /// Checks if an [Annotation] node implements [View]. + bool isView(Annotation annotation, AssetId assetId) => + _implements(firstMatch(annotation, assetId), VIEWS); + + /// Checks if `descriptor` extends or is any of the supplied `interfaces`. + bool _implements( + AnnotationDescriptor descriptor, List interfaces) { + if (descriptor == null) return false; + if (interfaces.contains(descriptor)) return true; + if (descriptor.superClass == null) return false; + var superClass = _annotations.firstWhere( + (a) => a.name == descriptor.superClass, orElse: () => null); + if (superClass == null) { + logger.warning( + 'Missing `custom_annotation` entry for `${descriptor.superClass}`.'); + return false; + } + return _implements(superClass, interfaces); + } + + // Checks if an [Annotation] matches an [AnnotationDescriptor]. + static bool _matchAnnotation( + Annotation annotation, AnnotationDescriptor descriptor, AssetId assetId) { + if (annotation.name.name != descriptor.name) return false; + return (annotation.root as CompilationUnit).directives + .where((d) => d is ImportDirective) + .any((ImportDirective i) { + var uriString = i.uri.stringValue; + if (uriString == descriptor.import) return true; + if (uriString.startsWith('package:') || uriString.startsWith('dart:')) { + return false; + } + return descriptor.assetId == + uriToAssetId(assetId, uriString, logger, null); + }); + } +} + +/// String based description of an annotation class and its location. +class AnnotationDescriptor { + /// The name of the class. + final String name; + /// A `package:` style import path to the file where the class is defined. + final String import; + /// The class that this class extends or implements. This is the only optional + /// field. + final String superClass; + + AssetId get assetId => new AssetId(package, packagePath); + String get package => path.split(import.replaceFirst('package:', '')).first; + String get packagePath => path.joinAll(['lib'] + ..addAll(path.split(import.replaceFirst('package:', ''))..removeAt(0))); + + const AnnotationDescriptor(this.name, this.import, this.superClass); +} diff --git a/modules/angular2/src/transform/common/options.dart b/modules/angular2/src/transform/common/options.dart index 202a9a3d69..9cc08b11e5 100644 --- a/modules/angular2/src/transform/common/options.dart +++ b/modules/angular2/src/transform/common/options.dart @@ -1,9 +1,11 @@ library angular2.transform.common.options; +import 'annotation_matcher.dart'; import 'mirror_mode.dart'; const ENTRY_POINT_PARAM = 'entry_points'; const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points'; +const CUSTOM_ANNOTATIONS_PARAM = 'custom_annotations'; /// Provides information necessary to transform an Angular2 app. class TransformerOptions { @@ -23,16 +25,23 @@ class TransformerOptions { /// Whether to generate calls to our generated `initReflector` code final bool initReflector; + /// The [AnnotationMatcher] which is used to identify angular annotations. + final AnnotationMatcher annotationMatcher; + TransformerOptions._internal(this.entryPoints, this.reflectionEntryPoints, - this.modeName, this.mirrorMode, this.initReflector); + this.modeName, this.mirrorMode, this.initReflector, + this.annotationMatcher); factory TransformerOptions(List entryPoints, {List reflectionEntryPoints, String modeName: 'release', - MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true}) { + MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true, + List customAnnotationDescriptors: const []}) { if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) { reflectionEntryPoints = entryPoints; } + var annotationMatcher = new AnnotationMatcher() + ..addAll(customAnnotationDescriptors); return new TransformerOptions._internal(entryPoints, reflectionEntryPoints, - modeName, mirrorMode, initReflector); + modeName, mirrorMode, initReflector, annotationMatcher); } } diff --git a/modules/angular2/src/transform/common/options_reader.dart b/modules/angular2/src/transform/common/options_reader.dart index 6bd6fb31f3..38fb73bdf4 100644 --- a/modules/angular2/src/transform/common/options_reader.dart +++ b/modules/angular2/src/transform/common/options_reader.dart @@ -1,6 +1,7 @@ library angular2.transform.common.options_reader; import 'package:barback/barback.dart'; +import 'annotation_matcher.dart'; import 'mirror_mode.dart'; import 'options.dart'; @@ -29,7 +30,8 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { reflectionEntryPoints: reflectionEntryPoints, modeName: settings.mode.name, mirrorMode: mirrorMode, - initReflector: initReflector); + initReflector: initReflector, + customAnnotationDescriptors: _readCustomAnnotations(config)); } /// Cribbed from the polymer project. @@ -53,3 +55,48 @@ List _readFileList(Map config, String paramName) { } return files; } + +/// Parse the [CUSTOM_ANNOTATIONS_PARAM] options out of the transformer into +/// [AnnotationDescriptor]s. +List _readCustomAnnotations(Map config) { + var descriptors = []; + var customAnnotations = config[CUSTOM_ANNOTATIONS_PARAM]; + if (customAnnotations == null) return descriptors; + var error = false; + if (customAnnotations is! List) { + error = true; + } else { + for (var description in customAnnotations) { + if (description is! Map) { + error = true; + continue; + } + var name = description['name']; + var import = description['import']; + var superClass = description['superClass']; + if (name == null || import == null || superClass == null) { + error = true; + continue; + } + descriptors.add(new AnnotationDescriptor(name, import, superClass)); + } + } + if (error) { + print(CUSTOM_ANNOTATIONS_ERROR); + } + return descriptors; +} + +const CUSTOM_ANNOTATIONS_ERROR = ''' + Invalid value for $CUSTOM_ANNOTATIONS_PARAM in the Angular2 transformer. + Expected something that looks like the following: + + transformers: + - angular2: + custom_annotations: + - name: MyAnnotation + import: 'package:my_package/my_annotation.dart' + superClass: Component + - name: ... + import: ... + superClass: ...'''; diff --git a/modules/angular2/src/transform/directive_processor/rewriter.dart b/modules/angular2/src/transform/directive_processor/rewriter.dart index 98f67ac419..8e9bc4cd76 100644 --- a/modules/angular2/src/transform/directive_processor/rewriter.dart +++ b/modules/angular2/src/transform/directive_processor/rewriter.dart @@ -2,6 +2,7 @@ library angular2.transform.directive_processor.rewriter; import 'package:analyzer/analyzer.dart'; import 'package:analyzer/src/generated/java_core.dart'; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/names.dart'; import 'package:barback/barback.dart' show AssetId; @@ -9,20 +10,20 @@ import 'package:path/path.dart' as path; import 'visitors.dart'; -/// Generates a file registering all Angular 2 `Directive`s found in [code] in -/// ngDeps format [TODO(kegluneq): documentation reference needed]. [path] is -/// the path to the file (or asset) containing [code]. +/// Generates a file registering all Angular 2 `Directive`s found in `code` in +/// ngDeps format [TODO(kegluneq): documentation reference needed]. `assetId` is +/// the id of the asset containing `code`. /// -/// If no Angular 2 `Directive`s are found in [code], returns the empty -/// string unless [forceGenerate] is true, in which case an empty ngDeps +/// If no Angular 2 `Directive`s are found in `code`, returns the empty +/// string unless `forceGenerate` is true, in which case an empty ngDeps /// file is created. -String createNgDeps(String code, String path, - Map> assetClasses) { +String createNgDeps( + String code, AssetId assetId, AnnotationMatcher annotationMatcher) { // TODO(kegluneq): Shortcut if we can determine that there are no // [Directive]s present, taking into account `export`s. var writer = new PrintStringWriter(); - var visitor = new CreateNgDepsVisitor(writer, path, assetClasses); - parseCompilationUnit(code, name: path).accept(visitor); + var visitor = new CreateNgDepsVisitor(writer, assetId, annotationMatcher); + parseCompilationUnit(code, name: assetId.toString()).accept(visitor); return '$writer'; } @@ -30,25 +31,23 @@ String createNgDeps(String code, String path, /// associated .ng_deps.dart file. class CreateNgDepsVisitor extends Object with SimpleAstVisitor { final PrintWriter writer; - final _Tester _tester; bool _foundNgDirectives = false; bool _wroteImport = false; final ToSourceVisitor _copyVisitor; final FactoryTransformVisitor _factoryVisitor; final ParameterTransformVisitor _paramsVisitor; final AnnotationsTransformVisitor _metaVisitor; + final AnnotationMatcher _annotationMatcher; - /// The path to the file which we are parsing. - final String importPath; + /// The assetId for the file which we are parsing. + final AssetId assetId; - CreateNgDepsVisitor(PrintWriter writer, this.importPath, - Map> assetClasses) + CreateNgDepsVisitor(PrintWriter writer, this.assetId, this._annotationMatcher) : writer = writer, _copyVisitor = new ToSourceVisitor(writer), _factoryVisitor = new FactoryTransformVisitor(writer), _paramsVisitor = new ParameterTransformVisitor(writer), - _metaVisitor = new AnnotationsTransformVisitor(writer), - _tester = new _Tester(assetClasses); + _metaVisitor = new AnnotationsTransformVisitor(writer); void _visitNodeListWithSeparator(NodeList list, String separator) { if (list == null) return; @@ -74,7 +73,7 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { void _maybeWriteImport() { if (_wroteImport) return; _wroteImport = true; - writer.print('''import '${path.basename(importPath)}';'''); + writer.print('''import '${path.basename(assetId.path)}';'''); } @override @@ -140,34 +139,34 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { @override Object visitClassDeclaration(ClassDeclaration node) { - var shouldProcess = node.metadata.any(_tester._shouldKeepMeta); - - if (shouldProcess) { - var ctor = _getCtor(node); - - if (!_foundNgDirectives) { - // The receiver for cascaded calls. - writer.print(REFLECTOR_VAR_NAME); - _foundNgDirectives = true; - } - writer.print('..registerType('); - node.name.accept(this); - writer.print(''', {'factory': '''); - if (ctor == null) { - _generateEmptyFactory(node.name.toString()); - } else { - ctor.accept(_factoryVisitor); - } - writer.print(''', 'parameters': '''); - if (ctor == null) { - _generateEmptyParams(); - } else { - ctor.accept(_paramsVisitor); - } - writer.print(''', 'annotations': '''); - node.accept(_metaVisitor); - writer.print('})'); + if (!node.metadata.any((a) => _annotationMatcher.hasMatch(a, assetId))) { + return null; } + + var ctor = _getCtor(node); + + if (!_foundNgDirectives) { + // The receiver for cascaded calls. + writer.print(REFLECTOR_VAR_NAME); + _foundNgDirectives = true; + } + writer.print('..registerType('); + node.name.accept(this); + writer.print(''', {'factory': '''); + if (ctor == null) { + _generateEmptyFactory(node.name.toString()); + } else { + ctor.accept(_factoryVisitor); + } + writer.print(''', 'parameters': '''); + if (ctor == null) { + _generateEmptyParams(); + } else { + ctor.accept(_paramsVisitor); + } + writer.print(''', 'annotations': '''); + node.accept(_metaVisitor); + writer.print('})'); return null; } @@ -189,7 +188,7 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { @override Object visitPartOfDirective(PartOfDirective node) { // TODO(kegluneq): Consider importing [node.libraryName]. - logger.warning('[${importPath}]: ' + logger.warning('[${assetId}]: ' 'Found `part of` directive while generating ${DEPS_EXTENSION} file, ' 'Transform may fail due to missing imports in generated file.'); return null; @@ -202,41 +201,3 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { @override Object visitSimpleIdentifier(SimpleIdentifier node) => _nodeToSource(node); } - -const annotationNamesToKeep = const ['Injectable', 'Template']; - -class _Tester { - final Map _classesByName; - - _Tester(Map> assetClasses) - : _classesByName = new Map.fromIterables(assetClasses.values - .expand((classes) => classes.map((c) => c.name.toString())), - assetClasses.values.expand((list) => list)); - - bool _shouldKeepMeta(Annotation meta) => - _shouldKeepClass(_classesByName[meta.name.name]); - - bool _shouldKeepClass(ClassDeclaration next) { - while (next != null) { - if (annotationNamesToKeep.contains(next.name.name)) return true; - - // Check classes that this class implements. - if (next.implementsClause != null) { - for (var interface in next.implementsClause.interfaces) { - if (_shouldKeepClass(_classesByName[interface.name.name])) { - return true; - } - } - } - - // Check the class that this class extends. - if (next.extendsClause != null && next.extendsClause.superclass != null) { - next = _classesByName[next.extendsClause.superclass.name.name]; - } else { - break; - } - } - - return false; - } -} diff --git a/modules/angular2/src/transform/directive_processor/transformer.dart b/modules/angular2/src/transform/directive_processor/transformer.dart index 6a6e0039b8..5d3bc6bb7a 100644 --- a/modules/angular2/src/transform/directive_processor/transformer.dart +++ b/modules/angular2/src/transform/directive_processor/transformer.dart @@ -2,8 +2,6 @@ library angular2.transform.directive_processor.transformer; import 'dart:async'; -import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/classdef_parser.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/options.dart'; @@ -34,10 +32,9 @@ class DirectiveProcessor extends Transformer { try { var asset = transform.primaryInput; - var reader = new AssetReader.fromTransform(transform); - var defMap = await createTypeMap(reader, asset.id); var assetCode = await asset.readAsString(); - var ngDepsSrc = createNgDeps(assetCode, asset.id.path, defMap); + var ngDepsSrc = + createNgDeps(assetCode, asset.id, options.annotationMatcher); if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) { var ngDepsAssetId = transform.primaryInput.id.changeExtension(DEPS_EXTENSION); diff --git a/modules/angular2/test/transform/directive_processor/all_tests.dart b/modules/angular2/test/transform/directive_processor/all_tests.dart index d41dbadd08..70b4f29431 100644 --- a/modules/angular2/test/transform/directive_processor/all_tests.dart +++ b/modules/angular2/test/transform/directive_processor/all_tests.dart @@ -2,8 +2,8 @@ library angular2.test.transform.directive_processor.all_tests; import 'package:barback/barback.dart'; import 'package:angular2/src/transform/directive_processor/rewriter.dart'; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; import '../common/read_file.dart'; -import 'package:angular2/src/transform/common/classdef_parser.dart'; import 'package:dart_style/dart_style.dart'; import 'package:guinness/guinness.dart'; import 'package:path/path.dart' as path; @@ -18,28 +18,40 @@ void allTests() { _testNgDeps('should preserve parameter annotations as const instances.', 'parameter_metadata/soup.dart'); - _testNgDeps('should recognize annotations which extend Injectable.', - 'custom_metadata/tortilla_soup.dart'); + _testNgDeps('should recognize custom annotations with package: imports', + 'custom_metadata/package_soup.dart', + customDescriptors: [ + const AnnotationDescriptor('Soup', 'package:soup/soup.dart', 'Component'), + ]); - _testNgDeps('should recognize annotations which implement Injectable.', - 'custom_metadata/chicken_soup.dart'); + _testNgDeps('should recognize custom annotations with relative imports', + 'custom_metadata/relative_soup.dart', + assetId: new AssetId('soup', 'lib/relative_soup.dart'), + customDescriptors: [ + const AnnotationDescriptor( + 'Soup', 'package:soup/annotations/soup.dart', 'Component'), + ]); - _testNgDeps( - 'should recognize annotations which implement a class that extends ' - 'Injectable.', 'custom_metadata/chicken_soup.dart'); + _testNgDeps('Requires the specified import.', 'custom_metadata/bad_soup.dart', + customDescriptors: [ + const AnnotationDescriptor('Soup', 'package:soup/soup.dart', 'Component'), + ]); } -void _testNgDeps(String name, String inputPath) { +void _testNgDeps(String name, String inputPath, + {List customDescriptors: const [], AssetId assetId}) { it(name, () async { var inputId = _assetIdForPath(inputPath); var reader = new TestAssetReader(); - var defMap = await createTypeMap(reader, inputId); var input = await reader.readAsString(inputId); - var output = formatter.format(createNgDeps(input, inputPath, defMap)); + var annotationMatcher = new AnnotationMatcher()..addAll(customDescriptors); + var proxyInputId = assetId != null ? assetId : inputId; + var output = + formatter.format(createNgDeps(input, proxyInputId, annotationMatcher)); var expectedPath = path.join(path.dirname(inputPath), 'expected', path.basename(inputPath).replaceFirst('.dart', '.ng_deps.dart')); - var expected = await reader.readAsString(_assetIdForPath(expectedPath)); - expect(output).toEqual(expected); + var expectedId = _assetIdForPath(expectedPath); + expect(output).toEqual(await reader.readAsString(expectedId)); }); } diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/bad_soup.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/bad_soup.dart new file mode 100644 index 0000000000..e6caa22a8c --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/bad_soup.dart @@ -0,0 +1,8 @@ +library dinner.bad_soup; + +// No recognized import for [Soup] + +@Soup() +class BadSoup { + BadSoup(); +} diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/expected/bad_soup.ng_deps.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/bad_soup.ng_deps.dart new file mode 100644 index 0000000000..c2970f51a6 --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/bad_soup.ng_deps.dart @@ -0,0 +1,9 @@ +library dinner.bad_soup.ng_deps.dart; + +import 'bad_soup.dart'; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; +} diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart new file mode 100644 index 0000000000..fdcd3e2092 --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/package_soup.ng_deps.dart @@ -0,0 +1,16 @@ +library dinner.package_soup.ng_deps.dart; + +import 'package_soup.dart'; +import 'package:soup/soup.dart'; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(PackageSoup, { + 'factory': () => new PackageSoup(), + 'parameters': const [], + 'annotations': const [const Soup()] + }); +} diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart new file mode 100644 index 0000000000..5671571997 --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/expected/relative_soup.ng_deps.dart @@ -0,0 +1,16 @@ +library dinner.relative_soup.ng_deps.dart; + +import 'relative_soup.dart'; +import 'annotations/soup.dart'; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(RelativeSoup, { + 'factory': () => new RelativeSoup(), + 'parameters': const [], + 'annotations': const [const Soup()] + }); +} diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/package_soup.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/package_soup.dart new file mode 100644 index 0000000000..3958e1d5c3 --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/package_soup.dart @@ -0,0 +1,8 @@ +library dinner.package_soup; + +import 'package:soup/soup.dart'; + +@Soup() +class PackageSoup { + PackageSoup(); +} diff --git a/modules/angular2/test/transform/directive_processor/custom_metadata/relative_soup.dart b/modules/angular2/test/transform/directive_processor/custom_metadata/relative_soup.dart new file mode 100644 index 0000000000..39ef5553bb --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/custom_metadata/relative_soup.dart @@ -0,0 +1,8 @@ +library dinner.relative_soup; + +import 'annotations/soup.dart'; + +@Soup() +class RelativeSoup { + RelativeSoup(); +}