refactor(compiler): support referenced `OpaqueToken`s correctly in offline compiler.

This commit is contained in:
Tobias Bosch 2016-04-29 16:27:21 -07:00 committed by Martin Probst
parent 176e55927c
commit 15f6b27ae0
2 changed files with 28 additions and 45 deletions

View File

@ -7,7 +7,6 @@ import {
isStringMap, isStringMap,
FunctionWrapper FunctionWrapper
} from 'angular2/src/facade/lang'; } from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import { import {
AttributeMetadata, AttributeMetadata,
DirectiveMetadata, DirectiveMetadata,
@ -35,11 +34,6 @@ import {
SkipSelfMetadata, SkipSelfMetadata,
InjectMetadata, InjectMetadata,
} from "angular2/src/core/di/metadata"; } from "angular2/src/core/di/metadata";
import {OpaqueToken} from 'angular2/src/core/di/opaque_token';
export class ModuleContext {
constructor(public moduleId: string, public filePath: string) {}
}
/** /**
* The host of the static resolver is expected to be able to provide module metadata in the form of * The host of the static resolver is expected to be able to provide module metadata in the form of
@ -71,7 +65,7 @@ export interface StaticReflectorHost {
* *
* This token is unique for a moduleId and name and can be used as a hash table key. * This token is unique for a moduleId and name and can be used as a hash table key.
*/ */
export class StaticSymbol implements ModuleContext { export class StaticSymbol {
constructor(public moduleId: string, public filePath: string, public name: string) {} constructor(public moduleId: string, public filePath: string, public name: string) {}
} }
@ -84,8 +78,7 @@ export class StaticReflector implements ReflectorReader {
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>(); private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
private parameterCache = new Map<StaticSymbol, any[]>(); private parameterCache = new Map<StaticSymbol, any[]>();
private metadataCache = new Map<string, {[key: string]: any}>(); private metadataCache = new Map<string, {[key: string]: any}>();
private conversionMap = private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
new Map<StaticSymbol, (moduleContext: ModuleContext, args: any[]) => any>();
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); } constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
@ -155,22 +148,20 @@ export class StaticReflector implements ReflectorReader {
} }
return parameters; return parameters;
} catch (e) { } catch (e) {
console.error('Failed on type', type, 'with error', e); console.log(`Failed on type ${type} with error ${e}`);
throw e; throw e;
} }
} }
private registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void { private registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
this.conversionMap.set(type, (moduleContext: ModuleContext, args: any[]) => { this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => {
let argValues = []; let argValues = [];
ListWrapper.forEachWithIndex(args, (arg, index) => { ListWrapper.forEachWithIndex(args, (arg, index) => {
let argValue; let argValue;
if (isStringMap(arg) && isBlank(arg['__symbolic'])) { if (isStringMap(arg) && isBlank(arg['__symbolic'])) {
argValue = argValue = mapStringMap(arg, (value, key) => this.simplify(context, value));
mapStringMap(arg, (value, key) => this.simplify(
moduleContext, value) );
} else { } else {
argValue = this.simplify(moduleContext, arg); argValue = this.simplify(context, arg);
} }
argValues.push(argValue); argValues.push(argValue);
}); });
@ -183,7 +174,6 @@ export class StaticReflector implements ReflectorReader {
let diDecorators = 'angular2/src/core/di/decorators'; let diDecorators = 'angular2/src/core/di/decorators';
let diMetadata = 'angular2/src/core/di/metadata'; let diMetadata = 'angular2/src/core/di/metadata';
let provider = 'angular2/src/core/di/provider'; let provider = 'angular2/src/core/di/provider';
let opaqueToken = 'angular2/src/core/di/opaque_token';
this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider); this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'), this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'),
@ -236,12 +226,10 @@ export class StaticReflector implements ReflectorReader {
SkipSelfMetadata); SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'), this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'),
OptionalMetadata); OptionalMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(opaqueToken, 'OpaqueToken'),
OpaqueToken);
} }
/** @internal */ /** @internal */
public simplify(moduleContext: ModuleContext, value: any): any { public simplify(context: StaticSymbol, value: any): any {
let _this = this; let _this = this;
function simplify(expression: any): any { function simplify(expression: any): any {
@ -331,41 +319,39 @@ export class StaticReflector implements ReflectorReader {
case "reference": case "reference":
if (isPresent(expression['module'])) { if (isPresent(expression['module'])) {
staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'], staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'],
moduleContext.filePath); context.filePath);
} else { } else {
staticSymbol = _this.host.getStaticSymbol( staticSymbol = _this.host.getStaticSymbol(context.moduleId, context.filePath,
moduleContext.moduleId, moduleContext.filePath, expression['name']); expression['name']);
} }
let result = staticSymbol; let result = staticSymbol;
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath); let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
let declarationValue = isPresent(moduleMetadata) ? moduleMetadata['metadata'][staticSymbol.name] : null; let declarationValue =
isPresent(moduleMetadata) ? moduleMetadata['metadata'][staticSymbol.name] : null;
if (isPresent(declarationValue)) { if (isPresent(declarationValue)) {
if (isClassMetadata(declarationValue)) { if (isClassMetadata(declarationValue)) {
result = staticSymbol; result = staticSymbol;
} else { } else {
let newModuleContext = result = _this.simplify(staticSymbol, declarationValue);
new ModuleContext(staticSymbol.moduleId, staticSymbol.filePath);
result = _this.simplify(newModuleContext, declarationValue);
} }
} }
return result; return result;
case "class":
return context;
case "new": case "new":
case "call": case "call":
let target = expression['expression']; let target = expression['expression'];
staticSymbol = _this.host.findDeclaration(target['module'], target['name'], staticSymbol =
moduleContext.filePath); _this.host.findDeclaration(target['module'], target['name'], context.filePath);
let converter = _this.conversionMap.get(staticSymbol); let converter = _this.conversionMap.get(staticSymbol);
if (isBlank(converter)) {
throw new BaseException(`Cannot convert call/new expression for ${target['name']} in ${moduleContext.filePath}`)
}
if (isPresent(converter)) { if (isPresent(converter)) {
let args = expression['arguments']; let args = expression['arguments'];
if (isBlank(args)) { if (isBlank(args)) {
args = []; args = [];
} }
return converter(moduleContext, args); return converter(context, args);
} else { } else {
return staticSymbol; return context;
} }
} }
return null; return null;

View File

@ -5,15 +5,14 @@ import {ListWrapper} from 'angular2/src/facade/collection';
import { import {
StaticReflector, StaticReflector,
StaticReflectorHost, StaticReflectorHost,
StaticSymbol, StaticSymbol
ModuleContext
} from 'angular2/src/compiler/static_reflector'; } from 'angular2/src/compiler/static_reflector';
export function main() { export function main() {
// Static reflector is not supported in Dart // Static reflector is not supported in Dart
// as we use reflection to create objects. // as we use reflection to create objects.
if (IS_DART) return; if (IS_DART) return;
let noContext = new ModuleContext('', ''); let noContext = new StaticSymbol('', '', '');
describe('StaticReflector', () => { describe('StaticReflector', () => {
let host: StaticReflectorHost; let host: StaticReflectorHost;
@ -24,8 +23,8 @@ export function main() {
reflector = new StaticReflector(host); reflector = new StaticReflector(host);
}); });
function simplify(moduleContext: ModuleContext, value: any) { function simplify(context: StaticSymbol, value: any) {
return reflector.simplify(moduleContext, value); return reflector.simplify(context, value);
} }
it('should get annotations for NgFor', () => { it('should get annotations for NgFor', () => {
@ -219,9 +218,7 @@ export function main() {
}); });
it('should simplify an array index', () => { it('should simplify an array index', () => {
expect( expect(simplify(noContext, ({__symbolic: "index", expression: [1, 2, 3], index: 2}))).toBe(3);
simplify(noContext, ({__symbolic: "index", expression: [1, 2, 3], index: 2})))
.toBe(3);
}); });
it('should simplify an object index', () => { it('should simplify an object index', () => {
@ -230,14 +227,14 @@ export function main() {
}); });
it('should simplify a module reference', () => { it('should simplify a module reference', () => {
expect(simplify(new ModuleContext('', '/src/cases'), expect(simplify(new StaticSymbol('', '/src/cases', ''),
({__symbolic: "reference", module: "./extern", name: "s"}))) ({__symbolic: "reference", module: "./extern", name: "s"})))
.toEqual("s"); .toEqual("s");
}); });
it('should simplify a non existing reference as a static symbol', () => { it('should simplify a non existing reference as a static symbol', () => {
expect(simplify(new ModuleContext('', '/src/cases'), expect(simplify(new StaticSymbol('', '/src/cases', ''),
({__symbolic: "reference", module: "./extern", name: "nonExisting"}))) ({__symbolic: "reference", module: "./extern", name: "nonExisting"})))
.toEqual(host.getStaticSymbol('', '/src/extern.d.ts', 'nonExisting')); .toEqual(host.getStaticSymbol('', '/src/extern.d.ts', 'nonExisting'));
}); });
}); });