fix(transformer): remove classDefParser in favor of hardcoded strings to speed up build
This commit is contained in:
parent
7844e3a275
commit
01d5c29513
|
@ -0,0 +1,157 @@
|
|||
library angular2.transform.common.annotation_matcher;
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
import 'package:code_transformers/assets.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'logging.dart' show logger;
|
||||
|
||||
/// [AnnotationDescriptor]s for the default angular annotations that can appear
|
||||
/// on a class. These classes are re-exported in many places so this covers all
|
||||
/// the possible libraries which could provide them.
|
||||
const INJECTABLES = const [
|
||||
const AnnotationDescriptor(
|
||||
'Injectable', 'package:angular2/src/di/annotations.dart', null),
|
||||
const AnnotationDescriptor(
|
||||
'Injectable', 'package:angular2/src/di/annotations_impl.dart', null),
|
||||
const AnnotationDescriptor(
|
||||
'Injectable', 'package:angular2/src/di/decorators.dart', null),
|
||||
const AnnotationDescriptor('Injectable', 'package:angular2/di.dart', null),
|
||||
const AnnotationDescriptor(
|
||||
'Injectable', 'package:angular2/angular2.dart', null),
|
||||
];
|
||||
|
||||
const DIRECTIVES = const [
|
||||
const AnnotationDescriptor('Directive',
|
||||
'package:angular2/src/core/annotations/annotations.dart', 'Injectable'),
|
||||
const AnnotationDescriptor('Directive',
|
||||
'package:angular2/src/core/annotations_impl/annotations.dart',
|
||||
'Injectable'),
|
||||
const AnnotationDescriptor(
|
||||
'Directive', 'package:angular2/annotations.dart', 'Injectable'),
|
||||
const AnnotationDescriptor(
|
||||
'Directive', 'package:angular2/angular2.dart', 'Injectable'),
|
||||
const AnnotationDescriptor(
|
||||
'Directive', 'package:angular2/core.dart', 'Injectable'),
|
||||
];
|
||||
|
||||
const COMPONENTS = const [
|
||||
const AnnotationDescriptor('Component',
|
||||
'package:angular2/src/core/annotations/annotations.dart', 'Directive'),
|
||||
const AnnotationDescriptor('Component',
|
||||
'package:angular2/src/core/annotations_impl/annotations.dart',
|
||||
'Directive'),
|
||||
const AnnotationDescriptor(
|
||||
'Component', 'package:angular2/annotations.dart', 'Directive'),
|
||||
const AnnotationDescriptor(
|
||||
'Component', 'package:angular2/angular2.dart', 'Directive'),
|
||||
const AnnotationDescriptor(
|
||||
'Component', 'package:angular2/core.dart', 'Directive'),
|
||||
];
|
||||
|
||||
const VIEWS = const [
|
||||
const AnnotationDescriptor('View', 'package:angular2/view.dart', null),
|
||||
const AnnotationDescriptor('View', 'package:angular2/angular2.dart', null),
|
||||
const AnnotationDescriptor('View', 'package:angular2/core.dart', null),
|
||||
const AnnotationDescriptor(
|
||||
'View', 'package:angular2/src/core/annotations/view.dart', null),
|
||||
const AnnotationDescriptor(
|
||||
'View', 'package:angular2/src/core/annotations_impl/view.dart', null),
|
||||
];
|
||||
|
||||
/// Checks if a given [Annotation] matches any of the given
|
||||
/// [AnnotationDescriptors].
|
||||
class AnnotationMatcher {
|
||||
/// Always start out with the default angular [AnnotationDescriptor]s.
|
||||
final List<AnnotationDescriptor> _annotations = []
|
||||
..addAll(VIEWS)
|
||||
..addAll(COMPONENTS)
|
||||
..addAll(INJECTABLES)
|
||||
..addAll(DIRECTIVES);
|
||||
|
||||
AnnotationMatcher();
|
||||
|
||||
/// Adds a new [AnnotationDescriptor].
|
||||
void add(AnnotationDescriptor annotation) => _annotations.add(annotation);
|
||||
|
||||
/// Adds a number of [AnnotationDescriptor]s.
|
||||
void addAll(Iterable<AnnotationDescriptor> annotations) =>
|
||||
_annotations.addAll(annotations);
|
||||
|
||||
/// Returns the first [AnnotationDescriptor] that matches the given
|
||||
/// [Annotation] node which appears in `assetId`.
|
||||
AnnotationDescriptor firstMatch(Annotation annotation, AssetId assetId) =>
|
||||
_annotations.firstWhere((a) => _matchAnnotation(annotation, a, assetId),
|
||||
orElse: () => null);
|
||||
|
||||
/// Checks whether an [Annotation] node matches any [AnnotationDescriptor].
|
||||
bool hasMatch(Annotation annotation, AssetId assetId) =>
|
||||
_annotations.any((a) => _matchAnnotation(annotation, a, assetId));
|
||||
|
||||
/// Checks if an [Annotation] node implements [Injectable].
|
||||
bool isInjectable(Annotation annotation, AssetId assetId) =>
|
||||
_implements(firstMatch(annotation, assetId), INJECTABLES);
|
||||
|
||||
/// Checks if an [Annotation] node implements [Directive].
|
||||
bool isDirective(Annotation annotation, AssetId assetId) =>
|
||||
_implements(firstMatch(annotation, assetId), DIRECTIVES);
|
||||
|
||||
/// Checks if an [Annotation] node implements [Component].
|
||||
bool isComponent(Annotation annotation, AssetId assetId) =>
|
||||
_implements(firstMatch(annotation, assetId), COMPONENTS);
|
||||
|
||||
/// Checks if an [Annotation] node implements [View].
|
||||
bool isView(Annotation annotation, AssetId assetId) =>
|
||||
_implements(firstMatch(annotation, assetId), VIEWS);
|
||||
|
||||
/// Checks if `descriptor` extends or is any of the supplied `interfaces`.
|
||||
bool _implements(
|
||||
AnnotationDescriptor descriptor, List<AnnotationDescriptor> interfaces) {
|
||||
if (descriptor == null) return false;
|
||||
if (interfaces.contains(descriptor)) return true;
|
||||
if (descriptor.superClass == null) return false;
|
||||
var superClass = _annotations.firstWhere(
|
||||
(a) => a.name == descriptor.superClass, orElse: () => null);
|
||||
if (superClass == null) {
|
||||
logger.warning(
|
||||
'Missing `custom_annotation` entry for `${descriptor.superClass}`.');
|
||||
return false;
|
||||
}
|
||||
return _implements(superClass, interfaces);
|
||||
}
|
||||
|
||||
// Checks if an [Annotation] matches an [AnnotationDescriptor].
|
||||
static bool _matchAnnotation(
|
||||
Annotation annotation, AnnotationDescriptor descriptor, AssetId assetId) {
|
||||
if (annotation.name.name != descriptor.name) return false;
|
||||
return (annotation.root as CompilationUnit).directives
|
||||
.where((d) => d is ImportDirective)
|
||||
.any((ImportDirective i) {
|
||||
var uriString = i.uri.stringValue;
|
||||
if (uriString == descriptor.import) return true;
|
||||
if (uriString.startsWith('package:') || uriString.startsWith('dart:')) {
|
||||
return false;
|
||||
}
|
||||
return descriptor.assetId ==
|
||||
uriToAssetId(assetId, uriString, logger, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// String based description of an annotation class and its location.
|
||||
class AnnotationDescriptor {
|
||||
/// The name of the class.
|
||||
final String name;
|
||||
/// A `package:` style import path to the file where the class is defined.
|
||||
final String import;
|
||||
/// The class that this class extends or implements. This is the only optional
|
||||
/// field.
|
||||
final String superClass;
|
||||
|
||||
AssetId get assetId => new AssetId(package, packagePath);
|
||||
String get package => path.split(import.replaceFirst('package:', '')).first;
|
||||
String get packagePath => path.joinAll(['lib']
|
||||
..addAll(path.split(import.replaceFirst('package:', ''))..removeAt(0)));
|
||||
|
||||
const AnnotationDescriptor(this.name, this.import, this.superClass);
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
library angular2.transform.common.options;
|
||||
|
||||
import 'annotation_matcher.dart';
|
||||
import 'mirror_mode.dart';
|
||||
|
||||
const ENTRY_POINT_PARAM = 'entry_points';
|
||||
const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points';
|
||||
const CUSTOM_ANNOTATIONS_PARAM = 'custom_annotations';
|
||||
|
||||
/// Provides information necessary to transform an Angular2 app.
|
||||
class TransformerOptions {
|
||||
|
@ -23,16 +25,23 @@ class TransformerOptions {
|
|||
/// Whether to generate calls to our generated `initReflector` code
|
||||
final bool initReflector;
|
||||
|
||||
/// The [AnnotationMatcher] which is used to identify angular annotations.
|
||||
final AnnotationMatcher annotationMatcher;
|
||||
|
||||
TransformerOptions._internal(this.entryPoints, this.reflectionEntryPoints,
|
||||
this.modeName, this.mirrorMode, this.initReflector);
|
||||
this.modeName, this.mirrorMode, this.initReflector,
|
||||
this.annotationMatcher);
|
||||
|
||||
factory TransformerOptions(List<String> entryPoints,
|
||||
{List<String> reflectionEntryPoints, String modeName: 'release',
|
||||
MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true}) {
|
||||
MirrorMode mirrorMode: MirrorMode.none, bool initReflector: true,
|
||||
List<AnnotationDescriptor> customAnnotationDescriptors: const []}) {
|
||||
if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) {
|
||||
reflectionEntryPoints = entryPoints;
|
||||
}
|
||||
var annotationMatcher = new AnnotationMatcher()
|
||||
..addAll(customAnnotationDescriptors);
|
||||
return new TransformerOptions._internal(entryPoints, reflectionEntryPoints,
|
||||
modeName, mirrorMode, initReflector);
|
||||
modeName, mirrorMode, initReflector, annotationMatcher);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
library angular2.transform.common.options_reader;
|
||||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'annotation_matcher.dart';
|
||||
import 'mirror_mode.dart';
|
||||
import 'options.dart';
|
||||
|
||||
|
@ -29,7 +30,8 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) {
|
|||
reflectionEntryPoints: reflectionEntryPoints,
|
||||
modeName: settings.mode.name,
|
||||
mirrorMode: mirrorMode,
|
||||
initReflector: initReflector);
|
||||
initReflector: initReflector,
|
||||
customAnnotationDescriptors: _readCustomAnnotations(config));
|
||||
}
|
||||
|
||||
/// Cribbed from the polymer project.
|
||||
|
@ -53,3 +55,48 @@ List<String> _readFileList(Map config, String paramName) {
|
|||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/// Parse the [CUSTOM_ANNOTATIONS_PARAM] options out of the transformer into
|
||||
/// [AnnotationDescriptor]s.
|
||||
List<AnnotationDescriptor> _readCustomAnnotations(Map config) {
|
||||
var descriptors = [];
|
||||
var customAnnotations = config[CUSTOM_ANNOTATIONS_PARAM];
|
||||
if (customAnnotations == null) return descriptors;
|
||||
var error = false;
|
||||
if (customAnnotations is! List) {
|
||||
error = true;
|
||||
} else {
|
||||
for (var description in customAnnotations) {
|
||||
if (description is! Map) {
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
var name = description['name'];
|
||||
var import = description['import'];
|
||||
var superClass = description['superClass'];
|
||||
if (name == null || import == null || superClass == null) {
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
descriptors.add(new AnnotationDescriptor(name, import, superClass));
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
print(CUSTOM_ANNOTATIONS_ERROR);
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
const CUSTOM_ANNOTATIONS_ERROR = '''
|
||||
Invalid value for $CUSTOM_ANNOTATIONS_PARAM in the Angular2 transformer.
|
||||
Expected something that looks like the following:
|
||||
|
||||
transformers:
|
||||
- angular2:
|
||||
custom_annotations:
|
||||
- name: MyAnnotation
|
||||
import: 'package:my_package/my_annotation.dart'
|
||||
superClass: Component
|
||||
- name: ...
|
||||
import: ...
|
||||
superClass: ...''';
|
||||
|
|
|
@ -2,6 +2,7 @@ library angular2.transform.directive_processor.rewriter;
|
|||
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
|
@ -9,20 +10,20 @@ import 'package:path/path.dart' as path;
|
|||
|
||||
import 'visitors.dart';
|
||||
|
||||
/// Generates a file registering all Angular 2 `Directive`s found in [code] in
|
||||
/// ngDeps format [TODO(kegluneq): documentation reference needed]. [path] is
|
||||
/// the path to the file (or asset) containing [code].
|
||||
/// Generates a file registering all Angular 2 `Directive`s found in `code` in
|
||||
/// ngDeps format [TODO(kegluneq): documentation reference needed]. `assetId` is
|
||||
/// the id of the asset containing `code`.
|
||||
///
|
||||
/// If no Angular 2 `Directive`s are found in [code], returns the empty
|
||||
/// string unless [forceGenerate] is true, in which case an empty ngDeps
|
||||
/// If no Angular 2 `Directive`s are found in `code`, returns the empty
|
||||
/// string unless `forceGenerate` is true, in which case an empty ngDeps
|
||||
/// file is created.
|
||||
String createNgDeps(String code, String path,
|
||||
Map<AssetId, List<ClassDeclaration>> assetClasses) {
|
||||
String createNgDeps(
|
||||
String code, AssetId assetId, AnnotationMatcher annotationMatcher) {
|
||||
// TODO(kegluneq): Shortcut if we can determine that there are no
|
||||
// [Directive]s present, taking into account `export`s.
|
||||
var writer = new PrintStringWriter();
|
||||
var visitor = new CreateNgDepsVisitor(writer, path, assetClasses);
|
||||
parseCompilationUnit(code, name: path).accept(visitor);
|
||||
var visitor = new CreateNgDepsVisitor(writer, assetId, annotationMatcher);
|
||||
parseCompilationUnit(code, name: assetId.toString()).accept(visitor);
|
||||
return '$writer';
|
||||
}
|
||||
|
||||
|
@ -30,25 +31,23 @@ String createNgDeps(String code, String path,
|
|||
/// associated .ng_deps.dart file.
|
||||
class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
final PrintWriter writer;
|
||||
final _Tester _tester;
|
||||
bool _foundNgDirectives = false;
|
||||
bool _wroteImport = false;
|
||||
final ToSourceVisitor _copyVisitor;
|
||||
final FactoryTransformVisitor _factoryVisitor;
|
||||
final ParameterTransformVisitor _paramsVisitor;
|
||||
final AnnotationsTransformVisitor _metaVisitor;
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
|
||||
/// The path to the file which we are parsing.
|
||||
final String importPath;
|
||||
/// The assetId for the file which we are parsing.
|
||||
final AssetId assetId;
|
||||
|
||||
CreateNgDepsVisitor(PrintWriter writer, this.importPath,
|
||||
Map<AssetId, List<ClassDeclaration>> assetClasses)
|
||||
CreateNgDepsVisitor(PrintWriter writer, this.assetId, this._annotationMatcher)
|
||||
: writer = writer,
|
||||
_copyVisitor = new ToSourceVisitor(writer),
|
||||
_factoryVisitor = new FactoryTransformVisitor(writer),
|
||||
_paramsVisitor = new ParameterTransformVisitor(writer),
|
||||
_metaVisitor = new AnnotationsTransformVisitor(writer),
|
||||
_tester = new _Tester(assetClasses);
|
||||
_metaVisitor = new AnnotationsTransformVisitor(writer);
|
||||
|
||||
void _visitNodeListWithSeparator(NodeList<AstNode> list, String separator) {
|
||||
if (list == null) return;
|
||||
|
@ -74,7 +73,7 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
void _maybeWriteImport() {
|
||||
if (_wroteImport) return;
|
||||
_wroteImport = true;
|
||||
writer.print('''import '${path.basename(importPath)}';''');
|
||||
writer.print('''import '${path.basename(assetId.path)}';''');
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -140,34 +139,34 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
var shouldProcess = node.metadata.any(_tester._shouldKeepMeta);
|
||||
|
||||
if (shouldProcess) {
|
||||
var ctor = _getCtor(node);
|
||||
|
||||
if (!_foundNgDirectives) {
|
||||
// The receiver for cascaded calls.
|
||||
writer.print(REFLECTOR_VAR_NAME);
|
||||
_foundNgDirectives = true;
|
||||
}
|
||||
writer.print('..registerType(');
|
||||
node.name.accept(this);
|
||||
writer.print(''', {'factory': ''');
|
||||
if (ctor == null) {
|
||||
_generateEmptyFactory(node.name.toString());
|
||||
} else {
|
||||
ctor.accept(_factoryVisitor);
|
||||
}
|
||||
writer.print(''', 'parameters': ''');
|
||||
if (ctor == null) {
|
||||
_generateEmptyParams();
|
||||
} else {
|
||||
ctor.accept(_paramsVisitor);
|
||||
}
|
||||
writer.print(''', 'annotations': ''');
|
||||
node.accept(_metaVisitor);
|
||||
writer.print('})');
|
||||
if (!node.metadata.any((a) => _annotationMatcher.hasMatch(a, assetId))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ctor = _getCtor(node);
|
||||
|
||||
if (!_foundNgDirectives) {
|
||||
// The receiver for cascaded calls.
|
||||
writer.print(REFLECTOR_VAR_NAME);
|
||||
_foundNgDirectives = true;
|
||||
}
|
||||
writer.print('..registerType(');
|
||||
node.name.accept(this);
|
||||
writer.print(''', {'factory': ''');
|
||||
if (ctor == null) {
|
||||
_generateEmptyFactory(node.name.toString());
|
||||
} else {
|
||||
ctor.accept(_factoryVisitor);
|
||||
}
|
||||
writer.print(''', 'parameters': ''');
|
||||
if (ctor == null) {
|
||||
_generateEmptyParams();
|
||||
} else {
|
||||
ctor.accept(_paramsVisitor);
|
||||
}
|
||||
writer.print(''', 'annotations': ''');
|
||||
node.accept(_metaVisitor);
|
||||
writer.print('})');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -189,7 +188,7 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
@override
|
||||
Object visitPartOfDirective(PartOfDirective node) {
|
||||
// TODO(kegluneq): Consider importing [node.libraryName].
|
||||
logger.warning('[${importPath}]: '
|
||||
logger.warning('[${assetId}]: '
|
||||
'Found `part of` directive while generating ${DEPS_EXTENSION} file, '
|
||||
'Transform may fail due to missing imports in generated file.');
|
||||
return null;
|
||||
|
@ -202,41 +201,3 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
|||
@override
|
||||
Object visitSimpleIdentifier(SimpleIdentifier node) => _nodeToSource(node);
|
||||
}
|
||||
|
||||
const annotationNamesToKeep = const ['Injectable', 'Template'];
|
||||
|
||||
class _Tester {
|
||||
final Map<String, ClassDeclaration> _classesByName;
|
||||
|
||||
_Tester(Map<AssetId, List<ClassDeclaration>> assetClasses)
|
||||
: _classesByName = new Map.fromIterables(assetClasses.values
|
||||
.expand((classes) => classes.map((c) => c.name.toString())),
|
||||
assetClasses.values.expand((list) => list));
|
||||
|
||||
bool _shouldKeepMeta(Annotation meta) =>
|
||||
_shouldKeepClass(_classesByName[meta.name.name]);
|
||||
|
||||
bool _shouldKeepClass(ClassDeclaration next) {
|
||||
while (next != null) {
|
||||
if (annotationNamesToKeep.contains(next.name.name)) return true;
|
||||
|
||||
// Check classes that this class implements.
|
||||
if (next.implementsClause != null) {
|
||||
for (var interface in next.implementsClause.interfaces) {
|
||||
if (_shouldKeepClass(_classesByName[interface.name.name])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the class that this class extends.
|
||||
if (next.extendsClause != null && next.extendsClause.superclass != null) {
|
||||
next = _classesByName[next.extendsClause.superclass.name.name];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ library angular2.transform.directive_processor.transformer;
|
|||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
import 'package:angular2/src/transform/common/classdef_parser.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:angular2/src/transform/common/options.dart';
|
||||
|
@ -34,10 +32,9 @@ class DirectiveProcessor extends Transformer {
|
|||
|
||||
try {
|
||||
var asset = transform.primaryInput;
|
||||
var reader = new AssetReader.fromTransform(transform);
|
||||
var defMap = await createTypeMap(reader, asset.id);
|
||||
var assetCode = await asset.readAsString();
|
||||
var ngDepsSrc = createNgDeps(assetCode, asset.id.path, defMap);
|
||||
var ngDepsSrc =
|
||||
createNgDeps(assetCode, asset.id, options.annotationMatcher);
|
||||
if (ngDepsSrc != null && ngDepsSrc.isNotEmpty) {
|
||||
var ngDepsAssetId =
|
||||
transform.primaryInput.id.changeExtension(DEPS_EXTENSION);
|
||||
|
|
|
@ -2,8 +2,8 @@ library angular2.test.transform.directive_processor.all_tests;
|
|||
|
||||
import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/transform/directive_processor/rewriter.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import '../common/read_file.dart';
|
||||
import 'package:angular2/src/transform/common/classdef_parser.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:guinness/guinness.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
@ -18,28 +18,40 @@ void allTests() {
|
|||
_testNgDeps('should preserve parameter annotations as const instances.',
|
||||
'parameter_metadata/soup.dart');
|
||||
|
||||
_testNgDeps('should recognize annotations which extend Injectable.',
|
||||
'custom_metadata/tortilla_soup.dart');
|
||||
_testNgDeps('should recognize custom annotations with package: imports',
|
||||
'custom_metadata/package_soup.dart',
|
||||
customDescriptors: [
|
||||
const AnnotationDescriptor('Soup', 'package:soup/soup.dart', 'Component'),
|
||||
]);
|
||||
|
||||
_testNgDeps('should recognize annotations which implement Injectable.',
|
||||
'custom_metadata/chicken_soup.dart');
|
||||
_testNgDeps('should recognize custom annotations with relative imports',
|
||||
'custom_metadata/relative_soup.dart',
|
||||
assetId: new AssetId('soup', 'lib/relative_soup.dart'),
|
||||
customDescriptors: [
|
||||
const AnnotationDescriptor(
|
||||
'Soup', 'package:soup/annotations/soup.dart', 'Component'),
|
||||
]);
|
||||
|
||||
_testNgDeps(
|
||||
'should recognize annotations which implement a class that extends '
|
||||
'Injectable.', 'custom_metadata/chicken_soup.dart');
|
||||
_testNgDeps('Requires the specified import.', 'custom_metadata/bad_soup.dart',
|
||||
customDescriptors: [
|
||||
const AnnotationDescriptor('Soup', 'package:soup/soup.dart', 'Component'),
|
||||
]);
|
||||
}
|
||||
|
||||
void _testNgDeps(String name, String inputPath) {
|
||||
void _testNgDeps(String name, String inputPath,
|
||||
{List<AnnotationDescriptor> customDescriptors: const [], AssetId assetId}) {
|
||||
it(name, () async {
|
||||
var inputId = _assetIdForPath(inputPath);
|
||||
var reader = new TestAssetReader();
|
||||
var defMap = await createTypeMap(reader, inputId);
|
||||
var input = await reader.readAsString(inputId);
|
||||
var output = formatter.format(createNgDeps(input, inputPath, defMap));
|
||||
var annotationMatcher = new AnnotationMatcher()..addAll(customDescriptors);
|
||||
var proxyInputId = assetId != null ? assetId : inputId;
|
||||
var output =
|
||||
formatter.format(createNgDeps(input, proxyInputId, annotationMatcher));
|
||||
var expectedPath = path.join(path.dirname(inputPath), 'expected',
|
||||
path.basename(inputPath).replaceFirst('.dart', '.ng_deps.dart'));
|
||||
var expected = await reader.readAsString(_assetIdForPath(expectedPath));
|
||||
expect(output).toEqual(expected);
|
||||
var expectedId = _assetIdForPath(expectedPath);
|
||||
expect(output).toEqual(await reader.readAsString(expectedId));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
library dinner.bad_soup;
|
||||
|
||||
// No recognized import for [Soup]
|
||||
|
||||
@Soup()
|
||||
class BadSoup {
|
||||
BadSoup();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
library dinner.bad_soup.ng_deps.dart;
|
||||
|
||||
import 'bad_soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
library dinner.package_soup.ng_deps.dart;
|
||||
|
||||
import 'package_soup.dart';
|
||||
import 'package:soup/soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(PackageSoup, {
|
||||
'factory': () => new PackageSoup(),
|
||||
'parameters': const [],
|
||||
'annotations': const [const Soup()]
|
||||
});
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
library dinner.relative_soup.ng_deps.dart;
|
||||
|
||||
import 'relative_soup.dart';
|
||||
import 'annotations/soup.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(RelativeSoup, {
|
||||
'factory': () => new RelativeSoup(),
|
||||
'parameters': const [],
|
||||
'annotations': const [const Soup()]
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
library dinner.package_soup;
|
||||
|
||||
import 'package:soup/soup.dart';
|
||||
|
||||
@Soup()
|
||||
class PackageSoup {
|
||||
PackageSoup();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
library dinner.relative_soup;
|
||||
|
||||
import 'annotations/soup.dart';
|
||||
|
||||
@Soup()
|
||||
class RelativeSoup {
|
||||
RelativeSoup();
|
||||
}
|
Loading…
Reference in New Issue