2016-04-12 09:40:37 -07:00
|
|
|
import {
|
|
|
|
AttributeMetadata,
|
|
|
|
DirectiveMetadata,
|
|
|
|
ComponentMetadata,
|
|
|
|
ContentChildrenMetadata,
|
|
|
|
ContentChildMetadata,
|
|
|
|
InputMetadata,
|
|
|
|
HostBindingMetadata,
|
|
|
|
HostListenerMetadata,
|
|
|
|
OutputMetadata,
|
|
|
|
PipeMetadata,
|
|
|
|
ViewChildMetadata,
|
|
|
|
ViewChildrenMetadata,
|
|
|
|
ViewQueryMetadata,
|
|
|
|
QueryMetadata,
|
2016-05-26 15:07:51 -07:00
|
|
|
Provider,
|
2016-02-18 10:53:21 -08:00
|
|
|
HostMetadata,
|
|
|
|
OptionalMetadata,
|
|
|
|
InjectableMetadata,
|
|
|
|
SelfMetadata,
|
|
|
|
SkipSelfMetadata,
|
2016-04-29 14:34:01 -07:00
|
|
|
InjectMetadata,
|
2016-04-28 17:50:03 -07:00
|
|
|
} from "@angular/core";
|
2016-05-26 15:07:51 -07:00
|
|
|
import {ReflectorReader} from "./core_private";
|
2016-04-28 21:54:02 -07:00
|
|
|
|
2016-03-24 10:03:10 -07:00
|
|
|
/**
|
|
|
|
* The host of the static resolver is expected to be able to provide module metadata in the form of
|
|
|
|
* ModuleMetadata. Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
|
|
|
* produced and the module has exported variables or classes with decorators. Module metadata can
|
|
|
|
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
|
|
|
*/
|
|
|
|
export interface StaticReflectorHost {
|
|
|
|
/**
|
2016-05-02 09:38:46 -07:00
|
|
|
* Return a ModuleMetadata for the given module.
|
2016-03-24 10:03:10 -07:00
|
|
|
*
|
2016-05-02 09:38:46 -07:00
|
|
|
* @param modulePath is a string identifier for a module as an absolute path.
|
2016-03-24 10:03:10 -07:00
|
|
|
* @returns the metadata for the given module.
|
|
|
|
*/
|
2016-02-18 10:53:21 -08:00
|
|
|
getMetadataFor(modulePath: string): {[key: string]: any};
|
2016-04-25 21:29:06 -07:00
|
|
|
|
|
|
|
/**
|
2016-04-28 21:54:02 -07:00
|
|
|
* Resolve a symbol from an import statement form, to the file where it is declared.
|
|
|
|
* @param module the location imported from
|
2016-04-25 21:29:06 -07:00
|
|
|
* @param containingFile for relative imports, the path of the file containing the import
|
|
|
|
*/
|
2016-04-28 21:54:02 -07:00
|
|
|
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
|
2016-02-18 10:53:21 -08:00
|
|
|
|
2016-05-02 09:38:46 -07:00
|
|
|
getStaticSymbol(declarationFile: string, name: string): StaticSymbol;
|
2016-05-01 11:22:39 -07:00
|
|
|
|
|
|
|
angularImportLocations():
|
|
|
|
{coreDecorators: string, diDecorators: string, diMetadata: string, provider: string};
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A token representing the a reference to a static type.
|
|
|
|
*
|
2016-05-02 09:38:46 -07:00
|
|
|
* This token is unique for a filePath and name and can be used as a hash table key.
|
2016-03-24 10:03:10 -07:00
|
|
|
*/
|
2016-04-29 16:27:21 -07:00
|
|
|
export class StaticSymbol {
|
2016-05-02 09:38:46 -07:00
|
|
|
constructor(public filePath: string, public name: string) {}
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A static reflector implements enough of the Reflector API that is necessary to compile
|
|
|
|
* templates statically.
|
|
|
|
*/
|
2016-02-18 10:53:21 -08:00
|
|
|
export class StaticReflector implements ReflectorReader {
|
2016-04-28 21:54:02 -07:00
|
|
|
private annotationCache = new Map<StaticSymbol, any[]>();
|
|
|
|
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
|
|
|
private parameterCache = new Map<StaticSymbol, any[]>();
|
2016-03-24 10:03:10 -07:00
|
|
|
private metadataCache = new Map<string, {[key: string]: any}>();
|
2016-04-29 16:27:21 -07:00
|
|
|
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
2016-02-18 10:53:21 -08:00
|
|
|
|
2016-03-24 10:03:10 -07:00
|
|
|
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
|
|
|
|
2016-05-03 17:31:40 -07:00
|
|
|
importUri(typeOrFunc: StaticSymbol): string {
|
|
|
|
var staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
|
|
|
return staticSymbol ? staticSymbol.filePath : null;
|
|
|
|
}
|
2016-02-18 10:53:21 -08:00
|
|
|
|
2016-04-28 21:54:02 -07:00
|
|
|
public annotations(type: StaticSymbol): any[] {
|
2016-03-24 10:03:10 -07:00
|
|
|
let annotations = this.annotationCache.get(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!annotations) {
|
2016-03-24 10:03:10 -07:00
|
|
|
let classMetadata = this.getTypeMetadata(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (classMetadata['decorators']) {
|
2016-04-29 14:34:01 -07:00
|
|
|
annotations = this.simplify(type, classMetadata['decorators']);
|
2016-04-08 15:39:21 -07:00
|
|
|
} else {
|
|
|
|
annotations = [];
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
this.annotationCache.set(type, annotations.filter(ann => !!ann));
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
return annotations;
|
|
|
|
}
|
|
|
|
|
2016-04-28 21:54:02 -07:00
|
|
|
public propMetadata(type: StaticSymbol): {[key: string]: any} {
|
2016-03-24 10:03:10 -07:00
|
|
|
let propMetadata = this.propertyCache.get(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!propMetadata) {
|
2016-03-24 10:03:10 -07:00
|
|
|
let classMetadata = this.getTypeMetadata(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
let members = classMetadata ? classMetadata['members'] : {};
|
2016-02-18 10:53:21 -08:00
|
|
|
propMetadata = mapStringMap(members, (propData, propName) => {
|
|
|
|
let prop = (<any[]>propData).find(a => a['__symbolic'] == 'property');
|
2016-05-03 09:24:09 -07:00
|
|
|
if (prop && prop['decorators']) {
|
2016-04-29 14:34:01 -07:00
|
|
|
return this.simplify(type, prop['decorators']);
|
2016-02-18 10:53:21 -08:00
|
|
|
} else {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
});
|
2016-03-24 10:03:10 -07:00
|
|
|
this.propertyCache.set(type, propMetadata);
|
|
|
|
}
|
|
|
|
return propMetadata;
|
|
|
|
}
|
|
|
|
|
2016-04-28 21:54:02 -07:00
|
|
|
public parameters(type: StaticSymbol): any[] {
|
2016-05-01 11:22:39 -07:00
|
|
|
if (!(type instanceof StaticSymbol)) {
|
2016-05-04 10:00:59 -07:00
|
|
|
throw new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
2016-05-01 11:22:39 -07:00
|
|
|
}
|
2016-04-29 14:34:01 -07:00
|
|
|
try {
|
|
|
|
let parameters = this.parameterCache.get(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!parameters) {
|
2016-04-29 14:34:01 -07:00
|
|
|
let classMetadata = this.getTypeMetadata(type);
|
2016-05-03 09:24:09 -07:00
|
|
|
let members = classMetadata ? classMetadata['members'] : null;
|
|
|
|
let ctorData = members ? members['__ctor__'] : null;
|
|
|
|
if (ctorData) {
|
2016-04-29 14:34:01 -07:00
|
|
|
let ctor = (<any[]>ctorData).find(a => a['__symbolic'] == 'constructor');
|
2016-05-04 10:00:59 -07:00
|
|
|
let parameterTypes = <any[]>this.simplify(type, ctor['parameters'] || []);
|
|
|
|
let parameterDecorators = <any[]>this.simplify(type, ctor['parameterDecorators'] || []);
|
2016-04-29 14:34:01 -07:00
|
|
|
|
|
|
|
parameters = [];
|
2016-05-03 18:49:59 -07:00
|
|
|
parameterTypes.forEach((paramType, index) => {
|
2016-04-30 12:27:37 -07:00
|
|
|
let nestedResult: any[] = [];
|
2016-05-03 09:24:09 -07:00
|
|
|
if (paramType) {
|
2016-04-29 14:34:01 -07:00
|
|
|
nestedResult.push(paramType);
|
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
let decorators = parameterDecorators ? parameterDecorators[index] : null;
|
|
|
|
if (decorators) {
|
|
|
|
nestedResult.push(...decorators);
|
2016-04-29 14:34:01 -07:00
|
|
|
}
|
|
|
|
parameters.push(nestedResult);
|
|
|
|
});
|
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!parameters) {
|
2016-04-29 14:34:01 -07:00
|
|
|
parameters = [];
|
|
|
|
}
|
|
|
|
this.parameterCache.set(type, parameters);
|
2016-04-08 15:39:21 -07:00
|
|
|
}
|
2016-04-29 14:34:01 -07:00
|
|
|
return parameters;
|
|
|
|
} catch (e) {
|
2016-05-01 11:22:39 -07:00
|
|
|
console.log(`Failed on type ${JSON.stringify(type)} with error ${e}`);
|
2016-04-29 14:34:01 -07:00
|
|
|
throw e;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-04 10:00:59 -07:00
|
|
|
hasLifecycleHook(type: any, lcInterface: /*Type*/ any, lcProperty: string): boolean {
|
|
|
|
if (!(type instanceof StaticSymbol)) {
|
|
|
|
throw new Error(
|
|
|
|
`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
|
|
|
}
|
|
|
|
let classMetadata = this.getTypeMetadata(type);
|
|
|
|
let members = classMetadata ? classMetadata['members'] : null;
|
|
|
|
let member:any[] = members ? members[lcProperty] : null;
|
|
|
|
return member ? member.some(a => a['__symbolic'] == 'method') : false;
|
|
|
|
}
|
|
|
|
|
2016-04-29 14:34:01 -07:00
|
|
|
private registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
|
2016-04-29 16:27:21 -07:00
|
|
|
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => {
|
2016-04-30 12:27:37 -07:00
|
|
|
let argValues: any[] = [];
|
2016-05-03 18:49:59 -07:00
|
|
|
args.forEach((arg, index) => {
|
2016-04-30 12:27:37 -07:00
|
|
|
let argValue: any;
|
2016-05-03 09:24:09 -07:00
|
|
|
if (typeof arg === 'object' && !arg['__symbolic']) {
|
2016-04-29 16:27:21 -07:00
|
|
|
argValue = mapStringMap(arg, (value, key) => this.simplify(context, value));
|
2016-02-18 10:53:21 -08:00
|
|
|
} else {
|
2016-04-29 16:27:21 -07:00
|
|
|
argValue = this.simplify(context, arg);
|
2016-02-18 10:53:21 -08:00
|
|
|
}
|
|
|
|
argValues.push(argValue);
|
2016-03-24 10:03:10 -07:00
|
|
|
});
|
2016-05-03 09:24:09 -07:00
|
|
|
var metadata = Object.create(ctor.prototype);
|
|
|
|
ctor.apply(metadata, argValues);
|
|
|
|
return metadata;
|
2016-03-24 10:03:10 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-18 10:53:21 -08:00
|
|
|
private initializeConversionMap(): void {
|
2016-05-01 11:22:39 -07:00
|
|
|
const {coreDecorators, diDecorators, diMetadata, provider} = this.host.angularImportLocations();
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider);
|
2016-03-24 10:03:10 -07:00
|
|
|
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'),
|
|
|
|
HostMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Injectable'),
|
2016-02-18 10:53:21 -08:00
|
|
|
InjectableMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'),
|
|
|
|
SelfMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'SkipSelf'),
|
2016-02-18 10:53:21 -08:00
|
|
|
SkipSelfMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'),
|
|
|
|
InjectMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Optional'),
|
2016-02-18 10:53:21 -08:00
|
|
|
OptionalMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Attribute'),
|
2016-02-18 10:53:21 -08:00
|
|
|
AttributeMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Query'),
|
|
|
|
QueryMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewQuery'),
|
2016-02-18 10:53:21 -08:00
|
|
|
ViewQueryMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ContentChild'),
|
2016-02-18 10:53:21 -08:00
|
|
|
ContentChildMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildrenMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChild'),
|
2016-02-18 10:53:21 -08:00
|
|
|
ViewChildMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChildren'),
|
2016-02-18 10:53:21 -08:00
|
|
|
ViewChildrenMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'),
|
|
|
|
InputMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Output'),
|
2016-02-18 10:53:21 -08:00
|
|
|
OutputMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'),
|
|
|
|
PipeMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostBinding'),
|
2016-02-18 10:53:21 -08:00
|
|
|
HostBindingMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostListener'),
|
2016-02-18 10:53:21 -08:00
|
|
|
HostListenerMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Directive'),
|
2016-04-29 14:34:01 -07:00
|
|
|
DirectiveMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Component'),
|
2016-04-29 14:34:01 -07:00
|
|
|
ComponentMetadata);
|
2016-03-24 10:03:10 -07:00
|
|
|
|
2016-02-18 10:53:21 -08:00
|
|
|
// Note: Some metadata classes can be used directly with Provider.deps.
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'HostMetadata'),
|
2016-02-18 10:53:21 -08:00
|
|
|
HostMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SelfMetadata'),
|
2016-02-18 10:53:21 -08:00
|
|
|
SelfMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SkipSelfMetadata'),
|
2016-02-18 10:53:21 -08:00
|
|
|
SkipSelfMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'),
|
2016-02-18 10:53:21 -08:00
|
|
|
OptionalMetadata);
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @internal */
|
2016-04-29 16:27:21 -07:00
|
|
|
public simplify(context: StaticSymbol, value: any): any {
|
2016-03-24 10:03:10 -07:00
|
|
|
let _this = this;
|
|
|
|
|
|
|
|
function simplify(expression: any): any {
|
|
|
|
if (isPrimitive(expression)) {
|
|
|
|
return expression;
|
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
if (expression instanceof Array) {
|
2016-04-30 12:27:37 -07:00
|
|
|
let result: any[] = [];
|
2016-04-12 09:40:37 -07:00
|
|
|
for (let item of(<any>expression)) {
|
2016-03-24 10:03:10 -07:00
|
|
|
result.push(simplify(item));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
if (expression) {
|
|
|
|
if (expression['__symbolic']) {
|
2016-04-30 12:27:37 -07:00
|
|
|
let staticSymbol: StaticSymbol;
|
2016-03-24 10:03:10 -07:00
|
|
|
switch (expression['__symbolic']) {
|
2016-04-12 09:40:37 -07:00
|
|
|
case "binop":
|
2016-03-24 10:03:10 -07:00
|
|
|
let left = simplify(expression['left']);
|
|
|
|
let right = simplify(expression['right']);
|
|
|
|
switch (expression['operator']) {
|
|
|
|
case '&&':
|
|
|
|
return left && right;
|
|
|
|
case '||':
|
|
|
|
return left || right;
|
|
|
|
case '|':
|
|
|
|
return left | right;
|
|
|
|
case '^':
|
|
|
|
return left ^ right;
|
|
|
|
case '&':
|
|
|
|
return left & right;
|
|
|
|
case '==':
|
|
|
|
return left == right;
|
|
|
|
case '!=':
|
|
|
|
return left != right;
|
|
|
|
case '===':
|
|
|
|
return left === right;
|
|
|
|
case '!==':
|
|
|
|
return left !== right;
|
|
|
|
case '<':
|
|
|
|
return left < right;
|
|
|
|
case '>':
|
|
|
|
return left > right;
|
|
|
|
case '<=':
|
|
|
|
return left <= right;
|
|
|
|
case '>=':
|
|
|
|
return left >= right;
|
|
|
|
case '<<':
|
|
|
|
return left << right;
|
|
|
|
case '>>':
|
|
|
|
return left >> right;
|
|
|
|
case '+':
|
|
|
|
return left + right;
|
|
|
|
case '-':
|
|
|
|
return left - right;
|
|
|
|
case '*':
|
|
|
|
return left * right;
|
|
|
|
case '/':
|
|
|
|
return left / right;
|
|
|
|
case '%':
|
|
|
|
return left % right;
|
|
|
|
}
|
|
|
|
return null;
|
2016-04-12 09:40:37 -07:00
|
|
|
case "pre":
|
2016-03-24 10:03:10 -07:00
|
|
|
let operand = simplify(expression['operand']);
|
|
|
|
switch (expression['operator']) {
|
|
|
|
case '+':
|
|
|
|
return operand;
|
|
|
|
case '-':
|
|
|
|
return -operand;
|
|
|
|
case '!':
|
|
|
|
return !operand;
|
|
|
|
case '~':
|
|
|
|
return ~operand;
|
|
|
|
}
|
|
|
|
return null;
|
2016-04-12 09:40:37 -07:00
|
|
|
case "index":
|
2016-03-24 10:03:10 -07:00
|
|
|
let indexTarget = simplify(expression['expression']);
|
|
|
|
let index = simplify(expression['index']);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
2016-03-24 10:03:10 -07:00
|
|
|
return null;
|
2016-04-12 09:40:37 -07:00
|
|
|
case "select":
|
2016-03-24 10:03:10 -07:00
|
|
|
let selectTarget = simplify(expression['expression']);
|
|
|
|
let member = simplify(expression['member']);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (selectTarget && isPrimitive(member)) return selectTarget[member];
|
2016-03-24 10:03:10 -07:00
|
|
|
return null;
|
2016-04-12 09:40:37 -07:00
|
|
|
case "reference":
|
2016-05-03 09:24:09 -07:00
|
|
|
if (expression['module']) {
|
2016-04-28 21:54:02 -07:00
|
|
|
staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'],
|
2016-04-29 16:27:21 -07:00
|
|
|
context.filePath);
|
2016-04-28 21:54:02 -07:00
|
|
|
} else {
|
2016-05-02 09:38:46 -07:00
|
|
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
|
2016-02-18 10:53:21 -08:00
|
|
|
}
|
2016-04-29 14:34:01 -07:00
|
|
|
let result = staticSymbol;
|
|
|
|
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
|
2016-04-29 16:27:21 -07:00
|
|
|
let declarationValue =
|
2016-05-03 09:24:09 -07:00
|
|
|
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
|
|
|
if (declarationValue) {
|
2016-05-02 16:45:58 -07:00
|
|
|
result = _this.simplify(staticSymbol, declarationValue);
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-02-18 10:53:21 -08:00
|
|
|
return result;
|
2016-04-29 16:27:21 -07:00
|
|
|
case "class":
|
|
|
|
return context;
|
2016-02-18 10:53:21 -08:00
|
|
|
case "new":
|
2016-04-12 09:40:37 -07:00
|
|
|
case "call":
|
2016-02-18 10:53:21 -08:00
|
|
|
let target = expression['expression'];
|
2016-05-07 08:58:20 -06:00
|
|
|
if (target['module']) {
|
|
|
|
staticSymbol =
|
2016-04-29 16:27:21 -07:00
|
|
|
_this.host.findDeclaration(target['module'], target['name'], context.filePath);
|
2016-05-07 08:58:20 -06:00
|
|
|
} else {
|
|
|
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
|
|
|
|
}
|
2016-04-28 21:54:02 -07:00
|
|
|
let converter = _this.conversionMap.get(staticSymbol);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (converter) {
|
2016-04-29 14:34:01 -07:00
|
|
|
let args = expression['arguments'];
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!args) {
|
2016-04-29 14:34:01 -07:00
|
|
|
args = [];
|
|
|
|
}
|
2016-04-29 16:27:21 -07:00
|
|
|
return converter(context, args);
|
2016-04-29 14:34:01 -07:00
|
|
|
} else {
|
2016-04-29 16:27:21 -07:00
|
|
|
return context;
|
2016-02-18 10:53:21 -08:00
|
|
|
}
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2016-02-18 10:53:21 -08:00
|
|
|
return mapStringMap(expression, (value, name) => simplify(value));
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return simplify(value);
|
|
|
|
}
|
|
|
|
|
2016-04-25 21:29:06 -07:00
|
|
|
/**
|
|
|
|
* @param module an absolute path to a module file.
|
|
|
|
*/
|
2016-02-18 10:53:21 -08:00
|
|
|
public getModuleMetadata(module: string): {[key: string]: any} {
|
2016-03-24 10:03:10 -07:00
|
|
|
let moduleMetadata = this.metadataCache.get(module);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!moduleMetadata) {
|
2016-03-24 10:03:10 -07:00
|
|
|
moduleMetadata = this.host.getMetadataFor(module);
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!moduleMetadata) {
|
2016-04-12 09:40:37 -07:00
|
|
|
moduleMetadata = {__symbolic: "module", module: module, metadata: {}};
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
this.metadataCache.set(module, moduleMetadata);
|
|
|
|
}
|
|
|
|
return moduleMetadata;
|
|
|
|
}
|
|
|
|
|
2016-04-28 21:54:02 -07:00
|
|
|
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
|
|
|
|
let moduleMetadata = this.getModuleMetadata(type.filePath);
|
2016-03-24 10:03:10 -07:00
|
|
|
let result = moduleMetadata['metadata'][type.name];
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!result) {
|
2016-04-12 09:40:37 -07:00
|
|
|
result = {__symbolic: "class"};
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 10:53:21 -08:00
|
|
|
function mapStringMap(input: {[key: string]: any},
|
|
|
|
transform: (value: any, key: string) => any): {[key: string]: any} {
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!input) return {};
|
2016-04-30 12:27:37 -07:00
|
|
|
var result: {[key: string]: any} = {};
|
2016-05-03 09:24:09 -07:00
|
|
|
Object.keys(input).forEach((key) => { result[key] = transform(input[key], key); });
|
2016-02-18 10:53:21 -08:00
|
|
|
return result;
|
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
|
2016-05-03 18:49:59 -07:00
|
|
|
function isPrimitive(o: any): boolean {
|
2016-05-03 09:24:09 -07:00
|
|
|
return o === null || (typeof o !== "function" && typeof o !== "object");
|
2016-05-26 15:07:51 -07:00
|
|
|
}
|