From 7986e7ce7e2b40ef74d54db9daacf40d2990a4f4 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald Date: Tue, 30 Jun 2015 08:39:03 -0700 Subject: [PATCH] feat(transformer): Support @Injectable() on static functions --- modules/angular2/src/reflection/reflector.ts | 20 ++++++----- .../directive_processor/rewriter.dart | 34 ++++++++++++++++--- .../directive_processor/all_tests.dart | 3 ++ .../expected/hello.ng_deps.dart | 20 +++++++++++ .../static_function_files/hello.dart | 11 ++++++ 5 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 modules/angular2/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart create mode 100644 modules/angular2/test/transform/directive_processor/static_function_files/hello.dart diff --git a/modules/angular2/src/reflection/reflector.ts b/modules/angular2/src/reflection/reflector.ts index b6f91829cc..4ed7431753 100644 --- a/modules/angular2/src/reflection/reflector.ts +++ b/modules/angular2/src/reflection/reflector.ts @@ -13,22 +13,26 @@ export {SetterFn, GetterFn, MethodFn} from './types'; export {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; export class Reflector { - _typeInfo: Map; + _injectableInfo: Map>; _getters: Map; _setters: Map; _methods: Map; reflectionCapabilities: PlatformReflectionCapabilities; constructor(reflectionCapabilities: PlatformReflectionCapabilities) { - this._typeInfo = new Map(); + this._injectableInfo = new Map(); this._getters = new Map(); this._setters = new Map(); this._methods = new Map(); this.reflectionCapabilities = reflectionCapabilities; } + registerFunction(func: Function, funcInfo: StringMap): void { + this._injectableInfo.set(func, funcInfo); + } + registerType(type: Type, typeInfo: StringMap): void { - this._typeInfo.set(type, typeInfo); + this._injectableInfo.set(type, typeInfo); } registerGetters(getters: StringMap): void { @@ -52,7 +56,7 @@ export class Reflector { } parameters(typeOrFunc): List { - if (this._typeInfo.has(typeOrFunc)) { + if (this._injectableInfo.has(typeOrFunc)) { return this._getTypeInfoField(typeOrFunc, "parameters", []); } else { return this.reflectionCapabilities.parameters(typeOrFunc); @@ -60,7 +64,7 @@ export class Reflector { } annotations(typeOrFunc): List { - if (this._typeInfo.has(typeOrFunc)) { + if (this._injectableInfo.has(typeOrFunc)) { return this._getTypeInfoField(typeOrFunc, "annotations", []); } else { return this.reflectionCapabilities.annotations(typeOrFunc); @@ -68,7 +72,7 @@ export class Reflector { } interfaces(type): List { - if (this._typeInfo.has(type)) { + if (this._injectableInfo.has(type)) { return this._getTypeInfoField(type, "interfaces", []); } else { return this.reflectionCapabilities.interfaces(type); @@ -100,11 +104,11 @@ export class Reflector { } _getTypeInfoField(typeOrFunc, key, defaultValue) { - var res = this._typeInfo.get(typeOrFunc)[key]; + var res = this._injectableInfo.get(typeOrFunc)[key]; return isPresent(res) ? res : defaultValue; } - _containsTypeInfo(typeOrFunc) { return this._typeInfo.has(typeOrFunc); } + _containsTypeInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); } } function _mergeMaps(target: Map, config: StringMap): void { diff --git a/modules/angular2/src/transform/directive_processor/rewriter.dart b/modules/angular2/src/transform/directive_processor/rewriter.dart index 4f47004ab8..6dc86d81bf 100644 --- a/modules/angular2/src/transform/directive_processor/rewriter.dart +++ b/modules/angular2/src/transform/directive_processor/rewriter.dart @@ -172,11 +172,7 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { var ctor = _getCtor(node); - if (!_foundNgInjectable) { - // The receiver for cascaded calls. - writer.print(REFLECTOR_VAR_NAME); - _foundNgInjectable = true; - } + _maybeWriteReflector(); writer.print('..registerType('); node.name.accept(this); writer.print(''', {'factory': '''); @@ -236,4 +232,32 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor { @override Object visitSimpleIdentifier(SimpleIdentifier node) => _nodeToSource(node); + + @override + bool visitFunctionDeclaration(FunctionDeclaration node) { + if (!node.metadata.any((a) => _annotationMatcher.hasMatch(a, assetId))) { + return null; + } + + _maybeWriteReflector(); + writer.print('..registerFunction('); + node.name.accept(this); + writer.print(''', {'parameters': const ['''); + var parameters = node.childEntities + .firstWhere((child) => child is FunctionExpression).parameters; + parameters.accept(_paramsVisitor); + writer.print('''], 'annotations': '''); + node.metadata.accept(_metaVisitor); + 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(REFLECTOR_VAR_NAME); + } } diff --git a/modules/angular2/test/transform/directive_processor/all_tests.dart b/modules/angular2/test/transform/directive_processor/all_tests.dart index 5dce1bad0f..347705cf81 100644 --- a/modules/angular2/test/transform/directive_processor/all_tests.dart +++ b/modules/angular2/test/transform/directive_processor/all_tests.dart @@ -93,6 +93,9 @@ void allTests() { 'ERROR: Could not read asset at uri bad_relative_url.css from angular2|' 'test/transform/directive_processor/invalid_url_files/hello.dart' ]); + + _testNgDeps('should find and register static functions.', + 'static_function_files/hello.dart'); } void _testNgDeps(String name, String inputPath, diff --git a/modules/angular2/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart b/modules/angular2/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart new file mode 100644 index 0000000000..045b25032a --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/static_function_files/expected/hello.ng_deps.dart @@ -0,0 +1,20 @@ +library static_function_files.hello.ng_deps.dart; + +import 'hello.dart'; +import 'package:angular2/angular2.dart'; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerFunction(getMessage, { + 'parameters': const [const [const Inject(Message)]], + 'annotations': const Injectable() + }) + ..registerType(Message, { + 'factory': () => new Message(), + 'parameters': const [], + 'annotations': const [const Injectable()] + }); +} diff --git a/modules/angular2/test/transform/directive_processor/static_function_files/hello.dart b/modules/angular2/test/transform/directive_processor/static_function_files/hello.dart new file mode 100644 index 0000000000..a9ac2ddd9c --- /dev/null +++ b/modules/angular2/test/transform/directive_processor/static_function_files/hello.dart @@ -0,0 +1,11 @@ +library static_function_files.hello; + +import 'package:angular2/angular2.dart'; + +@Injectable() +String getMessage(@Inject(Message) message) => message.value; + +@Injectable() +class Message { + String value = 'hello!'; +}