refactor(dart/transform): Use a protobufs representation during transform
To simplify processing and testing in the future, use protobufs to represent of `.ng_deps.dart` files rather than always dealing directly in Dart code. This update does not actually use the protobuf representation, but this is a step towards moving all phases to parse and use protobufs rather than Dart code.
This commit is contained in:
parent
cb4ff7491a
commit
e889ec8335
|
@ -0,0 +1,92 @@
|
|||
library angular2.transform.common.code.annotation_code;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/model/annotation_model.pb.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
|
||||
import 'constify.dart' show constify;
|
||||
|
||||
/// Visitor responsible for parsing [Annotation]s into [AnnotationModel]s.
|
||||
class AnnotationVisitor extends SimpleAstVisitor<AnnotationModel> {
|
||||
/// The file we are processing.
|
||||
final AssetId assetId;
|
||||
|
||||
/// Responsible for testing whether [Annotation]s are those recognized by
|
||||
/// Angular 2, for example `@Component`.
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
|
||||
AnnotationVisitor(this.assetId, this._annotationMatcher);
|
||||
|
||||
@override
|
||||
AnnotationModel visitAnnotation(Annotation node) {
|
||||
var name = constify(node.name);
|
||||
if (node.constructorName != null) {
|
||||
name += '.${constify(node.constructorName)}';
|
||||
}
|
||||
var isComponent = _annotationMatcher.isComponent(node, assetId);
|
||||
var isDirective =
|
||||
isComponent || _annotationMatcher.isDirective(node, assetId);
|
||||
var isInjectable =
|
||||
isDirective || _annotationMatcher.isInjectable(node, assetId);
|
||||
var isView = _annotationMatcher.isView(node, assetId);
|
||||
var model = new AnnotationModel()
|
||||
..name = name
|
||||
..isComponent = isComponent
|
||||
..isDirective = isDirective
|
||||
..isInjectable = isInjectable
|
||||
..isView = isView;
|
||||
|
||||
if (node.arguments != null) {
|
||||
for (var arg in node.arguments.arguments) {
|
||||
if (arg is NamedExpression) {
|
||||
model.namedParameters.add(new NamedParameter()
|
||||
..name = constify(arg.name.label)
|
||||
..value = constify(arg.expression));
|
||||
} else {
|
||||
model.parameters.add(constify(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which an [AnnotationModel] is expressed as Dart code
|
||||
/// in a `.ng_deps.dart` file.
|
||||
abstract class AnnotationWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void writeAnnotationModel(AnnotationModel model) {
|
||||
if (model.parameters != null || model.namedParameters != null) {
|
||||
buffer.write('const ${model.name}(');
|
||||
var first = true;
|
||||
for (var param in model.parameters) {
|
||||
if (!first) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
first = false;
|
||||
buffer.write(param);
|
||||
}
|
||||
// TODO(kegluneq): We are currently outputting these sorted to ensure we
|
||||
// have repeatable output for testing purposes.
|
||||
// Remove this sorting once we are not testing output code directly.
|
||||
var namedParameters = model.namedParameters.toList();
|
||||
namedParameters.sort((a, b) => a.name.compareTo(b.name));
|
||||
for (var param in namedParameters) {
|
||||
if (!first) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
first = false;
|
||||
buffer.write('${param.name}: ${param.value}');
|
||||
}
|
||||
buffer.write(')');
|
||||
} else {
|
||||
// This is a const instance, not a ctor invocation and does not need a
|
||||
// const instance creation expression.
|
||||
buffer.write(model.name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
library angular2.transform.common.code.constify;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
|
||||
/// Serializes the provided [AstNode] to Dart source, replacing `new` in
|
||||
/// [InstanceCreationExpression]s and the `@` in [Annotation]s with `const`.
|
||||
String constify(AstNode node) {
|
||||
var writer = new PrintStringWriter();
|
||||
node.accept(new _ConstifyingVisitor(writer));
|
||||
return '$writer';
|
||||
}
|
||||
|
||||
class _ConstifyingVisitor extends ToSourceVisitor {
|
||||
final PrintWriter writer;
|
||||
|
||||
_ConstifyingVisitor(PrintWriter writer)
|
||||
: this.writer = writer,
|
||||
super(writer);
|
||||
|
||||
@override
|
||||
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
|
||||
if (node.keyword.lexeme == 'const') {
|
||||
return super.visitInstanceCreationExpression(node);
|
||||
} else if (node.keyword.lexeme == 'new') {
|
||||
writer.print('const ');
|
||||
if (node.constructorName != null) {
|
||||
node.constructorName.accept(this);
|
||||
}
|
||||
if (node.argumentList != null) {
|
||||
node.argumentList.accept(this);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
var hasArguments =
|
||||
node.arguments != null && node.arguments.arguments != null;
|
||||
if (hasArguments) {
|
||||
writer.print('const ');
|
||||
}
|
||||
if (node.name != null) {
|
||||
node.name.accept(this);
|
||||
}
|
||||
if (node.constructorName != null) {
|
||||
writer.print('.');
|
||||
node.constructorName.accept(this);
|
||||
}
|
||||
if (hasArguments) {
|
||||
var args = node.arguments.arguments;
|
||||
writer.print('(');
|
||||
for (var i = 0, iLen = args.length; i < iLen; ++i) {
|
||||
if (i != 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
args[i].accept(this);
|
||||
}
|
||||
writer.print(')');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
library angular2.transform.common.code.import_export_code;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
|
||||
|
||||
/// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s.
|
||||
class ImportVisitor extends SimpleAstVisitor<ImportModel> {
|
||||
@override
|
||||
ImportModel visitImportDirective(ImportDirective node) {
|
||||
if (node.isSynthetic) return null;
|
||||
|
||||
var model = new ImportModel()
|
||||
..uri = stringLiteralToString(node.uri)
|
||||
..isDeferred = node.deferredKeyword != null;
|
||||
if (node.prefix != null) {
|
||||
model.prefix = node.prefix.name;
|
||||
}
|
||||
_populateCombinators(node, model);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor responsible for parsing [ExportDirective]s into [ExportModel]s.
|
||||
class ExportVisitor extends SimpleAstVisitor<ExportModel> {
|
||||
@override
|
||||
ExportModel visitExportDirective(ExportDirective node) {
|
||||
if (node.isSynthetic) return null;
|
||||
|
||||
var model = new ExportModel()..uri = stringLiteralToString(node.uri);
|
||||
_populateCombinators(node, model);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses `combinators` in `node` and adds them to `model`, which should be
|
||||
/// either an [ImportModel] or an [ExportModel].
|
||||
void _populateCombinators(NamespaceDirective node, dynamic model) {
|
||||
if (node.combinators != null) {
|
||||
node.combinators.forEach((c) {
|
||||
if (c is ShowCombinator) {
|
||||
model.showCombinators.addAll(c.shownNames.map((id) => '$id'));
|
||||
} else if (c is HideCombinator) {
|
||||
model.hideCombinators.addAll(c.hiddenNames.map((id) => '$id'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which an [ImportModel] is expressed as Dart code in a
|
||||
/// `.ng_deps.dart` file.
|
||||
abstract class ImportWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void writeImportModel(ImportModel model) {
|
||||
buffer.write("import '${model.uri}'");
|
||||
if (model.isDeferred) {
|
||||
buffer.write(' deferred');
|
||||
}
|
||||
if (model.prefix != null && model.prefix.isNotEmpty) {
|
||||
buffer.write(' as ${model.prefix}');
|
||||
}
|
||||
_writeCombinators(buffer, model);
|
||||
buffer.writeln(';');
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which an [ExportModel] is expressed as Dart code in a
|
||||
/// `.ng_deps.dart` file.
|
||||
abstract class ExportWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void writeExportModel(ExportModel model) {
|
||||
buffer.write("export '${model.uri}'");
|
||||
_writeCombinators(buffer, model);
|
||||
buffer.writeln(';');
|
||||
}
|
||||
}
|
||||
|
||||
void _writeCombinators(StringBuffer buffer, dynamic model) {
|
||||
if (model.showCombinators != null && model.showCombinators.isNotEmpty) {
|
||||
buffer.write(' show ');
|
||||
for (var i = 0; i < model.showCombinators.length; ++i) {
|
||||
if (i != 0) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
buffer.write(model.showCombinators[i]);
|
||||
}
|
||||
}
|
||||
if (model.hideCombinators != null && model.hideCombinators.isNotEmpty) {
|
||||
buffer.write(' hide ');
|
||||
for (var i = 0; i < model.hideCombinators.length; ++i) {
|
||||
if (i != 0) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
buffer.write(model.hideCombinators[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
library angular2.transform.common.code.ng_deps_code;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart';
|
||||
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'annotation_code.dart';
|
||||
import 'import_export_code.dart';
|
||||
import 'reflection_info_code.dart';
|
||||
import 'parameter_code.dart';
|
||||
|
||||
/// Visitor responsible for parsing source Dart files (that is, not
|
||||
/// `.ng_deps.dart` files) into [NgDepsModel] objects.
|
||||
class NgDepsVisitor extends RecursiveAstVisitor<Object> {
|
||||
final AssetId processedFile;
|
||||
final ImportVisitor _importVisitor = new ImportVisitor();
|
||||
final ExportVisitor _exportVisitor = new ExportVisitor();
|
||||
final ReflectionInfoVisitor _reflectableVisitor;
|
||||
|
||||
bool _isPart = false;
|
||||
NgDepsModel _model = null;
|
||||
|
||||
NgDepsVisitor(AssetId processedFile, AnnotationMatcher annotationMatcher)
|
||||
: this.processedFile = processedFile,
|
||||
_reflectableVisitor =
|
||||
new ReflectionInfoVisitor(processedFile, annotationMatcher);
|
||||
|
||||
bool get isPart => _isPart;
|
||||
NgDepsModel get model {
|
||||
if (_model == null) {
|
||||
_createModel('');
|
||||
}
|
||||
return _model;
|
||||
}
|
||||
|
||||
void _createModel(String libraryUri) {
|
||||
_model = new NgDepsModel()..libraryUri = libraryUri;
|
||||
|
||||
// We need to import & export the original file.
|
||||
var origDartFile = path.basename(processedFile.path);
|
||||
_model.imports.add(new ImportModel()..uri = origDartFile);
|
||||
_model.exports.add(new ExportModel()..uri = origDartFile);
|
||||
|
||||
// Used to register reflective information.
|
||||
_model.imports.add(new ImportModel()
|
||||
..uri = REFLECTOR_IMPORT
|
||||
..prefix = REFLECTOR_PREFIX);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
var reflectableModel = _reflectableVisitor.visitClassDeclaration(node);
|
||||
if (reflectableModel != null) {
|
||||
model.reflectables.add(reflectableModel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitExportDirective(ExportDirective node) {
|
||||
var export = _exportVisitor.visitExportDirective(node);
|
||||
if (export != null) {
|
||||
model.exports.add(export);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitImportDirective(ImportDirective node) {
|
||||
var import = _importVisitor.visitImportDirective(node);
|
||||
if (import != null) {
|
||||
model.imports.add(import);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitLibraryDirective(LibraryDirective node) {
|
||||
if (node != null) {
|
||||
assert(_model == null);
|
||||
_createModel('${node.name}');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitPartDirective(PartDirective node) {
|
||||
model.partUris.add(stringLiteralToString(node.uri));
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitPartOfDirective(PartOfDirective node) {
|
||||
_isPart = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
var reflectableModel = _reflectableVisitor.visitFunctionDeclaration(node);
|
||||
if (reflectableModel != null) {
|
||||
model.reflectables.add(reflectableModel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which an [NgDepsModel] is expressed as Dart code
|
||||
/// in a `.ng_deps.dart` file.
|
||||
class NgDepsWriter extends Object
|
||||
with
|
||||
AnnotationWriterMixin,
|
||||
ExportWriterMixin,
|
||||
ImportWriterMixin,
|
||||
NgDepsWriterMixin,
|
||||
ParameterWriterMixin,
|
||||
ReflectionWriterMixin {
|
||||
final StringBuffer buffer;
|
||||
|
||||
NgDepsWriter([StringBuffer buffer])
|
||||
: this.buffer = buffer != null ? buffer : new StringBuffer();
|
||||
}
|
||||
|
||||
abstract class NgDepsWriterMixin
|
||||
implements
|
||||
AnnotationWriterMixin,
|
||||
ExportWriterMixin,
|
||||
ImportWriterMixin,
|
||||
ParameterWriterMixin,
|
||||
ReflectionWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void writeNgDepsModel(NgDepsModel model) {
|
||||
if (model.libraryUri.isNotEmpty) {
|
||||
buffer.writeln('library ${model.libraryUri}${DEPS_EXTENSION};\n');
|
||||
}
|
||||
|
||||
// We do not support `partUris`, so skip outputting them.
|
||||
model.imports.forEach((importModel) {
|
||||
// Ignore deferred imports here so as to not load the deferred libraries
|
||||
// code in the current library causing much of the code to not be
|
||||
// deferred. Instead `DeferredRewriter` will rewrite the code as to load
|
||||
// `ng_deps` in a deferred way.
|
||||
if (importModel.isDeferred) return;
|
||||
|
||||
writeImportModel(importModel);
|
||||
});
|
||||
model.exports.forEach(writeExportModel);
|
||||
|
||||
buffer
|
||||
..writeln('var _visited = false;')
|
||||
..writeln('void ${SETUP_METHOD_NAME}() {')
|
||||
..writeln('if (_visited) return; _visited = true;');
|
||||
|
||||
if (model.reflectables != null && model.reflectables.isNotEmpty) {
|
||||
buffer.writeln('$REFLECTOR_PREFIX.$REFLECTOR_VAR_NAME');
|
||||
model.reflectables.forEach(writeRegistration);
|
||||
buffer.writeln(';');
|
||||
}
|
||||
|
||||
buffer.writeln('}');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
library angular2.transform.common.code.parameter_code;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/model/parameter_model.pb.dart';
|
||||
|
||||
import 'constify.dart';
|
||||
|
||||
/// Visitor responsible for parsing [FormalParameter]s into
|
||||
/// [ParameterModel]s.
|
||||
class ParameterVisitor extends SimpleAstVisitor<ParameterModel> {
|
||||
/// Maps field names to their declared types. See `_populateFieldMap`
|
||||
final Map<String, TypeName> _fieldNameToType = {};
|
||||
final Set<AstNode> _seen = new Set();
|
||||
|
||||
void _populateFieldMap(AstNode node) {
|
||||
ClassDeclaration clazz =
|
||||
node.getAncestor((node) => node is ClassDeclaration);
|
||||
if (_seen.contains(clazz)) return;
|
||||
_seen.add(clazz);
|
||||
|
||||
clazz.members
|
||||
.where((member) => member is FieldDeclaration)
|
||||
.forEach((FieldDeclaration field) {
|
||||
var type = field.fields.type;
|
||||
if (type != null) {
|
||||
field.fields.variables.forEach((VariableDeclaration decl) {
|
||||
var key = '${decl.name}';
|
||||
if (_fieldNameToType.containsKey(key)) {
|
||||
// Need to clear our `seen` list as the type for a var name has
|
||||
// changed and could be incorrect.
|
||||
_seen.clear();
|
||||
}
|
||||
_fieldNameToType[key] = type;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ParameterModel _visitNormalFormalParameter(
|
||||
NodeList<Annotation> metadata, TypeName type, SimpleIdentifier name) {
|
||||
var model = new ParameterModel();
|
||||
if (name != null && name.name != null && name.name.isNotEmpty) {
|
||||
model.paramName = '$name';
|
||||
}
|
||||
if (type != null) {
|
||||
var sTypeName = '${type.name}';
|
||||
if (sTypeName.isNotEmpty) {
|
||||
model.typeName = sTypeName;
|
||||
}
|
||||
if (type.typeArguments != null) {
|
||||
model.typeArgs = '${type.typeArguments}';
|
||||
}
|
||||
}
|
||||
if (metadata != null) {
|
||||
model.metadata.addAll(metadata.map(constify));
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@override
|
||||
ParameterModel visitSimpleFormalParameter(SimpleFormalParameter node) {
|
||||
return _visitNormalFormalParameter(
|
||||
node.metadata, node.type, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
ParameterModel visitFieldFormalParameter(FieldFormalParameter node) {
|
||||
if (node.parameters != null) {
|
||||
logger.error('Parameters in ctor not supported '
|
||||
'(${node.toSource()})');
|
||||
}
|
||||
var type = node.type;
|
||||
if (type == null) {
|
||||
_populateFieldMap(node);
|
||||
type = _fieldNameToType[node.identifier.toString()];
|
||||
}
|
||||
return _visitNormalFormalParameter(node.metadata, type, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
ParameterModel visitFunctionTypedFormalParameter(
|
||||
FunctionTypedFormalParameter node) {
|
||||
logger.error('Function typed formal parameters not supported '
|
||||
'(${node.toSource()})');
|
||||
return _visitNormalFormalParameter(node.metadata, null, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
ParameterModel visitDefaultFormalParameter(DefaultFormalParameter node) {
|
||||
// Ignore the declared default value.
|
||||
return node.parameter != null ? node.parameter.accept(this) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which a [ParameterModel] is expressed as Dart code
|
||||
/// in a `.ng_deps.dart` file.
|
||||
abstract class ParameterWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void writeParameterModelForList(ParameterModel model) {
|
||||
buffer.write('const [');
|
||||
var first = true;
|
||||
if (model.typeName != null && model.typeName.isNotEmpty) {
|
||||
if (!first) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
first = false;
|
||||
buffer.write('${model.typeName}');
|
||||
}
|
||||
for (var meta in model.metadata) {
|
||||
if (!first) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
first = false;
|
||||
buffer.write('$meta');
|
||||
}
|
||||
buffer.write(']');
|
||||
}
|
||||
|
||||
void writeParameterModelForDeclaration(ParameterModel model) {
|
||||
if (model.typeName != null && model.typeName.isNotEmpty) {
|
||||
buffer.write(model.typeName);
|
||||
if (model.typeArgs != null && model.typeArgs.isNotEmpty) {
|
||||
buffer.write(model.typeArgs);
|
||||
}
|
||||
buffer.write(' ');
|
||||
}
|
||||
if (model.paramName != null && model.paramName.isNotEmpty) {
|
||||
buffer.write(model.paramName);
|
||||
}
|
||||
}
|
||||
|
||||
void writeParameterModelForImpl(ParameterModel model) {
|
||||
buffer.write(model.paramName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
library angular2.transform.common.code.reflection_info_code;
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
|
||||
import 'annotation_code.dart';
|
||||
import 'parameter_code.dart';
|
||||
|
||||
/// Visitor responsible for parsing [ClassDeclaration]s into
|
||||
/// [ReflectionInfoModel]s.
|
||||
class ReflectionInfoVisitor extends RecursiveAstVisitor<ReflectionInfoModel> {
|
||||
/// The file we are processing.
|
||||
final AssetId assetId;
|
||||
|
||||
final AnnotationVisitor _annotationVisitor;
|
||||
final ParameterVisitor _parameterVisitor = new ParameterVisitor();
|
||||
|
||||
/// Whether an Angular 2 `Reflection` has been found.
|
||||
bool _foundNgReflection = false;
|
||||
|
||||
/// Responsible for testing whether [Annotation]s are those recognized by
|
||||
/// Angular 2, for example `@Component`.
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
|
||||
ReflectionInfoVisitor(AssetId assetId, AnnotationMatcher annotationMatcher)
|
||||
: this.assetId = assetId,
|
||||
_annotationMatcher = annotationMatcher,
|
||||
_annotationVisitor = new AnnotationVisitor(assetId, annotationMatcher);
|
||||
|
||||
bool get shouldCreateNgDeps => _foundNgReflection;
|
||||
|
||||
ConstructorDeclaration _getCtor(ClassDeclaration node) {
|
||||
int numCtorsFound = 0;
|
||||
var ctor = null;
|
||||
|
||||
for (ClassMember classMember in node.members) {
|
||||
if (classMember is ConstructorDeclaration) {
|
||||
numCtorsFound++;
|
||||
ConstructorDeclaration constructor = classMember;
|
||||
|
||||
// Use the unnnamed constructor if it is present.
|
||||
// Otherwise, use the first encountered.
|
||||
if (ctor == null) {
|
||||
ctor = constructor;
|
||||
} else if (constructor.name == null) {
|
||||
ctor = constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numCtorsFound > 1) {
|
||||
var ctorName = ctor.name;
|
||||
if (ctorName != null) {
|
||||
logger.warning('Found ${numCtorsFound} ctors for class ${node.name},'
|
||||
'Using constructor ${ctorName}.');
|
||||
}
|
||||
}
|
||||
return ctor;
|
||||
}
|
||||
|
||||
@override
|
||||
ReflectionInfoModel visitClassDeclaration(ClassDeclaration node) {
|
||||
if (!node.metadata
|
||||
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ctor = _getCtor(node);
|
||||
var model = new ReflectionInfoModel()..name = '${node.name}';
|
||||
if (ctor != null && ctor.name != null) {
|
||||
model.ctorName = '${ctor.name}';
|
||||
}
|
||||
|
||||
if (node.metadata != null) {
|
||||
node.metadata.forEach((node) {
|
||||
model.annotations.add(_annotationVisitor.visitAnnotation(node));
|
||||
});
|
||||
}
|
||||
if (ctor != null &&
|
||||
ctor.parameters != null &&
|
||||
ctor.parameters.parameters != null) {
|
||||
ctor.parameters.parameters.forEach((node) {
|
||||
model.parameters.add(node.accept(_parameterVisitor));
|
||||
});
|
||||
}
|
||||
if (node.implementsClause != null &&
|
||||
node.implementsClause.interfaces != null &&
|
||||
node.implementsClause.interfaces.isNotEmpty) {
|
||||
model.interfaces.addAll(node.implementsClause.interfaces
|
||||
.map((interface) => '${interface.name}'));
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@override
|
||||
ReflectionInfoModel visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
if (!node.metadata
|
||||
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var model = new ReflectionInfoModel()
|
||||
..name = '${node.name}'
|
||||
..isFunction = true;
|
||||
if (node.metadata != null) {
|
||||
node.metadata.forEach((node) {
|
||||
var annotation = _annotationVisitor.visitAnnotation(node);
|
||||
if (annotation != null) {
|
||||
model.annotations.add(annotation);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (node.functionExpression.parameters != null &&
|
||||
node.functionExpression.parameters.parameters != null) {
|
||||
node.functionExpression.parameters.parameters.forEach((node) {
|
||||
var param = node.accept(_parameterVisitor);
|
||||
if (param != null) {
|
||||
model.parameters.add(param);
|
||||
}
|
||||
});
|
||||
}
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the format in which an [ReflectionInfoModel] is expressed as Dart
|
||||
/// code in a `.ng_deps.dart` file.
|
||||
abstract class ReflectionWriterMixin
|
||||
implements AnnotationWriterMixin, ParameterWriterMixin {
|
||||
StringBuffer get buffer;
|
||||
|
||||
void _writeListWithSeparator(List l, Function writeFn,
|
||||
{String prefix, String suffix, String separator: ', '}) {
|
||||
buffer.write(prefix);
|
||||
for (var i = 0, iLen = l.length; i < iLen; ++i) {
|
||||
if (i != 0) {
|
||||
buffer.write(', ');
|
||||
}
|
||||
writeFn(l[i]);
|
||||
}
|
||||
buffer.write(suffix);
|
||||
}
|
||||
|
||||
void writeRegistration(ReflectionInfoModel model) {
|
||||
buffer.write('..register');
|
||||
if (model.isFunction) {
|
||||
buffer.write('Function');
|
||||
} else {
|
||||
buffer.write('Type');
|
||||
}
|
||||
buffer.writeln('(${model.name}, new $REFLECTOR_PREFIX.ReflectionInfo(');
|
||||
|
||||
// Annotations
|
||||
_writeListWithSeparator(model.annotations, writeAnnotationModel,
|
||||
prefix: 'const [', suffix: ']');
|
||||
// Parameters
|
||||
_writeListWithSeparator(model.parameters, writeParameterModelForList,
|
||||
prefix: ',\nconst [', suffix: ']');
|
||||
if (!model.isFunction) {
|
||||
// Factory
|
||||
_writeListWithSeparator(
|
||||
model.parameters, writeParameterModelForDeclaration,
|
||||
prefix: ',\n(', suffix: ')');
|
||||
buffer.write(' => new ${model.name}');
|
||||
if (model.ctorName != null && model.ctorName.isNotEmpty) {
|
||||
buffer.write('.${model.ctorName}');
|
||||
}
|
||||
_writeListWithSeparator(model.parameters, writeParameterModelForImpl,
|
||||
prefix: '(', suffix: ')');
|
||||
// Interfaces
|
||||
if (model.interfaces != null && model.interfaces.isNotEmpty) {
|
||||
_writeListWithSeparator(model.interfaces, buffer.write,
|
||||
prefix: ',\nconst [', suffix: ']');
|
||||
}
|
||||
}
|
||||
buffer.writeln(')\n)');
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ const META_EXTENSION = '.ng_meta.json';
|
|||
// upfront (rather than extracting it from ng_deps).
|
||||
const ALIAS_EXTENSION = '.aliases.json';
|
||||
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
|
||||
const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart';
|
||||
const REFLECTOR_PREFIX = '_ngRef';
|
||||
const REGISTER_TYPE_METHOD_NAME = 'registerType';
|
||||
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
|
||||
const REGISTER_SETTERS_METHOD_NAME = 'registerSetters';
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
library angular2.transform.directive_processor.inliner;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/error.dart';
|
||||
import 'package:analyzer/src/generated/parser.dart';
|
||||
import 'package:analyzer/src/generated/scanner.dart';
|
||||
import 'package:analyzer/src/string_source.dart';
|
||||
import 'package:angular2/src/core/render/xhr.dart' show XHR;
|
||||
import 'package:angular2/src/transform/common/async_string_writer.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/ng_deps_model.pb.dart';
|
||||
|
||||
Future inlineViewProps(XHR xhr, NgDepsModel model) {
|
||||
var toWait = <Future>[];
|
||||
for (var reflectable in model.reflectables) {
|
||||
for (var annotation in reflectable.annotations) {
|
||||
if (annotation.isView) {
|
||||
var rawTemplateUrl = _getTemplateUrlValue(annotation);
|
||||
if (rawTemplateUrl != null) {
|
||||
if (_hasTemplateValue(annotation)) {
|
||||
logger.warning('Both template url and template are specified. '
|
||||
'Ignoring `templateUrl` value.');
|
||||
} else {
|
||||
var url = _dumbEval(rawTemplateUrl);
|
||||
if (url is String) {
|
||||
toWait.add(_readOrEmptyString(xhr, url).then((templateText) {
|
||||
_setTemplateValue(annotation, "r'''$templateText'''");
|
||||
}));
|
||||
} else {
|
||||
logger.warning('template url is not a String ($rawTemplateUrl)');
|
||||
}
|
||||
}
|
||||
}
|
||||
var rawStyleUrls = _getStyleUrlsValue(annotation);
|
||||
if (rawStyleUrls != null) {
|
||||
if (_hasStylesValue(annotation)) {
|
||||
logger.warning('Both styleUrls and styles are specified. '
|
||||
'Ignoring `styleUrls` value.');
|
||||
} else {
|
||||
var urls = _dumbEval(rawStyleUrls);
|
||||
if (urls is List) {
|
||||
var writer = new AsyncStringWriter();
|
||||
for (var url in urls) {
|
||||
if (url is String) {
|
||||
writer.print("r'''");
|
||||
writer.asyncPrint(_readOrEmptyString(xhr, url));
|
||||
writer.print("''', ");
|
||||
} else {
|
||||
logger.warning('style url is not a String (${url})');
|
||||
}
|
||||
}
|
||||
toWait.add(writer.asyncToString().then((styleUrlText) {
|
||||
_setStylesValue(annotation, 'const [$styleUrlText]');
|
||||
_removeStyleUrlsValue(annotation);
|
||||
}));
|
||||
} else {
|
||||
logger.warning(
|
||||
'styleUrls is not a List of strings ($rawStyleUrls)');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Future.wait(toWait);
|
||||
}
|
||||
|
||||
String _getNamedArgValue(AnnotationModel model, String argName) {
|
||||
var value = null;
|
||||
if (model.namedParameters != null) {
|
||||
var match = model.namedParameters
|
||||
.firstWhere((p) => p.name == argName, orElse: () => null);
|
||||
value = match != null ? match.value : null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String _getTemplateUrlValue(AnnotationModel model) =>
|
||||
_getNamedArgValue(model, 'templateUrl');
|
||||
String _getStyleUrlsValue(AnnotationModel model) =>
|
||||
_getNamedArgValue(model, 'styleUrls');
|
||||
|
||||
bool _hasTemplateValue(AnnotationModel model) =>
|
||||
_getNamedArgValue(model, 'template') != null;
|
||||
bool _hasStylesValue(AnnotationModel model) =>
|
||||
_getNamedArgValue(model, 'styles') != null;
|
||||
|
||||
void _setNamedArgValue(AnnotationModel model, String argName, String argValue) {
|
||||
var matchedArg = model.namedParameters
|
||||
.firstWhere((p) => p.name == argName, orElse: () => null);
|
||||
if (matchedArg == null) {
|
||||
matchedArg = new NamedParameter()..name = argName;
|
||||
model.namedParameters.add(matchedArg);
|
||||
}
|
||||
matchedArg.value = argValue;
|
||||
}
|
||||
|
||||
void _setTemplateValue(AnnotationModel model, String template) =>
|
||||
_setNamedArgValue(model, 'template', template);
|
||||
void _setStylesValue(AnnotationModel model, String styles) =>
|
||||
_setNamedArgValue(model, 'styles', styles);
|
||||
|
||||
void _removeNamedArg(AnnotationModel model, String argName) {
|
||||
model.namedParameters.removeWhere((p) => p.name == argName);
|
||||
}
|
||||
|
||||
void _removeStyleUrlsValue(AnnotationModel model) =>
|
||||
_removeNamedArg(model, 'styleUrls');
|
||||
|
||||
final _constantEvaluator = new ConstantEvaluator();
|
||||
|
||||
/// Attempts to read the content from {@link url}, if it returns null then
|
||||
/// just return the empty string.
|
||||
Future<String> _readOrEmptyString(XHR xhr, String url) async {
|
||||
var content = await xhr.get(url);
|
||||
if (content == null) {
|
||||
content = '';
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
dynamic _dumbEval(String code) {
|
||||
var source = new StringSource(code, code);
|
||||
// TODO(kegluneq): Report errors.
|
||||
var errorCollector = AnalysisErrorListener.NULL_LISTENER;
|
||||
|
||||
var reader = new CharSequenceReader(code);
|
||||
var scanner = new Scanner(source, reader, errorCollector);
|
||||
var parser = new Parser(source, errorCollector)
|
||||
..currentToken = scanner.tokenize();
|
||||
var expr = parser.parseExpression2();
|
||||
var val = null;
|
||||
if (expr is SimpleStringLiteral) {
|
||||
val = stringLiteralToString(expr);
|
||||
} else {
|
||||
val = expr.accept(_constantEvaluator);
|
||||
}
|
||||
return val != ConstantEvaluator.NOT_A_CONSTANT ? val : null;
|
||||
}
|
|
@ -3,13 +3,11 @@ library angular2.transform.directive_processor.rewriter;
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:angular2/src/core/render/xhr.dart' show XHR;
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
import 'package:angular2/src/transform/common/async_string_writer.dart';
|
||||
import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/names.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;
|
||||
|
@ -17,7 +15,7 @@ import 'package:code_transformers/assets.dart';
|
|||
import 'package:path/path.dart' as path;
|
||||
import 'package:source_span/source_span.dart';
|
||||
|
||||
import 'visitors.dart';
|
||||
import 'inliner.dart';
|
||||
|
||||
/// Generates a file registering all Angular 2 `Directive`s found in `code` in
|
||||
/// ngDeps format [TODO(kegluneq): documentation reference needed]. `assetId` is
|
||||
|
@ -42,31 +40,34 @@ Future<String> createNgDeps(AssetReader reader, AssetId assetId,
|
|||
// parent, so it does not need its own `.ng_deps.dart` file.
|
||||
if (directivesVisitor.isPart) return null;
|
||||
|
||||
var writer = new AsyncStringWriter();
|
||||
directivesVisitor.writeTo(writer, assetId);
|
||||
|
||||
writer
|
||||
..println('var _visited = false;')
|
||||
..println('void ${SETUP_METHOD_NAME}() {')
|
||||
..println('if (_visited) return; _visited = true;');
|
||||
|
||||
var declarationsCode =
|
||||
var codeWithParts =
|
||||
await _getAllDeclarations(reader, assetId, code, directivesVisitor);
|
||||
var declarationsVisitor = new _NgDepsDeclarationsVisitor(
|
||||
assetId, writer, new XhrImpl(reader, assetId), annotationMatcher, ngMeta,
|
||||
inlineViews: inlineViews);
|
||||
parseCompilationUnit(declarationsCode, name: '${assetId.path} and parts')
|
||||
.declarations
|
||||
.accept(declarationsVisitor);
|
||||
if (declarationsVisitor.shouldCreateNgDeps) {
|
||||
writer.println(';');
|
||||
var parsedCode =
|
||||
parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts');
|
||||
|
||||
var ngDepsVisitor = new NgDepsVisitor(assetId, annotationMatcher);
|
||||
// TODO(kegluneq): Parse `declarations` in the NgDepsModel as well.
|
||||
parsedCode.accept(ngDepsVisitor);
|
||||
var ngDepsModel = ngDepsVisitor.model;
|
||||
|
||||
// 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.
|
||||
if (!directivesVisitor.usesNonLangLibs &&
|
||||
(ngDepsModel.reflectables == null || ngDepsModel.reflectables.isEmpty)) {
|
||||
return null;
|
||||
}
|
||||
writer.println('}');
|
||||
|
||||
if (!directivesVisitor.shouldCreateNgDeps &&
|
||||
!declarationsVisitor.shouldCreateNgDeps) return null;
|
||||
var ngMetaVisitor = new _NgMetaVisitor(ngMeta);
|
||||
parsedCode.accept(ngMetaVisitor);
|
||||
|
||||
return writer.asyncToString();
|
||||
if (inlineViews) {
|
||||
await inlineViewProps(new XhrImpl(reader, assetId), ngDepsModel);
|
||||
}
|
||||
|
||||
var buffer = new StringBuffer();
|
||||
var ngDepsWriter = new NgDepsWriter(buffer);
|
||||
ngDepsWriter.writeNgDepsModel(ngDepsModel);
|
||||
return '$buffer';
|
||||
}
|
||||
|
||||
/// Processes `visitor.parts`, reading and appending their contents to the
|
||||
|
@ -78,8 +79,8 @@ Future<String> createNgDeps(AssetReader reader, AssetId assetId,
|
|||
/// part 'lib1.dart'
|
||||
/// part 'lib2.dart'
|
||||
/// ```
|
||||
/// The output will first have the entirety of the original file, followed by
|
||||
/// the contents of lib1.dart followed by the contents of lib2.dart.
|
||||
/// The output will first have the contents of lib1 followed by the contents of
|
||||
/// lib2.dart, followed by the original code in the library.
|
||||
Future<String> _getAllDeclarations(AssetReader reader, AssetId assetId,
|
||||
String code, _NgDepsDirectivesVisitor visitor) {
|
||||
if (visitor.parts.isEmpty) return new Future<String>.value(code);
|
||||
|
@ -127,241 +128,50 @@ class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
/// visited a `part of` directive.
|
||||
bool _isPart = false;
|
||||
|
||||
// TODO(kegluneq): Support an intermediate representation of NgDeps and use it
|
||||
// instead of storing generated code.
|
||||
LibraryDirective _library = null;
|
||||
ScriptTag _scriptTag = null;
|
||||
final List<NamespaceDirective> _importAndExports = <NamespaceDirective>[];
|
||||
final List<PartDirective> _parts = <PartDirective>[];
|
||||
|
||||
bool get shouldCreateNgDeps {
|
||||
// If this library does not define an `@Injectable` and it does not import
|
||||
// any libaries that could, then we do not need to generate a `.ng_deps
|
||||
// .dart` file for it.
|
||||
if (!_usesNonLangLibs) return false;
|
||||
if (_isPart) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get usesNonLangLibs => _usesNonLangLibs;
|
||||
bool get isPart => _isPart;
|
||||
|
||||
/// In the order encountered in the source.
|
||||
Iterable<PartDirective> get parts => _parts;
|
||||
|
||||
@override
|
||||
Object visitScriptTag(ScriptTag node) {
|
||||
_scriptTag = node;
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitCompilationUnit(CompilationUnit node) {
|
||||
node.directives.accept(this);
|
||||
return null;
|
||||
}
|
||||
|
||||
void _updateUsesNonLangLibs(UriBasedDirective directive) {
|
||||
Object _updateUsesNonLangLibs(UriBasedDirective directive) {
|
||||
_usesNonLangLibs = _usesNonLangLibs ||
|
||||
!stringLiteralToString(directive.uri).startsWith('dart:');
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitImportDirective(ImportDirective node) {
|
||||
_updateUsesNonLangLibs(node);
|
||||
_importAndExports.add(node);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitExportDirective(ExportDirective node) {
|
||||
_updateUsesNonLangLibs(node);
|
||||
_importAndExports.add(node);
|
||||
return null;
|
||||
}
|
||||
Object visitExportDirective(ExportDirective node) =>
|
||||
_updateUsesNonLangLibs(node);
|
||||
|
||||
@override
|
||||
Object visitLibraryDirective(LibraryDirective node) {
|
||||
if (node != null) {
|
||||
_library = node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Object visitImportDirective(ImportDirective node) =>
|
||||
_updateUsesNonLangLibs(node);
|
||||
|
||||
@override
|
||||
Object visitPartDirective(PartDirective node) {
|
||||
_parts.add(node);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitPartOfDirective(PartOfDirective node) {
|
||||
_isPart = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Write the directives for the .ng_deps.dart for `processedFile` to
|
||||
/// `writer`. The .ng_deps.dart file has the same directives as
|
||||
/// `processedFile` with some exceptions (mentioned below).
|
||||
void writeTo(PrintWriter writer, AssetId processedFile) {
|
||||
var copyVisitor = new ToSourceVisitor(writer);
|
||||
|
||||
if (_scriptTag != null) {
|
||||
_scriptTag.accept(copyVisitor);
|
||||
writer.newLine();
|
||||
}
|
||||
|
||||
if (_library != null && _library.name != null) {
|
||||
writer.print('library ');
|
||||
_library.name.accept(copyVisitor);
|
||||
writer.println('$DEPS_EXTENSION;');
|
||||
}
|
||||
|
||||
// We do not output [PartDirective]s, which would not be valid now that we
|
||||
// have changed the library.
|
||||
|
||||
// We need to import & export the original file.
|
||||
var origDartFile = path.basename(processedFile.path);
|
||||
writer.println('''import '$origDartFile';''');
|
||||
writer.println('''export '$origDartFile';''');
|
||||
|
||||
// Used to register reflective information.
|
||||
writer.println("import '$_REFLECTOR_IMPORT' as $_REF_PREFIX;");
|
||||
|
||||
_importAndExports.forEach((node) {
|
||||
if (node.isSynthetic) return;
|
||||
|
||||
// Ignore deferred imports here so as to not load the deferred libraries
|
||||
// code in the current library causing much of the code to not be
|
||||
// deferred. Instead `DeferredRewriter` will rewrite the code as to load
|
||||
// `ng_deps` in a deferred way.
|
||||
if (node is ImportDirective && node.deferredKeyword != null) return;
|
||||
|
||||
node.accept(copyVisitor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor responsible for visiting a file's [Declaration]s and outputting the
|
||||
/// code necessary to register the file with the Angular 2 system.
|
||||
class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
final AsyncStringWriter writer;
|
||||
|
||||
/// The file we are processing.
|
||||
final AssetId assetId;
|
||||
|
||||
class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
/// 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.
|
||||
bool _foundNgInjectable = false;
|
||||
|
||||
/// Visitor that writes out code for AstNodes visited.
|
||||
final ToSourceVisitor _copyVisitor;
|
||||
final FactoryTransformVisitor _factoryVisitor;
|
||||
final ParameterTransformVisitor _paramsVisitor;
|
||||
final AnnotationsTransformVisitor _metaVisitor;
|
||||
|
||||
/// Responsible for testing whether [Annotation]s are those recognized by
|
||||
/// Angular 2, for example `@Component`.
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
|
||||
/// Used to fetch linked files.
|
||||
final XHR _xhr;
|
||||
|
||||
_NgDepsDeclarationsVisitor(AssetId assetId, AsyncStringWriter writer, XHR xhr,
|
||||
AnnotationMatcher annotationMatcher, this.ngMeta,
|
||||
{bool inlineViews})
|
||||
: writer = writer,
|
||||
_copyVisitor = new ToSourceVisitor(writer),
|
||||
_factoryVisitor = new FactoryTransformVisitor(writer),
|
||||
_paramsVisitor = new ParameterTransformVisitor(writer),
|
||||
_metaVisitor = new AnnotationsTransformVisitor(
|
||||
writer, xhr, annotationMatcher, assetId,
|
||||
inlineViews: inlineViews),
|
||||
_annotationMatcher = annotationMatcher,
|
||||
this.assetId = assetId,
|
||||
_xhr = xhr;
|
||||
|
||||
bool get shouldCreateNgDeps => _foundNgInjectable;
|
||||
|
||||
ConstructorDeclaration _getCtor(ClassDeclaration node) {
|
||||
int numCtorsFound = 0;
|
||||
var ctor = null;
|
||||
|
||||
for (ClassMember classMember in node.members) {
|
||||
if (classMember is ConstructorDeclaration) {
|
||||
numCtorsFound++;
|
||||
ConstructorDeclaration constructor = classMember;
|
||||
|
||||
// Use the unnnamed constructor if it is present.
|
||||
// Otherwise, use the first encountered.
|
||||
if (ctor == null) {
|
||||
ctor = constructor;
|
||||
} else if (constructor.name == null) {
|
||||
ctor = constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numCtorsFound > 1) {
|
||||
var ctorName = ctor.name;
|
||||
ctorName = ctorName == null
|
||||
? 'the unnamed constructor'
|
||||
: 'constructor "${ctorName}"';
|
||||
logger.warning('Found ${numCtorsFound} ctors for class ${node.name},'
|
||||
'Using ${ctorName}.');
|
||||
}
|
||||
return ctor;
|
||||
}
|
||||
|
||||
void _generateEmptyFactory(String typeName) {
|
||||
writer.print('() => new ${typeName}()');
|
||||
}
|
||||
|
||||
void _generateEmptyParams() => writer.print('const []');
|
||||
_NgMetaVisitor(this.ngMeta);
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
if (!node.metadata
|
||||
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ctor = _getCtor(node);
|
||||
|
||||
_maybeWriteReflector();
|
||||
writer.print('..registerType(');
|
||||
node.name.accept(this);
|
||||
writer.print(', new ${_REF_PREFIX}.ReflectionInfo(');
|
||||
node.accept(_metaVisitor);
|
||||
writer.print(', ');
|
||||
if (ctor == null) {
|
||||
_generateEmptyParams();
|
||||
} else {
|
||||
ctor.accept(_paramsVisitor);
|
||||
}
|
||||
writer.print(', ');
|
||||
if (ctor == null) {
|
||||
_generateEmptyFactory(node.name.toString());
|
||||
} else {
|
||||
ctor.accept(_factoryVisitor);
|
||||
}
|
||||
if (node.implementsClause != null &&
|
||||
node.implementsClause.interfaces != null &&
|
||||
node.implementsClause.interfaces.isNotEmpty) {
|
||||
writer
|
||||
..print(', const [')
|
||||
..print(node.implementsClause.interfaces
|
||||
.map((interface) => interface.name)
|
||||
.join(', '))
|
||||
..print(']');
|
||||
}
|
||||
writer.print('))');
|
||||
return null;
|
||||
Object visitCompilationUnit(CompilationUnit node) {
|
||||
if (node == null || node.declarations == null) return null;
|
||||
return node.declarations.accept(this);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -386,47 +196,4 @@ class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Object _nodeToSource(AstNode node) {
|
||||
if (node == null) return null;
|
||||
return node.accept(_copyVisitor);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitPrefixedIdentifier(PrefixedIdentifier node) =>
|
||||
_nodeToSource(node);
|
||||
|
||||
@override
|
||||
Object visitSimpleIdentifier(SimpleIdentifier node) => _nodeToSource(node);
|
||||
|
||||
@override
|
||||
bool visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
if (!node.metadata
|
||||
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_maybeWriteReflector();
|
||||
writer.print('..registerFunction(');
|
||||
node.name.accept(this);
|
||||
writer.print(', new ${_REF_PREFIX}.ReflectionInfo(const [');
|
||||
node.metadata.accept(_metaVisitor);
|
||||
writer.print('], const [');
|
||||
node.functionExpression.parameters.accept(_paramsVisitor);
|
||||
writer.print(']))');
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Writes out the reflector variable the first time it is called.
|
||||
void _maybeWriteReflector() {
|
||||
if (_foundNgInjectable) return;
|
||||
_foundNgInjectable = true;
|
||||
|
||||
// The receiver for cascaded calls.
|
||||
writer.print('$_REF_PREFIX.$REFLECTOR_VAR_NAME');
|
||||
}
|
||||
}
|
||||
|
||||
const _REF_PREFIX = '_ngRef';
|
||||
const _REFLECTOR_IMPORT =
|
||||
'package:angular2/src/core/reflection/reflection.dart';
|
||||
|
|
|
@ -1,341 +0,0 @@
|
|||
library angular2.transform.directive_processor.visitors;
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:angular2/src/core/render/xhr.dart' show XHR;
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/async_string_writer.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:barback/barback.dart';
|
||||
|
||||
/// `ToSourceVisitor` designed to accept {@link ConstructorDeclaration} nodes.
|
||||
class _CtorTransformVisitor extends ToSourceVisitor {
|
||||
bool _withParameterAnnotations = true;
|
||||
bool _withParameterTypes = true;
|
||||
bool _withParameterNames = true;
|
||||
final PrintWriter writer;
|
||||
|
||||
/// Maps field names to their declared types. This is populated whenever
|
||||
/// the listener visits a {@link ConstructorDeclaration} node.
|
||||
final Map<String, TypeName> _fieldNameToType = {};
|
||||
|
||||
_CtorTransformVisitor(PrintWriter writer)
|
||||
: this.writer = writer,
|
||||
super(writer);
|
||||
|
||||
void _visitNodeWithPrefix(String prefix, AstNode node) {
|
||||
if (node != null) {
|
||||
writer.print(prefix);
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void _visitNodeWithSuffix(AstNode node, String suffix) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
writer.print(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
void _visitNode(AstNode node) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// If `_withParameterTypes` is true, this method outputs `node`'s type. If
|
||||
/// `_withParameterNames` is true, this method outputs `node`'s identifier.
|
||||
Object _visitNormalFormalParameter(
|
||||
NodeList<Annotation> metadata, TypeName type, SimpleIdentifier name) {
|
||||
var needCompileTimeConstants = !_withParameterNames;
|
||||
var needType = _withParameterTypes && type != null;
|
||||
if (needType) {
|
||||
_visitNodeWithSuffix(type.name, ' ');
|
||||
if (!needCompileTimeConstants) {
|
||||
// Types with arguments are not compile-time constants.
|
||||
_visitNodeWithSuffix(type.typeArguments, ' ');
|
||||
}
|
||||
}
|
||||
if (_withParameterNames) {
|
||||
_visitNode(name);
|
||||
}
|
||||
if (_withParameterAnnotations && metadata != null) {
|
||||
assert(_withParameterTypes);
|
||||
for (var i = 0, iLen = metadata.length; i < iLen; ++i) {
|
||||
if (i != 0 || needType) {
|
||||
writer.print(', ');
|
||||
}
|
||||
metadata[i].accept(this);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _buildFieldMap(ConstructorDeclaration node) {
|
||||
ClassDeclaration clazz =
|
||||
node.getAncestor((node) => node is ClassDeclaration);
|
||||
_fieldNameToType.clear();
|
||||
clazz.members
|
||||
.where((member) => member is FieldDeclaration)
|
||||
.forEach((FieldDeclaration field) {
|
||||
var type = field.fields.type;
|
||||
if (type != null) {
|
||||
field.fields.variables.forEach((VariableDeclaration decl) {
|
||||
_fieldNameToType[decl.name.toString()] = type;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitSimpleFormalParameter(SimpleFormalParameter node) {
|
||||
return _visitNormalFormalParameter(
|
||||
node.metadata, node.type, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFieldFormalParameter(FieldFormalParameter node) {
|
||||
if (node.parameters != null) {
|
||||
logger.error('Parameters in ctor not supported '
|
||||
'(${node.toSource()})');
|
||||
}
|
||||
var type = node.type;
|
||||
if (type == null) {
|
||||
type = _fieldNameToType[node.identifier.toString()];
|
||||
}
|
||||
return _visitNormalFormalParameter(node.metadata, type, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
|
||||
logger.error('Function typed formal parameters not supported '
|
||||
'(${node.toSource()})');
|
||||
return _visitNormalFormalParameter(node.metadata, null, node.identifier);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
|
||||
_visitNode(node.parameter);
|
||||
// Ignore the declared default value.
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
/// Overridden to avoid outputting grouping operators for default parameters.
|
||||
Object visitFormalParameterList(FormalParameterList node) {
|
||||
writer.print('(');
|
||||
NodeList<FormalParameter> parameters = node.parameters;
|
||||
int size = parameters.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
parameters[i].accept(this);
|
||||
}
|
||||
writer.print(')');
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
var prefix =
|
||||
node.arguments != null && node.arguments.length > 0 ? 'const ' : '';
|
||||
_visitNodeWithPrefix(prefix, node.name);
|
||||
_visitNodeWithPrefix(".", node.constructorName);
|
||||
_visitNode(node.arguments);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print 'parameters' values for Angular2's
|
||||
/// `registerType` calls.
|
||||
class ParameterTransformVisitor extends _CtorTransformVisitor {
|
||||
ParameterTransformVisitor(PrintWriter writer) : super(writer) {
|
||||
_withParameterNames = false;
|
||||
_withParameterTypes = true;
|
||||
_withParameterAnnotations = true;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
_buildFieldMap(node);
|
||||
writer.print('const [');
|
||||
_visitNode(node.parameters);
|
||||
writer.print(']');
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFormalParameterList(FormalParameterList node) {
|
||||
NodeList<FormalParameter> parameters = node.parameters;
|
||||
for (int i = 0, iLen = parameters.length; i < iLen; i++) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
// TODO(kegluneq): Include annotations on parameters.
|
||||
writer.print('const [');
|
||||
parameters[i].accept(this);
|
||||
writer.print(']');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print 'factory' values for Angular2's
|
||||
/// `registerType` calls.
|
||||
class FactoryTransformVisitor extends _CtorTransformVisitor {
|
||||
FactoryTransformVisitor(PrintWriter writer) : super(writer) {
|
||||
_withParameterAnnotations = false;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitConstructorDeclaration(ConstructorDeclaration node) {
|
||||
_buildFieldMap(node);
|
||||
_withParameterNames = true;
|
||||
_withParameterTypes = true;
|
||||
_visitNode(node.parameters);
|
||||
writer.print(' => new ');
|
||||
_visitNode(node.returnType);
|
||||
_visitNodeWithPrefix(".", node.name);
|
||||
|
||||
_withParameterTypes = false;
|
||||
_visitNode(node.parameters);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ToSourceVisitor designed to print a `ClassDeclaration` node as a
|
||||
/// 'annotations' value for Angular2's `registerType` calls.
|
||||
class AnnotationsTransformVisitor extends ToSourceVisitor {
|
||||
final AsyncStringWriter writer;
|
||||
final XHR _xhr;
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
final AssetId _assetId;
|
||||
final bool _inlineViews;
|
||||
final ConstantEvaluator _evaluator = new ConstantEvaluator();
|
||||
bool _isProcessingView = false;
|
||||
bool _isProcessingDirective = false;
|
||||
|
||||
AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr,
|
||||
this._annotationMatcher, this._assetId, {bool inlineViews})
|
||||
: writer = writer,
|
||||
_inlineViews = inlineViews,
|
||||
super(writer);
|
||||
|
||||
void _resetState() {
|
||||
_isProcessingView = _isProcessingDirective = false;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
writer.print('const [');
|
||||
var size = node.metadata.length;
|
||||
for (var i = 0; i < size; ++i) {
|
||||
if (i > 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
node.metadata[i].accept(this);
|
||||
}
|
||||
writer.print(']');
|
||||
|
||||
_resetState();
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
writer.print('const ');
|
||||
if (node.name != null) {
|
||||
_isProcessingDirective = _annotationMatcher.isDirective(node, _assetId);
|
||||
_isProcessingView = _annotationMatcher.isView(node, _assetId);
|
||||
node.name.accept(this);
|
||||
} else {
|
||||
_isProcessingDirective = false;
|
||||
_isProcessingView = false;
|
||||
}
|
||||
if (node.constructorName != null) {
|
||||
writer.print('.');
|
||||
node.constructorName.accept(this);
|
||||
}
|
||||
if (node.arguments != null && node.arguments.arguments != null) {
|
||||
var args = node.arguments.arguments;
|
||||
writer.print('(');
|
||||
for (var i = 0, iLen = args.length; i < iLen; ++i) {
|
||||
if (i != 0) {
|
||||
writer.print(', ');
|
||||
}
|
||||
args[i].accept(this);
|
||||
}
|
||||
writer.print(')');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// These correspond to the annotation parameters.
|
||||
@override
|
||||
Object visitNamedExpression(NamedExpression node) {
|
||||
if (!_isProcessingView && !_isProcessingDirective) {
|
||||
return super.visitNamedExpression(node);
|
||||
}
|
||||
// TODO(kegluneq): Remove this limitation.
|
||||
if (node.name is! Label || node.name.label is! SimpleIdentifier) {
|
||||
return super.visitNamedExpression(node);
|
||||
}
|
||||
var keyString = '${node.name.label}';
|
||||
if (_isProcessingView && _inlineViews) {
|
||||
var isSuccess = this._inlineView(keyString, node.expression);
|
||||
if (isSuccess) return null;
|
||||
}
|
||||
return super.visitNamedExpression(node);
|
||||
}
|
||||
|
||||
/// Inlines the template and/or style refered to by `keyString`.
|
||||
/// Returns whether the `keyString` value was successfully processed.
|
||||
bool _inlineView(String keyString, AstNode node) {
|
||||
if (keyString == 'templateUrl') {
|
||||
// Inline the templateUrl
|
||||
var url = node.accept(_evaluator);
|
||||
if (url is String) {
|
||||
writer.print("template: r'''");
|
||||
writer.asyncPrint(_readOrEmptyString(url));
|
||||
writer.print("'''");
|
||||
|
||||
// We keep the templateUrl in case the body of the template includes
|
||||
// relative urls that might be inlined later on (e.g. @import
|
||||
// directives or url() css values in style tags).
|
||||
writer.print(", templateUrl: r'$url'");
|
||||
return true;
|
||||
} else {
|
||||
logger.warning('template url is not a String $url');
|
||||
}
|
||||
} else if (keyString == 'styleUrls') {
|
||||
// Inline the styleUrls
|
||||
var urls = node.accept(_evaluator);
|
||||
writer.print('styles: const [');
|
||||
for (var url in urls) {
|
||||
if (url is String) {
|
||||
writer.print("r'''");
|
||||
writer.asyncPrint(_readOrEmptyString(url));
|
||||
writer.print("''', ");
|
||||
} else {
|
||||
logger.warning('style url is not a String ${url}');
|
||||
}
|
||||
}
|
||||
writer.print(']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Attempts to read the content from {@link url}, if it returns null then
|
||||
/// just return the empty string.
|
||||
Future<String> _readOrEmptyString(String url) async {
|
||||
var content = await _xhr.get(url);
|
||||
if (content == null) {
|
||||
content = '';
|
||||
}
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -13,9 +13,15 @@ main() {
|
|||
it("directiveMetadataToMap", () {
|
||||
var someComponent = new RenderDirectiveMetadata(
|
||||
compileChildren: false,
|
||||
hostListeners: MapWrapper.createFromPairs([["LKey", "LVal"]]),
|
||||
hostProperties: MapWrapper.createFromPairs([["PKey", "PVal"]]),
|
||||
hostAttributes: MapWrapper.createFromPairs([["AtKey", "AtVal"]]),
|
||||
hostListeners: MapWrapper.createFromPairs([
|
||||
["LKey", "LVal"]
|
||||
]),
|
||||
hostProperties: MapWrapper.createFromPairs([
|
||||
["PKey", "PVal"]
|
||||
]),
|
||||
hostAttributes: MapWrapper.createFromPairs([
|
||||
["AtKey", "AtVal"]
|
||||
]),
|
||||
id: "someComponent",
|
||||
properties: ["propKey: propVal"],
|
||||
readAttributes: ["read1", "read2"],
|
||||
|
@ -34,12 +40,15 @@ main() {
|
|||
changeDetection: ChangeDetectionStrategy.CheckOnce);
|
||||
var map = directiveMetadataToMap(someComponent);
|
||||
expect(map["compileChildren"]).toEqual(false);
|
||||
expect(map["hostListeners"])
|
||||
.toEqual(MapWrapper.createFromPairs([["LKey", "LVal"]]));
|
||||
expect(map["hostProperties"])
|
||||
.toEqual(MapWrapper.createFromPairs([["PKey", "PVal"]]));
|
||||
expect(map["hostAttributes"])
|
||||
.toEqual(MapWrapper.createFromPairs([["AtKey", "AtVal"]]));
|
||||
expect(map["hostListeners"]).toEqual(MapWrapper.createFromPairs([
|
||||
["LKey", "LVal"]
|
||||
]));
|
||||
expect(map["hostProperties"]).toEqual(MapWrapper.createFromPairs([
|
||||
["PKey", "PVal"]
|
||||
]));
|
||||
expect(map["hostAttributes"]).toEqual(MapWrapper.createFromPairs([
|
||||
["AtKey", "AtVal"]
|
||||
]));
|
||||
expect(map["id"]).toEqual("someComponent");
|
||||
expect(map["properties"]).toEqual(["propKey: propVal"]);
|
||||
expect(map["readAttributes"]).toEqual(["read1", "read2"]);
|
||||
|
@ -55,17 +64,39 @@ main() {
|
|||
expect(map["callAfterViewChecked"]).toEqual(true);
|
||||
expect(map["exportAs"]).toEqual("aaa");
|
||||
expect(map["events"]).toEqual(["onFoo", "onBar"]);
|
||||
expect(map["changeDetection"]).toEqual(ChangeDetectionStrategy.CheckOnce.index);
|
||||
expect(map["changeDetection"])
|
||||
.toEqual(ChangeDetectionStrategy.CheckOnce.index);
|
||||
});
|
||||
it("mapToDirectiveMetadata", () {
|
||||
var map = MapWrapper.createFromPairs([
|
||||
["compileChildren", false],
|
||||
["hostProperties", MapWrapper.createFromPairs([["PKey", "testVal"]])],
|
||||
["hostListeners", MapWrapper.createFromPairs([["LKey", "testVal"]])],
|
||||
["hostAttributes", MapWrapper.createFromPairs([["AtKey", "testVal"]])],
|
||||
[
|
||||
"hostProperties",
|
||||
MapWrapper.createFromPairs([
|
||||
["PKey", "testVal"]
|
||||
])
|
||||
],
|
||||
[
|
||||
"hostListeners",
|
||||
MapWrapper.createFromPairs([
|
||||
["LKey", "testVal"]
|
||||
])
|
||||
],
|
||||
[
|
||||
"hostAttributes",
|
||||
MapWrapper.createFromPairs([
|
||||
["AtKey", "testVal"]
|
||||
])
|
||||
],
|
||||
["id", "testId"],
|
||||
["properties", ["propKey: propVal"]],
|
||||
["readAttributes", ["readTest1", "readTest2"]],
|
||||
[
|
||||
"properties",
|
||||
["propKey: propVal"]
|
||||
],
|
||||
[
|
||||
"readAttributes",
|
||||
["readTest1", "readTest2"]
|
||||
],
|
||||
["selector", "testSelector"],
|
||||
["type", RenderDirectiveMetadata.DIRECTIVE_TYPE],
|
||||
["exportAs", "aaa"],
|
||||
|
@ -77,17 +108,23 @@ main() {
|
|||
["callAfterContentChecked", true],
|
||||
["callAfterViewInit", true],
|
||||
["callAfterViewChecked", true],
|
||||
["events", ["onFoo", "onBar"]],
|
||||
[
|
||||
"events",
|
||||
["onFoo", "onBar"]
|
||||
],
|
||||
["changeDetection", ChangeDetectionStrategy.CheckOnce.index]
|
||||
]);
|
||||
var meta = directiveMetadataFromMap(map);
|
||||
expect(meta.compileChildren).toEqual(false);
|
||||
expect(meta.hostProperties)
|
||||
.toEqual(MapWrapper.createFromPairs([["PKey", "testVal"]]));
|
||||
expect(meta.hostListeners)
|
||||
.toEqual(MapWrapper.createFromPairs([["LKey", "testVal"]]));
|
||||
expect(meta.hostAttributes)
|
||||
.toEqual(MapWrapper.createFromPairs([["AtKey", "testVal"]]));
|
||||
expect(meta.hostProperties).toEqual(MapWrapper.createFromPairs([
|
||||
["PKey", "testVal"]
|
||||
]));
|
||||
expect(meta.hostListeners).toEqual(MapWrapper.createFromPairs([
|
||||
["LKey", "testVal"]
|
||||
]));
|
||||
expect(meta.hostAttributes).toEqual(MapWrapper.createFromPairs([
|
||||
["AtKey", "testVal"]
|
||||
]));
|
||||
expect(meta.id).toEqual("testId");
|
||||
expect(meta.properties).toEqual(["propKey: propVal"]);
|
||||
expect(meta.readAttributes).toEqual(["readTest1", "readTest2"]);
|
||||
|
|
|
@ -121,7 +121,8 @@ void allTests() {
|
|||
it('should parse changeDetection.', () async {
|
||||
var metadata = await readMetadata('directive_metadata_extractor/'
|
||||
'directive_metadata_files/changeDetection.ng_deps.dart');
|
||||
expect(metadata.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
|
||||
expect(metadata.changeDetection)
|
||||
.toEqual(ChangeDetectionStrategy.CheckOnce);
|
||||
});
|
||||
|
||||
it('should fail when a class is annotated with multiple Directives.',
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.absolute_url_expression_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -16,9 +16,9 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
styles: const [r'''.greeting { .color: blue; }''',],
|
||||
template: r'''{{greeting}}''',
|
||||
templateUrl: r'package:other_package/template.html',
|
||||
styles: const [r'''.greeting { .color: blue; }''',])
|
||||
templateUrl: 'package:other_package/template.html')
|
||||
], const [], () => new HelloCmp()))
|
||||
..registerFunction(
|
||||
hello, new _ngRef.ReflectionInfo(const [const Injectable()], const []));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library dinner.package_soup.ng_deps.dart;
|
||||
|
||||
import 'package_soup.dart';
|
||||
export 'package_soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:soup/soup.dart';
|
||||
export 'package_soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library dinner.relative_soup.ng_deps.dart;
|
||||
|
||||
import 'relative_soup.dart';
|
||||
export 'relative_soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'annotations/soup.dart';
|
||||
export 'relative_soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
library examples.src.hello_world.absolute_url_expression_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/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;
|
||||
export 'hello.dart';
|
||||
export 'a.dart' show alias3;
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -18,8 +18,8 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
styles: const [r'''.greeting { .color: blue; }''',],
|
||||
template: r'''{{greeting}}''',
|
||||
templateUrl: r'template.html',
|
||||
styles: const [r'''.greeting { .color: blue; }''',])
|
||||
templateUrl: 'template.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.index_common_dart.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
_ngRef.reflector
|
||||
..registerType(
|
||||
OnChangeSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.OnChanges])
|
||||
],
|
||||
const [],
|
||||
() => new OnChangeSoupComponent(),
|
||||
const [OnChanges]))
|
||||
..registerType(
|
||||
OnDestroySoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.OnDestroy])
|
||||
],
|
||||
const [],
|
||||
() => new OnDestroySoupComponent(),
|
||||
const [OnDestroy]))
|
||||
..registerType(
|
||||
OnCheckSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]', lifecycle: const [LifecycleEvent.DoCheck])
|
||||
],
|
||||
const [],
|
||||
() => new OnCheckSoupComponent(),
|
||||
const [DoCheck]))
|
||||
..registerType(
|
||||
OnInitSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]', lifecycle: const [LifecycleEvent.OnInit])
|
||||
],
|
||||
const [],
|
||||
() => new OnInitSoupComponent(),
|
||||
const [OnInit]))
|
||||
..registerType(
|
||||
AfterContentInitSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterContentInit])
|
||||
],
|
||||
const [],
|
||||
() => new AfterContentInitSoupComponent(),
|
||||
const [AfterContentInit]))
|
||||
..registerType(
|
||||
AfterContentCheckedSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterContentChecked])
|
||||
],
|
||||
const [],
|
||||
() => new AfterContentCheckedSoupComponent(),
|
||||
const [AfterContentChecked]))
|
||||
..registerType(
|
||||
AfterViewInitSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterViewInit])
|
||||
],
|
||||
const [],
|
||||
() => new AfterViewInitSoupComponent(),
|
||||
const [AfterViewInit]))
|
||||
..registerType(
|
||||
AfterViewCheckedSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterViewChecked])
|
||||
],
|
||||
const [],
|
||||
() => new AfterViewCheckedSoupComponent(),
|
||||
const [AfterViewChecked]));
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
import 'package:angular2/src/core/compiler.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -14,8 +14,7 @@ void initReflector() {
|
|||
..registerType(
|
||||
ChangingSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(selector: '[soup]')],
|
||||
const [const Component(selector: '[soup]')],
|
||||
const [],
|
||||
() => new ChangingSoupComponent(),
|
||||
const [OnChanges, AnotherInterface]));
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library test.transform.directive_processor.invalid_url_files.hello.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -16,8 +16,8 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
styles: const [r'''''', r'''''',],
|
||||
template: r'''''',
|
||||
templateUrl: r'/bad/absolute/url.html',
|
||||
styles: const [r'''''', r'''''',])
|
||||
templateUrl: '/bad/absolute/url.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
import 'package:angular2/src/core/compiler.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -14,9 +14,7 @@ void initReflector() {
|
|||
..registerType(
|
||||
MultiSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(selector: '[soup]')
|
||||
],
|
||||
const [const Component(selector: '[soup]')],
|
||||
const [],
|
||||
() => new MultiSoupComponent(),
|
||||
const [OnChanges, OnDestroy, OnInit]));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library main.ng_deps.dart;
|
||||
|
||||
import 'main.dart';
|
||||
export 'main.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'main.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.multiple_style_urls_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -15,12 +15,9 @@ void initReflector() {
|
|||
HelloCmp,
|
||||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
template: r'''{{greeting}}''',
|
||||
templateUrl: r'template.html',
|
||||
styles: const [
|
||||
r'''.greeting { .color: blue; }''',
|
||||
r'''.hello { .color: red; }''',
|
||||
])
|
||||
const View(styles: const [
|
||||
r'''.greeting { .color: blue; }''',
|
||||
r'''.hello { .color: red; }''',
|
||||
], template: r'''{{greeting}}''', templateUrl: 'template.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.multiple_style_urls_not_inlined_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -15,11 +15,9 @@ void initReflector() {
|
|||
HelloCmp,
|
||||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
templateUrl: 'package:a/template.html',
|
||||
styleUrls: const [
|
||||
'package:a/template.css',
|
||||
'package:a/template_other.css'
|
||||
])
|
||||
const View(styleUrls: const [
|
||||
'package:a/template.css',
|
||||
'package:a/template_other.css'
|
||||
], templateUrl: 'package:a/template.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -15,7 +15,7 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: '[soup]')
|
||||
], const [
|
||||
const [String, Tasty],
|
||||
const [String,const Tasty()],
|
||||
const [const Inject(Salt)]
|
||||
], (String description, salt) => new SoupComponent(description, salt)));
|
||||
}
|
||||
|
|
|
@ -4,5 +4,5 @@ import 'package:angular2/src/core/metadata.dart';
|
|||
|
||||
@Component(selector: '[soup]')
|
||||
class SoupComponent {
|
||||
SoupComponent(@Tasty String description, @Inject(Salt) salt);
|
||||
SoupComponent(@Tasty() String description, @Inject(Salt) salt);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library main.ng_deps.dart;
|
||||
|
||||
import 'main.dart';
|
||||
export 'main.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'main.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/compiler.dart' as prefix;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.split_url_expression_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -16,6 +16,6 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
template: r'''{{greeting}}''', templateUrl: r'template.html')
|
||||
template: r'''{{greeting}}''', templateUrl: 'templ' 'ate.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library static_function_files.hello.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart';
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library dinner.soup.ng_deps.dart;
|
||||
|
||||
import 'soup.dart';
|
||||
export 'soup.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/compiler.dart';
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -13,8 +13,6 @@ void initReflector() {
|
|||
_ngRef.reflector
|
||||
..registerType(
|
||||
OnChangeSoupComponent,
|
||||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(
|
||||
selector: '[soup]')
|
||||
], const [], () => new OnChangeSoupComponent()));
|
||||
new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')],
|
||||
const [], () => new OnChangeSoupComponent()));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library examples.src.hello_world.url_expression_files.ng_deps.dart;
|
||||
|
||||
import 'hello.dart';
|
||||
export 'hello.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/angular2.dart'
|
||||
show Component, Directive, View, NgElement;
|
||||
export 'hello.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
@ -16,6 +16,6 @@ void initReflector() {
|
|||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: 'hello-app'),
|
||||
const View(
|
||||
template: r'''{{greeting}}''', templateUrl: r'template.html')
|
||||
template: r'''{{greeting}}''', templateUrl: 'template.html')
|
||||
], const [], () => new HelloCmp()));
|
||||
}
|
||||
|
|
|
@ -12,9 +12,8 @@ main() {
|
|||
}
|
||||
|
||||
var formatter = new DartFormatter();
|
||||
var transform = new AngularTransformerGroup(new TransformerOptions(
|
||||
['web/index.dart'],
|
||||
formatCode: true));
|
||||
var transform = new AngularTransformerGroup(
|
||||
new TransformerOptions(['web/index.dart'], formatCode: true));
|
||||
|
||||
class IntegrationTestConfig {
|
||||
final String name;
|
||||
|
@ -96,7 +95,8 @@ void allTests() {
|
|||
new IntegrationTestConfig('should preserve multiple annotations.', inputs: {
|
||||
'a|web/index.dart': 'two_annotations_files/index.dart',
|
||||
'a|web/bar.dart': 'two_annotations_files/bar.dart',
|
||||
'angular2|lib/src/core/metadata.dart': '../../../lib/src/core/metadata.dart'
|
||||
'angular2|lib/src/core/metadata.dart':
|
||||
'../../../lib/src/core/metadata.dart'
|
||||
}, outputs: {
|
||||
'a|web/bar.ng_deps.dart':
|
||||
'two_annotations_files/expected/bar.ng_deps.dart'
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
export 'bar.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
import 'foo.dart';
|
||||
export 'bar.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
export 'bar.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'bar.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
library web_foo.ng_deps.dart;
|
||||
|
||||
import 'index.dart';
|
||||
export 'index.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/bootstrap_static.dart';
|
||||
import 'index.ng_deps.dart' as ngStaticInit;
|
||||
import 'package:angular2/src/core/reflection/reflection.dart';
|
||||
import 'bar.dart';
|
||||
import 'bar.ng_deps.dart' as i0;
|
||||
export 'index.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
export 'bar.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'bar.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
|
@ -4,19 +4,21 @@ import 'package:angular2/src/core/change_detection/pregen_proto_change_detector.
|
|||
as _gen;
|
||||
|
||||
import 'bar.dart';
|
||||
export 'bar.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
export 'bar.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
_ngRef.reflector
|
||||
..registerType(MyComponent, new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: '[soup]'),
|
||||
const View(template: 'Salad: {{myNum}} is awesome')
|
||||
], const [], () => new MyComponent()))
|
||||
..registerType(
|
||||
MyComponent,
|
||||
new _ngRef.ReflectionInfo(const [
|
||||
const Component(selector: '[soup]'),
|
||||
const View(template: 'Salad: {{myNum}} is awesome')
|
||||
], const [], () => new MyComponent()))
|
||||
..registerGetters({'myNum': (o) => o.myNum});
|
||||
_gen.preGeneratedProtoDetectors['MyComponent_comp_0'] =
|
||||
_MyComponent_ChangeDetector0.newProtoChangeDetector;
|
||||
|
@ -26,18 +28,19 @@ class _MyComponent_ChangeDetector0
|
|||
extends _gen.AbstractChangeDetector<MyComponent> {
|
||||
var myNum0, interpolate1;
|
||||
|
||||
_MyComponent_ChangeDetector0(dispatcher) : super(
|
||||
"MyComponent_comp_0", dispatcher, 2,
|
||||
_MyComponent_ChangeDetector0.gen_propertyBindingTargets,
|
||||
_MyComponent_ChangeDetector0.gen_directiveIndices,null) {
|
||||
_MyComponent_ChangeDetector0(dispatcher)
|
||||
: super(
|
||||
"MyComponent_comp_0",
|
||||
dispatcher,
|
||||
2,
|
||||
_MyComponent_ChangeDetector0.gen_propertyBindingTargets,
|
||||
_MyComponent_ChangeDetector0.gen_directiveIndices,
|
||||
null) {
|
||||
dehydrateDirectives(false);
|
||||
}
|
||||
|
||||
void detectChangesInRecordsInternal(throwOnChange) {
|
||||
var l_context = this.context,
|
||||
l_myNum0,
|
||||
c_myNum0,
|
||||
l_interpolate1;
|
||||
var l_context = this.context, l_myNum0, c_myNum0, l_interpolate1;
|
||||
c_myNum0 = false;
|
||||
var isChanged = false;
|
||||
var changes = null;
|
||||
|
@ -88,4 +91,4 @@ class _MyComponent_ChangeDetector0
|
|||
return new _gen.PregenProtoChangeDetector(
|
||||
(a) => new _MyComponent_ChangeDetector0(a), def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
export 'bar.dart';
|
||||
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
import 'foo.dart' as prefix;
|
||||
export 'bar.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector() {
|
||||
|
|
Loading…
Reference in New Issue