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-09-27 17:12:25 -07:00
import { Attribute , Component , ContentChild , ContentChildren , Directive , Host , HostBinding , HostListener , Inject , Injectable , Input , NgModule , Optional , Output , Pipe , Self , SkipSelf , ViewChild , ViewChildren , animate , group , keyframes , sequence , state , style , transition , trigger } from '@angular/core' ;
2016-12-15 09:12:40 -08:00
2016-11-14 17:37:47 -08:00
import { ReflectorReader } from '../private_import_core' ;
2017-01-27 13:19:00 -08:00
import { syntaxError } from '../util' ;
2016-06-03 15:43:09 -07:00
2017-01-04 13:59:43 -08:00
import { StaticSymbol } from './static_symbol' ;
import { StaticSymbolResolver } from './static_symbol_resolver' ;
2016-12-15 09:12:40 -08:00
2016-11-15 08:49:23 -08:00
const ANGULAR_IMPORT_LOCATIONS = {
coreDecorators : '@angular/core/src/metadata' ,
diDecorators : '@angular/core/src/di/metadata' ,
diMetadata : '@angular/core/src/di/metadata' ,
2017-01-03 16:54:46 -08:00
diInjectionToken : '@angular/core/src/di/injection_token' ,
diOpaqueToken : '@angular/core/src/di/injection_token' ,
2016-11-15 08:49:23 -08:00
animationMetadata : '@angular/core/src/animation/metadata' ,
provider : '@angular/core/src/di/provider'
} ;
2016-03-24 10:03:10 -07:00
2016-12-12 10:49:17 -08:00
const HIDDEN_KEY = /^\$.*\$$/ ;
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 [ ] > ( ) ;
2016-11-18 15:17:44 -08:00
private propertyCache = new Map < StaticSymbol , { [ key : string ] : any [ ] } > ( ) ;
2016-04-28 21:54:02 -07:00
private parameterCache = new Map < StaticSymbol , any [ ] > ( ) ;
2016-11-18 15:17:44 -08:00
private methodCache = new Map < StaticSymbol , { [ key : string ] : boolean } > ( ) ;
2016-04-29 16:27:21 -07:00
private conversionMap = new Map < StaticSymbol , ( context : StaticSymbol , args : any [ ] ) = > any > ( ) ;
2017-01-03 16:54:46 -08:00
private injectionToken : StaticSymbol ;
2016-06-13 15:56:51 -07:00
private opaqueToken : StaticSymbol ;
2016-02-18 10:53:21 -08:00
2016-11-18 16:58:14 -08:00
constructor (
2016-12-15 09:12:40 -08:00
private symbolResolver : StaticSymbolResolver ,
2016-11-18 15:17:44 -08:00
knownMetadataClasses : { name : string , filePath : string , ctor : any } [ ] = [ ] ,
2016-12-02 14:34:16 -08:00
knownMetadataFunctions : { name : string , filePath : string , fn : any } [ ] = [ ] ,
private errorRecorder ? : ( error : any , fileName : string ) = > void ) {
2016-11-18 16:58:14 -08:00
this . initializeConversionMap ( ) ;
2016-11-18 15:17:44 -08:00
knownMetadataClasses . forEach (
( kc ) = > this . _registerDecoratorOrConstructor (
this . getStaticSymbol ( kc . filePath , kc . name ) , kc . ctor ) ) ;
knownMetadataFunctions . forEach (
( kf ) = > this . _registerFunction ( this . getStaticSymbol ( kf . filePath , kf . name ) , kf . fn ) ) ;
2016-11-18 16:58:14 -08:00
}
2016-03-24 10:03:10 -07:00
2016-05-03 17:31:40 -07:00
importUri ( typeOrFunc : StaticSymbol ) : string {
2016-12-15 09:12:40 -08:00
const staticSymbol = this . findSymbolDeclaration ( typeOrFunc ) ;
2016-05-03 17:31:40 -07:00
return staticSymbol ? staticSymbol.filePath : null ;
}
2016-02-18 10:53:21 -08:00
2016-12-15 09:12:40 -08:00
resolveIdentifier ( name : string , moduleUrl : string ) : StaticSymbol {
return this . findDeclaration ( moduleUrl , name ) ;
}
findDeclaration ( moduleUrl : string , name : string , containingFile? : string ) : StaticSymbol {
return this . findSymbolDeclaration (
this . symbolResolver . getSymbolByModule ( moduleUrl , name , containingFile ) ) ;
}
findSymbolDeclaration ( symbol : StaticSymbol ) : StaticSymbol {
const resolvedSymbol = this . symbolResolver . resolveSymbol ( symbol ) ;
if ( resolvedSymbol && resolvedSymbol . metadata instanceof StaticSymbol ) {
return this . findSymbolDeclaration ( resolvedSymbol . metadata ) ;
} else {
return symbol ;
}
2016-08-24 17:39:49 -07:00
}
2016-08-29 08:52:25 -07:00
resolveEnum ( enumIdentifier : any , name : string ) : any {
const staticSymbol : StaticSymbol = enumIdentifier ;
2016-11-15 08:49:23 -08:00
return this . getStaticSymbol ( staticSymbol . filePath , staticSymbol . name , [ name ] ) ;
2016-08-24 17:39:49 -07: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-11-18 15:17:44 -08:00
annotations = [ ] ;
2016-11-12 14:08:58 +01:00
const classMetadata = this . getTypeMetadata ( type ) ;
2016-11-18 15:17:44 -08:00
if ( classMetadata [ 'extends' ] ) {
2017-01-27 15:35:31 -08:00
const parentType = this . trySimplify ( type , classMetadata [ 'extends' ] ) ;
2017-01-06 20:43:17 -08:00
if ( parentType && ( parentType instanceof StaticSymbol ) ) {
2016-12-27 09:36:47 -08:00
const parentAnnotations = this . annotations ( parentType ) ;
annotations . push ( . . . parentAnnotations ) ;
}
2016-11-18 15:17:44 -08:00
}
2016-05-03 09:24:09 -07:00
if ( classMetadata [ 'decorators' ] ) {
2016-11-18 15:17:44 -08:00
const ownAnnotations : any [ ] = this . simplify ( type , classMetadata [ 'decorators' ] ) ;
annotations . push ( . . . ownAnnotations ) ;
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-11-18 15:17:44 -08: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-12-15 09:12:40 -08:00
const classMetadata = this . getTypeMetadata ( type ) ;
2016-11-18 15:17:44 -08:00
propMetadata = { } ;
if ( classMetadata [ 'extends' ] ) {
2016-12-27 09:36:47 -08:00
const parentType = this . simplify ( type , classMetadata [ 'extends' ] ) ;
if ( parentType instanceof StaticSymbol ) {
const parentPropMetadata = this . propMetadata ( parentType ) ;
Object . keys ( parentPropMetadata ) . forEach ( ( parentProp ) = > {
propMetadata [ parentProp ] = parentPropMetadata [ parentProp ] ;
} ) ;
}
2016-11-18 15:17:44 -08:00
}
const members = classMetadata [ 'members' ] || { } ;
Object . keys ( members ) . forEach ( ( propName ) = > {
const propData = members [ propName ] ;
2016-11-12 14:08:58 +01:00
const prop = ( < any [ ] > propData )
. find ( a = > a [ '__symbolic' ] == 'property' || a [ '__symbolic' ] == 'method' ) ;
2016-11-18 15:17:44 -08:00
const decorators : any [ ] = [ ] ;
if ( propMetadata [ propName ] ) {
decorators . push ( . . . propMetadata [ propName ] ) ;
}
propMetadata [ propName ] = decorators ;
2016-05-03 09:24:09 -07:00
if ( prop && prop [ 'decorators' ] ) {
2016-11-18 15:17:44 -08:00
decorators . push ( . . . this . simplify ( type , prop [ 'decorators' ] ) ) ;
2016-02-18 10:53:21 -08:00
}
} ) ;
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-12-02 14:34:16 -08:00
this . reportError (
new Error ( ` parameters received ${ JSON . stringify ( type ) } which is not a StaticSymbol ` ) ,
type ) ;
return [ ] ;
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-11-12 14:08:58 +01:00
const classMetadata = this . getTypeMetadata ( type ) ;
const members = classMetadata ? classMetadata [ 'members' ] : null ;
const ctorData = members ? members [ '__ctor__' ] : null ;
2016-05-03 09:24:09 -07:00
if ( ctorData ) {
2016-11-12 14:08:58 +01:00
const ctor = ( < any [ ] > ctorData ) . find ( a = > a [ '__symbolic' ] == 'constructor' ) ;
const parameterTypes = < any [ ] > this . simplify ( type , ctor [ 'parameters' ] || [ ] ) ;
const 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-11-12 14:08:58 +01:00
const nestedResult : any [ ] = [ ] ;
2016-05-03 09:24:09 -07:00
if ( paramType ) {
2016-04-29 14:34:01 -07:00
nestedResult . push ( paramType ) ;
}
2016-11-12 14:08:58 +01:00
const decorators = parameterDecorators ? parameterDecorators [ index ] : null ;
2016-05-03 09:24:09 -07:00
if ( decorators ) {
nestedResult . push ( . . . decorators ) ;
2016-04-29 14:34:01 -07:00
}
parameters . push ( nestedResult ) ;
} ) ;
2016-11-18 15:17:44 -08:00
} else if ( classMetadata [ 'extends' ] ) {
2016-12-27 09:36:47 -08:00
const parentType = this . simplify ( type , classMetadata [ 'extends' ] ) ;
if ( parentType instanceof StaticSymbol ) {
parameters = this . parameters ( parentType ) ;
}
2016-04-29 14:34:01 -07:00
}
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-11-22 13:29:53 -08:00
console . error ( ` 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-11-18 15:17:44 -08:00
private _methodNames ( type : any ) : { [ key : string ] : boolean } {
let methodNames = this . methodCache . get ( type ) ;
if ( ! methodNames ) {
2016-12-15 09:12:40 -08:00
const classMetadata = this . getTypeMetadata ( type ) ;
2016-11-18 15:17:44 -08:00
methodNames = { } ;
if ( classMetadata [ 'extends' ] ) {
2016-12-27 09:36:47 -08:00
const parentType = this . simplify ( type , classMetadata [ 'extends' ] ) ;
if ( parentType instanceof StaticSymbol ) {
const parentMethodNames = this . _methodNames ( parentType ) ;
Object . keys ( parentMethodNames ) . forEach ( ( parentProp ) = > {
methodNames [ parentProp ] = parentMethodNames [ parentProp ] ;
} ) ;
}
2016-11-18 15:17:44 -08:00
}
const members = classMetadata [ 'members' ] || { } ;
Object . keys ( members ) . forEach ( ( propName ) = > {
const propData = members [ propName ] ;
const isMethod = ( < any [ ] > propData ) . some ( a = > a [ '__symbolic' ] == 'method' ) ;
methodNames [ propName ] = methodNames [ propName ] || isMethod ;
} ) ;
this . methodCache . set ( type , methodNames ) ;
}
return methodNames ;
}
2016-10-12 10:05:32 -07:00
hasLifecycleHook ( type : any , lcProperty : string ) : boolean {
2016-05-04 10:00:59 -07:00
if ( ! ( type instanceof StaticSymbol ) ) {
2016-12-02 14:34:16 -08:00
this . reportError (
new Error (
` hasLifecycleHook received ${ JSON . stringify ( type ) } which is not a StaticSymbol ` ) ,
type ) ;
2016-05-04 10:00:59 -07:00
}
2016-11-18 15:17:44 -08:00
try {
return ! ! this . _methodNames ( type ) [ lcProperty ] ;
} catch ( e ) {
console . error ( ` Failed on type ${ JSON . stringify ( type ) } with error ${ e } ` ) ;
throw e ;
}
2016-05-04 10:00:59 -07:00
}
2016-11-18 15:17:44 -08:00
private _registerDecoratorOrConstructor ( type : StaticSymbol , ctor : any ) : void {
2016-09-12 09:44:20 -07:00
this . conversionMap . set ( type , ( context : StaticSymbol , args : any [ ] ) = > new ctor ( . . . args ) ) ;
2016-03-24 10:03:10 -07:00
}
2016-11-18 15:17:44 -08:00
private _registerFunction ( type : StaticSymbol , fn : any ) : void {
2016-09-12 09:44:20 -07:00
this . conversionMap . set ( type , ( context : StaticSymbol , args : any [ ] ) = > fn . apply ( undefined , args ) ) ;
2016-05-31 09:15:17 -07:00
}
2016-02-18 10:53:21 -08:00
private initializeConversionMap ( ) : void {
2017-01-03 16:54:46 -08:00
const { coreDecorators , diDecorators , diMetadata , diInjectionToken ,
diOpaqueToken , animationMetadata , provider } = ANGULAR_IMPORT_LOCATIONS ;
this . injectionToken = this . findDeclaration ( diInjectionToken , 'InjectionToken' ) ;
this . opaqueToken = this . findDeclaration ( diInjectionToken , 'OpaqueToken' ) ;
2016-03-24 10:03:10 -07:00
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diDecorators , 'Host' ) , Host ) ;
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( diDecorators , 'Injectable' ) , Injectable ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diDecorators , 'Self' ) , Self ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diDecorators , 'SkipSelf' ) , SkipSelf ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diDecorators , 'Inject' ) , Inject ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diDecorators , 'Optional' ) , Optional ) ;
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'Attribute' ) , Attribute ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'ContentChild' ) , ContentChild ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'ContentChildren' ) , ContentChildren ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'ViewChild' ) , ViewChild ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'ViewChildren' ) , ViewChildren ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor ( this . findDeclaration ( coreDecorators , 'Input' ) , Input ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( coreDecorators , 'Output' ) , Output ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( coreDecorators , 'Pipe' ) , Pipe ) ;
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'HostBinding' ) , HostBinding ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'HostListener' ) , HostListener ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'Directive' ) , Directive ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
2016-11-15 08:49:23 -08:00
this . findDeclaration ( coreDecorators , 'Component' ) , Component ) ;
2016-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor (
this . findDeclaration ( coreDecorators , 'NgModule' ) , NgModule ) ;
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-11-18 15:17:44 -08:00
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diMetadata , 'Host' ) , Host ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diMetadata , 'Self' ) , Self ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diMetadata , 'SkipSelf' ) , SkipSelf ) ;
this . _registerDecoratorOrConstructor ( this . findDeclaration ( diMetadata , 'Optional' ) , Optional ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'trigger' ) , trigger ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'state' ) , state ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'transition' ) , transition ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'style' ) , style ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'animate' ) , animate ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'keyframes' ) , keyframes ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'sequence' ) , sequence ) ;
this . _registerFunction ( this . findDeclaration ( animationMetadata , 'group' ) , group ) ;
2016-11-15 08:49:23 -08:00
}
/ * *
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded .
* All types passed to the StaticResolver should be pseudo - types returned by this method .
*
* @param declarationFile the absolute path of the file where the symbol is declared
* @param name the name of the type .
* /
getStaticSymbol ( declarationFile : string , name : string , members? : string [ ] ) : StaticSymbol {
2016-12-15 09:12:40 -08:00
return this . symbolResolver . getStaticSymbol ( declarationFile , name , members ) ;
2016-11-15 08:49:23 -08:00
}
2016-12-02 14:34:16 -08:00
private reportError ( error : Error , context : StaticSymbol , path? : string ) {
if ( this . errorRecorder ) {
this . errorRecorder ( error , ( context && context . filePath ) || path ) ;
} else {
throw error ;
}
}
2017-01-27 15:35:31 -08:00
/ * *
* Simplify but discard any errors
* /
private trySimplify ( context : StaticSymbol , value : any ) : any {
const originalRecorder = this . errorRecorder ;
this . errorRecorder = ( error : any , fileName : string ) = > { } ;
const result = this . simplify ( context , value ) ;
this . errorRecorder = originalRecorder ;
return result ;
}
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-11-18 15:17:44 -08:00
const self = this ;
2016-06-13 15:56:51 -07:00
let scope = BindingScope . empty ;
2016-10-21 10:29:47 -07:00
const 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 resolveReferenceValue ( staticSymbol : StaticSymbol ) : any {
2016-12-15 09:12:40 -08:00
const resolvedSymbol = self . symbolResolver . resolveSymbol ( staticSymbol ) ;
return resolvedSymbol ? resolvedSymbol.metadata : null ;
2016-03-24 10:03:10 -07:00
}
2016-06-13 15:56:51 -07:00
2016-12-15 09:12:40 -08:00
function simplifyCall ( functionSymbol : StaticSymbol , targetFunction : any , args : any [ ] ) {
if ( targetFunction && targetFunction [ '__symbolic' ] == 'function' ) {
if ( calling . get ( functionSymbol ) ) {
throw new Error ( 'Recursion not supported' ) ;
2016-06-17 13:11:00 -07:00
}
2016-12-15 09:12:40 -08:00
calling . set ( functionSymbol , true ) ;
try {
const value = targetFunction [ 'value' ] ;
if ( value && ( depth != 0 || value . __symbolic != 'error' ) ) {
const parameters : string [ ] = targetFunction [ 'parameters' ] ;
const defaults : any [ ] = targetFunction . defaults ;
2017-01-05 15:22:38 -08:00
args = args . map ( arg = > simplifyInContext ( context , arg , depth + 1 ) ) ;
2016-12-15 09:12:40 -08:00
if ( defaults && defaults . length > args . length ) {
args . push ( . . . defaults . slice ( args . length ) . map ( ( value : any ) = > simplify ( value ) ) ) ;
}
const functionScope = BindingScope . build ( ) ;
for ( let i = 0 ; i < parameters . length ; i ++ ) {
functionScope . define ( parameters [ i ] , args [ i ] ) ;
2016-03-24 10:03:10 -07:00
}
2016-12-15 09:12:40 -08:00
const oldScope = scope ;
let result : any ;
try {
scope = functionScope . done ( ) ;
result = simplifyInContext ( functionSymbol , value , depth + 1 ) ;
} finally {
scope = oldScope ;
}
return result ;
2016-06-13 15:56:51 -07:00
}
2016-12-15 09:12:40 -08: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 (
2016-12-15 09:12:40 -08:00
{ __symbolic : 'error' , message : 'Function call not supported' , context : functionSymbol } ) ;
2016-06-13 15:56:51 -07:00
}
function simplify ( expression : any ) : any {
if ( isPrimitive ( expression ) ) {
return expression ;
}
if ( expression instanceof Array ) {
2016-11-12 14:08:58 +01:00
const result : any [ ] = [ ] ;
for ( const item of ( < any > expression ) ) {
2016-06-13 15:56:51 -07:00
// Check for a spread expression
if ( item && item . __symbolic === 'spread' ) {
2016-11-12 14:08:58 +01:00
const spreadArray = simplify ( item . expression ) ;
2016-06-13 15:56:51 -07:00
if ( Array . isArray ( spreadArray ) ) {
2016-11-12 14:08:58 +01:00
for ( const spreadItem of spreadArray ) {
2016-06-13 15:56:51 -07:00
result . push ( spreadItem ) ;
}
continue ;
2016-05-07 08:58:20 -06:00
}
2016-06-13 15:56:51 -07:00
}
2016-11-12 14:08:58 +01:00
const value = simplify ( item ) ;
2016-06-17 13:11:00 -07:00
if ( shouldIgnore ( value ) ) {
continue ;
}
result . push ( value ) ;
2016-06-13 15:56:51 -07:00
}
return result ;
}
2016-10-11 15:47:44 -07:00
if ( expression instanceof StaticSymbol ) {
2016-12-15 09:12:40 -08:00
// Stop simplification at builtin symbols
2017-01-03 16:54:46 -08:00
if ( expression === self . injectionToken || expression === self . opaqueToken ||
self . conversionMap . has ( expression ) ) {
2016-12-15 09:12:40 -08:00
return expression ;
} else {
const staticSymbol = expression ;
const declarationValue = resolveReferenceValue ( staticSymbol ) ;
if ( declarationValue ) {
return simplifyInContext ( staticSymbol , declarationValue , depth + 1 ) ;
} else {
return staticSymbol ;
}
}
2016-10-11 15:47:44 -07:00
}
2016-06-13 15:56:51 -07:00
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' :
2016-12-15 09:12:40 -08:00
const member = expression [ 'member' ] ;
2016-11-29 12:02:50 -08:00
let selectContext = context ;
2016-06-13 15:56:51 -07:00
let selectTarget = simplify ( expression [ 'expression' ] ) ;
2016-07-27 19:26:59 -07:00
if ( selectTarget instanceof StaticSymbol ) {
2016-12-15 09:12:40 -08:00
const members = selectTarget . members . concat ( member ) ;
2016-11-29 12:02:50 -08:00
selectContext =
self . getStaticSymbol ( selectTarget . filePath , selectTarget . name , members ) ;
2016-12-15 09:12:40 -08:00
const declarationValue = resolveReferenceValue ( selectContext ) ;
if ( declarationValue ) {
return simplifyInContext ( selectContext , declarationValue , depth + 1 ) ;
2016-07-27 19:26:59 -07:00
} else {
2016-11-29 12:02:50 -08:00
return selectContext ;
2016-07-27 19:26:59 -07:00
}
}
2016-11-29 12:02:50 -08:00
if ( selectTarget && isPrimitive ( member ) )
return simplifyInContext ( selectContext , selectTarget [ member ] , depth + 1 ) ;
2016-06-13 15:56:51 -07:00
return null ;
case 'reference' :
2016-12-15 09:12:40 -08:00
// Note: This only has to deal with variable references,
// as symbol references have been converted into StaticSymbols already
// in the StaticSymbolResolver!
const name : string = expression [ 'name' ] ;
const localValue = scope . resolve ( name ) ;
if ( localValue != BindingScope . missing ) {
return localValue ;
2016-12-14 14:01:50 -08:00
}
2016-12-15 09:12:40 -08:00
break ;
2016-06-13 15:56:51 -07:00
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
2016-12-15 09:12:40 -08:00
staticSymbol = simplifyInContext ( context , expression [ 'expression' ] , depth + 1 ) ;
if ( staticSymbol instanceof StaticSymbol ) {
2017-01-03 16:54:46 -08:00
if ( staticSymbol === self . injectionToken || staticSymbol === self . opaqueToken ) {
// if somebody calls new InjectionToken, don't create an InjectionToken,
// but rather return the symbol to which the InjectionToken is assigned to.
2016-12-15 09:12:40 -08:00
return context ;
}
const argExpressions : any [ ] = expression [ 'arguments' ] || [ ] ;
let converter = self . conversionMap . get ( staticSymbol ) ;
if ( converter ) {
2017-01-05 15:22:38 -08:00
const args =
argExpressions . map ( arg = > simplifyInContext ( context , arg , depth + 1 ) ) ;
2016-12-15 09:12:40 -08:00
return converter ( context , args ) ;
} else {
// Determine if the function is one we can simplify.
const targetFunction = resolveReferenceValue ( staticSymbol ) ;
2017-01-05 15:22:38 -08:00
return simplifyCall ( staticSymbol , targetFunction , argExpressions ) ;
2016-06-13 15:56:51 -07:00
}
}
2016-12-15 09:12:40 -08:00
break ;
2016-06-13 15:56:51 -07:00
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-11-09 16:29:22 -08:00
throw positionalError (
message , context . filePath , expression [ 'line' ] , expression [ 'character' ] ) ;
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 ) {
2016-12-15 09:12:40 -08:00
const members = context . members . length ? ` . ${ context . members . join ( '.' ) } ` : '' ;
const message =
` ${ e . message } , resolving symbol ${ context . name } ${ members } in ${ context . filePath } ` ;
2016-11-09 16:29:22 -08:00
if ( e . fileName ) {
throw positionalError ( message , e . fileName , e . line , e . column ) ;
}
2017-01-27 13:19:00 -08:00
throw syntaxError ( message ) ;
2016-06-13 15:56:51 -07:00
}
2016-06-03 15:43:09 -07:00
}
2016-06-13 15:56:51 -07:00
2016-12-02 14:34:16 -08:00
const recordedSimplifyInContext = ( context : StaticSymbol , value : any , depth : number ) = > {
try {
return simplifyInContext ( context , value , depth ) ;
} catch ( e ) {
this . reportError ( e , context ) ;
}
} ;
const result = this . errorRecorder ? recordedSimplifyInContext ( context , value , 0 ) :
simplifyInContext ( context , value , 0 ) ;
2016-06-17 13:11:00 -07:00
if ( shouldIgnore ( result ) ) {
return undefined ;
}
return result ;
2016-03-24 10:03:10 -07:00
}
2016-04-28 21:54:02 -07:00
private getTypeMetadata ( type : StaticSymbol ) : { [ key : string ] : any } {
2016-12-15 09:12:40 -08:00
const resolvedSymbol = this . symbolResolver . resolveSymbol ( type ) ;
return resolvedSymbol && resolvedSymbol . metadata ? resolvedSymbol . metadata :
{ __symbolic : 'class' } ;
2016-03-24 10:03:10 -07:00
}
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 ) {
2016-08-22 17:37:48 -07:00
return ` Reference to a non-exported class ${ error . context . className } . Consider exporting the class ` ;
2016-06-03 15:43:09 -07:00
}
break ;
case 'Variable not initialized' :
2016-08-22 17:37:48 -07:00
return 'Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler' ;
2016-06-03 15:43:09 -07:00
case 'Destructuring not supported' :
2016-08-22 17:37:48 -07:00
return 'Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring' ;
2016-06-03 15:43:09 -07:00
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-08-02 14:38:31 -07:00
case 'Reference to a local symbol' :
if ( error . context && error . context . name ) {
return ` Reference to a local (non-exported) symbol ' ${ error . context . name } '. Consider exporting the symbol ` ;
}
2016-11-17 09:52:38 -08:00
break ;
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-10-21 10:29:47 -07:00
const result : { [ key : string ] : any } = { } ;
2016-06-17 13:11:00 -07:00
Object . keys ( input ) . forEach ( ( key ) = > {
2016-11-12 14:08:58 +01:00
const value = transform ( input [ key ] , key ) ;
2016-06-17 13:11:00 -07:00
if ( ! shouldIgnore ( value ) ) {
2016-12-12 10:49:17 -08:00
if ( HIDDEN_KEY . test ( key ) ) {
Object . defineProperty ( result , key , { enumerable : false , configurable : true , value : value } ) ;
} else {
result [ key ] = value ;
}
2016-06-17 13:11:00 -07:00
}
} ) ;
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 {
2016-10-21 10:29:47 -07:00
const current = new Map < string , any > ( ) ;
2016-06-13 15:56:51 -07:00
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 ;
}
}
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
}
2016-11-09 16:29:22 -08:00
function positionalError ( message : string , fileName : string , line : number , column : number ) : Error {
const result = new Error ( message ) ;
( result as any ) . fileName = fileName ;
( result as any ) . line = line ;
( result as any ) . column = column ;
return result ;
2017-01-03 16:54:46 -08:00
}