Skip to content

Commit

Permalink
fix(transformer): Support prefixed annotations in the transformer.
Browse files Browse the repository at this point in the history
closes #2754
  • Loading branch information
jakemac53 committed Jul 7, 2015
1 parent 569766f commit 9e1158d
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 7 deletions.
30 changes: 25 additions & 5 deletions modules/angular2/src/transform/common/annotation_matcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,37 @@ class AnnotationMatcher {
// Checks if an [Annotation] matches an [AnnotationDescriptor].
static bool _matchAnnotation(
Annotation annotation, AnnotationDescriptor descriptor, AssetId assetId) {
if (annotation.name.name != descriptor.name) return false;
String name;
Identifier prefix;
if (annotation.name is PrefixedIdentifier) {
// TODO(jakemac): Shouldn't really need a cast here, remove once
// https://github.com/dart-lang/sdk/issues/23798 is fixed.
var prefixedName = annotation.name as PrefixedIdentifier;
name = prefixedName.identifier.name;
prefix = prefixedName.prefix;
} else {
name = annotation.name.name;
}
if (name != descriptor.name) return false;
return (annotation.root as CompilationUnit).directives
.where((d) => d is ImportDirective)
.any((ImportDirective i) {
var importMatch = false;
var uriString = i.uri.stringValue;
if (uriString == descriptor.import) return true;
if (uriString.startsWith('package:') || uriString.startsWith('dart:')) {
if (uriString == descriptor.import) {
importMatch = true;
} else if (uriString.startsWith('package:') ||
uriString.startsWith('dart:')) {
return false;
} else {
importMatch = descriptor.assetId ==
uriToAssetId(assetId, uriString, logger, null);
}
return descriptor.assetId ==
uriToAssetId(assetId, uriString, logger, null);

if (!importMatch) return false;
if (prefix == null) return i.prefix == null;
if (i.prefix == null) return false;
return prefix.name == i.prefix.name;
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ class ViewDefinitionEntry {
String _getComponentId(AssetId assetId, String className) => '$className';

// TODO(kegluenq): Improve this test.
bool _isViewAnnotation(InstanceCreationExpression node) =>
'${node.constructorName.type}' == 'View';
bool _isViewAnnotation(InstanceCreationExpression node) {
var constructorName = node.constructorName.type.name;
if (constructorName is PrefixedIdentifier) {
constructorName = constructorName.identifier;
}
return constructorName.name == 'View';
}

/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in
/// `entryPoint`.
Expand Down
104 changes: 104 additions & 0 deletions modules/angular2/test/transform/common/annotation_matcher_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
library angular2.test.transform.common.annotation_matcher_test;

import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:barback/barback.dart' show AssetId;
import 'package:guinness/guinness.dart';

main() {
allTests();
}

var simpleAst = parseCompilationUnit('''
import 'package:test/test.dart';
@Test()
var foo;
''');

var namespacedAst = parseCompilationUnit('''
import 'package:test/test.dart' as test;
@test.Test()
var foo;
''');

var relativePathAst = parseCompilationUnit('''
import 'test.dart';
@Test()
var foo;
''');

var namespacedRelativePathAst = parseCompilationUnit('''
import 'test.dart' as test;
@test.Test()
var foo;
''');

void allTests() {
it('should be able to match basic annotations.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Test', 'package:test/test.dart', null));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.length).toBe(1);
});

it('should be able to match namespaced annotations.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Test', 'package:test/test.dart', null));
var visitor = new MatchRecordingVisitor(matcher);
namespacedAst.accept(visitor);
expect(visitor.matches.length).toBe(1);
});

it('should be able to match relative imports.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Test', 'package:test/test.dart', null));
var visitor =
new MatchRecordingVisitor(matcher, new AssetId('test', 'lib/foo.dart'));
relativePathAst.accept(visitor);
expect(visitor.matches.length).toBe(1);
});

it('should be able to match relative imports with a namespace.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Test', 'package:test/test.dart', null));
var visitor =
new MatchRecordingVisitor(matcher, new AssetId('test', 'lib/foo.dart'));
namespacedRelativePathAst.accept(visitor);
expect(visitor.matches.length).toBe(1);
});

it('should not match annotations if the import is missing.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Test', 'package:test/foo.dart', null));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.isEmpty).toBeTrue();
});

it('should not match annotations if the name is different.', () {
var matcher = new AnnotationMatcher()
..add(const AnnotationDescriptor('Foo', 'package:test/test.dart', null));
var visitor = new MatchRecordingVisitor(matcher);
simpleAst.accept(visitor);
expect(visitor.matches.isEmpty).toBeTrue();
});
}

class MatchRecordingVisitor extends RecursiveAstVisitor {
final AssetId assetId;
final AnnotationMatcher matcher;
final List<Annotation> matches = [];

MatchRecordingVisitor(this.matcher, [this.assetId]) : super();

@override
void visitAnnotation(Annotation annotation) {
if (matcher.hasMatch(annotation, assetId)) matches.add(annotation);
}
}
12 changes: 12 additions & 0 deletions modules/angular2/test/transform/template_compiler/all_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import '../common/read_file.dart';

var formatter = new DartFormatter();

main() => allTests();

void allTests() {
Html5LibDomAdapter.makeCurrent();
AssetReader reader = new TestAssetReader();
Expand Down Expand Up @@ -93,6 +95,16 @@ void allTests() {
_formatThenExpectEquals(output, expected);
});

it('should parse angular directives with a prefix', () async {
var inputPath =
'template_compiler/with_prefix_files/ng2_prefix.ng_deps.dart';
var expected = readFile(
'template_compiler/with_prefix_files/expected/ng2_prefix.ng_deps.dart');

var output = await process(new AssetId('a', inputPath));
_formatThenExpectEquals(output, expected);
});

it('should create the same output for multiple calls.', () async {
var inputPath =
'template_compiler/inline_expression_files/hello.ng_deps.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
library angular2.test.transform.template_compiler.with_prefix_files.ng2_prefix.ng_deps.dart;

import 'ng2_prefix.dart';
import 'package:angular2/angular2.dart' as ng2
show bootstrap, Component, Directive, View, NgElement;

var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(MyApp, {
'factory': () => new MyApp(),
'parameters': const [const []],
'annotations': const [
const ng2.Component(selector: 'my-app'),
const ng2.View(template: 'MyApp {{name}}')
]
})
..registerGetters({'name': (o) => o.name})
..registerSetters({'name': (o, v) => o.name = v});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
library angular2.test.transform.template_compiler.with_prefix_files.ng2_prefix.ng_deps.dart;

import 'ng2_prefix.dart';
import 'package:angular2/angular2.dart' as ng2
show bootstrap, Component, Directive, View, NgElement;

var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(MyApp, {
'factory': () => new MyApp(),
'parameters': const [const []],
'annotations': const [
const ng2.Component(selector: 'my-app'),
const ng2.View(template: 'MyApp {{name}}')
]
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"MyApp":{
"id":"MyApp",
"selector":"my-app",
"compileChildren":true,
"host":{},
"properties":[],
"readAttributes":[],
"type":1,
"version":1
}
}

0 comments on commit 9e1158d

Please sign in to comment.