From c68c9aaf1da042d0385df95f6c4abd18e7841bf8 Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Tue, 29 Dec 2015 10:22:59 -0800 Subject: [PATCH] Transformer changes to tbosch original commit --- .../transform/common/annotation_matcher.dart | 19 ++ .../common/code/reflection_info_code.dart | 64 ++++--- .../model/reflection_info_model.pb.dart | 55 +++--- .../common/model/reflection_info_model.proto | 13 +- .../lib/src/transform/common/ng_compiler.dart | 11 +- .../lib/src/transform/common/ng_meta.dart | 10 +- .../lib/src/transform/common/options.dart | 8 + .../src/transform/common/options_reader.dart | 2 + ..._reader.dart => type_metadata_reader.dart} | 163 ++++++++++++++++-- .../directive_processor/rewriter.dart | 16 +- .../change_detector_codegen.dart | 23 +-- .../compile_data_creator.dart | 120 +++++++------ .../template_compiler/generator.dart | 13 +- .../template_compiler/reflection/model.dart | 8 +- .../reflection/processor.dart | 22 +-- .../template_compiler/transformer.dart | 3 +- .../ng_for.ng_meta.dart | 1 + .../test/transform/common/ng_meta_helper.dart | 18 ++ .../hello.ng_meta.json | 3 +- .../hello.ng_meta.json | 3 +- .../directive_processor/all_tests.dart | 84 ++++++++- .../bad_directives_files/pipes.dart | 9 + .../directives_files/components.dart | 11 +- .../directives_files/dep1.dart | 5 +- .../directives_files/dep2.dart | 5 +- .../directive_processor/pipe_files/pipes.dart | 10 ++ .../deferred_files/expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/foo.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_meta.json | 28 --- .../expected/bar.ng_deps.dart | 2 +- .../expected/bar.ng_deps.dart | 2 +- .../two_deps_files/expected/bar.ng_deps.dart | 2 +- .../template_compiler/all_tests.dart | 69 ++++++-- 41 files changed, 583 insertions(+), 239 deletions(-) rename modules_dart/transform/lib/src/transform/common/{directive_metadata_reader.dart => type_metadata_reader.dart} (79%) create mode 100644 modules_dart/transform/test/transform/directive_processor/bad_directives_files/pipes.dart create mode 100644 modules_dart/transform/test/transform/directive_processor/pipe_files/pipes.dart delete mode 100644 modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json diff --git a/modules_dart/transform/lib/src/transform/common/annotation_matcher.dart b/modules_dart/transform/lib/src/transform/common/annotation_matcher.dart index 137c0d100a92..af1c51c03f29 100644 --- a/modules_dart/transform/lib/src/transform/common/annotation_matcher.dart +++ b/modules_dart/transform/lib/src/transform/common/annotation_matcher.dart @@ -48,6 +48,20 @@ const _COMPONENTS = const [ superClass: 'Directive'), ]; +const _PIPES = const [ + const ClassDescriptor( + 'Pipe', 'package:angular2/src/core/metadata/directive.dart', + superClass: 'Injectable'), + const ClassDescriptor('Pipe', 'package:angular2/src/core/metadata.dart', + superClass: 'Injectable'), + const ClassDescriptor('Pipe', 'package:angular2/angular2.dart', + superClass: 'Injectable'), + const ClassDescriptor('Pipe', 'package:angular2/core.dart', + superClass: 'Injectable'), + const ClassDescriptor('Pipe', 'package:angular2/web_worker/worker.dart', + superClass: 'Injectable'), +]; + const _VIEWS = const [ const ClassDescriptor('View', 'package:angular2/angular2.dart'), const ClassDescriptor('View', 'package:angular2/web_worker/worker.dart'), @@ -79,6 +93,7 @@ class AnnotationMatcher extends ClassMatcherBase { return new AnnotationMatcher._([] ..addAll(_COMPONENTS) ..addAll(_DIRECTIVES) + ..addAll(_PIPES) ..addAll(_INJECTABLES) ..addAll(_VIEWS) ..addAll(_ENTRYPOINTS)); @@ -109,6 +124,10 @@ class AnnotationMatcher extends ClassMatcherBase { bool isView(Annotation annotation, AssetId assetId) => _implementsWithWarning(annotation, assetId, _VIEWS); + /// Checks if an [Annotation] node implements [Pipe]. + bool isPipe(Annotation annotation, AssetId assetId) => + _implementsWithWarning(annotation, assetId, _PIPES); + /// Checks if an [Annotation] node implements [AngularEntrypoint] bool isEntrypoint(Annotation annotation, AssetId assetId) => _implementsWithWarning(annotation, assetId, _ENTRYPOINTS); 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 index b3ff0958c7f3..4c6e0354faf6 100644 --- 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 @@ -79,26 +79,34 @@ class ReflectionInfoVisitor extends RecursiveAstVisitor { } if (node.metadata != null) { - var componentDirectives, viewDirectives; + var componentDirectives = []; + var componentPipes = []; + var viewDirectives, viewPipes; node.metadata.forEach((node) { if (_annotationMatcher.isComponent(node, assetId)) { - componentDirectives = _extractDirectives(node); + componentDirectives = _extractReferencedTypes(node, 'directives'); + componentPipes = _extractReferencedTypes(node, 'pipes'); } else if (_annotationMatcher.isView(node, assetId)) { - viewDirectives = _extractDirectives(node); + viewDirectives = _extractReferencedTypes(node, 'directives'); + viewPipes = _extractReferencedTypes(node, 'pipes'); } model.annotations.add(_annotationVisitor.visitAnnotation(node)); }); - if (componentDirectives != null && componentDirectives.isNotEmpty) { - if (viewDirectives != null) { - log.warning( - 'Cannot specify view parameters on @Component when a @View ' - 'is present. Component name: ${model.name}', - asset: assetId); - } - model.directives.addAll(componentDirectives); - } else if (viewDirectives != null) { + if ((componentDirectives.isNotEmpty || componentPipes.isNotEmpty) && + (viewDirectives != null || viewPipes != null)) { + log.warning( + 'Cannot specify view parameters on @Component when a @View ' + 'is present. Component name: ${model.name}', + asset: assetId); + } + model.directives.addAll(componentDirectives); + model.pipes.addAll(componentPipes); + if (viewDirectives != null) { model.directives.addAll(viewDirectives); } + if (viewPipes != null) { + model.pipes.addAll(viewPipes); + } } if (ctor != null && ctor.parameters != null && @@ -151,43 +159,43 @@ class ReflectionInfoVisitor extends RecursiveAstVisitor { } } - /// Returns [PrefixedDirective] values parsed from the value of the - /// `directives` parameter of the provided `node`. + /// Returns [PrefixedType] values parsed from the value of the + /// `directives`/`pipes` parameter of the provided `node`. /// This will always return a non-null value, so if there are no `directives` - /// specified on `node`, it will return an empty iterable. - Iterable _extractDirectives(Annotation node) { + /// nor `pipes` specified on `node`, it will return an empty iterable. + Iterable _extractReferencedTypes(Annotation node, String fieldName) { assert(_annotationMatcher.isComponent(node, assetId) || _annotationMatcher.isView(node, assetId)); if (node.arguments == null && node.arguments.arguments == null) { return const []; } - final directivesNode = node.arguments.arguments.firstWhere((arg) { - return arg is NamedExpression && '${arg.name.label}' == 'directives'; + final typesNode = node.arguments.arguments.firstWhere((arg) { + return arg is NamedExpression && '${arg.name.label}' == fieldName; }, orElse: () => null); - if (directivesNode == null) return const []; + if (typesNode == null) return const []; - if (directivesNode.expression is! ListLiteral) { + if (typesNode.expression is! ListLiteral) { log.warning( - 'Angular 2 expects a list literal for `directives` ' - 'but found a ${directivesNode.expression.runtimeType}', + 'Angular 2 expects a list literal for `${fieldName}` ' + 'but found a ${typesNode.expression.runtimeType}', asset: assetId); return const []; } - final directives = []; - for (var dep in (directivesNode.expression as ListLiteral).elements) { + final types = []; + for (var dep in (typesNode.expression as ListLiteral).elements) { if (dep is PrefixedIdentifier) { - directives.add(new PrefixedDirective() + types.add(new PrefixedType() ..prefix = '${dep.prefix}' ..name = '${dep.identifier}'); } else if (dep is Identifier) { - directives.add(new PrefixedDirective()..name = '${dep}'); + types.add(new PrefixedType()..name = '${dep}'); } else { - log.warning('Found unexpected value $dep in `directives`.', + log.warning('Found unexpected value $dep in `types`.', asset: assetId); } } - return directives; + return types; } @override diff --git a/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.pb.dart b/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.pb.dart index ae551795f591..a96d4e20c4d4 100644 --- a/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.pb.dart +++ b/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.pb.dart @@ -52,33 +52,32 @@ class PropertyMetadataModel extends GeneratedMessage { class _ReadonlyPropertyMetadataModel extends PropertyMetadataModel with ReadonlyMessageMixin {} -class PrefixedDirective extends GeneratedMessage { - static final BuilderInfo _i = new BuilderInfo('PrefixedDirective') +class PrefixedType extends GeneratedMessage { + static final BuilderInfo _i = new BuilderInfo('PrefixedType') ..a(1, 'prefix', PbFieldType.OS) ..a(2, 'name', PbFieldType.OS) ..hasRequiredFields = false; - PrefixedDirective() : super(); - PrefixedDirective.fromBuffer(List i, + PrefixedType() : super(); + PrefixedType.fromBuffer(List i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r); - PrefixedDirective.fromJson(String i, + PrefixedType.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r); - PrefixedDirective clone() => new PrefixedDirective()..mergeFromMessage(this); + PrefixedType clone() => new PrefixedType()..mergeFromMessage(this); BuilderInfo get info_ => _i; - static PrefixedDirective create() => new PrefixedDirective(); - static PbList createRepeated() => - new PbList(); - static PrefixedDirective getDefault() { + static PrefixedType create() => new PrefixedType(); + static PbList createRepeated() => new PbList(); + static PrefixedType getDefault() { if (_defaultInstance == null) _defaultInstance = - new _ReadonlyPrefixedDirective(); + new _ReadonlyPrefixedType(); return _defaultInstance; } - static PrefixedDirective _defaultInstance; - static void $checkItem(PrefixedDirective v) { - if (v is! PrefixedDirective) checkItemFailed(v, 'PrefixedDirective'); + static PrefixedType _defaultInstance; + static void $checkItem(PrefixedType v) { + if (v is! PrefixedType) checkItemFailed(v, 'PrefixedType'); } String get prefix => $_get(0, 1, ''); @@ -98,8 +97,7 @@ class PrefixedDirective extends GeneratedMessage { void clearName() => clearField(2); } -class _ReadonlyPrefixedDirective extends PrefixedDirective - with ReadonlyMessageMixin {} +class _ReadonlyPrefixedType extends PrefixedType with ReadonlyMessageMixin {} class ReflectionInfoModel extends GeneratedMessage { static final BuilderInfo _i = new BuilderInfo('ReflectionInfoModel') @@ -113,8 +111,10 @@ class ReflectionInfoModel extends GeneratedMessage { ..p(6, 'interfaces', PbFieldType.PS) ..pp(7, 'propertyMetadata', PbFieldType.PM, PropertyMetadataModel.$checkItem, PropertyMetadataModel.create) - ..pp(8, 'directives', PbFieldType.PM, PrefixedDirective.$checkItem, - PrefixedDirective.create); + ..pp(8, 'directives', PbFieldType.PM, PrefixedType.$checkItem, + PrefixedType.create) + ..pp(9, 'pipes', PbFieldType.PM, PrefixedType.$checkItem, + PrefixedType.create); ReflectionInfoModel() : super(); ReflectionInfoModel.fromBuffer(List i, @@ -172,7 +172,9 @@ class ReflectionInfoModel extends GeneratedMessage { List get propertyMetadata => $_get(6, 7, null); - List get directives => $_get(7, 8, null); + List get directives => $_get(7, 8, null); + + List get pipes => $_get(8, 9, null); } class _ReadonlyReflectionInfoModel extends ReflectionInfoModel @@ -192,8 +194,8 @@ const PropertyMetadataModel$json = const { ], }; -const PrefixedDirective$json = const { - '1': 'PrefixedDirective', +const PrefixedType$json = const { + '1': 'PrefixedType', '2': const [ const {'1': 'prefix', '3': 1, '4': 1, '5': 9}, const {'1': 'name', '3': 2, '4': 1, '5': 9}, @@ -233,14 +235,21 @@ const ReflectionInfoModel$json = const { '3': 8, '4': 3, '5': 11, - '6': '.angular2.src.transform.common.model.proto.PrefixedDirective' + '6': '.angular2.src.transform.common.model.proto.PrefixedType' + }, + const { + '1': 'pipes', + '3': 9, + '4': 3, + '5': 11, + '6': '.angular2.src.transform.common.model.proto.PrefixedType' }, ], }; /** * Generated with: - * reflection_info_model.proto (e81bf93b6872b2bd5fabc6625be2560bacc3d186) + * reflection_info_model.proto (7670e589733b1190f9b4f1c9b42f90a613975afd) * libprotoc 2.6.1 * dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0) */ diff --git a/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.proto b/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.proto index 65064dddda4c..c4ef6e043d41 100644 --- a/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.proto +++ b/modules_dart/transform/lib/src/transform/common/model/reflection_info_model.proto @@ -13,12 +13,12 @@ message PropertyMetadataModel { repeated AnnotationModel annotations = 2; } -message PrefixedDirective { - // The prefix used to reference this Directive, if any. +message PrefixedType { + // The prefix used to reference this Type, if any. optional string prefix = 1; - // The name of the Directive or directive alias. - // See https://goo.gl/d8XPt0 for info on directive aliases. + // The name of the Type or type alias. + // See https://goo.gl/d8XPt0 for info on type aliases. optional string name = 2; } @@ -44,5 +44,8 @@ message ReflectionInfoModel { // Directive dependencies parsed from the @View or @Component `directives` // parameter. - repeated PrefixedDirective directives = 8; + repeated PrefixedType directives = 8; + + // Pipe dependencies parsed from the @View or @Component `pipes` parameter. + repeated PrefixedType pipes = 9; } diff --git a/modules_dart/transform/lib/src/transform/common/ng_compiler.dart b/modules_dart/transform/lib/src/transform/common/ng_compiler.dart index c8021d30ec48..64ce0c9240e5 100644 --- a/modules_dart/transform/lib/src/transform/common/ng_compiler.dart +++ b/modules_dart/transform/lib/src/transform/common/ng_compiler.dart @@ -1,6 +1,6 @@ library angular2.transform.template_compiler.ng_compiler; -import 'package:angular2/src/compiler/command_compiler.dart'; +import 'package:angular2/src/compiler/view_compiler.dart'; import 'package:angular2/src/compiler/html_parser.dart'; import 'package:angular2/src/compiler/style_compiler.dart'; import 'package:angular2/src/compiler/template_compiler.dart'; @@ -13,6 +13,7 @@ import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/core/change_detection/interfaces.dart'; import 'package:angular2/src/compiler/change_detector_compiler.dart'; import 'package:angular2/router/router_link_dsl.dart'; +import 'package:angular2/src/compiler/proto_view_compiler.dart'; import 'xhr_impl.dart'; import 'url_resolver.dart'; @@ -37,6 +38,10 @@ TemplateCompiler createTemplateCompiler(AssetReader reader, new TemplateNormalizer(_xhr, _urlResolver, _htmlParser), templateParser, new StyleCompiler(_xhr, _urlResolver), - new CommandCompiler(), - cdCompiler); + cdCompiler, + new ProtoViewCompiler(), + new ViewCompiler(), + null /* ResolvedMetadataCache */, + changeDetectionConfig + ); } diff --git a/modules_dart/transform/lib/src/transform/common/ng_meta.dart b/modules_dart/transform/lib/src/transform/common/ng_meta.dart index 0ba3fa231063..3671722fb867 100644 --- a/modules_dart/transform/lib/src/transform/common/ng_meta.dart +++ b/modules_dart/transform/lib/src/transform/common/ng_meta.dart @@ -34,7 +34,7 @@ class NgMeta { static const _VALUE_KEY = 'value'; /// Directive metadata for each type annotated as a directive. - final Map types; + final Map types; /// List of other types and names associated with a given name. final Map> aliases; @@ -43,7 +43,7 @@ class NgMeta { final NgDepsModel ngDeps; NgMeta( - {Map types, + {Map types, Map> aliases, this.ngDeps: null}) : this.types = types != null ? types : {}, @@ -91,7 +91,7 @@ class NgMeta { continue; } if (entry[_KIND_KEY] == _TYPE_VALUE) { - types[key] = CompileDirectiveMetadata.fromJson(entry[_VALUE_KEY]); + types[key] = CompileMetadataWithType.fromJson(entry[_VALUE_KEY]); } else if (entry[_KIND_KEY] == _ALIAS_VALUE) { aliases[key] = entry[_VALUE_KEY]; } @@ -123,8 +123,8 @@ class NgMeta { } /// Returns the metadata for every type associated with the given [alias]. - List flatten(String alias) { - var result = []; + List flatten(String alias) { + var result = []; var seen = new Set(); helper(name) { if (!seen.add(name)) { diff --git a/modules_dart/transform/lib/src/transform/common/options.dart b/modules_dart/transform/lib/src/transform/common/options.dart index 460df8a61609..fc71eacfd9a7 100644 --- a/modules_dart/transform/lib/src/transform/common/options.dart +++ b/modules_dart/transform/lib/src/transform/common/options.dart @@ -10,6 +10,7 @@ const ENTRY_POINT_PARAM = 'entry_points'; const FORMAT_CODE_PARAM = 'format_code'; const REFLECT_PROPERTIES_AS_ATTRIBUTES = 'reflect_properties_as_attributes'; const PLATFORM_DIRECTIVES = 'platform_directives'; +const PLATFORM_PIPES = 'platform_pipes'; const INIT_REFLECTOR_PARAM = 'init_reflector'; const INLINE_VIEWS_PARAM = 'inline_views'; const MIRROR_MODE_PARAM = 'mirror_mode'; @@ -47,6 +48,10 @@ class TransformerOptions { /// Format of an item in the list: angular2/lib/src/common/directives.dart#CORE_DIRECTIVES final List platformDirectives; + /// A set of pipes that will be automatically passed-in to the template compiler + /// Format of an item in the list: angular2/lib/src/common/directives.dart#CORE_DIRECTIVES + final List platformPipes; + /// Whether to format generated code. /// Code that is only modified will never be formatted because doing so may /// invalidate the source maps generated by `dart2js` and/or other tools. @@ -76,6 +81,7 @@ class TransformerOptions { {this.genChangeDetectionDebugInfo, this.reflectPropertiesAsAttributes, this.platformDirectives, + this.platformPipes, this.inlineViews, this.lazyTransformers, this.formatCode}); @@ -89,6 +95,7 @@ class TransformerOptions { bool genChangeDetectionDebugInfo: false, bool reflectPropertiesAsAttributes: false, List platformDirectives, + List platformPipes, bool lazyTransformers: false, bool formatCode: false}) { var annotationMatcher = new AnnotationMatcher() @@ -101,6 +108,7 @@ class TransformerOptions { genChangeDetectionDebugInfo: genChangeDetectionDebugInfo, reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, platformDirectives: platformDirectives, + platformPipes: platformPipes, inlineViews: inlineViews, lazyTransformers: lazyTransformers, formatCode: formatCode); diff --git a/modules_dart/transform/lib/src/transform/common/options_reader.dart b/modules_dart/transform/lib/src/transform/common/options_reader.dart index 21a78b7e3092..9123917b38ca 100644 --- a/modules_dart/transform/lib/src/transform/common/options_reader.dart +++ b/modules_dart/transform/lib/src/transform/common/options_reader.dart @@ -13,6 +13,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { var reflectPropertiesAsAttributes = _readBool(config, REFLECT_PROPERTIES_AS_ATTRIBUTES, defaultValue: false); var platformDirectives = _readStringList(config, PLATFORM_DIRECTIVES); + var platformPipes = _readStringList(config, PLATFORM_PIPES); var formatCode = _readBool(config, FORMAT_CODE_PARAM, defaultValue: false); String mirrorModeVal = config.containsKey(MIRROR_MODE_PARAM) ? config[MIRROR_MODE_PARAM] : ''; @@ -36,6 +37,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { customAnnotationDescriptors: _readCustomAnnotations(config), reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, platformDirectives: platformDirectives, + platformPipes: platformPipes, inlineViews: _readBool(config, INLINE_VIEWS_PARAM, defaultValue: false), lazyTransformers: _readBool(config, LAZY_TRANSFORMERS, defaultValue: false), diff --git a/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart b/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart similarity index 79% rename from modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart rename to modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart index f8188ee10dae..9f4030580a97 100644 --- a/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart +++ b/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart @@ -1,4 +1,4 @@ -library angular2.transform.common.directive_metadata_reader; +library angular2.transform.common.type_metadata_reader; import 'dart:async'; @@ -17,21 +17,24 @@ import 'package:barback/barback.dart' show AssetId; import 'naive_eval.dart'; -class DirectiveMetadataReader { - final _DirectiveMetadataVisitor _visitor; +class TypeMetadataReader { + final _DirectiveMetadataVisitor _directiveVisitor; + final _PipeMetadataVisitor _pipeVisitor; final TemplateCompiler _templateCompiler; - DirectiveMetadataReader._(this._visitor, this._templateCompiler); + TypeMetadataReader._(this._directiveVisitor, this._pipeVisitor, this._templateCompiler); /// Accepts an [AnnotationMatcher] which tests that an [Annotation] /// is a [Directive], [Component], or [View]. - factory DirectiveMetadataReader(AnnotationMatcher annotationMatcher, + factory TypeMetadataReader(AnnotationMatcher annotationMatcher, InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) { var lifecycleVisitor = new _LifecycleHookVisitor(interfaceMatcher); - var visitor = + var directiveVisitor = new _DirectiveMetadataVisitor(annotationMatcher, lifecycleVisitor); + var pipeVisitor = + new _PipeMetadataVisitor(annotationMatcher); - return new DirectiveMetadataReader._(visitor, templateCompiler); + return new TypeMetadataReader._(directiveVisitor, pipeVisitor, templateCompiler); } /// Reads *un-normalized* [CompileDirectiveMetadata] from the @@ -44,15 +47,19 @@ class DirectiveMetadataReader { /// `assetId` is the [AssetId] from which `node` was read, unless `node` was /// read from a part file, in which case `assetId` should be the [AssetId] of /// the parent file. - Future readDirectiveMetadata( + Future readTypeMetadata( ClassDeclaration node, AssetId assetId) { - _visitor.reset(assetId); - node.accept(_visitor); - if (!_visitor.hasMetadata) { - return new Future.value(null); - } else { - final metadata = _visitor.createMetadata(); + _directiveVisitor.reset(assetId); + _pipeVisitor.reset(assetId); + node.accept(_directiveVisitor); + node.accept(_pipeVisitor); + if (_directiveVisitor.hasMetadata) { + final metadata = _directiveVisitor.createMetadata(); return _templateCompiler.normalizeDirectiveMetadata(metadata); + } else if (_pipeVisitor.hasMetadata) { + return new Future.value(_pipeVisitor.createMetadata()); + } else { + return new Future.value(null); } } } @@ -103,6 +110,19 @@ String _expressionToString(Expression node, String nodeDescription) { return value; } +/// Evaluates `node` and expects that the result will be a bool. If not, +/// throws a [FormatException]. +bool _expressionToBool(Expression node, String nodeDescription) { + var value = naiveEval(node); + if (value is! bool) { + throw new FormatException( + 'Angular 2 could not understand the value ' + 'in $nodeDescription.', + '$node' /* source */); + } + return value; +} + /// Visitor responsible for processing a [Directive] annotated /// [ClassDeclaration] and creating a [CompileDirectiveMetadata] object. class _DirectiveMetadataVisitor extends Object @@ -387,7 +407,7 @@ class _DirectiveMetadataVisitor extends Object void _checkMeta() { if (!_hasMetadata) { throw new ArgumentError( - 'Incorrect value passed to readDirectiveMetadata. ' + 'Incorrect value passed to readTypeMetadata. ' 'Expected type is ClassDeclaration'); } } @@ -550,3 +570,116 @@ class _CompileTemplateMetadataVisitor static final _viewEncapsulationMap = new Map.fromIterable(ViewEncapsulation.values, key: (v) => v.toString()); } + +/// Visitor responsible for processing a [Pipe] annotated +/// [ClassDeclaration] and creating a [CompilePipeMetadata] object. +class _PipeMetadataVisitor extends Object + with RecursiveAstVisitor { + /// Tests [Annotation]s to determine if they deifne a [Directive], + /// [Component], [View], or none of these. + final AnnotationMatcher _annotationMatcher; + + /// The [AssetId] we are currently processing. + AssetId _assetId; + + _PipeMetadataVisitor(this._annotationMatcher) { + reset(null); + } + + /// Whether the visitor has found a [Pipe] annotation + /// since the last call to `reset`. + bool _hasMetadata = false; + + // Annotation fields + CompileTypeMetadata _type; + String _name; + bool _pure; + + void reset(AssetId assetId) { + _assetId = assetId; + + _hasMetadata = false; + _type = null; + _name = null; + _pure = null; + } + + bool get hasMetadata => _hasMetadata; + + CompilePipeMetadata createMetadata() { + return new CompilePipeMetadata( + type: _type, + name: _name, + pure: _pure); + } + + @override + Object visitAnnotation(Annotation node) { + var isPipe = _annotationMatcher.isPipe(node, _assetId); + if (isPipe) { + if (_hasMetadata) { + throw new FormatException( + 'Only one Pipe is allowed per class. ' + 'Found unexpected "$node".', + '$node' /* source */); + } + _hasMetadata = true; + super.visitAnnotation(node); + } + + // Annotation we do not recognize - no need to visit. + return null; + } + + @override + Object visitClassDeclaration(ClassDeclaration node) { + node.metadata.accept(this); + if (this._hasMetadata) { + _type = new CompileTypeMetadata( + moduleUrl: 'asset:${_assetId.package}/${_assetId.path}', + name: node.name.toString(), + runtime: null // Intentionally `null`, cannot be provided here. + ); + node.members.accept(this); + } + return null; + } + + @override + Object visitNamedExpression(NamedExpression node) { + // TODO(kegluneq): Remove this limitation. + if (node.name is! Label || node.name.label is! SimpleIdentifier) { + throw new FormatException( + 'Angular 2 currently only supports simple identifiers in directives.', + '$node' /* source */); + } + var keyString = '${node.name.label}'; + switch (keyString) { + case 'name': + _popuplateName(node.expression); + break; + case 'pure': + _populatePure(node.expression); + break; + } + return null; + } + + void _checkMeta() { + if (!_hasMetadata) { + throw new ArgumentError( + 'Incorrect value passed to readTypeMetadata. ' + 'Expected type is ClassDeclaration'); + } + } + + void _popuplateName(Expression nameValue) { + _checkMeta(); + _name = _expressionToString(nameValue, 'Pipe#name'); + } + + void _populatePure(Expression pureValue) { + _checkMeta(); + _pure = _expressionToBool(pureValue, 'Pipe#pure'); + } +} 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 dda7db751e51..fec07f816ed3 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart @@ -9,7 +9,7 @@ import 'package:angular2/src/compiler/template_compiler.dart'; import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/code/ng_deps_code.dart'; -import 'package:angular2/src/transform/common/directive_metadata_reader.dart'; +import 'package:angular2/src/transform/common/type_metadata_reader.dart'; import 'package:angular2/src/transform/common/interface_matcher.dart'; import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/ng_compiler.dart'; @@ -64,12 +64,12 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor { /// The [AssetId] we are currently processing. final AssetId assetId; - final DirectiveMetadataReader _reader; + final TypeMetadataReader _reader; final _normalizations = []; _NgMetaVisitor(this.ngMeta, this.assetId, AnnotationMatcher annotationMatcher, InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) - : _reader = new DirectiveMetadataReader( + : _reader = new TypeMetadataReader( annotationMatcher, interfaceMatcher, templateCompiler); Future whenDone() { @@ -89,11 +89,11 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor { @override Object visitClassDeclaration(ClassDeclaration node) { _normalizations.add(_reader - .readDirectiveMetadata(node, assetId) - .then((compileDirectiveMetadata) { - if (compileDirectiveMetadata != null) { - ngMeta.types[compileDirectiveMetadata.type.name] = - compileDirectiveMetadata; + .readTypeMetadata(node, assetId) + .then((compileMetadataWithType) { + if (compileMetadataWithType != null) { + ngMeta.types[compileMetadataWithType.type.name] = + compileMetadataWithType; } }).catchError((err) { log.error('ERROR: $err', asset: assetId); diff --git a/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart b/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart index 99c818536a8e..e5935c2f59f9 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart @@ -145,9 +145,9 @@ class _CodegenState { class $_changeDetectorTypeName extends ${_genPrefix}$_BASE_CLASS<$_contextTypeName> { ${_genDeclareFields()} - $_changeDetectorTypeName(dispatcher) + $_changeDetectorTypeName() : super(${codify(_changeDetectorDefId)}, - dispatcher, ${_records.length}, + ${_records.length}, ${_changeDetectorTypeName}.${_GEN_PROPERTY_BINDING_TARGETS_NAME}, ${_changeDetectorTypeName}.${_GEN_DIRECTIVE_INDICES_NAME}, ${_changeDetectionStrategyAsCode}) { @@ -177,8 +177,8 @@ class _CodegenState { ${_genDirectiveIndices()}; static ${_genPrefix}ChangeDetector - $CHANGE_DETECTOR_FACTORY_METHOD(a) { - return new $_changeDetectorTypeName(a); + $CHANGE_DETECTOR_FACTORY_METHOD() { + return new $_changeDetectorTypeName(); } } '''); @@ -283,13 +283,16 @@ class _CodegenState { String _maybeGenDehydrateDirectives() { var destroyPipesParamName = 'destroyPipes'; var destroyPipesCode = _names.genPipeOnDestroy(); - if (destroyPipesCode.isNotEmpty) { - destroyPipesCode = 'if (${destroyPipesParamName}) {${destroyPipesCode}}'; - } var dehydrateFieldsCode = _names.genDehydrateFields(); - if (destroyPipesCode.isEmpty && dehydrateFieldsCode.isEmpty) return ''; - return 'void dehydrateDirectives(${destroyPipesParamName}) ' - '{ ${destroyPipesCode} ${dehydrateFieldsCode} }'; + var destroyDirectivesCode = _logic.genDirectivesOnDestroy(this._directiveRecords); + if (destroyPipesCode.isEmpty && dehydrateFieldsCode.isEmpty && destroyDirectivesCode.isEmpty) return ''; + return '''void dehydrateDirectives(${destroyPipesParamName}) { + if (${destroyPipesParamName}) { + ${destroyPipesCode} + ${destroyDirectivesCode} + } + ${dehydrateFieldsCode} + }'''; } String _maybeGenHydrateDirectives() { diff --git a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart index 9ddee693759a..89be67951b37 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart @@ -20,10 +20,10 @@ import 'package:barback/barback.dart'; /// The returned value wraps the [NgDepsModel] at `assetId` as well as these /// created objects. Future createCompileData(AssetReader reader, - AssetId assetId, List platformDirectives) async { + AssetId assetId, List platformDirectives, List platformPipes) async { return logElapsedAsync(() async { final creator = - await _CompileDataCreator.create(reader, assetId, platformDirectives); + await _CompileDataCreator.create(reader, assetId, platformDirectives, platformPipes); return creator != null ? creator.createCompileData() : null; }, operationName: 'createCompileData', assetId: assetId); } @@ -43,18 +43,19 @@ class _CompileDataCreator { final AssetId entryPoint; final NgMeta ngMeta; final List platformDirectives; + final List platformPipes; _CompileDataCreator( - this.reader, this.entryPoint, this.ngMeta, this.platformDirectives); + this.reader, this.entryPoint, this.ngMeta, this.platformDirectives, this.platformPipes); static Future<_CompileDataCreator> create(AssetReader reader, AssetId assetId, - List platformDirectives) async { + List platformDirectives, List platformPipes) async { if (!(await reader.hasInput(assetId))) return null; final json = await reader.readAsString(assetId); if (json == null || json.isEmpty) return null; final ngMeta = new NgMeta.fromJson(JSON.decode(json)); - return new _CompileDataCreator(reader, assetId, ngMeta, platformDirectives); + return new _CompileDataCreator(reader, assetId, ngMeta, platformDirectives, platformPipes); } NgDepsModel get ngDeps => ngMeta.ngDeps; @@ -67,39 +68,20 @@ class _CompileDataCreator { final compileData = {}; final ngMetaMap = await _extractNgMeta(); - final platformDirectives = await _readPlatformDirectives(); + final platformDirectives = await _readPlatformTypes(this.platformDirectives, 'directives'); + final platformPipes = await _readPlatformTypes(this.platformPipes, 'pipes'); for (var reflectable in ngDeps.reflectables) { if (ngMeta.types.containsKey(reflectable.name)) { final compileDirectiveMetadata = ngMeta.types[reflectable.name]; - if (compileDirectiveMetadata.template != null) { + if (compileDirectiveMetadata is CompileDirectiveMetadata && + compileDirectiveMetadata.template != null) { final compileDatum = new NormalizedComponentWithViewDirectives( - compileDirectiveMetadata, []); + compileDirectiveMetadata, [], []); compileDatum.directives.addAll(platformDirectives); - - for (var dep in reflectable.directives) { - if (!ngMetaMap.containsKey(dep.prefix)) { - log.warning( - 'Missing prefix "${dep.prefix}" ' - 'needed by "${dep}" from metadata map', - asset: entryPoint); - continue; - } - final depNgMeta = ngMetaMap[dep.prefix]; - - if (depNgMeta.types.containsKey(dep.name)) { - compileDatum.directives.add(depNgMeta.types[dep.name]); - } else if (depNgMeta.aliases.containsKey(dep.name)) { - compileDatum.directives.addAll(depNgMeta.flatten(dep.name)); - } else { - log.warning( - 'Could not find Directive entry for $dep. ' - 'Please be aware that Dart transformers have limited support for ' - 'reusable, pre-defined lists of Directives (aka ' - '"directive aliases"). See https://goo.gl/d8XPt0 for details.', - asset: entryPoint); - } - } + compileDatum.directives.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.directives)); + compileDatum.pipes.addAll(platformPipes); + compileDatum.pipes.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.pipes)); compileData[reflectable] = compileDatum; } } @@ -107,46 +89,72 @@ class _CompileDataCreator { return new CompileDataResults._(ngMeta, compileData); } - Future> _readPlatformDirectives() async { - if (platformDirectives == null) return const []; + List _resolveTypeMetadata(Map ngMetaMap, List prefixedTypes) { + var resolvedMetadata = []; + for (var dep in prefixedTypes) { + if (!ngMetaMap.containsKey(dep.prefix)) { + log.warning( + 'Missing prefix "${dep.prefix}" ' + 'needed by "${dep}" from metadata map', + asset: entryPoint); + continue; + } + final depNgMeta = ngMetaMap[dep.prefix]; + + if (depNgMeta.types.containsKey(dep.name)) { + resolvedMetadata.add(depNgMeta.types[dep.name]); + } else if (depNgMeta.aliases.containsKey(dep.name)) { + resolvedMetadata.addAll(depNgMeta.flatten(dep.name)); + } else { + log.warning( + 'Could not find Directive/Pipe entry for $dep. ' + 'Please be aware that Dart transformers have limited support for ' + 'reusable, pre-defined lists of Directives/Pipes (aka ' + '"directive/pipe aliases"). See https://goo.gl/d8XPt0 for details.', + asset: entryPoint); + } + } + return resolvedMetadata; + } + + Future> _readPlatformTypes(List inputPlatformTypes, String configOption) async { + if (inputPlatformTypes == null) return const []; final res = []; - for (var ad in platformDirectives) { - final parts = ad.split("#"); + for (var pd in inputPlatformTypes) { + final parts = pd.split("#"); if (parts.length != 2) { log.warning( - 'The platform directives configuration option ' + 'The platform ${configOption} configuration option ' 'must be in the following format: "URI#TOKEN"', asset: entryPoint); return const []; } - res.addAll(await _readPlatformDirectivesFromUri(parts[0], parts[1])); + res.addAll(await _readPlatformTypeFromUri(parts[0], parts[1])); } return res; } - Future> _readPlatformDirectivesFromUri( + Future> _readPlatformTypeFromUri( String uri, String token) async { final metaAssetId = fromUri(toMetaExtension(uri)); - if (await reader.hasInput(metaAssetId)) { - try { - var jsonString = await reader.readAsString(metaAssetId); - if (jsonString != null && jsonString.isNotEmpty) { - var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString)); - - if (newMetadata.types.containsKey(token)) { - return [newMetadata.types[token]]; - } else if (newMetadata.aliases.containsKey(token)) { - return newMetadata.flatten(token); - } else { - log.warning( - 'Could not resolve platform directive ${token} in ${uri}', - asset: metaAssetId); - } + try { + var jsonString = await reader.readAsString(metaAssetId); + if (jsonString != null && jsonString.isNotEmpty) { + var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString)); + + if (newMetadata.types.containsKey(token)) { + return [newMetadata.types[token]]; + } else if (newMetadata.aliases.containsKey(token)) { + return newMetadata.flatten(token); + } else { + log.warning( + 'Could not resolve platform directive ${token} in ${uri}', + asset: metaAssetId); } - } catch (ex, stackTrace) { - log.warning('Failed to decode: $ex, $stackTrace', asset: metaAssetId); } + } catch (ex, stackTrace) { + log.warning('Failed to decode: $ex, $stackTrace', asset: metaAssetId); } return []; } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart index 960fbfc985a6..40648a888833 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart @@ -30,14 +30,15 @@ import 'compile_data_creator.dart'; Future processTemplates(AssetReader reader, AssetId assetId, {bool genChangeDetectionDebugInfo: false, bool reflectPropertiesAsAttributes: false, - List platformDirectives}) async { + List platformDirectives, + List platformPipes}) async { var viewDefResults = - await createCompileData(reader, assetId, platformDirectives); + await createCompileData(reader, assetId, platformDirectives, platformPipes); if (viewDefResults == null) return null; - final directiveMetadatas = viewDefResults.ngMeta.types.values; - if (directiveMetadatas.isNotEmpty) { + final compileTypeMetadatas = viewDefResults.ngMeta.types.values; + if (compileTypeMetadatas.isNotEmpty) { var processor = new reg.Processor(); - directiveMetadatas.forEach(processor.process); + compileTypeMetadatas.forEach(processor.process); viewDefResults.ngMeta.ngDeps.getters .addAll(processor.getterNames.map((e) => e.sanitizedName)); viewDefResults.ngMeta.ngDeps.setters @@ -71,7 +72,7 @@ Future processTemplates(AssetReader reader, AssetId assetId, ..prefix = '_templates'); for (var reflectable in viewDefResults.viewDefinitions.keys) { reflectable.annotations.add(new AnnotationModel() - ..name = '_templates.Host${reflectable.name}Template' + ..name = '_templates.hostViewFactory_${reflectable.name}' ..isConstObject = true); } } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart index c590be9f3ef2..aaddc7ec3eed 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart @@ -1,7 +1,6 @@ library angular2.transform.template_compiler.reflection.model; import 'package:angular2/src/compiler/util.dart'; -import 'package:angular2/src/core/linker/event_config.dart'; /// Defines the names of getters, setters, and methods which need to be /// available to Angular 2 via the `reflector` at runtime. @@ -42,5 +41,10 @@ class ReflectiveAccessor { } String sanitizePropertyName(String name) { - return dashCaseToCamelCase(EventConfig.parse(name).fieldName); + var fieldName = name; + var separatorIdx = name.indexOf(':'); + if (separatorIdx > -1) { + fieldName = name.substring(0, separatorIdx).trim(); + } + return dashCaseToCamelCase(fieldName); } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart index d51157ebe7b2..404a3e29e568 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart @@ -14,16 +14,18 @@ class Processor implements CodegenModel { /// The names of all requested `method`s. final Set methodNames = new Set(); - void process(CompileDirectiveMetadata meta) { - if (meta.outputs != null) { - meta.outputs.keys.forEach((eventName) { - getterNames.add(new ReflectiveAccessor(eventName)); - }); - } - if (meta.inputs != null) { - meta.inputs.keys.forEach((inputName) { - setterNames.add(new ReflectiveAccessor(inputName)); - }); + void process(CompileMetadataWithType meta) { + if (meta is CompileDirectiveMetadata) { + if (meta.outputs != null) { + meta.outputs.keys.forEach((eventName) { + getterNames.add(new ReflectiveAccessor(eventName)); + }); + } + if (meta.inputs != null) { + meta.inputs.keys.forEach((inputName) { + setterNames.add(new ReflectiveAccessor(inputName)); + }); + } } } } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart index 79281476aae5..ad045c673858 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart @@ -46,7 +46,8 @@ class TemplateCompiler extends Transformer implements LazyTransformer { var outputs = await processTemplates(reader, primaryId, genChangeDetectionDebugInfo: options.genChangeDetectionDebugInfo, reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes, - platformDirectives: options.platformDirectives); + platformDirectives: options.platformDirectives, + platformPipes: options.platformPipes); var ngDepsCode = _emptyNgDepsContents; var templatesCode = ''; if (outputs != null) { diff --git a/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart b/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart index c2620df207c0..20437d09a63e 100644 --- a/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart +++ b/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart @@ -4,6 +4,7 @@ final ngFor = { "NgFor": { "kind": "type", "value": { + "class": "Directive", "isComponent": false, "dynamicLoadable": true, "selector": "[ngFor][ngForOf]", diff --git a/modules_dart/transform/test/transform/common/ng_meta_helper.dart b/modules_dart/transform/test/transform/common/ng_meta_helper.dart index cbc7475b0863..4489b2cf7622 100644 --- a/modules_dart/transform/test/transform/common/ng_meta_helper.dart +++ b/modules_dart/transform/test/transform/common/ng_meta_helper.dart @@ -26,6 +26,17 @@ CompileDirectiveMetadata createComponentMetadataForTest( encapsulation: ViewEncapsulation.Emulated, template: template)); } +CompilePipeMetadata createPipeMetadataForTest( + {String name: 'TestPipe', + moduleUrl: 'asset:angular2/test/test.dart', + String pipeName: 'test', + bool pure: false}) { + return new CompilePipeMetadata( + type: new CompileTypeMetadata(name: name, moduleUrl: moduleUrl), + name: pipeName, + pure: pure); +} + CompileDirectiveMetadata createDirectiveMetadataForTest( {String name: 'TestMetadata', String moduleUrl: 'asset:angular2/test/test.dart', @@ -59,6 +70,13 @@ CompileDirectiveMetadata createBar([String moduleBase = 'asset:a']) => selector: 'bar', template: 'Bar'); +CompilePipeMetadata createBarPipe([String moduleBase = 'asset:a']) => + createPipeMetadataForTest( + name: 'BarPipe', + pipeName: 'bar', + moduleUrl: '$moduleBase/export_cycle_files/bar.dart', + pure: false); + CompileDirectiveMetadata createBaz([String moduleBase = 'asset:a']) => createComponentMetadataForTest( name: 'BazComponent', diff --git a/modules_dart/transform/test/transform/deferred_rewriter/complex_deferred_example/hello.ng_meta.json b/modules_dart/transform/test/transform/deferred_rewriter/complex_deferred_example/hello.ng_meta.json index 5368afb25e4d..1d06b71fd10b 100644 --- a/modules_dart/transform/test/transform/deferred_rewriter/complex_deferred_example/hello.ng_meta.json +++ b/modules_dart/transform/test/transform/deferred_rewriter/complex_deferred_example/hello.ng_meta.json @@ -3,6 +3,7 @@ { "kind": "type", "value": { + "class": "Directive", "isComponent": true, "dynamicLoadable": true, "selector":"hello-app", @@ -29,4 +30,4 @@ } } } -} \ No newline at end of file +} diff --git a/modules_dart/transform/test/transform/deferred_rewriter/simple_deferred_example/hello.ng_meta.json b/modules_dart/transform/test/transform/deferred_rewriter/simple_deferred_example/hello.ng_meta.json index a4b890a104f8..7bd5ce332f17 100644 --- a/modules_dart/transform/test/transform/deferred_rewriter/simple_deferred_example/hello.ng_meta.json +++ b/modules_dart/transform/test/transform/deferred_rewriter/simple_deferred_example/hello.ng_meta.json @@ -3,6 +3,7 @@ { "kind": "type", "value": { + "class": "Directive", "isComponent": true, "dynamicLoadable": true, "selector":"hello-app", @@ -29,4 +30,4 @@ } } } -} \ No newline at end of file +} diff --git a/modules_dart/transform/test/transform/directive_processor/all_tests.dart b/modules_dart/transform/test/transform/directive_processor/all_tests.dart index 5075ac27890c..d24d79a51a54 100644 --- a/modules_dart/transform/test/transform/directive_processor/all_tests.dart +++ b/modules_dart/transform/test/transform/directive_processor/all_tests.dart @@ -460,8 +460,8 @@ void allTests() { expect(componentFirst.directives).toBeNotNull(); expect(componentFirst.directives.length).toEqual(2); expect(componentFirst.directives.first) - .toEqual(new PrefixedDirective()..name = 'Dep'); - expect(componentFirst.directives[1]).toEqual(new PrefixedDirective() + .toEqual(new PrefixedType()..name = 'Dep'); + expect(componentFirst.directives[1]).toEqual(new PrefixedType() ..name = 'Dep' ..prefix = 'dep2'); }); @@ -474,11 +474,11 @@ void allTests() { expect(viewFirst).toBeNotNull(); expect(viewFirst.directives).toBeNotNull(); expect(viewFirst.directives.length).toEqual(2); - expect(viewFirst.directives.first).toEqual(new PrefixedDirective() + expect(viewFirst.directives.first).toEqual(new PrefixedType() ..name = 'Dep' ..prefix = 'dep2'); expect(viewFirst.directives[1]) - .toEqual(new PrefixedDirective()..name = 'Dep'); + .toEqual(new PrefixedType()..name = 'Dep'); }); it('should populate `directives` from @Component value with no @View.', @@ -490,12 +490,57 @@ void allTests() { expect(componentOnly.directives).toBeNotNull(); expect(componentOnly.directives.length).toEqual(2); expect(componentOnly.directives.first) - .toEqual(new PrefixedDirective()..name = 'Dep'); - expect(componentOnly.directives[1]).toEqual(new PrefixedDirective() + .toEqual(new PrefixedType()..name = 'Dep'); + expect(componentOnly.directives[1]).toEqual(new PrefixedType() ..name = 'Dep' ..prefix = 'dep2'); }); + it('should populate `pipes` from @View value specified second.', + () async { + var model = + (await _testCreateModel('directives_files/components.dart')).ngDeps; + final componentFirst = reflectableNamed(model, 'ComponentFirst'); + expect(componentFirst).toBeNotNull(); + expect(componentFirst.pipes).toBeNotNull(); + expect(componentFirst.pipes.length).toEqual(2); + expect(componentFirst.pipes.first) + .toEqual(new PrefixedType()..name = 'PipeDep'); + expect(componentFirst.pipes[1]).toEqual(new PrefixedType() + ..name = 'PipeDep' + ..prefix = 'dep2'); + }); + + it('should populate `pipes` from @View value specified first.', + () async { + var model = + (await _testCreateModel('directives_files/components.dart')).ngDeps; + final viewFirst = reflectableNamed(model, 'ViewFirst'); + expect(viewFirst).toBeNotNull(); + expect(viewFirst.pipes).toBeNotNull(); + expect(viewFirst.pipes.length).toEqual(2); + expect(viewFirst.pipes.first).toEqual(new PrefixedType() + ..name = 'PipeDep' + ..prefix = 'dep2'); + expect(viewFirst.pipes[1]) + .toEqual(new PrefixedType()..name = 'PipeDep'); + }); + + it('should populate `pipes` from @Component value with no @View.', + () async { + var model = + (await _testCreateModel('directives_files/components.dart')).ngDeps; + final componentOnly = reflectableNamed(model, 'ComponentOnly'); + expect(componentOnly).toBeNotNull(); + expect(componentOnly.pipes).toBeNotNull(); + expect(componentOnly.pipes.length).toEqual(2); + expect(componentOnly.pipes.first) + .toEqual(new PrefixedType()..name = 'PipeDep'); + expect(componentOnly.pipes[1]).toEqual(new PrefixedType() + ..name = 'PipeDep' + ..prefix = 'dep2'); + }); + it('should merge `outputs` from the annotation and fields.', () async { var model = await _testCreateModel('directives_files/components.dart'); expect(model.types['ComponentWithOutputs'].outputs).toEqual( @@ -560,6 +605,33 @@ void allTests() { expect(warning.toLowerCase()) .toContain('cannot specify view parameters on @component'); }); + + + it('should warn if @Component has `pipes` and @View is present.', + () async { + final logger = new RecordingLogger(); + final model = await _testCreateModel( + 'bad_directives_files/pipes.dart', + logger: logger); + var warning = + logger.logs.firstWhere((l) => l.contains('WARN'), orElse: () => null); + expect(warning).toBeNotNull(); + expect(warning.toLowerCase()) + .toContain('cannot specify view parameters on @component'); + }); + }); + + describe('pipes', () { + it('should read the pipe name', () async { + var model = await _testCreateModel('pipe_files/pipes.dart'); + expect(model.types['NameOnlyPipe'].name).toEqual('nameOnly'); + expect(model.types['NameOnlyPipe'].pure).toBe(false); + }); + + it('should read the pure flag', () async { + var model = await _testCreateModel('pipe_files/pipes.dart'); + expect(model.types['NameAndPurePipe'].pure).toBe(true); + }); }); } diff --git a/modules_dart/transform/test/transform/directive_processor/bad_directives_files/pipes.dart b/modules_dart/transform/test/transform/directive_processor/bad_directives_files/pipes.dart new file mode 100644 index 000000000000..c455922fd9d0 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_processor/bad_directives_files/pipes.dart @@ -0,0 +1,9 @@ +library angular2.test.transform.directive_processor.bad_directives_files.pipes; + +import 'package:angular2/angular2.dart' + show Component, Directive, View, NgElement; +import 'dep1.dart'; + +@Component(selector: 'component-first', pipes: [Dep]) +@View(template: '
Hi
') +class BadDirectives {} diff --git a/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart b/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart index 31d27bd7348c..000622d0a2de 100644 --- a/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart +++ b/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart @@ -6,17 +6,22 @@ import 'dep1.dart'; import 'dep2.dart' as dep2; @Component(selector: 'component-first') -@View(template: '', directives: [Dep, dep2.Dep]) +@View(template: '', + directives: [Dep, dep2.Dep], + pipes: [PipeDep, dep2.PipeDep]) class ComponentFirst {} -@View(template: '', directives: [dep2.Dep, Dep]) +@View(template: '', + directives: [dep2.Dep, Dep], + pipes: [dep2.PipeDep, PipeDep]) @Component(selector: 'view-first') class ViewFirst {} @Component( selector: 'component-only', template: '', - directives: [Dep, dep2.Dep]) + directives: [Dep, dep2.Dep], + pipes: [PipeDep, dep2.PipeDep]) class ComponentOnly {} @Component( diff --git a/modules_dart/transform/test/transform/directive_processor/directives_files/dep1.dart b/modules_dart/transform/test/transform/directive_processor/directives_files/dep1.dart index 95b281941346..76ae0d126827 100644 --- a/modules_dart/transform/test/transform/directive_processor/directives_files/dep1.dart +++ b/modules_dart/transform/test/transform/directive_processor/directives_files/dep1.dart @@ -1,8 +1,11 @@ library angular2.test.transform.directive_processor.directive_files.dep1; import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; + show Component, Directive, View, Pipe; @Component(selector: 'dep1') @View(template: 'Dep1') class Dep {} + +@Pipe(name: 'dep1') +class PipeDep {} diff --git a/modules_dart/transform/test/transform/directive_processor/directives_files/dep2.dart b/modules_dart/transform/test/transform/directive_processor/directives_files/dep2.dart index a4eeb14741e9..d5c8bb0f9d6f 100644 --- a/modules_dart/transform/test/transform/directive_processor/directives_files/dep2.dart +++ b/modules_dart/transform/test/transform/directive_processor/directives_files/dep2.dart @@ -1,8 +1,11 @@ library angular2.test.transform.directive_processor.directive_files.dep2; import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; + show Component, Directive, View, Pipe; @Component(selector: 'dep2') @View(template: 'Dep2') class Dep {} + +@Pipe(name: 'dep2') +class PipeDep {} diff --git a/modules_dart/transform/test/transform/directive_processor/pipe_files/pipes.dart b/modules_dart/transform/test/transform/directive_processor/pipe_files/pipes.dart new file mode 100644 index 000000000000..5f30adba0c10 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_processor/pipe_files/pipes.dart @@ -0,0 +1,10 @@ +library angular2.test.transform.directive_processor.pipe_files.pipes; + +import 'package:angular2/angular2.dart' + show Pipe; + +@Pipe(name: 'nameOnly') +class NameOnlyPipe {} + +@Pipe(name: 'nameAndPure', pure: true) +class NameAndPurePipe {} diff --git a/modules_dart/transform/test/transform/integration/deferred_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/deferred_files/expected/bar.ng_deps.dart index fb5036acfd50..c4c438c5e856 100644 --- a/modules_dart/transform/test/transform/integration/deferred_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/deferred_files/expected/bar.ng_deps.dart @@ -17,7 +17,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); } diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart index 79685a30cb58..ef0233c80123 100644 --- a/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart @@ -19,7 +19,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'soup'), const View(directives: [Foo], template: 'foo'), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); i1.initReflector(); diff --git a/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart index a4042fda626d..a64aab487409 100644 --- a/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart @@ -19,7 +19,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: 'soup'), const View(directives: [prefix.Foo], template: 'foo'), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); i1.initReflector(); diff --git a/modules_dart/transform/test/transform/integration/empty_ng_deps_files/expected/foo.ng_deps.dart b/modules_dart/transform/test/transform/integration/empty_ng_deps_files/expected/foo.ng_deps.dart index 3dd525cb7ffe..c2d7ce4ce966 100644 --- a/modules_dart/transform/test/transform/integration/empty_ng_deps_files/expected/foo.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/empty_ng_deps_files/expected/foo.ng_deps.dart @@ -19,7 +19,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]'), const View(directives: const [directiveAlias], template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); i1.initReflector(); diff --git a/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart index 6e977774b1c6..d7e7b68a789b 100644 --- a/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart @@ -19,7 +19,7 @@ void initReflector() { outputs: ['eventName1', 'eventName2: propName2'], selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())) ..registerGetters( {'eventName1': (o) => o.eventName1, 'eventName2': (o) => o.eventName2}); 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 e218e06a490a..f13458dea6da 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 @@ -18,7 +18,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(componentServices: const [MyContext]), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [ const [MyContext] ], (MyContext c) => new MyComponent(c))); diff --git a/modules_dart/transform/test/transform/integration/override_annotation_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/override_annotation_files/expected/bar.ng_deps.dart index 53a0ddc53bde..43fd420e5048 100644 --- a/modules_dart/transform/test/transform/integration/override_annotation_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/override_annotation_files/expected/bar.ng_deps.dart @@ -18,7 +18,7 @@ void initReflector() { const [ const Component(selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent(), diff --git a/modules_dart/transform/test/transform/integration/queries_class_annotation_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/queries_class_annotation_files/expected/bar.ng_deps.dart index 95e6bb124033..28b8e644d97c 100644 --- a/modules_dart/transform/test/transform/integration/queries_class_annotation_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/queries_class_annotation_files/expected/bar.ng_deps.dart @@ -19,7 +19,7 @@ void initReflector() { queries: const {'queryField': const ContentChild('child')}, selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())) ..registerSetters({'queryField': (o, v) => o.queryField = v}); i0.initReflector(); diff --git a/modules_dart/transform/test/transform/integration/queries_prop_annotation_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/queries_prop_annotation_files/expected/bar.ng_deps.dart index 13c63897243f..200405af2743 100644 --- a/modules_dart/transform/test/transform/integration/queries_prop_annotation_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/queries_prop_annotation_files/expected/bar.ng_deps.dart @@ -18,7 +18,7 @@ void initReflector() { const [ const Component(selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent(), 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 6db43dcc9e6e..8b073ed8b6a5 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 @@ -16,7 +16,7 @@ void initReflector() { MyComponent, new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]', template: 'aa'), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); } diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json deleted file mode 100644 index 313a65c14c30..000000000000 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "MyComponent": { - "kind": "type", - "value": { - "id": "MyComponent", - "selector": "[soup]", - "compileChildren": true, - "hostProperties": {}, - "hostListeners": {}, - "hostAttributes": {}, - "inputs": [], - "readAttributes": [], - "type": 1, - "exportAs": null, - "callOnDestroy": false, - "callDoCheck": false, - "callOnInit": false, - "callOnChanges": false, - "callAfterContentInit": false, - "callAfterContentChecked": false, - "callAfterViewInit": false, - "callAfterViewChecked": false, - "outputs": [], - "changeDetection": null, - "version": 1 - } - } -} 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 fb5036acfd50..c4c438c5e856 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 @@ -17,7 +17,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.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 35b3e520e875..5e81fad67548 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 @@ -17,7 +17,7 @@ void initReflector() { new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]'), const View(template: 'Salad: {{myNum}} is awesome'), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [], () => new MyComponent())); i0.initReflector(); } 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 e3242233e7c5..551d9cd5774d 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 @@ -19,7 +19,7 @@ void initReflector() { const [ const Component(selector: 'soup'), const View(template: ''), - _templates.HostMyComponentTemplate + _templates.hostViewFactory_MyComponent ], const [ const [prefix.MyContext], diff --git a/modules_dart/transform/test/transform/template_compiler/all_tests.dart b/modules_dart/transform/test/transform/template_compiler/all_tests.dart index b29ad38928f1..821f5d565081 100644 --- a/modules_dart/transform/test/transform/template_compiler/all_tests.dart +++ b/modules_dart/transform/test/transform/template_compiler/all_tests.dart @@ -26,7 +26,7 @@ RecordingLogger logger; main() => allTests(); var fooComponentMeta, fooNgMeta, fooAssetId; -var barComponentMeta, barNgMeta, barAssetId; +var barComponentMeta, barPipeMeta, barNgMeta, barAssetId; var bazComponentMeta, bazNgMeta, bazAssetId; /// Call after making changes to `fooNgMeta`, `barNgMeta`, or `bazNgMeta` and @@ -58,10 +58,13 @@ void allTests() { fooNgMeta.types[fooComponentMeta.type.name] = fooComponentMeta; barComponentMeta = createBar(moduleBase); + barPipeMeta = createBarPipe(moduleBase); barNgMeta = new NgMeta(ngDeps: new NgDepsModel() ..libraryUri = 'test.bar' + ..reflectables.add(new ReflectionInfoModel()..name = barPipeMeta.type.name) ..reflectables.add(new ReflectionInfoModel()..name = barComponentMeta.type.name)); barNgMeta.types[barComponentMeta.type.name] = barComponentMeta; + barNgMeta.types[barPipeMeta.type.name] = barPipeMeta; bazComponentMeta = createBaz(moduleBase); bazNgMeta = new NgMeta(ngDeps: new NgDepsModel() @@ -75,11 +78,13 @@ void allTests() { updateReader(); }); - Future process(AssetId assetId, {List platformDirectives}) { + Future process(AssetId assetId, {List platformDirectives, + List platformPipes}) { logger = new RecordingLogger(); return zone.exec( () => processTemplates(reader, assetId, - platformDirectives: platformDirectives), + platformDirectives: platformDirectives, + platformPipes: platformPipes), log: logger); } @@ -93,7 +98,7 @@ void allTests() { ..isView = true; fooNgMeta.ngDeps.reflectables.first.annotations.add(viewAnnotation); fooNgMeta.ngDeps.reflectables.first.directives - .add(new PrefixedDirective()..name = 'NgFor'); + .add(new PrefixedType()..name = 'NgFor'); fooNgMeta.ngDeps.imports.add( new ImportModel()..uri = 'package:angular2/src/directives/ng_for.dart'); @@ -121,7 +126,7 @@ void allTests() { ..prefix = '_templates'); expect(ngDeps.reflectables.first.annotations) .toContain(new AnnotationModel() - ..name = '_templates.HostFooComponentTemplate' + ..name = '_templates.hostViewFactory_FooComponent' ..isConstObject = true); expect(outputs.templatesCode) ..toContain('$CONTEXT_ACCESSOR.greeting') @@ -142,7 +147,7 @@ void allTests() { ..prefix = '_templates'); expect(ngDeps.reflectables.first.annotations) .toContain(new AnnotationModel() - ..name = '_templates.HostFooComponentTemplate' + ..name = '_templates.hostViewFactory_FooComponent' ..isConstObject = true); expect(outputs.templatesCode)..toContain('$CONTEXT_ACCESSOR.action()'); }); @@ -158,7 +163,7 @@ void allTests() { ..value = 'const [${barComponentMeta.type.name}]'); fooNgMeta.ngDeps.reflectables.first.annotations.add(viewAnnotation); fooNgMeta.ngDeps.reflectables.first.directives - .add(new PrefixedDirective()..name = barComponentMeta.type.name); + .add(new PrefixedType()..name = barComponentMeta.type.name); fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'bar.dart'); barComponentMeta.template = new CompileTemplateMetadata(template: 'BarTemplate'); @@ -172,7 +177,7 @@ void allTests() { ..prefix = '_templates'); expect(ngDeps.reflectables.first.annotations) .toContain(new AnnotationModel() - ..name = '_templates.HostFooComponentTemplate' + ..name = '_templates.hostViewFactory_FooComponent' ..isConstObject = true); expect(outputs.templatesCode) @@ -188,7 +193,7 @@ void allTests() { ..name = 'View' ..isView = true; fooNgMeta.ngDeps.reflectables.first.annotations.add(componentAnnotation); - fooNgMeta.ngDeps.reflectables.first.directives.add(new PrefixedDirective() + fooNgMeta.ngDeps.reflectables.first.directives.add(new PrefixedType() ..name = barComponentMeta.type.name ..prefix = 'prefix'); fooNgMeta.ngDeps.imports.add(new ImportModel() @@ -206,7 +211,7 @@ void allTests() { ..prefix = '_templates'); expect(ngDeps.reflectables.first.annotations) .toContain(new AnnotationModel() - ..name = '_templates.HostFooComponentTemplate' + ..name = '_templates.hostViewFactory_FooComponent' ..isConstObject = true); expect(outputs.templatesCode) @@ -222,7 +227,7 @@ void allTests() { ..isView = true; fooNgMeta.ngDeps.reflectables.first.annotations.add(componentAnnotation); fooNgMeta.ngDeps.reflectables.first.directives - .add(new PrefixedDirective()..name = 'directiveAlias'); + .add(new PrefixedType()..name = 'directiveAlias'); fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'bar.dart'); fooNgMeta.aliases['directiveAlias'] = [barComponentMeta.type.name]; @@ -238,7 +243,7 @@ void allTests() { ..prefix = '_templates'); expect(ngDeps.reflectables.first.annotations) .toContain(new AnnotationModel() - ..name = '_templates.HostFooComponentTemplate' + ..name = '_templates.hostViewFactory_FooComponent' ..isConstObject = true); expect(outputs.templatesCode) @@ -370,7 +375,7 @@ void allTests() { ..toContain(barComponentMeta.template.template); }); - it('should include platform directives when it it a list.', () async { + it('should include platform directives when it is a list.', () async { fooComponentMeta.template = new CompileTemplateMetadata( template: ''); final viewAnnotation = new AnnotationModel() @@ -417,6 +422,44 @@ void allTests() { final ngDeps = outputs.ngDeps; expect(ngDeps).toBeNotNull(); }); + + it('should parse `View` pipes with a single dependency.', () async { + fooComponentMeta.template = + new CompileTemplateMetadata(template: '{{1 | bar}}'); + final viewAnnotation = new AnnotationModel() + ..name = 'View' + ..isView = true; + viewAnnotation.namedParameters.add(new NamedParameter() + ..name = 'pipes' + ..value = 'const [${barPipeMeta.type.name}]'); + fooNgMeta.ngDeps.reflectables.first.annotations.add(viewAnnotation); + fooNgMeta.ngDeps.reflectables.first.pipes + .add(new PrefixedType()..name = barPipeMeta.type.name); + fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'bar.dart'); + updateReader(); + + final outputs = await process(fooAssetId); + + expect(outputs.templatesCode) + ..toContain("import 'bar.dart'") + ..toContain(barPipeMeta.name); + }); + + it('should include platform pipes.', () async { + fooComponentMeta.template = new CompileTemplateMetadata( + template: '{{1 | bar}}'); + + barNgMeta.aliases['PLATFORM'] = [barPipeMeta.type.name]; + updateReader(); + + final outputs = await process(fooAssetId, + platformPipes: ['package:a/bar.dart#PLATFORM']); + + expect(outputs.templatesCode) + ..toContain("import 'bar.dart'") + ..toContain(barPipeMeta.name); + }); + } void _formatThenExpectEquals(String actual, String expected) {