2016-06-23 09:47:54 -07:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2016-07-18 03:50:31 -07:00
|
|
|
import {AttributeMetadata, ComponentMetadata, ContentChildMetadata, ContentChildrenMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, HostMetadata, InjectMetadata, InjectableMetadata, InputMetadata, NgModuleMetadata, OptionalMetadata, OutputMetadata, PipeMetadata, Provider, QueryMetadata, SelfMetadata, SkipSelfMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
2016-06-08 16:38:52 -07:00
|
|
|
|
|
|
|
import {ReflectorReader} from './core_private';
|
2016-06-03 15:43:09 -07:00
|
|
|
|
2016-06-02 16:40:38 -07:00
|
|
|
const SUPPORTED_SCHEMA_VERSION = 1;
|
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
|
|
|
|
2016-06-08 16:38:52 -07:00
|
|
|
angularImportLocations(): {
|
|
|
|
coreDecorators: string,
|
|
|
|
diDecorators: string,
|
|
|
|
diMetadata: string,
|
2016-06-13 15:56:51 -07:00
|
|
|
diOpaqueToken: string,
|
2016-06-08 16:38:52 -07:00
|
|
|
animationMetadata: 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-06-13 15:56:51 -07:00
|
|
|
private opaqueToken: StaticSymbol;
|
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) => {
|
2016-07-27 02:05:07 -07:00
|
|
|
let prop = (<any[]>propData)
|
|
|
|
.find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method');
|
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;
|
2016-06-08 16:38:52 -07:00
|
|
|
let member: any[] = members ? members[lcProperty] : null;
|
2016-05-04 10:00:59 -07:00
|
|
|
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-05-03 09:24:09 -07:00
|
|
|
var metadata = Object.create(ctor.prototype);
|
2016-06-17 13:11:00 -07:00
|
|
|
ctor.apply(metadata, args);
|
2016-05-03 09:24:09 -07:00
|
|
|
return metadata;
|
2016-03-24 10:03:10 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-05-31 09:15:17 -07:00
|
|
|
private registerFunction(type: StaticSymbol, fn: any): void {
|
2016-06-17 13:11:00 -07:00
|
|
|
this.conversionMap.set(
|
|
|
|
type, (context: StaticSymbol, args: any[]) => { return fn.apply(undefined, args); });
|
2016-05-31 09:15:17 -07:00
|
|
|
}
|
|
|
|
|
2016-02-18 10:53:21 -08:00
|
|
|
private initializeConversionMap(): void {
|
2016-06-13 15:56:51 -07:00
|
|
|
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
|
2016-06-08 16:38:52 -07:00
|
|
|
this.host.angularImportLocations();
|
2016-06-13 15:56:51 -07:00
|
|
|
this.opaqueToken = this.host.findDeclaration(diOpaqueToken, 'OpaqueToken');
|
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-06-08 16:38:52 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'Host'), HostMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'Injectable'), InjectableMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'Self'), SelfMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'SkipSelf'), SkipSelfMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'Inject'), InjectMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diDecorators, 'Optional'), OptionalMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Attribute'), AttributeMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Query'), QueryMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ViewQuery'), ViewQueryMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ContentChild'), ContentChildMetadata);
|
2016-04-28 21:54:02 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildrenMetadata);
|
2016-06-08 16:38:52 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ViewChild'), ViewChildMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildrenMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Input'), InputMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Output'), OutputMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Pipe'), PipeMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'HostBinding'), HostBindingMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'HostListener'), HostListenerMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Directive'), DirectiveMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(coreDecorators, 'Component'), ComponentMetadata);
|
2016-06-28 09:54:42 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
2016-07-18 03:50:31 -07:00
|
|
|
this.host.findDeclaration(coreDecorators, 'NgModule'), NgModuleMetadata);
|
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-06-08 16:38:52 -07:00
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diMetadata, 'HostMetadata'), HostMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diMetadata, 'SelfMetadata'), SelfMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diMetadata, 'SkipSelfMetadata'), SkipSelfMetadata);
|
|
|
|
this.registerDecoratorOrConstructor(
|
|
|
|
this.host.findDeclaration(diMetadata, 'OptionalMetadata'), OptionalMetadata);
|
2016-05-31 09:15:17 -07:00
|
|
|
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'trigger'), trigger);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'state'), state);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'transition'), transition);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'style'), style);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'animate'), animate);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'keyframes'), keyframes);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'sequence'), sequence);
|
|
|
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'group'), group);
|
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;
|
2016-06-13 15:56:51 -07:00
|
|
|
let scope = BindingScope.empty;
|
|
|
|
let calling = new Map<StaticSymbol, boolean>();
|
2016-03-24 10:03:10 -07:00
|
|
|
|
2016-06-17 13:11:00 -07:00
|
|
|
function simplifyInContext(context: StaticSymbol, value: any, depth: number): any {
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
2016-06-13 15:56:51 -07:00
|
|
|
let staticSymbol: StaticSymbol;
|
|
|
|
if (expression['module']) {
|
|
|
|
staticSymbol = _this.host.findDeclaration(
|
|
|
|
expression['module'], expression['name'], context.filePath);
|
|
|
|
} else {
|
|
|
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
|
|
|
|
}
|
|
|
|
return staticSymbol;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
function resolveReferenceValue(staticSymbol: StaticSymbol): any {
|
|
|
|
let result: any = staticSymbol;
|
|
|
|
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
|
|
|
|
let declarationValue =
|
|
|
|
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
|
|
|
return declarationValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isOpaqueToken(context: StaticSymbol, value: any): boolean {
|
2016-06-13 15:56:51 -07:00
|
|
|
if (value && value.__symbolic === 'new' && value.expression) {
|
|
|
|
let target = value.expression;
|
|
|
|
if (target.__symbolic == 'reference') {
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
return sameSymbol(resolveReference(context, target), _this.opaqueToken);
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
return false;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
|
|
|
|
function simplifyCall(expression: any) {
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
let callContext: {[name: string]: string}|undefined = undefined;
|
2016-06-13 15:56:51 -07:00
|
|
|
if (expression['__symbolic'] == 'call') {
|
|
|
|
let target = expression['expression'];
|
2016-07-25 05:29:20 -07:00
|
|
|
let functionSymbol: StaticSymbol;
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
let targetFunction: any;
|
2016-07-26 10:18:35 -07:00
|
|
|
if (target) {
|
|
|
|
switch (target.__symbolic) {
|
|
|
|
case 'reference':
|
|
|
|
// Find the function to call.
|
|
|
|
callContext = {name: target.name};
|
|
|
|
functionSymbol = resolveReference(context, target);
|
|
|
|
targetFunction = resolveReferenceValue(functionSymbol);
|
|
|
|
break;
|
|
|
|
case 'select':
|
|
|
|
// Find the static method to call
|
|
|
|
if (target.expression.__symbolic == 'reference') {
|
|
|
|
functionSymbol = resolveReference(context, target.expression);
|
|
|
|
const classData = resolveReferenceValue(functionSymbol);
|
|
|
|
if (classData && classData.statics) {
|
|
|
|
targetFunction = classData.statics[target.member];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-06-17 13:11:00 -07:00
|
|
|
}
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
if (targetFunction && targetFunction['__symbolic'] == 'function') {
|
2016-07-25 05:29:20 -07:00
|
|
|
if (calling.get(functionSymbol)) {
|
2016-06-13 15:56:51 -07:00
|
|
|
throw new Error('Recursion not supported');
|
|
|
|
}
|
2016-07-25 05:29:20 -07:00
|
|
|
calling.set(functionSymbol, true);
|
2016-07-28 17:32:29 -07:00
|
|
|
try {
|
|
|
|
let value = targetFunction['value'];
|
|
|
|
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
|
|
|
// Determine the arguments
|
|
|
|
let args = (expression['arguments'] || []).map((arg: any) => simplify(arg));
|
|
|
|
let parameters: string[] = targetFunction['parameters'];
|
|
|
|
let functionScope = BindingScope.build();
|
|
|
|
for (let i = 0; i < parameters.length; i++) {
|
|
|
|
functionScope.define(parameters[i], args[i]);
|
|
|
|
}
|
|
|
|
let oldScope = scope;
|
|
|
|
let result: any;
|
|
|
|
try {
|
|
|
|
scope = functionScope.done();
|
|
|
|
result = simplifyInContext(functionSymbol, value, depth + 1);
|
|
|
|
} finally {
|
|
|
|
scope = oldScope;
|
|
|
|
}
|
|
|
|
return result;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-07-28 17:32:29 -07:00
|
|
|
} finally {
|
|
|
|
calling.delete(functionSymbol);
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-17 13:11:00 -07:00
|
|
|
if (depth === 0) {
|
|
|
|
// If depth is 0 we are evaluating the top level expression that is describing element
|
|
|
|
// decorator. In this case, it is a decorator we don't understand, such as a custom
|
|
|
|
// non-angular decorator, and we should just ignore it.
|
|
|
|
return {__symbolic: 'ignore'};
|
|
|
|
}
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
return simplify(
|
|
|
|
{__symbolic: 'error', message: 'Function call not supported', context: callContext});
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function simplify(expression: any): any {
|
|
|
|
if (isPrimitive(expression)) {
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
if (expression instanceof Array) {
|
|
|
|
let result: any[] = [];
|
|
|
|
for (let item of (<any>expression)) {
|
|
|
|
// Check for a spread expression
|
|
|
|
if (item && item.__symbolic === 'spread') {
|
|
|
|
let spreadArray = simplify(item.expression);
|
|
|
|
if (Array.isArray(spreadArray)) {
|
|
|
|
for (let spreadItem of spreadArray) {
|
|
|
|
result.push(spreadItem);
|
|
|
|
}
|
|
|
|
continue;
|
2016-05-07 08:58:20 -06:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
2016-06-17 13:11:00 -07:00
|
|
|
let value = simplify(item);
|
|
|
|
if (shouldIgnore(value)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
result.push(value);
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if (expression) {
|
|
|
|
if (expression['__symbolic']) {
|
|
|
|
let staticSymbol: StaticSymbol;
|
|
|
|
switch (expression['__symbolic']) {
|
|
|
|
case 'binop':
|
|
|
|
let left = simplify(expression['left']);
|
2016-06-17 13:11:00 -07:00
|
|
|
if (shouldIgnore(left)) return left;
|
2016-06-13 15:56:51 -07:00
|
|
|
let right = simplify(expression['right']);
|
2016-06-17 13:11:00 -07:00
|
|
|
if (shouldIgnore(right)) return right;
|
2016-06-13 15:56:51 -07:00
|
|
|
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-07-28 17:32:29 -07:00
|
|
|
case 'if':
|
|
|
|
let condition = simplify(expression['condition']);
|
|
|
|
return condition ? simplify(expression['thenExpression']) :
|
|
|
|
simplify(expression['elseExpression']);
|
2016-06-13 15:56:51 -07:00
|
|
|
case 'pre':
|
|
|
|
let operand = simplify(expression['operand']);
|
2016-06-17 13:11:00 -07:00
|
|
|
if (shouldIgnore(operand)) return operand;
|
2016-06-13 15:56:51 -07:00
|
|
|
switch (expression['operator']) {
|
|
|
|
case '+':
|
|
|
|
return operand;
|
|
|
|
case '-':
|
|
|
|
return -operand;
|
|
|
|
case '!':
|
|
|
|
return !operand;
|
|
|
|
case '~':
|
|
|
|
return ~operand;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
case 'index':
|
|
|
|
let indexTarget = simplify(expression['expression']);
|
|
|
|
let index = simplify(expression['index']);
|
|
|
|
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
|
|
|
return null;
|
|
|
|
case 'select':
|
|
|
|
let selectTarget = simplify(expression['expression']);
|
2016-07-27 19:26:59 -07:00
|
|
|
if (selectTarget instanceof StaticSymbol) {
|
|
|
|
// Access to a static instance variable
|
|
|
|
const declarationValue = resolveReferenceValue(selectTarget);
|
|
|
|
if (declarationValue && declarationValue.statics) {
|
|
|
|
selectTarget = declarationValue.statics;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const member = simplify(expression['member']);
|
|
|
|
if (selectTarget && isPrimitive(member)) return simplify(selectTarget[member]);
|
2016-06-13 15:56:51 -07:00
|
|
|
return null;
|
|
|
|
case 'reference':
|
|
|
|
if (!expression.module) {
|
|
|
|
let name: string = expression['name'];
|
|
|
|
let localValue = scope.resolve(name);
|
|
|
|
if (localValue != BindingScope.missing) {
|
|
|
|
return localValue;
|
|
|
|
}
|
2016-04-29 14:34:01 -07:00
|
|
|
}
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
staticSymbol = resolveReference(context, expression);
|
2016-06-13 15:56:51 -07:00
|
|
|
let result: any = staticSymbol;
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
let declarationValue = resolveReferenceValue(result);
|
2016-06-13 15:56:51 -07:00
|
|
|
if (declarationValue) {
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
if (isOpaqueToken(staticSymbol, declarationValue)) {
|
2016-06-13 15:56:51 -07:00
|
|
|
// If the referenced symbol is initalized by a new OpaqueToken we can keep the
|
|
|
|
// reference to the symbol.
|
|
|
|
return staticSymbol;
|
|
|
|
}
|
2016-06-17 13:11:00 -07:00
|
|
|
result = simplifyInContext(staticSymbol, declarationValue, depth + 1);
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
case 'class':
|
2016-04-29 16:27:21 -07:00
|
|
|
return context;
|
2016-06-13 15:56:51 -07:00
|
|
|
case 'function':
|
feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:
```
@AppModule({
modules: [BrowserModule],
precompile: [MainComponent],
providers: […], // additional providers
directives: […], // additional platform directives
pipes: […] // additional platform pipes
})
class MyModule {
constructor(appRef: ApplicationRef) {
appRef.bootstrap(MainComponent);
}
}
// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);
// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```
The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.
Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
public so that the offline compiler can resolve the token
BREAKING CHANGES:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler). Inject `Compiler` instead.
To provide custom providers for the compiler,
create a custom compiler via `browserCompiler({providers: [...]})`
and pass that into the `bootstrap` method.
2016-06-30 13:07:17 -07:00
|
|
|
return context;
|
2016-06-13 15:56:51 -07:00
|
|
|
case 'new':
|
|
|
|
case 'call':
|
|
|
|
// Determine if the function is a built-in conversion
|
|
|
|
let target = expression['expression'];
|
|
|
|
if (target['module']) {
|
|
|
|
staticSymbol = _this.host.findDeclaration(
|
|
|
|
target['module'], target['name'], context.filePath);
|
|
|
|
} else {
|
|
|
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
|
|
|
|
}
|
|
|
|
let converter = _this.conversionMap.get(staticSymbol);
|
|
|
|
if (converter) {
|
2016-06-17 13:11:00 -07:00
|
|
|
let args: any[] = expression['arguments'];
|
2016-06-13 15:56:51 -07:00
|
|
|
if (!args) {
|
|
|
|
args = [];
|
|
|
|
}
|
2016-06-17 13:11:00 -07:00
|
|
|
return converter(
|
|
|
|
context, args.map(arg => simplifyInContext(context, arg, depth + 1)));
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if the function is one we can simplify.
|
|
|
|
return simplifyCall(expression);
|
|
|
|
|
|
|
|
case 'error':
|
|
|
|
let message = produceErrorMessage(expression);
|
|
|
|
if (expression['line']) {
|
|
|
|
message =
|
2016-07-11 17:26:35 -07:00
|
|
|
`${message} (position ${expression['line']+1}:${expression['character']+1} in the original .ts file)`;
|
2016-06-13 15:56:51 -07:00
|
|
|
}
|
|
|
|
throw new Error(message);
|
|
|
|
}
|
|
|
|
return null;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
return mapStringMap(expression, (value, name) => simplify(value));
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
return null;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
2016-06-13 15:56:51 -07:00
|
|
|
try {
|
|
|
|
return simplify(value);
|
|
|
|
} catch (e) {
|
|
|
|
throw new Error(`${e.message}, resolving symbol ${context.name} in ${context.filePath}`);
|
|
|
|
}
|
2016-06-03 15:43:09 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
|
2016-06-17 13:11:00 -07:00
|
|
|
let result = simplifyInContext(context, value, 0);
|
|
|
|
if (shouldIgnore(result)) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
return result;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
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-06-02 16:40:38 -07:00
|
|
|
if (Array.isArray(moduleMetadata)) {
|
2016-06-08 16:38:52 -07:00
|
|
|
moduleMetadata = (<Array<any>>moduleMetadata)
|
|
|
|
.find(element => element.version === SUPPORTED_SCHEMA_VERSION) ||
|
|
|
|
moduleMetadata[0];
|
2016-06-02 16:40:38 -07:00
|
|
|
}
|
2016-05-03 09:24:09 -07:00
|
|
|
if (!moduleMetadata) {
|
2016-06-08 16:38:52 -07:00
|
|
|
moduleMetadata =
|
|
|
|
{__symbolic: 'module', version: SUPPORTED_SCHEMA_VERSION, module: module, metadata: {}};
|
2016-06-02 16:40:38 -07:00
|
|
|
}
|
|
|
|
if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) {
|
2016-06-08 16:38:52 -07:00
|
|
|
throw new Error(
|
|
|
|
`Metadata version mismatch for module ${module}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`);
|
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-06-08 16:38:52 -07:00
|
|
|
result = {__symbolic: 'class'};
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2016-06-03 15:43:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function expandedMessage(error: any): string {
|
|
|
|
switch (error.message) {
|
|
|
|
case 'Reference to non-exported class':
|
|
|
|
if (error.context && error.context.className) {
|
|
|
|
return `Reference to a non-exported class ${error.context.className}`;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'Variable not initialized':
|
|
|
|
return 'Only initialized variables and constants can be referenced';
|
|
|
|
case 'Destructuring not supported':
|
|
|
|
return 'Referencing an exported destructured variable or constant is not supported';
|
|
|
|
case 'Could not resolve type':
|
|
|
|
if (error.context && error.context.typeName) {
|
|
|
|
return `Could not resolve type ${error.context.typeName}`;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'Function call not supported':
|
2016-06-17 13:11:00 -07:00
|
|
|
let prefix =
|
|
|
|
error.context && error.context.name ? `Calling function '${error.context.name}', f` : 'F';
|
|
|
|
return prefix +
|
|
|
|
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
|
2016-06-03 15:43:09 -07:00
|
|
|
}
|
|
|
|
return error.message;
|
|
|
|
}
|
|
|
|
|
|
|
|
function produceErrorMessage(error: any): string {
|
|
|
|
return `Error encountered resolving symbol values statically. ${expandedMessage(error)}`;
|
2016-03-24 10:03:10 -07:00
|
|
|
}
|
|
|
|
|
2016-06-08 16:38:52 -07: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-06-17 13:11:00 -07:00
|
|
|
Object.keys(input).forEach((key) => {
|
|
|
|
let value = transform(input[key], key);
|
|
|
|
if (!shouldIgnore(value)) {
|
|
|
|
result[key] = value;
|
|
|
|
}
|
|
|
|
});
|
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-06-08 16:38:52 -07:00
|
|
|
return o === null || (typeof o !== 'function' && typeof o !== 'object');
|
2016-05-26 15:07:51 -07:00
|
|
|
}
|
2016-06-13 15:56:51 -07:00
|
|
|
|
|
|
|
interface BindingScopeBuilder {
|
|
|
|
define(name: string, value: any): BindingScopeBuilder;
|
|
|
|
done(): BindingScope;
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract class BindingScope {
|
|
|
|
abstract resolve(name: string): any;
|
|
|
|
public static missing = {};
|
|
|
|
public static empty: BindingScope = {resolve: name => BindingScope.missing};
|
|
|
|
|
|
|
|
public static build(): BindingScopeBuilder {
|
|
|
|
let current = new Map<string, any>();
|
|
|
|
let parent: BindingScope = undefined;
|
|
|
|
return {
|
|
|
|
define: function(name, value) {
|
|
|
|
current.set(name, value);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
done: function() {
|
|
|
|
return current.size > 0 ? new PopulatedScope(current) : BindingScope.empty;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class PopulatedScope extends BindingScope {
|
|
|
|
constructor(private bindings: Map<string, any>) { super(); }
|
|
|
|
|
|
|
|
resolve(name: string): any {
|
|
|
|
return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function sameSymbol(a: StaticSymbol, b: StaticSymbol): boolean {
|
|
|
|
return a === b || (a.name == b.name && a.filePath == b.filePath);
|
|
|
|
}
|
2016-06-17 13:11:00 -07:00
|
|
|
|
|
|
|
function shouldIgnore(value: any): boolean {
|
|
|
|
return value && value.__symbolic == 'ignore';
|
2016-07-18 03:50:31 -07:00
|
|
|
}
|