feat(transformers): directive aliases in Dart transformers (fix #1747)
This commit is contained in:
parent
46502e4d61
commit
fd46b49ea6
|
@ -1,3 +1,4 @@
|
||||||
|
import {Injectable} from 'angular2/di';
|
||||||
import {StringMapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
import {StringMapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {isPresent, isArray} from 'angular2/src/facade/lang';
|
import {isPresent, isArray} from 'angular2/src/facade/lang';
|
||||||
import * as modelModule from './model';
|
import * as modelModule from './model';
|
||||||
|
@ -67,6 +68,7 @@ import * as modelModule from './model';
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
@Injectable()
|
||||||
export class FormBuilder {
|
export class FormBuilder {
|
||||||
group(controlsConfig: StringMap<string, any>,
|
group(controlsConfig: StringMap<string, any>,
|
||||||
extra: StringMap<string, any> = null): modelModule.ControlGroup {
|
extra: StringMap<string, any> = null): modelModule.ControlGroup {
|
||||||
|
|
|
@ -6,6 +6,9 @@ const REFLECTOR_VAR_NAME = 'reflector';
|
||||||
const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
|
const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
|
||||||
const DEPS_EXTENSION = '.ng_deps.dart';
|
const DEPS_EXTENSION = '.ng_deps.dart';
|
||||||
const META_EXTENSION = '.ng_meta.json';
|
const META_EXTENSION = '.ng_meta.json';
|
||||||
|
// TODO(sigmund): consider merging into .ng_meta by generating local metadata
|
||||||
|
// upfront (rather than extracting it from ng_deps).
|
||||||
|
const ALIAS_EXTENSION = '.aliases.json';
|
||||||
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
|
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
|
||||||
const REGISTER_TYPE_METHOD_NAME = 'registerType';
|
const REGISTER_TYPE_METHOD_NAME = 'registerType';
|
||||||
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
|
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
|
||||||
|
@ -20,6 +23,10 @@ String toMetaExtension(String uri) =>
|
||||||
String toDepsExtension(String uri) =>
|
String toDepsExtension(String uri) =>
|
||||||
_toExtension(uri, const [META_EXTENSION, '.dart'], DEPS_EXTENSION);
|
_toExtension(uri, const [META_EXTENSION, '.dart'], DEPS_EXTENSION);
|
||||||
|
|
||||||
|
/// Returns `uri` with its extension updated to [ALIAS_EXTENSION].
|
||||||
|
String toAliasExtension(String uri) =>
|
||||||
|
_toExtension(uri, const [DEPS_EXTENSION, '.dart'], ALIAS_EXTENSION);
|
||||||
|
|
||||||
/// Returns `uri` with its extension updated to `toExtension` if its
|
/// Returns `uri` with its extension updated to `toExtension` if its
|
||||||
/// extension is currently in `fromExtension`.
|
/// extension is currently in `fromExtension`.
|
||||||
String _toExtension(
|
String _toExtension(
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
library angular2.transform.common.ng_meta;
|
||||||
|
|
||||||
|
import 'package:angular2/src/render/api.dart';
|
||||||
|
import 'package:angular2/src/render/dom/convert.dart';
|
||||||
|
import 'logging.dart';
|
||||||
|
|
||||||
|
/// Metadata about directives and directive aliases.
|
||||||
|
///
|
||||||
|
/// [NgMeta] is used in three stages of the transformation process. First we
|
||||||
|
/// store directive aliases exported from a single file in an [NgMeta] instance.
|
||||||
|
/// Later we use another [NgMeta] instance to store more information about a
|
||||||
|
/// single file, including both directive aliases and directives extracted from
|
||||||
|
/// the corresponding `.ng_deps.dart` file. Further down the compilation
|
||||||
|
/// process, the template compiler needs to reason about the namespace of import
|
||||||
|
/// prefixes, so it will combine multple [NgMeta] instances together if they
|
||||||
|
/// were imported into a file with the same prefix.
|
||||||
|
///
|
||||||
|
/// Instances of this class are serialized into `.aliases.json` and
|
||||||
|
/// `.ng_meta.json` files as intermediate assets to make the compilation process
|
||||||
|
/// easier.
|
||||||
|
class NgMeta {
|
||||||
|
/// Directive metadata for each type annotated as a directive.
|
||||||
|
final Map<String, DirectiveMetadata> types;
|
||||||
|
|
||||||
|
/// List of other types and names associated with a given name.
|
||||||
|
final Map<String, List<String>> aliases;
|
||||||
|
|
||||||
|
NgMeta(this.types, this.aliases);
|
||||||
|
|
||||||
|
NgMeta.empty() : this({}, {});
|
||||||
|
|
||||||
|
bool get isEmpty => types.isEmpty && aliases.isEmpty;
|
||||||
|
|
||||||
|
/// Parse from the serialized form produced by [toJson].
|
||||||
|
factory NgMeta.fromJson(Map json) {
|
||||||
|
var types = {};
|
||||||
|
var aliases = {};
|
||||||
|
for (var key in json.keys) {
|
||||||
|
var entry = json[key];
|
||||||
|
if (entry['kind'] == 'type') {
|
||||||
|
types[key] = directiveMetadataFromMap(entry['value']);
|
||||||
|
} else if (entry['kind'] == 'alias') {
|
||||||
|
aliases[key] = entry['value'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NgMeta(types, aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialized representation of this instance.
|
||||||
|
Map toJson() {
|
||||||
|
var result = {};
|
||||||
|
types.forEach((k, v) {
|
||||||
|
result[k] = {'kind': 'type', 'value': directiveMetadataToMap(v)};
|
||||||
|
});
|
||||||
|
|
||||||
|
aliases.forEach((k, v) {
|
||||||
|
result[k] = {'kind': 'alias', 'value': v};
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge into this instance all information from [other].
|
||||||
|
void addAll(NgMeta other) {
|
||||||
|
types.addAll(other.types);
|
||||||
|
aliases.addAll(other.aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the metadata for every type associated with the given [alias].
|
||||||
|
List<DirectiveMetadata> flatten(String alias) {
|
||||||
|
var result = [];
|
||||||
|
var seen = new Set();
|
||||||
|
helper(name) {
|
||||||
|
if (!seen.add(name)) {
|
||||||
|
logger.warning('Circular alias dependency for "$name".');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (types.containsKey(name)) {
|
||||||
|
result.add(types[name]);
|
||||||
|
} else if (aliases.containsKey(name)) {
|
||||||
|
aliases[name].forEach(helper);
|
||||||
|
} else {
|
||||||
|
logger.warning('Unknown alias: "$name".');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helper(alias);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +1,49 @@
|
||||||
library angular2.transform.directive_metadata_extractor.extractor;
|
library angular2.transform.directive_metadata_extractor.extractor;
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:analyzer/analyzer.dart';
|
import 'package:analyzer/analyzer.dart';
|
||||||
import 'package:angular2/src/render/api.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/logging.dart';
|
import 'package:angular2/src/transform/common/logging.dart';
|
||||||
import 'package:angular2/src/transform/common/names.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_deps.dart';
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
import 'package:code_transformers/assets.dart';
|
import 'package:code_transformers/assets.dart';
|
||||||
|
|
||||||
/// Returns a map from a class name (that is, its `Identifier` stringified)
|
/// Returns [NgMeta] associated with [entryPoint].
|
||||||
/// to [DirectiveMetadata] for all `Directive`-annotated classes visible
|
///
|
||||||
/// in a file importing `entryPoint`. That is, this includes all
|
/// This includes entries for every `Directive`-annotated classes and
|
||||||
/// `Directive` annotated classes in `entryPoint` and any assets which it
|
/// constants that match the directive-aliases pattern, which are visible in a
|
||||||
/// `export`s.
|
/// file importing `entryPoint`. That is, this includes all `Directive`
|
||||||
/// Returns `null` if there are no `Directive`-annotated classes in
|
/// annotated public classes in `entryPoint`, all `DirectiveAlias` annotated
|
||||||
/// `entryPoint`.
|
/// public variables, and any assets which it `export`s. Returns an empty
|
||||||
Future<Map<String, DirectiveMetadata>> extractDirectiveMetadata(
|
/// [NgMeta] if there are no `Directive`-annotated classes in `entryPoint`.
|
||||||
AssetReader reader, AssetId entryPoint) async {
|
Future<NgMeta> extractDirectiveMetadata(
|
||||||
|
AssetReader reader, AssetId entryPoint) {
|
||||||
return _extractDirectiveMetadataRecursive(reader, entryPoint);
|
return _extractDirectiveMetadataRecursive(reader, entryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _nullFuture = new Future.value(null);
|
var _nullFuture = new Future.value(null);
|
||||||
|
|
||||||
Future<Map<String, DirectiveMetadata>> _extractDirectiveMetadataRecursive(
|
Future<NgMeta> _extractDirectiveMetadataRecursive(
|
||||||
AssetReader reader, AssetId entryPoint) async {
|
AssetReader reader, AssetId entryPoint) async {
|
||||||
if (!(await reader.hasInput(entryPoint))) return null;
|
var ngMeta = new NgMeta.empty();
|
||||||
|
if (!(await reader.hasInput(entryPoint))) return ngMeta;
|
||||||
|
|
||||||
var ngDeps = await NgDeps.parse(reader, entryPoint);
|
var ngDeps = await NgDeps.parse(reader, entryPoint);
|
||||||
var baseMap = _metadataMapFromNgDeps(ngDeps);
|
_extractMetadata(ngDeps, ngMeta);
|
||||||
|
|
||||||
return Future.wait(ngDeps.exports.map((export) {
|
var aliasesFile =
|
||||||
|
new AssetId(entryPoint.package, toAliasExtension(entryPoint.path));
|
||||||
|
|
||||||
|
if (await reader.hasInput(aliasesFile)) {
|
||||||
|
ngMeta.addAll(new NgMeta.fromJson(
|
||||||
|
JSON.decode(await reader.readAsString(aliasesFile))));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.wait(ngDeps.exports.map((export) {
|
||||||
var uri = stringLiteralToString(export.uri);
|
var uri = stringLiteralToString(export.uri);
|
||||||
if (uri.startsWith('dart:')) return _nullFuture;
|
if (uri.startsWith('dart:')) return _nullFuture;
|
||||||
|
|
||||||
|
@ -41,25 +52,16 @@ Future<Map<String, DirectiveMetadata>> _extractDirectiveMetadataRecursive(
|
||||||
errorOnAbsolute: false);
|
errorOnAbsolute: false);
|
||||||
if (assetId == entryPoint) return _nullFuture;
|
if (assetId == entryPoint) return _nullFuture;
|
||||||
return _extractDirectiveMetadataRecursive(reader, assetId)
|
return _extractDirectiveMetadataRecursive(reader, assetId)
|
||||||
.then((exportMap) {
|
.then(ngMeta.addAll);
|
||||||
if (exportMap != null) {
|
}));
|
||||||
if (baseMap == null) {
|
return ngMeta;
|
||||||
baseMap = exportMap;
|
|
||||||
} else {
|
|
||||||
baseMap.addAll(exportMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})).then((_) => baseMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, DirectiveMetadata> _metadataMapFromNgDeps(NgDeps ngDeps) {
|
// TODO(sigmund): rather than having to parse it from generated code. we should
|
||||||
if (ngDeps == null || ngDeps.registeredTypes.isEmpty) return null;
|
// be able to produce directly all information we need for ngMeta.
|
||||||
var retVal = <String, DirectiveMetadata>{};
|
void _extractMetadata(NgDeps ngDeps, NgMeta ngMeta) {
|
||||||
ngDeps.registeredTypes.forEach((rType) {
|
if (ngDeps == null) return;
|
||||||
if (rType.directiveMetadata != null) {
|
ngDeps.registeredTypes.forEach((type) {
|
||||||
retVal['${rType.typeName}'] = rType.directiveMetadata;
|
ngMeta.types[type.typeName.name] = type.directiveMetadata;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ library angular2.transform.directive_metadata_extractor.transformer;
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:angular2/src/render/dom/convert.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/logging.dart' as log;
|
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||||
import 'package:angular2/src/transform/common/names.dart';
|
import 'package:angular2/src/transform/common/names.dart';
|
||||||
|
@ -29,14 +28,10 @@ class DirectiveMetadataExtractor extends Transformer {
|
||||||
var reader = new AssetReader.fromTransform(transform);
|
var reader = new AssetReader.fromTransform(transform);
|
||||||
var fromAssetId = transform.primaryInput.id;
|
var fromAssetId = transform.primaryInput.id;
|
||||||
|
|
||||||
var metadataMap = await extractDirectiveMetadata(reader, fromAssetId);
|
var ngMeta = await extractDirectiveMetadata(reader, fromAssetId);
|
||||||
if (metadataMap != null) {
|
if (ngMeta != null && !ngMeta.isEmpty) {
|
||||||
var jsonMap = <String, Map>{};
|
|
||||||
metadataMap.forEach((k, v) {
|
|
||||||
jsonMap[k] = directiveMetadataToMap(v);
|
|
||||||
});
|
|
||||||
transform.addOutput(new Asset.fromString(
|
transform.addOutput(new Asset.fromString(
|
||||||
_outputAssetId(fromAssetId), _encoder.convert(jsonMap)));
|
_outputAssetId(fromAssetId), _encoder.convert(ngMeta.toJson())));
|
||||||
}
|
}
|
||||||
}, errorMessage: 'Extracting ng metadata failed.');
|
}, errorMessage: 'Extracting ng metadata failed.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:angular2/src/transform/common/interface_matcher.dart';
|
||||||
import 'package:angular2/src/transform/common/logging.dart';
|
import 'package:angular2/src/transform/common/logging.dart';
|
||||||
import 'package:angular2/src/transform/common/names.dart';
|
import 'package:angular2/src/transform/common/names.dart';
|
||||||
import 'package:angular2/src/transform/common/xhr_impl.dart';
|
import 'package:angular2/src/transform/common/xhr_impl.dart';
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:barback/barback.dart' show AssetId;
|
import 'package:barback/barback.dart' show AssetId;
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
@ -23,14 +24,19 @@ import 'visitors.dart';
|
||||||
/// If no Angular 2 `Directive`s are found in `code`, returns the empty
|
/// If no Angular 2 `Directive`s are found in `code`, returns the empty
|
||||||
/// string unless `forceGenerate` is true, in which case an empty ngDeps
|
/// string unless `forceGenerate` is true, in which case an empty ngDeps
|
||||||
/// file is created.
|
/// file is created.
|
||||||
Future<String> createNgDeps(
|
Future<String> createNgDeps(AssetReader reader, AssetId assetId,
|
||||||
AssetReader reader, AssetId assetId, AnnotationMatcher annotationMatcher,
|
AnnotationMatcher annotationMatcher, NgMeta ngMeta,
|
||||||
{bool inlineViews}) async {
|
{bool inlineViews}) async {
|
||||||
// TODO(kegluneq): Shortcut if we can determine that there are no
|
// TODO(kegluneq): Shortcut if we can determine that there are no
|
||||||
// [Directive]s present, taking into account `export`s.
|
// [Directive]s present, taking into account `export`s.
|
||||||
var writer = new AsyncStringWriter();
|
var writer = new AsyncStringWriter();
|
||||||
var visitor = new CreateNgDepsVisitor(writer, assetId,
|
var visitor = new CreateNgDepsVisitor(
|
||||||
new XhrImpl(reader, assetId), annotationMatcher, _interfaceMatcher,
|
writer,
|
||||||
|
assetId,
|
||||||
|
new XhrImpl(reader, assetId),
|
||||||
|
annotationMatcher,
|
||||||
|
_interfaceMatcher,
|
||||||
|
ngMeta,
|
||||||
inlineViews: inlineViews);
|
inlineViews: inlineViews);
|
||||||
var code = await reader.readAsString(assetId);
|
var code = await reader.readAsString(assetId);
|
||||||
parseCompilationUnit(code, name: assetId.path).accept(visitor);
|
parseCompilationUnit(code, name: assetId.path).accept(visitor);
|
||||||
|
@ -49,10 +55,19 @@ InterfaceMatcher _interfaceMatcher = new InterfaceMatcher();
|
||||||
/// associated .ng_deps.dart file.
|
/// associated .ng_deps.dart file.
|
||||||
class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
final AsyncStringWriter writer;
|
final AsyncStringWriter writer;
|
||||||
|
|
||||||
|
/// Output ngMeta information about aliases.
|
||||||
|
// TODO(sigmund): add more to ngMeta. Currently this only contains aliasing
|
||||||
|
// information, but we could produce here all the metadata we need and avoid
|
||||||
|
// parsing the ngdeps files later.
|
||||||
|
final NgMeta ngMeta;
|
||||||
|
|
||||||
/// Whether an Angular 2 `Injectable` has been found.
|
/// Whether an Angular 2 `Injectable` has been found.
|
||||||
bool _foundNgInjectable = false;
|
bool _foundNgInjectable = false;
|
||||||
|
|
||||||
/// Whether this library `imports` or `exports` any non-'dart:' libraries.
|
/// Whether this library `imports` or `exports` any non-'dart:' libraries.
|
||||||
bool _usesNonLangLibs = false;
|
bool _usesNonLangLibs = false;
|
||||||
|
|
||||||
/// Whether we have written an import of base file
|
/// Whether we have written an import of base file
|
||||||
/// (the file we are processing).
|
/// (the file we are processing).
|
||||||
bool _wroteBaseLibImport = false;
|
bool _wroteBaseLibImport = false;
|
||||||
|
@ -66,8 +81,13 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
/// The assetId for the file which we are parsing.
|
/// The assetId for the file which we are parsing.
|
||||||
final AssetId assetId;
|
final AssetId assetId;
|
||||||
|
|
||||||
CreateNgDepsVisitor(AsyncStringWriter writer, AssetId assetId, XHR xhr,
|
CreateNgDepsVisitor(
|
||||||
AnnotationMatcher annotationMatcher, InterfaceMatcher interfaceMatcher,
|
AsyncStringWriter writer,
|
||||||
|
AssetId assetId,
|
||||||
|
XHR xhr,
|
||||||
|
AnnotationMatcher annotationMatcher,
|
||||||
|
InterfaceMatcher interfaceMatcher,
|
||||||
|
this.ngMeta,
|
||||||
{bool inlineViews})
|
{bool inlineViews})
|
||||||
: writer = writer,
|
: writer = writer,
|
||||||
_copyVisitor = new ToSourceVisitor(writer),
|
_copyVisitor = new ToSourceVisitor(writer),
|
||||||
|
@ -223,6 +243,29 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
||||||
|
// We process any top-level declaration that fits the directive-alias
|
||||||
|
// declaration pattern. Ideally we would use an annotation on the field to
|
||||||
|
// help us filter out only what's needed, but unfortunately TypeScript
|
||||||
|
// doesn't support decorators on variable declarations (see
|
||||||
|
// angular/angular#1747 and angular/ts2dart#249 for context).
|
||||||
|
outer: for (var variable in node.variables.variables) {
|
||||||
|
var initializer = variable.initializer;
|
||||||
|
if (initializer != null && initializer is ListLiteral) {
|
||||||
|
var otherNames = [];
|
||||||
|
for (var exp in initializer.elements) {
|
||||||
|
// Only simple identifiers are supported for now.
|
||||||
|
// TODO(sigmund): add support for prefixes (see issue #3232).
|
||||||
|
if (exp is! SimpleIdentifier) continue outer;
|
||||||
|
otherNames.add(exp.name);
|
||||||
|
}
|
||||||
|
ngMeta.aliases[variable.name.name] = otherNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Object _nodeToSource(AstNode node) {
|
Object _nodeToSource(AstNode node) {
|
||||||
if (node == null) return null;
|
if (node == null) return null;
|
||||||
return node.accept(_copyVisitor);
|
return node.accept(_copyVisitor);
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
library angular2.transform.directive_processor.transformer;
|
library angular2.transform.directive_processor.transformer;
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||||
import 'package:angular2/src/transform/common/logging.dart' as log;
|
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||||
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';
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
|
|
||||||
import 'rewriter.dart';
|
import 'rewriter.dart';
|
||||||
|
@ -32,8 +34,9 @@ class DirectiveProcessor extends Transformer {
|
||||||
await log.initZoned(transform, () async {
|
await log.initZoned(transform, () async {
|
||||||
var asset = transform.primaryInput;
|
var asset = transform.primaryInput;
|
||||||
var reader = new AssetReader.fromTransform(transform);
|
var reader = new AssetReader.fromTransform(transform);
|
||||||
|
var ngMeta = new NgMeta.empty();
|
||||||
var ngDepsSrc = await createNgDeps(
|
var ngDepsSrc = await createNgDeps(
|
||||||
reader, asset.id, options.annotationMatcher,
|
reader, asset.id, options.annotationMatcher, ngMeta,
|
||||||
inlineViews: options.inlineViews);
|
inlineViews: options.inlineViews);
|
||||||
if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) {
|
if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) {
|
||||||
var ngDepsAssetId =
|
var ngDepsAssetId =
|
||||||
|
@ -44,6 +47,12 @@ class DirectiveProcessor extends Transformer {
|
||||||
}
|
}
|
||||||
transform.addOutput(new Asset.fromString(ngDepsAssetId, ngDepsSrc));
|
transform.addOutput(new Asset.fromString(ngDepsAssetId, ngDepsSrc));
|
||||||
}
|
}
|
||||||
|
if (!ngMeta.isEmpty) {
|
||||||
|
var ngAliasesId =
|
||||||
|
transform.primaryInput.id.changeExtension(ALIAS_EXTENSION);
|
||||||
|
transform.addOutput(new Asset.fromString(ngAliasesId,
|
||||||
|
new JsonEncoder.withIndent(" ").convert(ngMeta.toJson())));
|
||||||
|
}
|
||||||
}, errorMessage: 'Processing ng directives failed.');
|
}, errorMessage: 'Processing ng directives failed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:analyzer/analyzer.dart';
|
import 'package:analyzer/analyzer.dart';
|
||||||
import 'package:angular2/src/render/api.dart';
|
import 'package:angular2/src/render/api.dart';
|
||||||
import 'package:angular2/src/render/dom/convert.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/logging.dart';
|
import 'package:angular2/src/transform/common/logging.dart';
|
||||||
import 'package:angular2/src/transform/common/names.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_deps.dart';
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
import 'package:code_transformers/assets.dart';
|
import 'package:code_transformers/assets.dart';
|
||||||
|
|
||||||
|
@ -60,18 +60,20 @@ class _ViewDefinitionCreator {
|
||||||
var ngDeps = await ngDepsFuture;
|
var ngDeps = await ngDepsFuture;
|
||||||
|
|
||||||
var retVal = <RegisteredType, ViewDefinitionEntry>{};
|
var retVal = <RegisteredType, ViewDefinitionEntry>{};
|
||||||
var visitor = new _TemplateExtractVisitor(await _createMetadataMap());
|
var visitor = new _TemplateExtractVisitor(await _extractNgMeta());
|
||||||
ngDeps.registeredTypes.forEach((rType) {
|
ngDeps.registeredTypes.forEach((rType) {
|
||||||
visitor.reset();
|
visitor.reset();
|
||||||
rType.annotations.accept(visitor);
|
rType.annotations.accept(visitor);
|
||||||
if (visitor.viewDef != null) {
|
if (visitor.viewDef != null) {
|
||||||
|
// Note: we use '' because the current file maps to the default prefix.
|
||||||
|
var ngMeta = visitor._metadataMap[''];
|
||||||
var typeName = '${rType.typeName}';
|
var typeName = '${rType.typeName}';
|
||||||
var hostMetadata = null;
|
var hostMetadata = null;
|
||||||
if (visitor._metadataMap.containsKey(typeName)) {
|
if (ngMeta.types.containsKey(typeName)) {
|
||||||
hostMetadata = visitor._metadataMap[typeName];
|
hostMetadata = ngMeta.types[typeName];
|
||||||
visitor.viewDef.componentId = hostMetadata.id;
|
visitor.viewDef.componentId = hostMetadata.id;
|
||||||
} else {
|
} else {
|
||||||
logger.error('Missing component "$typeName" in metadata map',
|
logger.warning('Missing component "$typeName" in metadata map',
|
||||||
asset: entryPoint);
|
asset: entryPoint);
|
||||||
visitor.viewDef.componentId = _getComponentId(entryPoint, typeName);
|
visitor.viewDef.componentId = _getComponentId(entryPoint, typeName);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +93,7 @@ class _ViewDefinitionCreator {
|
||||||
var ngDeps = await ngDepsFuture;
|
var ngDeps = await ngDepsFuture;
|
||||||
|
|
||||||
var importAssetToPrefix = <AssetId, String>{};
|
var importAssetToPrefix = <AssetId, String>{};
|
||||||
// Include the `.ng_meta.dart` file associated with `entryPoint`.
|
// Include the `.ng_meta.json` file associated with `entryPoint`.
|
||||||
importAssetToPrefix[new AssetId(
|
importAssetToPrefix[new AssetId(
|
||||||
entryPoint.package, toMetaExtension(entryPoint.path))] = null;
|
entryPoint.package, toMetaExtension(entryPoint.path))] = null;
|
||||||
|
|
||||||
|
@ -137,24 +139,24 @@ class _ViewDefinitionCreator {
|
||||||
/// ...<any other entries>...
|
/// ...<any other entries>...
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
Future<Map<String, DirectiveMetadata>> _createMetadataMap() async {
|
Future<Map<String, NgMeta>> _extractNgMeta() async {
|
||||||
var importAssetToPrefix = await _createImportAssetToPrefixMap();
|
var importAssetToPrefix = await _createImportAssetToPrefixMap();
|
||||||
|
|
||||||
var retVal = <String, DirectiveMetadata>{};
|
var retVal = <String, NgMeta>{};
|
||||||
for (var importAssetId in importAssetToPrefix.keys) {
|
for (var importAssetId in importAssetToPrefix.keys) {
|
||||||
|
var prefix = importAssetToPrefix[importAssetId];
|
||||||
|
if (prefix == null) prefix = '';
|
||||||
|
var ngMeta = retVal.putIfAbsent(prefix, () => new NgMeta.empty());
|
||||||
var metaAssetId = new AssetId(
|
var metaAssetId = new AssetId(
|
||||||
importAssetId.package, toMetaExtension(importAssetId.path));
|
importAssetId.package, toMetaExtension(importAssetId.path));
|
||||||
if (await reader.hasInput(metaAssetId)) {
|
if (await reader.hasInput(metaAssetId)) {
|
||||||
try {
|
try {
|
||||||
var json = await reader.readAsString(metaAssetId);
|
var json = JSON.decode(await reader.readAsString(metaAssetId));
|
||||||
var jsonMap = JSON.decode(json);
|
var newMetadata = new NgMeta.fromJson(json);
|
||||||
jsonMap.forEach((className, metaDataMap) {
|
newMetadata.types.forEach((className, metadata) {
|
||||||
var prefixStr = importAssetToPrefix[importAssetId];
|
metadata.id = _getComponentId(importAssetId, className);
|
||||||
var key = prefixStr != null ? '$prefixStr.$className' : className;
|
|
||||||
var value = directiveMetadataFromMap(metaDataMap)
|
|
||||||
..id = _getComponentId(importAssetId, className);
|
|
||||||
retVal[key] = value;
|
|
||||||
});
|
});
|
||||||
|
ngMeta.addAll(newMetadata);
|
||||||
} catch (ex, stackTrace) {
|
} catch (ex, stackTrace) {
|
||||||
logger.warning('Failed to decode: $ex, $stackTrace',
|
logger.warning('Failed to decode: $ex, $stackTrace',
|
||||||
asset: metaAssetId);
|
asset: metaAssetId);
|
||||||
|
@ -169,7 +171,7 @@ class _ViewDefinitionCreator {
|
||||||
/// [RegisterType] object and pulling out [ViewDefinition] information.
|
/// [RegisterType] object and pulling out [ViewDefinition] information.
|
||||||
class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
|
class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
|
||||||
ViewDefinition viewDef = null;
|
ViewDefinition viewDef = null;
|
||||||
final Map<String, DirectiveMetadata> _metadataMap;
|
final Map<String, NgMeta> _metadataMap;
|
||||||
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
||||||
|
|
||||||
_TemplateExtractVisitor(this._metadataMap);
|
_TemplateExtractVisitor(this._metadataMap);
|
||||||
|
@ -237,28 +239,35 @@ class _TemplateExtractVisitor extends Object with RecursiveAstVisitor<Object> {
|
||||||
if (viewDef == null) return;
|
if (viewDef == null) return;
|
||||||
|
|
||||||
if (node is! ListLiteral) {
|
if (node is! ListLiteral) {
|
||||||
logger.error(
|
logger.error('Angular 2 currently only supports list literals as values '
|
||||||
'Angular 2 currently only supports list literals as values for'
|
'for "directives". Source: $node');
|
||||||
' "directives". Source: $node');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var directiveList = (node as ListLiteral);
|
var directiveList = (node as ListLiteral);
|
||||||
for (var node in directiveList.elements) {
|
for (var node in directiveList.elements) {
|
||||||
if (node is! SimpleIdentifier && node is! PrefixedIdentifier) {
|
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.name;
|
||||||
|
} else {
|
||||||
logger.error(
|
logger.error(
|
||||||
'Angular 2 currently only supports simple and prefixed identifiers '
|
'Angular 2 currently only supports simple and prefixed identifiers '
|
||||||
'as values for "directives". Source: $node');
|
'as values for "directives". Source: $node');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var name = '$node';
|
if (ngMeta.types.containsKey(name)) {
|
||||||
if (_metadataMap.containsKey(name)) {
|
viewDef.directives.add(ngMeta.types[name]);
|
||||||
viewDef.directives.add(_metadataMap[name]);
|
} else if (ngMeta.aliases.containsKey(name)) {
|
||||||
|
viewDef.directives.addAll(ngMeta.flatten(name));
|
||||||
} else {
|
} else {
|
||||||
logger.warning('Could not find Directive entry for $name. '
|
logger.warning('Could not find Directive entry for $node. '
|
||||||
'Please be aware that reusable, pre-defined lists of Directives '
|
'Please be aware that Dart transformers have limited support for '
|
||||||
'(aka "directive aliases") are not yet supported and will cause '
|
'reusable, pre-defined lists of Directives (aka '
|
||||||
'your application to misbehave. '
|
'"directive aliases"). See https://goo.gl/d8XPt0 for details.');
|
||||||
'See https://github.com/angular/angular/issues/1747 for details.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
library angular2.test.transform.common.annotation_matcher_test;
|
||||||
|
|
||||||
|
import 'package:angular2/src/render/api.dart';
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
|
import 'package:guinness/guinness.dart';
|
||||||
|
|
||||||
|
main() => allTests();
|
||||||
|
|
||||||
|
void allTests() {
|
||||||
|
var mockData = [
|
||||||
|
new DirectiveMetadata(id: 'm1'),
|
||||||
|
new DirectiveMetadata(id: 'm2'),
|
||||||
|
new DirectiveMetadata(id: 'm3'),
|
||||||
|
new DirectiveMetadata(id: 'm4')
|
||||||
|
];
|
||||||
|
|
||||||
|
it('should allow empty data.', () {
|
||||||
|
var ngMeta = new NgMeta.empty();
|
||||||
|
expect(ngMeta.isEmpty).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('serialization', () {
|
||||||
|
it('should parse empty data correctly.', () {
|
||||||
|
var ngMeta = new NgMeta.fromJson({});
|
||||||
|
expect(ngMeta.isEmpty).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be lossless', () {
|
||||||
|
var a = new NgMeta.empty();
|
||||||
|
a.types['T0'] = mockData[0];
|
||||||
|
a.types['T1'] = mockData[1];
|
||||||
|
a.types['T2'] = mockData[2];
|
||||||
|
a.types['T3'] = mockData[3];
|
||||||
|
a.aliases['a1'] = ['T1'];
|
||||||
|
a.aliases['a2'] = ['a1'];
|
||||||
|
a.aliases['a3'] = ['T3', 'a2'];
|
||||||
|
a.aliases['a4'] = ['a3', 'T3'];
|
||||||
|
_checkSimilar(a, new NgMeta.fromJson(a.toJson()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('flatten', () {
|
||||||
|
it('should include recursive aliases.', () {
|
||||||
|
var a = new NgMeta.empty();
|
||||||
|
a.types['T0'] = mockData[0];
|
||||||
|
a.types['T1'] = mockData[1];
|
||||||
|
a.types['T2'] = mockData[2];
|
||||||
|
a.types['T3'] = mockData[3];
|
||||||
|
a.aliases['a1'] = ['T1'];
|
||||||
|
a.aliases['a2'] = ['a1'];
|
||||||
|
a.aliases['a3'] = ['T3', 'a2'];
|
||||||
|
a.aliases['a4'] = ['a3', 'T0'];
|
||||||
|
expect(a.flatten('a4')).toEqual([mockData[3], mockData[1], mockData[0]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect cycles.', () {
|
||||||
|
var a = new NgMeta.empty();
|
||||||
|
a.types['T0'] = mockData[0];
|
||||||
|
a.aliases['a1'] = ['T0', 'a1'];
|
||||||
|
a.aliases['a2'] = ['a1'];
|
||||||
|
expect(a.flatten('a1')).toEqual([mockData[0]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('merge', () {
|
||||||
|
it('should merge all types on addAll', () {
|
||||||
|
var a = new NgMeta.empty();
|
||||||
|
var b = new NgMeta.empty();
|
||||||
|
a.types['T0'] = mockData[0];
|
||||||
|
b.types['T1'] = mockData[1];
|
||||||
|
a.addAll(b);
|
||||||
|
expect(a.types).toContain('T1');
|
||||||
|
expect(a.types['T1']).toEqual(mockData[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge all aliases on addAll', () {
|
||||||
|
var a = new NgMeta.empty();
|
||||||
|
var b = new NgMeta.empty();
|
||||||
|
a.aliases['a'] = ['x'];
|
||||||
|
b.aliases['b'] = ['y'];
|
||||||
|
a.addAll(b);
|
||||||
|
expect(a.aliases).toContain('b');
|
||||||
|
expect(a.aliases['b']).toEqual(['y']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkSimilar(NgMeta a, NgMeta b) {
|
||||||
|
expect(a.types.length).toEqual(b.types.length);
|
||||||
|
expect(a.aliases.length).toEqual(b.aliases.length);
|
||||||
|
for (var k in a.types.keys) {
|
||||||
|
expect(b.types).toContain(k);
|
||||||
|
var at = a.types[k];
|
||||||
|
var bt = b.types[k];
|
||||||
|
expect(at.id).toEqual(bt.id);
|
||||||
|
}
|
||||||
|
for (var k in a.aliases.keys) {
|
||||||
|
expect(b.aliases).toContain(k);
|
||||||
|
expect(b.aliases[k]).toEqual(a.aliases[k]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,10 @@ void allTests() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse compile children values', () async {
|
it('should parse compile children values', () async {
|
||||||
var ngDeps = await NgDeps.parse(reader, new AssetId('a',
|
var ngDeps = await NgDeps.parse(
|
||||||
|
reader,
|
||||||
|
new AssetId(
|
||||||
|
'a',
|
||||||
'directive_metadata_extractor/'
|
'directive_metadata_extractor/'
|
||||||
'directive_metadata_files/compile_children.ng_deps.dart'));
|
'directive_metadata_files/compile_children.ng_deps.dart'));
|
||||||
var it = ngDeps.registeredTypes.iterator;
|
var it = ngDeps.registeredTypes.iterator;
|
||||||
|
@ -122,71 +125,108 @@ void allTests() {
|
||||||
|
|
||||||
it('should fail when a class is annotated with multiple Directives.',
|
it('should fail when a class is annotated with multiple Directives.',
|
||||||
() async {
|
() async {
|
||||||
var ngDeps = await NgDeps.parse(reader, new AssetId('a',
|
var ngDeps = await NgDeps.parse(
|
||||||
|
reader,
|
||||||
|
new AssetId(
|
||||||
|
'a',
|
||||||
'directive_metadata_extractor/'
|
'directive_metadata_extractor/'
|
||||||
'directive_metadata_files/too_many_directives.ng_deps.dart'));
|
'directive_metadata_files/too_many_directives.ng_deps.dart'));
|
||||||
expect(() => ngDeps.registeredTypes.first.directiveMetadata).toThrowWith(
|
expect(() => ngDeps.registeredTypes.first.directiveMetadata)
|
||||||
anInstanceOf: PrintLoggerError);
|
.toThrowWith(anInstanceOf: PrintLoggerError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('extractMetadata', () {
|
describe('extractMetadata', () {
|
||||||
it('should generate `DirectiveMetadata` from .ng_deps.dart files.',
|
it('should generate `DirectiveMetadata` from .ng_deps.dart files.',
|
||||||
() async {
|
() async {
|
||||||
var extracted = await extractDirectiveMetadata(reader, new AssetId(
|
var extracted = await extractDirectiveMetadata(
|
||||||
'a', 'directive_metadata_extractor/simple_files/foo.ng_deps.dart'));
|
reader,
|
||||||
expect(extracted).toContain('FooComponent');
|
new AssetId('a',
|
||||||
|
'directive_metadata_extractor/simple_files/foo.ng_deps.dart'));
|
||||||
|
expect(extracted.types).toContain('FooComponent');
|
||||||
|
|
||||||
var extractedMeta = extracted['FooComponent'];
|
var extractedMeta = extracted.types['FooComponent'];
|
||||||
expect(extractedMeta.selector).toEqual('[foo]');
|
expect(extractedMeta.selector).toEqual('[foo]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate `DirectiveMetadata` from .ng_deps.dart files that use '
|
it(
|
||||||
'automatic adjacent string concatenation.', () async {
|
'should generate `DirectiveMetadata` from .ng_deps.dart files that use '
|
||||||
var extracted = await extractDirectiveMetadata(reader, new AssetId('a',
|
'automatic adjacent string concatenation.',
|
||||||
|
() async {
|
||||||
|
var extracted = await extractDirectiveMetadata(
|
||||||
|
reader,
|
||||||
|
new AssetId(
|
||||||
|
'a',
|
||||||
'directive_metadata_extractor/adjacent_strings_files/'
|
'directive_metadata_extractor/adjacent_strings_files/'
|
||||||
'foo.ng_deps.dart'));
|
'foo.ng_deps.dart'));
|
||||||
expect(extracted).toContain('FooComponent');
|
expect(extracted.types).toContain('FooComponent');
|
||||||
|
|
||||||
var extractedMeta = extracted['FooComponent'];
|
var extractedMeta = extracted.types['FooComponent'];
|
||||||
expect(extractedMeta.selector).toEqual('[foo]');
|
expect(extractedMeta.selector).toEqual('[foo]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include `DirectiveMetadata` from exported files.', () async {
|
it('should include `DirectiveMetadata` from exported files.', () async {
|
||||||
var extracted = await extractDirectiveMetadata(reader, new AssetId(
|
var extracted = await extractDirectiveMetadata(
|
||||||
'a', 'directive_metadata_extractor/export_files/foo.ng_deps.dart'));
|
reader,
|
||||||
expect(extracted).toContain('FooComponent');
|
new AssetId('a',
|
||||||
expect(extracted).toContain('BarComponent');
|
'directive_metadata_extractor/export_files/foo.ng_deps.dart'));
|
||||||
|
expect(extracted.types).toContain('FooComponent');
|
||||||
|
expect(extracted.types).toContain('BarComponent');
|
||||||
|
|
||||||
expect(extracted['FooComponent'].selector).toEqual('[foo]');
|
expect(extracted.types['FooComponent'].selector).toEqual('[foo]');
|
||||||
expect(extracted['BarComponent'].selector).toEqual('[bar]');
|
expect(extracted.types['BarComponent'].selector).toEqual('[bar]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include `DirectiveMetadata` recursively from exported files.',
|
it('should include `DirectiveMetadata` recursively from exported files.',
|
||||||
() async {
|
() async {
|
||||||
var extracted = await extractDirectiveMetadata(reader, new AssetId('a',
|
var extracted = await extractDirectiveMetadata(
|
||||||
|
reader,
|
||||||
|
new AssetId('a',
|
||||||
'directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart'));
|
'directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart'));
|
||||||
expect(extracted).toContain('FooComponent');
|
expect(extracted.types).toContain('FooComponent');
|
||||||
expect(extracted).toContain('BarComponent');
|
expect(extracted.types).toContain('BarComponent');
|
||||||
expect(extracted).toContain('BazComponent');
|
expect(extracted.types).toContain('BazComponent');
|
||||||
|
|
||||||
expect(extracted['FooComponent'].selector).toEqual('[foo]');
|
expect(extracted.types['FooComponent'].selector).toEqual('[foo]');
|
||||||
expect(extracted['BarComponent'].selector).toEqual('[bar]');
|
expect(extracted.types['BarComponent'].selector).toEqual('[bar]');
|
||||||
expect(extracted['BazComponent'].selector).toEqual('[baz]');
|
expect(extracted.types['BazComponent'].selector).toEqual('[baz]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include `DirectiveMetadata` from exported files '
|
it(
|
||||||
'expressed as absolute uris', () async {
|
'should include `DirectiveMetadata` from exported files '
|
||||||
reader.addAsset(new AssetId('bar', 'lib/bar.ng_deps.dart'), readFile(
|
'expressed as absolute uris',
|
||||||
|
() async {
|
||||||
|
reader.addAsset(
|
||||||
|
new AssetId('bar', 'lib/bar.ng_deps.dart'),
|
||||||
|
readFile(
|
||||||
'directive_metadata_extractor/absolute_export_files/bar.ng_deps.dart'));
|
'directive_metadata_extractor/absolute_export_files/bar.ng_deps.dart'));
|
||||||
|
|
||||||
var extracted = await extractDirectiveMetadata(reader, new AssetId('a',
|
var extracted = await extractDirectiveMetadata(
|
||||||
|
reader,
|
||||||
|
new AssetId('a',
|
||||||
'directive_metadata_extractor/absolute_export_files/foo.ng_deps.dart'));
|
'directive_metadata_extractor/absolute_export_files/foo.ng_deps.dart'));
|
||||||
expect(extracted).toContain('FooComponent');
|
expect(extracted.types).toContain('FooComponent');
|
||||||
expect(extracted).toContain('BarComponent');
|
expect(extracted.types).toContain('BarComponent');
|
||||||
|
|
||||||
expect(extracted['FooComponent'].selector).toEqual('[foo]');
|
expect(extracted.types['FooComponent'].selector).toEqual('[foo]');
|
||||||
expect(extracted['BarComponent'].selector).toEqual('[bar]');
|
expect(extracted.types['BarComponent'].selector).toEqual('[bar]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include directive aliases', () async {
|
||||||
|
reader.addAsset(
|
||||||
|
new AssetId('bar', 'lib/bar.ng_deps.dart'),
|
||||||
|
readFile(
|
||||||
|
'directive_metadata_extractor/directive_aliases_files/bar.ng_deps.dart'));
|
||||||
|
|
||||||
|
var extracted = await extractDirectiveMetadata(
|
||||||
|
reader,
|
||||||
|
new AssetId('a',
|
||||||
|
'directive_metadata_extractor/directive_aliases_files/foo.ng_deps.dart'));
|
||||||
|
expect(extracted.aliases).toContain('alias1');
|
||||||
|
expect(extracted.aliases).toContain('alias2');
|
||||||
|
expect(extracted.aliases['alias1']).toContain('BarComponent');
|
||||||
|
expect(extracted.aliases['alias2']).toContain('FooComponent');
|
||||||
|
expect(extracted.aliases['alias2']).toContain('alias1');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"alias1": {
|
||||||
|
"kind": "alias",
|
||||||
|
"value": [
|
||||||
|
"BarComponent"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
library foo.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'bar.dart';
|
||||||
|
import 'package:angular2/src/core/annotations/annotations.dart';
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(BarComponent, {
|
||||||
|
'factory': () => new BarComponent(),
|
||||||
|
'parameters': const [],
|
||||||
|
'annotations': const [const Component(selector: '[bar]')]
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"alias2": {
|
||||||
|
"kind": "alias",
|
||||||
|
"value": [
|
||||||
|
"FooComponent",
|
||||||
|
"alias1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
library foo.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'foo.dart';
|
||||||
|
import 'package:angular2/src/core/annotations/annotations.dart';
|
||||||
|
|
||||||
|
export 'bar.dart';
|
||||||
|
import 'bar.ng_deps.dart' as i0;
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(FooComponent, {
|
||||||
|
'factory': () => new FooComponent(),
|
||||||
|
'parameters': const [],
|
||||||
|
'annotations': const [const Component(selector: '[foo]')]
|
||||||
|
});
|
||||||
|
i0.initReflector(reflector);
|
||||||
|
}
|
|
@ -1,10 +1,13 @@
|
||||||
library angular2.test.transform.directive_processor.all_tests;
|
library angular2.test.transform.directive_processor.all_tests;
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:barback/barback.dart';
|
import 'package:barback/barback.dart';
|
||||||
import 'package:angular2/src/transform/directive_processor/rewriter.dart';
|
import 'package:angular2/src/transform/directive_processor/rewriter.dart';
|
||||||
import 'package:angular2/src/transform/common/annotation_matcher.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/asset_reader.dart';
|
||||||
import 'package:angular2/src/transform/common/logging.dart' as log;
|
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||||
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:code_transformers/messages/build_logger.dart';
|
import 'package:code_transformers/messages/build_logger.dart';
|
||||||
import 'package:dart_style/dart_style.dart';
|
import 'package:dart_style/dart_style.dart';
|
||||||
import 'package:guinness/guinness.dart';
|
import 'package:guinness/guinness.dart';
|
||||||
|
@ -18,17 +21,17 @@ main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void allTests() {
|
void allTests() {
|
||||||
_testNgDeps('should preserve parameter annotations as const instances.',
|
_testProcessor('should preserve parameter annotations as const instances.',
|
||||||
'parameter_metadata/soup.dart');
|
'parameter_metadata/soup.dart');
|
||||||
|
|
||||||
_testNgDeps('should recognize custom annotations with package: imports',
|
_testProcessor('should recognize custom annotations with package: imports',
|
||||||
'custom_metadata/package_soup.dart',
|
'custom_metadata/package_soup.dart',
|
||||||
customDescriptors: [
|
customDescriptors: [
|
||||||
const ClassDescriptor('Soup', 'package:soup/soup.dart',
|
const ClassDescriptor('Soup', 'package:soup/soup.dart',
|
||||||
superClass: 'Component'),
|
superClass: 'Component'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
_testNgDeps('should recognize custom annotations with relative imports',
|
_testProcessor('should recognize custom annotations with relative imports',
|
||||||
'custom_metadata/relative_soup.dart',
|
'custom_metadata/relative_soup.dart',
|
||||||
assetId: new AssetId('soup', 'lib/relative_soup.dart'),
|
assetId: new AssetId('soup', 'lib/relative_soup.dart'),
|
||||||
customDescriptors: [
|
customDescriptors: [
|
||||||
|
@ -36,27 +39,32 @@ void allTests() {
|
||||||
superClass: 'Component'),
|
superClass: 'Component'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
_testNgDeps('Requires the specified import.', 'custom_metadata/bad_soup.dart',
|
_testProcessor(
|
||||||
|
'Requires the specified import.', 'custom_metadata/bad_soup.dart',
|
||||||
customDescriptors: [
|
customDescriptors: [
|
||||||
const ClassDescriptor('Soup', 'package:soup/soup.dart',
|
const ClassDescriptor('Soup', 'package:soup/soup.dart',
|
||||||
superClass: 'Component'),
|
superClass: 'Component'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'should inline `templateUrl` values.', 'url_expression_files/hello.dart');
|
'should inline `templateUrl` values.', 'url_expression_files/hello.dart');
|
||||||
|
|
||||||
var absoluteReader = new TestAssetReader();
|
var absoluteReader = new TestAssetReader();
|
||||||
absoluteReader.addAsset(new AssetId('other_package', 'lib/template.html'),
|
absoluteReader.addAsset(
|
||||||
|
new AssetId('other_package', 'lib/template.html'),
|
||||||
readFile(
|
readFile(
|
||||||
'directive_processor/absolute_url_expression_files/template.html'));
|
'directive_processor/absolute_url_expression_files/template.html'));
|
||||||
absoluteReader.addAsset(new AssetId('other_package', 'lib/template.css'),
|
absoluteReader.addAsset(
|
||||||
|
new AssetId('other_package', 'lib/template.css'),
|
||||||
readFile(
|
readFile(
|
||||||
'directive_processor/absolute_url_expression_files/template.css'));
|
'directive_processor/absolute_url_expression_files/template.css'));
|
||||||
_testNgDeps('should inline `templateUrl` and `styleUrls` values expressed as'
|
_testProcessor(
|
||||||
' absolute urls.', 'absolute_url_expression_files/hello.dart',
|
'should inline `templateUrl` and `styleUrls` values expressed'
|
||||||
|
' as absolute urls.',
|
||||||
|
'absolute_url_expression_files/hello.dart',
|
||||||
reader: absoluteReader);
|
reader: absoluteReader);
|
||||||
|
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'should inline multiple `styleUrls` values expressed as absolute urls.',
|
'should inline multiple `styleUrls` values expressed as absolute urls.',
|
||||||
'multiple_style_urls_files/hello.dart');
|
'multiple_style_urls_files/hello.dart');
|
||||||
|
|
||||||
|
@ -64,40 +72,44 @@ void allTests() {
|
||||||
readFile('directive_processor/multiple_style_urls_files/template.html'));
|
readFile('directive_processor/multiple_style_urls_files/template.html'));
|
||||||
absoluteReader.addAsset(new AssetId('a', 'lib/template.css'),
|
absoluteReader.addAsset(new AssetId('a', 'lib/template.css'),
|
||||||
readFile('directive_processor/multiple_style_urls_files/template.css'));
|
readFile('directive_processor/multiple_style_urls_files/template.css'));
|
||||||
absoluteReader.addAsset(new AssetId('a', 'lib/template_other.css'), readFile(
|
absoluteReader.addAsset(
|
||||||
|
new AssetId('a', 'lib/template_other.css'),
|
||||||
|
readFile(
|
||||||
'directive_processor/multiple_style_urls_files/template_other.css'));
|
'directive_processor/multiple_style_urls_files/template_other.css'));
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'shouldn\'t inline multiple `styleUrls` values expressed as absolute '
|
'shouldn\'t inline multiple `styleUrls` values expressed as absolute '
|
||||||
'urls.', 'multiple_style_urls_not_inlined_files/hello.dart',
|
'urls.',
|
||||||
inlineViews: false, reader: absoluteReader);
|
'multiple_style_urls_not_inlined_files/hello.dart',
|
||||||
|
inlineViews: false,
|
||||||
|
reader: absoluteReader);
|
||||||
|
|
||||||
_testNgDeps('should inline `templateUrl`s expressed as adjacent strings.',
|
_testProcessor('should inline `templateUrl`s expressed as adjacent strings.',
|
||||||
'split_url_expression_files/hello.dart');
|
'split_url_expression_files/hello.dart');
|
||||||
|
|
||||||
_testNgDeps('should report implemented types as `interfaces`.',
|
_testProcessor('should report implemented types as `interfaces`.',
|
||||||
'interfaces_files/soup.dart');
|
'interfaces_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps('should not include transitively implemented types.',
|
_testProcessor('should not include transitively implemented types.',
|
||||||
'interface_chain_files/soup.dart');
|
'interface_chain_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps('should not include superclasses in `interfaces`.',
|
_testProcessor('should not include superclasses in `interfaces`.',
|
||||||
'superclass_files/soup.dart');
|
'superclass_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'should populate `lifecycle` when lifecycle interfaces are present.',
|
'should populate `lifecycle` when lifecycle interfaces are present.',
|
||||||
'interface_lifecycle_files/soup.dart');
|
'interface_lifecycle_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps('should populate multiple `lifecycle` values when necessary.',
|
_testProcessor('should populate multiple `lifecycle` values when necessary.',
|
||||||
'multiple_interface_lifecycle_files/soup.dart');
|
'multiple_interface_lifecycle_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'should populate `lifecycle` when lifecycle superclass is present.',
|
'should populate `lifecycle` when lifecycle superclass is present.',
|
||||||
'superclass_lifecycle_files/soup.dart');
|
'superclass_lifecycle_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps('should populate `lifecycle` with prefix when necessary.',
|
_testProcessor('should populate `lifecycle` with prefix when necessary.',
|
||||||
'prefixed_interface_lifecycle_files/soup.dart');
|
'prefixed_interface_lifecycle_files/soup.dart');
|
||||||
|
|
||||||
_testNgDeps(
|
_testProcessor(
|
||||||
'should not throw/hang on invalid urls', 'invalid_url_files/hello.dart',
|
'should not throw/hang on invalid urls', 'invalid_url_files/hello.dart',
|
||||||
expectedLogs: [
|
expectedLogs: [
|
||||||
'ERROR: Uri /bad/absolute/url.html not supported from angular2|test/'
|
'ERROR: Uri /bad/absolute/url.html not supported from angular2|test/'
|
||||||
|
@ -110,13 +122,20 @@ void allTests() {
|
||||||
'test/transform/directive_processor/invalid_url_files/hello.dart'
|
'test/transform/directive_processor/invalid_url_files/hello.dart'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
_testNgDeps('should find and register static functions.',
|
_testProcessor('should find and register static functions.',
|
||||||
'static_function_files/hello.dart');
|
'static_function_files/hello.dart');
|
||||||
|
|
||||||
|
_testProcessor('should find direcive aliases patterns.',
|
||||||
|
'directive_aliases_files/hello.dart',
|
||||||
|
reader: absoluteReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _testNgDeps(String name, String inputPath,
|
void _testProcessor(String name, String inputPath,
|
||||||
{List<AnnotationDescriptor> customDescriptors: const [], AssetId assetId,
|
{List<AnnotationDescriptor> customDescriptors: const [],
|
||||||
AssetReader reader, List<String> expectedLogs, bool inlineViews: true,
|
AssetId assetId,
|
||||||
|
AssetReader reader,
|
||||||
|
List<String> expectedLogs,
|
||||||
|
bool inlineViews: true,
|
||||||
bool isolate: false}) {
|
bool isolate: false}) {
|
||||||
var testFn = isolate ? iit : it;
|
var testFn = isolate ? iit : it;
|
||||||
testFn(name, () async {
|
testFn(name, () async {
|
||||||
|
@ -130,20 +149,33 @@ void _testNgDeps(String name, String inputPath,
|
||||||
reader.addAsset(assetId, await reader.readAsString(inputId));
|
reader.addAsset(assetId, await reader.readAsString(inputId));
|
||||||
inputId = assetId;
|
inputId = assetId;
|
||||||
}
|
}
|
||||||
var expectedPath = path.join(path.dirname(inputPath), 'expected',
|
var expectedNgDepsPath = path.join(path.dirname(inputPath), 'expected',
|
||||||
path.basename(inputPath).replaceFirst('.dart', '.ng_deps.dart'));
|
path.basename(inputPath).replaceFirst('.dart', '.ng_deps.dart'));
|
||||||
var expectedId = _assetIdForPath(expectedPath);
|
var expectedNgDepsId = _assetIdForPath(expectedNgDepsPath);
|
||||||
|
|
||||||
|
var expectedAliasesPath = path.join(path.dirname(inputPath), 'expected',
|
||||||
|
path.basename(inputPath).replaceFirst('.dart', '.aliases.json'));
|
||||||
|
var expectedAliasesId = _assetIdForPath(expectedAliasesPath);
|
||||||
|
|
||||||
var annotationMatcher = new AnnotationMatcher()
|
var annotationMatcher = new AnnotationMatcher()
|
||||||
..addAll(customDescriptors);
|
..addAll(customDescriptors);
|
||||||
var output = await createNgDeps(reader, inputId, annotationMatcher,
|
var ngMeta = new NgMeta.empty();
|
||||||
|
var output = await createNgDeps(
|
||||||
|
reader, inputId, annotationMatcher, ngMeta,
|
||||||
inlineViews: inlineViews);
|
inlineViews: inlineViews);
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
expect(await reader.hasInput(expectedId)).toBeFalse();
|
expect(await reader.hasInput(expectedNgDepsId)).toBeFalse();
|
||||||
} else {
|
} else {
|
||||||
var input = await reader.readAsString(expectedId);
|
var input = await reader.readAsString(expectedNgDepsId);
|
||||||
expect(formatter.format(output)).toEqual(formatter.format(input));
|
expect(formatter.format(output)).toEqual(formatter.format(input));
|
||||||
}
|
}
|
||||||
|
if (ngMeta.isEmpty) {
|
||||||
|
expect(await reader.hasInput(expectedAliasesId)).toBeFalse();
|
||||||
|
} else {
|
||||||
|
var expectedJson = await reader.readAsString(expectedAliasesId);
|
||||||
|
expect(new JsonEncoder.withIndent(' ').convert(ngMeta.toJson()))
|
||||||
|
.toEqual(expectedJson.trim());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (expectedLogs != null) {
|
if (expectedLogs != null) {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
class Bar {}
|
||||||
|
|
||||||
|
const alias3 = const [Bar];
|
|
@ -0,0 +1 @@
|
||||||
|
class Baz {}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"alias1": {
|
||||||
|
"kind": "alias",
|
||||||
|
"value": [
|
||||||
|
"HelloCmp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"alias2": {
|
||||||
|
"kind": "alias",
|
||||||
|
"value": [
|
||||||
|
"HelloCmp",
|
||||||
|
"Foo"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
library examples.src.hello_world.absolute_url_expression_files.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'hello.dart';
|
||||||
|
export 'hello.dart';
|
||||||
|
import 'package:angular2/src/reflection/reflection.dart' as _ngRef;
|
||||||
|
import 'package:angular2/angular2.dart'
|
||||||
|
show bootstrap, Component, Directive, View, NgElement;
|
||||||
|
export 'a.dart' show alias3;
|
||||||
|
import 'b.dart' as b;
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector() {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
_ngRef.reflector
|
||||||
|
..registerType(HelloCmp, {
|
||||||
|
'factory': () => new HelloCmp(),
|
||||||
|
'parameters': const [],
|
||||||
|
'annotations': const [
|
||||||
|
const Component(selector: 'hello-app'),
|
||||||
|
const View(
|
||||||
|
template: r'''{{greeting}}''',
|
||||||
|
templateUrl: r'template.html',
|
||||||
|
styles: const [r'''.greeting { .color: blue; }''',])
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
library examples.src.hello_world.absolute_url_expression_files;
|
||||||
|
|
||||||
|
import 'package:angular2/angular2.dart'
|
||||||
|
show bootstrap, Component, Directive, View, NgElement;
|
||||||
|
export 'a.dart' show alias3;
|
||||||
|
import 'b.dart' as b;
|
||||||
|
|
||||||
|
@Component(selector: 'hello-app')
|
||||||
|
@View(templateUrl: 'template.html', styleUrls: const ['template.css'])
|
||||||
|
class HelloCmp {}
|
||||||
|
|
||||||
|
class Foo {}
|
||||||
|
|
||||||
|
// valid
|
||||||
|
const alias1 = const [HelloCmp];
|
||||||
|
// valid, even though it includes things that are not components
|
||||||
|
const alias2 = const [HelloCmp, Foo];
|
||||||
|
|
||||||
|
// Prefixed names are not supported
|
||||||
|
const alias4 = const [b.Baz];
|
|
@ -0,0 +1 @@
|
||||||
|
.greeting { .color: blue; }
|
|
@ -0,0 +1 @@
|
||||||
|
{{greeting}}
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"MyComponent": {
|
"MyComponent": {
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id": "MyComponent",
|
"id": "MyComponent",
|
||||||
"selector": "[soup]",
|
"selector": "[soup]",
|
||||||
"compileChildren": true,
|
"compileChildren": true,
|
||||||
|
@ -20,4 +22,5 @@
|
||||||
"changeDetection": null,
|
"changeDetection": null,
|
||||||
"version": 1
|
"version": 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -36,6 +36,21 @@ void changeDetectorTests() {
|
||||||
var output = await (process(new AssetId('a', inputPath)));
|
var output = await (process(new AssetId('a', inputPath)));
|
||||||
expect(output).toContain('notifyOnBinding');
|
expect(output).toContain('notifyOnBinding');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should include directives mentioned in directive aliases.', () async {
|
||||||
|
// Input 2 is the same as input1, but contains the directive aliases
|
||||||
|
// inlined.
|
||||||
|
var input1Path =
|
||||||
|
'template_compiler/directive_aliases_files/hello1.ng_deps.dart';
|
||||||
|
var input2Path =
|
||||||
|
'template_compiler/directive_aliases_files/hello2.ng_deps.dart';
|
||||||
|
// Except for the directive argument in the View annotation, the generated
|
||||||
|
// change detectors are identical.
|
||||||
|
var output1 = (await process(new AssetId('a', input1Path))).replaceFirst(
|
||||||
|
'directives: const [alias1]', 'directives: const [GoodbyeCmp]');
|
||||||
|
var output2 = await process(new AssetId('a', input2Path));
|
||||||
|
_formatThenExpectEquals(output1, output2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void noChangeDetectorTests() {
|
void noChangeDetectorTests() {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
library examples.hello_world.index_common_dart.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'hello.dart';
|
||||||
|
import 'package:angular2/angular2.dart'
|
||||||
|
show bootstrap, Component, Directive, View, NgElement;
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(HelloCmp, {
|
||||||
|
'factory': () => new HelloCmp(),
|
||||||
|
'parameters': const [const []],
|
||||||
|
'annotations': const [
|
||||||
|
const Component(selector: 'hello-app'),
|
||||||
|
const View(template: 'goodbye-app', directives: const [alias1])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
..registerType(GoodbyeCmp, {
|
||||||
|
'factory': () => new GoodbyeCmp(),
|
||||||
|
'parameters': const [const []],
|
||||||
|
'annotations': const [
|
||||||
|
const Component(selector: 'goodbye-app'),
|
||||||
|
const View(template: 'Goodbye')
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"HelloCmp":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"id":"HelloCmp",
|
||||||
|
"selector":"hello-app",
|
||||||
|
"compileChildren":true,
|
||||||
|
"host":{},
|
||||||
|
"properties":[],
|
||||||
|
"readAttributes":[],
|
||||||
|
"type":1,
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GoodbyeCmp":{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"id":"GoodbyeCmp",
|
||||||
|
"selector":"goodbye-app",
|
||||||
|
"compileChildren":true,
|
||||||
|
"host":{},
|
||||||
|
"properties":[],
|
||||||
|
"readAttributes":[],
|
||||||
|
"type":1,
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aliases1":{
|
||||||
|
"kind": "alias",
|
||||||
|
"value": [
|
||||||
|
"GoodbyeCmp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
library examples.hello_world.index_common_dart.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'hello.dart';
|
||||||
|
import 'package:angular2/angular2.dart'
|
||||||
|
show bootstrap, Component, Directive, View, NgElement;
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector(reflector) {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
reflector
|
||||||
|
..registerType(HelloCmp, {
|
||||||
|
'factory': () => new HelloCmp(),
|
||||||
|
'parameters': const [const []],
|
||||||
|
'annotations': const [
|
||||||
|
const Component(selector: 'hello-app'),
|
||||||
|
const View(template: 'goodbye-app', directives: const [GoodbyeCmp])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
..registerType(GoodbyeCmp, {
|
||||||
|
'factory': () => new GoodbyeCmp(),
|
||||||
|
'parameters': const [const []],
|
||||||
|
'annotations': const [
|
||||||
|
const Component(selector: 'goodbye-app'),
|
||||||
|
const View(template: 'Goodbye')
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"HelloCmp":
|
||||||
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"id":"HelloCmp",
|
||||||
|
"selector":"hello-app",
|
||||||
|
"compileChildren":true,
|
||||||
|
"host":{},
|
||||||
|
"properties":[],
|
||||||
|
"readAttributes":[],
|
||||||
|
"type":1,
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GoodbyeCmp":{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
|
"id":"GoodbyeCmp",
|
||||||
|
"selector":"goodbye-app",
|
||||||
|
"compileChildren":true,
|
||||||
|
"host":{},
|
||||||
|
"properties":[],
|
||||||
|
"readAttributes":[],
|
||||||
|
"type":1,
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -9,8 +11,11 @@
|
||||||
"readAttributes":[],
|
"readAttributes":[],
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"GoodbyeCmp":{
|
"GoodbyeCmp":{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"GoodbyeCmp",
|
"id":"GoodbyeCmp",
|
||||||
"selector":"goodbye-app",
|
"selector":"goodbye-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -20,4 +25,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"GoodbyeCmp":{
|
"GoodbyeCmp":{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"GoodbyeCmp",
|
"id":"GoodbyeCmp",
|
||||||
"selector":"goodbye-app",
|
"selector":"goodbye-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -9,4 +11,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"HelloCmp":
|
"HelloCmp":
|
||||||
{
|
{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"HelloCmp",
|
"id":"HelloCmp",
|
||||||
"selector":"hello-app",
|
"selector":"hello-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -10,4 +12,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"MyApp":{
|
"MyApp":{
|
||||||
|
"kind": "type",
|
||||||
|
"value": {
|
||||||
"id":"MyApp",
|
"id":"MyApp",
|
||||||
"selector":"my-app",
|
"selector":"my-app",
|
||||||
"compileChildren":true,
|
"compileChildren":true,
|
||||||
|
@ -9,4 +11,5 @@
|
||||||
"type":1,
|
"type":1,
|
||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:unittest/unittest.dart' hide expect;
|
||||||
import 'package:unittest/vm_config.dart';
|
import 'package:unittest/vm_config.dart';
|
||||||
|
|
||||||
import 'common/async_string_writer_tests.dart' as asyncStringWriter;
|
import 'common/async_string_writer_tests.dart' as asyncStringWriter;
|
||||||
|
import 'common/ng_meta_test.dart' as ngMetaTest;
|
||||||
import 'bind_generator/all_tests.dart' as bindGenerator;
|
import 'bind_generator/all_tests.dart' as bindGenerator;
|
||||||
import 'deferred_rewriter/all_tests.dart' as deferredRewriter;
|
import 'deferred_rewriter/all_tests.dart' as deferredRewriter;
|
||||||
import 'directive_linker/all_tests.dart' as directiveLinker;
|
import 'directive_linker/all_tests.dart' as directiveLinker;
|
||||||
|
@ -17,6 +18,7 @@ import 'template_compiler/all_tests.dart' as templateCompiler;
|
||||||
main() {
|
main() {
|
||||||
useVMConfiguration();
|
useVMConfiguration();
|
||||||
describe('AsyncStringWriter', asyncStringWriter.allTests);
|
describe('AsyncStringWriter', asyncStringWriter.allTests);
|
||||||
|
describe('NgMeta', ngMetaTest.allTests);
|
||||||
describe('Bind Generator', bindGenerator.allTests);
|
describe('Bind Generator', bindGenerator.allTests);
|
||||||
describe('Directive Linker', directiveLinker.allTests);
|
describe('Directive Linker', directiveLinker.allTests);
|
||||||
describe('Directive Metadata Extractor', directiveMeta.allTests);
|
describe('Directive Metadata Extractor', directiveMeta.allTests);
|
||||||
|
|
|
@ -30,13 +30,10 @@ transformers:
|
||||||
- web/src/key_events/index.dart
|
- web/src/key_events/index.dart
|
||||||
- web/src/sourcemap/index.dart
|
- web/src/sourcemap/index.dart
|
||||||
- web/src/todo/index.dart
|
- web/src/todo/index.dart
|
||||||
# These entrypoints are disabled until nested-directives are supported
|
- web/src/model_driven_forms/index.dart
|
||||||
# by transformers (issue #1747):
|
- web/src/order_management/index.dart
|
||||||
# web/src/model_driven_forms/index.dart
|
- web/src/person_management/index.dart
|
||||||
# web/src/order_management/index.dart
|
- web/src/template_driven_forms/index.dart
|
||||||
# web/src/person_management/index.dart
|
|
||||||
# web/src/template_driven_forms/index.dart
|
|
||||||
#
|
|
||||||
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
||||||
# - web/src/material/button/index.dart
|
# - web/src/material/button/index.dart
|
||||||
# - web/src/material/checkbox/index.dart
|
# - web/src/material/checkbox/index.dart
|
||||||
|
@ -57,13 +54,10 @@ transformers:
|
||||||
- web/src/key_events/index.dart
|
- web/src/key_events/index.dart
|
||||||
- web/src/sourcemap/index.dart
|
- web/src/sourcemap/index.dart
|
||||||
- web/src/todo/index.dart
|
- web/src/todo/index.dart
|
||||||
# These entrypoints are disabled until nested-directives are supported
|
- web/src/model_driven_forms/index.dart
|
||||||
# by transformers (issue #1747):
|
- web/src/order_management/index.dart
|
||||||
# web/src/model_driven_forms/index.dart
|
- web/src/person_management/index.dart
|
||||||
# web/src/order_management/index.dart
|
- web/src/template_driven_forms/index.dart
|
||||||
# web/src/person_management/index.dart
|
|
||||||
# web/src/template_driven_forms/index.dart
|
|
||||||
#
|
|
||||||
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
||||||
# - web/src/material/button/index.dart
|
# - web/src/material/button/index.dart
|
||||||
# - web/src/material/checkbox/index.dart
|
# - web/src/material/checkbox/index.dart
|
||||||
|
|
|
@ -13,6 +13,8 @@ import {
|
||||||
EventEmitter
|
EventEmitter
|
||||||
} from 'angular2/bootstrap';
|
} from 'angular2/bootstrap';
|
||||||
|
|
||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
|
||||||
import {formDirectives} from 'angular2/forms';
|
import {formDirectives} from 'angular2/forms';
|
||||||
|
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
@ -44,6 +46,7 @@ class Order {
|
||||||
// ---- services
|
// ---- services
|
||||||
|
|
||||||
var _nextId = 1000;
|
var _nextId = 1000;
|
||||||
|
@Injectable()
|
||||||
class DataService {
|
class DataService {
|
||||||
orderItems: OrderItem[];
|
orderItems: OrderItem[];
|
||||||
orders: Order[];
|
orders: Order[];
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {
|
||||||
Binding
|
Binding
|
||||||
} from 'angular2/bootstrap';
|
} from 'angular2/bootstrap';
|
||||||
|
|
||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
|
||||||
import {formDirectives} from 'angular2/forms';
|
import {formDirectives} from 'angular2/forms';
|
||||||
|
|
||||||
import {RegExpWrapper, print, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
import {RegExpWrapper, print, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
|
@ -50,6 +52,7 @@ class Person {
|
||||||
|
|
||||||
// ---- services
|
// ---- services
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
class DataService {
|
class DataService {
|
||||||
currentPerson: Person;
|
currentPerson: Person;
|
||||||
persons: Person[];
|
persons: Person[];
|
||||||
|
|
|
@ -51,7 +51,8 @@ function getSourceTree() {
|
||||||
translateBuiltins: true,
|
translateBuiltins: true,
|
||||||
});
|
});
|
||||||
// Native sources, dart only examples, etc.
|
// Native sources, dart only examples, etc.
|
||||||
var dartSrcs = modulesFunnel(['**/*.dart', '**/*.ng_meta.json', '**/css/**']);
|
var dartSrcs =
|
||||||
|
modulesFunnel(['**/*.dart', '**/*.ng_meta.json', '**/*.aliases.json', '**/css/**']);
|
||||||
return mergeTrees([transpiled, dartSrcs]);
|
return mergeTrees([transpiled, dartSrcs]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue