diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts index 782bf0d7a4..af1246d8de 100644 --- a/modules/@angular/compiler/src/compile_metadata.ts +++ b/modules/@angular/compiler/src/compile_metadata.ts @@ -1,4 +1,4 @@ -import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core'; +import {ChangeDetectionStrategy, ViewEncapsulation, reflector} from '@angular/core'; import { CHANGE_DETECTION_STRATEGY_VALUES, VIEW_ENCAPSULATION_VALUES, @@ -259,10 +259,13 @@ export class CompileFactoryMetadata implements CompileIdentifierMetadata, } } +var UNDEFINED = new Object(); + export class CompileTokenMetadata implements CompileMetadataWithIdentifier { value: any; identifier: CompileIdentifierMetadata; identifierIsInstance: boolean; + private _assetCacheKey = UNDEFINED; constructor({value, identifier, identifierIsInstance}: { value?: any, @@ -299,14 +302,23 @@ export class CompileTokenMetadata implements CompileMetadataWithIdentifier { } get assetCacheKey(): any { - if (isPresent(this.identifier)) { - return isPresent(this.identifier.moduleUrl) && - isPresent(getUrlScheme(this.identifier.moduleUrl)) ? - `${this.identifier.name}|${this.identifier.moduleUrl}|${this.identifierIsInstance}` : - null; - } else { - return this.value; + if (this._assetCacheKey === UNDEFINED) { + if (isPresent(this.identifier)) { + if (isPresent(this.identifier.moduleUrl) && + isPresent(getUrlScheme(this.identifier.moduleUrl))) { + var uri = reflector.importUri({ + 'filePath': this.identifier.moduleUrl, + 'name': this.identifier.name + }); + this._assetCacheKey = `${this.identifier.name}|${uri}|${this.identifierIsInstance}`; + } else { + this._assetCacheKey = null; + } + } else { + this._assetCacheKey = this.value; + } } + return this._assetCacheKey; } equalsTo(token2: CompileTokenMetadata): boolean { diff --git a/modules/@angular/compiler_cli/integrationtest/src/basic.html b/modules/@angular/compiler_cli/integrationtest/src/basic.html index a2e5268700..8a535b9117 100644 --- a/modules/@angular/compiler_cli/integrationtest/src/basic.html +++ b/modules/@angular/compiler_cli/integrationtest/src/basic.html @@ -1,3 +1,3 @@
{{ctxProp}}
- \ No newline at end of file + \ No newline at end of file diff --git a/modules/@angular/compiler_cli/integrationtest/src/basic.ts b/modules/@angular/compiler_cli/integrationtest/src/basic.ts index 551e1b1ee2..56e6430eaf 100644 --- a/modules/@angular/compiler_cli/integrationtest/src/basic.ts +++ b/modules/@angular/compiler_cli/integrationtest/src/basic.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {FORM_DIRECTIVES} from '@angular/common'; +import {FORM_DIRECTIVES, NgIf} from '@angular/common'; import {MyComp} from './a/multiple_components'; @Component({ @@ -7,9 +7,10 @@ import {MyComp} from './a/multiple_components'; templateUrl: './basic.html', styles: ['.red { color: red }'], styleUrls: ['./basic.css'], - directives: [MyComp, FORM_DIRECTIVES] + directives: [MyComp, FORM_DIRECTIVES, NgIf] }) export class Basic { ctxProp: string; - constructor() { this.ctxProp = 'initiaValue'; } + ctxBool: boolean; + constructor() { this.ctxProp = 'initialValue'; } } diff --git a/modules/@angular/compiler_cli/integrationtest/test/basic_spec.ts b/modules/@angular/compiler_cli/integrationtest/test/basic_spec.ts index f3bb094b7a..750e064db6 100644 --- a/modules/@angular/compiler_cli/integrationtest/test/basic_spec.ts +++ b/modules/@angular/compiler_cli/integrationtest/test/basic_spec.ts @@ -1,5 +1,9 @@ import * as fs from 'fs'; import * as path from 'path'; +import {BasicNgFactory} from '../src/basic.ngfactory'; +import {MyComp} from '../src/a/multiple_components'; +import {ReflectiveInjector, DebugElement, getDebugNode} from '@angular/core'; +import {browserPlatform, BROWSER_APP_STATIC_PROVIDERS} from '@angular/platform-browser'; describe("template codegen output", () => { const outDir = path.join('dist', 'all', '@angular', 'compiler_cli', 'integrationtest', 'src'); @@ -23,4 +27,17 @@ describe("template codegen output", () => { expect(fs.existsSync(dtsOutput)).toBeTruthy(); expect(fs.readFileSync(dtsOutput, {encoding: 'utf-8'})).toContain('Basic'); }); + + it("should be able to create the basic component and trigger an ngIf", () => { + const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_STATIC_PROVIDERS, + browserPlatform().injector); + var comp = BasicNgFactory.create(appInjector); + var debugElement = getDebugNode(comp.location.nativeElement); + expect(debugElement.children.length).toBe(2); + + comp.instance.ctxBool = true; + comp.changeDetectorRef.detectChanges(); + expect(debugElement.children.length).toBe(3); + expect(debugElement.children[2].injector.get(MyComp)).toBeTruthy(); + }); }); \ No newline at end of file diff --git a/modules/@angular/compiler_cli/src/codegen.ts b/modules/@angular/compiler_cli/src/codegen.ts index f1f9066e6c..be4f8152e2 100644 --- a/modules/@angular/compiler_cli/src/codegen.ts +++ b/modules/@angular/compiler_cli/src/codegen.ts @@ -25,6 +25,7 @@ import {Parse5DomAdapter} from '@angular/platform-server'; import {MetadataCollector} from 'ts-metadata-collector'; import {NodeReflectorHost} from './reflector_host'; +import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities'; const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/; @@ -164,6 +165,7 @@ export class CodeGenerator { const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver(); const reflectorHost = new NodeReflectorHost(program, compilerHost, options, ngOptions); const staticReflector = new StaticReflector(reflectorHost); + StaticAndDynamicReflectionCapabilities.install(staticReflector); const htmlParser = new HtmlParser(); const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser); const parser = new Parser(new Lexer()); diff --git a/modules/@angular/compiler_cli/src/core_private.ts b/modules/@angular/compiler_cli/src/core_private.ts index 5197e05a10..c2a9ec2f38 100644 --- a/modules/@angular/compiler_cli/src/core_private.ts +++ b/modules/@angular/compiler_cli/src/core_private.ts @@ -2,3 +2,6 @@ import {__core_private__ as r, __core_private_types__ as t} from '@angular/core' export type ReflectorReader = t.ReflectorReader; export var ReflectorReader: typeof t.ReflectorReader = r.ReflectorReader; + +export type ReflectionCapabilities = t.ReflectionCapabilities; +export var ReflectionCapabilities: typeof t.ReflectionCapabilities = r.ReflectionCapabilities; diff --git a/modules/@angular/compiler_cli/src/main.ts b/modules/@angular/compiler_cli/src/main.ts index 0ae6f5f8d9..cc33e93363 100644 --- a/modules/@angular/compiler_cli/src/main.ts +++ b/modules/@angular/compiler_cli/src/main.ts @@ -1,4 +1,4 @@ -#!/usr/bin / env node +#!/usr/bin/env node // Must be imported first, because angular2 decorators throws on load. import 'reflect-metadata'; diff --git a/modules/@angular/compiler_cli/src/reflector_host.ts b/modules/@angular/compiler_cli/src/reflector_host.ts index c4bd6e19db..bceb9a3d2c 100644 --- a/modules/@angular/compiler_cli/src/reflector_host.ts +++ b/modules/@angular/compiler_cli/src/reflector_host.ts @@ -37,11 +37,15 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator { return resolved ? resolved.resolvedFileName : null; }; + private normalizeAssetUrl(url: string): string { + let assetUrl = AssetUrl.parse(url); + return assetUrl ? `${assetUrl.packageName}/${assetUrl.modulePath}` : null; + } private resolveAssetUrl(url: string, containingFile: string): string { - let assetUrl = AssetUrl.parse(url); + let assetUrl = this.normalizeAssetUrl(url); if (assetUrl) { - return this.resolve(`${assetUrl.packageName}/${assetUrl.modulePath}`, containingFile); + return this.resolve(assetUrl, containingFile); } return url; } @@ -92,6 +96,10 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator { } try { + let assetUrl = this.normalizeAssetUrl(module); + if (assetUrl) { + module = assetUrl; + } const filePath = this.resolve(module, containingFile); if (!filePath) { diff --git a/modules/@angular/compiler_cli/src/static_reflection_capabilities.ts b/modules/@angular/compiler_cli/src/static_reflection_capabilities.ts new file mode 100644 index 0000000000..91ca210a37 --- /dev/null +++ b/modules/@angular/compiler_cli/src/static_reflection_capabilities.ts @@ -0,0 +1,48 @@ +import {reflector} from '@angular/core'; +import {ReflectionCapabilities} from './core_private'; +import {StaticReflector} from './static_reflector'; + +export class StaticAndDynamicReflectionCapabilities { + static install(staticDelegate: StaticReflector) { + reflector.updateCapabilities(new StaticAndDynamicReflectionCapabilities(staticDelegate)); + } + + private dynamicDelegate = new ReflectionCapabilities(); + + constructor(private staticDelegate: StaticReflector) {} + + isReflectionEnabled(): boolean { + return true; + } + factory(type: any): Function { + return this.dynamicDelegate.factory(type); + } + interfaces(type: any): any[] { + return this.dynamicDelegate.interfaces(type); + } + parameters(type: any): any[][] { + return isStaticType(type) ? this.staticDelegate.parameters(type) : this.dynamicDelegate.parameters(type); + } + annotations(type: any): any[] { + return isStaticType(type) ? this.staticDelegate.annotations(type) : this.dynamicDelegate.annotations(type); + } + propMetadata(typeOrFunc: any): {[key: string]: any[]} { + return isStaticType(typeOrFunc) ? this.staticDelegate.propMetadata(typeOrFunc) : this.dynamicDelegate.propMetadata(typeOrFunc); + } + getter(name: string) { + return this.dynamicDelegate.getter(name); + } + setter(name: string) { + return this.dynamicDelegate.setter(name); + } + method(name: string) { + return this.dynamicDelegate.method(name); + } + importUri(type: any): string { + return this.staticDelegate.importUri(type); + } +} + +function isStaticType(type: any): boolean { + return typeof type === 'object' && type.name && type.filePath; +} \ No newline at end of file diff --git a/modules/@angular/compiler_cli/src/static_reflector.ts b/modules/@angular/compiler_cli/src/static_reflector.ts index d2ad0c975e..2b3c4a5f2d 100644 --- a/modules/@angular/compiler_cli/src/static_reflector.ts +++ b/modules/@angular/compiler_cli/src/static_reflector.ts @@ -75,7 +75,10 @@ export class StaticReflector implements ReflectorReader { constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); } - importUri(typeOrFunc: any): string { return (typeOrFunc).filePath; } + importUri(typeOrFunc: StaticSymbol): string { + var staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, ''); + return staticSymbol ? staticSymbol.filePath : null; + } public annotations(type: StaticSymbol): any[] { let annotations = this.annotationCache.get(type); diff --git a/modules/@angular/core/src/reflection/platform_reflection_capabilities.ts b/modules/@angular/core/src/reflection/platform_reflection_capabilities.ts index ad4c13f27e..c28ec060cc 100644 --- a/modules/@angular/core/src/reflection/platform_reflection_capabilities.ts +++ b/modules/@angular/core/src/reflection/platform_reflection_capabilities.ts @@ -11,5 +11,5 @@ export interface PlatformReflectionCapabilities { getter(name: string): GetterFn; setter(name: string): SetterFn; method(name: string): MethodFn; - importUri(type: Type): string; + importUri(type: any): string; } diff --git a/modules/@angular/core/src/reflection/reflection_capabilities.dart b/modules/@angular/core/src/reflection/reflection_capabilities.dart index 3cd4b4a030..7082065057 100644 --- a/modules/@angular/core/src/reflection/reflection_capabilities.dart +++ b/modules/@angular/core/src/reflection/reflection_capabilities.dart @@ -342,7 +342,12 @@ class ReflectionCapabilities implements PlatformReflectionCapabilities { return classMirror.metadata; } - String importUri(Type type) { + String importUri(dynamic type) { + // StaticSymbol + if (type is Map && type['filePath'] != null) { + return type['filePath']; + } + // Runtime type return '${(reflectClass(type).owner as LibraryMirror).uri}'; } } diff --git a/modules/@angular/core/src/reflection/reflection_capabilities.ts b/modules/@angular/core/src/reflection/reflection_capabilities.ts index 07796ac688..525c7ec332 100644 --- a/modules/@angular/core/src/reflection/reflection_capabilities.ts +++ b/modules/@angular/core/src/reflection/reflection_capabilities.ts @@ -214,7 +214,14 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { } // There is not a concept of import uri in Js, but this is useful in developing Dart applications. - importUri(type: Type): string { return `./${stringify(type)}`; } + importUri(type: any): string { + // StaticSymbol + if (typeof type === 'object' && type['filePath']) { + return type['filePath']; + } + // Runtime type + return `./${stringify(type)}`; + } } function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] { diff --git a/modules/@angular/core/src/reflection/reflector.ts b/modules/@angular/core/src/reflection/reflector.ts index 191db83e6c..56d1984be0 100644 --- a/modules/@angular/core/src/reflection/reflector.ts +++ b/modules/@angular/core/src/reflection/reflector.ts @@ -45,6 +45,10 @@ export class Reflector extends ReflectorReader { this.reflectionCapabilities = reflectionCapabilities; } + updateCapabilities(caps: PlatformReflectionCapabilities) { + this.reflectionCapabilities = caps; + } + isReflectionEnabled(): boolean { return this.reflectionCapabilities.isReflectionEnabled(); } /** @@ -160,7 +164,7 @@ export class Reflector extends ReflectorReader { /** @internal */ _containsReflectionInfo(typeOrFunc: any) { return this._injectableInfo.has(typeOrFunc); } - importUri(type: Type): string { return this.reflectionCapabilities.importUri(type); } + importUri(type: any): string { return this.reflectionCapabilities.importUri(type); } } function _mergeMaps(target: Map, config: {[key: string]: Function}): void {