fix(compiler): walk third party modules (#12453)
fixes #11889 fixes #12428
This commit is contained in:
parent
bfc97ff2cd
commit
a838aba756
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'use-third-party',
|
||||||
|
template: '<third-party-comp [thirdParty]="title"></third-party-comp>' +
|
||||||
|
'<another-third-party-comp></another-third-party-comp>',
|
||||||
|
})
|
||||||
|
export class ComponentUsingThirdParty {
|
||||||
|
title: string = 'from 3rd party';
|
||||||
|
}
|
|
@ -12,6 +12,10 @@
|
||||||
<source>Welcome</source>
|
<source>Welcome</source>
|
||||||
<target>tervetuloa</target>
|
<target>tervetuloa</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
|
||||||
|
<source>other-3rdP-component</source>
|
||||||
|
<target>other-3rdP-component</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
|
@ -9,4 +9,5 @@
|
||||||
<translationbundle>
|
<translationbundle>
|
||||||
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
|
<translation id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4">käännä teksti</translation>
|
||||||
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
|
<translation id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">tervetuloa</translation>
|
||||||
|
<translation id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</translation>
|
||||||
</translationbundle>
|
</translationbundle>
|
||||||
|
|
|
@ -11,9 +11,12 @@ import {FormsModule} from '@angular/forms';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {MdButtonModule} from '@angular2-material/button';
|
import {MdButtonModule} from '@angular2-material/button';
|
||||||
|
|
||||||
|
import {ThirdpartyModule} from '../third_party_src/module';
|
||||||
|
|
||||||
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
|
import {MultipleComponentsMyComp, NextComp} from './a/multiple_components';
|
||||||
import {AnimateCmp} from './animate';
|
import {AnimateCmp} from './animate';
|
||||||
import {BasicComp} from './basic';
|
import {BasicComp} from './basic';
|
||||||
|
import {ComponentUsingThirdParty} from './comp_using_3rdp';
|
||||||
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
||||||
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
||||||
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
|
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
|
||||||
|
@ -22,35 +25,47 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
SomeDirectiveInRootModule,
|
|
||||||
SomePipeInRootModule,
|
|
||||||
AnimateCmp,
|
AnimateCmp,
|
||||||
BasicComp,
|
BasicComp,
|
||||||
|
CompConsumingEvents,
|
||||||
CompForChildQuery,
|
CompForChildQuery,
|
||||||
CompWithEntryComponents,
|
CompUsingPipes,
|
||||||
|
CompUsingRootModuleDirectiveAndPipe,
|
||||||
CompWithAnalyzeEntryComponentsProvider,
|
CompWithAnalyzeEntryComponentsProvider,
|
||||||
ProjectingComp,
|
|
||||||
CompWithChildQuery,
|
CompWithChildQuery,
|
||||||
CompWithDirectiveChild,
|
CompWithDirectiveChild,
|
||||||
|
CompWithEntryComponents,
|
||||||
CompWithNgContent,
|
CompWithNgContent,
|
||||||
CompUsingRootModuleDirectiveAndPipe,
|
|
||||||
CompWithProviders,
|
CompWithProviders,
|
||||||
CompWithReferences,
|
CompWithReferences,
|
||||||
CompUsingPipes,
|
DirectiveForQuery,
|
||||||
CompConsumingEvents,
|
|
||||||
DirPublishingEvents,
|
DirPublishingEvents,
|
||||||
MultipleComponentsMyComp,
|
MultipleComponentsMyComp,
|
||||||
DirectiveForQuery,
|
|
||||||
NextComp,
|
NextComp,
|
||||||
|
ProjectingComp,
|
||||||
|
SomeDirectiveInRootModule,
|
||||||
|
SomePipeInRootModule,
|
||||||
|
ComponentUsingThirdParty,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule, FormsModule, someLibModuleWithProviders(), ModuleUsingCustomElements,
|
BrowserModule,
|
||||||
MdButtonModule
|
FormsModule,
|
||||||
|
MdButtonModule,
|
||||||
|
ModuleUsingCustomElements,
|
||||||
|
someLibModuleWithProviders(),
|
||||||
|
ThirdpartyModule,
|
||||||
],
|
],
|
||||||
providers: [SomeService],
|
providers: [SomeService],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider,
|
AnimateCmp,
|
||||||
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe, CompWithReferences
|
BasicComp,
|
||||||
|
CompUsingRootModuleDirectiveAndPipe,
|
||||||
|
CompWithAnalyzeEntryComponentsProvider,
|
||||||
|
CompWithChildQuery,
|
||||||
|
CompWithEntryComponents,
|
||||||
|
CompWithReferences,
|
||||||
|
ProjectingComp,
|
||||||
|
ComponentUsingThirdParty,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class MainModule {
|
export class MainModule {
|
||||||
|
|
|
@ -43,13 +43,13 @@ describe('template codegen output', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to create the basic component', () => {
|
it('should be able to create the basic component', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
expect(compFixture.componentInstance).toBeTruthy();
|
expect(compFixture.componentInstance).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support ngIf', () => {
|
it('should support ngIf', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
var debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children.length).toBe(3);
|
expect(debugElement.children.length).toBe(3);
|
||||||
|
|
||||||
compFixture.componentInstance.ctxBool = true;
|
compFixture.componentInstance.ctxBool = true;
|
||||||
|
@ -59,8 +59,8 @@ describe('template codegen output', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support ngFor', () => {
|
it('should support ngFor', () => {
|
||||||
var compFixture = createComponent(BasicComp);
|
const compFixture = createComponent(BasicComp);
|
||||||
var debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children.length).toBe(3);
|
expect(debugElement.children.length).toBe(3);
|
||||||
|
|
||||||
// test NgFor
|
// test NgFor
|
||||||
|
@ -83,11 +83,9 @@ describe('template codegen output', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support i18n for content tags', () => {
|
it('should support i18n for content tags', () => {
|
||||||
const compFixture = createComponent(BasicComp);
|
const containerElement = createComponent(BasicComp).nativeElement;
|
||||||
const debugElement = compFixture.debugElement;
|
const pElement = containerElement.children.find((c: any) => c.name == 'p');
|
||||||
const containerElement = <any>debugElement.nativeElement;
|
const pText = pElement.children.map((c: any) => c.data).join('').trim();
|
||||||
const pElement = <any>containerElement.children.find((c: any) => c.name == 'p');
|
|
||||||
const pText = <string>pElement.children.map((c: any) => c.data).join('').trim();
|
|
||||||
expect(pText).toBe('tervetuloa');
|
expect(pText).toBe('tervetuloa');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,6 +34,7 @@ const EXPECTED_XMB = `<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!ELEMENT ex (#PCDATA)>
|
<!ELEMENT ex (#PCDATA)>
|
||||||
]>
|
]>
|
||||||
<messagebundle>
|
<messagebundle>
|
||||||
|
<msg id="63a85808f03b8181e36a952e0fa38202c2304862">other-3rdP-component</msg>
|
||||||
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
|
<msg id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" desc="desc" meaning="meaning">translate me</msg>
|
||||||
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
|
<msg id="65cc4ab3b4c438e07c89be2b677d08369fb62da2">Welcome</msg>
|
||||||
</messagebundle>
|
</messagebundle>
|
||||||
|
@ -43,6 +44,10 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<file source-language="en" datatype="plaintext" original="ng2.template">
|
<file source-language="en" datatype="plaintext" original="ng2.template">
|
||||||
<body>
|
<body>
|
||||||
|
<trans-unit id="63a85808f03b8181e36a952e0fa38202c2304862" datatype="html">
|
||||||
|
<source>other-3rdP-component</source>
|
||||||
|
<target/>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
|
<trans-unit id="76e1eccb1b772fa9f294ef9c146ea6d0efa8a2d4" datatype="html">
|
||||||
<source>translate me</source>
|
<source>translate me</source>
|
||||||
<target/>
|
<target/>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import './init';
|
import './init';
|
||||||
|
|
||||||
|
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
|
||||||
import {MainModule} from '../src/module';
|
import {MainModule} from '../src/module';
|
||||||
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
|
import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures';
|
||||||
|
|
||||||
|
@ -15,9 +16,9 @@ import {createComponent, createModule} from './util';
|
||||||
describe('NgModule', () => {
|
describe('NgModule', () => {
|
||||||
it('should support providers', () => {
|
it('should support providers', () => {
|
||||||
const moduleRef = createModule();
|
const moduleRef = createModule();
|
||||||
expect(moduleRef.instance instanceof MainModule).toBe(true);
|
expect(moduleRef.instance instanceof MainModule).toEqual(true);
|
||||||
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toBe(true);
|
expect(moduleRef.injector.get(MainModule) instanceof MainModule).toEqual(true);
|
||||||
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toBe(true);
|
expect(moduleRef.injector.get(SomeService) instanceof SomeService).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support entryComponents components', () => {
|
it('should support entryComponents components', () => {
|
||||||
|
@ -26,7 +27,7 @@ describe('NgModule', () => {
|
||||||
CompUsingRootModuleDirectiveAndPipe);
|
CompUsingRootModuleDirectiveAndPipe);
|
||||||
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
|
expect(cf.componentType).toBe(CompUsingRootModuleDirectiveAndPipe);
|
||||||
const compRef = cf.create(moduleRef.injector);
|
const compRef = cf.create(moduleRef.injector);
|
||||||
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toBe(true);
|
expect(compRef.instance instanceof CompUsingRootModuleDirectiveAndPipe).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
|
it('should support entryComponents via the ANALYZE_FOR_ENTRY_COMPONENTS provider and function providers in components',
|
||||||
|
@ -42,12 +43,30 @@ describe('NgModule', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('third-party modules', () => {
|
||||||
|
// https://github.com/angular/angular/issues/11889
|
||||||
|
it('should support third party entryComponents components', () => {
|
||||||
|
const fixture = createComponent(ComponentUsingThirdParty);
|
||||||
|
const thirdPComps = fixture.nativeElement.children;
|
||||||
|
expect(thirdPComps[0].children[0].children[0].data).toEqual('3rdP-component');
|
||||||
|
expect(thirdPComps[1].children[0].children[0].data).toEqual('other-3rdP-component');
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/angular/angular/issues/12428
|
||||||
|
it('should support third party directives', () => {
|
||||||
|
const fixture = createComponent(ComponentUsingThirdParty);
|
||||||
|
const debugElement = fixture.debugElement;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(debugElement.children[0].properties['title']).toEqual('from 3rd party');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should support module directives and pipes', () => {
|
it('should support module directives and pipes', () => {
|
||||||
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
|
const compFixture = createComponent(CompUsingRootModuleDirectiveAndPipe);
|
||||||
compFixture.detectChanges();
|
compFixture.detectChanges();
|
||||||
|
|
||||||
const debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
|
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support module directives and pipes on lib modules', () => {
|
it('should support module directives and pipes on lib modules', () => {
|
||||||
|
@ -55,10 +74,10 @@ describe('NgModule', () => {
|
||||||
compFixture.detectChanges();
|
compFixture.detectChanges();
|
||||||
|
|
||||||
const debugElement = compFixture.debugElement;
|
const debugElement = compFixture.debugElement;
|
||||||
expect(debugElement.children[0].properties['title']).toBe('transformed someValue');
|
expect(debugElement.children[0].properties['title']).toEqual('transformed someValue');
|
||||||
|
|
||||||
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toBe(true);
|
expect(debugElement.injector.get(SomeLibModule) instanceof SomeLibModule).toEqual(true);
|
||||||
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
|
expect(debugElement.injector.get(ServiceUsingLibModule) instanceof ServiceUsingLibModule)
|
||||||
.toBe(true);
|
.toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
This folder emulates consuming precompiled modules and components.
|
||||||
|
It is compiled separately from the other sources under `src`
|
||||||
|
to only generate `*.js` / `*.d.ts` / `*.metadata.json` files,
|
||||||
|
but no `*.ngfactory.ts` files.
|
||||||
|
|
||||||
|
** WARNING **
|
||||||
|
Do not import components/directives from here directly as we want to test that ngc still compiles
|
||||||
|
them when they are not imported.
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'third-party-comp',
|
||||||
|
template: '<div>3rdP-component</div>',
|
||||||
|
})
|
||||||
|
export class ThirdPartyComponent {
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Directive, Input} from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[thirdParty]',
|
||||||
|
host: {'[title]': 'thirdParty'},
|
||||||
|
})
|
||||||
|
export class ThirdPartyDirective {
|
||||||
|
@Input() thirdParty: string;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
import {ThirdPartyComponent} from './comp';
|
||||||
|
import {ThirdPartyDirective} from './directive';
|
||||||
|
import {AnotherThirdPartyModule} from './other_module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
ThirdPartyComponent,
|
||||||
|
ThirdPartyDirective,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AnotherThirdPartyModule,
|
||||||
|
ThirdPartyComponent,
|
||||||
|
ThirdPartyDirective,
|
||||||
|
],
|
||||||
|
imports: [AnotherThirdPartyModule]
|
||||||
|
})
|
||||||
|
export class ThirdpartyModule {
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'another-third-party-comp',
|
||||||
|
template: '<div i18n>other-3rdP-component</div>',
|
||||||
|
})
|
||||||
|
export class AnotherThirdpartyComponent {
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {AnotherThirdpartyComponent} from './other_comp';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [AnotherThirdpartyComponent],
|
||||||
|
exports: [AnotherThirdpartyComponent],
|
||||||
|
})
|
||||||
|
export class AnotherThirdPartyModule {
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
// For TypeScript 1.8, we have to lay out generated files
|
||||||
|
// in the same source directory with your code.
|
||||||
|
"genDir": ".",
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "",
|
||||||
|
"declaration": true,
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"baseUrl": ".",
|
||||||
|
"outDir": "../node_modules/third_party"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
// For TypeScript 1.8, we have to lay out generated files
|
||||||
|
// in the same source directory with your code.
|
||||||
|
"genDir": ".",
|
||||||
|
"debug": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "",
|
||||||
|
"declaration": true,
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"baseUrl": "."
|
||||||
|
},
|
||||||
|
|
||||||
|
"files": [
|
||||||
|
"src/module",
|
||||||
|
"src/bootstrap",
|
||||||
|
"test/all_spec",
|
||||||
|
"benchmarks/src/tree/ng2/index_aot.ts",
|
||||||
|
"benchmarks/src/tree/ng2_switch/index_aot.ts",
|
||||||
|
"benchmarks/src/largetable/ng2/index_aot.ts",
|
||||||
|
"benchmarks/src/largetable/ng2_switch/index_aot.ts"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"angularCompilerOptions": {
|
|
||||||
// For TypeScript 1.8, we have to lay out generated files
|
|
||||||
// in the same source directory with your code.
|
|
||||||
"genDir": ".",
|
|
||||||
"debug": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"rootDir": "",
|
|
||||||
"declaration": true,
|
|
||||||
"lib": ["es6", "dom"],
|
|
||||||
"baseUrl": "."
|
|
||||||
},
|
|
||||||
|
|
||||||
"files": [
|
|
||||||
"src/module",
|
|
||||||
"src/bootstrap",
|
|
||||||
"test/all_spec",
|
|
||||||
"benchmarks/src/tree/ng2/index_aot.ts",
|
|
||||||
"benchmarks/src/tree/ng2_switch/index_aot.ts",
|
|
||||||
"benchmarks/src/largetable/ng2/index_aot.ts",
|
|
||||||
"benchmarks/src/largetable/ng2_switch/index_aot.ts"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -40,50 +40,47 @@ export class CodeGeneratorModuleCollector {
|
||||||
private staticReflector: StaticReflector, private reflectorHost: StaticReflectorHost,
|
private staticReflector: StaticReflector, private reflectorHost: StaticReflectorHost,
|
||||||
private program: ts.Program, private options: AngularCompilerOptions) {}
|
private program: ts.Program, private options: AngularCompilerOptions) {}
|
||||||
|
|
||||||
getModuleSymbols(program: ts.Program): {fileMetas: FileMetadata[], ngModules: StaticSymbol[]} {
|
getModuleSymbols(): StaticSymbol[] {
|
||||||
// Compare with false since the default should be true
|
// Compare with false since the default should be true
|
||||||
const skipFileNames = (this.options.generateCodeForLibraries === false) ?
|
const skipFileNames =
|
||||||
GENERATED_OR_DTS_FILES :
|
this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
||||||
GENERATED_FILES;
|
|
||||||
let filePaths = this.program.getSourceFiles()
|
|
||||||
.filter(sf => !skipFileNames.test(sf.fileName))
|
|
||||||
.map(sf => this.reflectorHost.getCanonicalFileName(sf.fileName));
|
|
||||||
const fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
|
|
||||||
const ngModules = fileMetas.reduce((ngModules, fileMeta) => {
|
|
||||||
ngModules.push(...fileMeta.ngModules);
|
|
||||||
return ngModules;
|
|
||||||
}, <StaticSymbol[]>[]);
|
|
||||||
return {fileMetas, ngModules};
|
|
||||||
}
|
|
||||||
|
|
||||||
private readFileMetadata(absSourcePath: string): FileMetadata {
|
const ngModules: StaticSymbol[] = [];
|
||||||
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
|
||||||
const result: FileMetadata = {directives: [], ngModules: [], fileUrl: absSourcePath};
|
this.program.getSourceFiles()
|
||||||
if (!moduleMetadata) {
|
.filter(sourceFile => !skipFileNames.test(sourceFile.fileName))
|
||||||
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
.forEach(sourceFile => {
|
||||||
return result;
|
const absSrcPath = this.reflectorHost.getCanonicalFileName(sourceFile.fileName);
|
||||||
}
|
|
||||||
const metadata = moduleMetadata['metadata'];
|
const moduleMetadata = this.staticReflector.getModuleMetadata(absSrcPath);
|
||||||
const symbols = metadata && Object.keys(metadata);
|
if (!moduleMetadata) {
|
||||||
if (!symbols || !symbols.length) {
|
console.log(`WARNING: no metadata found for ${absSrcPath}`);
|
||||||
return result;
|
return;
|
||||||
}
|
}
|
||||||
for (const symbol of symbols) {
|
|
||||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
const metadata = moduleMetadata['metadata'];
|
||||||
// Ignore symbols that are only included to record error information.
|
|
||||||
continue;
|
if (!metadata) {
|
||||||
}
|
return;
|
||||||
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
}
|
||||||
const annotations = this.staticReflector.annotations(staticType);
|
|
||||||
annotations.forEach((annotation) => {
|
for (const symbol of Object.keys(metadata)) {
|
||||||
if (annotation instanceof NgModule) {
|
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||||
result.ngModules.push(staticType);
|
// Ignore symbols that are only included to record error information.
|
||||||
} else if (annotation instanceof Directive) {
|
continue;
|
||||||
result.directives.push(staticType);
|
}
|
||||||
}
|
const staticType = this.reflectorHost.findDeclaration(absSrcPath, symbol, absSrcPath);
|
||||||
});
|
const annotations = this.staticReflector.annotations(staticType);
|
||||||
}
|
annotations.some((annotation) => {
|
||||||
return result;
|
if (annotation instanceof NgModule) {
|
||||||
|
ngModules.push(staticType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ngModules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +98,7 @@ export class CodeGenerator {
|
||||||
// Write codegen in a directory structure matching the sources.
|
// Write codegen in a directory structure matching the sources.
|
||||||
private calculateEmitPath(filePath: string): string {
|
private calculateEmitPath(filePath: string): string {
|
||||||
let root = this.options.basePath;
|
let root = this.options.basePath;
|
||||||
for (let eachRootDir of this.options.rootDirs || []) {
|
for (const eachRootDir of this.options.rootDirs || []) {
|
||||||
if (this.options.trace) {
|
if (this.options.trace) {
|
||||||
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
||||||
}
|
}
|
||||||
|
@ -111,31 +108,27 @@ export class CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// transplant the codegen path to be inside the `genDir`
|
// transplant the codegen path to be inside the `genDir`
|
||||||
var relativePath: string = path.relative(root, filePath);
|
let relativePath: string = path.relative(root, filePath);
|
||||||
while (relativePath.startsWith('..' + path.sep)) {
|
while (relativePath.startsWith('..' + path.sep)) {
|
||||||
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
||||||
// into `genDir`.
|
// into `genDir`.
|
||||||
relativePath = relativePath.substr(3);
|
relativePath = relativePath.substr(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.join(this.options.genDir, relativePath);
|
return path.join(this.options.genDir, relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
codegen(): Promise<any> {
|
codegen(): Promise<any> {
|
||||||
const {fileMetas, ngModules} = this.moduleCollector.getModuleSymbols(this.program);
|
const ngModules = this.moduleCollector.getModuleSymbols();
|
||||||
const analyzedNgModules = this.compiler.analyzeModules(ngModules);
|
|
||||||
return Promise.all(fileMetas.map(
|
return this.compiler.compileModules(ngModules).then(generatedModules => {
|
||||||
(fileMeta) =>
|
generatedModules.forEach(generatedModule => {
|
||||||
this.compiler
|
const sourceFile = this.program.getSourceFile(generatedModule.fileUrl);
|
||||||
.compile(
|
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
||||||
fileMeta.fileUrl, analyzedNgModules, fileMeta.directives, fileMeta.ngModules)
|
this.host.writeFile(
|
||||||
.then((generatedModules) => {
|
emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
|
||||||
generatedModules.forEach((generatedModule) => {
|
});
|
||||||
const sourceFile = this.program.getSourceFile(fileMeta.fileUrl);
|
});
|
||||||
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
|
||||||
this.host.writeFile(
|
|
||||||
emitPath, PREAMBLE + generatedModule.source, false, () => {}, [sourceFile]);
|
|
||||||
});
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
|
@ -201,9 +194,3 @@ export class CodeGenerator {
|
||||||
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
|
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileMetadata {
|
|
||||||
fileUrl: string;
|
|
||||||
directives: StaticSymbol[];
|
|
||||||
ngModules: StaticSymbol[];
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract i18n messages from source code
|
* Extract i18n messages from source code
|
||||||
*
|
|
||||||
* TODO(vicb): factorize code with the CodeGenerator
|
|
||||||
*/
|
*/
|
||||||
// Must be imported first, because angular2 decorators throws on load.
|
// Must be imported first, because angular2 decorators throws on load.
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
|
@ -18,16 +18,13 @@ import 'reflect-metadata';
|
||||||
import * as compiler from '@angular/compiler';
|
import * as compiler from '@angular/compiler';
|
||||||
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
|
import {Component, NgModule, ViewEncapsulation} from '@angular/core';
|
||||||
import * as tsc from '@angular/tsc-wrapped';
|
import * as tsc from '@angular/tsc-wrapped';
|
||||||
import * as path from 'path';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Console} from './private_import_core';
|
|
||||||
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
||||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
import {StaticReflector, StaticSymbol} from './static_reflector';
|
import {StaticReflector, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||||
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
|
||||||
|
|
||||||
export class Extractor {
|
export class Extractor {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -37,82 +34,82 @@ export class Extractor {
|
||||||
private metadataResolver: compiler.CompileMetadataResolver,
|
private metadataResolver: compiler.CompileMetadataResolver,
|
||||||
private directiveNormalizer: compiler.DirectiveNormalizer) {}
|
private directiveNormalizer: compiler.DirectiveNormalizer) {}
|
||||||
|
|
||||||
private readFileMetadata(absSourcePath: string): FileMetadata {
|
private readModuleSymbols(absSourcePath: string): StaticSymbol[] {
|
||||||
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
||||||
const result: FileMetadata = {components: [], ngModules: [], fileUrl: absSourcePath};
|
const modSymbols: StaticSymbol[] = [];
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
||||||
return result;
|
return modSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = moduleMetadata['metadata'];
|
const metadata = moduleMetadata['metadata'];
|
||||||
const symbols = metadata && Object.keys(metadata);
|
const symbols = metadata && Object.keys(metadata);
|
||||||
if (!symbols || !symbols.length) {
|
if (!symbols || !symbols.length) {
|
||||||
return result;
|
return modSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const symbol of symbols) {
|
for (const symbol of symbols) {
|
||||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||||
// Ignore symbols that are only included to record error information.
|
// Ignore symbols that are only included to record error information.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
||||||
const annotations = this.staticReflector.annotations(staticType);
|
const annotations = this.staticReflector.annotations(staticType);
|
||||||
annotations.forEach((annotation) => {
|
|
||||||
if (annotation instanceof NgModule) {
|
annotations.some(a => {
|
||||||
result.ngModules.push(staticType);
|
if (a instanceof NgModule) {
|
||||||
} else if (annotation instanceof Component) {
|
modSymbols.push(staticType);
|
||||||
result.components.push(staticType);
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return modSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
extract(): Promise<compiler.MessageBundle> {
|
extract(): Promise<compiler.MessageBundle> {
|
||||||
const skipFileNames = (this.options.generateCodeForLibraries === false) ?
|
|
||||||
GENERATED_OR_DTS_FILES :
|
|
||||||
GENERATED_FILES;
|
|
||||||
const filePaths =
|
const filePaths =
|
||||||
this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !skipFileNames.test(f));
|
this.program.getSourceFiles().map(sf => sf.fileName).filter(f => !GENERATED_FILES.test(f));
|
||||||
const fileMetas = filePaths.map((filePath) => this.readFileMetadata(filePath));
|
const ngModules: StaticSymbol[] = [];
|
||||||
const ngModules = fileMetas.reduce((ngModules, fileMeta) => {
|
|
||||||
ngModules.push(...fileMeta.ngModules);
|
filePaths.forEach((filePath) => ngModules.push(...this.readModuleSymbols(filePath)));
|
||||||
return ngModules;
|
|
||||||
}, <StaticSymbol[]>[]);
|
const files = compiler.analyzeNgModules(ngModules, this.metadataResolver).files;
|
||||||
const analyzedNgModules = compiler.analyzeModules(ngModules, this.metadataResolver);
|
const errors: compiler.ParseError[] = [];
|
||||||
const errors: compiler.ParseError[] = [];
|
const filePromises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const cmpPromises: Promise<compiler.CompileDirectiveMetadata>[] = [];
|
||||||
|
file.directives.forEach(directiveType => {
|
||||||
|
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
|
if (dirMeta.isComponent) {
|
||||||
|
cmpPromises.push(this.directiveNormalizer.normalizeDirective(dirMeta).asyncResult);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cmpPromises.length) {
|
||||||
|
const done =
|
||||||
|
Promise.all(cmpPromises).then((compMetas: compiler.CompileDirectiveMetadata[]) => {
|
||||||
|
compMetas.forEach(compMeta => {
|
||||||
|
const html = compMeta.template.template;
|
||||||
|
const interpolationConfig =
|
||||||
|
compiler.InterpolationConfig.fromArray(compMeta.template.interpolation);
|
||||||
|
errors.push(...this.messageBundle.updateFromTemplate(
|
||||||
|
html, file.srcUrl, interpolationConfig));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
filePromises.push(done);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let bundlePromise =
|
|
||||||
Promise
|
|
||||||
.all(fileMetas.map((fileMeta) => {
|
|
||||||
const url = fileMeta.fileUrl;
|
|
||||||
return Promise.all(fileMeta.components.map(compType => {
|
|
||||||
const compMeta = this.metadataResolver.getDirectiveMetadata(<any>compType);
|
|
||||||
const ngModule = analyzedNgModules.ngModuleByDirective.get(compType);
|
|
||||||
if (!ngModule) {
|
|
||||||
throw new Error(
|
|
||||||
`Cannot determine the module for component ${compMeta.type.name}!`);
|
|
||||||
}
|
|
||||||
return Promise
|
|
||||||
.all([compMeta, ...ngModule.transitiveModule.directives].map(
|
|
||||||
dirMeta =>
|
|
||||||
this.directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
|
|
||||||
.then((normalizedCompWithDirectives) => {
|
|
||||||
const compMeta = normalizedCompWithDirectives[0];
|
|
||||||
const html = compMeta.template.template;
|
|
||||||
const interpolationConfig =
|
|
||||||
compiler.InterpolationConfig.fromArray(compMeta.template.interpolation);
|
|
||||||
errors.push(
|
|
||||||
...this.messageBundle.updateFromTemplate(html, url, interpolationConfig));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}))
|
|
||||||
.then(_ => this.messageBundle);
|
|
||||||
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
throw new Error(errors.map(e => e.toString()).join('\n'));
|
throw new Error(errors.map(e => e.toString()).join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bundlePromise;
|
return Promise.all(filePromises).then(_ => this.messageBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
|
@ -148,10 +145,4 @@ export class Extractor {
|
||||||
options, program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver,
|
options, program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver,
|
||||||
normalizer);
|
normalizer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FileMetadata {
|
|
||||||
fileUrl: string;
|
|
||||||
components: StaticSymbol[];
|
|
||||||
ngModules: StaticSymbol[];
|
|
||||||
}
|
|
|
@ -250,6 +250,12 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||||
} else {
|
} else {
|
||||||
const sf = this.program.getSourceFile(filePath);
|
const sf = this.program.getSourceFile(filePath);
|
||||||
if (!sf) {
|
if (!sf) {
|
||||||
|
if (this.context.fileExists(filePath)) {
|
||||||
|
const sourceText = this.context.readFile(filePath);
|
||||||
|
return this.metadataCollector.getMetadata(
|
||||||
|
ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true));
|
||||||
|
}
|
||||||
|
|
||||||
throw new Error(`Source file ${filePath} not present in program.`);
|
throw new Error(`Source file ${filePath} not present in program.`);
|
||||||
}
|
}
|
||||||
return this.metadataCollector.getMetadata(sf);
|
return this.metadataCollector.getMetadata(sf);
|
||||||
|
|
|
@ -508,7 +508,7 @@ export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata regarding compilation of a directive.
|
* Metadata regarding compilation of a module.
|
||||||
*/
|
*/
|
||||||
export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
||||||
type: CompileTypeMetadata;
|
type: CompileTypeMetadata;
|
||||||
|
@ -568,6 +568,7 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
||||||
export class TransitiveCompileNgModuleMetadata {
|
export class TransitiveCompileNgModuleMetadata {
|
||||||
directivesSet = new Set<Type<any>>();
|
directivesSet = new Set<Type<any>>();
|
||||||
pipesSet = new Set<Type<any>>();
|
pipesSet = new Set<Type<any>>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
|
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
|
||||||
public entryComponents: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
|
public entryComponents: CompileTypeMetadata[], public directives: CompileDirectiveMetadata[],
|
||||||
|
@ -580,11 +581,13 @@ export class TransitiveCompileNgModuleMetadata {
|
||||||
export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
|
export function removeIdentifierDuplicates<T extends CompileMetadataWithIdentifier>(items: T[]):
|
||||||
T[] {
|
T[] {
|
||||||
const map = new Map<any, T>();
|
const map = new Map<any, T>();
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
if (!map.get(item.identifier.reference)) {
|
if (!map.get(item.identifier.reference)) {
|
||||||
map.set(item.identifier.reference, item);
|
map.set(item.identifier.reference, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return MapWrapper.values(map);
|
return MapWrapper.values(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -378,15 +378,15 @@ export class CompileMetadataResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getTypeDescriptor(type: Type<any>): string {
|
private _getTypeDescriptor(type: Type<any>): string {
|
||||||
if (this._directiveResolver.resolve(type, false) !== null) {
|
if (this._directiveResolver.resolve(type, false)) {
|
||||||
return 'directive';
|
return 'directive';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._pipeResolver.resolve(type, false) !== null) {
|
if (this._pipeResolver.resolve(type, false)) {
|
||||||
return 'pipe';
|
return 'pipe';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._ngModuleResolver.resolve(type, false) !== null) {
|
if (this._ngModuleResolver.resolve(type, false)) {
|
||||||
return 'module';
|
return 'module';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +508,7 @@ export class CompileMetadataResolver {
|
||||||
let isOptional = false;
|
let isOptional = false;
|
||||||
let query: Query = null;
|
let query: Query = null;
|
||||||
let viewQuery: Query = null;
|
let viewQuery: Query = null;
|
||||||
var token: any = null;
|
let token: any = null;
|
||||||
if (Array.isArray(param)) {
|
if (Array.isArray(param)) {
|
||||||
param.forEach((paramEntry) => {
|
param.forEach((paramEntry) => {
|
||||||
if (paramEntry instanceof Host) {
|
if (paramEntry instanceof Host) {
|
||||||
|
@ -605,19 +605,20 @@ export class CompileMetadataResolver {
|
||||||
} else if (isValidType(provider)) {
|
} else if (isValidType(provider)) {
|
||||||
compileProvider = this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
|
compileProvider = this.getTypeMetadata(provider, staticTypeModuleUrl(provider));
|
||||||
} else {
|
} else {
|
||||||
let providersInfo = (<string[]>providers.reduce(
|
const providersInfo =
|
||||||
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
(<string[]>providers.reduce(
|
||||||
if (seenProviderIdx < providerIdx) {
|
(soFar: string[], seenProvider: any, seenProviderIdx: number) => {
|
||||||
soFar.push(`${stringify(seenProvider)}`);
|
if (seenProviderIdx < providerIdx) {
|
||||||
} else if (seenProviderIdx == providerIdx) {
|
soFar.push(`${stringify(seenProvider)}`);
|
||||||
soFar.push(`?${stringify(seenProvider)}?`);
|
} else if (seenProviderIdx == providerIdx) {
|
||||||
} else if (seenProviderIdx == providerIdx + 1) {
|
soFar.push(`?${stringify(seenProvider)}?`);
|
||||||
soFar.push('...');
|
} else if (seenProviderIdx == providerIdx + 1) {
|
||||||
}
|
soFar.push('...');
|
||||||
return soFar;
|
}
|
||||||
},
|
return soFar;
|
||||||
[]))
|
},
|
||||||
.join(', ');
|
[]))
|
||||||
|
.join(', ');
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`);
|
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {AnimationParser} from './animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
|
import {ListWrapper, MapWrapper} from './facade/collection';
|
||||||
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
||||||
import {CompileMetadataResolver} from './metadata_resolver';
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
import {NgModuleCompiler} from './ng_module_compiler';
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
|
@ -23,28 +24,63 @@ import {TemplateParser} from './template_parser/template_parser';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
|
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
|
||||||
|
|
||||||
export class SourceModule {
|
export class SourceModule {
|
||||||
constructor(public moduleUrl: string, public source: string) {}
|
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NgModulesSummary {
|
// Returns all the source files and a mapping from modules to directives
|
||||||
constructor(
|
export function analyzeNgModules(
|
||||||
public ngModuleByDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
ngModules: StaticSymbol[], metadataResolver: CompileMetadataResolver): {
|
||||||
public ngModules: CompileNgModuleMetadata[]) {}
|
ngModuleByDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
}
|
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>
|
||||||
|
} {
|
||||||
|
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
||||||
|
|
||||||
export function analyzeModules(
|
// For every input modules add the list of transitively included modules
|
||||||
ngModules: StaticSymbol[], metadataResolver: CompileMetadataResolver) {
|
ngModules.forEach(ngModule => {
|
||||||
|
const modMeta = metadataResolver.getNgModuleMetadata(ngModule);
|
||||||
|
modMeta.transitiveModule.modules.forEach(
|
||||||
|
modMeta => { moduleMetasByRef.set(modMeta.type.reference, modMeta); });
|
||||||
|
});
|
||||||
|
|
||||||
|
const ngModuleMetas = MapWrapper.values(moduleMetasByRef);
|
||||||
const ngModuleByDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
const ngModuleByDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||||
const modules: CompileNgModuleMetadata[] = [];
|
const ngModulesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const ngDirectivesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const srcFileUrls = new Set<string>();
|
||||||
|
|
||||||
|
// Looping over all modules to construct:
|
||||||
|
// - a map from files to modules `ngModulesByFile`,
|
||||||
|
// - a map from files to directives `ngDirectivesByFile`,
|
||||||
|
// - a map from modules to directives `ngModuleByDirective`.
|
||||||
|
ngModuleMetas.forEach((ngModuleMeta) => {
|
||||||
|
const srcFileUrl = ngModuleMeta.type.reference.filePath;
|
||||||
|
srcFileUrls.add(srcFileUrl);
|
||||||
|
ngModulesByFile.set(
|
||||||
|
srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference));
|
||||||
|
|
||||||
ngModules.forEach((ngModule) => {
|
|
||||||
const ngModuleMeta = metadataResolver.getNgModuleMetadata(<any>ngModule);
|
|
||||||
modules.push(ngModuleMeta);
|
|
||||||
ngModuleMeta.declaredDirectives.forEach((dirMeta: CompileDirectiveMetadata) => {
|
ngModuleMeta.declaredDirectives.forEach((dirMeta: CompileDirectiveMetadata) => {
|
||||||
|
const fileUrl = dirMeta.type.reference.filePath;
|
||||||
|
srcFileUrls.add(fileUrl);
|
||||||
|
ngDirectivesByFile.set(
|
||||||
|
fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirMeta.type.reference));
|
||||||
ngModuleByDirective.set(dirMeta.type.reference, ngModuleMeta);
|
ngModuleByDirective.set(dirMeta.type.reference, ngModuleMeta);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return new NgModulesSummary(ngModuleByDirective, modules);
|
|
||||||
|
const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = [];
|
||||||
|
|
||||||
|
srcFileUrls.forEach((srcUrl) => {
|
||||||
|
const directives = ngDirectivesByFile.get(srcUrl) || [];
|
||||||
|
const ngModules = ngModulesByFile.get(srcUrl) || [];
|
||||||
|
files.push({srcUrl, directives, ngModules});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
// map from modules to declared directives
|
||||||
|
ngModuleByDirective,
|
||||||
|
// list of modules and directives for every source file
|
||||||
|
files,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OfflineCompiler {
|
export class OfflineCompiler {
|
||||||
|
@ -59,19 +95,26 @@ export class OfflineCompiler {
|
||||||
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
||||||
private _localeId: string, private _translationFormat: string) {}
|
private _localeId: string, private _translationFormat: string) {}
|
||||||
|
|
||||||
analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
|
|
||||||
return analyzeModules(ngModules, this._metadataResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
this._directiveNormalizer.clearCache();
|
this._directiveNormalizer.clearCache();
|
||||||
this._metadataResolver.clearCache();
|
this._metadataResolver.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(
|
compileModules(ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
||||||
moduleUrl: string, ngModulesSummary: NgModulesSummary, directives: StaticSymbol[],
|
const {ngModuleByDirective, files} = analyzeNgModules(ngModules, this._metadataResolver);
|
||||||
ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
|
||||||
const fileSuffix = _splitTypescriptSuffix(moduleUrl)[1];
|
const sourceModules = files.map(
|
||||||
|
file => this._compileSrcFile(
|
||||||
|
file.srcUrl, ngModuleByDirective, file.directives, file.ngModules));
|
||||||
|
|
||||||
|
return Promise.all(sourceModules)
|
||||||
|
.then((modules: SourceModule[][]) => ListWrapper.flatten(modules));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _compileSrcFile(
|
||||||
|
srcFileUrl: string, ngModuleByDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
|
directives: StaticSymbol[], ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
||||||
|
const fileSuffix = _splitTypescriptSuffix(srcFileUrl)[1];
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
const exportedVars: string[] = [];
|
const exportedVars: string[] = [];
|
||||||
const outputSourceModules: SourceModule[] = [];
|
const outputSourceModules: SourceModule[] = [];
|
||||||
|
@ -91,7 +134,7 @@ export class OfflineCompiler {
|
||||||
if (!compMeta.isComponent) {
|
if (!compMeta.isComponent) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
const ngModule = ngModulesSummary.ngModuleByDirective.get(dirType);
|
const ngModule = ngModuleByDirective.get(dirType);
|
||||||
if (!ngModule) {
|
if (!ngModule) {
|
||||||
throw new Error(`Cannot determine the module for component ${compMeta.type.name}!`);
|
throw new Error(`Cannot determine the module for component ${compMeta.type.name}!`);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +149,8 @@ export class OfflineCompiler {
|
||||||
// compile styles
|
// compile styles
|
||||||
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
||||||
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
||||||
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
|
outputSourceModules.push(
|
||||||
|
this._codgenStyles(srcFileUrl, compiledStyleSheet, fileSuffix));
|
||||||
});
|
});
|
||||||
|
|
||||||
// compile components
|
// compile components
|
||||||
|
@ -119,8 +163,9 @@ export class OfflineCompiler {
|
||||||
}))
|
}))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (statements.length > 0) {
|
if (statements.length > 0) {
|
||||||
outputSourceModules.unshift(this._codegenSourceModule(
|
const srcModule = this._codegenSourceModule(
|
||||||
_ngfactoryModuleUrl(moduleUrl), statements, exportedVars));
|
srcFileUrl, _ngfactoryModuleUrl(srcFileUrl), statements, exportedVars);
|
||||||
|
outputSourceModules.unshift(srcModule);
|
||||||
}
|
}
|
||||||
return outputSourceModules;
|
return outputSourceModules;
|
||||||
});
|
});
|
||||||
|
@ -209,18 +254,21 @@ export class OfflineCompiler {
|
||||||
return viewResult.viewFactoryVar;
|
return viewResult.viewFactoryVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _codgenStyles(stylesCompileResult: CompiledStylesheet, fileSuffix: string): SourceModule {
|
private _codgenStyles(
|
||||||
|
fileUrl: string, stylesCompileResult: CompiledStylesheet, fileSuffix: string): SourceModule {
|
||||||
_resolveStyleStatements(stylesCompileResult, fileSuffix);
|
_resolveStyleStatements(stylesCompileResult, fileSuffix);
|
||||||
return this._codegenSourceModule(
|
return this._codegenSourceModule(
|
||||||
_stylesModuleUrl(
|
fileUrl, _stylesModuleUrl(
|
||||||
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
||||||
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
|
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _codegenSourceModule(
|
private _codegenSourceModule(
|
||||||
moduleUrl: string, statements: o.Statement[], exportedVars: string[]): SourceModule {
|
fileUrl: string, moduleUrl: string, statements: o.Statement[],
|
||||||
|
exportedVars: string[]): SourceModule {
|
||||||
return new SourceModule(
|
return new SourceModule(
|
||||||
moduleUrl, this._outputEmitter.emitStatements(moduleUrl, statements, exportedVars));
|
fileUrl, moduleUrl,
|
||||||
|
this._outputEmitter.emitStatements(moduleUrl, statements, exportedVars));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ LINKABLE_PKGS=(
|
||||||
PKGS=(
|
PKGS=(
|
||||||
reflect-metadata@0.1.8
|
reflect-metadata@0.1.8
|
||||||
typescript@2.0.2
|
typescript@2.0.2
|
||||||
zone.js@0.6.21
|
zone.js@0.6.25
|
||||||
rxjs@5.0.0-beta.11
|
rxjs@5.0.0-beta.12
|
||||||
@types/{node@6.0.38,jasmine@2.2.33}
|
@types/{node@6.0.38,jasmine@2.2.33}
|
||||||
jasmine@2.4.1
|
jasmine@2.4.1
|
||||||
webpack@2.1.0-beta.21
|
webpack@2.1.0-beta.21
|
||||||
|
@ -35,12 +35,20 @@ cp -v package.json $TMP
|
||||||
npm install ${LINKABLE_PKGS[*]}
|
npm install ${LINKABLE_PKGS[*]}
|
||||||
|
|
||||||
./node_modules/.bin/tsc --version
|
./node_modules/.bin/tsc --version
|
||||||
|
# Compile the compiler-cli third_party simulation.
|
||||||
|
# Use ngc-wrapped directly so we don't produce *.ngfactory.ts files!
|
||||||
|
|
||||||
# Compile the compiler-cli integration tests
|
# Compile the compiler-cli integration tests
|
||||||
# TODO(vicb): restore the test for .xtb
|
# TODO(vicb): restore the test for .xtb
|
||||||
#./node_modules/.bin/ngc --i18nFile=src/messages.fi.xtb --locale=fi --i18nFormat=xtb
|
#./node_modules/.bin/ngc -p tsconfig-build.json --i18nFile=src/messages.fi.xtb --locale=fi --i18nFormat=xtb
|
||||||
./node_modules/.bin/ngc --i18nFile=src/messages.fi.xlf --locale=fi --i18nFormat=xlf
|
|
||||||
./node_modules/.bin/ng-xi18n --i18nFormat=xlf
|
# Generate the metadata for the third-party modules
|
||||||
./node_modules/.bin/ng-xi18n --i18nFormat=xmb
|
node ./node_modules/@angular/tsc-wrapped/src/main -p third_party_src/tsconfig-build.json
|
||||||
|
|
||||||
|
./node_modules/.bin/ngc -p tsconfig-build.json --i18nFile=src/messages.fi.xlf --locale=fi --i18nFormat=xlf
|
||||||
|
|
||||||
|
./node_modules/.bin/ng-xi18n -p tsconfig-build.json --i18nFormat=xlf
|
||||||
|
./node_modules/.bin/ng-xi18n -p tsconfig-build.json --i18nFormat=xmb
|
||||||
|
|
||||||
./node_modules/.bin/jasmine init
|
./node_modules/.bin/jasmine init
|
||||||
# Run compiler-cli integration tests in node
|
# Run compiler-cli integration tests in node
|
||||||
|
@ -48,6 +56,6 @@ cp -v package.json $TMP
|
||||||
./node_modules/.bin/jasmine ./all_spec.js
|
./node_modules/.bin/jasmine ./all_spec.js
|
||||||
|
|
||||||
# Compile again with a differently named tsconfig file
|
# Compile again with a differently named tsconfig file
|
||||||
mv tsconfig.json othername.json
|
mv tsconfig-build.json othername.json
|
||||||
./node_modules/.bin/ngc -p othername.json
|
./node_modules/.bin/ngc -p othername.json
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue