From a18358d4848821efbd5282c812ae0e70619c2913 Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Tue, 13 Oct 2015 16:38:00 -0700 Subject: [PATCH] refactor(dart/transform): Fold bind_generator into other phases Update `DirectiveProcessor` and `TemplateCompiler` to generate the getters, setters, and methods currently generated in `BindGenerator`. Update `DirectiveMetadataLinker` to output `.ng_meta.json` files instead of `.ng_deps.dart` files, avoiding full codegen until the last phase. This allows us to dedupe codegen logic and remove an additional phase from the transformer. --- .../common/code/reflection_info_code.dart | 14 +- .../lib/src/transform/common/ng_meta.dart | 6 +- .../transformer.dart | 28 +- .../compile_data_creator.dart | 282 ++++++++---------- .../template_compiler/generator.dart | 118 ++------ .../template_compiler/reflection/codegen.dart | 82 ----- .../template_compiler/transformer.dart | 17 +- .../lib/src/transform/transformer.dart | 4 +- 8 files changed, 186 insertions(+), 365 deletions(-) delete mode 100644 modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart 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 c63b218dd0..0d09777497 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 @@ -180,14 +180,17 @@ class _PropertyMetadataVisitor List visitFieldDeclaration(FieldDeclaration node) { var retVal = null; for (var variable in node.fields.variables) { - var propModel = new PropertyMetadataModel()..name = '${variable.name}'; + var propModel = null; for (var meta in node.metadata) { var annotationModel = meta.accept(_annotationVisitor); if (annotationModel != null) { + if (propModel == null) { + propModel = new PropertyMetadataModel()..name = '${variable.name}'; + } propModel.annotations.add(annotationModel); } } - if (propModel.annotations.isNotEmpty) { + if (propModel != null && propModel.annotations.isNotEmpty) { if (retVal == null) { retVal = []; } @@ -200,14 +203,17 @@ class _PropertyMetadataVisitor @override List visitMethodDeclaration(MethodDeclaration node) { if (node.isGetter || node.isSetter) { - var propModel = new PropertyMetadataModel()..name = '${node.name}'; + var propModel = null; for (var meta in node.metadata) { var annotationModel = meta.accept(_annotationVisitor); if (annotationModel != null) { + if (propModel == null) { + propModel = new PropertyMetadataModel()..name = '${node.name}'; + } propModel.annotations.add(annotationModel); } } - if (propModel.annotations.isNotEmpty) { + if (propModel != null && propModel.annotations.isNotEmpty) { return [propModel]; } } 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 6af170d01e..b8d115ebbf 100644 --- a/modules_dart/transform/lib/src/transform/common/ng_meta.dart +++ b/modules_dart/transform/lib/src/transform/common/ng_meta.dart @@ -101,11 +101,9 @@ class NgMeta { } /// Serialized representation of this instance. - Map toJson({bool withNgDeps: true}) { + Map toJson() { var result = {}; - if (withNgDeps) { - result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap(); - } + result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap(); types.forEach((k, v) { result[k] = {_KIND_KEY: _TYPE_VALUE, _VALUE_KEY: v.toJson()}; diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart index 2b0092aeff..e8656dcecb 100644 --- a/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart @@ -4,8 +4,6 @@ import 'dart:async'; import 'dart:convert'; 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/formatter.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; import 'package:barback/barback.dart'; @@ -34,34 +32,14 @@ class DirectiveMetadataLinker extends Transformer { return linkDirectiveMetadata( new AssetReader.fromTransform(transform), primaryId).then((ngMeta) { if (ngMeta != null) { - if (!ngMeta.types.isEmpty || !ngMeta.aliases.isEmpty) { + if (!ngMeta.isEmpty) { transform.addOutput(new Asset.fromString( - primaryId, _encoder.convert(ngMeta.toJson(withNgDeps: false)))); + primaryId, _encoder.convert(ngMeta.toJson()))); } else { // Not outputting an asset could confuse barback. transform.addOutput(new Asset.fromString(primaryId, '')); } - - var depsAssetId = _depsAssetId(primaryId); - if (!ngMeta.isNgDepsEmpty) { - var buf = new StringBuffer(); - var writer = new NgDepsWriter(buf); - writer.writeNgDepsModel(ngMeta.ngDeps); - var formattedCode = - formatter.format(buf.toString(), uri: depsAssetId.path); - transform - .addOutput(new Asset.fromString(depsAssetId, formattedCode)); - } else { - transform.addOutput( - new Asset.fromString(depsAssetId, _emptyNgDepsContents)); - } - } - }); + } }); }); } } - -AssetId _depsAssetId(AssetId primaryId) => - new AssetId(primaryId.package, toDepsExtension(primaryId.path)); - -const _emptyNgDepsContents = 'initReflector() {}'; 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 27498b45f2..d282e678f3 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 @@ -3,54 +3,91 @@ library angular2.transform.template_compiler.compile_data_creator; import 'dart:async'; import 'dart:convert'; -import 'package:analyzer/analyzer.dart'; import 'package:angular2/src/core/compiler/directive_metadata.dart'; import 'package:angular2/src/core/compiler/template_compiler.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; +import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; +import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart'; import 'package:angular2/src/transform/common/names.dart'; -import 'package:angular2/src/transform/common/ng_deps.dart'; import 'package:angular2/src/transform/common/ng_meta.dart'; +import 'package:angular2/src/transform/common/url_resolver.dart'; import 'package:barback/barback.dart'; -import 'package:code_transformers/assets.dart'; /// Creates [NormalizedComponentWithViewDirectives] objects for all `View` -/// `Directive`s defined in `entryPoint`. +/// `Directive`s defined in `assetId`. /// -/// The returned value wraps the [NgDeps] at `entryPoint` as well as these +/// The returned value wraps the [NgDepsModel] at `assetId` as well as these /// created objects. Future createCompileData( AssetReader reader, AssetId assetId) async { - return logElapsedAsync(() { - return new _CompileDataCreator(reader, assetId).createCompileData(); + return logElapsedAsync(() async { + return (await _CompileDataCreator.create(reader, assetId)) + .createCompileData(); }, operationName: 'createCompileData', assetId: assetId); } class CompileDataResults { - final NgDeps ngDeps; - final Map viewDefinitions; final List directiveMetadatas; CompileDataResults._( - this.ngDeps, this.viewDefinitions, this.directiveMetadatas); + this.ngMeta, this.viewDefinitions, this.directiveMetadatas); } -// TODO(kegluenq): Improve this test. -bool _isViewAnnotation(InstanceCreationExpression node) { - var constructorName = node.constructorName.type.name; - if (constructorName is PrefixedIdentifier) { - constructorName = constructorName.identifier; +class _PrefixedDirectiveName { + final String prefix; + final String directiveName; + + _PrefixedDirectiveName(String prefix, this.directiveName) + : this.prefix = prefix == null ? '' : prefix; + + @override + String toString() { + if (prefix.isEmpty) { + return directiveName; + } else { + return '${prefix}.${directiveName}'; + } } - return constructorName.name == 'View'; } -bool _isComponentAnnotation(InstanceCreationExpression node) { - var constructorName = node.constructorName.type.name; - if (constructorName is PrefixedIdentifier) { - constructorName = constructorName.identifier; +String _directivesValue(ReflectionInfoModel model, bool test(AnnotationModel)) { + final viewAnnotation = model.annotations.firstWhere(test, orElse: () => null); + if (viewAnnotation == null) return null; + final directivesParam = viewAnnotation.namedParameters + .firstWhere((p) => p.name == 'directives', orElse: () => null); + return directivesParam != null ? directivesParam.value : null; +} + +// TODO(kegluneq): Parse this value when creating [NgDepsModel]? +/// Find the `directives` parameter on the @View annotation and make sure that +/// all necessary [CompileDirectiveMetadata] objects are available. +Iterable<_PrefixedDirectiveName> _getDirectiveDeps(ReflectionInfoModel model) { + var directives = _directivesValue(model, (m) => m.isView); + if (directives == null) { + directives = _directivesValue(model, (m) => m.isComponent); } - return constructorName.name == 'Component'; + if (directives == null) return const []; + directives = directives.trim(); + for (var toTrim in ['const [', '[']) { + if (directives.startsWith(toTrim) && directives.endsWith(']')) { + directives = + directives.substring(toTrim.length, directives.length - 1).trim(); + } + } + if (directives.length == 0) return const []; + return directives.split(',').map((p) { + var parts = p.trim().split('.'); + if (parts.length == 1) { + return new _PrefixedDirectiveName(null, parts[0]); + } else { + return new _PrefixedDirectiveName(parts[0], parts[1]); + } + }); } /// Creates [ViewDefinition] objects for all `View` `Directive`s defined in @@ -58,37 +95,65 @@ bool _isComponentAnnotation(InstanceCreationExpression node) { class _CompileDataCreator { final AssetReader reader; final AssetId entryPoint; - final Future ngDepsFuture; - final List directiveMetadatas = []; + final NgMeta ngMeta; + final directiveMetadatas = []; - _CompileDataCreator(AssetReader reader, AssetId entryPoint) - : this.reader = reader, - this.entryPoint = entryPoint, - ngDepsFuture = NgDeps.parse(reader, entryPoint); + _CompileDataCreator(this.reader, this.entryPoint, this.ngMeta); + + static Future<_CompileDataCreator> create( + AssetReader reader, AssetId assetId) 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); + } + + NgDepsModel get ngDeps => ngMeta.ngDeps; Future createCompileData() async { - var ngDeps = await ngDepsFuture; + if (ngDeps == null || ngDeps.reflectables == null) { + return new CompileDataResults._(ngMeta, const {}, directiveMetadatas); + } - var retVal = {}; - var visitor = new _DirectiveDependenciesVisitor(await _extractNgMeta()); - ngDeps.registeredTypes.forEach((rType) { - visitor.reset(); - rType.annotations.accept(visitor); - if (visitor.compileData != null) { - // Note: we use '' because the current file maps to the default prefix. - var ngMeta = visitor._metadataMap['']; - var typeName = '${rType.typeName}'; + final compileData = + {}; + final ngMetaMap = await _extractNgMeta(); - if (ngMeta.types.containsKey(typeName)) { - visitor.compileData.component = ngMeta.types[typeName]; - } else { - logger.warning('Missing component "$typeName" in metadata map', - asset: entryPoint); + for (var reflectable in ngDeps.reflectables) { + if (ngMeta.types.containsKey(reflectable.name)) { + final compileDirectiveMetadata = ngMeta.types[reflectable.name]; + if (compileDirectiveMetadata.template != null) { + final compileDatum = new NormalizedComponentWithViewDirectives( + compileDirectiveMetadata, []); + for (var dep in _getDirectiveDeps(reflectable)) { + if (!ngMetaMap.containsKey(dep.prefix)) { + logger.warning( + 'Missing prefix "${dep.prefix}" ' + 'needed by "${dep}" from metadata map', + asset: entryPoint); + continue; + } + final depNgMeta = ngMetaMap[dep.prefix]; + + if (depNgMeta.types.containsKey(dep.directiveName)) { + compileDatum.directives.add(depNgMeta.types[dep.directiveName]); + } else if (depNgMeta.aliases.containsKey(dep.directiveName)) { + compileDatum.directives + .addAll(depNgMeta.flatten(dep.directiveName)); + } else { + logger.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.'); + } + } + compileData[reflectable] = compileDatum; } - retVal[rType] = visitor.compileData; } - }); - return new CompileDataResults._(ngDeps, retVal, directiveMetadatas); + } + return new CompileDataResults._(ngMeta, compileData, directiveMetadatas); } /// Creates a map from [AssetId] to import prefix for `.dart` libraries @@ -96,27 +161,27 @@ class _CompileDataCreator { /// Unprefixed imports have `null` as their value. `entryPoint` is included /// in the map with no prefix. Future> _createImportAssetToPrefixMap() async { - var ngDeps = await ngDepsFuture; + final importAssetToPrefix = {entryPoint: null}; + if (ngDeps == null || ngDeps.imports == null || ngDeps.imports.isEmpty) { + return importAssetToPrefix; + } + final baseUri = toAssetUri(entryPoint); + final resolver = const TransformerUrlResolver(); - var importAssetToPrefix = {entryPoint: null}; - - for (ImportDirective node in ngDeps.imports) { - var uri = stringLiteralToString(node.uri); - if (uri.endsWith('.dart') && !uri.endsWith(DEPS_EXTENSION)) { - var prefix = node.prefix != null && node.prefix.name != null - ? '${node.prefix.name}' - : null; - importAssetToPrefix[uriToAssetId( - entryPoint, uri, logger, null /* span */, - errorOnAbsolute: false)] = prefix; + for (ImportModel model in ngMeta.ngDeps.imports) { + if (model.uri.endsWith('.dart') && !model.isNgDeps) { + var prefix = + model.prefix != null && model.prefix.isEmpty ? null : model.prefix; + importAssetToPrefix[fromUri(resolver.resolve(baseUri, model.uri))] = + prefix; } } return importAssetToPrefix; } /// Reads the `.ng_meta.json` files associated with all of `entryPoint`'s - /// imports and creates a map `Type` name, prefixed if appropriate to the - /// associated [CompileDirectiveMetadata]. + /// imports and creates a map of prefix (or blank) to the + /// associated [NgMeta] object. /// /// For example, if in `entryPoint` we have: /// @@ -132,13 +197,13 @@ class _CompileDataCreator { /// ``` /// /// This method will look for `component.ng_meta.json`to contain the - /// serialized [CompileDirectiveMetadata] for `MyComponent` and any other + /// serialized [NgMeta] for `MyComponent` and any other /// `Directive`s declared in `component.dart`. We use this information to /// build a map: /// /// ``` /// { - /// "prefix.MyComponent": [CompileDirectiveMetadata for MyComponent], + /// "prefix": [NgMeta with CompileDirectiveMetadata for MyComponent], /// ...... /// } /// ``` @@ -172,98 +237,3 @@ class _CompileDataCreator { return retVal; } } - -/// Visitor responsible for processing the `annotations` property of a -/// [RegisterType] object, extracting the `directives` dependencies, and adding -/// their associated [CompileDirectiveMetadata] to the `directives` of a -/// created [NormalizedComponentWithViewDirectives] object. -/// -/// The `component` property of the created -/// [NormalizedComponentWithViewDirectives] will be null. -/// -/// If no `View` annotation is found, `compileData` will be null. -class _DirectiveDependenciesVisitor extends Object - with RecursiveAstVisitor { - NormalizedComponentWithViewDirectives compileData = null; - final Map _metadataMap; - - _DirectiveDependenciesVisitor(this._metadataMap); - - void reset() { - compileData = null; - } - - /// These correspond to the annotations themselves, which are converted into - /// const instance creation expressions so they can be stored in the - /// reflector. - @override - Object visitInstanceCreationExpression(InstanceCreationExpression node) { - if (_isViewAnnotation(node) || _isComponentAnnotation(node)) { - if (compileData == null) { - compileData = new NormalizedComponentWithViewDirectives( - null, []); - } else { - // This is set above, after the visitor is finished. If this value is - // non-null it indicates that we forgot to call `reset()`. - assert(compileData.component == null); - } - node.visitChildren(this); - } - return null; - } - - /// These correspond to the annotation parameters. - @override - Object visitNamedExpression(NamedExpression node) { - // TODO(kegluneq): Remove this limitation. - if (node.name is! Label || node.name.label is! SimpleIdentifier) { - logger.error( - 'Angular 2 currently only supports simple identifiers in directives.' - ' Source: ${node}'); - return null; - } - if ('${node.name.label}' == 'directives') { - _readDirectives(node.expression); - } - return null; - } - - void _readDirectives(Expression node) { - // This could happen in a non-View annotation with a `directives` - // parameter. - if (compileData == null) return; - - if (node is! ListLiteral) { - logger.error('Angular 2 currently only supports list literals as values ' - 'for "directives". Source: $node'); - return; - } - var directiveList = (node as ListLiteral); - for (var node in directiveList.elements) { - var ngMeta; - var name; - if (node is SimpleIdentifier) { - ngMeta = _metadataMap['']; - name = node.name; - } else if (node is PrefixedIdentifier) { - ngMeta = _metadataMap[node.prefix.name]; - name = node.identifier.name; - } else { - logger.error( - 'Angular 2 currently only supports simple and prefixed identifiers ' - 'as values for "directives". Source: $node'); - return; - } - if (ngMeta.types.containsKey(name)) { - compileData.directives.add(ngMeta.types[name]); - } else if (ngMeta.aliases.containsKey(name)) { - compileData.directives.addAll(ngMeta.flatten(name)); - } else { - logger.warning('Could not find Directive entry for $node. ' - '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.'); - } - } - } -} 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 0180a6a945..34919e0fec 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart @@ -2,22 +2,20 @@ library angular2.transform.template_compiler.generator; import 'dart:async'; -import 'package:analyzer/analyzer.dart'; -import 'package:angular2/src/core/compiler/source_module.dart'; -import 'package:angular2/src/core/compiler/template_compiler.dart'; import 'package:angular2/src/core/change_detection/interfaces.dart'; import 'package:angular2/src/core/facade/lang.dart'; import 'package:angular2/src/core/reflection/reflection.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/code/source_module.dart'; import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/model/annotation_model.pb.dart'; +import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; +import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/ng_compiler.dart'; -import 'package:angular2/src/transform/common/ng_deps.dart'; import 'package:barback/barback.dart'; import 'package:path/path.dart' as path; -import 'reflection/codegen.dart' as reg; import 'reflection/processor.dart' as reg; import 'reflection/reflection_capabilities.dart'; import 'compile_data_creator.dart'; @@ -30,22 +28,24 @@ import 'compile_data_creator.dart'; Future processTemplates(AssetReader reader, AssetId assetId, {bool reflectPropertiesAsAttributes: false}) async { var viewDefResults = await createCompileData(reader, assetId); - var codegen = null; if (viewDefResults.directiveMetadatas.isNotEmpty) { var processor = new reg.Processor(); viewDefResults.directiveMetadatas.forEach(processor.process); - codegen = new reg.Codegen(); - codegen.generate(processor); + viewDefResults.ngMeta.ngDeps.getters + .addAll(processor.getterNames.map((e) => e.sanitizedName)); + viewDefResults.ngMeta.ngDeps.setters + .addAll(processor.setterNames.map((e) => e.sanitizedName)); + viewDefResults.ngMeta.ngDeps.methods + .addAll(processor.methodNames.map((e) => e.sanitizedName)); } var templateCompiler = createTemplateCompiler(reader, changeDetectionConfig: new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), reflectPropertiesAsAttributes, false)); - var ngDeps = viewDefResults.ngDeps; - var compileData = + final compileData = viewDefResults.viewDefinitions.values.toList(growable: false); if (compileData.isEmpty) { - return new Outputs(assetId, ngDeps, codegen, null, null); + return new Outputs._(viewDefResults.ngMeta.ngDeps, null); } var savedReflectionCapabilities = reflector.reflectionCapabilities; @@ -55,86 +55,30 @@ Future processTemplates(AssetReader reader, AssetId assetId, }, operationName: 'compileTemplatesCodegen', assetId: assetId); reflector.reflectionCapabilities = savedReflectionCapabilities; - return new Outputs(assetId, ngDeps, codegen, viewDefResults.viewDefinitions, - compiledTemplates); + if (compiledTemplates != null) { + viewDefResults.ngMeta.ngDeps.imports.add(new ImportModel() + ..uri = toTemplateExtension(path.basename(assetId.path)) + ..prefix = '_templates'); + for (var reflectable in viewDefResults.viewDefinitions.keys) { + reflectable.annotations.add(new AnnotationModel() + ..name = '_templates.Host${reflectable.name}Template' + ..isConstObject = true); + } + } + + return new Outputs._( + viewDefResults.ngMeta.ngDeps, writeSourceModule(compiledTemplates)); } -AssetId templatesAssetId(AssetId ngDepsAssetId) => - new AssetId(ngDepsAssetId.package, toTemplateExtension(ngDepsAssetId.path)); +AssetId ngDepsAssetId(AssetId primaryId) => + new AssetId(primaryId.package, toDepsExtension(primaryId.path)); + +AssetId templatesAssetId(AssetId primaryId) => + new AssetId(primaryId.package, toTemplateExtension(primaryId.path)); class Outputs { - final String ngDepsCode; + final NgDepsModel ngDeps; final String templatesCode; - Outputs._(this.ngDepsCode, this.templatesCode); - - factory Outputs( - AssetId assetId, - NgDeps ngDeps, - reg.Codegen accessors, - Map compileDataMap, - SourceModule templatesSource) { - return new Outputs._( - _generateNgDepsCode(assetId, ngDeps, accessors, compileDataMap), - writeSourceModule(templatesSource)); - } - - // Updates the NgDeps code with an additional `CompiledTemplate` annotation - // for each Directive we generated one for. - // - // Also adds an import to the `.template.dart` file that we will generate. - static String _generateNgDepsCode( - AssetId id, - NgDeps ngDeps, - reg.Codegen accessors, - Map compileDataMap) { - var code = ngDeps.code; - if (accessors == null && - (compileDataMap == null || compileDataMap.isEmpty)) return code; - - if (ngDeps.registeredTypes.isEmpty) return code; - var beginRegistrationsIdx = - ngDeps.registeredTypes.first.registerMethod.offset; - var endRegistratationsIdx = ngDeps.registeredTypes.last.registerMethod.end; - var importInjectIdx = ngDeps.lib != null ? ngDeps.lib.end : 0; - - // Add everything up to the point where we begin registering classes with - // the reflector, injecting an import to the generated template code. - var buf; - if (compileDataMap != null) { - buf = new StringBuffer('${code.substring(0, importInjectIdx)}' - 'import \'${toTemplateExtension(path.basename(id.path))}\' as _templates;' - '${code.substring(importInjectIdx, beginRegistrationsIdx)}'); - } else { - buf = new StringBuffer('${code.substring(0, beginRegistrationsIdx)}'); - } - for (var registeredType in ngDeps.registeredTypes) { - if (compileDataMap != null && - compileDataMap.containsKey(registeredType)) { - // We generated a template for this type, so add the generated - // `CompiledTemplate` value as the final annotation in the list. - var annotations = registeredType.annotations as ListLiteral; - if (annotations.length == 0) { - throw new FormatException('Unexpected format - attempting to codegen ' - 'a class with no Component annotation ${registeredType.typeName}'); - } - buf.write(code.substring(registeredType.registerMethod.offset, - annotations.elements.last.end)); - buf.write(', _templates.Host${registeredType.typeName}Template]'); - buf.writeln(code.substring( - registeredType.annotations.end, registeredType.registerMethod.end)); - } else { - // There is no compiled template for this type, write it out without any - // changes. - buf.writeln(code.substring(registeredType.registerMethod.offset, - registeredType.registerMethod.end)); - } - } - buf.writeln(accessors.toString()); - - // Add everything after the final registration. - buf.writeln(code.substring(endRegistratationsIdx)); - return buf.toString(); - } + Outputs._(this.ngDeps, this.templatesCode); } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart deleted file mode 100644 index 21b621ebd6..0000000000 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart +++ /dev/null @@ -1,82 +0,0 @@ -library angular2.transform.template_compiler.reflection.codegen; - -import 'package:angular2/src/transform/common/names.dart'; -import 'package:angular2/src/transform/common/property_utils.dart' as prop; - -import 'model.dart'; - -class Codegen { - final StringBuffer _buf = new StringBuffer(); - - /// Generates code to register all getters, setters, and methods stored by - /// `model`. - /// - /// The code takes the form of zero or more cascaded calls. The receiver of - /// these calls is expected to be an Angular 2 reflector object. - void generate(CodegenModel model) { - if (model != null) { - var calls = _generateGetters(_extractNames(model.getterNames)); - if (calls.isNotEmpty) { - _buf.write('..${REGISTER_GETTERS_METHOD_NAME}' - '({${calls.join(', ')}})'); - } - calls = _generateSetters(_extractNames(model.setterNames)); - if (calls.isNotEmpty) { - _buf.write('..${REGISTER_SETTERS_METHOD_NAME}' - '({${calls.join(', ')}})'); - } - calls = _generateMethods(_extractNames(model.methodNames)); - if (calls.isNotEmpty) { - _buf.write('..${REGISTER_METHODS_METHOD_NAME}' - '({${calls.join(', ')}})'); - } - } - } - - Iterable _extractNames(Iterable accessors) { - var names = accessors.map((accessor) => accessor.sanitizedName); - var nameList = names.toList(); - nameList.sort(); - return nameList; - } - - bool get isEmpty => _buf.isEmpty; - - @override - String toString() => '$_buf'; -} - -Iterable _generateGetters(Iterable getterNames) { - return getterNames.map((getterName) { - if (!prop.isValid(getterName)) { - // TODO(kegluenq): Eagerly throw here once #1295 is addressed. - return prop.lazyInvalidGetter(getterName); - } else { - return ''' '${prop.sanitize(getterName)}': (o) => o.$getterName'''; - } - }); -} - -Iterable _generateSetters(Iterable setterName) { - return setterName.map((setterName) { - if (!prop.isValid(setterName)) { - // TODO(kegluenq): Eagerly throw here once #1295 is addressed. - return prop.lazyInvalidSetter(setterName); - } else { - return ''' '${prop.sanitize(setterName)}': ''' - ''' (o, v) => o.$setterName = v '''; - } - }); -} - -Iterable _generateMethods(Iterable methodNames) { - return methodNames.map((methodName) { - if (!prop.isValid(methodName)) { - // TODO(kegluenq): Eagerly throw here once #1295 is addressed. - return prop.lazyInvalidMethod(methodName); - } else { - return ''' '${prop.sanitize(methodName)}': ''' - '(o, List args) => Function.apply(o.$methodName, args) '; - } - }); -} 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 101e39fc41..7d82b21aa9 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'package:angular2/src/core/dom/html_adapter.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/formatter.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; @@ -24,7 +25,7 @@ class TemplateCompiler extends Transformer { TemplateCompiler(this.options); @override - bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION); + bool isPrimary(AssetId id) => id.path.endsWith(META_EXTENSION); @override Future apply(Transform transform) async { @@ -34,19 +35,25 @@ class TemplateCompiler extends Transformer { var reader = new AssetReader.fromTransform(transform); var outputs = await processTemplates(reader, primaryId, reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes); - var ngDepsCode = ''; + var ngDepsCode = _emptyNgDepsContents; var templatesCode = ''; if (outputs != null) { - if (outputs.ngDepsCode != null) { - ngDepsCode = formatter.format(outputs.ngDepsCode); + if (outputs.ngDeps != null) { + final buf = new StringBuffer(); + final writer = new NgDepsWriter(buf); + writer.writeNgDepsModel(outputs.ngDeps); + ngDepsCode = formatter.format(buf.toString()); } if (outputs.templatesCode != null) { templatesCode = formatter.format(outputs.templatesCode); } } - transform.addOutput(new Asset.fromString(primaryId, ngDepsCode)); + transform.addOutput( + new Asset.fromString(ngDepsAssetId(primaryId), ngDepsCode)); transform.addOutput( new Asset.fromString(templatesAssetId(primaryId), templatesCode)); }); } } + +const _emptyNgDepsContents = 'initReflector() {}\n'; diff --git a/modules_dart/transform/lib/src/transform/transformer.dart b/modules_dart/transform/lib/src/transform/transformer.dart index 8f80327c49..607368d644 100644 --- a/modules_dart/transform/lib/src/transform/transformer.dart +++ b/modules_dart/transform/lib/src/transform/transformer.dart @@ -40,8 +40,8 @@ class AngularTransformerGroup extends TransformerGroup { [ new TemplateCompiler(options), new StylesheetCompiler(), - new DeferredRewriter(options) - ] + ], + [new DeferredRewriter(options)] ]; } return new AngularTransformerGroup._(phases,