feat(dart/transform): Generate all code into <file>.template.dart

Previously, we generated the code to initialize the reflector into the
<file>.ng_deps.dart and the compiled template and change detector code
into <file>.template.dart.

Update the transformer to generate all code into <file>.template.dart to
avoid the additional HTTP requests necessary when debugging
applications in Dartium.
This commit is contained in:
Tim Blasi 2016-01-25 17:37:47 -08:00 committed by Timothy Blasi
parent ed2dbf2db7
commit 8c36aa866a
21 changed files with 141 additions and 108 deletions

View File

@ -58,7 +58,7 @@ class AnnotationVisitor extends SimpleAstVisitor<AnnotationModel> {
} }
/// Defines the format in which an [AnnotationModel] is expressed as Dart code /// Defines the format in which an [AnnotationModel] is expressed as Dart code
/// in a `.ng_deps.dart` file. /// when registered with the reflector.
abstract class AnnotationWriterMixin { abstract class AnnotationWriterMixin {
StringBuffer get buffer; StringBuffer get buffer;

View File

@ -78,8 +78,8 @@ void _populateCombinators(NamespaceDirective node, dynamic model) {
} }
} }
/// Defines the format in which an [ImportModel] is expressed as Dart code in a /// Defines the format in which an [ImportModel] is expressed as Dart code when
/// `.ng_deps.dart` file. /// registered with the reflector.
abstract class ImportWriterMixin { abstract class ImportWriterMixin {
StringBuffer get buffer; StringBuffer get buffer;
@ -96,8 +96,8 @@ abstract class ImportWriterMixin {
} }
} }
/// Defines the format in which an [ExportModel] is expressed as Dart code in a /// Defines the format in which an [ExportModel] is expressed as Dart code when
/// `.ng_deps.dart` file. /// registered with the reflector.
abstract class ExportWriterMixin { abstract class ExportWriterMixin {
StringBuffer get buffer; StringBuffer get buffer;

View File

@ -14,8 +14,7 @@ import 'reflection_info_code.dart';
import 'parameter_code.dart'; import 'parameter_code.dart';
import 'queries_code.dart'; import 'queries_code.dart';
/// Visitor responsible for parsing source Dart files (that is, not /// Visitor responsible for parsing Dart source into [NgDepsModel] objects.
/// `.ng_deps.dart` files) into [NgDepsModel] objects.
class NgDepsVisitor extends RecursiveAstVisitor<Object> { class NgDepsVisitor extends RecursiveAstVisitor<Object> {
final AssetId processedFile; final AssetId processedFile;
final _importVisitor = new ImportVisitor(); final _importVisitor = new ImportVisitor();
@ -113,7 +112,7 @@ class NgDepsVisitor extends RecursiveAstVisitor<Object> {
} }
/// Defines the format in which an [NgDepsModel] is expressed as Dart code /// Defines the format in which an [NgDepsModel] is expressed as Dart code
/// in a `.ng_deps.dart` file. /// when registered with the reflector.
class NgDepsWriter extends Object class NgDepsWriter extends Object
with with
AnnotationWriterMixin, AnnotationWriterMixin,
@ -139,10 +138,10 @@ abstract class NgDepsWriterMixin
void writeNgDepsModel(NgDepsModel model) { void writeNgDepsModel(NgDepsModel model) {
if (model.libraryUri.isNotEmpty) { if (model.libraryUri.isNotEmpty) {
buffer.writeln('library ${model.libraryUri}${DEPS_EXTENSION};\n'); buffer.writeln('library ${model.libraryUri}${TEMPLATE_EXTENSION};\n');
} }
// We need to import & export the source file. // We need to import & export (see below) the source file.
writeImportModel(new ImportModel()..uri = model.sourceFile); writeImportModel(new ImportModel()..uri = model.sourceFile);
// Used to register reflective information. // Used to register reflective information.

View File

@ -95,7 +95,7 @@ class ParameterVisitor extends SimpleAstVisitor<ParameterModel> {
} }
/// Defines the format in which a [ParameterModel] is expressed as Dart code /// Defines the format in which a [ParameterModel] is expressed as Dart code
/// in a `.ng_deps.dart` file. /// when registered with the reflector.
abstract class ParameterWriterMixin { abstract class ParameterWriterMixin {
StringBuffer get buffer; StringBuffer get buffer;

View File

@ -284,7 +284,7 @@ class _PropertyMetadataVisitor
} }
/// Defines the format in which an [ReflectionInfoModel] is expressed as Dart /// Defines the format in which an [ReflectionInfoModel] is expressed as Dart
/// code in a `.ng_deps.dart` file. /// code when registered with the reflector.
abstract class ReflectionWriterMixin abstract class ReflectionWriterMixin
implements AnnotationWriterMixin, ParameterWriterMixin { implements AnnotationWriterMixin, ParameterWriterMixin {
StringBuffer get buffer; StringBuffer get buffer;

View File

@ -1,35 +1,51 @@
library angular2.transform.common.code.source_module; library angular2.transform.common.code.source_module;
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
import 'package:angular2/src/compiler/source_module.dart'; import 'package:angular2/src/compiler/source_module.dart';
import 'package:analyzer/src/generated/scanner.dart' show Keyword;
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/model/source_module.dart';
import 'uri.dart'; import 'ng_deps_code.dart';
/// Writes the full Dart code for the provided [SourceModule]. /// Writes the full Dart code for the provided [SourceModule].
String writeSourceModule(SourceModule sourceModule, {String libraryName}) { String writeSourceModule(SourceModule sourceModule, {String libraryName}) {
if (sourceModule == null) return null; if (sourceModule == null) return null;
var buf = new StringBuffer(); var buf = new StringBuffer();
final writer = new NgDepsWriter(buf);
var sourceWithImports = sourceModule.getSourceWithImports(); var sourceWithImports = sourceModule.getSourceWithImports();
libraryName = _sanitizeLibName( libraryName = _sanitizeLibName(
libraryName != null ? libraryName : sourceModule.moduleUrl); libraryName != null ? libraryName : sourceModule.moduleUrl);
buf..writeln('library $libraryName;')..writeln(); buf..writeln('library $libraryName;')..writeln();
sourceWithImports.imports.forEach((import) {
// Format for importLine := [uri, prefix] extractImports(sourceWithImports, sourceModule.moduleUrl).forEach((import) {
if (import.length != 2) { writer.writeImportModel(import);
throw new FormatException(
'Unexpected import format! '
'Angular 2 compiler returned imports in an unexpected format. '
'Expected [<import_uri>, <prefix>].',
import.join(', '));
}
buf.writeln(writeImportUri(import[0],
prefix: import[1], fromAbsolute: sourceModule.moduleUrl));
}); });
buf..writeln()..writeln(sourceWithImports.source); buf..writeln()..writeln(sourceWithImports.source);
return buf.toString(); return buf.toString();
} }
/// Uses `writer` to write a Dart library representing `model` and
/// `sourceModule`.
void writeTemplateFile(
NgDepsWriterMixin writer, NgDepsModel model, SourceModule sourceModule) {
if (model == null) return null;
var sourceModuleCode = '';
if (sourceModule != null) {
var sourceWithImports = sourceModule.getSourceWithImports();
sourceModuleCode = sourceWithImports.source;
// Since we modify `imports`, make a copy to avoid changing the provided
// value.
var sourceModuleImports =
extractImports(sourceWithImports, sourceModule.moduleUrl);
model = model.clone();
model.imports.addAll(sourceModuleImports);
}
writer.writeNgDepsModel(model);
writer.buffer..writeln()..writeln(sourceModuleCode);
}
final _unsafeCharsPattern = new RegExp(r'[^a-zA-Z0-9_\.]'); final _unsafeCharsPattern = new RegExp(r'[^a-zA-Z0-9_\.]');
String _sanitizeLibName(String moduleUrl) { String _sanitizeLibName(String moduleUrl) {
var sanitized = var sanitized =

View File

@ -122,7 +122,7 @@ const NgDepsModel$json = const {
/** /**
* Generated with: * Generated with:
* ng_deps_model.proto (64702efcc1d7fb434f3652943ba051104960ffd5) * ng_deps_model.proto (03511db92c8cfa3c1279d845be8fd7de36de3ee1)
* libprotoc 2.6.1 * libprotoc 2.6.1
* dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0) * dart-protoc-plugin (af5fc2bf1de367a434c3b1847ab260510878ffc0)
*/ */

View File

@ -33,7 +33,7 @@ message NgDepsModel {
// framework. // framework.
repeated string methods = 9; repeated string methods = 9;
// Imports for the .ng_deps.dart files associated with the declared `imports` // Imports of the generated files associated with the declared `imports`
// and `exports` for this file. // and `exports` of the source file.
repeated ImportModel dep_imports = 10; repeated ImportModel dep_imports = 10;
} }

View File

@ -1,13 +1,37 @@
library angular2.transform.common.code.uri; library angular2.transform.common.model.source_module;
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
/// Generates an `import` statement for the file specified by `importPath`. import 'package:angular2/src/compiler/source_module.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'import_export_model.pb.dart';
/// Generates [ImportModel]s for all imports in `sourceWithImports`.
///
/// Imports in `sourceWithImports` are resolved relative to `moduleUrl`.
List<ImportModel> extractImports(
SourceWithImports sourceWithImports, String moduleUrl) {
if (sourceWithImports == null) return const <ImportModel>[];
return sourceWithImports.imports.map((import) {
// Format for importLine := [uri, prefix]
if (import.length != 2) {
throw new FormatException(
'Internal Angular 2 compiler error. '
'Angular 2 compiler returned imports in an unexpected format. '
'Expected [<import_uri>, <prefix>].',
import.join(', '));
}
return toImportModel(import[0], prefix: import[1], fromAbsolute: moduleUrl);
}).toList();
}
/// Generates an [ImportModel] for the file specified by `importPath`.
/// ///
/// If `fromAbsolute` is specified, `importPath` may be a relative path, /// If `fromAbsolute` is specified, `importPath` may be a relative path,
/// otherwise it is expected to be absolute. /// otherwise it is expected to be absolute.
String writeImportUri(String importPath, {String prefix, String fromAbsolute}) { ImportModel toImportModel(String importPath,
{String prefix, String fromAbsolute}) {
var urlResolver = const TransformerUrlResolver(); var urlResolver = const TransformerUrlResolver();
var codegenImportPath; var codegenImportPath;
@ -33,10 +57,12 @@ String writeImportUri(String importPath, {String prefix, String fromAbsolute}) {
} }
} }
final model = new ImportModel()..uri = codegenImportPath;
if (prefix != null && prefix.isNotEmpty) { if (prefix != null && prefix.isNotEmpty) {
prefix = ' as $prefix'; model.prefix = prefix;
} }
return 'import \'$codegenImportPath\'$prefix;'; return model;
} }
// For a relative import, the scheme, first (package) and second (lib|test|web) // For a relative import, the scheme, first (package) and second (lib|test|web)

View File

@ -8,7 +8,6 @@ const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
const CSS_EXTENSION = '.css'; const CSS_EXTENSION = '.css';
const SHIMMED_STYLESHEET_EXTENSION = '.css.shim.dart'; const SHIMMED_STYLESHEET_EXTENSION = '.css.shim.dart';
const NON_SHIMMED_STYLESHEET_EXTENSION = '.css.dart'; const NON_SHIMMED_STYLESHEET_EXTENSION = '.css.dart';
const DEPS_EXTENSION = '.ng_deps.dart';
const META_EXTENSION = '.ng_meta.json'; const META_EXTENSION = '.ng_meta.json';
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities'; const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart'; const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart';
@ -24,7 +23,6 @@ const TEMPLATE_EXTENSION = '.template.dart';
/// important. For example, putting '.dart' first in this list will cause /// important. For example, putting '.dart' first in this list will cause
/// incorrect behavior. /// incorrect behavior.
const ALL_EXTENSIONS = const [ const ALL_EXTENSIONS = const [
DEPS_EXTENSION,
META_EXTENSION, META_EXTENSION,
SUMMARY_META_EXTENSION, SUMMARY_META_EXTENSION,
TEMPLATE_EXTENSION, TEMPLATE_EXTENSION,
@ -38,7 +36,6 @@ const ALL_EXTENSIONS = const [
/// any files named like transformer outputs will be reported as generated. /// any files named like transformer outputs will be reported as generated.
bool isGenerated(String uri) { bool isGenerated(String uri) {
return const [ return const [
DEPS_EXTENSION,
META_EXTENSION, META_EXTENSION,
NON_SHIMMED_STYLESHEET_EXTENSION, NON_SHIMMED_STYLESHEET_EXTENSION,
SHIMMED_STYLESHEET_EXTENSION, SHIMMED_STYLESHEET_EXTENSION,
@ -51,10 +48,6 @@ bool isGenerated(String uri) {
String toMetaExtension(String uri) => String toMetaExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, META_EXTENSION); _toExtension(uri, ALL_EXTENSIONS, META_EXTENSION);
/// Returns `uri` with its extension updated to [DEPS_EXTENSION].
String toDepsExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, DEPS_EXTENSION);
/// Returns `uri` with its extension updated to [TEMPLATES_EXTENSION]. /// Returns `uri` with its extension updated to [TEMPLATES_EXTENSION].
String toTemplateExtension(String uri) => String toTemplateExtension(String uri) =>
_toExtension(uri, ALL_EXTENSIONS, TEMPLATE_EXTENSION); _toExtension(uri, ALL_EXTENSIONS, TEMPLATE_EXTENSION);

View File

@ -5,7 +5,7 @@ import 'logging.dart';
import 'model/ng_deps_model.pb.dart'; import 'model/ng_deps_model.pb.dart';
import 'url_resolver.dart' show isDartCoreUri; import 'url_resolver.dart' show isDartCoreUri;
/// Metadata about directives, directive aliases, and injectable values. /// Metadata about directives, pipes, directive aliases, and injectable values.
/// ///
/// [NgMeta] is used in three stages of the transformation process: /// [NgMeta] is used in three stages of the transformation process:
/// ///
@ -20,12 +20,12 @@ import 'url_resolver.dart' show isDartCoreUri;
/// 2. Use the [NgDepsModel] to write Dart code registering all injectable /// 2. Use the [NgDepsModel] to write Dart code registering all injectable
/// values with the Angular 2 runtime reflection system. /// values with the Angular 2 runtime reflection system.
/// ///
/// Further down the compilation process, the template compiler needs to reason /// Later in the compilation process, the template compiler needs to reason
/// about the namespace of import prefixes, so it will combine multiple [NgMeta] /// about the namespace of import prefixes, so it will combine multiple [NgMeta]
/// instances together if they were imported into a file with the same prefix. /// instances together if they were imported into a file with the same prefix.
/// ///
/// Instances of this class are serialized into `.ng_meta.json` files as /// Instances of this class are serialized into `.ng_summary.json` and
/// intermediate assets to make the compilation process easier. /// `.ng_meta.json` files as intermediate assets during the compilation process.
class NgMeta { class NgMeta {
static const _ALIAS_VALUE = 'alias'; static const _ALIAS_VALUE = 'alias';
static const _KIND_KEY = 'kind'; static const _KIND_KEY = 'kind';
@ -58,7 +58,8 @@ class NgMeta {
bool get isNgDepsEmpty { bool get isNgDepsEmpty {
if (ngDeps == null) return true; if (ngDeps == null) return true;
// If this file imports only dart: libraries and does not define any // If this file imports only dart: libraries and does not define any
// reflectables of its own, it doesn't need a .ng_deps.dart file. // reflectables of its own, we don't need to register any information from
// it with the Angular 2 reflector.
if (ngDeps.reflectables == null || ngDeps.reflectables.isEmpty) { if (ngDeps.reflectables == null || ngDeps.reflectables.isEmpty) {
if ((ngDeps.imports == null || ngDeps.imports.every(_isDartImport)) && if ((ngDeps.imports == null || ngDeps.imports.every(_isDartImport)) &&
(ngDeps.exports == null || ngDeps.exports.every(_isDartImport))) { (ngDeps.exports == null || ngDeps.exports.every(_isDartImport))) {

View File

@ -27,7 +27,7 @@ class Rewriter {
/// `_entryPoint` /// `_entryPoint`
/// 2. Removes any libraries that don't require angular codegen. /// 2. Removes any libraries that don't require angular codegen.
/// 3. For the remaining libraries, rewrites the import to the corresponding /// 3. For the remaining libraries, rewrites the import to the corresponding
/// `ng_deps.dart` file. /// `.template.dart` file.
/// 4. Chains a future to the `loadLibrary` call which initializes the /// 4. Chains a future to the `loadLibrary` call which initializes the
/// library. /// library.
/// ///
@ -62,11 +62,12 @@ class Rewriter {
var buf = new StringBuffer(); var buf = new StringBuffer();
var idx = var idx =
_visitor.deferredImports.fold(0, (int lastIdx, ImportDirective node) { _visitor.deferredImports.fold(0, (int lastIdx, ImportDirective node) {
buf.write(code.substring(lastIdx, node.offset)); // Write from where we left off until the start of the import uri.
buf.write(code.substring(lastIdx, node.uri.offset));
var import = code.substring(node.offset, node.end); // Rewrite the uri to be that of the generated file.
buf.write(import.replaceFirst('.dart', DEPS_EXTENSION)); buf.write("'${toTemplateExtension('${node.uri.stringValue}')}'");
return node.end; // Update the last index we've processed.
return node.uri.end;
}); });
idx = _visitor.loadLibraryInvocations.fold(idx, idx = _visitor.loadLibraryInvocations.fold(idx,
@ -86,7 +87,7 @@ class Rewriter {
/// Visitor responsible for finding the deferred libraries that need angular /// Visitor responsible for finding the deferred libraries that need angular
/// codegen. Those are the libraries that are loaded deferred and have a /// codegen. Those are the libraries that are loaded deferred and have a
/// corresponding ng_deps file. /// corresponding generated file.
class _FindDeferredLibraries extends Object with RecursiveAstVisitor<Object> { class _FindDeferredLibraries extends Object with RecursiveAstVisitor<Object> {
var deferredImports = new List<ImportDirective>(); var deferredImports = new List<ImportDirective>();
var loadLibraryInvocations = new List<MethodInvocation>(); var loadLibraryInvocations = new List<MethodInvocation>();
@ -132,25 +133,26 @@ class _FindDeferredLibraries extends Object with RecursiveAstVisitor<Object> {
Future cull() async { Future cull() async {
var baseUri = toAssetUri(_entryPoint); var baseUri = toAssetUri(_entryPoint);
// Determine whether a deferred import has ng_deps. // Determine whether a deferred import has an associated generated file.
var hasInputs = await Future.wait(deferredImports var hasInputs = await Future.wait(deferredImports
.map((import) => stringLiteralToString(import.uri)) .map((import) => stringLiteralToString(import.uri))
.map((uri) => toMetaExtension(uri)) .map((uri) => toMetaExtension(uri))
.map((metaUri) => fromUri(_urlResolver.resolve(baseUri, metaUri))) .map((metaUri) => fromUri(_urlResolver.resolve(baseUri, metaUri)))
.map((asset) => _reader.hasInput(asset))); .map((asset) => _reader.hasInput(asset)));
// Filter out any deferred imports that do not have ng_deps. // Filter out any deferred imports that do not have an associated generated
// file.
deferredImports = it.zip([deferredImports, hasInputs]) deferredImports = it.zip([deferredImports, hasInputs])
.where((importHasInput) => importHasInput[1]) .where((importHasInput) => importHasInput[1])
.map((importHasInput) => importHasInput[0]) .map((importHasInput) => importHasInput[0])
.toList(); .toList();
// Find the set of prefixes which have ng_deps. // Find the set of prefixes which have associated generated files.
var prefixes = var prefixes =
new Set.from(deferredImports.map((import) => import.prefix.name)); new Set.from(deferredImports.map((import) => import.prefix.name));
// Filters out any load library invocations where the prefix is not a known // Filters out any load library invocations where the prefix is not a known
// library with ng_deps. // library with associated generated file.
loadLibraryInvocations = loadLibraryInvocations.where((library) { loadLibraryInvocations = loadLibraryInvocations.where((library) {
var value = library.realTarget as SimpleIdentifier; var value = library.realTarget as SimpleIdentifier;
return prefixes.contains(value.name); return prefixes.contains(value.name);

View File

@ -12,12 +12,13 @@ import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:barback/barback.dart'; import 'package:barback/barback.dart';
/// Modifies the [NgDepsModel] represented by `entryPoint` to import its /// Modifies the [NgDepsModel] represented by `entryPoint` to import its
/// dependencies' associated `.ng_deps.dart` files. /// dependencies' associated, generated files.
/// ///
/// For example, if entry_point.ng_deps.dart imports dependency.dart, this /// For example, if entry_point.dart imports dependency.dart, this will check if
/// will check if dependency.ng_meta.json exists. If it does, we add an entry /// dependency.ng_meta.json exists. If it does, we add an entry to the
/// to the `depImports` of [NgDepsModel] for dependency.ng_deps.dart. We can /// `depImports` of [NgDepsModel] for dependency.template.dart.
/// use this information later to ensure that each file's dependencies are ///
/// We use this information later to ensure that each file's dependencies are
/// initialized when that file is initialized. /// initialized when that file is initialized.
Future<NgDepsModel> linkNgDeps(NgDepsModel ngDepsModel, AssetReader reader, Future<NgDepsModel> linkNgDeps(NgDepsModel ngDepsModel, AssetReader reader,
AssetId assetId, UrlResolver resolver) async { AssetId assetId, UrlResolver resolver) async {
@ -29,7 +30,6 @@ Future<NgDepsModel> linkNgDeps(NgDepsModel ngDepsModel, AssetReader reader,
if (linkedDepsMap.isEmpty) { if (linkedDepsMap.isEmpty) {
// We are not calling `initReflector` on any other libraries, but we still // We are not calling `initReflector` on any other libraries, but we still
// return the model to ensure it is written to code. // return the model to ensure it is written to code.
// TODO(kegluneq): Continue using the protobuf format after this phase.
return ngDepsModel; return ngDepsModel;
} }
@ -40,7 +40,7 @@ Future<NgDepsModel> linkNgDeps(NgDepsModel ngDepsModel, AssetReader reader,
if (linkedDepsMap.containsKey(dep.uri) && !seen.contains(dep.uri)) { if (linkedDepsMap.containsKey(dep.uri) && !seen.contains(dep.uri)) {
seen.add(dep.uri); seen.add(dep.uri);
var linkedModel = new ImportModel() var linkedModel = new ImportModel()
..uri = toDepsExtension(dep.uri) ..uri = toTemplateExtension(dep.uri)
..prefix = 'i${idx++}'; ..prefix = 'i${idx++}';
// TODO(kegluneq): Preserve combinators? // TODO(kegluneq): Preserve combinators?
ngDepsModel.depImports.add(linkedModel); ngDepsModel.depImports.add(linkedModel);

View File

@ -20,8 +20,8 @@ import 'ng_meta_linker.dart';
/// Said another way, after this step there should be an entry in this `NgMeta` /// Said another way, after this step there should be an entry in this `NgMeta`
/// object for all `Directives` visible from its associated `.dart` file. /// object for all `Directives` visible from its associated `.dart` file.
/// ///
/// This step also ensures that, if `a.dart` imports `b.dart`, `a.ng_deps.dart` /// This step also ensures that, if `a.dart` imports `b.dart`, `a.template.dart`
/// imports `b.ng_deps.dart` (if it exists) and we note that this is a /// imports `b.template.dart` (if it exists) and we note that this is a
/// ngDeps dependency, ensuring that a's `initReflector` function calls b's /// ngDeps dependency, ensuring that a's `initReflector` function calls b's
/// `initReflector' function. /// `initReflector' function.
/// ///

View File

@ -35,7 +35,7 @@ Future<String> inlineParts(AssetReader reader, AssetId assetId) async {
.accept(directivesVisitor); .accept(directivesVisitor);
// If this is part of another library, its contents will be processed by its // If this is part of another library, its contents will be processed by its
// parent, so it does not need its own `.ng_deps.dart` file. // parent, so it does not need its own generated file.
if (directivesVisitor.isPart) return null; if (directivesVisitor.isPart) return null;
return logElapsedAsync(() { return logElapsedAsync(() {

View File

@ -22,8 +22,8 @@ class Codegen {
/// The code generated here should follow the example of code generated for /// The code generated here should follow the example of code generated for
/// an {@link ImportDirective} node. /// an {@link ImportDirective} node.
String codegenImport() { String codegenImport() {
var importUri = path var importUri = path.basename(
.basename(reflectionEntryPoint.changeExtension(DEPS_EXTENSION).path); reflectionEntryPoint.changeExtension(TEMPLATE_EXTENSION).path);
return '''import '$importUri' as $prefix;'''; return '''import '$importUri' as $prefix;''';
} }

View File

@ -18,9 +18,9 @@ import 'remove_reflection_capabilities.dart';
/// The goal of this is to break the app's dependency on dart:mirrors. /// The goal of this is to break the app's dependency on dart:mirrors.
/// ///
/// This transformer assumes that {@link DirectiveProcessor} and {@link DirectiveLinker} /// This transformer assumes that {@link DirectiveProcessor} and {@link DirectiveLinker}
/// have already been run and that a .ng_deps.dart file has been generated for /// have already been run and that a .template.dart file has been generated for
/// {@link options.entryPoint}. The instantiation of {@link ReflectionCapabilities} is /// {@link options.entryPoint}. The instantiation of {@link ReflectionCapabilities} is
/// replaced by calling `setupReflection` in that .ng_deps.dart file. /// replaced by calling `initReflector` in that .template.dart file.
class ReflectionRemover extends Transformer implements LazyTransformer { class ReflectionRemover extends Transformer implements LazyTransformer {
final TransformerOptions options; final TransformerOptions options;

View File

@ -37,7 +37,7 @@ class Codegen {
/// Generates a change detector class with name `changeDetectorTypeName`, /// Generates a change detector class with name `changeDetectorTypeName`,
/// which must not conflict with other generated classes in the same /// which must not conflict with other generated classes in the same
/// `.ng_deps.dart` file. The change detector is used to detect changes in /// `.template.dart` file. The change detector is used to detect changes in
/// Objects of type `typeName`. /// Objects of type `typeName`.
void generate(String typeName, String changeDetectorTypeName, void generate(String typeName, String changeDetectorTypeName,
ChangeDetectorDefinition def) { ChangeDetectorDefinition def) {

View File

@ -184,8 +184,8 @@ class _CompileDataCreator {
} }
/// Creates a map from import prefix to the asset: uris of all `.dart` /// Creates a map from import prefix to the asset: uris of all `.dart`
/// libraries visible from `entryPoint`, excluding `dart:` and `.ng_deps.dart` /// libraries visible from `entryPoint`, excluding `dart:` and generated files
/// files it imports. Unprefixed imports have the empty string as their key. /// it imports. Unprefixed imports have the empty string as their key.
/// `entryPoint` is included in the map with no prefix. /// `entryPoint` is included in the map with no prefix.
Map<String, Iterable<String>> _createPrefixToImportsMap() { Map<String, Iterable<String>> _createPrefixToImportsMap() {
final baseUri = toAssetUri(entryPoint); final baseUri = toAssetUri(entryPoint);

View File

@ -3,16 +3,13 @@ library angular2.transform.template_compiler.generator;
import 'dart:async'; import 'dart:async';
import 'package:barback/barback.dart'; import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
import 'package:angular2/src/core/change_detection/interfaces.dart'; import 'package:angular2/src/core/change_detection/interfaces.dart';
import 'package:angular2/src/facade/lang.dart'; import 'package:angular2/src/facade/lang.dart';
import 'package:angular2/src/core/reflection/reflection.dart'; import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/transform/common/asset_reader.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/logging.dart';
import 'package:angular2/src/transform/common/model/annotation_model.pb.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/model/ng_deps_model.pb.dart';
import 'package:angular2/src/transform/common/names.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_compiler.dart';
@ -22,17 +19,18 @@ import 'reflection/processor.dart' as reg;
import 'reflection/reflection_capabilities.dart'; import 'reflection/reflection_capabilities.dart';
import 'compile_data_creator.dart'; import 'compile_data_creator.dart';
/// Generates `.ng_deps.dart` files to initialize the Angular2 system. /// Generates `.template.dart` files to initialize the Angular2 system.
/// ///
/// Processes the `.ng_summary.json` file represented by `assetId` /// - Processes the `.ng_meta.json` file represented by `assetId` using
/// `createCompileData`. /// `createCompileData`.
/// Uses the resulting `NgMeta` object to generate /// - Uses the resulting `NgMeta` object to register `getter`s, `setter`s, and
/// `getter`s, `setter`s, and `method`s that would otherwise need to be /// `method`s that would otherwise need to be reflectively accessed with the
/// reflectively accessed. /// `NgDeps` object.
/// Passes the resulting `NormalizedComponentWithViewDirectives` instances /// - Passes the resulting `NormalizedComponentWithViewDirectives` instance(s)
/// to the `TemplateCompiler` to generate compiled template(s). /// to the `TemplateCompiler` to generate compiled template(s) as a
/// Uses the resulting `NgDeps` object to generate a .ng_deps.dart file which /// `SourceModule`.
/// initializes the Angular2 reflective system. /// - Uses the resulting `NgDeps` object to generate code which initializes the
/// Angular2 reflective system.
/// ///
/// This method assumes a {@link DomAdapter} has been registered. /// This method assumes a {@link DomAdapter} has been registered.
Future<Outputs> processTemplates(AssetReader reader, AssetId assetId, Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
@ -77,29 +75,26 @@ Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
reflector.reflectionCapabilities = savedReflectionCapabilities; reflector.reflectionCapabilities = savedReflectionCapabilities;
if (compiledTemplates != null) { if (compiledTemplates != null) {
viewDefResults.ngMeta.ngDeps.imports.add(new ImportModel() // We successfully compiled templates!
..uri = toTemplateExtension(path.basename(assetId.path)) // For each compiled template, add the compiled template class as an
..prefix = '_templates'); // "Annotation" on the code to be registered with the reflector.
for (var reflectable in viewDefResults.viewDefinitions.keys) { for (var reflectable in viewDefResults.viewDefinitions.keys) {
// TODO(kegluneq): Avoid duplicating naming logic for generated classes.
reflectable.annotations.add(new AnnotationModel() reflectable.annotations.add(new AnnotationModel()
..name = '_templates.hostViewFactory_${reflectable.name}' ..name = 'hostViewFactory_${reflectable.name}'
..isConstObject = true); ..isConstObject = true);
} }
} }
return new Outputs._( return new Outputs._(viewDefResults.ngMeta.ngDeps, compiledTemplates);
viewDefResults.ngMeta.ngDeps, writeSourceModule(compiledTemplates));
} }
AssetId ngDepsAssetId(AssetId primaryId) =>
new AssetId(primaryId.package, toDepsExtension(primaryId.path));
AssetId templatesAssetId(AssetId primaryId) => AssetId templatesAssetId(AssetId primaryId) =>
new AssetId(primaryId.package, toTemplateExtension(primaryId.path)); new AssetId(primaryId.package, toTemplateExtension(primaryId.path));
class Outputs { class Outputs {
final NgDepsModel ngDeps; final NgDepsModel ngDeps;
final String templatesCode; final SourceModule templatesSource;
Outputs._(this.ngDeps, this.templatesCode); Outputs._(this.ngDeps, this.templatesSource);
} }

View File

@ -7,6 +7,7 @@ import 'package:barback/barback.dart';
import 'package:angular2/src/platform/server/html_adapter.dart'; import 'package:angular2/src/platform/server/html_adapter.dart';
import 'package:angular2/src/transform/common/asset_reader.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/code/ng_deps_code.dart';
import 'package:angular2/src/transform/common/code/source_module.dart';
import 'package:angular2/src/transform/common/formatter.dart'; import 'package:angular2/src/transform/common/formatter.dart';
import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/names.dart';
import 'package:angular2/src/transform/common/options.dart'; import 'package:angular2/src/transform/common/options.dart';
@ -33,7 +34,6 @@ class TemplateCompiler extends Transformer implements LazyTransformer {
@override @override
declareOutputs(DeclaringTransform transform) { declareOutputs(DeclaringTransform transform) {
transform.declareOutput(ngDepsAssetId(transform.primaryId));
transform.declareOutput(templatesAssetId(transform.primaryId)); transform.declareOutput(templatesAssetId(transform.primaryId));
} }
@ -49,22 +49,23 @@ class TemplateCompiler extends Transformer implements LazyTransformer {
platformDirectives: options.platformDirectives, platformDirectives: options.platformDirectives,
platformPipes: options.platformPipes); platformPipes: options.platformPipes);
var ngDepsCode = _emptyNgDepsContents; var ngDepsCode = _emptyNgDepsContents;
var templatesCode = '';
if (outputs != null) { if (outputs != null) {
if (outputs.ngDeps != null) { if (outputs.ngDeps != null) {
final buf = new StringBuffer(); final buf = new StringBuffer();
final writer = new NgDepsWriter(buf); writeTemplateFile(
writer.writeNgDepsModel(outputs.ngDeps); new NgDepsWriter(buf), outputs.ngDeps, outputs.templatesSource);
ngDepsCode = formatter.format(buf.toString()); ngDepsCode = formatter.format(buf.toString());
}
if (outputs.templatesCode != null) { if (primaryId.path.endsWith('index.ng_meta.json')) {
templatesCode = formatter.format(outputs.templatesCode); final buf2 = new StringBuffer();
var writer = new NgDepsWriter(buf2);
outputs.ngDeps.imports.forEach(writer.writeImportModel);
print(buf2.toString());
}
} }
} }
transform.addOutput( transform.addOutput(
new Asset.fromString(ngDepsAssetId(primaryId), ngDepsCode)); new Asset.fromString(templatesAssetId(primaryId), ngDepsCode));
transform.addOutput(
new Asset.fromString(templatesAssetId(primaryId), templatesCode));
}, log: transform.logger); }, log: transform.logger);
} }
} }