style(compiler-cli): reformat of codebase with new clang-format version (#36520)
This commit reformats the packages/compiler-cli tree using the new version of clang-format. PR Close #36520
This commit is contained in:
parent
717df13207
commit
0a69a2832b
|
@ -20,7 +20,9 @@ export class NormalService {
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
found: boolean;
|
found: boolean;
|
||||||
constructor(service: ShakeableService) { this.found = !!service.normal; }
|
constructor(service: ShakeableService) {
|
||||||
|
this.found = !!service.normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -29,7 +29,9 @@ export class AppComponent {
|
||||||
export class ChildComponent {
|
export class ChildComponent {
|
||||||
found: boolean;
|
found: boolean;
|
||||||
|
|
||||||
constructor(@Optional() @Self() service: Service|null) { this.found = !!service; }
|
constructor(@Optional() @Self() service: Service|null) {
|
||||||
|
this.found = !!service;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -21,7 +21,9 @@ export class NormalService {
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
found: boolean;
|
found: boolean;
|
||||||
constructor(service: NormalService) { this.found = !!service.shakeable; }
|
constructor(service: NormalService) {
|
||||||
|
this.found = !!service.shakeable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -17,7 +17,9 @@ import {ServerModule} from '@angular/platform-server';
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
data: string;
|
data: string;
|
||||||
constructor(service: Service) { this.data = service.data; }
|
constructor(service: Service) {
|
||||||
|
this.data = service.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, Inject, Injectable, InjectionToken, NgModule, forwardRef, inject} from '@angular/core';
|
import {Component, forwardRef, Inject, inject, Injectable, InjectionToken, NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {ServerModule} from '@angular/platform-server';
|
import {ServerModule} from '@angular/platform-server';
|
||||||
|
|
||||||
export interface IService { readonly dep: {readonly data: string;}; }
|
export interface IService {
|
||||||
|
readonly dep: {readonly data: string;};
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class TokenModule {
|
export class TokenModule {
|
||||||
|
@ -28,7 +30,9 @@ export const TOKEN = new InjectionToken('test', {
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
data: string;
|
data: string;
|
||||||
constructor(@Inject(TOKEN) service: IService) { this.data = service.dep.data; }
|
constructor(@Inject(TOKEN) service: IService) {
|
||||||
|
this.data = service.dep.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, INJECTOR, Injectable, NgModule} from '@angular/core';
|
import {Component, Injectable, INJECTOR, NgModule} from '@angular/core';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {renderModuleFactory} from '@angular/platform-server';
|
import {renderModuleFactory} from '@angular/platform-server';
|
||||||
import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory';
|
import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory';
|
||||||
|
@ -104,7 +104,6 @@ describe('ngInjectableDef Bazel Integration', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows provider override in JIT for module-scoped @Injectables', () => {
|
it('allows provider override in JIT for module-scoped @Injectables', () => {
|
||||||
|
|
||||||
@NgModule()
|
@NgModule()
|
||||||
class Module {
|
class Module {
|
||||||
}
|
}
|
||||||
|
@ -172,7 +171,9 @@ describe('ngInjectableDef Bazel Integration', () => {
|
||||||
|
|
||||||
// ChildServices exteds ParentService but does not have @Injectable
|
// ChildServices exteds ParentService but does not have @Injectable
|
||||||
class ChildService extends ParentService {
|
class ChildService extends ParentService {
|
||||||
constructor(value: string) { super(value); }
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
static ngInjectableDef = {
|
static ngInjectableDef = {
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
factory: () => new ChildService('child'),
|
factory: () => new ChildService('child'),
|
||||||
|
|
|
@ -6,17 +6,23 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable, InjectionToken, Injector, NgModule, forwardRef, ɵcreateInjector as createInjector} from '@angular/core';
|
import {forwardRef, Injectable, InjectionToken, Injector, NgModule, ɵcreateInjector as createInjector} from '@angular/core';
|
||||||
import {AOT_TOKEN, AotModule, AotService} from 'app_built/src/module';
|
import {AOT_TOKEN, AotModule, AotService} from 'app_built/src/module';
|
||||||
|
|
||||||
describe('Ivy NgModule', () => {
|
describe('Ivy NgModule', () => {
|
||||||
describe('AOT', () => {
|
describe('AOT', () => {
|
||||||
let injector: Injector;
|
let injector: Injector;
|
||||||
|
|
||||||
beforeEach(() => { injector = createInjector(AotModule); });
|
beforeEach(() => {
|
||||||
it('works', () => { expect(injector.get(AotService) instanceof AotService).toBeTruthy(); });
|
injector = createInjector(AotModule);
|
||||||
|
});
|
||||||
|
it('works', () => {
|
||||||
|
expect(injector.get(AotService) instanceof AotService).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it('merges imports and exports', () => { expect(injector.get(AOT_TOKEN)).toEqual('exports'); });
|
it('merges imports and exports', () => {
|
||||||
|
expect(injector.get(AOT_TOKEN)).toEqual('exports');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +44,9 @@ describe('Ivy NgModule', () => {
|
||||||
class JitAppModule {
|
class JitAppModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
it('works', () => { createInjector(JitAppModule); });
|
it('works', () => {
|
||||||
|
createInjector(JitAppModule);
|
||||||
|
});
|
||||||
|
|
||||||
it('throws an error on circular module dependencies', () => {
|
it('throws an error on circular module dependencies', () => {
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -16,10 +16,8 @@ export class LazyFeatureComponent {
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild([
|
imports: [RouterModule.forChild([
|
||||||
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
|
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
|
||||||
{path: 'feature', loadChildren: './feature.module#FeatureModule'}, {
|
{path: 'feature', loadChildren: './feature.module#FeatureModule'},
|
||||||
path: 'nested-feature',
|
{path: 'nested-feature', loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'}
|
||||||
loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'
|
|
||||||
}
|
|
||||||
])],
|
])],
|
||||||
declarations: [LazyFeatureComponent]
|
declarations: [LazyFeatureComponent]
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {AUTO_STYLE, animate, state, style, transition, trigger} from '@angular/animations';
|
import {animate, AUTO_STYLE, state, style, transition, trigger} from '@angular/animations';
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -30,8 +30,16 @@ import {Component} from '@angular/core';
|
||||||
})
|
})
|
||||||
export class AnimateCmp {
|
export class AnimateCmp {
|
||||||
stateExpression: string;
|
stateExpression: string;
|
||||||
constructor() { this.setAsClosed(); }
|
constructor() {
|
||||||
setAsSomethingElse() { this.stateExpression = 'something'; }
|
this.setAsClosed();
|
||||||
setAsOpen() { this.stateExpression = 'open'; }
|
}
|
||||||
setAsClosed() { this.stateExpression = 'closed'; }
|
setAsSomethingElse() {
|
||||||
|
this.stateExpression = 'something';
|
||||||
|
}
|
||||||
|
setAsOpen() {
|
||||||
|
this.stateExpression = 'open';
|
||||||
|
}
|
||||||
|
setAsClosed() {
|
||||||
|
this.stateExpression = 'closed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
import {InjectionToken} from '@angular/core';
|
import {InjectionToken} from '@angular/core';
|
||||||
|
|
||||||
export interface Named { name: string; }
|
export interface Named {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const CUSTOM = new InjectionToken<Named>('CUSTOM');
|
export const CUSTOM = new InjectionToken<Named>('CUSTOM');
|
||||||
|
|
|
@ -10,5 +10,7 @@ import {Component} from '@angular/core';
|
||||||
|
|
||||||
@Component({selector: 'comp-with-error', templateUrl: 'errors.html'})
|
@Component({selector: 'comp-with-error', templateUrl: 'errors.html'})
|
||||||
export class BindingErrorComp {
|
export class BindingErrorComp {
|
||||||
createError() { throw new Error('Test'); }
|
createError() {
|
||||||
|
throw new Error('Test');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as common from '@angular/common';
|
import * as common from '@angular/common';
|
||||||
import {CUSTOM_ELEMENTS_SCHEMA, Component, Directive, EventEmitter, Inject, InjectionToken, NgModule, Output, forwardRef} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, Directive, EventEmitter, forwardRef, Inject, InjectionToken, NgModule, Output} from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
import {wrapInArray} from './funcs';
|
import {wrapInArray} from './funcs';
|
||||||
|
@ -62,7 +62,9 @@ export class CompUsingCustomElements {
|
||||||
})
|
})
|
||||||
export class CompConsumingEvents {
|
export class CompConsumingEvents {
|
||||||
handleDomEventVoid(e: any): void {}
|
handleDomEventVoid(e: any): void {}
|
||||||
handleDomEventPreventDefault(e: any): boolean { return false; }
|
handleDomEventPreventDefault(e: any): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
handleDirEvent(e: any): void {}
|
handleDirEvent(e: any): void {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +72,7 @@ export class CompConsumingEvents {
|
||||||
selector: '[dirEvent]',
|
selector: '[dirEvent]',
|
||||||
})
|
})
|
||||||
export class DirPublishingEvents {
|
export class DirPublishingEvents {
|
||||||
@Output('dirEvent')
|
@Output('dirEvent') dirEvent: Observable<string> = new EventEmitter();
|
||||||
dirEvent: Observable<string> = new EventEmitter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: wrapInArray(CompUsingCustomElements)})
|
@NgModule({schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: wrapInArray(CompUsingCustomElements)})
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core';
|
||||||
const instances = new Map<any, Base>();
|
const instances = new Map<any, Base>();
|
||||||
|
|
||||||
export function expectInstanceCreated(type: any) {
|
export function expectInstanceCreated(type: any) {
|
||||||
const instance = instances.get(type) !;
|
const instance = instances.get(type)!;
|
||||||
expect(instance).toBeDefined();
|
expect(instance).toBeDefined();
|
||||||
expect(instance.dep instanceof SomeDep).toBe(true);
|
expect(instance.dep instanceof SomeDep).toBe(true);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ export function expectInstanceCreated(type: any) {
|
||||||
export class SomeDep {}
|
export class SomeDep {}
|
||||||
|
|
||||||
export class Base {
|
export class Base {
|
||||||
constructor(public dep: SomeDep) { instances.set(Object.getPrototypeOf(this).constructor, this); }
|
constructor(public dep: SomeDep) {
|
||||||
|
instances.set(Object.getPrototypeOf(this).constructor, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({templateUrl: './jit_summaries.html'})
|
@Component({templateUrl: './jit_summaries.html'})
|
||||||
|
@ -36,7 +38,9 @@ export class SomeDirective extends Base {
|
||||||
|
|
||||||
@Pipe({name: 'somePipe'})
|
@Pipe({name: 'somePipe'})
|
||||||
export class SomePipe extends Base {
|
export class SomePipe extends Base {
|
||||||
transform(value: any) { return value; }
|
transform(value: any) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ApplicationRef, NgModule, forwardRef} from '@angular/core';
|
import {ApplicationRef, forwardRef, NgModule} from '@angular/core';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
import {ServerModule} from '@angular/platform-server';
|
import {ServerModule} from '@angular/platform-server';
|
||||||
import {FlatModule} from 'flat_module';
|
import {FlatModule} from 'flat_module';
|
||||||
|
|
|
@ -19,24 +19,26 @@ export class ServiceUsingLibModule {
|
||||||
|
|
||||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||||
export class SomeDirectiveInRootModule {
|
export class SomeDirectiveInRootModule {
|
||||||
@Input()
|
@Input() someDir: string;
|
||||||
someDir: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||||
export class SomeDirectiveInLibModule {
|
export class SomeDirectiveInLibModule {
|
||||||
@Input()
|
@Input() someDir: string;
|
||||||
someDir: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pipe({name: 'somePipe'})
|
@Pipe({name: 'somePipe'})
|
||||||
export class SomePipeInRootModule {
|
export class SomePipeInRootModule {
|
||||||
transform(value: string): any { return `transformed ${value}`; }
|
transform(value: string): any {
|
||||||
|
return `transformed ${value}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pipe({name: 'somePipe'})
|
@Pipe({name: 'somePipe'})
|
||||||
export class SomePipeInLibModule {
|
export class SomePipeInLibModule {
|
||||||
transform(value: string): any { return `transformed ${value}`; }
|
transform(value: string): any {
|
||||||
|
return `transformed ${value}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
|
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
|
||||||
|
@ -66,8 +68,8 @@ export class SomeLibModule {
|
||||||
return {
|
return {
|
||||||
ngModule: SomeLibModule,
|
ngModule: SomeLibModule,
|
||||||
providers: [
|
providers: [
|
||||||
ServiceUsingLibModule, provideValueWithEntryComponents(
|
ServiceUsingLibModule,
|
||||||
[{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
provideValueWithEntryComponents([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {ServerTestingModule, platformServerTesting} from '@angular/platform-server/testing';
|
import {platformServerTesting, ServerTestingModule} from '@angular/platform-server/testing';
|
||||||
|
|
||||||
import {SomeDep, SomeDirective, SomeModule, SomePipe, SomePrivateComponent, SomeService, expectInstanceCreated} from '../src/jit_summaries';
|
import {expectInstanceCreated, SomeDep, SomeDirective, SomeModule, SomePipe, SomePrivateComponent, SomeService} from '../src/jit_summaries';
|
||||||
import {SomeModuleNgSummary} from '../src/jit_summaries.ngsummary';
|
import {SomeModuleNgSummary} from '../src/jit_summaries.ngsummary';
|
||||||
|
|
||||||
describe('Jit Summaries', () => {
|
describe('Jit Summaries', () => {
|
||||||
|
@ -18,7 +18,9 @@ describe('Jit Summaries', () => {
|
||||||
TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting(), SomeModuleNgSummary);
|
TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting(), SomeModuleNgSummary);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => { TestBed.resetTestEnvironment(); });
|
afterEach(() => {
|
||||||
|
TestBed.resetTestEnvironment();
|
||||||
|
});
|
||||||
|
|
||||||
it('should use directive metadata from summaries', () => {
|
it('should use directive metadata from summaries', () => {
|
||||||
@Component({template: '<div someDir></div>'})
|
@Component({template: '<div someDir></div>'})
|
||||||
|
|
|
@ -10,7 +10,7 @@ import './init';
|
||||||
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
|
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
|
||||||
import {ComponentUsingFlatModule} from '../src/comp_using_flat_module';
|
import {ComponentUsingFlatModule} from '../src/comp_using_flat_module';
|
||||||
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, ServiceUsingLibModule, SOME_TOKEN, SomeLibModule, SomeService} from '../src/module_fixtures';
|
||||||
|
|
||||||
import {createComponent, createModule} from './util';
|
import {createComponent, createModule} from './util';
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ describe('child queries', () => {
|
||||||
debugElement.query(By.directive(CompWithChildQuery));
|
debugElement.query(By.directive(CompWithChildQuery));
|
||||||
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
|
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
|
||||||
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
|
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support compiling children queries', () => {
|
it('should support compiling children queries', () => {
|
||||||
|
|
|
@ -31,7 +31,7 @@ function getSourcePositionForStack(stack: string): {source: string, line: number
|
||||||
const htmlLocations = stack
|
const htmlLocations = stack
|
||||||
.split('\n')
|
.split('\n')
|
||||||
// e.g. at View_MyComp_0 (...html:153:40)
|
// e.g. at View_MyComp_0 (...html:153:40)
|
||||||
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line) !)
|
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line)!)
|
||||||
.filter(match => !!match)
|
.filter(match => !!match)
|
||||||
.map(match => ({
|
.map(match => ({
|
||||||
source: match[1],
|
source: match[1],
|
||||||
|
|
|
@ -22,10 +22,15 @@ import {createProgram, readConfiguration} from '@angular/compiler-cli';
|
||||||
* properly read and wrote.
|
* properly read and wrote.
|
||||||
*/
|
*/
|
||||||
function main() {
|
function main() {
|
||||||
Promise.resolve().then(() => lazyRoutesTest()).then(() => { process.exit(0); }).catch((err) => {
|
Promise.resolve()
|
||||||
console.error(err.stack);
|
.then(() => lazyRoutesTest())
|
||||||
process.exit(1);
|
.then(() => {
|
||||||
});
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err.stack);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyRoutesTest() {
|
function lazyRoutesTest() {
|
||||||
|
@ -36,7 +41,8 @@ function lazyRoutesTest() {
|
||||||
const host = ts.createCompilerHost(config.options, true);
|
const host = ts.createCompilerHost(config.options, true);
|
||||||
const program = createProgram({
|
const program = createProgram({
|
||||||
rootNames: config.rootNames,
|
rootNames: config.rootNames,
|
||||||
options: config.options, host,
|
options: config.options,
|
||||||
|
host,
|
||||||
});
|
});
|
||||||
|
|
||||||
config.options.basePath = basePath;
|
config.options.basePath = basePath;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {platformServerTesting} from '@angular/platform-server/testing';
|
||||||
import {MainModule} from '../src/module';
|
import {MainModule} from '../src/module';
|
||||||
import {MainModuleNgFactory} from '../src/module.ngfactory';
|
import {MainModuleNgFactory} from '../src/module.ngfactory';
|
||||||
|
|
||||||
let mainModuleRef: NgModuleRef<MainModule> = null !;
|
let mainModuleRef: NgModuleRef<MainModule> = null!;
|
||||||
beforeEach((done) => {
|
beforeEach((done) => {
|
||||||
platformServerTesting().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
|
platformServerTesting().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
|
||||||
mainModuleRef = moduleRef;
|
mainModuleRef = moduleRef;
|
||||||
|
|
|
@ -35,7 +35,8 @@ export function translateDiagnostics(
|
||||||
const fileName = span.start.file.url;
|
const fileName = span.start.file.url;
|
||||||
ng.push({
|
ng.push({
|
||||||
messageText: diagnosticMessageToString(diagnostic.messageText),
|
messageText: diagnosticMessageToString(diagnostic.messageText),
|
||||||
category: diagnostic.category, span,
|
category: diagnostic.category,
|
||||||
|
span,
|
||||||
source: SOURCE,
|
source: SOURCE,
|
||||||
code: DEFAULT_ERROR_CODE
|
code: DEFAULT_ERROR_CODE
|
||||||
});
|
});
|
||||||
|
@ -53,6 +54,6 @@ function sourceSpanOf(host: TypeCheckHost, source: ts.SourceFile, start: number)
|
||||||
return host.parseSourceSpanOf(source.fileName, line, character);
|
return host.parseSourceSpanOf(source.fileName, line, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
function diagnosticMessageToString(message: ts.DiagnosticMessageChain | string): string {
|
function diagnosticMessageToString(message: ts.DiagnosticMessageChain|string): string {
|
||||||
return ts.flattenDiagnosticMessageText(message, '\n');
|
return ts.flattenDiagnosticMessageText(message, '\n');
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,4 @@ to the language service.
|
||||||
*/
|
*/
|
||||||
export {MetadataCollector, ModuleMetadata} from './metadata';
|
export {MetadataCollector, ModuleMetadata} from './metadata';
|
||||||
export {CompilerOptions} from './transformers/api';
|
export {CompilerOptions} from './transformers/api';
|
||||||
export {MetadataReaderCache, MetadataReaderHost, createMetadataReaderCache, readMetadata} from './transformers/metadata_reader';
|
export {createMetadataReaderCache, MetadataReaderCache, MetadataReaderHost, readMetadata} from './transformers/metadata_reader';
|
||||||
|
|
|
@ -24,9 +24,9 @@ import {NodeJSFileSystem, setFileSystem} from './ngtsc/file_system';
|
||||||
export function main(
|
export function main(
|
||||||
args: string[], consoleError: (s: string) => void = console.error,
|
args: string[], consoleError: (s: string) => void = console.error,
|
||||||
config?: NgcParsedConfiguration, customTransformers?: api.CustomTransformers, programReuse?: {
|
config?: NgcParsedConfiguration, customTransformers?: api.CustomTransformers, programReuse?: {
|
||||||
program: api.Program | undefined,
|
program: api.Program|undefined,
|
||||||
},
|
},
|
||||||
modifiedResourceFiles?: Set<string>| null): number {
|
modifiedResourceFiles?: Set<string>|null): number {
|
||||||
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
|
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
|
||||||
config || readNgcCommandLineAndConfiguration(args);
|
config || readNgcCommandLineAndConfiguration(args);
|
||||||
if (configErrors.length) {
|
if (configErrors.length) {
|
||||||
|
@ -47,7 +47,9 @@ export function main(
|
||||||
options,
|
options,
|
||||||
emitFlags,
|
emitFlags,
|
||||||
oldProgram,
|
oldProgram,
|
||||||
emitCallback: createEmitCallback(options), customTransformers, modifiedResourceFiles
|
emitCallback: createEmitCallback(options),
|
||||||
|
customTransformers,
|
||||||
|
modifiedResourceFiles
|
||||||
});
|
});
|
||||||
if (programReuse !== undefined) {
|
if (programReuse !== undefined) {
|
||||||
programReuse.program = program;
|
programReuse.program = program;
|
||||||
|
@ -57,8 +59,8 @@ export function main(
|
||||||
|
|
||||||
export function mainDiagnosticsForTest(
|
export function mainDiagnosticsForTest(
|
||||||
args: string[], config?: NgcParsedConfiguration,
|
args: string[], config?: NgcParsedConfiguration,
|
||||||
programReuse?: {program: api.Program | undefined},
|
programReuse?: {program: api.Program|undefined},
|
||||||
modifiedResourceFiles?: Set<string>| null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> {
|
modifiedResourceFiles?: Set<string>|null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> {
|
||||||
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
|
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
|
||||||
config || readNgcCommandLineAndConfiguration(args);
|
config || readNgcCommandLineAndConfiguration(args);
|
||||||
if (configErrors.length) {
|
if (configErrors.length) {
|
||||||
|
@ -100,9 +102,10 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un
|
||||||
options.emitDecoratorMetadata = true;
|
options.emitDecoratorMetadata = true;
|
||||||
}
|
}
|
||||||
const tsickleHost: Pick<
|
const tsickleHost: Pick<
|
||||||
tsickle.TsickleHost, 'shouldSkipTsickleProcessing'|'pathToModuleName'|
|
tsickle.TsickleHost,
|
||||||
'shouldIgnoreWarningsForPath'|'fileNameToModuleId'|'googmodule'|'untyped'|
|
'shouldSkipTsickleProcessing'|'pathToModuleName'|'shouldIgnoreWarningsForPath'|
|
||||||
'convertIndexImportShorthand'|'transformDecorators'|'transformTypesToClosure'> = {
|
'fileNameToModuleId'|'googmodule'|'untyped'|'convertIndexImportShorthand'|
|
||||||
|
'transformDecorators'|'transformTypesToClosure'> = {
|
||||||
shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName) ||
|
shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName) ||
|
||||||
// View Engine's generated files were never intended to be processed with tsickle.
|
// View Engine's generated files were never intended to be processed with tsickle.
|
||||||
(!options.enableIvy && GENERATED_FILES.test(fileName)),
|
(!options.enableIvy && GENERATED_FILES.test(fileName)),
|
||||||
|
@ -111,7 +114,9 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un
|
||||||
fileNameToModuleId: (fileName) => fileName,
|
fileNameToModuleId: (fileName) => fileName,
|
||||||
googmodule: false,
|
googmodule: false,
|
||||||
untyped: true,
|
untyped: true,
|
||||||
convertIndexImportShorthand: false, transformDecorators, transformTypesToClosure,
|
convertIndexImportShorthand: false,
|
||||||
|
transformDecorators,
|
||||||
|
transformTypesToClosure,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.annotateForClosureCompiler || options.annotationsAs === 'static fields') {
|
if (options.annotateForClosureCompiler || options.annotationsAs === 'static fields') {
|
||||||
|
@ -147,7 +152,9 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NgcParsedConfiguration extends ParsedConfiguration { watch?: boolean; }
|
export interface NgcParsedConfiguration extends ParsedConfiguration {
|
||||||
|
watch?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration {
|
export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration {
|
||||||
const options: api.CompilerOptions = {};
|
const options: api.CompilerOptions = {};
|
||||||
|
@ -194,7 +201,8 @@ export function readCommandLineAndConfiguration(
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
project,
|
project,
|
||||||
rootNames: config.rootNames, options,
|
rootNames: config.rootNames,
|
||||||
|
options,
|
||||||
errors: config.errors,
|
errors: config.errors,
|
||||||
emitFlags: config.emitFlags
|
emitFlags: config.emitFlags
|
||||||
};
|
};
|
||||||
|
@ -237,7 +245,7 @@ export function watchMode(
|
||||||
|
|
||||||
function printDiagnostics(
|
function printDiagnostics(
|
||||||
diagnostics: ReadonlyArray<ts.Diagnostic|api.Diagnostic>,
|
diagnostics: ReadonlyArray<ts.Diagnostic|api.Diagnostic>,
|
||||||
options: api.CompilerOptions | undefined, consoleError: (s: string) => void): void {
|
options: api.CompilerOptions|undefined, consoleError: (s: string) => void): void {
|
||||||
if (diagnostics.length === 0) {
|
if (diagnostics.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,7 @@ function createSyntheticIndexHost<H extends ts.CompilerHost>(
|
||||||
|
|
||||||
newHost.writeFile =
|
newHost.writeFile =
|
||||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||||
onError: ((message: string) => void) | undefined,
|
onError: ((message: string) => void)|undefined, sourceFiles: Readonly<ts.SourceFile>[]) => {
|
||||||
sourceFiles: Readonly<ts.SourceFile>[]) => {
|
|
||||||
delegate.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
delegate.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||||
if (fileName.match(DTS) && sourceFiles && sourceFiles.length == 1 &&
|
if (fileName.match(DTS) && sourceFiles && sourceFiles.length == 1 &&
|
||||||
path.normalize(sourceFiles[0].fileName) === normalSyntheticIndexName) {
|
path.normalize(sourceFiles[0].fileName) === normalSyntheticIndexName) {
|
||||||
|
@ -103,7 +102,7 @@ export function createBundleIndexHost<H extends ts.CompilerHost>(
|
||||||
// contents of the flat module index. The bundle produced during emit does use the metadata cache
|
// contents of the flat module index. The bundle produced during emit does use the metadata cache
|
||||||
// with associated transforms, so the metadata will have lowered expressions, resource inlining,
|
// with associated transforms, so the metadata will have lowered expressions, resource inlining,
|
||||||
// etc.
|
// etc.
|
||||||
const getMetadataBundle = (cache: MetadataCache | null) => {
|
const getMetadataBundle = (cache: MetadataCache|null) => {
|
||||||
const bundler = new MetadataBundler(
|
const bundler = new MetadataBundler(
|
||||||
indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host, cache, ngOptions),
|
indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host, cache, ngOptions),
|
||||||
ngOptions.flatModulePrivateSymbolPrefix);
|
ngOptions.flatModulePrivateSymbolPrefix);
|
||||||
|
@ -113,7 +112,7 @@ export function createBundleIndexHost<H extends ts.CompilerHost>(
|
||||||
// First, produce the bundle with no MetadataCache.
|
// First, produce the bundle with no MetadataCache.
|
||||||
const metadataBundle = getMetadataBundle(/* MetadataCache */ null);
|
const metadataBundle = getMetadataBundle(/* MetadataCache */ null);
|
||||||
const name =
|
const name =
|
||||||
path.join(path.dirname(indexModule), ngOptions.flatModuleOutFile !.replace(JS_EXT, '.ts'));
|
path.join(path.dirname(indexModule), ngOptions.flatModuleOutFile!.replace(JS_EXT, '.ts'));
|
||||||
const libraryIndex = `./${path.basename(indexModule)}`;
|
const libraryIndex = `./${path.basename(indexModule)}`;
|
||||||
const content = privateEntriesToIndex(libraryIndex, metadataBundle.privates);
|
const content = privateEntriesToIndex(libraryIndex, metadataBundle.privates);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
||||||
import {MetadataCache} from '../transformers/metadata_cache';
|
import {MetadataCache} from '../transformers/metadata_cache';
|
||||||
|
|
||||||
import {MetadataCollector} from './collector';
|
import {MetadataCollector} from './collector';
|
||||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicCallExpression, isMetadataSymbolicExpression, isMethodMetadata} from './schema';
|
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicCallExpression, isMetadataSymbolicExpression, isMethodMetadata, MemberMetadata, METADATA_VERSION, MetadataEntry, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata} from './schema';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +59,9 @@ interface Symbol {
|
||||||
privateName?: string;
|
privateName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BundleEntries { [name: string]: MetadataEntry; }
|
export interface BundleEntries {
|
||||||
|
[name: string]: MetadataEntry;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BundlePrivateEntry {
|
export interface BundlePrivateEntry {
|
||||||
privateName: string;
|
privateName: string;
|
||||||
|
@ -77,7 +79,7 @@ export interface MetadataBundlerHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaticsMetadata = {
|
type StaticsMetadata = {
|
||||||
[name: string]: MetadataValue | FunctionMetadata;
|
[name: string]: MetadataValue|FunctionMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class MetadataBundler {
|
export class MetadataBundler {
|
||||||
|
@ -87,7 +89,7 @@ export class MetadataBundler {
|
||||||
private rootModule: string;
|
private rootModule: string;
|
||||||
private privateSymbolPrefix: string;
|
private privateSymbolPrefix: string;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private exported !: Set<Symbol>;
|
private exported!: Set<Symbol>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private root: string, private importAs: string|undefined, private host: MetadataBundlerHost,
|
private root: string, private importAs: string|undefined, private host: MetadataBundlerHost,
|
||||||
|
@ -106,14 +108,14 @@ export class MetadataBundler {
|
||||||
const privates = Array.from(this.symbolMap.values())
|
const privates = Array.from(this.symbolMap.values())
|
||||||
.filter(s => s.referenced && s.isPrivate)
|
.filter(s => s.referenced && s.isPrivate)
|
||||||
.map(s => ({
|
.map(s => ({
|
||||||
privateName: s.privateName !,
|
privateName: s.privateName!,
|
||||||
name: s.declaration !.name,
|
name: s.declaration!.name,
|
||||||
module: s.declaration !.module
|
module: s.declaration!.module
|
||||||
}));
|
}));
|
||||||
const origins = Array.from(this.symbolMap.values())
|
const origins = Array.from(this.symbolMap.values())
|
||||||
.filter(s => s.referenced && !s.reexport)
|
.filter(s => s.referenced && !s.reexport)
|
||||||
.reduce<{[name: string]: string}>((p, s) => {
|
.reduce<{[name: string]: string}>((p, s) => {
|
||||||
p[s.isPrivate ? s.privateName ! : s.name] = s.declaration !.module;
|
p[s.isPrivate ? s.privateName! : s.name] = s.declaration!.module;
|
||||||
return p;
|
return p;
|
||||||
}, {});
|
}, {});
|
||||||
const exports = this.getReExports(exportedSymbols);
|
const exports = this.getReExports(exportedSymbols);
|
||||||
|
@ -121,8 +123,10 @@ export class MetadataBundler {
|
||||||
metadata: {
|
metadata: {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: METADATA_VERSION,
|
version: METADATA_VERSION,
|
||||||
exports: exports.length ? exports : undefined, metadata, origins,
|
exports: exports.length ? exports : undefined,
|
||||||
importAs: this.importAs !
|
metadata,
|
||||||
|
origins,
|
||||||
|
importAs: this.importAs!
|
||||||
},
|
},
|
||||||
privates
|
privates
|
||||||
};
|
};
|
||||||
|
@ -156,7 +160,7 @@ export class MetadataBundler {
|
||||||
|
|
||||||
const exportSymbol = (exportedSymbol: Symbol, exportAs: string) => {
|
const exportSymbol = (exportedSymbol: Symbol, exportAs: string) => {
|
||||||
const symbol = this.symbolOf(moduleName, exportAs);
|
const symbol = this.symbolOf(moduleName, exportAs);
|
||||||
result !.push(symbol);
|
result!.push(symbol);
|
||||||
exportedSymbol.reexportedAs = symbol;
|
exportedSymbol.reexportedAs = symbol;
|
||||||
symbol.exports = exportedSymbol;
|
symbol.exports = exportedSymbol;
|
||||||
};
|
};
|
||||||
|
@ -276,18 +280,18 @@ export class MetadataBundler {
|
||||||
Array.from(this.symbolMap.values()).forEach(symbol => {
|
Array.from(this.symbolMap.values()).forEach(symbol => {
|
||||||
if (symbol.referenced && !symbol.reexport) {
|
if (symbol.referenced && !symbol.reexport) {
|
||||||
let name = symbol.name;
|
let name = symbol.name;
|
||||||
const identifier = `${symbol.declaration!.module}:${symbol.declaration !.name}`;
|
const identifier = `${symbol.declaration!.module}:${symbol.declaration!.name}`;
|
||||||
if (symbol.isPrivate && !symbol.privateName) {
|
if (symbol.isPrivate && !symbol.privateName) {
|
||||||
name = newPrivateName(this.privateSymbolPrefix);
|
name = newPrivateName(this.privateSymbolPrefix);
|
||||||
symbol.privateName = name;
|
symbol.privateName = name;
|
||||||
}
|
}
|
||||||
if (symbolsMap.has(identifier)) {
|
if (symbolsMap.has(identifier)) {
|
||||||
const names = symbolsMap.get(identifier);
|
const names = symbolsMap.get(identifier);
|
||||||
names !.push(name);
|
names!.push(name);
|
||||||
} else {
|
} else {
|
||||||
symbolsMap.set(identifier, [name]);
|
symbolsMap.set(identifier, [name]);
|
||||||
}
|
}
|
||||||
result[name] = symbol.value !;
|
result[name] = symbol.value!;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -320,9 +324,9 @@ export class MetadataBundler {
|
||||||
for (const symbol of exportedSymbols) {
|
for (const symbol of exportedSymbols) {
|
||||||
if (symbol.reexport) {
|
if (symbol.reexport) {
|
||||||
// symbol.declaration is guaranteed to be defined during the phase this method is called.
|
// symbol.declaration is guaranteed to be defined during the phase this method is called.
|
||||||
const declaration = symbol.declaration !;
|
const declaration = symbol.declaration!;
|
||||||
const module = declaration.module;
|
const module = declaration.module;
|
||||||
if (declaration !.name == '*') {
|
if (declaration!.name == '*') {
|
||||||
// Reexport all the symbols.
|
// Reexport all the symbols.
|
||||||
exportAlls.add(declaration.module);
|
exportAlls.add(declaration.module);
|
||||||
} else {
|
} else {
|
||||||
|
@ -346,12 +350,12 @@ export class MetadataBundler {
|
||||||
|
|
||||||
private convertSymbol(symbol: Symbol) {
|
private convertSymbol(symbol: Symbol) {
|
||||||
// canonicalSymbol is ensured to be defined before this is called.
|
// canonicalSymbol is ensured to be defined before this is called.
|
||||||
const canonicalSymbol = symbol.canonicalSymbol !;
|
const canonicalSymbol = symbol.canonicalSymbol!;
|
||||||
|
|
||||||
if (!canonicalSymbol.referenced) {
|
if (!canonicalSymbol.referenced) {
|
||||||
canonicalSymbol.referenced = true;
|
canonicalSymbol.referenced = true;
|
||||||
// declaration is ensured to be definded before this method is called.
|
// declaration is ensured to be definded before this method is called.
|
||||||
const declaration = canonicalSymbol.declaration !;
|
const declaration = canonicalSymbol.declaration!;
|
||||||
const module = this.getMetadata(declaration.module);
|
const module = this.getMetadata(declaration.module);
|
||||||
if (module) {
|
if (module) {
|
||||||
const value = module.metadata[declaration.name];
|
const value = module.metadata[declaration.name];
|
||||||
|
@ -399,11 +403,11 @@ export class MetadataBundler {
|
||||||
private convertMember(moduleName: string, member: MemberMetadata) {
|
private convertMember(moduleName: string, member: MemberMetadata) {
|
||||||
const result: MemberMetadata = {__symbolic: member.__symbolic};
|
const result: MemberMetadata = {__symbolic: member.__symbolic};
|
||||||
result.decorators =
|
result.decorators =
|
||||||
member.decorators && member.decorators.map(d => this.convertExpression(moduleName, d) !);
|
member.decorators && member.decorators.map(d => this.convertExpression(moduleName, d)!);
|
||||||
if (isMethodMetadata(member)) {
|
if (isMethodMetadata(member)) {
|
||||||
(result as MethodMetadata).parameterDecorators = member.parameterDecorators &&
|
(result as MethodMetadata).parameterDecorators = member.parameterDecorators &&
|
||||||
member.parameterDecorators.map(
|
member.parameterDecorators.map(
|
||||||
d => d && d.map(p => this.convertExpression(moduleName, p) !));
|
d => d && d.map(p => this.convertExpression(moduleName, p)!));
|
||||||
if (isConstructorMetadata(member)) {
|
if (isConstructorMetadata(member)) {
|
||||||
if (member.parameters) {
|
if (member.parameters) {
|
||||||
(result as ConstructorMetadata).parameters =
|
(result as ConstructorMetadata).parameters =
|
||||||
|
@ -450,7 +454,7 @@ export class MetadataBundler {
|
||||||
return this.convertError(moduleName, value);
|
return this.convertError(moduleName, value);
|
||||||
}
|
}
|
||||||
if (isMetadataSymbolicExpression(value)) {
|
if (isMetadataSymbolicExpression(value)) {
|
||||||
return this.convertExpression(moduleName, value) !;
|
return this.convertExpression(moduleName, value)!;
|
||||||
}
|
}
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(v => this.convertValue(moduleName, v));
|
return value.map(v => this.convertValue(moduleName, v));
|
||||||
|
@ -466,8 +470,8 @@ export class MetadataBundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertExpression(
|
private convertExpression(
|
||||||
moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|
|
moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|undefined):
|
||||||
undefined): MetadataSymbolicExpression|MetadataError|undefined|null {
|
MetadataSymbolicExpression|MetadataError|undefined|null {
|
||||||
if (value) {
|
if (value) {
|
||||||
switch (value.__symbolic) {
|
switch (value.__symbolic) {
|
||||||
case 'error':
|
case 'error':
|
||||||
|
@ -487,14 +491,15 @@ export class MetadataBundler {
|
||||||
message: value.message,
|
message: value.message,
|
||||||
line: value.line,
|
line: value.line,
|
||||||
character: value.character,
|
character: value.character,
|
||||||
context: value.context, module
|
context: value.context,
|
||||||
|
module
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertReference(moduleName: string, value: MetadataSymbolicReferenceExpression):
|
private convertReference(moduleName: string, value: MetadataSymbolicReferenceExpression):
|
||||||
MetadataSymbolicReferenceExpression|MetadataError|undefined {
|
MetadataSymbolicReferenceExpression|MetadataError|undefined {
|
||||||
const createReference = (symbol: Symbol): MetadataSymbolicReferenceExpression => {
|
const createReference = (symbol: Symbol): MetadataSymbolicReferenceExpression => {
|
||||||
const declaration = symbol.declaration !;
|
const declaration = symbol.declaration!;
|
||||||
if (declaration.module.startsWith('.')) {
|
if (declaration.module.startsWith('.')) {
|
||||||
// Reference to a symbol defined in the module. Ensure it is converted then return a
|
// Reference to a symbol defined in the module. Ensure it is converted then return a
|
||||||
// references to the final symbol.
|
// references to the final symbol.
|
||||||
|
@ -503,11 +508,11 @@ export class MetadataBundler {
|
||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
get name() {
|
get name() {
|
||||||
// Resolved lazily because private names are assigned late.
|
// Resolved lazily because private names are assigned late.
|
||||||
const canonicalSymbol = symbol.canonicalSymbol !;
|
const canonicalSymbol = symbol.canonicalSymbol!;
|
||||||
if (canonicalSymbol.isPrivate == null) {
|
if (canonicalSymbol.isPrivate == null) {
|
||||||
throw Error('Invalid state: isPrivate was not initialized');
|
throw Error('Invalid state: isPrivate was not initialized');
|
||||||
}
|
}
|
||||||
return canonicalSymbol.isPrivate ? canonicalSymbol.privateName ! : canonicalSymbol.name;
|
return canonicalSymbol.isPrivate ? canonicalSymbol.privateName! : canonicalSymbol.name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -584,7 +589,7 @@ export class MetadataBundler {
|
||||||
|
|
||||||
private convertExpressionNode(moduleName: string, value: MetadataSymbolicExpression):
|
private convertExpressionNode(moduleName: string, value: MetadataSymbolicExpression):
|
||||||
MetadataSymbolicExpression {
|
MetadataSymbolicExpression {
|
||||||
const result: MetadataSymbolicExpression = { __symbolic: value.__symbolic } as any;
|
const result: MetadataSymbolicExpression = {__symbolic: value.__symbolic} as any;
|
||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
(result as any)[key] = this.convertValue(moduleName, (value as any)[key]);
|
(result as any)[key] = this.convertValue(moduleName, (value as any)[key]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Evaluator, errorSymbol, recordMapEntry} from './evaluator';
|
import {errorSymbol, Evaluator, recordMapEntry} from './evaluator';
|
||||||
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema';
|
import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata, MemberMetadata, METADATA_VERSION, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata} from './schema';
|
||||||
import {Symbols} from './symbols';
|
import {Symbols} from './symbols';
|
||||||
|
|
||||||
const isStatic = (node: ts.Declaration) =>
|
const isStatic = (node: ts.Declaration) =>
|
||||||
|
@ -60,12 +60,12 @@ export class MetadataCollector {
|
||||||
new Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>();
|
new Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>();
|
||||||
const composedSubstituter = substituteExpression && this.options.substituteExpression ?
|
const composedSubstituter = substituteExpression && this.options.substituteExpression ?
|
||||||
(value: MetadataValue, node: ts.Node) =>
|
(value: MetadataValue, node: ts.Node) =>
|
||||||
this.options.substituteExpression !(substituteExpression(value, node), node) :
|
this.options.substituteExpression!(substituteExpression(value, node), node) :
|
||||||
substituteExpression;
|
substituteExpression;
|
||||||
const evaluatorOptions = substituteExpression ?
|
const evaluatorOptions = substituteExpression ?
|
||||||
{...this.options, substituteExpression: composedSubstituter} :
|
{...this.options, substituteExpression: composedSubstituter} :
|
||||||
this.options;
|
this.options;
|
||||||
let metadata: {[name: string]: MetadataValue | ClassMetadata | FunctionMetadata}|undefined;
|
let metadata: {[name: string]: MetadataValue|ClassMetadata|FunctionMetadata}|undefined;
|
||||||
const evaluator = new Evaluator(locals, nodeMap, evaluatorOptions, (name, value) => {
|
const evaluator = new Evaluator(locals, nodeMap, evaluatorOptions, (name, value) => {
|
||||||
if (!metadata) metadata = {};
|
if (!metadata) metadata = {};
|
||||||
metadata[name] = value;
|
metadata[name] = value;
|
||||||
|
@ -88,9 +88,9 @@ export class MetadataCollector {
|
||||||
return errorSymbol(message, node, context, sourceFile);
|
return errorSymbol(message, node, context, sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeGetSimpleFunction(
|
function maybeGetSimpleFunction(functionDeclaration: ts.FunctionDeclaration|
|
||||||
functionDeclaration: ts.FunctionDeclaration |
|
ts.MethodDeclaration): {func: FunctionMetadata, name: string}|
|
||||||
ts.MethodDeclaration): {func: FunctionMetadata, name: string}|undefined {
|
undefined {
|
||||||
if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
|
if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
|
||||||
const nameNode = <ts.Identifier>functionDeclaration.name;
|
const nameNode = <ts.Identifier>functionDeclaration.name;
|
||||||
const functionName = nameNode.text;
|
const functionName = nameNode.text;
|
||||||
|
@ -119,8 +119,8 @@ export class MetadataCollector {
|
||||||
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
|
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
|
||||||
const result: ClassMetadata = {__symbolic: 'class'};
|
const result: ClassMetadata = {__symbolic: 'class'};
|
||||||
|
|
||||||
function getDecorators(decorators: ReadonlyArray<ts.Decorator>| undefined):
|
function getDecorators(decorators: ReadonlyArray<ts.Decorator>|
|
||||||
MetadataSymbolicExpression[]|undefined {
|
undefined): MetadataSymbolicExpression[]|undefined {
|
||||||
if (decorators && decorators.length)
|
if (decorators && decorators.length)
|
||||||
return decorators.map(decorator => objFromDecorator(decorator));
|
return decorators.map(decorator => objFromDecorator(decorator));
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -167,8 +167,8 @@ export class MetadataCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
// static member
|
// static member
|
||||||
let statics: {[name: string]: MetadataValue | FunctionMetadata}|null = null;
|
let statics: {[name: string]: MetadataValue|FunctionMetadata}|null = null;
|
||||||
function recordStaticMember(name: string, value: MetadataValue | FunctionMetadata) {
|
function recordStaticMember(name: string, value: MetadataValue|FunctionMetadata) {
|
||||||
if (!statics) statics = {};
|
if (!statics) statics = {};
|
||||||
statics[name] = value;
|
statics[name] = value;
|
||||||
}
|
}
|
||||||
|
@ -189,11 +189,10 @@ export class MetadataCollector {
|
||||||
}
|
}
|
||||||
const methodDecorators = getDecorators(method.decorators);
|
const methodDecorators = getDecorators(method.decorators);
|
||||||
const parameters = method.parameters;
|
const parameters = method.parameters;
|
||||||
const parameterDecoratorData:
|
const parameterDecoratorData: ((MetadataSymbolicExpression | MetadataError)[]|
|
||||||
((MetadataSymbolicExpression | MetadataError)[] | undefined)[] = [];
|
undefined)[] = [];
|
||||||
const parametersData:
|
const parametersData: (MetadataSymbolicReferenceExpression|MetadataError|
|
||||||
(MetadataSymbolicReferenceExpression | MetadataError |
|
MetadataSymbolicSelectExpression|null)[] = [];
|
||||||
MetadataSymbolicSelectExpression | null)[] = [];
|
|
||||||
let hasDecoratorData: boolean = false;
|
let hasDecoratorData: boolean = false;
|
||||||
let hasParameterData: boolean = false;
|
let hasParameterData: boolean = false;
|
||||||
for (const parameter of parameters) {
|
for (const parameter of parameters) {
|
||||||
|
@ -282,15 +281,14 @@ export class MetadataCollector {
|
||||||
ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export;
|
ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export;
|
||||||
const isExportedIdentifier = (identifier?: ts.Identifier) =>
|
const isExportedIdentifier = (identifier?: ts.Identifier) =>
|
||||||
identifier && exportMap.has(identifier.text);
|
identifier && exportMap.has(identifier.text);
|
||||||
const isExported =
|
const isExported = (node: ts.FunctionDeclaration|ts.ClassDeclaration|ts.TypeAliasDeclaration|
|
||||||
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration |
|
ts.InterfaceDeclaration|ts.EnumDeclaration) =>
|
||||||
ts.InterfaceDeclaration | ts.EnumDeclaration) =>
|
isExport(node) || isExportedIdentifier(node.name);
|
||||||
isExport(node) || isExportedIdentifier(node.name);
|
|
||||||
const exportedIdentifierName = (identifier?: ts.Identifier) =>
|
const exportedIdentifierName = (identifier?: ts.Identifier) =>
|
||||||
identifier && (exportMap.get(identifier.text) || identifier.text);
|
identifier && (exportMap.get(identifier.text) || identifier.text);
|
||||||
const exportedName =
|
const exportedName = (node: ts.FunctionDeclaration|ts.ClassDeclaration|
|
||||||
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration |
|
ts.InterfaceDeclaration|ts.TypeAliasDeclaration|ts.EnumDeclaration) =>
|
||||||
ts.TypeAliasDeclaration | ts.EnumDeclaration) => exportedIdentifierName(node.name);
|
exportedIdentifierName(node.name);
|
||||||
|
|
||||||
|
|
||||||
// Pre-declare classes and functions
|
// Pre-declare classes and functions
|
||||||
|
@ -419,8 +417,8 @@ export class MetadataCollector {
|
||||||
if (name) {
|
if (name) {
|
||||||
if (!metadata) metadata = {};
|
if (!metadata) metadata = {};
|
||||||
// TODO(alxhub): The literal here is not valid FunctionMetadata.
|
// TODO(alxhub): The literal here is not valid FunctionMetadata.
|
||||||
metadata[name] = maybeFunc ? recordEntry(maybeFunc.func, node) :
|
metadata[name] =
|
||||||
({ __symbolic: 'function' } as any);
|
maybeFunc ? recordEntry(maybeFunc.func, node) : ({__symbolic: 'function'} as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -456,7 +454,8 @@ export class MetadataCollector {
|
||||||
operator: '+',
|
operator: '+',
|
||||||
left: {
|
left: {
|
||||||
__symbolic: 'select',
|
__symbolic: 'select',
|
||||||
expression: recordEntry({__symbolic: 'reference', name: enumName}, node), name
|
expression: recordEntry({__symbolic: 'reference', name: enumName}, node),
|
||||||
|
name
|
||||||
},
|
},
|
||||||
} as any;
|
} as any;
|
||||||
} else {
|
} else {
|
||||||
|
@ -555,7 +554,8 @@ export class MetadataCollector {
|
||||||
}
|
}
|
||||||
const result: ModuleMetadata = {
|
const result: ModuleMetadata = {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: this.options.version || METADATA_VERSION, metadata
|
version: this.options.version || METADATA_VERSION,
|
||||||
|
metadata
|
||||||
};
|
};
|
||||||
if (sourceFile.moduleName) result.importAs = sourceFile.moduleName;
|
if (sourceFile.moduleName) result.importAs = sourceFile.moduleName;
|
||||||
if (exports) result.exports = exports;
|
if (exports) result.exports = exports;
|
||||||
|
@ -570,8 +570,7 @@ function validateMetadata(
|
||||||
metadata: {[name: string]: MetadataEntry}) {
|
metadata: {[name: string]: MetadataEntry}) {
|
||||||
let locals: Set<string> = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']);
|
let locals: Set<string> = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']);
|
||||||
|
|
||||||
function validateExpression(
|
function validateExpression(expression: MetadataValue|MetadataSymbolicExpression|MetadataError) {
|
||||||
expression: MetadataValue | MetadataSymbolicExpression | MetadataError) {
|
|
||||||
if (!expression) {
|
if (!expression) {
|
||||||
return;
|
return;
|
||||||
} else if (Array.isArray(expression)) {
|
} else if (Array.isArray(expression)) {
|
||||||
|
@ -648,11 +647,11 @@ function validateMetadata(
|
||||||
}
|
}
|
||||||
if (classData.members) {
|
if (classData.members) {
|
||||||
Object.getOwnPropertyNames(classData.members)
|
Object.getOwnPropertyNames(classData.members)
|
||||||
.forEach(name => classData.members ![name].forEach((m) => validateMember(classData, m)));
|
.forEach(name => classData.members![name].forEach((m) => validateMember(classData, m)));
|
||||||
}
|
}
|
||||||
if (classData.statics) {
|
if (classData.statics) {
|
||||||
Object.getOwnPropertyNames(classData.statics).forEach(name => {
|
Object.getOwnPropertyNames(classData.statics).forEach(name => {
|
||||||
const staticMember = classData.statics ![name];
|
const staticMember = classData.statics![name];
|
||||||
if (isFunctionMetadata(staticMember)) {
|
if (isFunctionMetadata(staticMember)) {
|
||||||
validateExpression(staticMember.value);
|
validateExpression(staticMember.value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -675,7 +674,7 @@ function validateMetadata(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldReportNode(node: ts.Node | undefined) {
|
function shouldReportNode(node: ts.Node|undefined) {
|
||||||
if (node) {
|
if (node) {
|
||||||
const nodeStart = node.getStart();
|
const nodeStart = node.getStart();
|
||||||
return !(
|
return !(
|
||||||
|
@ -688,12 +687,13 @@ function validateMetadata(
|
||||||
function reportError(error: MetadataError) {
|
function reportError(error: MetadataError) {
|
||||||
const node = nodeMap.get(error);
|
const node = nodeMap.get(error);
|
||||||
if (shouldReportNode(node)) {
|
if (shouldReportNode(node)) {
|
||||||
const lineInfo = error.line != undefined ?
|
const lineInfo = error.line != undefined ? error.character != undefined ?
|
||||||
error.character != undefined ? `:${error.line + 1}:${error.character + 1}` :
|
`:${error.line + 1}:${error.character + 1}` :
|
||||||
`:${error.line + 1}` :
|
`:${error.line + 1}` :
|
||||||
'';
|
'';
|
||||||
throw new Error(
|
throw new Error(`${sourceFile.fileName}${
|
||||||
`${sourceFile.fileName}${lineInfo}: Metadata collected contains an error that will be reported at runtime: ${expandedMessage(error)}.\n ${JSON.stringify(error)}`);
|
lineInfo}: Metadata collected contains an error that will be reported at runtime: ${
|
||||||
|
expandedMessage(error)}.\n ${JSON.stringify(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,8 +708,9 @@ function validateMetadata(
|
||||||
if (shouldReportNode(node)) {
|
if (shouldReportNode(node)) {
|
||||||
if (node) {
|
if (node) {
|
||||||
const {line, character} = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
const {line, character} = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
||||||
throw new Error(
|
throw new Error(`${sourceFile.fileName}:${line + 1}:${
|
||||||
`${sourceFile.fileName}:${line + 1}:${character + 1}: Error encountered in metadata generated for exported symbol '${name}': \n ${e.message}`);
|
character + 1}: Error encountered in metadata generated for exported symbol '${
|
||||||
|
name}': \n ${e.message}`);
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Error encountered in metadata generated for exported symbol ${name}: \n ${e.message}`);
|
`Error encountered in metadata generated for exported symbol ${name}: \n ${e.message}`);
|
||||||
|
@ -722,7 +723,7 @@ function validateMetadata(
|
||||||
function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] {
|
function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] {
|
||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
|
|
||||||
function addNamesOf(name: ts.Identifier | ts.BindingPattern) {
|
function addNamesOf(name: ts.Identifier|ts.BindingPattern) {
|
||||||
if (name.kind == ts.SyntaxKind.Identifier) {
|
if (name.kind == ts.SyntaxKind.Identifier) {
|
||||||
const identifier = <ts.Identifier>name;
|
const identifier = <ts.Identifier>name;
|
||||||
result.push(identifier.text);
|
result.push(identifier.text);
|
||||||
|
@ -752,7 +753,8 @@ function expandedMessage(error: any): string {
|
||||||
switch (error.message) {
|
switch (error.message) {
|
||||||
case 'Reference to non-exported class':
|
case 'Reference to non-exported class':
|
||||||
if (error.context && error.context.className) {
|
if (error.context && error.context.className) {
|
||||||
return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
|
return `Reference to a non-exported class ${
|
||||||
|
error.context.className}. Consider exporting the class`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Variable not initialized':
|
case 'Variable not initialized':
|
||||||
|
@ -771,7 +773,8 @@ function expandedMessage(error: any): string {
|
||||||
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
|
'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function';
|
||||||
case 'Reference to a local symbol':
|
case 'Reference to a local symbol':
|
||||||
if (error.context && error.context.name) {
|
if (error.context && error.context.name) {
|
||||||
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
|
return `Reference to a local (non-exported) symbol '${
|
||||||
|
error.context.name}'. Consider exporting the symbol`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error.message;
|
return error.message;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CollectorOptions} from './collector';
|
import {CollectorOptions} from './collector';
|
||||||
import {ClassMetadata, FunctionMetadata, InterfaceMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema';
|
import {ClassMetadata, FunctionMetadata, InterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue} from './schema';
|
||||||
import {Symbols} from './symbols';
|
import {Symbols} from './symbols';
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,8 +46,9 @@ export function recordMapEntry<T extends MetadataEntry>(
|
||||||
sourceFile?: ts.SourceFile) {
|
sourceFile?: ts.SourceFile) {
|
||||||
if (!nodeMap.has(entry)) {
|
if (!nodeMap.has(entry)) {
|
||||||
nodeMap.set(entry, node);
|
nodeMap.set(entry, node);
|
||||||
if (node && (isMetadataImportedSymbolReferenceExpression(entry) ||
|
if (node &&
|
||||||
isMetadataImportDefaultReference(entry)) &&
|
(isMetadataImportedSymbolReferenceExpression(entry) ||
|
||||||
|
isMetadataImportDefaultReference(entry)) &&
|
||||||
entry.line == null) {
|
entry.line == null) {
|
||||||
const info = sourceInfo(node, sourceFile);
|
const info = sourceInfo(node, sourceFile);
|
||||||
if (info.line != null) entry.line = info.line;
|
if (info.line != null) entry.line = info.line;
|
||||||
|
@ -88,7 +89,7 @@ export interface ImportMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
|
function getSourceFileOfNode(node: ts.Node|undefined): ts.SourceFile {
|
||||||
while (node && node.kind != ts.SyntaxKind.SourceFile) {
|
while (node && node.kind != ts.SyntaxKind.SourceFile) {
|
||||||
node = node.parent;
|
node = node.parent;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
|
||||||
|
|
||||||
/* @internal */
|
/* @internal */
|
||||||
export function sourceInfo(
|
export function sourceInfo(
|
||||||
node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo {
|
node: ts.Node|undefined, sourceFile: ts.SourceFile|undefined): MetadataSourceLocationInfo {
|
||||||
if (node) {
|
if (node) {
|
||||||
sourceFile = sourceFile || getSourceFileOfNode(node);
|
sourceFile = sourceFile || getSourceFileOfNode(node);
|
||||||
if (sourceFile) {
|
if (sourceFile) {
|
||||||
|
@ -435,7 +436,7 @@ export class Evaluator {
|
||||||
case ts.SyntaxKind.TypeReference:
|
case ts.SyntaxKind.TypeReference:
|
||||||
const typeReferenceNode = <ts.TypeReferenceNode>node;
|
const typeReferenceNode = <ts.TypeReferenceNode>node;
|
||||||
const typeNameNode = typeReferenceNode.typeName;
|
const typeNameNode = typeReferenceNode.typeName;
|
||||||
const getReference: (typeNameNode: ts.Identifier | ts.QualifiedName) => MetadataValue =
|
const getReference: (typeNameNode: ts.Identifier|ts.QualifiedName) => MetadataValue =
|
||||||
node => {
|
node => {
|
||||||
if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
|
if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
|
||||||
const qualifiedName = <ts.QualifiedName>node;
|
const qualifiedName = <ts.QualifiedName>node;
|
||||||
|
@ -691,6 +692,6 @@ function isPropertyAssignment(node: ts.Node): node is ts.PropertyAssignment {
|
||||||
|
|
||||||
const empty = ts.createNodeArray<any>();
|
const empty = ts.createNodeArray<any>();
|
||||||
|
|
||||||
function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>| undefined): ts.NodeArray<T> {
|
function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>|undefined): ts.NodeArray<T> {
|
||||||
return v || empty;
|
return v || empty;
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
export const METADATA_VERSION = 4;
|
export const METADATA_VERSION = 4;
|
||||||
|
|
||||||
export type MetadataEntry = ClassMetadata | InterfaceMetadata | FunctionMetadata | MetadataValue;
|
export type MetadataEntry = ClassMetadata|InterfaceMetadata|FunctionMetadata|MetadataValue;
|
||||||
|
|
||||||
export interface ModuleMetadata {
|
export interface ModuleMetadata {
|
||||||
__symbolic: 'module';
|
__symbolic: 'module';
|
||||||
|
@ -43,18 +43,22 @@ export interface ClassMetadata {
|
||||||
arity?: number;
|
arity?: number;
|
||||||
decorators?: (MetadataSymbolicExpression|MetadataError)[];
|
decorators?: (MetadataSymbolicExpression|MetadataError)[];
|
||||||
members?: MetadataMap;
|
members?: MetadataMap;
|
||||||
statics?: {[name: string]: MetadataValue | FunctionMetadata};
|
statics?: {[name: string]: MetadataValue|FunctionMetadata};
|
||||||
}
|
}
|
||||||
export function isClassMetadata(value: any): value is ClassMetadata {
|
export function isClassMetadata(value: any): value is ClassMetadata {
|
||||||
return value && value.__symbolic === 'class';
|
return value && value.__symbolic === 'class';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InterfaceMetadata { __symbolic: 'interface'; }
|
export interface InterfaceMetadata {
|
||||||
|
__symbolic: 'interface';
|
||||||
|
}
|
||||||
export function isInterfaceMetadata(value: any): value is InterfaceMetadata {
|
export function isInterfaceMetadata(value: any): value is InterfaceMetadata {
|
||||||
return value && value.__symbolic === 'interface';
|
return value && value.__symbolic === 'interface';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataMap { [name: string]: MemberMetadata[]; }
|
export interface MetadataMap {
|
||||||
|
[name: string]: MemberMetadata[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface MemberMetadata {
|
export interface MemberMetadata {
|
||||||
__symbolic: 'constructor'|'method'|'property';
|
__symbolic: 'constructor'|'method'|'property';
|
||||||
|
@ -99,24 +103,26 @@ export function isFunctionMetadata(value: any): value is FunctionMetadata {
|
||||||
return value && value.__symbolic === 'function';
|
return value && value.__symbolic === 'function';
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetadataValue = string | number | boolean | undefined | null | MetadataObject |
|
export type MetadataValue = string|number|boolean|undefined|null|MetadataObject|MetadataArray|
|
||||||
MetadataArray | MetadataSymbolicExpression | MetadataSymbolicReferenceExpression |
|
MetadataSymbolicExpression|MetadataSymbolicReferenceExpression|MetadataSymbolicBinaryExpression|
|
||||||
MetadataSymbolicBinaryExpression | MetadataSymbolicIndexExpression |
|
MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression|
|
||||||
MetadataSymbolicCallExpression | MetadataSymbolicPrefixExpression |
|
MetadataSymbolicIfExpression|MetadataSymbolicSpreadExpression|MetadataSymbolicSelectExpression|
|
||||||
MetadataSymbolicIfExpression | MetadataSymbolicSpreadExpression |
|
MetadataError;
|
||||||
MetadataSymbolicSelectExpression | MetadataError;
|
|
||||||
|
|
||||||
export interface MetadataObject { [name: string]: MetadataValue; }
|
export interface MetadataObject {
|
||||||
|
[name: string]: MetadataValue;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MetadataArray { [name: number]: MetadataValue; }
|
export interface MetadataArray {
|
||||||
|
[name: number]: MetadataValue;
|
||||||
|
}
|
||||||
|
|
||||||
export type MetadataSymbolicExpression = MetadataSymbolicBinaryExpression |
|
export type MetadataSymbolicExpression = MetadataSymbolicBinaryExpression|
|
||||||
MetadataSymbolicIndexExpression | MetadataSymbolicIndexExpression |
|
MetadataSymbolicIndexExpression|MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression|
|
||||||
MetadataSymbolicCallExpression | MetadataSymbolicCallExpression |
|
MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression|MetadataSymbolicIfExpression|
|
||||||
MetadataSymbolicPrefixExpression | MetadataSymbolicIfExpression |
|
MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression|
|
||||||
MetadataGlobalReferenceExpression | MetadataModuleReferenceExpression |
|
MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression|
|
||||||
MetadataImportedSymbolReferenceExpression | MetadataImportedDefaultReferenceExpression |
|
MetadataSymbolicSelectExpression|MetadataSymbolicSpreadExpression;
|
||||||
MetadataSymbolicSelectExpression | MetadataSymbolicSpreadExpression;
|
|
||||||
|
|
||||||
export function isMetadataSymbolicExpression(value: any): value is MetadataSymbolicExpression {
|
export function isMetadataSymbolicExpression(value: any): value is MetadataSymbolicExpression {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -234,18 +240,17 @@ export function isMetadataImportedSymbolReferenceExpression(value: any):
|
||||||
export interface MetadataImportedDefaultReferenceExpression extends MetadataSourceLocationInfo {
|
export interface MetadataImportedDefaultReferenceExpression extends MetadataSourceLocationInfo {
|
||||||
__symbolic: 'reference';
|
__symbolic: 'reference';
|
||||||
module: string;
|
module: string;
|
||||||
default:
|
default: boolean;
|
||||||
boolean;
|
arguments?: MetadataValue[];
|
||||||
arguments?: MetadataValue[];
|
|
||||||
}
|
}
|
||||||
export function isMetadataImportDefaultReference(value: any):
|
export function isMetadataImportDefaultReference(value: any):
|
||||||
value is MetadataImportedDefaultReferenceExpression {
|
value is MetadataImportedDefaultReferenceExpression {
|
||||||
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
|
export type MetadataSymbolicReferenceExpression =
|
||||||
MetadataModuleReferenceExpression | MetadataImportedSymbolReferenceExpression |
|
MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression|
|
||||||
MetadataImportedDefaultReferenceExpression;
|
MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression;
|
||||||
export function isMetadataSymbolicReferenceExpression(value: any):
|
export function isMetadataSymbolicReferenceExpression(value: any):
|
||||||
value is MetadataSymbolicReferenceExpression {
|
value is MetadataSymbolicReferenceExpression {
|
||||||
return value && value.__symbolic === 'reference';
|
return value && value.__symbolic === 'reference';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {MetadataSymbolicReferenceExpression, MetadataValue} from './schema';
|
||||||
|
|
||||||
export class Symbols {
|
export class Symbols {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
private _symbols !: Map<string, MetadataValue>;
|
private _symbols!: Map<string, MetadataValue>;
|
||||||
private references = new Map<string, MetadataSymbolicReferenceExpression>();
|
private references = new Map<string, MetadataSymbolicReferenceExpression>();
|
||||||
|
|
||||||
constructor(private sourceFile: ts.SourceFile) {}
|
constructor(private sourceFile: ts.SourceFile) {}
|
||||||
|
@ -21,12 +21,16 @@ export class Symbols {
|
||||||
return (preferReference && this.references.get(name)) || this.symbols.get(name);
|
return (preferReference && this.references.get(name)) || this.symbols.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
define(name: string, value: MetadataValue) { this.symbols.set(name, value); }
|
define(name: string, value: MetadataValue) {
|
||||||
|
this.symbols.set(name, value);
|
||||||
|
}
|
||||||
defineReference(name: string, value: MetadataSymbolicReferenceExpression) {
|
defineReference(name: string, value: MetadataSymbolicReferenceExpression) {
|
||||||
this.references.set(name, value);
|
this.references.set(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
has(name: string): boolean { return this.symbols.has(name); }
|
has(name: string): boolean {
|
||||||
|
return this.symbols.has(name);
|
||||||
|
}
|
||||||
|
|
||||||
private get symbols(): Map<string, MetadataValue> {
|
private get symbols(): Map<string, MetadataValue> {
|
||||||
let result = this._symbols;
|
let result = this._symbols;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, ParseError, ParseSourceFile, ParseTemplateOptions, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler';
|
import {compileComponentFromMetadata, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, makeBindingParser, ParseError, ParseSourceFile, parseTemplate, ParseTemplateOptions, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CycleAnalyzer} from '../../cycles';
|
import {CycleAnalyzer} from '../../cycles';
|
||||||
|
@ -15,7 +15,7 @@ import {absoluteFrom, relative} from '../../file_system';
|
||||||
import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
|
import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
|
||||||
import {DependencyTracker} from '../../incremental/api';
|
import {DependencyTracker} from '../../incremental/api';
|
||||||
import {IndexingContext} from '../../indexer';
|
import {IndexingContext} from '../../indexer';
|
||||||
import {DirectiveMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, extractDirectiveGuards} from '../../metadata';
|
import {DirectiveMeta, extractDirectiveGuards, InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
||||||
import {flattenInheritedDirectiveMetadata} from '../../metadata/src/inheritance';
|
import {flattenInheritedDirectiveMetadata} from '../../metadata/src/inheritance';
|
||||||
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
|
@ -200,7 +200,7 @@ export class ComponentDecoratorHandler implements
|
||||||
} else {
|
} else {
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
}, undefined) !;
|
}, undefined)!;
|
||||||
|
|
||||||
|
|
||||||
// Note that we could technically combine the `viewProvidersRequiringFactory` and
|
// Note that we could technically combine the `viewProvidersRequiringFactory` and
|
||||||
|
@ -211,7 +211,7 @@ export class ComponentDecoratorHandler implements
|
||||||
let wrappedViewProviders: Expression|null = null;
|
let wrappedViewProviders: Expression|null = null;
|
||||||
|
|
||||||
if (component.has('viewProviders')) {
|
if (component.has('viewProviders')) {
|
||||||
const viewProviders = component.get('viewProviders') !;
|
const viewProviders = component.get('viewProviders')!;
|
||||||
viewProvidersRequiringFactory =
|
viewProvidersRequiringFactory =
|
||||||
resolveProvidersRequiringFactory(viewProviders, this.reflector, this.evaluator);
|
resolveProvidersRequiringFactory(viewProviders, this.reflector, this.evaluator);
|
||||||
wrappedViewProviders = new WrappedNodeExpr(
|
wrappedViewProviders = new WrappedNodeExpr(
|
||||||
|
@ -221,7 +221,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
if (component.has('providers')) {
|
if (component.has('providers')) {
|
||||||
providersRequiringFactory = resolveProvidersRequiringFactory(
|
providersRequiringFactory = resolveProvidersRequiringFactory(
|
||||||
component.get('providers') !, this.reflector, this.evaluator);
|
component.get('providers')!, this.reflector, this.evaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the template.
|
// Parse the template.
|
||||||
|
@ -232,14 +232,14 @@ export class ComponentDecoratorHandler implements
|
||||||
let template: ParsedTemplateWithSource;
|
let template: ParsedTemplateWithSource;
|
||||||
if (this.preanalyzeTemplateCache.has(node)) {
|
if (this.preanalyzeTemplateCache.has(node)) {
|
||||||
// The template was parsed in preanalyze. Use it and delete it to save memory.
|
// The template was parsed in preanalyze. Use it and delete it to save memory.
|
||||||
const preanalyzed = this.preanalyzeTemplateCache.get(node) !;
|
const preanalyzed = this.preanalyzeTemplateCache.get(node)!;
|
||||||
this.preanalyzeTemplateCache.delete(node);
|
this.preanalyzeTemplateCache.delete(node);
|
||||||
|
|
||||||
template = preanalyzed;
|
template = preanalyzed;
|
||||||
} else {
|
} else {
|
||||||
// The template was not already parsed. Either there's a templateUrl, or an inline template.
|
// The template was not already parsed. Either there's a templateUrl, or an inline template.
|
||||||
if (component.has('templateUrl')) {
|
if (component.has('templateUrl')) {
|
||||||
const templateUrlExpr = component.get('templateUrl') !;
|
const templateUrlExpr = component.get('templateUrl')!;
|
||||||
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||||
if (typeof templateUrl !== 'string') {
|
if (typeof templateUrl !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -303,7 +303,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
let animations: Expression|null = null;
|
let animations: Expression|null = null;
|
||||||
if (component.has('animations')) {
|
if (component.has('animations')) {
|
||||||
animations = new WrappedNodeExpr(component.get('animations') !);
|
animations = new WrappedNodeExpr(component.get('animations')!);
|
||||||
}
|
}
|
||||||
|
|
||||||
const output: AnalysisOutput<ComponentAnalysisData> = {
|
const output: AnalysisOutput<ComponentAnalysisData> = {
|
||||||
|
@ -323,7 +323,8 @@ export class ComponentDecoratorHandler implements
|
||||||
// analyzed and the full compilation scope for the component can be realized.
|
// analyzed and the full compilation scope for the component can be realized.
|
||||||
animations,
|
animations,
|
||||||
viewProviders: wrappedViewProviders,
|
viewProviders: wrappedViewProviders,
|
||||||
i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath,
|
i18nUseExternalIds: this.i18nUseExternalIds,
|
||||||
|
relativeContextFilePath,
|
||||||
},
|
},
|
||||||
guards: extractDirectiveGuards(node, this.reflector),
|
guards: extractDirectiveGuards(node, this.reflector),
|
||||||
metadataStmt: generateSetClassMetadataCall(
|
metadataStmt: generateSetClassMetadataCall(
|
||||||
|
@ -335,7 +336,7 @@ export class ComponentDecoratorHandler implements
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (changeDetection !== null) {
|
if (changeDetection !== null) {
|
||||||
output.analysis !.meta.changeDetection = changeDetection;
|
output.analysis!.meta.changeDetection = changeDetection;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +354,8 @@ export class ComponentDecoratorHandler implements
|
||||||
outputs: analysis.meta.outputs,
|
outputs: analysis.meta.outputs,
|
||||||
queries: analysis.meta.queries.map(query => query.propertyName),
|
queries: analysis.meta.queries.map(query => query.propertyName),
|
||||||
isComponent: true,
|
isComponent: true,
|
||||||
baseClass: analysis.baseClass, ...analysis.guards,
|
baseClass: analysis.baseClass,
|
||||||
|
...analysis.guards,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.injectableRegistry.registerInjectable(node);
|
this.injectableRegistry.registerInjectable(node);
|
||||||
|
@ -415,8 +417,8 @@ export class ComponentDecoratorHandler implements
|
||||||
}
|
}
|
||||||
for (const {name, ref} of scope.compilation.pipes) {
|
for (const {name, ref} of scope.compilation.pipes) {
|
||||||
if (!ts.isClassDeclaration(ref.node)) {
|
if (!ts.isClassDeclaration(ref.node)) {
|
||||||
throw new Error(
|
throw new Error(`Unexpected non-class declaration ${
|
||||||
`Unexpected non-class declaration ${ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`);
|
ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`);
|
||||||
}
|
}
|
||||||
pipes.set(name, ref as Reference<ClassDeclaration<ts.ClassDeclaration>>);
|
pipes.set(name, ref as Reference<ClassDeclaration<ts.ClassDeclaration>>);
|
||||||
}
|
}
|
||||||
|
@ -491,7 +493,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
// The BoundTarget knows which directives and pipes matched the template.
|
// The BoundTarget knows which directives and pipes matched the template.
|
||||||
const usedDirectives = bound.getUsedDirectives();
|
const usedDirectives = bound.getUsedDirectives();
|
||||||
const usedPipes = bound.getUsedPipes().map(name => pipes.get(name) !);
|
const usedPipes = bound.getUsedPipes().map(name => pipes.get(name)!);
|
||||||
|
|
||||||
// Scan through the directives/pipes actually used in the template and check whether any
|
// Scan through the directives/pipes actually used in the template and check whether any
|
||||||
// import which needs to be generated would create a cycle.
|
// import which needs to be generated would create a cycle.
|
||||||
|
@ -539,7 +541,7 @@ export class ComponentDecoratorHandler implements
|
||||||
if (analysis.providersRequiringFactory !== null &&
|
if (analysis.providersRequiringFactory !== null &&
|
||||||
analysis.meta.providers instanceof WrappedNodeExpr) {
|
analysis.meta.providers instanceof WrappedNodeExpr) {
|
||||||
const providerDiagnostics = getProviderDiagnostics(
|
const providerDiagnostics = getProviderDiagnostics(
|
||||||
analysis.providersRequiringFactory, analysis.meta.providers !.node,
|
analysis.providersRequiringFactory, analysis.meta.providers!.node,
|
||||||
this.injectableRegistry);
|
this.injectableRegistry);
|
||||||
diagnostics.push(...providerDiagnostics);
|
diagnostics.push(...providerDiagnostics);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +549,7 @@ export class ComponentDecoratorHandler implements
|
||||||
if (analysis.viewProvidersRequiringFactory !== null &&
|
if (analysis.viewProvidersRequiringFactory !== null &&
|
||||||
analysis.meta.viewProviders instanceof WrappedNodeExpr) {
|
analysis.meta.viewProviders instanceof WrappedNodeExpr) {
|
||||||
const viewProviderDiagnostics = getProviderDiagnostics(
|
const viewProviderDiagnostics = getProviderDiagnostics(
|
||||||
analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders !.node,
|
analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders!.node,
|
||||||
this.injectableRegistry);
|
this.injectableRegistry);
|
||||||
diagnostics.push(...viewProviderDiagnostics);
|
diagnostics.push(...viewProviderDiagnostics);
|
||||||
}
|
}
|
||||||
|
@ -587,7 +589,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
private _resolveLiteral(decorator: Decorator): ts.ObjectLiteralExpression {
|
private _resolveLiteral(decorator: Decorator): ts.ObjectLiteralExpression {
|
||||||
if (this.literalCache.has(decorator)) {
|
if (this.literalCache.has(decorator)) {
|
||||||
return this.literalCache.get(decorator) !;
|
return this.literalCache.get(decorator)!;
|
||||||
}
|
}
|
||||||
if (decorator.args === null || decorator.args.length !== 1) {
|
if (decorator.args === null || decorator.args.length !== 1) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -609,7 +611,7 @@ export class ComponentDecoratorHandler implements
|
||||||
component: Map<string, ts.Expression>, field: string, enumSymbolName: string): number|null {
|
component: Map<string, ts.Expression>, field: string, enumSymbolName: string): number|null {
|
||||||
let resolved: number|null = null;
|
let resolved: number|null = null;
|
||||||
if (component.has(field)) {
|
if (component.has(field)) {
|
||||||
const expr = component.get(field) !;
|
const expr = component.get(field)!;
|
||||||
const value = this.evaluator.evaluate(expr) as any;
|
const value = this.evaluator.evaluate(expr) as any;
|
||||||
if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) {
|
if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) {
|
||||||
resolved = value.resolved as number;
|
resolved = value.resolved as number;
|
||||||
|
@ -628,7 +630,7 @@ export class ComponentDecoratorHandler implements
|
||||||
return extraUrls.length > 0 ? extraUrls : null;
|
return extraUrls.length > 0 ? extraUrls : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styleUrlsExpr = component.get('styleUrls') !;
|
const styleUrlsExpr = component.get('styleUrls')!;
|
||||||
const styleUrls = this.evaluator.evaluate(styleUrlsExpr);
|
const styleUrls = this.evaluator.evaluate(styleUrlsExpr);
|
||||||
if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) {
|
if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -643,7 +645,7 @@ export class ComponentDecoratorHandler implements
|
||||||
containingFile: string): Promise<ParsedTemplate|null> {
|
containingFile: string): Promise<ParsedTemplate|null> {
|
||||||
if (component.has('templateUrl')) {
|
if (component.has('templateUrl')) {
|
||||||
// Extract the templateUrl and preload it.
|
// Extract the templateUrl and preload it.
|
||||||
const templateUrlExpr = component.get('templateUrl') !;
|
const templateUrlExpr = component.get('templateUrl')!;
|
||||||
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||||
if (typeof templateUrl !== 'string') {
|
if (typeof templateUrl !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -703,7 +705,7 @@ export class ComponentDecoratorHandler implements
|
||||||
ErrorCode.COMPONENT_MISSING_TEMPLATE, Decorator.nodeForError(decorator),
|
ErrorCode.COMPONENT_MISSING_TEMPLATE, Decorator.nodeForError(decorator),
|
||||||
'component is missing a template');
|
'component is missing a template');
|
||||||
}
|
}
|
||||||
const templateExpr = component.get('template') !;
|
const templateExpr = component.get('template')!;
|
||||||
|
|
||||||
let templateStr: string;
|
let templateStr: string;
|
||||||
let templateUrl: string = '';
|
let templateUrl: string = '';
|
||||||
|
@ -721,7 +723,7 @@ export class ComponentDecoratorHandler implements
|
||||||
escapedString = true;
|
escapedString = true;
|
||||||
sourceMapping = {
|
sourceMapping = {
|
||||||
type: 'direct',
|
type: 'direct',
|
||||||
node: templateExpr as(ts.StringLiteral | ts.NoSubstitutionTemplateLiteral),
|
node: templateExpr as (ts.StringLiteral | ts.NoSubstitutionTemplateLiteral),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const resolvedTemplate = this.evaluator.evaluate(templateExpr);
|
const resolvedTemplate = this.evaluator.evaluate(templateExpr);
|
||||||
|
@ -749,7 +751,7 @@ export class ComponentDecoratorHandler implements
|
||||||
templateRange: LexerRange|undefined, escapedString: boolean): ParsedTemplate {
|
templateRange: LexerRange|undefined, escapedString: boolean): ParsedTemplate {
|
||||||
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
|
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
|
||||||
if (component.has('preserveWhitespaces')) {
|
if (component.has('preserveWhitespaces')) {
|
||||||
const expr = component.get('preserveWhitespaces') !;
|
const expr = component.get('preserveWhitespaces')!;
|
||||||
const value = this.evaluator.evaluate(expr);
|
const value = this.evaluator.evaluate(expr);
|
||||||
if (typeof value !== 'boolean') {
|
if (typeof value !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -760,7 +762,7 @@ export class ComponentDecoratorHandler implements
|
||||||
|
|
||||||
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
|
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
|
||||||
if (component.has('interpolation')) {
|
if (component.has('interpolation')) {
|
||||||
const expr = component.get('interpolation') !;
|
const expr = component.get('interpolation')!;
|
||||||
const value = this.evaluator.evaluate(expr);
|
const value = this.evaluator.evaluate(expr);
|
||||||
if (!Array.isArray(value) || value.length !== 2 ||
|
if (!Array.isArray(value) || value.length !== 2 ||
|
||||||
!value.every(element => typeof element === 'string')) {
|
!value.every(element => typeof element === 'string')) {
|
||||||
|
@ -768,14 +770,15 @@ export class ComponentDecoratorHandler implements
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr,
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr,
|
||||||
'interpolation must be an array with 2 elements of string type');
|
'interpolation must be an array with 2 elements of string type');
|
||||||
}
|
}
|
||||||
interpolation = InterpolationConfig.fromArray(value as[string, string]);
|
interpolation = InterpolationConfig.fromArray(value as [string, string]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {errors, nodes: emitNodes, styleUrls, styles, ngContentSelectors} =
|
const {errors, nodes: emitNodes, styleUrls, styles, ngContentSelectors} =
|
||||||
parseTemplate(templateStr, templateUrl, {
|
parseTemplate(templateStr, templateUrl, {
|
||||||
preserveWhitespaces,
|
preserveWhitespaces,
|
||||||
interpolationConfig: interpolation,
|
interpolationConfig: interpolation,
|
||||||
range: templateRange, escapedString,
|
range: templateRange,
|
||||||
|
escapedString,
|
||||||
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -795,7 +798,8 @@ export class ComponentDecoratorHandler implements
|
||||||
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
|
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
|
||||||
preserveWhitespaces: true,
|
preserveWhitespaces: true,
|
||||||
interpolationConfig: interpolation,
|
interpolationConfig: interpolation,
|
||||||
range: templateRange, escapedString,
|
range: templateRange,
|
||||||
|
escapedString,
|
||||||
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
||||||
leadingTriviaChars: [],
|
leadingTriviaChars: [],
|
||||||
});
|
});
|
||||||
|
@ -808,7 +812,8 @@ export class ComponentDecoratorHandler implements
|
||||||
styles,
|
styles,
|
||||||
ngContentSelectors,
|
ngContentSelectors,
|
||||||
errors,
|
errors,
|
||||||
template: templateStr, templateUrl,
|
template: templateStr,
|
||||||
|
templateUrl,
|
||||||
isInline: component.has('template'),
|
isInline: component.has('template'),
|
||||||
file: new ParseSourceFile(templateStr, templateUrl),
|
file: new ParseSourceFile(templateStr, templateUrl),
|
||||||
};
|
};
|
||||||
|
@ -820,7 +825,7 @@ export class ComponentDecoratorHandler implements
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out what file is being imported.
|
// Figure out what file is being imported.
|
||||||
return this.moduleResolver.resolveModule(expr.value.moduleName !, origin.fileName);
|
return this.moduleResolver.resolveModule(expr.value.moduleName!, origin.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isCyclicImport(expr: Expression, origin: ts.SourceFile): boolean {
|
private _isCyclicImport(expr: Expression, origin: ts.SourceFile): boolean {
|
||||||
|
|
|
@ -36,9 +36,13 @@ export function getProviderDiagnostics(
|
||||||
const contextNode = provider.getOriginForDiagnostics(providersDeclaration);
|
const contextNode = provider.getOriginForDiagnostics(providersDeclaration);
|
||||||
diagnostics.push(makeDiagnostic(
|
diagnostics.push(makeDiagnostic(
|
||||||
ErrorCode.UNDECORATED_PROVIDER, contextNode,
|
ErrorCode.UNDECORATED_PROVIDER, contextNode,
|
||||||
`The class '${provider.node.name.text}' cannot be created via dependency injection, as it does not have an Angular decorator. This will result in an error at runtime.
|
`The class '${
|
||||||
|
provider.node.name
|
||||||
|
.text}' cannot be created via dependency injection, as it does not have an Angular decorator. This will result in an error at runtime.
|
||||||
|
|
||||||
Either add the @Injectable() decorator to '${provider.node.name.text}', or configure a different provider (such as a provider with 'useFactory').
|
Either add the @Injectable() decorator to '${
|
||||||
|
provider.node.name
|
||||||
|
.text}', or configure a different provider (such as a provider with 'useFactory').
|
||||||
`,
|
`,
|
||||||
[{node: provider.node, messageText: `'${provider.node.name.text}' is declared here.`}]));
|
[{node: provider.node, messageText: `'${provider.node.name.text}' is declared here.`}]));
|
||||||
}
|
}
|
||||||
|
@ -52,7 +56,7 @@ export function getDirectiveDiagnostics(
|
||||||
kind: string): ts.Diagnostic[]|null {
|
kind: string): ts.Diagnostic[]|null {
|
||||||
let diagnostics: ts.Diagnostic[]|null = [];
|
let diagnostics: ts.Diagnostic[]|null = [];
|
||||||
|
|
||||||
const addDiagnostics = (more: ts.Diagnostic | ts.Diagnostic[] | null) => {
|
const addDiagnostics = (more: ts.Diagnostic|ts.Diagnostic[]|null) => {
|
||||||
if (more === null) {
|
if (more === null) {
|
||||||
return;
|
return;
|
||||||
} else if (diagnostics === null) {
|
} else if (diagnostics === null) {
|
||||||
|
@ -121,14 +125,16 @@ export function checkInheritanceOfDirective(
|
||||||
|
|
||||||
function getInheritedUndecoratedCtorDiagnostic(
|
function getInheritedUndecoratedCtorDiagnostic(
|
||||||
node: ClassDeclaration, baseClass: Reference, reader: MetadataReader) {
|
node: ClassDeclaration, baseClass: Reference, reader: MetadataReader) {
|
||||||
const subclassMeta = reader.getDirectiveMetadata(new Reference(node)) !;
|
const subclassMeta = reader.getDirectiveMetadata(new Reference(node))!;
|
||||||
const dirOrComp = subclassMeta.isComponent ? 'Component' : 'Directive';
|
const dirOrComp = subclassMeta.isComponent ? 'Component' : 'Directive';
|
||||||
const baseClassName = baseClass.debugName;
|
const baseClassName = baseClass.debugName;
|
||||||
|
|
||||||
return makeDiagnostic(
|
return makeDiagnostic(
|
||||||
ErrorCode.DIRECTIVE_INHERITS_UNDECORATED_CTOR, node.name,
|
ErrorCode.DIRECTIVE_INHERITS_UNDECORATED_CTOR, node.name,
|
||||||
`The ${dirOrComp.toLowerCase()} ${node.name.text} inherits its constructor from ${baseClassName}, ` +
|
`The ${dirOrComp.toLowerCase()} ${node.name.text} inherits its constructor from ${
|
||||||
|
baseClassName}, ` +
|
||||||
`but the latter does not have an Angular decorator of its own. Dependency injection will not be able to ` +
|
`but the latter does not have an Angular decorator of its own. Dependency injection will not be able to ` +
|
||||||
`resolve the parameters of ${baseClassName}'s constructor. Either add a @Directive decorator ` +
|
`resolve the parameters of ${
|
||||||
|
baseClassName}'s constructor. Either add a @Directive decorator ` +
|
||||||
`to ${baseClassName}, or add an explicit constructor to ${node.name.text}.`);
|
`to ${baseClassName}, or add an explicit constructor to ${node.name.text}.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ConstantPool, Expression, Identifiers, ParseError, ParsedHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler';
|
import {compileDirectiveFromMetadata, ConstantPool, Expression, Identifiers, makeBindingParser, ParsedHostBindings, ParseError, parseHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, verifyHostBindings, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
|
@ -14,7 +14,7 @@ import {DefaultImportRecorder, Reference} from '../../imports';
|
||||||
import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
||||||
import {extractDirectiveGuards} from '../../metadata/src/util';
|
import {extractDirectiveGuards} from '../../metadata/src/util';
|
||||||
import {DynamicValue, EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
import {DynamicValue, EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
|
import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, filterToMembersWithDecorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||||
import {LocalModuleScopeRegistry} from '../../scope';
|
import {LocalModuleScopeRegistry} from '../../scope';
|
||||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ export class DirectiveDecoratorHandler implements
|
||||||
let providersRequiringFactory: Set<Reference<ClassDeclaration>>|null = null;
|
let providersRequiringFactory: Set<Reference<ClassDeclaration>>|null = null;
|
||||||
if (directiveResult !== undefined && directiveResult.decorator.has('providers')) {
|
if (directiveResult !== undefined && directiveResult.decorator.has('providers')) {
|
||||||
providersRequiringFactory = resolveProvidersRequiringFactory(
|
providersRequiringFactory = resolveProvidersRequiringFactory(
|
||||||
directiveResult.decorator.get('providers') !, this.reflector, this.evaluator);
|
directiveResult.decorator.get('providers')!, this.reflector, this.evaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -102,7 +102,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||||
this.annotateForClosureCompiler),
|
this.annotateForClosureCompiler),
|
||||||
baseClass: readBaseClass(node, this.reflector, this.evaluator),
|
baseClass: readBaseClass(node, this.reflector, this.evaluator),
|
||||||
guards: extractDirectiveGuards(node, this.reflector), providersRequiringFactory
|
guards: extractDirectiveGuards(node, this.reflector),
|
||||||
|
providersRequiringFactory
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
outputs: analysis.meta.outputs,
|
outputs: analysis.meta.outputs,
|
||||||
queries: analysis.meta.queries.map(query => query.propertyName),
|
queries: analysis.meta.queries.map(query => query.propertyName),
|
||||||
isComponent: false,
|
isComponent: false,
|
||||||
baseClass: analysis.baseClass, ...analysis.guards,
|
baseClass: analysis.baseClass,
|
||||||
|
...analysis.guards,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.injectableRegistry.registerInjectable(node);
|
this.injectableRegistry.registerInjectable(node);
|
||||||
|
@ -132,7 +134,7 @@ export class DirectiveDecoratorHandler implements
|
||||||
if (analysis.providersRequiringFactory !== null &&
|
if (analysis.providersRequiringFactory !== null &&
|
||||||
analysis.meta.providers instanceof WrappedNodeExpr) {
|
analysis.meta.providers instanceof WrappedNodeExpr) {
|
||||||
const providerDiagnostics = getProviderDiagnostics(
|
const providerDiagnostics = getProviderDiagnostics(
|
||||||
analysis.providersRequiringFactory, analysis.meta.providers !.node,
|
analysis.providersRequiringFactory, analysis.meta.providers!.node,
|
||||||
this.injectableRegistry);
|
this.injectableRegistry);
|
||||||
diagnostics.push(...providerDiagnostics);
|
diagnostics.push(...providerDiagnostics);
|
||||||
}
|
}
|
||||||
|
@ -176,9 +178,8 @@ export class DirectiveDecoratorHandler implements
|
||||||
export function extractDirectiveMetadata(
|
export function extractDirectiveMetadata(
|
||||||
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
||||||
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||||
flags: HandlerFlags, annotateForClosureCompiler: boolean,
|
flags: HandlerFlags, annotateForClosureCompiler: boolean, defaultSelector: string|null = null):
|
||||||
defaultSelector: string | null =
|
{decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined {
|
||||||
null): {decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined {
|
|
||||||
let directive: Map<string, ts.Expression>;
|
let directive: Map<string, ts.Expression>;
|
||||||
if (decorator === null || decorator.args === null || decorator.args.length === 0) {
|
if (decorator === null || decorator.args === null || decorator.args.length === 0) {
|
||||||
directive = new Map<string, ts.Expression>();
|
directive = new Map<string, ts.Expression>();
|
||||||
|
@ -220,9 +221,10 @@ export function extractDirectiveMetadata(
|
||||||
|
|
||||||
// And outputs.
|
// And outputs.
|
||||||
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator);
|
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator);
|
||||||
const outputsFromFields = parseDecoratedFields(
|
const outputsFromFields =
|
||||||
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
|
parseDecoratedFields(
|
||||||
resolveOutput) as{[field: string]: string};
|
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
|
||||||
|
resolveOutput) as {[field: string]: string};
|
||||||
// Construct the list of queries.
|
// Construct the list of queries.
|
||||||
const contentChildFromFields = queriesFromFields(
|
const contentChildFromFields = queriesFromFields(
|
||||||
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
|
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
|
||||||
|
@ -244,7 +246,7 @@ export function extractDirectiveMetadata(
|
||||||
|
|
||||||
if (directive.has('queries')) {
|
if (directive.has('queries')) {
|
||||||
const queriesFromDecorator =
|
const queriesFromDecorator =
|
||||||
extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore);
|
extractQueriesFromDecorator(directive.get('queries')!, reflector, evaluator, isCore);
|
||||||
queries.push(...queriesFromDecorator.content);
|
queries.push(...queriesFromDecorator.content);
|
||||||
viewQueries.push(...queriesFromDecorator.view);
|
viewQueries.push(...queriesFromDecorator.view);
|
||||||
}
|
}
|
||||||
|
@ -252,7 +254,7 @@ export function extractDirectiveMetadata(
|
||||||
// Parse the selector.
|
// Parse the selector.
|
||||||
let selector = defaultSelector;
|
let selector = defaultSelector;
|
||||||
if (directive.has('selector')) {
|
if (directive.has('selector')) {
|
||||||
const expr = directive.get('selector') !;
|
const expr = directive.get('selector')!;
|
||||||
const resolved = evaluator.evaluate(expr);
|
const resolved = evaluator.evaluate(expr);
|
||||||
if (typeof resolved !== 'string') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -272,8 +274,8 @@ export function extractDirectiveMetadata(
|
||||||
const providers: Expression|null = directive.has('providers') ?
|
const providers: Expression|null = directive.has('providers') ?
|
||||||
new WrappedNodeExpr(
|
new WrappedNodeExpr(
|
||||||
annotateForClosureCompiler ?
|
annotateForClosureCompiler ?
|
||||||
wrapFunctionExpressionsInParens(directive.get('providers') !) :
|
wrapFunctionExpressionsInParens(directive.get('providers')!) :
|
||||||
directive.get('providers') !) :
|
directive.get('providers')!) :
|
||||||
null;
|
null;
|
||||||
|
|
||||||
// Determine if `ngOnChanges` is a lifecycle hook defined on the component.
|
// Determine if `ngOnChanges` is a lifecycle hook defined on the component.
|
||||||
|
@ -284,7 +286,7 @@ export function extractDirectiveMetadata(
|
||||||
// Parse exportAs.
|
// Parse exportAs.
|
||||||
let exportAs: string[]|null = null;
|
let exportAs: string[]|null = null;
|
||||||
if (directive.has('exportAs')) {
|
if (directive.has('exportAs')) {
|
||||||
const expr = directive.get('exportAs') !;
|
const expr = directive.get('exportAs')!;
|
||||||
const resolved = evaluator.evaluate(expr);
|
const resolved = evaluator.evaluate(expr);
|
||||||
if (typeof resolved !== 'string') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -312,15 +314,24 @@ export function extractDirectiveMetadata(
|
||||||
|
|
||||||
const metadata: R3DirectiveMetadata = {
|
const metadata: R3DirectiveMetadata = {
|
||||||
name: clazz.name.text,
|
name: clazz.name.text,
|
||||||
deps: ctorDeps, host,
|
deps: ctorDeps,
|
||||||
|
host,
|
||||||
lifecycle: {
|
lifecycle: {
|
||||||
usesOnChanges,
|
usesOnChanges,
|
||||||
},
|
},
|
||||||
inputs: {...inputsFromMeta, ...inputsFromFields},
|
inputs: {...inputsFromMeta, ...inputsFromFields},
|
||||||
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, viewQueries, selector,
|
outputs: {...outputsFromMeta, ...outputsFromFields},
|
||||||
fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), type, internalType,
|
queries,
|
||||||
|
viewQueries,
|
||||||
|
selector,
|
||||||
|
fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE),
|
||||||
|
type,
|
||||||
|
internalType,
|
||||||
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
|
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
|
||||||
typeSourceSpan: createSourceSpan(clazz.name), usesInheritance, exportAs, providers
|
typeSourceSpan: createSourceSpan(clazz.name),
|
||||||
|
usesInheritance,
|
||||||
|
exportAs,
|
||||||
|
providers
|
||||||
};
|
};
|
||||||
return {decorator: directive, metadata};
|
return {decorator: directive, metadata};
|
||||||
}
|
}
|
||||||
|
@ -366,11 +377,11 @@ export function extractQueryMetadata(
|
||||||
}
|
}
|
||||||
const options = reflectObjectLiteral(optionsExpr);
|
const options = reflectObjectLiteral(optionsExpr);
|
||||||
if (options.has('read')) {
|
if (options.has('read')) {
|
||||||
read = new WrappedNodeExpr(options.get('read') !);
|
read = new WrappedNodeExpr(options.get('read')!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.has('descendants')) {
|
if (options.has('descendants')) {
|
||||||
const descendantsExpr = options.get('descendants') !;
|
const descendantsExpr = options.get('descendants')!;
|
||||||
const descendantsValue = evaluator.evaluate(descendantsExpr);
|
const descendantsValue = evaluator.evaluate(descendantsExpr);
|
||||||
if (typeof descendantsValue !== 'boolean') {
|
if (typeof descendantsValue !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -381,7 +392,7 @@ export function extractQueryMetadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.has('static')) {
|
if (options.has('static')) {
|
||||||
const staticValue = evaluator.evaluate(options.get('static') !);
|
const staticValue = evaluator.evaluate(options.get('static')!);
|
||||||
if (typeof staticValue !== 'boolean') {
|
if (typeof staticValue !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, node, `@${name} options.static must be a boolean`);
|
ErrorCode.VALUE_HAS_WRONG_TYPE, node, `@${name} options.static must be a boolean`);
|
||||||
|
@ -466,7 +477,7 @@ export function parseFieldArrayValue(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the field of interest from the directive metadata to a string[].
|
// Resolve the field of interest from the directive metadata to a string[].
|
||||||
const expression = directive.get(field) !;
|
const expression = directive.get(field)!;
|
||||||
const value = evaluator.evaluate(expression);
|
const value = evaluator.evaluate(expression);
|
||||||
if (!isStringArrayOrDie(value, field, expression)) {
|
if (!isStringArrayOrDie(value, field, expression)) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -489,15 +500,13 @@ function parseFieldToPropertyMapping(
|
||||||
return EMPTY_OBJECT;
|
return EMPTY_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return metaValues.reduce(
|
return metaValues.reduce((results, value) => {
|
||||||
(results, value) => {
|
// Either the value is 'field' or 'field: property'. In the first case, `property` will
|
||||||
// Either the value is 'field' or 'field: property'. In the first case, `property` will
|
// be undefined, in which case the field name should also be used as the property name.
|
||||||
// be undefined, in which case the field name should also be used as the property name.
|
const [field, property] = value.split(':', 2).map(str => str.trim());
|
||||||
const [field, property] = value.split(':', 2).map(str => str.trim());
|
results[field] = property || field;
|
||||||
results[field] = property || field;
|
return results;
|
||||||
return results;
|
}, {} as {[field: string]: string});
|
||||||
},
|
|
||||||
{} as{[field: string]: string});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -507,33 +516,32 @@ function parseFieldToPropertyMapping(
|
||||||
function parseDecoratedFields(
|
function parseDecoratedFields(
|
||||||
fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator,
|
fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator,
|
||||||
mapValueResolver: (publicName: string, internalName: string) =>
|
mapValueResolver: (publicName: string, internalName: string) =>
|
||||||
string | [string, string]): {[field: string]: string | [string, string]} {
|
string | [string, string]): {[field: string]: string|[string, string]} {
|
||||||
return fields.reduce(
|
return fields.reduce((results, field) => {
|
||||||
(results, field) => {
|
const fieldName = field.member.name;
|
||||||
const fieldName = field.member.name;
|
field.decorators.forEach(decorator => {
|
||||||
field.decorators.forEach(decorator => {
|
// The decorator either doesn't have an argument (@Input()) in which case the property
|
||||||
// The decorator either doesn't have an argument (@Input()) in which case the property
|
// name is used, or it has one argument (@Output('named')).
|
||||||
// name is used, or it has one argument (@Output('named')).
|
if (decorator.args == null || decorator.args.length === 0) {
|
||||||
if (decorator.args == null || decorator.args.length === 0) {
|
results[fieldName] = fieldName;
|
||||||
results[fieldName] = fieldName;
|
} else if (decorator.args.length === 1) {
|
||||||
} else if (decorator.args.length === 1) {
|
const property = evaluator.evaluate(decorator.args[0]);
|
||||||
const property = evaluator.evaluate(decorator.args[0]);
|
if (typeof property !== 'string') {
|
||||||
if (typeof property !== 'string') {
|
throw new FatalDiagnosticError(
|
||||||
throw new FatalDiagnosticError(
|
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
`@${decorator.name} decorator argument must resolve to a string`);
|
||||||
`@${decorator.name} decorator argument must resolve to a string`);
|
}
|
||||||
}
|
results[fieldName] = mapValueResolver(property, fieldName);
|
||||||
results[fieldName] = mapValueResolver(property, fieldName);
|
} else {
|
||||||
} else {
|
// Too many arguments.
|
||||||
// Too many arguments.
|
throw new FatalDiagnosticError(
|
||||||
throw new FatalDiagnosticError(
|
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
||||||
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
`@${decorator.name} can have at most one argument, got ${
|
||||||
`@${decorator.name} can have at most one argument, got ${decorator.args.length} argument(s)`);
|
decorator.args.length} argument(s)`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
},
|
}, {} as {[field: string]: string | [string, string]});
|
||||||
{} as{[field: string]: string | [string, string]});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveInput(publicName: string, internalName: string): [string, string] {
|
function resolveInput(publicName: string, internalName: string): [string, string] {
|
||||||
|
@ -552,7 +560,7 @@ export function queriesFromFields(
|
||||||
const node = member.node || Decorator.nodeForError(decorator);
|
const node = member.node || Decorator.nodeForError(decorator);
|
||||||
|
|
||||||
// Throw in case of `@Input() @ContentChild('foo') foo: any`, which is not supported in Ivy
|
// Throw in case of `@Input() @ContentChild('foo') foo: any`, which is not supported in Ivy
|
||||||
if (member.decorators !.some(v => v.name === 'Input')) {
|
if (member.decorators!.some(v => v.name === 'Input')) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.DECORATOR_COLLISION, node,
|
ErrorCode.DECORATOR_COLLISION, node,
|
||||||
'Cannot combine @Input decorators with query decorators');
|
'Cannot combine @Input decorators with query decorators');
|
||||||
|
@ -626,38 +634,40 @@ function evaluateHostExpressionBindings(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractHostBindings(
|
export function extractHostBindings(
|
||||||
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined,
|
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string|undefined,
|
||||||
metadata?: Map<string, ts.Expression>): ParsedHostBindings {
|
metadata?: Map<string, ts.Expression>): ParsedHostBindings {
|
||||||
let bindings: ParsedHostBindings;
|
let bindings: ParsedHostBindings;
|
||||||
if (metadata && metadata.has('host')) {
|
if (metadata && metadata.has('host')) {
|
||||||
bindings = evaluateHostExpressionBindings(metadata.get('host') !, evaluator);
|
bindings = evaluateHostExpressionBindings(metadata.get('host')!, evaluator);
|
||||||
} else {
|
} else {
|
||||||
bindings = parseHostBindings({});
|
bindings = parseHostBindings({});
|
||||||
}
|
}
|
||||||
|
|
||||||
filterToMembersWithDecorator(members, 'HostBinding', coreModule).forEach(({member, decorators}) => {
|
filterToMembersWithDecorator(members, 'HostBinding', coreModule)
|
||||||
decorators.forEach(decorator => {
|
.forEach(({member, decorators}) => {
|
||||||
let hostPropertyName: string = member.name;
|
decorators.forEach(decorator => {
|
||||||
if (decorator.args !== null && decorator.args.length > 0) {
|
let hostPropertyName: string = member.name;
|
||||||
if (decorator.args.length !== 1) {
|
if (decorator.args !== null && decorator.args.length > 0) {
|
||||||
throw new FatalDiagnosticError(
|
if (decorator.args.length !== 1) {
|
||||||
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
throw new FatalDiagnosticError(
|
||||||
`@HostBinding can have at most one argument, got ${decorator.args.length} argument(s)`);
|
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
||||||
}
|
`@HostBinding can have at most one argument, got ${
|
||||||
|
decorator.args.length} argument(s)`);
|
||||||
|
}
|
||||||
|
|
||||||
const resolved = evaluator.evaluate(decorator.args[0]);
|
const resolved = evaluator.evaluate(decorator.args[0]);
|
||||||
if (typeof resolved !== 'string') {
|
if (typeof resolved !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||||
`@HostBinding's argument must be a string`);
|
`@HostBinding's argument must be a string`);
|
||||||
}
|
}
|
||||||
|
|
||||||
hostPropertyName = resolved;
|
hostPropertyName = resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings.properties[hostPropertyName] = member.name;
|
bindings.properties[hostPropertyName] = member.name;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
filterToMembersWithDecorator(members, 'HostListener', coreModule)
|
filterToMembersWithDecorator(members, 'HostListener', coreModule)
|
||||||
.forEach(({member, decorators}) => {
|
.forEach(({member, decorators}) => {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {R3FactoryMetadata, compileFactoryFunction} from '@angular/compiler';
|
import {compileFactoryFunction, R3FactoryMetadata} from '@angular/compiler';
|
||||||
|
|
||||||
import {CompileResult} from '../../transform';
|
import {CompileResult} from '../../transform';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Expression, Identifiers, LiteralExpr, R3DependencyMetadata, R3FactoryTarget, R3InjectableMetadata, R3ResolvedDependencyType, Statement, WrappedNodeExpr, compileInjectable as compileIvyInjectable} from '@angular/compiler';
|
import {compileInjectable as compileIvyInjectable, Expression, Identifiers, LiteralExpr, R3DependencyMetadata, R3FactoryTarget, R3InjectableMetadata, R3ResolvedDependencyType, Statement, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
|
@ -83,7 +83,9 @@ export class InjectableDecoratorHandler implements
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
register(node: ClassDeclaration): void { this.injectableRegistry.registerInjectable(node); }
|
register(node: ClassDeclaration): void {
|
||||||
|
this.injectableRegistry.registerInjectable(node);
|
||||||
|
}
|
||||||
|
|
||||||
compile(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>): CompileResult[] {
|
compile(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>): CompileResult[] {
|
||||||
const res = compileIvyInjectable(analysis.meta);
|
const res = compileIvyInjectable(analysis.meta);
|
||||||
|
@ -165,12 +167,12 @@ function extractInjectableMetadata(
|
||||||
const meta = reflectObjectLiteral(metaNode);
|
const meta = reflectObjectLiteral(metaNode);
|
||||||
let providedIn: Expression = new LiteralExpr(null);
|
let providedIn: Expression = new LiteralExpr(null);
|
||||||
if (meta.has('providedIn')) {
|
if (meta.has('providedIn')) {
|
||||||
providedIn = new WrappedNodeExpr(meta.get('providedIn') !);
|
providedIn = new WrappedNodeExpr(meta.get('providedIn')!);
|
||||||
}
|
}
|
||||||
|
|
||||||
let userDeps: R3DependencyMetadata[]|undefined = undefined;
|
let userDeps: R3DependencyMetadata[]|undefined = undefined;
|
||||||
if ((meta.has('useClass') || meta.has('useFactory')) && meta.has('deps')) {
|
if ((meta.has('useClass') || meta.has('useFactory')) && meta.has('deps')) {
|
||||||
const depsExpr = meta.get('deps') !;
|
const depsExpr = meta.get('deps')!;
|
||||||
if (!ts.isArrayLiteralExpression(depsExpr)) {
|
if (!ts.isArrayLiteralExpression(depsExpr)) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_NOT_LITERAL, depsExpr,
|
ErrorCode.VALUE_NOT_LITERAL, depsExpr,
|
||||||
|
@ -186,7 +188,7 @@ function extractInjectableMetadata(
|
||||||
typeArgumentCount,
|
typeArgumentCount,
|
||||||
internalType,
|
internalType,
|
||||||
providedIn,
|
providedIn,
|
||||||
useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue') !, reflector)),
|
useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue')!, reflector)),
|
||||||
};
|
};
|
||||||
} else if (meta.has('useExisting')) {
|
} else if (meta.has('useExisting')) {
|
||||||
return {
|
return {
|
||||||
|
@ -195,7 +197,7 @@ function extractInjectableMetadata(
|
||||||
typeArgumentCount,
|
typeArgumentCount,
|
||||||
internalType,
|
internalType,
|
||||||
providedIn,
|
providedIn,
|
||||||
useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting') !, reflector)),
|
useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting')!, reflector)),
|
||||||
};
|
};
|
||||||
} else if (meta.has('useClass')) {
|
} else if (meta.has('useClass')) {
|
||||||
return {
|
return {
|
||||||
|
@ -204,19 +206,20 @@ function extractInjectableMetadata(
|
||||||
typeArgumentCount,
|
typeArgumentCount,
|
||||||
internalType,
|
internalType,
|
||||||
providedIn,
|
providedIn,
|
||||||
useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass') !, reflector)),
|
useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass')!, reflector)),
|
||||||
userDeps,
|
userDeps,
|
||||||
};
|
};
|
||||||
} else if (meta.has('useFactory')) {
|
} else if (meta.has('useFactory')) {
|
||||||
// useFactory is special - the 'deps' property must be analyzed.
|
// useFactory is special - the 'deps' property must be analyzed.
|
||||||
const factory = new WrappedNodeExpr(meta.get('useFactory') !);
|
const factory = new WrappedNodeExpr(meta.get('useFactory')!);
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
typeArgumentCount,
|
typeArgumentCount,
|
||||||
internalType,
|
internalType,
|
||||||
providedIn,
|
providedIn,
|
||||||
useFactory: factory, userDeps,
|
useFactory: factory,
|
||||||
|
userDeps,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {name, type, typeArgumentCount, internalType, providedIn};
|
return {name, type, typeArgumentCount, internalType, providedIn};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NONE_TYPE, ReturnStatement, Statement, WrappedNodeExpr, literalMap} from '@angular/compiler';
|
import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, literalMap, NONE_TYPE, ReturnStatement, Statement, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DefaultImportRecorder} from '../../imports';
|
import {DefaultImportRecorder} from '../../imports';
|
||||||
|
@ -71,7 +71,7 @@ export function generateSetClassMetadataCall(
|
||||||
duplicateDecoratedMemberNames.join(', '));
|
duplicateDecoratedMemberNames.join(', '));
|
||||||
}
|
}
|
||||||
const decoratedMembers =
|
const decoratedMembers =
|
||||||
classMembers.map(member => classMemberToMetadata(member.name, member.decorators !, isCore));
|
classMembers.map(member => classMemberToMetadata(member.name, member.decorators!, isCore));
|
||||||
if (decoratedMembers.length > 0) {
|
if (decoratedMembers.length > 0) {
|
||||||
metaPropDecorators = ts.createObjectLiteral(decoratedMembers);
|
metaPropDecorators = ts.createObjectLiteral(decoratedMembers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CUSTOM_ELEMENTS_SCHEMA, Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NO_ERRORS_SCHEMA, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, STRING_TYPE, SchemaMetadata, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler';
|
import {compileInjector, compileNgModule, CUSTOM_ELEMENTS_SCHEMA, Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NO_ERRORS_SCHEMA, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, SchemaMetadata, Statement, STRING_TYPE, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
||||||
|
@ -40,7 +40,9 @@ export interface NgModuleAnalysis {
|
||||||
providers: ts.Expression|null;
|
providers: ts.Expression|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NgModuleResolution { injectorImports: Expression[]; }
|
export interface NgModuleResolution {
|
||||||
|
injectorImports: Expression[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles @NgModule annotations to ngModuleDef fields.
|
* Compiles @NgModule annotations to ngModuleDef fields.
|
||||||
|
@ -116,7 +118,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
let declarationRefs: Reference<ClassDeclaration>[] = [];
|
let declarationRefs: Reference<ClassDeclaration>[] = [];
|
||||||
let rawDeclarations: ts.Expression|null = null;
|
let rawDeclarations: ts.Expression|null = null;
|
||||||
if (ngModule.has('declarations')) {
|
if (ngModule.has('declarations')) {
|
||||||
rawDeclarations = ngModule.get('declarations') !;
|
rawDeclarations = ngModule.get('declarations')!;
|
||||||
const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver);
|
const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver);
|
||||||
declarationRefs =
|
declarationRefs =
|
||||||
this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations');
|
this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations');
|
||||||
|
@ -128,7 +130,9 @@ export class NgModuleDecoratorHandler implements
|
||||||
|
|
||||||
diagnostics.push(makeDiagnostic(
|
diagnostics.push(makeDiagnostic(
|
||||||
ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode,
|
ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode,
|
||||||
`Cannot declare '${ref.node.name.text}' in an NgModule as it's not a part of the current compilation.`,
|
`Cannot declare '${
|
||||||
|
ref.node.name
|
||||||
|
.text}' in an NgModule as it's not a part of the current compilation.`,
|
||||||
[{
|
[{
|
||||||
node: ref.node.name,
|
node: ref.node.name,
|
||||||
messageText: `'${ref.node.name.text}' is declared here.`,
|
messageText: `'${ref.node.name.text}' is declared here.`,
|
||||||
|
@ -144,28 +148,28 @@ export class NgModuleDecoratorHandler implements
|
||||||
let importRefs: Reference<ClassDeclaration>[] = [];
|
let importRefs: Reference<ClassDeclaration>[] = [];
|
||||||
let rawImports: ts.Expression|null = null;
|
let rawImports: ts.Expression|null = null;
|
||||||
if (ngModule.has('imports')) {
|
if (ngModule.has('imports')) {
|
||||||
rawImports = ngModule.get('imports') !;
|
rawImports = ngModule.get('imports')!;
|
||||||
const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers);
|
const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers);
|
||||||
importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports');
|
importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports');
|
||||||
}
|
}
|
||||||
let exportRefs: Reference<ClassDeclaration>[] = [];
|
let exportRefs: Reference<ClassDeclaration>[] = [];
|
||||||
let rawExports: ts.Expression|null = null;
|
let rawExports: ts.Expression|null = null;
|
||||||
if (ngModule.has('exports')) {
|
if (ngModule.has('exports')) {
|
||||||
rawExports = ngModule.get('exports') !;
|
rawExports = ngModule.get('exports')!;
|
||||||
const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers);
|
const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers);
|
||||||
exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports');
|
exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports');
|
||||||
this.referencesRegistry.add(node, ...exportRefs);
|
this.referencesRegistry.add(node, ...exportRefs);
|
||||||
}
|
}
|
||||||
let bootstrapRefs: Reference<ClassDeclaration>[] = [];
|
let bootstrapRefs: Reference<ClassDeclaration>[] = [];
|
||||||
if (ngModule.has('bootstrap')) {
|
if (ngModule.has('bootstrap')) {
|
||||||
const expr = ngModule.get('bootstrap') !;
|
const expr = ngModule.get('bootstrap')!;
|
||||||
const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver);
|
const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver);
|
||||||
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
||||||
}
|
}
|
||||||
|
|
||||||
const schemas: SchemaMetadata[] = [];
|
const schemas: SchemaMetadata[] = [];
|
||||||
if (ngModule.has('schemas')) {
|
if (ngModule.has('schemas')) {
|
||||||
const rawExpr = ngModule.get('schemas') !;
|
const rawExpr = ngModule.get('schemas')!;
|
||||||
const result = this.evaluator.evaluate(rawExpr);
|
const result = this.evaluator.evaluate(rawExpr);
|
||||||
if (!Array.isArray(result)) {
|
if (!Array.isArray(result)) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -203,7 +207,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
}
|
}
|
||||||
|
|
||||||
const id: Expression|null =
|
const id: Expression|null =
|
||||||
ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id') !) : null;
|
ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id')!) : null;
|
||||||
const valueContext = node.getSourceFile();
|
const valueContext = node.getSourceFile();
|
||||||
|
|
||||||
let typeContext = valueContext;
|
let typeContext = valueContext;
|
||||||
|
@ -220,7 +224,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext));
|
const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext));
|
||||||
|
|
||||||
const isForwardReference = (ref: R3Reference) =>
|
const isForwardReference = (ref: R3Reference) =>
|
||||||
isExpressionForwardReference(ref.value, node.name !, valueContext);
|
isExpressionForwardReference(ref.value, node.name!, valueContext);
|
||||||
const containsForwardDecls = bootstrap.some(isForwardReference) ||
|
const containsForwardDecls = bootstrap.some(isForwardReference) ||
|
||||||
declarations.some(isForwardReference) || imports.some(isForwardReference) ||
|
declarations.some(isForwardReference) || imports.some(isForwardReference) ||
|
||||||
exports.some(isForwardReference);
|
exports.some(isForwardReference);
|
||||||
|
@ -244,7 +248,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
schemas: [],
|
schemas: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rawProviders = ngModule.has('providers') ? ngModule.get('providers') ! : null;
|
const rawProviders = ngModule.has('providers') ? ngModule.get('providers')! : null;
|
||||||
const wrapperProviders = rawProviders !== null ?
|
const wrapperProviders = rawProviders !== null ?
|
||||||
new WrappedNodeExpr(
|
new WrappedNodeExpr(
|
||||||
this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) :
|
this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) :
|
||||||
|
@ -256,7 +260,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
// and pipes from the module exports.
|
// and pipes from the module exports.
|
||||||
const injectorImports: WrappedNodeExpr<ts.Expression>[] = [];
|
const injectorImports: WrappedNodeExpr<ts.Expression>[] = [];
|
||||||
if (ngModule.has('imports')) {
|
if (ngModule.has('imports')) {
|
||||||
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports') !));
|
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports')!));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.routeAnalyzer !== null) {
|
if (this.routeAnalyzer !== null) {
|
||||||
|
@ -279,7 +283,8 @@ export class NgModuleDecoratorHandler implements
|
||||||
schemas: schemas,
|
schemas: schemas,
|
||||||
mod: ngModuleDef,
|
mod: ngModuleDef,
|
||||||
inj: ngInjectorDef,
|
inj: ngInjectorDef,
|
||||||
declarations: declarationRefs, rawDeclarations,
|
declarations: declarationRefs,
|
||||||
|
rawDeclarations,
|
||||||
imports: importRefs,
|
imports: importRefs,
|
||||||
exports: exportRefs,
|
exports: exportRefs,
|
||||||
providers: rawProviders,
|
providers: rawProviders,
|
||||||
|
@ -326,7 +331,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
|
|
||||||
if (analysis.providersRequiringFactory !== null) {
|
if (analysis.providersRequiringFactory !== null) {
|
||||||
const providerDiagnostics = getProviderDiagnostics(
|
const providerDiagnostics = getProviderDiagnostics(
|
||||||
analysis.providersRequiringFactory, analysis.providers !, this.injectableRegistry);
|
analysis.providersRequiringFactory, analysis.providers!, this.injectableRegistry);
|
||||||
diagnostics.push(...providerDiagnostics);
|
diagnostics.push(...providerDiagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +401,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
const pipes = scope.compilation.pipes.map(pipe => this.refEmitter.emit(pipe.ref, context));
|
const pipes = scope.compilation.pipes.map(pipe => this.refEmitter.emit(pipe.ref, context));
|
||||||
const directiveArray = new LiteralArrayExpr(directives);
|
const directiveArray = new LiteralArrayExpr(directives);
|
||||||
const pipesArray = new LiteralArrayExpr(pipes);
|
const pipesArray = new LiteralArrayExpr(pipes);
|
||||||
const declExpr = this.refEmitter.emit(decl, context) !;
|
const declExpr = this.refEmitter.emit(decl, context)!;
|
||||||
const setComponentScope = new ExternalExpr(R3Identifiers.setComponentScope);
|
const setComponentScope = new ExternalExpr(R3Identifiers.setComponentScope);
|
||||||
const callExpr =
|
const callExpr =
|
||||||
new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
||||||
|
@ -472,8 +477,9 @@ export class NgModuleDecoratorHandler implements
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const typeName = type && (ts.isIdentifier(type.typeName) && type.typeName ||
|
const typeName = type &&
|
||||||
ts.isQualifiedName(type.typeName) && type.typeName.right) ||
|
(ts.isIdentifier(type.typeName) && type.typeName ||
|
||||||
|
ts.isQualifiedName(type.typeName) && type.typeName.right) ||
|
||||||
null;
|
null;
|
||||||
if (typeName === null) {
|
if (typeName === null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -559,7 +565,7 @@ export class NgModuleDecoratorHandler implements
|
||||||
// Unwrap ModuleWithProviders for modules that are locally declared (and thus static
|
// Unwrap ModuleWithProviders for modules that are locally declared (and thus static
|
||||||
// resolution was able to descend into the function and return an object literal, a Map).
|
// resolution was able to descend into the function and return an object literal, a Map).
|
||||||
if (entry instanceof Map && entry.has('ngModule')) {
|
if (entry instanceof Map && entry.has('ngModule')) {
|
||||||
entry = entry.get('ngModule') !;
|
entry = entry.get('ngModule')!;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(entry)) {
|
if (Array.isArray(entry)) {
|
||||||
|
@ -569,14 +575,16 @@ export class NgModuleDecoratorHandler implements
|
||||||
if (!this.isClassDeclarationReference(entry)) {
|
if (!this.isClassDeclarationReference(entry)) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, entry.node,
|
ErrorCode.VALUE_HAS_WRONG_TYPE, entry.node,
|
||||||
`Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a class`);
|
`Value at position ${idx} in the NgModule.${arrayName} of ${
|
||||||
|
className} is not a class`);
|
||||||
}
|
}
|
||||||
refList.push(entry);
|
refList.push(entry);
|
||||||
} else {
|
} else {
|
||||||
// TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
|
// TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr,
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr,
|
||||||
`Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a reference: ${entry}`);
|
`Value at position ${idx} in the NgModule.${arrayName} of ${
|
||||||
|
className} is not a reference: ${entry}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr, compilePipeFromMetadata} from '@angular/compiler';
|
import {compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
|
@ -79,7 +79,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.PIPE_MISSING_NAME, meta, `@Pipe decorator is missing name field`);
|
ErrorCode.PIPE_MISSING_NAME, meta, `@Pipe decorator is missing name field`);
|
||||||
}
|
}
|
||||||
const pipeNameExpr = pipe.get('name') !;
|
const pipeNameExpr = pipe.get('name')!;
|
||||||
const pipeName = this.evaluator.evaluate(pipeNameExpr);
|
const pipeName = this.evaluator.evaluate(pipeNameExpr);
|
||||||
if (typeof pipeName !== 'string') {
|
if (typeof pipeName !== 'string') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -88,7 +88,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
||||||
|
|
||||||
let pure = true;
|
let pure = true;
|
||||||
if (pipe.has('pure')) {
|
if (pipe.has('pure')) {
|
||||||
const expr = pipe.get('pure') !;
|
const expr = pipe.get('pure')!;
|
||||||
const pureValue = this.evaluator.evaluate(expr);
|
const pureValue = this.evaluator.evaluate(expr);
|
||||||
if (typeof pureValue !== 'boolean') {
|
if (typeof pureValue !== 'boolean') {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -103,7 +103,8 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
internalType,
|
internalType,
|
||||||
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0, pipeName,
|
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
||||||
|
pipeName,
|
||||||
deps: getValidConstructorDependencies(
|
deps: getValidConstructorDependencies(
|
||||||
clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||||
pure,
|
pure,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
||||||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
||||||
import {DefaultImportRecorder, ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
import {DefaultImportRecorder, ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
||||||
import {ForeignFunctionResolver, PartialEvaluator} from '../../partial_evaluator';
|
import {ForeignFunctionResolver, PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, CtorParameter, Decorator, Import, ReflectionHost, TypeValueReference, isNamedClassDeclaration} from '../../reflection';
|
import {ClassDeclaration, CtorParameter, Decorator, Import, isNamedClassDeclaration, ReflectionHost, TypeValueReference} from '../../reflection';
|
||||||
import {DeclarationData} from '../../scope';
|
import {DeclarationData} from '../../scope';
|
||||||
|
|
||||||
export enum ConstructorDepErrorKind {
|
export enum ConstructorDepErrorKind {
|
||||||
|
@ -21,8 +21,7 @@ export enum ConstructorDepErrorKind {
|
||||||
|
|
||||||
export type ConstructorDeps = {
|
export type ConstructorDeps = {
|
||||||
deps: R3DependencyMetadata[];
|
deps: R3DependencyMetadata[];
|
||||||
} |
|
}|{
|
||||||
{
|
|
||||||
deps: null;
|
deps: null;
|
||||||
errors: ConstructorDepError[];
|
errors: ConstructorDepError[];
|
||||||
};
|
};
|
||||||
|
@ -53,7 +52,7 @@ export function getConstructorDependencies(
|
||||||
let resolved = R3ResolvedDependencyType.Token;
|
let resolved = R3ResolvedDependencyType.Token;
|
||||||
|
|
||||||
(param.decorators || []).filter(dec => isCore || isAngularCore(dec)).forEach(dec => {
|
(param.decorators || []).filter(dec => isCore || isAngularCore(dec)).forEach(dec => {
|
||||||
const name = isCore || dec.import === null ? dec.name : dec.import !.name;
|
const name = isCore || dec.import === null ? dec.name : dec.import!.name;
|
||||||
if (name === 'Inject') {
|
if (name === 'Inject') {
|
||||||
if (dec.args === null || dec.args.length !== 1) {
|
if (dec.args === null || dec.args.length !== 1) {
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
|
@ -97,7 +96,8 @@ export function getConstructorDependencies(
|
||||||
if (token === null) {
|
if (token === null) {
|
||||||
errors.push({
|
errors.push({
|
||||||
index: idx,
|
index: idx,
|
||||||
kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, param,
|
kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN,
|
||||||
|
param,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
deps.push({token, attribute, optional, self, skipSelf, host, resolved});
|
deps.push({token, attribute, optional, self, skipSelf, host, resolved});
|
||||||
|
@ -122,10 +122,10 @@ export function valueReferenceToExpression(
|
||||||
export function valueReferenceToExpression(
|
export function valueReferenceToExpression(
|
||||||
valueRef: null, defaultImportRecorder: DefaultImportRecorder): null;
|
valueRef: null, defaultImportRecorder: DefaultImportRecorder): null;
|
||||||
export function valueReferenceToExpression(
|
export function valueReferenceToExpression(
|
||||||
valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||||
null;
|
null;
|
||||||
export function valueReferenceToExpression(
|
export function valueReferenceToExpression(
|
||||||
valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||||
null {
|
null {
|
||||||
if (valueRef === null) {
|
if (valueRef === null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -138,7 +138,7 @@ export function valueReferenceToExpression(
|
||||||
return new WrappedNodeExpr(valueRef.expression);
|
return new WrappedNodeExpr(valueRef.expression);
|
||||||
} else {
|
} else {
|
||||||
// TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here.
|
// TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here.
|
||||||
return new ExternalExpr(valueRef as{moduleName: string, name: string});
|
return new ExternalExpr(valueRef as {moduleName: string, name: string});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ export function valueReferenceToExpression(
|
||||||
*
|
*
|
||||||
* This is a companion function to `validateConstructorDependencies` which accepts invalid deps.
|
* This is a companion function to `validateConstructorDependencies` which accepts invalid deps.
|
||||||
*/
|
*/
|
||||||
export function unwrapConstructorDependencies(deps: ConstructorDeps | null): R3DependencyMetadata[]|
|
export function unwrapConstructorDependencies(deps: ConstructorDeps|null): R3DependencyMetadata[]|
|
||||||
'invalid'|null {
|
'invalid'|null {
|
||||||
if (deps === null) {
|
if (deps === null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -176,18 +176,19 @@ export function getValidConstructorDependencies(
|
||||||
* deps.
|
* deps.
|
||||||
*/
|
*/
|
||||||
export function validateConstructorDependencies(
|
export function validateConstructorDependencies(
|
||||||
clazz: ClassDeclaration, deps: ConstructorDeps | null): R3DependencyMetadata[]|null {
|
clazz: ClassDeclaration, deps: ConstructorDeps|null): R3DependencyMetadata[]|null {
|
||||||
if (deps === null) {
|
if (deps === null) {
|
||||||
return null;
|
return null;
|
||||||
} else if (deps.deps !== null) {
|
} else if (deps.deps !== null) {
|
||||||
return deps.deps;
|
return deps.deps;
|
||||||
} else {
|
} else {
|
||||||
// TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here.
|
// TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here.
|
||||||
const {param, index} = (deps as{errors: ConstructorDepError[]}).errors[0];
|
const {param, index} = (deps as {errors: ConstructorDepError[]}).errors[0];
|
||||||
// There is at least one error.
|
// There is at least one error.
|
||||||
throw new FatalDiagnosticError(
|
throw new FatalDiagnosticError(
|
||||||
ErrorCode.PARAM_MISSING_TOKEN, param.nameNode,
|
ErrorCode.PARAM_MISSING_TOKEN, param.nameNode,
|
||||||
`No suitable injection token for parameter '${param.name || index}' of class '${clazz.name.text}'.\n` +
|
`No suitable injection token for parameter '${param.name || index}' of class '${
|
||||||
|
clazz.name.text}'.\n` +
|
||||||
(param.typeNode !== null ? `Found ${param.typeNode.getText()}` :
|
(param.typeNode !== null ? `Found ${param.typeNode.getText()}` :
|
||||||
'no type or decorator'));
|
'no type or decorator'));
|
||||||
}
|
}
|
||||||
|
@ -319,8 +320,7 @@ export function forwardRefResolver(
|
||||||
*/
|
*/
|
||||||
export function combineResolvers(resolvers: ForeignFunctionResolver[]): ForeignFunctionResolver {
|
export function combineResolvers(resolvers: ForeignFunctionResolver[]): ForeignFunctionResolver {
|
||||||
return (ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>,
|
return (ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>,
|
||||||
args: ReadonlyArray<ts.Expression>): ts.Expression |
|
args: ReadonlyArray<ts.Expression>): ts.Expression|null => {
|
||||||
null => {
|
|
||||||
for (const resolver of resolvers) {
|
for (const resolver of resolvers) {
|
||||||
const resolved = resolver(ref, args);
|
const resolved = resolver(ref, args);
|
||||||
if (resolved !== null) {
|
if (resolved !== null) {
|
||||||
|
@ -406,8 +406,8 @@ export function makeDuplicateDeclarationError(
|
||||||
const contextNode = decl.ref.getOriginForDiagnostics(decl.rawDeclarations, decl.ngModule.name);
|
const contextNode = decl.ref.getOriginForDiagnostics(decl.rawDeclarations, decl.ngModule.name);
|
||||||
context.push({
|
context.push({
|
||||||
node: contextNode,
|
node: contextNode,
|
||||||
messageText:
|
messageText: `'${node.name.text}' is listed in the declarations of the NgModule '${
|
||||||
`'${node.name.text}' is listed in the declarations of the NgModule '${decl.ngModule.name.text}'.`,
|
decl.ngModule.name.text}'.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +441,7 @@ export function resolveProvidersRequiringFactory(
|
||||||
} else if (provider instanceof Reference) {
|
} else if (provider instanceof Reference) {
|
||||||
tokenClass = provider;
|
tokenClass = provider;
|
||||||
} else if (provider instanceof Map && provider.has('useClass') && !provider.has('deps')) {
|
} else if (provider instanceof Map && provider.has('useClass') && !provider.has('deps')) {
|
||||||
const useExisting = provider.get('useClass') !;
|
const useExisting = provider.get('useClass')!;
|
||||||
if (useExisting instanceof Reference) {
|
if (useExisting instanceof Reference) {
|
||||||
tokenClass = useExisting;
|
tokenClass = useExisting;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,23 @@ import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
||||||
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {ResourceLoader} from '../src/api';
|
import {ResourceLoader} from '../src/api';
|
||||||
import {ComponentDecoratorHandler} from '../src/component';
|
import {ComponentDecoratorHandler} from '../src/component';
|
||||||
|
|
||||||
export class NoopResourceLoader implements ResourceLoader {
|
export class NoopResourceLoader implements ResourceLoader {
|
||||||
resolve(): string { throw new Error('Not implemented.'); }
|
resolve(): string {
|
||||||
|
throw new Error('Not implemented.');
|
||||||
|
}
|
||||||
canPreload = false;
|
canPreload = false;
|
||||||
load(): string { throw new Error('Not implemented'); }
|
load(): string {
|
||||||
preload(): Promise<void>|undefined { throw new Error('Not implemented'); }
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
|
preload(): Promise<void>|undefined {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
runInEachFileSystem(() => {
|
runInEachFileSystem(() => {
|
||||||
describe('ComponentDecoratorHandler', () => {
|
describe('ComponentDecoratorHandler', () => {
|
||||||
|
@ -83,10 +89,12 @@ runInEachFileSystem(() => {
|
||||||
const diag = err.toDiagnostic();
|
const diag = err.toDiagnostic();
|
||||||
expect(diag.code).toEqual(ivyCode(ErrorCode.DECORATOR_ARG_NOT_LITERAL));
|
expect(diag.code).toEqual(ivyCode(ErrorCode.DECORATOR_ARG_NOT_LITERAL));
|
||||||
expect(diag.file.fileName.endsWith('entry.ts')).toBe(true);
|
expect(diag.file.fileName.endsWith('entry.ts')).toBe(true);
|
||||||
expect(diag.start).toBe(detected.metadata.args ![0].getStart());
|
expect(diag.start).toBe(detected.metadata.args![0].getStart());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function ivyCode(code: ErrorCode): number { return Number('-99' + code.valueOf()); }
|
function ivyCode(code: ErrorCode): number {
|
||||||
|
return Number('-99' + code.valueOf());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom} from '../../file_system';
|
import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
||||||
import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {ClassDeclaration, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {DirectiveDecoratorHandler} from '../src/directive';
|
import {DirectiveDecoratorHandler} from '../src/directive';
|
||||||
|
@ -77,9 +78,13 @@ runInEachFileSystem(() => {
|
||||||
// Helpers
|
// Helpers
|
||||||
function analyzeDirective(program: ts.Program, dirName: string, hasBaseClass: boolean = false) {
|
function analyzeDirective(program: ts.Program, dirName: string, hasBaseClass: boolean = false) {
|
||||||
class TestReflectionHost extends TypeScriptReflectionHost {
|
class TestReflectionHost extends TypeScriptReflectionHost {
|
||||||
constructor(checker: ts.TypeChecker) { super(checker); }
|
constructor(checker: ts.TypeChecker) {
|
||||||
|
super(checker);
|
||||||
|
}
|
||||||
|
|
||||||
hasBaseClass(_class: ClassDeclaration): boolean { return hasBaseClass; }
|
hasBaseClass(_class: ClassDeclaration): boolean {
|
||||||
|
return hasBaseClass;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const checker = program.getTypeChecker();
|
const checker = program.getTypeChecker();
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {absoluteFrom} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports';
|
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports';
|
||||||
import {InjectableClassRegistry} from '../../metadata';
|
import {InjectableClassRegistry} from '../../metadata';
|
||||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {InjectableDecoratorHandler} from '../src/injectable';
|
import {InjectableDecoratorHandler} from '../src/injectable';
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ runInEachFileSystem(() => {
|
||||||
const diag = err.toDiagnostic();
|
const diag = err.toDiagnostic();
|
||||||
expect(diag.code).toEqual(ngErrorCode(ErrorCode.INJECTABLE_DUPLICATE_PROV));
|
expect(diag.code).toEqual(ngErrorCode(ErrorCode.INJECTABLE_DUPLICATE_PROV));
|
||||||
expect(diag.file.fileName.endsWith('entry.ts')).toBe(true);
|
expect(diag.file.fileName.endsWith('entry.ts')).toBe(true);
|
||||||
expect(diag.start).toBe(ɵprov.nameNode !.getStart());
|
expect(diag.start).toBe(ɵprov.nameNode!.getStart());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@ runInEachFileSystem(() => {
|
||||||
expect(res).not.toContain(jasmine.objectContaining({name: 'ɵprov'}));
|
expect(res).not.toContain(jasmine.objectContaining({name: 'ɵprov'}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
||||||
import {TestFile, runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||||
import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
|
import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
|
||||||
import {TypeScriptReflectionHost} from '../../reflection';
|
import {TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
||||||
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {NgModuleDecoratorHandler} from '../src/ng_module';
|
import {NgModuleDecoratorHandler} from '../src/ng_module';
|
||||||
|
@ -79,7 +79,7 @@ runInEachFileSystem(() => {
|
||||||
if (detected === undefined) {
|
if (detected === undefined) {
|
||||||
return fail('Failed to recognize @NgModule');
|
return fail('Failed to recognize @NgModule');
|
||||||
}
|
}
|
||||||
const moduleDef = handler.analyze(TestModule, detected.metadata).analysis !.mod;
|
const moduleDef = handler.analyze(TestModule, detected.metadata).analysis!.mod;
|
||||||
|
|
||||||
expect(getReferenceIdentifierTexts(moduleDef.declarations)).toEqual(['TestComp']);
|
expect(getReferenceIdentifierTexts(moduleDef.declarations)).toEqual(['TestComp']);
|
||||||
expect(getReferenceIdentifierTexts(moduleDef.exports)).toEqual(['TestComp']);
|
expect(getReferenceIdentifierTexts(moduleDef.exports)).toEqual(['TestComp']);
|
||||||
|
|
|
@ -13,8 +13,9 @@ import {unwrapExpression} from '../src/util';
|
||||||
describe('ngtsc annotation utilities', () => {
|
describe('ngtsc annotation utilities', () => {
|
||||||
describe('unwrapExpression', () => {
|
describe('unwrapExpression', () => {
|
||||||
const obj = ts.createObjectLiteral();
|
const obj = ts.createObjectLiteral();
|
||||||
it('should pass through an ObjectLiteralExpression',
|
it('should pass through an ObjectLiteralExpression', () => {
|
||||||
() => { expect(unwrapExpression(obj)).toBe(obj); });
|
expect(unwrapExpression(obj)).toBe(obj);
|
||||||
|
});
|
||||||
|
|
||||||
it('should unwrap an ObjectLiteralExpression in parentheses', () => {
|
it('should unwrap an ObjectLiteralExpression in parentheses', () => {
|
||||||
const wrapped = ts.createParen(obj);
|
const wrapped = ts.createParen(obj);
|
||||||
|
|
|
@ -56,7 +56,7 @@ export interface ResourceHost {
|
||||||
* core interface.
|
* core interface.
|
||||||
*/
|
*/
|
||||||
export interface ExtendedTsCompilerHost extends ts.CompilerHost, Partial<ResourceHost>,
|
export interface ExtendedTsCompilerHost extends ts.CompilerHost, Partial<ResourceHost>,
|
||||||
Partial<UnifiedModulesHost> {}
|
Partial<UnifiedModulesHost> {}
|
||||||
|
|
||||||
export interface LazyRoute {
|
export interface LazyRoute {
|
||||||
route: string;
|
route: string;
|
||||||
|
|
|
@ -36,7 +36,8 @@ export interface TestOnlyOptions {
|
||||||
*/
|
*/
|
||||||
ivyTemplateTypeCheck?: boolean;
|
ivyTemplateTypeCheck?: boolean;
|
||||||
|
|
||||||
/** An option to enable ngtsc's internal performance tracing.
|
/**
|
||||||
|
* An option to enable ngtsc's internal performance tracing.
|
||||||
*
|
*
|
||||||
* This should be a path to a JSON file where trace information will be written. An optional 'ts:'
|
* This should be a path to a JSON file where trace information will be written. An optional 'ts:'
|
||||||
* prefix will cause the trace to be written via the TS host instead of directly to the filesystem
|
* prefix will cause the trace to be written via the TS host instead of directly to the filesystem
|
||||||
|
@ -54,4 +55,5 @@ export interface TestOnlyOptions {
|
||||||
* Also includes a few miscellaneous options.
|
* Also includes a few miscellaneous options.
|
||||||
*/
|
*/
|
||||||
export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options,
|
export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options,
|
||||||
NgcCompatibilityOptions, StrictTemplateOptions, TestOnlyOptions, I18nOptions, MiscOptions {}
|
NgcCompatibilityOptions, StrictTemplateOptions,
|
||||||
|
TestOnlyOptions, I18nOptions, MiscOptions {}
|
|
@ -12,23 +12,23 @@ import * as ts from 'typescript';
|
||||||
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from '../../annotations';
|
import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from '../../annotations';
|
||||||
import {CycleAnalyzer, ImportGraph} from '../../cycles';
|
import {CycleAnalyzer, ImportGraph} from '../../cycles';
|
||||||
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
||||||
import {ReferenceGraph, checkForPrivateExports} from '../../entry_point';
|
import {checkForPrivateExports, ReferenceGraph} from '../../entry_point';
|
||||||
import {LogicalFileSystem, getSourceFileOrError} from '../../file_system';
|
import {getSourceFileOrError, LogicalFileSystem} from '../../file_system';
|
||||||
import {AbsoluteModuleStrategy, AliasStrategy, AliasingHost, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports';
|
import {AbsoluteModuleStrategy, AliasingHost, AliasStrategy, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports';
|
||||||
import {IncrementalDriver} from '../../incremental';
|
import {IncrementalDriver} from '../../incremental';
|
||||||
import {IndexedComponent, IndexingContext, generateAnalysis} from '../../indexer';
|
import {generateAnalysis, IndexedComponent, IndexingContext} from '../../indexer';
|
||||||
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, MetadataReader} from '../../metadata';
|
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, MetadataReader} from '../../metadata';
|
||||||
import {ModuleWithProvidersScanner} from '../../modulewithproviders';
|
import {ModuleWithProvidersScanner} from '../../modulewithproviders';
|
||||||
import {PartialEvaluator} from '../../partial_evaluator';
|
import {PartialEvaluator} from '../../partial_evaluator';
|
||||||
import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf';
|
import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf';
|
||||||
import {TypeScriptReflectionHost} from '../../reflection';
|
import {TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {HostResourceLoader} from '../../resource';
|
import {HostResourceLoader} from '../../resource';
|
||||||
import {NgModuleRouteAnalyzer, entryPointKeyFor} from '../../routing';
|
import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing';
|
||||||
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||||
import {generatedFactoryTransform} from '../../shims';
|
import {generatedFactoryTransform} from '../../shims';
|
||||||
import {ivySwitchTransform} from '../../switch';
|
import {ivySwitchTransform} from '../../switch';
|
||||||
import {DecoratorHandler, DtsTransformRegistry, TraitCompiler, aliasTransformFactory, declarationTransformFactory, ivyTransformFactory} from '../../transform';
|
import {aliasTransformFactory, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
||||||
import {TypeCheckContext, TypeCheckingConfig, isTemplateDiagnostic} from '../../typecheck';
|
import {isTemplateDiagnostic, TypeCheckContext, TypeCheckingConfig} from '../../typecheck';
|
||||||
import {getSourceFileOrNull, isDtsPath, resolveModuleName} from '../../util/src/typescript';
|
import {getSourceFileOrNull, isDtsPath, resolveModuleName} from '../../util/src/typescript';
|
||||||
import {LazyRoute, NgCompilerOptions} from '../api';
|
import {LazyRoute, NgCompilerOptions} from '../api';
|
||||||
|
|
||||||
|
@ -191,7 +191,9 @@ export class NgCompiler {
|
||||||
/**
|
/**
|
||||||
* Get all setup-related diagnostics for this compilation.
|
* Get all setup-related diagnostics for this compilation.
|
||||||
*/
|
*/
|
||||||
getOptionDiagnostics(): ts.Diagnostic[] { return this.constructionDiagnostics; }
|
getOptionDiagnostics(): ts.Diagnostic[] {
|
||||||
|
return this.constructionDiagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the `ts.Program` to use as a starting point when spawning a subsequent incremental
|
* Get the `ts.Program` to use as a starting point when spawning a subsequent incremental
|
||||||
|
@ -202,7 +204,9 @@ export class NgCompiler {
|
||||||
* operation, the consumer's `ts.Program` is no longer usable for starting a new incremental
|
* operation, the consumer's `ts.Program` is no longer usable for starting a new incremental
|
||||||
* compilation. `getNextProgram` retrieves the `ts.Program` which can be used instead.
|
* compilation. `getNextProgram` retrieves the `ts.Program` which can be used instead.
|
||||||
*/
|
*/
|
||||||
getNextProgram(): ts.Program { return this.nextProgram; }
|
getNextProgram(): ts.Program {
|
||||||
|
return this.nextProgram;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform Angular's analysis step (as a precursor to `getDiagnostics` or `prepareEmit`)
|
* Perform Angular's analysis step (as a precursor to `getDiagnostics` or `prepareEmit`)
|
||||||
|
@ -262,8 +266,8 @@ export class NgCompiler {
|
||||||
|
|
||||||
// Relative entry paths are disallowed.
|
// Relative entry paths are disallowed.
|
||||||
if (entryRoute.startsWith('.')) {
|
if (entryRoute.startsWith('.')) {
|
||||||
throw new Error(
|
throw new Error(`Failed to list lazy routes: Resolution of relative paths (${
|
||||||
`Failed to list lazy routes: Resolution of relative paths (${entryRoute}) is not supported.`);
|
entryRoute}) is not supported.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-relative entry paths fall into one of the following categories:
|
// Non-relative entry paths fall into one of the following categories:
|
||||||
|
@ -349,7 +353,7 @@ export class NgCompiler {
|
||||||
if (this.compilation === null) {
|
if (this.compilation === null) {
|
||||||
this.analyzeSync();
|
this.analyzeSync();
|
||||||
}
|
}
|
||||||
return this.compilation !;
|
return this.compilation!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private analyzeSync(): void {
|
private analyzeSync(): void {
|
||||||
|
@ -482,7 +486,7 @@ export class NgCompiler {
|
||||||
// Execute the typeCheck phase of each decorator in the program.
|
// Execute the typeCheck phase of each decorator in the program.
|
||||||
const prepSpan = this.perfRecorder.start('typeCheckPrep');
|
const prepSpan = this.perfRecorder.start('typeCheckPrep');
|
||||||
const ctx = new TypeCheckContext(
|
const ctx = new TypeCheckContext(
|
||||||
typeCheckingConfig, compilation.refEmitter !, compilation.reflector, host.typeCheckFile);
|
typeCheckingConfig, compilation.refEmitter!, compilation.reflector, host.typeCheckFile);
|
||||||
compilation.traitCompiler.typeCheck(ctx);
|
compilation.traitCompiler.typeCheck(ctx);
|
||||||
this.perfRecorder.stop(prepSpan);
|
this.perfRecorder.stop(prepSpan);
|
||||||
|
|
||||||
|
@ -505,7 +509,7 @@ export class NgCompiler {
|
||||||
const recordSpan = this.perfRecorder.start('recordDependencies');
|
const recordSpan = this.perfRecorder.start('recordDependencies');
|
||||||
const depGraph = this.incrementalDriver.depGraph;
|
const depGraph = this.incrementalDriver.depGraph;
|
||||||
|
|
||||||
for (const scope of this.compilation !.scopeRegistry !.getCompilationScopes()) {
|
for (const scope of this.compilation!.scopeRegistry!.getCompilationScopes()) {
|
||||||
const file = scope.declaration.getSourceFile();
|
const file = scope.declaration.getSourceFile();
|
||||||
const ngModuleFile = scope.ngModule.getSourceFile();
|
const ngModuleFile = scope.ngModule.getSourceFile();
|
||||||
|
|
||||||
|
@ -517,7 +521,7 @@ export class NgCompiler {
|
||||||
depGraph.addDependency(file, ngModuleFile);
|
depGraph.addDependency(file, ngModuleFile);
|
||||||
|
|
||||||
const meta =
|
const meta =
|
||||||
this.compilation !.metaReader.getDirectiveMetadata(new Reference(scope.declaration));
|
this.compilation!.metaReader.getDirectiveMetadata(new Reference(scope.declaration));
|
||||||
if (meta !== null && meta.isComponent) {
|
if (meta !== null && meta.isComponent) {
|
||||||
// If a component's template changes, it might have affected the import graph, and thus the
|
// If a component's template changes, it might have affected the import graph, and thus the
|
||||||
// remote scoping feature which is activated in the event of potential import cycles. Thus,
|
// remote scoping feature which is activated in the event of potential import cycles. Thus,
|
||||||
|
@ -543,12 +547,11 @@ export class NgCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private scanForMwp(sf: ts.SourceFile): void {
|
private scanForMwp(sf: ts.SourceFile): void {
|
||||||
this.compilation !.mwpScanner.scan(sf, {
|
this.compilation!.mwpScanner.scan(sf, {
|
||||||
addTypeReplacement: (node: ts.Declaration, type: Type): void => {
|
addTypeReplacement: (node: ts.Declaration, type: Type): void => {
|
||||||
// Only obtain the return type transform for the source file once there's a type to replace,
|
// Only obtain the return type transform for the source file once there's a type to replace,
|
||||||
// so that no transform is allocated when there's nothing to do.
|
// so that no transform is allocated when there's nothing to do.
|
||||||
this.compilation !.dtsTransforms !.getReturnTypeTransform(sf).addTypeReplacement(
|
this.compilation!.dtsTransforms!.getReturnTypeTransform(sf).addTypeReplacement(node, type);
|
||||||
node, type);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -686,9 +689,18 @@ export class NgCompiler {
|
||||||
this.options.compileNonExportedClasses !== false, dtsTransforms);
|
this.options.compileNonExportedClasses !== false, dtsTransforms);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isCore, traitCompiler, reflector, scopeRegistry,
|
isCore,
|
||||||
dtsTransforms, exportReferenceGraph, routeAnalyzer, mwpScanner,
|
traitCompiler,
|
||||||
metaReader, defaultImportTracker, aliasingHost, refEmitter,
|
reflector,
|
||||||
|
scopeRegistry,
|
||||||
|
dtsTransforms,
|
||||||
|
exportReferenceGraph,
|
||||||
|
routeAnalyzer,
|
||||||
|
mwpScanner,
|
||||||
|
metaReader,
|
||||||
|
defaultImportTracker,
|
||||||
|
aliasingHost,
|
||||||
|
refEmitter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
||||||
import {FlatIndexGenerator, findFlatIndexEntryPoint} from '../../entry_point';
|
import {findFlatIndexEntryPoint, FlatIndexGenerator} from '../../entry_point';
|
||||||
import {AbsoluteFsPath, resolve} from '../../file_system';
|
import {AbsoluteFsPath, resolve} from '../../file_system';
|
||||||
import {FactoryGenerator, FactoryTracker, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator} from '../../shims';
|
import {FactoryGenerator, FactoryTracker, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator} from '../../shims';
|
||||||
import {typeCheckFilePath} from '../../typecheck';
|
import {typeCheckFilePath} from '../../typecheck';
|
||||||
|
@ -88,8 +88,7 @@ export class DelegatingCompilerHost implements
|
||||||
* `ExtendedTsCompilerHost` methods whenever present.
|
* `ExtendedTsCompilerHost` methods whenever present.
|
||||||
*/
|
*/
|
||||||
export class NgCompilerHost extends DelegatingCompilerHost implements
|
export class NgCompilerHost extends DelegatingCompilerHost implements
|
||||||
RequiredCompilerHostDelegations,
|
RequiredCompilerHostDelegations, ExtendedTsCompilerHost {
|
||||||
ExtendedTsCompilerHost {
|
|
||||||
readonly factoryTracker: FactoryTracker|null = null;
|
readonly factoryTracker: FactoryTracker|null = null;
|
||||||
readonly entryPoint: AbsoluteFsPath|null = null;
|
readonly entryPoint: AbsoluteFsPath|null = null;
|
||||||
readonly diagnostics: ts.Diagnostic[];
|
readonly diagnostics: ts.Diagnostic[];
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {FileSystem, NgtscCompilerHost, absoluteFrom as _, getFileSystem, getSourceFileOrError, setFileSystem} from '../../file_system';
|
import {absoluteFrom as _, FileSystem, getFileSystem, getSourceFileOrError, NgtscCompilerHost, setFileSystem} from '../../file_system';
|
||||||
import {runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem} from '../../file_system/testing';
|
||||||
import {NgCompilerOptions} from '../api';
|
import {NgCompilerOptions} from '../api';
|
||||||
import {NgCompiler} from '../src/compiler';
|
import {NgCompiler} from '../src/compiler';
|
||||||
|
@ -16,7 +16,6 @@ import {NgCompilerHost} from '../src/host';
|
||||||
|
|
||||||
|
|
||||||
runInEachFileSystem(() => {
|
runInEachFileSystem(() => {
|
||||||
|
|
||||||
describe('NgCompiler', () => {
|
describe('NgCompiler', () => {
|
||||||
let fs: FileSystem;
|
let fs: FileSystem;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class ImportGraph {
|
||||||
if (!this.map.has(sf)) {
|
if (!this.map.has(sf)) {
|
||||||
this.map.set(sf, this.scanImports(sf));
|
this.map.set(sf, this.scanImports(sf));
|
||||||
}
|
}
|
||||||
return this.map.get(sf) !;
|
return this.map.get(sf)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +47,9 @@ export class ImportGraph {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results.add(sf);
|
results.add(sf);
|
||||||
this.importsOf(sf).forEach(imported => { this.transitiveImportsOfHelper(imported, results); });
|
this.importsOf(sf).forEach(imported => {
|
||||||
|
this.transitiveImportsOfHelper(imported, results);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,7 +33,8 @@ export function makeDiagnostic(code: ErrorCode, node: ts.Node, messageText: stri
|
||||||
code: Number('-99' + code.valueOf()),
|
code: Number('-99' + code.valueOf()),
|
||||||
file: ts.getOriginalNode(node).getSourceFile(),
|
file: ts.getOriginalNode(node).getSourceFile(),
|
||||||
start: node.getStart(undefined, false),
|
start: node.getStart(undefined, false),
|
||||||
length: node.getWidth(), messageText,
|
length: node.getWidth(),
|
||||||
|
messageText,
|
||||||
};
|
};
|
||||||
if (relatedInfo !== undefined) {
|
if (relatedInfo !== undefined) {
|
||||||
diag.relatedInformation = relatedInfo.map(info => {
|
diag.relatedInformation = relatedInfo.map(info => {
|
||||||
|
|
|
@ -24,7 +24,9 @@ export class FlatIndexGenerator implements ShimGenerator {
|
||||||
join(dirname(entryPoint), relativeFlatIndexPath).replace(/\.js$/, '') + '.ts';
|
join(dirname(entryPoint), relativeFlatIndexPath).replace(/\.js$/, '') + '.ts';
|
||||||
}
|
}
|
||||||
|
|
||||||
recognize(fileName: string): boolean { return fileName === this.flatIndexPath; }
|
recognize(fileName: string): boolean {
|
||||||
|
return fileName === this.flatIndexPath;
|
||||||
|
}
|
||||||
|
|
||||||
generate(): ts.SourceFile {
|
generate(): ts.SourceFile {
|
||||||
const relativeEntryPoint = relativePathBetween(this.flatIndexPath, this.entryPoint);
|
const relativeEntryPoint = relativePathBetween(this.flatIndexPath, this.entryPoint);
|
||||||
|
|
|
@ -95,9 +95,11 @@ export function checkForPrivateExports(
|
||||||
const diagnostic: ts.Diagnostic = {
|
const diagnostic: ts.Diagnostic = {
|
||||||
category: ts.DiagnosticCategory.Error,
|
category: ts.DiagnosticCategory.Error,
|
||||||
code: ngErrorCode(ErrorCode.SYMBOL_NOT_EXPORTED),
|
code: ngErrorCode(ErrorCode.SYMBOL_NOT_EXPORTED),
|
||||||
file: transitiveReference.getSourceFile(), ...getPosOfDeclaration(transitiveReference),
|
file: transitiveReference.getSourceFile(),
|
||||||
messageText:
|
...getPosOfDeclaration(transitiveReference),
|
||||||
`Unsupported private ${descriptor} ${name}. This ${descriptor} is visible to consumers via ${visibleVia}, but is not exported from the top-level library entrypoint.`,
|
messageText: `Unsupported private ${descriptor} ${name}. This ${
|
||||||
|
descriptor} is visible to consumers via ${
|
||||||
|
visibleVia}, but is not exported from the top-level library entrypoint.`,
|
||||||
};
|
};
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
||||||
if (!this.references.has(from)) {
|
if (!this.references.has(from)) {
|
||||||
this.references.set(from, new Set());
|
this.references.set(from, new Set());
|
||||||
}
|
}
|
||||||
this.references.get(from) !.add(to);
|
this.references.get(from)!.add(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
transitiveReferencesOf(target: T): Set<T> {
|
transitiveReferencesOf(target: T): Set<T> {
|
||||||
|
@ -47,7 +47,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
||||||
// Look through the outgoing edges of `source`.
|
// Look through the outgoing edges of `source`.
|
||||||
// TODO(alxhub): use proper iteration when the legacy build is removed. (#27762)
|
// TODO(alxhub): use proper iteration when the legacy build is removed. (#27762)
|
||||||
let candidatePath: T[]|null = null;
|
let candidatePath: T[]|null = null;
|
||||||
this.references.get(source) !.forEach(edge => {
|
this.references.get(source)!.forEach(edge => {
|
||||||
// Early exit if a path has already been found.
|
// Early exit if a path has already been found.
|
||||||
if (candidatePath !== null) {
|
if (candidatePath !== null) {
|
||||||
return;
|
return;
|
||||||
|
@ -67,7 +67,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
||||||
private collectTransitiveReferences(set: Set<T>, decl: T): void {
|
private collectTransitiveReferences(set: Set<T>, decl: T): void {
|
||||||
if (this.references.has(decl)) {
|
if (this.references.has(decl)) {
|
||||||
// TODO(alxhub): use proper iteration when the legacy build is removed. (#27762)
|
// TODO(alxhub): use proper iteration when the legacy build is removed. (#27762)
|
||||||
this.references.get(decl) !.forEach(ref => {
|
this.references.get(decl)!.forEach(ref => {
|
||||||
if (!set.has(ref)) {
|
if (!set.has(ref)) {
|
||||||
set.add(ref);
|
set.add(ref);
|
||||||
this.collectTransitiveReferences(set, ref);
|
this.collectTransitiveReferences(set, ref);
|
||||||
|
|
|
@ -16,9 +16,9 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => _ = absoluteFrom);
|
beforeEach(() => _ = absoluteFrom);
|
||||||
|
|
||||||
describe('findFlatIndexEntryPoint', () => {
|
describe('findFlatIndexEntryPoint', () => {
|
||||||
|
it('should use the only source file if only a single one is specified', () => {
|
||||||
it('should use the only source file if only a single one is specified',
|
expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts'));
|
||||||
() => { expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts')); });
|
});
|
||||||
|
|
||||||
it('should use the shortest source file ending with "index.ts" for multiple files', () => {
|
it('should use the shortest source file ending with "index.ts" for multiple files', () => {
|
||||||
expect(findFlatIndexEntryPoint([
|
expect(findFlatIndexEntryPoint([
|
||||||
|
|
|
@ -12,8 +12,9 @@ import {ReferenceGraph} from '../src/reference_graph';
|
||||||
describe('entry_point reference graph', () => {
|
describe('entry_point reference graph', () => {
|
||||||
let graph: ReferenceGraph<string>;
|
let graph: ReferenceGraph<string>;
|
||||||
|
|
||||||
const refs =
|
const refs = (target: string) => {
|
||||||
(target: string) => { return Array.from(graph.transitiveReferencesOf(target)).sort(); };
|
return Array.from(graph.transitiveReferencesOf(target)).sort();
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
graph = new ReferenceGraph();
|
graph = new ReferenceGraph();
|
||||||
|
@ -45,6 +46,7 @@ describe('entry_point reference graph', () => {
|
||||||
expect(graph.pathFrom('beta', 'alpha')).toEqual(['beta', 'delta', 'alpha']);
|
expect(graph.pathFrom('beta', 'alpha')).toEqual(['beta', 'delta', 'alpha']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not report a path that doesn\'t exist',
|
it('should not report a path that doesn\'t exist', () => {
|
||||||
() => { expect(graph.pathFrom('gamma', 'beta')).toBeNull(); });
|
expect(graph.pathFrom('gamma', 'beta')).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class CachedFileSystem implements FileSystem {
|
||||||
if (!this.existsCache.has(path)) {
|
if (!this.existsCache.has(path)) {
|
||||||
this.existsCache.set(path, this.delegate.exists(path));
|
this.existsCache.set(path, this.delegate.exists(path));
|
||||||
}
|
}
|
||||||
return this.existsCache.get(path) !;
|
return this.existsCache.get(path)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateCaches(path: AbsoluteFsPath) {
|
invalidateCaches(path: AbsoluteFsPath) {
|
||||||
|
@ -131,15 +131,33 @@ export class CachedFileSystem implements FileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following methods simply call through to the delegate.
|
// The following methods simply call through to the delegate.
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[] { return this.delegate.readdir(path); }
|
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||||
pwd(): AbsoluteFsPath { return this.delegate.pwd(); }
|
return this.delegate.readdir(path);
|
||||||
chdir(path: AbsoluteFsPath): void { this.delegate.chdir(path); }
|
}
|
||||||
extname(path: AbsoluteFsPath|PathSegment): string { return this.delegate.extname(path); }
|
pwd(): AbsoluteFsPath {
|
||||||
isCaseSensitive(): boolean { return this.delegate.isCaseSensitive(); }
|
return this.delegate.pwd();
|
||||||
isRoot(path: AbsoluteFsPath): boolean { return this.delegate.isRoot(path); }
|
}
|
||||||
isRooted(path: string): boolean { return this.delegate.isRooted(path); }
|
chdir(path: AbsoluteFsPath): void {
|
||||||
resolve(...paths: string[]): AbsoluteFsPath { return this.delegate.resolve(...paths); }
|
this.delegate.chdir(path);
|
||||||
dirname<T extends PathString>(file: T): T { return this.delegate.dirname(file); }
|
}
|
||||||
|
extname(path: AbsoluteFsPath|PathSegment): string {
|
||||||
|
return this.delegate.extname(path);
|
||||||
|
}
|
||||||
|
isCaseSensitive(): boolean {
|
||||||
|
return this.delegate.isCaseSensitive();
|
||||||
|
}
|
||||||
|
isRoot(path: AbsoluteFsPath): boolean {
|
||||||
|
return this.delegate.isRoot(path);
|
||||||
|
}
|
||||||
|
isRooted(path: string): boolean {
|
||||||
|
return this.delegate.isRooted(path);
|
||||||
|
}
|
||||||
|
resolve(...paths: string[]): AbsoluteFsPath {
|
||||||
|
return this.delegate.resolve(...paths);
|
||||||
|
}
|
||||||
|
dirname<T extends PathString>(file: T): T {
|
||||||
|
return this.delegate.dirname(file);
|
||||||
|
}
|
||||||
join<T extends PathString>(basePath: T, ...paths: string[]): T {
|
join<T extends PathString>(basePath: T, ...paths: string[]): T {
|
||||||
return this.delegate.join(basePath, ...paths);
|
return this.delegate.join(basePath, ...paths);
|
||||||
}
|
}
|
||||||
|
@ -149,7 +167,13 @@ export class CachedFileSystem implements FileSystem {
|
||||||
basename(filePath: string, extension?: string|undefined): PathSegment {
|
basename(filePath: string, extension?: string|undefined): PathSegment {
|
||||||
return this.delegate.basename(filePath, extension);
|
return this.delegate.basename(filePath, extension);
|
||||||
}
|
}
|
||||||
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { return this.delegate.realpath(filePath); }
|
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath {
|
||||||
getDefaultLibLocation(): AbsoluteFsPath { return this.delegate.getDefaultLibLocation(); }
|
return this.delegate.realpath(filePath);
|
||||||
normalize<T extends PathString>(path: T): T { return this.delegate.normalize(path); }
|
}
|
||||||
|
getDefaultLibLocation(): AbsoluteFsPath {
|
||||||
|
return this.delegate.getDefaultLibLocation();
|
||||||
|
}
|
||||||
|
normalize<T extends PathString>(path: T): T {
|
||||||
|
return this.delegate.normalize(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ export class NgtscCompilerHost implements ts.CompilerHost {
|
||||||
return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
|
return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultLibLocation(): string { return this.fs.getDefaultLibLocation(); }
|
getDefaultLibLocation(): string {
|
||||||
|
return this.fs.getDefaultLibLocation();
|
||||||
|
}
|
||||||
|
|
||||||
writeFile(
|
writeFile(
|
||||||
fileName: string, data: string, writeByteOrderMark: boolean,
|
fileName: string, data: string, writeByteOrderMark: boolean,
|
||||||
|
@ -37,13 +39,17 @@ export class NgtscCompilerHost implements ts.CompilerHost {
|
||||||
this.fs.writeFile(path, data);
|
this.fs.writeFile(path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentDirectory(): string { return this.fs.pwd(); }
|
getCurrentDirectory(): string {
|
||||||
|
return this.fs.pwd();
|
||||||
|
}
|
||||||
|
|
||||||
getCanonicalFileName(fileName: string): string {
|
getCanonicalFileName(fileName: string): string {
|
||||||
return this.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
return this.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
useCaseSensitiveFileNames(): boolean { return this.fs.isCaseSensitive(); }
|
useCaseSensitiveFileNames(): boolean {
|
||||||
|
return this.fs.isCaseSensitive();
|
||||||
|
}
|
||||||
|
|
||||||
getNewLine(): string {
|
getNewLine(): string {
|
||||||
switch (this.options.newLine) {
|
switch (this.options.newLine) {
|
||||||
|
|
|
@ -16,32 +16,84 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
||||||
* the `FileSystem` under the hood.
|
* the `FileSystem` under the hood.
|
||||||
*/
|
*/
|
||||||
export class InvalidFileSystem implements FileSystem {
|
export class InvalidFileSystem implements FileSystem {
|
||||||
exists(path: AbsoluteFsPath): boolean { throw makeError(); }
|
exists(path: AbsoluteFsPath): boolean {
|
||||||
readFile(path: AbsoluteFsPath): string { throw makeError(); }
|
throw makeError();
|
||||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { throw makeError(); }
|
}
|
||||||
removeFile(path: AbsoluteFsPath): void { throw makeError(); }
|
readFile(path: AbsoluteFsPath): string {
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); }
|
throw makeError();
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); }
|
}
|
||||||
lstat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void {
|
||||||
stat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
throw makeError();
|
||||||
pwd(): AbsoluteFsPath { throw makeError(); }
|
}
|
||||||
chdir(path: AbsoluteFsPath): void { throw makeError(); }
|
removeFile(path: AbsoluteFsPath): void {
|
||||||
extname(path: AbsoluteFsPath|PathSegment): string { throw makeError(); }
|
throw makeError();
|
||||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
|
}
|
||||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void {
|
||||||
ensureDir(path: AbsoluteFsPath): void { throw makeError(); }
|
throw makeError();
|
||||||
removeDeep(path: AbsoluteFsPath): void { throw makeError(); }
|
}
|
||||||
isCaseSensitive(): boolean { throw makeError(); }
|
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||||
resolve(...paths: string[]): AbsoluteFsPath { throw makeError(); }
|
throw makeError();
|
||||||
dirname<T extends PathString>(file: T): T { throw makeError(); }
|
}
|
||||||
join<T extends PathString>(basePath: T, ...paths: string[]): T { throw makeError(); }
|
lstat(path: AbsoluteFsPath): FileStats {
|
||||||
isRoot(path: AbsoluteFsPath): boolean { throw makeError(); }
|
throw makeError();
|
||||||
isRooted(path: string): boolean { throw makeError(); }
|
}
|
||||||
relative<T extends PathString>(from: T, to: T): PathSegment { throw makeError(); }
|
stat(path: AbsoluteFsPath): FileStats {
|
||||||
basename(filePath: string, extension?: string): PathSegment { throw makeError(); }
|
throw makeError();
|
||||||
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { throw makeError(); }
|
}
|
||||||
getDefaultLibLocation(): AbsoluteFsPath { throw makeError(); }
|
pwd(): AbsoluteFsPath {
|
||||||
normalize<T extends PathString>(path: T): T { throw makeError(); }
|
throw makeError();
|
||||||
|
}
|
||||||
|
chdir(path: AbsoluteFsPath): void {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
extname(path: AbsoluteFsPath|PathSegment): string {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
ensureDir(path: AbsoluteFsPath): void {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
removeDeep(path: AbsoluteFsPath): void {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
isCaseSensitive(): boolean {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
resolve(...paths: string[]): AbsoluteFsPath {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
dirname<T extends PathString>(file: T): T {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
join<T extends PathString>(basePath: T, ...paths: string[]): T {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
isRoot(path: AbsoluteFsPath): boolean {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
isRooted(path: string): boolean {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
relative<T extends PathString>(from: T, to: T): PathSegment {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
basename(filePath: string, extension?: string): PathSegment {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
getDefaultLibLocation(): AbsoluteFsPath {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
|
normalize<T extends PathString>(path: T): T {
|
||||||
|
throw makeError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeError() {
|
function makeError() {
|
||||||
|
|
|
@ -91,7 +91,7 @@ export class LogicalFileSystem {
|
||||||
}
|
}
|
||||||
this.cache.set(physicalFile, logicalFile);
|
this.cache.set(physicalFile, logicalFile);
|
||||||
}
|
}
|
||||||
return this.cache.get(physicalFile) !;
|
return this.cache.get(physicalFile)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createLogicalProjectPath(file: AbsoluteFsPath, rootDir: AbsoluteFsPath):
|
private createLogicalProjectPath(file: AbsoluteFsPath, rootDir: AbsoluteFsPath):
|
||||||
|
|
|
@ -17,20 +17,42 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
||||||
*/
|
*/
|
||||||
export class NodeJSFileSystem implements FileSystem {
|
export class NodeJSFileSystem implements FileSystem {
|
||||||
private _caseSensitive: boolean|undefined = undefined;
|
private _caseSensitive: boolean|undefined = undefined;
|
||||||
exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); }
|
exists(path: AbsoluteFsPath): boolean {
|
||||||
readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); }
|
return fs.existsSync(path);
|
||||||
|
}
|
||||||
|
readFile(path: AbsoluteFsPath): string {
|
||||||
|
return fs.readFileSync(path, 'utf8');
|
||||||
|
}
|
||||||
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
|
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
|
||||||
fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined);
|
fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined);
|
||||||
}
|
}
|
||||||
removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); }
|
removeFile(path: AbsoluteFsPath): void {
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); }
|
fs.unlinkSync(path);
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; }
|
}
|
||||||
lstat(path: AbsoluteFsPath): FileStats { return fs.lstatSync(path); }
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void {
|
||||||
stat(path: AbsoluteFsPath): FileStats { return fs.statSync(path); }
|
fs.symlinkSync(target, path);
|
||||||
pwd(): AbsoluteFsPath { return this.normalize(process.cwd()) as AbsoluteFsPath; }
|
}
|
||||||
chdir(dir: AbsoluteFsPath): void { process.chdir(dir); }
|
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.copyFileSync(from, to); }
|
return fs.readdirSync(path) as PathSegment[];
|
||||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.renameSync(from, to); }
|
}
|
||||||
|
lstat(path: AbsoluteFsPath): FileStats {
|
||||||
|
return fs.lstatSync(path);
|
||||||
|
}
|
||||||
|
stat(path: AbsoluteFsPath): FileStats {
|
||||||
|
return fs.statSync(path);
|
||||||
|
}
|
||||||
|
pwd(): AbsoluteFsPath {
|
||||||
|
return this.normalize(process.cwd()) as AbsoluteFsPath;
|
||||||
|
}
|
||||||
|
chdir(dir: AbsoluteFsPath): void {
|
||||||
|
process.chdir(dir);
|
||||||
|
}
|
||||||
|
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void {
|
||||||
|
fs.copyFileSync(from, to);
|
||||||
|
}
|
||||||
|
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void {
|
||||||
|
fs.renameSync(from, to);
|
||||||
|
}
|
||||||
ensureDir(path: AbsoluteFsPath): void {
|
ensureDir(path: AbsoluteFsPath): void {
|
||||||
const parents: AbsoluteFsPath[] = [];
|
const parents: AbsoluteFsPath[] = [];
|
||||||
while (!this.isRoot(path) && !this.exists(path)) {
|
while (!this.isRoot(path) && !this.exists(path)) {
|
||||||
|
@ -38,10 +60,12 @@ export class NodeJSFileSystem implements FileSystem {
|
||||||
path = this.dirname(path);
|
path = this.dirname(path);
|
||||||
}
|
}
|
||||||
while (parents.length) {
|
while (parents.length) {
|
||||||
this.safeMkdir(parents.pop() !);
|
this.safeMkdir(parents.pop()!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeDeep(path: AbsoluteFsPath): void { fsExtra.removeSync(path); }
|
removeDeep(path: AbsoluteFsPath): void {
|
||||||
|
fsExtra.removeSync(path);
|
||||||
|
}
|
||||||
isCaseSensitive(): boolean {
|
isCaseSensitive(): boolean {
|
||||||
if (this._caseSensitive === undefined) {
|
if (this._caseSensitive === undefined) {
|
||||||
this._caseSensitive = this.exists(togglePathCase(__filename));
|
this._caseSensitive = this.exists(togglePathCase(__filename));
|
||||||
|
@ -52,20 +76,30 @@ export class NodeJSFileSystem implements FileSystem {
|
||||||
return this.normalize(p.resolve(...paths)) as AbsoluteFsPath;
|
return this.normalize(p.resolve(...paths)) as AbsoluteFsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirname<T extends string>(file: T): T { return this.normalize(p.dirname(file)) as T; }
|
dirname<T extends string>(file: T): T {
|
||||||
|
return this.normalize(p.dirname(file)) as T;
|
||||||
|
}
|
||||||
join<T extends string>(basePath: T, ...paths: string[]): T {
|
join<T extends string>(basePath: T, ...paths: string[]): T {
|
||||||
return this.normalize(p.join(basePath, ...paths)) as T;
|
return this.normalize(p.join(basePath, ...paths)) as T;
|
||||||
}
|
}
|
||||||
isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === this.normalize(path); }
|
isRoot(path: AbsoluteFsPath): boolean {
|
||||||
isRooted(path: string): boolean { return p.isAbsolute(path); }
|
return this.dirname(path) === this.normalize(path);
|
||||||
|
}
|
||||||
|
isRooted(path: string): boolean {
|
||||||
|
return p.isAbsolute(path);
|
||||||
|
}
|
||||||
relative<T extends PathString>(from: T, to: T): PathSegment {
|
relative<T extends PathString>(from: T, to: T): PathSegment {
|
||||||
return relativeFrom(this.normalize(p.relative(from, to)));
|
return relativeFrom(this.normalize(p.relative(from, to)));
|
||||||
}
|
}
|
||||||
basename(filePath: string, extension?: string): PathSegment {
|
basename(filePath: string, extension?: string): PathSegment {
|
||||||
return p.basename(filePath, extension) as PathSegment;
|
return p.basename(filePath, extension) as PathSegment;
|
||||||
}
|
}
|
||||||
extname(path: AbsoluteFsPath|PathSegment): string { return p.extname(path); }
|
extname(path: AbsoluteFsPath|PathSegment): string {
|
||||||
realpath(path: AbsoluteFsPath): AbsoluteFsPath { return this.resolve(fs.realpathSync(path)); }
|
return p.extname(path);
|
||||||
|
}
|
||||||
|
realpath(path: AbsoluteFsPath): AbsoluteFsPath {
|
||||||
|
return this.resolve(fs.realpathSync(path));
|
||||||
|
}
|
||||||
getDefaultLibLocation(): AbsoluteFsPath {
|
getDefaultLibLocation(): AbsoluteFsPath {
|
||||||
return this.resolve(require.resolve('typescript'), '..');
|
return this.resolve(require.resolve('typescript'), '..');
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* A `string` is not assignable to a `BrandedPath`, but a `BrandedPath` is assignable to a `string`.
|
* A `string` is not assignable to a `BrandedPath`, but a `BrandedPath` is assignable to a `string`.
|
||||||
* Two `BrandedPath`s with different brands are not mutually assignable.
|
* Two `BrandedPath`s with different brands are not mutually assignable.
|
||||||
*/
|
*/
|
||||||
export type BrandedPath<B extends string> = string & {
|
export type BrandedPath<B extends string> = string&{
|
||||||
_brand: B;
|
_brand: B;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ export interface FileSystem {
|
||||||
normalize<T extends PathString>(path: T): T;
|
normalize<T extends PathString>(path: T): T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PathString = string | AbsoluteFsPath | PathSegment;
|
export type PathString = string|AbsoluteFsPath|PathSegment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about an object in the FileSystem.
|
* Information about an object in the FileSystem.
|
||||||
|
|
|
@ -28,8 +28,8 @@ export function stripExtension(path: string): string {
|
||||||
export function getSourceFileOrError(program: ts.Program, fileName: AbsoluteFsPath): ts.SourceFile {
|
export function getSourceFileOrError(program: ts.Program, fileName: AbsoluteFsPath): ts.SourceFile {
|
||||||
const sf = program.getSourceFile(fileName);
|
const sf = program.getSourceFile(fileName);
|
||||||
if (sf === undefined) {
|
if (sf === undefined) {
|
||||||
throw new Error(
|
throw new Error(`Program does not contain "${fileName}" - available files are ${
|
||||||
`Program does not contain "${fileName}" - available files are ${program.getSourceFiles().map(sf => sf.fileName).join(', ')}`);
|
program.getSourceFiles().map(sf => sf.fileName).join(', ')}`);
|
||||||
}
|
}
|
||||||
return sf;
|
return sf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,37 +11,49 @@ import {absoluteFrom, relativeFrom, setFileSystem} from '../src/helpers';
|
||||||
import {NodeJSFileSystem} from '../src/node_js_file_system';
|
import {NodeJSFileSystem} from '../src/node_js_file_system';
|
||||||
|
|
||||||
describe('path types', () => {
|
describe('path types', () => {
|
||||||
beforeEach(() => { setFileSystem(new NodeJSFileSystem()); });
|
beforeEach(() => {
|
||||||
|
setFileSystem(new NodeJSFileSystem());
|
||||||
|
});
|
||||||
|
|
||||||
describe('absoluteFrom', () => {
|
describe('absoluteFrom', () => {
|
||||||
it('should not throw when creating one from an absolute path',
|
it('should not throw when creating one from an absolute path', () => {
|
||||||
() => { expect(() => absoluteFrom('/test.txt')).not.toThrow(); });
|
expect(() => absoluteFrom('/test.txt')).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
it('should not throw when creating one from a windows absolute path',
|
it('should not throw when creating one from a windows absolute path', () => {
|
||||||
() => { expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt'); });
|
expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt');
|
||||||
|
});
|
||||||
it('should not throw when creating one from a windows absolute path with POSIX separators',
|
it('should not throw when creating one from a windows absolute path with POSIX separators',
|
||||||
() => { expect(absoluteFrom('C:/test.txt')).toEqual('C:/test.txt'); });
|
() => {
|
||||||
it('should support windows drive letters',
|
expect(absoluteFrom('C:/test.txt')).toEqual('C:/test.txt');
|
||||||
() => { expect(absoluteFrom('D:\\foo\\test.txt')).toEqual('D:/foo/test.txt'); });
|
});
|
||||||
it('should convert Windows path separators to POSIX separators',
|
it('should support windows drive letters', () => {
|
||||||
() => { expect(absoluteFrom('C:\\foo\\test.txt')).toEqual('C:/foo/test.txt'); });
|
expect(absoluteFrom('D:\\foo\\test.txt')).toEqual('D:/foo/test.txt');
|
||||||
|
});
|
||||||
|
it('should convert Windows path separators to POSIX separators', () => {
|
||||||
|
expect(absoluteFrom('C:\\foo\\test.txt')).toEqual('C:/foo/test.txt');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should throw when creating one from a non-absolute path',
|
it('should throw when creating one from a non-absolute path', () => {
|
||||||
() => { expect(() => absoluteFrom('test.txt')).toThrow(); });
|
expect(() => absoluteFrom('test.txt')).toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('relativeFrom', () => {
|
describe('relativeFrom', () => {
|
||||||
it('should not throw when creating one from a relative path',
|
it('should not throw when creating one from a relative path', () => {
|
||||||
() => { expect(() => relativeFrom('a/b/c.txt')).not.toThrow(); });
|
expect(() => relativeFrom('a/b/c.txt')).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw when creating one from an absolute path',
|
it('should throw when creating one from an absolute path', () => {
|
||||||
() => { expect(() => relativeFrom('/a/b/c.txt')).toThrow(); });
|
expect(() => relativeFrom('/a/b/c.txt')).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
it('should throw when creating one from a Windows absolute path',
|
it('should throw when creating one from a Windows absolute path', () => {
|
||||||
() => { expect(() => relativeFrom('C:/a/b/c.txt')).toThrow(); });
|
expect(() => relativeFrom('C:/a/b/c.txt')).toThrow();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,4 +10,4 @@ export {Folder, MockFileSystem} from './src/mock_file_system';
|
||||||
export {MockFileSystemNative} from './src/mock_file_system_native';
|
export {MockFileSystemNative} from './src/mock_file_system_native';
|
||||||
export {MockFileSystemPosix} from './src/mock_file_system_posix';
|
export {MockFileSystemPosix} from './src/mock_file_system_posix';
|
||||||
export {MockFileSystemWindows} from './src/mock_file_system_windows';
|
export {MockFileSystemWindows} from './src/mock_file_system_windows';
|
||||||
export {TestFile, initMockFileSystem, runInEachFileSystem} from './src/test_helper';
|
export {initMockFileSystem, runInEachFileSystem, TestFile} from './src/test_helper';
|
||||||
|
|
|
@ -21,9 +21,13 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
this._cwd = this.normalize(cwd);
|
this._cwd = this.normalize(cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCaseSensitive() { return this._isCaseSensitive; }
|
isCaseSensitive() {
|
||||||
|
return this._isCaseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
exists(path: AbsoluteFsPath): boolean { return this.findFromPath(path).entity !== null; }
|
exists(path: AbsoluteFsPath): boolean {
|
||||||
|
return this.findFromPath(path).entity !== null;
|
||||||
|
}
|
||||||
|
|
||||||
readFile(path: AbsoluteFsPath): string {
|
readFile(path: AbsoluteFsPath): string {
|
||||||
const {entity} = this.findFromPath(path);
|
const {entity} = this.findFromPath(path);
|
||||||
|
@ -142,7 +146,9 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
delete entity[basename];
|
delete entity[basename];
|
||||||
}
|
}
|
||||||
|
|
||||||
isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === path; }
|
isRoot(path: AbsoluteFsPath): boolean {
|
||||||
|
return this.dirname(path) === path;
|
||||||
|
}
|
||||||
|
|
||||||
extname(path: AbsoluteFsPath|PathSegment): string {
|
extname(path: AbsoluteFsPath|PathSegment): string {
|
||||||
const match = /.+(\.[^.]*)$/.exec(path);
|
const match = /.+(\.[^.]*)$/.exec(path);
|
||||||
|
@ -159,9 +165,13 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pwd(): AbsoluteFsPath { return this._cwd; }
|
pwd(): AbsoluteFsPath {
|
||||||
|
return this._cwd;
|
||||||
|
}
|
||||||
|
|
||||||
chdir(path: AbsoluteFsPath): void { this._cwd = this.normalize(path); }
|
chdir(path: AbsoluteFsPath): void {
|
||||||
|
this._cwd = this.normalize(path);
|
||||||
|
}
|
||||||
|
|
||||||
getDefaultLibLocation(): AbsoluteFsPath {
|
getDefaultLibLocation(): AbsoluteFsPath {
|
||||||
// Mimic the node module resolution algorithm and start in the current directory, then look
|
// Mimic the node module resolution algorithm and start in the current directory, then look
|
||||||
|
@ -201,8 +211,12 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
abstract normalize<T extends PathString>(path: T): T;
|
abstract normalize<T extends PathString>(path: T): T;
|
||||||
protected abstract splitPath<T extends PathString>(path: T): string[];
|
protected abstract splitPath<T extends PathString>(path: T): string[];
|
||||||
|
|
||||||
dump(): Folder { return cloneFolder(this._fileTree); }
|
dump(): Folder {
|
||||||
init(folder: Folder): void { this._fileTree = cloneFolder(folder); }
|
return cloneFolder(this._fileTree);
|
||||||
|
}
|
||||||
|
init(folder: Folder): void {
|
||||||
|
this._fileTree = cloneFolder(folder);
|
||||||
|
}
|
||||||
|
|
||||||
protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult {
|
protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult {
|
||||||
const followSymLinks = !!options && options.followSymLinks;
|
const followSymLinks = !!options && options.followSymLinks;
|
||||||
|
@ -215,7 +229,7 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
segments[0] = '';
|
segments[0] = '';
|
||||||
let current: Entity|null = this._fileTree;
|
let current: Entity|null = this._fileTree;
|
||||||
while (segments.length) {
|
while (segments.length) {
|
||||||
current = current[segments.shift() !];
|
current = current[segments.shift()!];
|
||||||
if (current === undefined) {
|
if (current === undefined) {
|
||||||
return {path, entity: null};
|
return {path, entity: null};
|
||||||
}
|
}
|
||||||
|
@ -239,7 +253,7 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
|
|
||||||
protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
|
protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
|
||||||
const segments = this.splitPath(path);
|
const segments = this.splitPath(path);
|
||||||
const file = segments.pop() !;
|
const file = segments.pop()!;
|
||||||
return [path.substring(0, path.length - file.length - 1) as AbsoluteFsPath, file];
|
return [path.substring(0, path.length - file.length - 1) as AbsoluteFsPath, file];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,8 +261,10 @@ export interface FindResult {
|
||||||
path: AbsoluteFsPath;
|
path: AbsoluteFsPath;
|
||||||
entity: Entity|null;
|
entity: Entity|null;
|
||||||
}
|
}
|
||||||
export type Entity = Folder | File | SymLink;
|
export type Entity = Folder|File|SymLink;
|
||||||
export interface Folder { [pathSegments: string]: Entity; }
|
export interface Folder {
|
||||||
|
[pathSegments: string]: Entity;
|
||||||
|
}
|
||||||
export type File = string;
|
export type File = string;
|
||||||
export class SymLink {
|
export class SymLink {
|
||||||
constructor(public path: AbsoluteFsPath) {}
|
constructor(public path: AbsoluteFsPath) {}
|
||||||
|
@ -256,24 +272,32 @@ export class SymLink {
|
||||||
|
|
||||||
class MockFileStats implements FileStats {
|
class MockFileStats implements FileStats {
|
||||||
constructor(private entity: Entity) {}
|
constructor(private entity: Entity) {}
|
||||||
isFile(): boolean { return isFile(this.entity); }
|
isFile(): boolean {
|
||||||
isDirectory(): boolean { return isFolder(this.entity); }
|
return isFile(this.entity);
|
||||||
isSymbolicLink(): boolean { return isSymLink(this.entity); }
|
}
|
||||||
|
isDirectory(): boolean {
|
||||||
|
return isFolder(this.entity);
|
||||||
|
}
|
||||||
|
isSymbolicLink(): boolean {
|
||||||
|
return isSymLink(this.entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockFileSystemError extends Error {
|
class MockFileSystemError extends Error {
|
||||||
constructor(public code: string, public path: string, message: string) { super(message); }
|
constructor(public code: string, public path: string, message: string) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFile(item: Entity | null): item is File {
|
export function isFile(item: Entity|null): item is File {
|
||||||
return typeof item === 'string';
|
return typeof item === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSymLink(item: Entity | null): item is SymLink {
|
export function isSymLink(item: Entity|null): item is SymLink {
|
||||||
return item instanceof SymLink;
|
return item instanceof SymLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFolder(item: Entity | null): item is Folder {
|
export function isFolder(item: Entity|null): item is Folder {
|
||||||
return item !== null && !isFile(item) && !isSymLink(item);
|
return item !== null && !isFile(item) && !isSymLink(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@ import {MockFileSystem} from './mock_file_system';
|
||||||
const isWindows = os.platform() === 'win32';
|
const isWindows = os.platform() === 'win32';
|
||||||
|
|
||||||
export class MockFileSystemNative extends MockFileSystem {
|
export class MockFileSystemNative extends MockFileSystem {
|
||||||
constructor(cwd: AbsoluteFsPath = '/' as AbsoluteFsPath) { super(undefined, cwd); }
|
constructor(cwd: AbsoluteFsPath = '/' as AbsoluteFsPath) {
|
||||||
|
super(undefined, cwd);
|
||||||
|
}
|
||||||
|
|
||||||
// Delegate to the real NodeJSFileSystem for these path related methods
|
// Delegate to the real NodeJSFileSystem for these path related methods
|
||||||
|
|
||||||
|
@ -36,9 +38,13 @@ export class MockFileSystemNative extends MockFileSystem {
|
||||||
return NodeJSFileSystem.prototype.basename.call(this, filePath, extension);
|
return NodeJSFileSystem.prototype.basename.call(this, filePath, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCaseSensitive() { return NodeJSFileSystem.prototype.isCaseSensitive.call(this); }
|
isCaseSensitive() {
|
||||||
|
return NodeJSFileSystem.prototype.isCaseSensitive.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
isRooted(path: string): boolean { return NodeJSFileSystem.prototype.isRooted.call(this, path); }
|
isRooted(path: string): boolean {
|
||||||
|
return NodeJSFileSystem.prototype.isRooted.call(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
isRoot(path: AbsoluteFsPath): boolean {
|
isRoot(path: AbsoluteFsPath): boolean {
|
||||||
return NodeJSFileSystem.prototype.isRoot.call(this, path);
|
return NodeJSFileSystem.prototype.isRoot.call(this, path);
|
||||||
|
@ -57,5 +63,7 @@ export class MockFileSystemNative extends MockFileSystem {
|
||||||
return NodeJSFileSystem.prototype.normalize.call(this, path) as T;
|
return NodeJSFileSystem.prototype.normalize.call(this, path) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected splitPath<T>(path: string): string[] { return path.split(/[\\\/]/); }
|
protected splitPath<T>(path: string): string[] {
|
||||||
|
return path.split(/[\\\/]/);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,9 @@ export class MockFileSystemPosix extends MockFileSystem {
|
||||||
return this.normalize(resolved) as AbsoluteFsPath;
|
return this.normalize(resolved) as AbsoluteFsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirname<T extends string>(file: T): T { return this.normalize(p.posix.dirname(file)) as T; }
|
dirname<T extends string>(file: T): T {
|
||||||
|
return this.normalize(p.posix.dirname(file)) as T;
|
||||||
|
}
|
||||||
|
|
||||||
join<T extends string>(basePath: T, ...paths: string[]): T {
|
join<T extends string>(basePath: T, ...paths: string[]): T {
|
||||||
return this.normalize(p.posix.join(basePath, ...paths)) as T;
|
return this.normalize(p.posix.join(basePath, ...paths)) as T;
|
||||||
|
@ -31,9 +33,13 @@ export class MockFileSystemPosix extends MockFileSystem {
|
||||||
return p.posix.basename(filePath, extension) as PathSegment;
|
return p.posix.basename(filePath, extension) as PathSegment;
|
||||||
}
|
}
|
||||||
|
|
||||||
isRooted(path: string): boolean { return path.startsWith('/'); }
|
isRooted(path: string): boolean {
|
||||||
|
return path.startsWith('/');
|
||||||
|
}
|
||||||
|
|
||||||
protected splitPath<T extends PathString>(path: T): string[] { return path.split('/'); }
|
protected splitPath<T extends PathString>(path: T): string[] {
|
||||||
|
return path.split('/');
|
||||||
|
}
|
||||||
|
|
||||||
normalize<T extends PathString>(path: T): T {
|
normalize<T extends PathString>(path: T): T {
|
||||||
return path.replace(/^[a-z]:\//i, '/').replace(/\\/g, '/') as T;
|
return path.replace(/^[a-z]:\//i, '/').replace(/\\/g, '/') as T;
|
||||||
|
|
|
@ -17,7 +17,9 @@ export class MockFileSystemWindows extends MockFileSystem {
|
||||||
return this.normalize(resolved as AbsoluteFsPath);
|
return this.normalize(resolved as AbsoluteFsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
dirname<T extends string>(path: T): T { return this.normalize(p.win32.dirname(path) as T); }
|
dirname<T extends string>(path: T): T {
|
||||||
|
return this.normalize(p.win32.dirname(path) as T);
|
||||||
|
}
|
||||||
|
|
||||||
join<T extends string>(basePath: T, ...paths: string[]): T {
|
join<T extends string>(basePath: T, ...paths: string[]): T {
|
||||||
return this.normalize(p.win32.join(basePath, ...paths)) as T;
|
return this.normalize(p.win32.join(basePath, ...paths)) as T;
|
||||||
|
@ -31,9 +33,13 @@ export class MockFileSystemWindows extends MockFileSystem {
|
||||||
return p.win32.basename(filePath, extension) as PathSegment;
|
return p.win32.basename(filePath, extension) as PathSegment;
|
||||||
}
|
}
|
||||||
|
|
||||||
isRooted(path: string): boolean { return /^([A-Z]:)?([\\\/]|$)/i.test(path); }
|
isRooted(path: string): boolean {
|
||||||
|
return /^([A-Z]:)?([\\\/]|$)/i.test(path);
|
||||||
|
}
|
||||||
|
|
||||||
protected splitPath<T extends PathString>(path: T): string[] { return path.split(/[\\\/]/); }
|
protected splitPath<T extends PathString>(path: T): string[] {
|
||||||
|
return path.split(/[\\\/]/);
|
||||||
|
}
|
||||||
|
|
||||||
normalize<T extends PathString>(path: T): T {
|
normalize<T extends PathString>(path: T): T {
|
||||||
return path.replace(/^[\/\\]/i, 'C:/').replace(/\\/g, '/') as T;
|
return path.replace(/^[\/\\]/i, 'C:/').replace(/\\/g, '/') as T;
|
||||||
|
|
|
@ -47,7 +47,9 @@ function runInFileSystem(os: string, callback: (os: string) => void, error: bool
|
||||||
afterEach(() => setFileSystem(new InvalidFileSystem()));
|
afterEach(() => setFileSystem(new InvalidFileSystem()));
|
||||||
callback(os);
|
callback(os);
|
||||||
if (error) {
|
if (error) {
|
||||||
afterAll(() => { throw new Error(`runInFileSystem limited to ${os}, cannot pass`); });
|
afterAll(() => {
|
||||||
|
throw new Error(`runInFileSystem limited to ${os}, cannot pass`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -125,14 +127,16 @@ function monkeyPatchTypeScript(os: string, fs: MockFileSystem) {
|
||||||
return {files, directories};
|
return {files, directories};
|
||||||
}
|
}
|
||||||
|
|
||||||
function realPath(path: string): string { return fs.realpath(fs.resolve(path)); }
|
function realPath(path: string): string {
|
||||||
|
return fs.realpath(fs.resolve(path));
|
||||||
|
}
|
||||||
|
|
||||||
// Rather than completely re-implementing we are using the `ts.matchFiles` function,
|
// Rather than completely re-implementing we are using the `ts.matchFiles` function,
|
||||||
// which is internal to the `ts` namespace.
|
// which is internal to the `ts` namespace.
|
||||||
const tsMatchFiles: (
|
const tsMatchFiles: (
|
||||||
path: string, extensions: ReadonlyArray<string>| undefined,
|
path: string, extensions: ReadonlyArray<string>|undefined,
|
||||||
excludes: ReadonlyArray<string>| undefined, includes: ReadonlyArray<string>| undefined,
|
excludes: ReadonlyArray<string>|undefined, includes: ReadonlyArray<string>|undefined,
|
||||||
useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined,
|
useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number|undefined,
|
||||||
getFileSystemEntries: (path: string) => FileSystemEntries,
|
getFileSystemEntries: (path: string) => FileSystemEntries,
|
||||||
realpath: (path: string) => string) => string[] = (ts as any).matchFiles;
|
realpath: (path: string) => string) => string[] = (ts as any).matchFiles;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {AliasStrategy, AliasingHost, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias';
|
export {AliasingHost, AliasStrategy, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias';
|
||||||
export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core';
|
export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core';
|
||||||
export {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default';
|
export {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default';
|
||||||
export {AbsoluteModuleStrategy, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter';
|
export {AbsoluteModuleStrategy, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {Expression, ExternalExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {UnifiedModulesHost} from '../../core/api';
|
import {UnifiedModulesHost} from '../../core/api';
|
||||||
import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
|
||||||
|
|
||||||
import {ImportFlags, ReferenceEmitStrategy} from './emitter';
|
import {ImportFlags, ReferenceEmitStrategy} from './emitter';
|
||||||
import {Reference} from './references';
|
import {Reference} from './references';
|
||||||
|
@ -203,7 +203,9 @@ export class PrivateExportAliasingHost implements AliasingHost {
|
||||||
*
|
*
|
||||||
* Thus, `getAliasIn` always returns `null`.
|
* Thus, `getAliasIn` always returns `null`.
|
||||||
*/
|
*/
|
||||||
getAliasIn(): null { return null; }
|
getAliasIn(): null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,11 +36,17 @@ export interface ImportRewriter {
|
||||||
* `ImportRewriter` that does no rewriting.
|
* `ImportRewriter` that does no rewriting.
|
||||||
*/
|
*/
|
||||||
export class NoopImportRewriter implements ImportRewriter {
|
export class NoopImportRewriter implements ImportRewriter {
|
||||||
shouldImportSymbol(symbol: string, specifier: string): boolean { return true; }
|
shouldImportSymbol(symbol: string, specifier: string): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rewriteSymbol(symbol: string, specifier: string): string { return symbol; }
|
rewriteSymbol(symbol: string, specifier: string): string {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
rewriteSpecifier(specifier: string, inContextOfFile: string): string { return specifier; }
|
rewriteSpecifier(specifier: string, inContextOfFile: string): string {
|
||||||
|
return specifier;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,7 +76,9 @@ const CORE_MODULE = '@angular/core';
|
||||||
export class R3SymbolsImportRewriter implements ImportRewriter {
|
export class R3SymbolsImportRewriter implements ImportRewriter {
|
||||||
constructor(private r3SymbolsPath: string) {}
|
constructor(private r3SymbolsPath: string) {}
|
||||||
|
|
||||||
shouldImportSymbol(symbol: string, specifier: string): boolean { return true; }
|
shouldImportSymbol(symbol: string, specifier: string): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rewriteSymbol(symbol: string, specifier: string): string {
|
rewriteSymbol(symbol: string, specifier: string): string {
|
||||||
if (specifier !== CORE_MODULE) {
|
if (specifier !== CORE_MODULE) {
|
||||||
|
@ -89,8 +97,8 @@ export class R3SymbolsImportRewriter implements ImportRewriter {
|
||||||
|
|
||||||
const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath);
|
const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath);
|
||||||
if (relativePathToR3Symbols === null) {
|
if (relativePathToR3Symbols === null) {
|
||||||
throw new Error(
|
throw new Error(`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${
|
||||||
`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${this.r3SymbolsPath}`);
|
this.r3SymbolsPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return relativePathToR3Symbols;
|
return relativePathToR3Symbols;
|
||||||
|
@ -101,5 +109,5 @@ export function validateAndRewriteCoreSymbol(name: string): string {
|
||||||
if (!CORE_SUPPORTED_SYMBOLS.has(name)) {
|
if (!CORE_SUPPORTED_SYMBOLS.has(name)) {
|
||||||
throw new Error(`Importing unexpected symbol ${name} while compiling ${CORE_MODULE}`);
|
throw new Error(`Importing unexpected symbol ${name} while compiling ${CORE_MODULE}`);
|
||||||
}
|
}
|
||||||
return CORE_SUPPORTED_SYMBOLS.get(name) !;
|
return CORE_SUPPORTED_SYMBOLS.get(name)!;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
||||||
if (!this.sourceFileToImportMap.has(sf)) {
|
if (!this.sourceFileToImportMap.has(sf)) {
|
||||||
this.sourceFileToImportMap.set(sf, new Map<ts.Identifier, ts.ImportDeclaration>());
|
this.sourceFileToImportMap.set(sf, new Map<ts.Identifier, ts.ImportDeclaration>());
|
||||||
}
|
}
|
||||||
this.sourceFileToImportMap.get(sf) !.set(id, decl);
|
this.sourceFileToImportMap.get(sf)!.set(id, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
recordUsedIdentifier(id: ts.Identifier): void {
|
recordUsedIdentifier(id: ts.Identifier): void {
|
||||||
|
@ -105,18 +105,18 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
||||||
// The identifier's source file has no registered default imports at all.
|
// The identifier's source file has no registered default imports at all.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const identiferToDeclaration = this.sourceFileToImportMap.get(sf) !;
|
const identiferToDeclaration = this.sourceFileToImportMap.get(sf)!;
|
||||||
if (!identiferToDeclaration.has(id)) {
|
if (!identiferToDeclaration.has(id)) {
|
||||||
// The identifier isn't from a registered default import.
|
// The identifier isn't from a registered default import.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const decl = identiferToDeclaration.get(id) !;
|
const decl = identiferToDeclaration.get(id)!;
|
||||||
|
|
||||||
// Add the default import declaration to the set of used import declarations for the file.
|
// Add the default import declaration to the set of used import declarations for the file.
|
||||||
if (!this.sourceFileToUsedImports.has(sf)) {
|
if (!this.sourceFileToUsedImports.has(sf)) {
|
||||||
this.sourceFileToUsedImports.set(sf, new Set<ts.ImportDeclaration>());
|
this.sourceFileToUsedImports.set(sf, new Set<ts.ImportDeclaration>());
|
||||||
}
|
}
|
||||||
this.sourceFileToUsedImports.get(sf) !.add(decl);
|
this.sourceFileToUsedImports.get(sf)!.add(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,7 +127,9 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
||||||
*/
|
*/
|
||||||
importPreservingTransformer(): ts.TransformerFactory<ts.SourceFile> {
|
importPreservingTransformer(): ts.TransformerFactory<ts.SourceFile> {
|
||||||
return (context: ts.TransformationContext) => {
|
return (context: ts.TransformationContext) => {
|
||||||
return (sf: ts.SourceFile) => { return this.transformSourceFile(sf); };
|
return (sf: ts.SourceFile) => {
|
||||||
|
return this.transformSourceFile(sf);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +144,7 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are declarations that need to be preserved.
|
// There are declarations that need to be preserved.
|
||||||
const importsToPreserve = this.sourceFileToUsedImports.get(originalSf) !;
|
const importsToPreserve = this.sourceFileToUsedImports.get(originalSf)!;
|
||||||
|
|
||||||
// Generate a new statement list which preserves any imports present in `importsToPreserve`.
|
// Generate a new statement list which preserves any imports present in `importsToPreserve`.
|
||||||
const statements = sf.statements.map(stmt => {
|
const statements = sf.statements.map(stmt => {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@ang
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {UnifiedModulesHost} from '../../core/api';
|
import {UnifiedModulesHost} from '../../core/api';
|
||||||
import {LogicalFileSystem, LogicalProjectPath, PathSegment, absoluteFromSourceFile, dirname, relative} from '../../file_system';
|
import {absoluteFromSourceFile, dirname, LogicalFileSystem, LogicalProjectPath, PathSegment, relative} from '../../file_system';
|
||||||
import {stripExtension} from '../../file_system/src/util';
|
import {stripExtension} from '../../file_system/src/util';
|
||||||
import {ReflectionHost} from '../../reflection';
|
import {ReflectionHost} from '../../reflection';
|
||||||
import {getSourceFile, isDeclaration, isTypeDeclaration, nodeNameForError} from '../../util/src/typescript';
|
import {getSourceFile, isDeclaration, isTypeDeclaration, nodeNameForError} from '../../util/src/typescript';
|
||||||
|
@ -93,8 +93,8 @@ export class ReferenceEmitter {
|
||||||
return emitted;
|
return emitted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(`Unable to write a reference to ${nodeNameForError(ref.node)} in ${
|
||||||
`Unable to write a reference to ${nodeNameForError(ref.node)} in ${ref.node.getSourceFile().fileName} from ${context.fileName}`);
|
ref.node.getSourceFile().fileName} from ${context.fileName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,11 +149,11 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
||||||
return null;
|
return null;
|
||||||
} else if (!isDeclaration(ref.node)) {
|
} else if (!isDeclaration(ref.node)) {
|
||||||
// It's not possible to import something which isn't a declaration.
|
// It's not possible to import something which isn't a declaration.
|
||||||
throw new Error(
|
throw new Error(`Debug assert: unable to import a Reference to non-declaration of type ${
|
||||||
`Debug assert: unable to import a Reference to non-declaration of type ${ts.SyntaxKind[ref.node.kind]}.`);
|
ts.SyntaxKind[ref.node.kind]}.`);
|
||||||
} else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) {
|
} else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) {
|
||||||
throw new Error(
|
throw new Error(`Importing a type-only declaration of type ${
|
||||||
`Importing a type-only declaration of type ${ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`);
|
ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find the exported name of the declaration, if one is available.
|
// Try to find the exported name of the declaration, if one is available.
|
||||||
|
@ -162,8 +162,9 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
||||||
if (symbolName === null) {
|
if (symbolName === null) {
|
||||||
// TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be
|
// TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be
|
||||||
// triggered.
|
// triggered.
|
||||||
throw new Error(
|
throw new Error(`Symbol ${ref.debugName} declared in ${
|
||||||
`Symbol ${ref.debugName} declared in ${getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${context.fileName})`);
|
getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${
|
||||||
|
context.fileName})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExternalExpr(new ExternalReference(specifier, symbolName));
|
return new ExternalExpr(new ExternalReference(specifier, symbolName));
|
||||||
|
@ -173,7 +174,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
||||||
|null {
|
|null {
|
||||||
const exports = this.getExportsOfModule(moduleName, fromFile);
|
const exports = this.getExportsOfModule(moduleName, fromFile);
|
||||||
if (exports !== null && exports.has(target)) {
|
if (exports !== null && exports.has(target)) {
|
||||||
return exports.get(target) !;
|
return exports.get(target)!;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +185,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
||||||
if (!this.moduleExportsCache.has(moduleName)) {
|
if (!this.moduleExportsCache.has(moduleName)) {
|
||||||
this.moduleExportsCache.set(moduleName, this.enumerateExportsOfModule(moduleName, fromFile));
|
this.moduleExportsCache.set(moduleName, this.enumerateExportsOfModule(moduleName, fromFile));
|
||||||
}
|
}
|
||||||
return this.moduleExportsCache.get(moduleName) !;
|
return this.moduleExportsCache.get(moduleName)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enumerateExportsOfModule(specifier: string, fromFile: string):
|
protected enumerateExportsOfModule(specifier: string, fromFile: string):
|
||||||
|
|
|
@ -80,7 +80,9 @@ export class Reference<T extends ts.Node = ts.Node> {
|
||||||
*
|
*
|
||||||
* See `bestGuessOwningModule`.
|
* See `bestGuessOwningModule`.
|
||||||
*/
|
*/
|
||||||
get hasOwningModuleGuess(): boolean { return this.bestGuessOwningModule !== null; }
|
get hasOwningModuleGuess(): boolean {
|
||||||
|
return this.bestGuessOwningModule !== null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A name for the node, if one is available.
|
* A name for the node, if one is available.
|
||||||
|
@ -93,14 +95,18 @@ export class Reference<T extends ts.Node = ts.Node> {
|
||||||
return id !== null ? id.text : null;
|
return id !== null ? id.text : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get alias(): Expression|null { return this._alias; }
|
get alias(): Expression|null {
|
||||||
|
return this._alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record a `ts.Identifier` by which it's valid to refer to this node, within the context of this
|
* Record a `ts.Identifier` by which it's valid to refer to this node, within the context of this
|
||||||
* `Reference`.
|
* `Reference`.
|
||||||
*/
|
*/
|
||||||
addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); }
|
addIdentifier(identifier: ts.Identifier): void {
|
||||||
|
this.identifiers.push(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a `ts.Identifier` within this `Reference` that can be used to refer within the context of a
|
* Get a `ts.Identifier` within this `Reference` that can be used to refer within the context of a
|
||||||
|
|
|
@ -39,7 +39,7 @@ runInEachFileSystem(() => {
|
||||||
module: ts.ModuleKind.ES2015,
|
module: ts.ModuleKind.ES2015,
|
||||||
});
|
});
|
||||||
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
||||||
const fooId = fooClause.name !;
|
const fooId = fooClause.name!;
|
||||||
const fooDecl = fooClause.parent;
|
const fooDecl = fooClause.parent;
|
||||||
|
|
||||||
const tracker = new DefaultImportTracker();
|
const tracker = new DefaultImportTracker();
|
||||||
|
@ -48,7 +48,7 @@ runInEachFileSystem(() => {
|
||||||
program.emit(undefined, undefined, undefined, undefined, {
|
program.emit(undefined, undefined, undefined, undefined, {
|
||||||
before: [tracker.importPreservingTransformer()],
|
before: [tracker.importPreservingTransformer()],
|
||||||
});
|
});
|
||||||
const testContents = host.readFile('/test.js') !;
|
const testContents = host.readFile('/test.js')!;
|
||||||
expect(testContents).toContain(`import Foo from './dep';`);
|
expect(testContents).toContain(`import Foo from './dep';`);
|
||||||
|
|
||||||
// The control should have the import elided.
|
// The control should have the import elided.
|
||||||
|
@ -69,7 +69,7 @@ runInEachFileSystem(() => {
|
||||||
module: ts.ModuleKind.CommonJS,
|
module: ts.ModuleKind.CommonJS,
|
||||||
});
|
});
|
||||||
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
||||||
const fooId = ts.updateIdentifier(fooClause.name !);
|
const fooId = ts.updateIdentifier(fooClause.name!);
|
||||||
const fooDecl = fooClause.parent;
|
const fooDecl = fooClause.parent;
|
||||||
|
|
||||||
const tracker = new DefaultImportTracker();
|
const tracker = new DefaultImportTracker();
|
||||||
|
@ -81,7 +81,7 @@ runInEachFileSystem(() => {
|
||||||
tracker.importPreservingTransformer(),
|
tracker.importPreservingTransformer(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const testContents = host.readFile('/test.js') !;
|
const testContents = host.readFile('/test.js')!;
|
||||||
expect(testContents).toContain(`var dep_1 = require("./dep");`);
|
expect(testContents).toContain(`var dep_1 = require("./dep");`);
|
||||||
expect(testContents).toContain(`var ref = dep_1["default"];`);
|
expect(testContents).toContain(`var ref = dep_1["default"];`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
import {ExternalExpr} from '@angular/compiler';
|
import {ExternalExpr} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {LogicalFileSystem, absoluteFrom as _} from '../../file_system';
|
import {absoluteFrom as _, LogicalFileSystem} from '../../file_system';
|
||||||
import {TestFile, runInEachFileSystem} from '../../file_system/testing';
|
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||||
import {Declaration, TypeScriptReflectionHost} from '../../reflection';
|
import {Declaration, TypeScriptReflectionHost} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
import {AbsoluteModuleStrategy, ImportFlags, LogicalProjectStrategy} from '../src/emitter';
|
import {AbsoluteModuleStrategy, ImportFlags, LogicalProjectStrategy} from '../src/emitter';
|
||||||
|
@ -42,7 +42,7 @@ runInEachFileSystem(() => {
|
||||||
]);
|
]);
|
||||||
const decl =
|
const decl =
|
||||||
getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration);
|
getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration);
|
||||||
const context = program.getSourceFile(_('/context.ts')) !;
|
const context = program.getSourceFile(_('/context.ts'))!;
|
||||||
|
|
||||||
const reference = new Reference(decl);
|
const reference = new Reference(decl);
|
||||||
const emitted = strategy.emit(reference, context, ImportFlags.None);
|
const emitted = strategy.emit(reference, context, ImportFlags.None);
|
||||||
|
@ -65,7 +65,7 @@ runInEachFileSystem(() => {
|
||||||
]);
|
]);
|
||||||
const decl =
|
const decl =
|
||||||
getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration);
|
getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration);
|
||||||
const context = program.getSourceFile(_('/context.ts')) !;
|
const context = program.getSourceFile(_('/context.ts'))!;
|
||||||
|
|
||||||
const reference = new Reference(decl, {
|
const reference = new Reference(decl, {
|
||||||
specifier: 'external',
|
specifier: 'external',
|
||||||
|
@ -92,7 +92,7 @@ runInEachFileSystem(() => {
|
||||||
]);
|
]);
|
||||||
const decl = getDeclaration(
|
const decl = getDeclaration(
|
||||||
program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration);
|
program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration);
|
||||||
const context = program.getSourceFile(_('/context.ts')) !;
|
const context = program.getSourceFile(_('/context.ts'))!;
|
||||||
|
|
||||||
const reference = new Reference(decl, {
|
const reference = new Reference(decl, {
|
||||||
specifier: 'external',
|
specifier: 'external',
|
||||||
|
@ -116,7 +116,7 @@ runInEachFileSystem(() => {
|
||||||
]);
|
]);
|
||||||
const decl = getDeclaration(
|
const decl = getDeclaration(
|
||||||
program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration);
|
program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration);
|
||||||
const context = program.getSourceFile(_('/context.ts')) !;
|
const context = program.getSourceFile(_('/context.ts'))!;
|
||||||
|
|
||||||
const reference =
|
const reference =
|
||||||
new Reference(decl, {specifier: 'external', resolutionContext: context.fileName});
|
new Reference(decl, {specifier: 'external', resolutionContext: context.fileName});
|
||||||
|
@ -139,7 +139,9 @@ runInEachFileSystem(() => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const fakeExports = new Map<string, Declaration>();
|
const fakeExports = new Map<string, Declaration>();
|
||||||
realExports.forEach((decl, name) => { fakeExports.set(`test${name}`, decl); });
|
realExports.forEach((decl, name) => {
|
||||||
|
fakeExports.set(`test${name}`, decl);
|
||||||
|
});
|
||||||
return fakeExports;
|
return fakeExports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,12 +160,12 @@ runInEachFileSystem(() => {
|
||||||
const logicalFs = new LogicalFileSystem([_('/')]);
|
const logicalFs = new LogicalFileSystem([_('/')]);
|
||||||
const strategy = new LogicalProjectStrategy(new TestHost(checker), logicalFs);
|
const strategy = new LogicalProjectStrategy(new TestHost(checker), logicalFs);
|
||||||
const decl = getDeclaration(program, _('/index.ts'), 'Foo', ts.isClassDeclaration);
|
const decl = getDeclaration(program, _('/index.ts'), 'Foo', ts.isClassDeclaration);
|
||||||
const context = program.getSourceFile(_('/context.ts')) !;
|
const context = program.getSourceFile(_('/context.ts'))!;
|
||||||
const ref = strategy.emit(new Reference(decl), context);
|
const ref = strategy.emit(new Reference(decl), context);
|
||||||
expect(ref).not.toBeNull();
|
expect(ref).not.toBeNull();
|
||||||
|
|
||||||
// Expect the prefixed name from the TestHost.
|
// Expect the prefixed name from the TestHost.
|
||||||
expect((ref !as ExternalExpr).value.name).toEqual('testFoo');
|
expect((ref! as ExternalExpr).value.name).toEqual('testFoo');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ export interface IncrementalBuild<W> {
|
||||||
/**
|
/**
|
||||||
* Tracks dependencies between source files or resources in the application.
|
* Tracks dependencies between source files or resources in the application.
|
||||||
*/
|
*/
|
||||||
export interface DependencyTracker<T extends{fileName: string} = ts.SourceFile> {
|
export interface DependencyTracker<T extends {fileName: string} = ts.SourceFile> {
|
||||||
/**
|
/**
|
||||||
* Record that the file `from` depends on the file `on`.
|
* Record that the file `from` depends on the file `on`.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,11 +23,13 @@ import {DependencyTracker} from '../api';
|
||||||
* 2. One of its dependencies has physically changed.
|
* 2. One of its dependencies has physically changed.
|
||||||
* 3. One of its resource dependencies has physically changed.
|
* 3. One of its resource dependencies has physically changed.
|
||||||
*/
|
*/
|
||||||
export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> implements
|
export class FileDependencyGraph<T extends {fileName: string} = ts.SourceFile> implements
|
||||||
DependencyTracker<T> {
|
DependencyTracker<T> {
|
||||||
private nodes = new Map<T, FileNode>();
|
private nodes = new Map<T, FileNode>();
|
||||||
|
|
||||||
addDependency(from: T, on: T): void { this.nodeFor(from).dependsOn.add(on.fileName); }
|
addDependency(from: T, on: T): void {
|
||||||
|
this.nodeFor(from).dependsOn.add(on.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
addResourceDependency(from: T, resource: AbsoluteFsPath): void {
|
addResourceDependency(from: T, resource: AbsoluteFsPath): void {
|
||||||
this.nodeFor(from).usesResources.add(resource);
|
this.nodeFor(from).usesResources.add(resource);
|
||||||
|
@ -103,7 +105,7 @@ export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> im
|
||||||
usesResources: new Set<AbsoluteFsPath>(),
|
usesResources: new Set<AbsoluteFsPath>(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.nodes.get(sf) !;
|
return this.nodes.get(sf)!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +113,7 @@ export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> im
|
||||||
* Determine whether `sf` has logically changed, given its dependencies and the set of physically
|
* Determine whether `sf` has logically changed, given its dependencies and the set of physically
|
||||||
* changed files and resources.
|
* changed files and resources.
|
||||||
*/
|
*/
|
||||||
function isLogicallyChanged<T extends{fileName: string}>(
|
function isLogicallyChanged<T extends {fileName: string}>(
|
||||||
sf: T, node: FileNode, changedTsPaths: ReadonlySet<string>, deletedTsPaths: ReadonlySet<string>,
|
sf: T, node: FileNode, changedTsPaths: ReadonlySet<string>, deletedTsPaths: ReadonlySet<string>,
|
||||||
changedResources: ReadonlySet<AbsoluteFsPath>): boolean {
|
changedResources: ReadonlySet<AbsoluteFsPath>): boolean {
|
||||||
// A file is logically changed if it has physically changed itself (including being deleted).
|
// A file is logically changed if it has physically changed itself (including being deleted).
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {AbsoluteFsPath, absoluteFrom} from '../../file_system';
|
import {absoluteFrom, AbsoluteFsPath} from '../../file_system';
|
||||||
import {ClassRecord, TraitCompiler} from '../../transform';
|
import {ClassRecord, TraitCompiler} from '../../transform';
|
||||||
import {IncrementalBuild} from '../api';
|
import {IncrementalBuild} from '../api';
|
||||||
|
|
||||||
|
@ -194,9 +194,13 @@ export class IncrementalDriver implements IncrementalBuild<ClassRecord> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
recordSuccessfulEmit(sf: ts.SourceFile): void { this.state.pendingEmit.delete(sf.fileName); }
|
recordSuccessfulEmit(sf: ts.SourceFile): void {
|
||||||
|
this.state.pendingEmit.delete(sf.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
safeToSkipEmit(sf: ts.SourceFile): boolean { return !this.state.pendingEmit.has(sf.fileName); }
|
safeToSkipEmit(sf: ts.SourceFile): boolean {
|
||||||
|
return !this.state.pendingEmit.has(sf.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
priorWorkFor(sf: ts.SourceFile): ClassRecord[]|null {
|
priorWorkFor(sf: ts.SourceFile): ClassRecord[]|null {
|
||||||
if (this.state.lastGood === null || this.logicalChanges === null) {
|
if (this.state.lastGood === null || this.logicalChanges === null) {
|
||||||
|
@ -212,7 +216,7 @@ export class IncrementalDriver implements IncrementalBuild<ClassRecord> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildState = PendingBuildState | AnalyzedBuildState;
|
type BuildState = PendingBuildState|AnalyzedBuildState;
|
||||||
|
|
||||||
enum BuildStateKind {
|
enum BuildStateKind {
|
||||||
Pending,
|
Pending,
|
||||||
|
|
|
@ -43,13 +43,19 @@ interface ExpressionIdentifier extends TemplateIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Describes a property accessed in a template. */
|
/** Describes a property accessed in a template. */
|
||||||
export interface PropertyIdentifier extends ExpressionIdentifier { kind: IdentifierKind.Property; }
|
export interface PropertyIdentifier extends ExpressionIdentifier {
|
||||||
|
kind: IdentifierKind.Property;
|
||||||
|
}
|
||||||
|
|
||||||
/** Describes a method accessed in a template. */
|
/** Describes a method accessed in a template. */
|
||||||
export interface MethodIdentifier extends ExpressionIdentifier { kind: IdentifierKind.Method; }
|
export interface MethodIdentifier extends ExpressionIdentifier {
|
||||||
|
kind: IdentifierKind.Method;
|
||||||
|
}
|
||||||
|
|
||||||
/** Describes an element attribute in a template. */
|
/** Describes an element attribute in a template. */
|
||||||
export interface AttributeIdentifier extends TemplateIdentifier { kind: IdentifierKind.Attribute; }
|
export interface AttributeIdentifier extends TemplateIdentifier {
|
||||||
|
kind: IdentifierKind.Attribute;
|
||||||
|
}
|
||||||
|
|
||||||
/** A reference to a directive node and its selector. */
|
/** A reference to a directive node and its selector. */
|
||||||
interface DirectiveReference {
|
interface DirectiveReference {
|
||||||
|
@ -85,7 +91,7 @@ export interface ReferenceIdentifier extends TemplateIdentifier {
|
||||||
/** The target of this reference. If the target is not known, this is `null`. */
|
/** The target of this reference. If the target is not known, this is `null`. */
|
||||||
target: {
|
target: {
|
||||||
/** The template AST node that the reference targets. */
|
/** The template AST node that the reference targets. */
|
||||||
node: ElementIdentifier | TemplateIdentifier;
|
node: ElementIdentifier|TemplateIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The directive on `node` that the reference targets. If no directive is targeted, this is
|
* The directive on `node` that the reference targets. If no directive is targeted, this is
|
||||||
|
@ -96,14 +102,16 @@ export interface ReferenceIdentifier extends TemplateIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Describes a template variable like "foo" in `<div *ngFor="let foo of foos"></div>`. */
|
/** Describes a template variable like "foo" in `<div *ngFor="let foo of foos"></div>`. */
|
||||||
export interface VariableIdentifier extends TemplateIdentifier { kind: IdentifierKind.Variable; }
|
export interface VariableIdentifier extends TemplateIdentifier {
|
||||||
|
kind: IdentifierKind.Variable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifiers recorded at the top level of the template, without any context about the HTML nodes
|
* Identifiers recorded at the top level of the template, without any context about the HTML nodes
|
||||||
* they were discovered in.
|
* they were discovered in.
|
||||||
*/
|
*/
|
||||||
export type TopLevelIdentifier = PropertyIdentifier | MethodIdentifier | ElementIdentifier |
|
export type TopLevelIdentifier = PropertyIdentifier|MethodIdentifier|ElementIdentifier|
|
||||||
TemplateNodeIdentifier | ReferenceIdentifier | VariableIdentifier;
|
TemplateNodeIdentifier|ReferenceIdentifier|VariableIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the absolute byte offsets of a text anchor in a source code.
|
* Describes the absolute byte offsets of a text anchor in a source code.
|
||||||
|
|
|
@ -56,5 +56,7 @@ export class IndexingContext {
|
||||||
/**
|
/**
|
||||||
* Adds a component to the context.
|
* Adds a component to the context.
|
||||||
*/
|
*/
|
||||||
addComponent(info: ComponentInfo) { this.components.add(info); }
|
addComponent(info: ComponentInfo) {
|
||||||
|
this.components.add(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ interface HTMLNode extends TmplAstNode {
|
||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExpressionIdentifier = PropertyIdentifier | MethodIdentifier;
|
type ExpressionIdentifier = PropertyIdentifier|MethodIdentifier;
|
||||||
type TmplTarget = TmplAstReference | TmplAstVariable;
|
type TmplTarget = TmplAstReference|TmplAstVariable;
|
||||||
type TargetIdentifier = ReferenceIdentifier | VariableIdentifier;
|
type TargetIdentifier = ReferenceIdentifier|VariableIdentifier;
|
||||||
type TargetIdentifierMap = Map<TmplTarget, TargetIdentifier>;
|
type TargetIdentifierMap = Map<TmplTarget, TargetIdentifier>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +62,9 @@ class ExpressionVisitor extends RecursiveAstVisitor {
|
||||||
return visitor.identifiers;
|
return visitor.identifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(ast: AST) { ast.visit(this); }
|
visit(ast: AST) {
|
||||||
|
ast.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
visitMethodCall(ast: MethodCall, context: {}) {
|
visitMethodCall(ast: MethodCall, context: {}) {
|
||||||
this.visitIdentifier(ast, IdentifierKind.Method);
|
this.visitIdentifier(ast, IdentifierKind.Method);
|
||||||
|
@ -144,16 +146,22 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
*
|
*
|
||||||
* @param boundTemplate bound template target
|
* @param boundTemplate bound template target
|
||||||
*/
|
*/
|
||||||
constructor(private boundTemplate: BoundTarget<ComponentMeta>) { super(); }
|
constructor(private boundTemplate: BoundTarget<ComponentMeta>) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visits a node in the template.
|
* Visits a node in the template.
|
||||||
*
|
*
|
||||||
* @param node node to visit
|
* @param node node to visit
|
||||||
*/
|
*/
|
||||||
visit(node: HTMLNode) { node.visit(this); }
|
visit(node: HTMLNode) {
|
||||||
|
node.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
visitAll(nodes: TmplAstNode[]) { nodes.forEach(node => this.visit(node)); }
|
visitAll(nodes: TmplAstNode[]) {
|
||||||
|
nodes.forEach(node => this.visit(node));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an identifier for an HTML element and visit its children recursively.
|
* Add an identifier for an HTML element and visit its children recursively.
|
||||||
|
@ -204,8 +212,12 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
this.targetToIdentifier.bind(this));
|
this.targetToIdentifier.bind(this));
|
||||||
identifiers.forEach(id => this.identifiers.add(id));
|
identifiers.forEach(id => this.identifiers.add(id));
|
||||||
}
|
}
|
||||||
visitBoundEvent(attribute: TmplAstBoundEvent) { this.visitExpression(attribute.handler); }
|
visitBoundEvent(attribute: TmplAstBoundEvent) {
|
||||||
visitBoundText(text: TmplAstBoundText) { this.visitExpression(text.value); }
|
this.visitExpression(attribute.handler);
|
||||||
|
}
|
||||||
|
visitBoundText(text: TmplAstBoundText) {
|
||||||
|
this.visitExpression(text.value);
|
||||||
|
}
|
||||||
visitReference(reference: TmplAstReference) {
|
visitReference(reference: TmplAstReference) {
|
||||||
const referenceIdentifer = this.targetToIdentifier(reference);
|
const referenceIdentifer = this.targetToIdentifier(reference);
|
||||||
|
|
||||||
|
@ -222,7 +234,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
|TemplateNodeIdentifier {
|
|TemplateNodeIdentifier {
|
||||||
// If this node has already been seen, return the cached result.
|
// If this node has already been seen, return the cached result.
|
||||||
if (this.elementAndTemplateIdentifierCache.has(node)) {
|
if (this.elementAndTemplateIdentifierCache.has(node)) {
|
||||||
return this.elementAndTemplateIdentifierCache.get(node) !;
|
return this.elementAndTemplateIdentifierCache.get(node)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name: string;
|
let name: string;
|
||||||
|
@ -254,7 +266,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
|
|
||||||
const identifier = {
|
const identifier = {
|
||||||
name,
|
name,
|
||||||
span: absoluteSpan, kind,
|
span: absoluteSpan,
|
||||||
|
kind,
|
||||||
attributes: new Set(attributes),
|
attributes: new Set(attributes),
|
||||||
usedDirectives: new Set(usedDirectives.map(dir => {
|
usedDirectives: new Set(usedDirectives.map(dir => {
|
||||||
return {
|
return {
|
||||||
|
@ -274,7 +287,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
private targetToIdentifier(node: TmplAstReference|TmplAstVariable): TargetIdentifier {
|
private targetToIdentifier(node: TmplAstReference|TmplAstVariable): TargetIdentifier {
|
||||||
// If this node has already been seen, return the cached result.
|
// If this node has already been seen, return the cached result.
|
||||||
if (this.targetIdentifierCache.has(node)) {
|
if (this.targetIdentifierCache.has(node)) {
|
||||||
return this.targetIdentifierCache.get(node) !;
|
return this.targetIdentifierCache.get(node)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {name, sourceSpan} = node;
|
const {name, sourceSpan} = node;
|
||||||
|
@ -304,7 +317,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
||||||
identifier = {
|
identifier = {
|
||||||
name,
|
name,
|
||||||
span,
|
span,
|
||||||
kind: IdentifierKind.Reference, target,
|
kind: IdentifierKind.Reference,
|
||||||
|
target,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
identifier = {
|
identifier = {
|
||||||
|
|
|
@ -19,7 +19,8 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
context.addComponent({
|
context.addComponent({
|
||||||
declaration,
|
declaration,
|
||||||
selector: 'c-selector', boundTemplate,
|
selector: 'c-selector',
|
||||||
|
boundTemplate,
|
||||||
templateMeta: {
|
templateMeta: {
|
||||||
isInline: false,
|
isInline: false,
|
||||||
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
||||||
|
@ -29,7 +30,8 @@ runInEachFileSystem(() => {
|
||||||
expect(context.components).toEqual(new Set([
|
expect(context.components).toEqual(new Set([
|
||||||
{
|
{
|
||||||
declaration,
|
declaration,
|
||||||
selector: 'c-selector', boundTemplate,
|
selector: 'c-selector',
|
||||||
|
boundTemplate,
|
||||||
templateMeta: {
|
templateMeta: {
|
||||||
isInline: false,
|
isInline: false,
|
||||||
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
||||||
|
|
|
@ -219,11 +219,11 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const refArr = Array.from(refs);
|
const refArr = Array.from(refs);
|
||||||
expect(refArr).toEqual(jasmine.arrayContaining([{
|
expect(refArr).toEqual(jasmine.arrayContaining([{
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
kind: IdentifierKind.Property,
|
kind: IdentifierKind.Property,
|
||||||
span: new AbsoluteSourceSpan(20, 23),
|
span: new AbsoluteSourceSpan(20, 23),
|
||||||
target: null,
|
target: null,
|
||||||
}] as TopLevelIdentifier[]));
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore property writes that are not implicitly received by the template', () => {
|
it('should ignore property writes that are not implicitly received by the template', () => {
|
||||||
|
@ -314,12 +314,13 @@ runInEachFileSystem(() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const refArray = Array.from(refs);
|
const refArray = Array.from(refs);
|
||||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
expect(refArray).toEqual(
|
||||||
name: 'foo',
|
jasmine.arrayContaining([{
|
||||||
kind: IdentifierKind.Reference,
|
name: 'foo',
|
||||||
span: new AbsoluteSourceSpan(6, 9),
|
kind: IdentifierKind.Reference,
|
||||||
target: {node: elementReference, directive: null},
|
span: new AbsoluteSourceSpan(6, 9),
|
||||||
}] as TopLevelIdentifier[]));
|
target: {node: elementReference, directive: null},
|
||||||
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover nested references', () => {
|
it('should discover nested references', () => {
|
||||||
|
@ -334,12 +335,13 @@ runInEachFileSystem(() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const refArray = Array.from(refs);
|
const refArray = Array.from(refs);
|
||||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
expect(refArray).toEqual(
|
||||||
name: 'foo',
|
jasmine.arrayContaining([{
|
||||||
kind: IdentifierKind.Reference,
|
name: 'foo',
|
||||||
span: new AbsoluteSourceSpan(12, 15),
|
kind: IdentifierKind.Reference,
|
||||||
target: {node: elementReference, directive: null},
|
span: new AbsoluteSourceSpan(12, 15),
|
||||||
}] as TopLevelIdentifier[]));
|
target: {node: elementReference, directive: null},
|
||||||
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover references to references', () => {
|
it('should discover references to references', () => {
|
||||||
|
@ -409,14 +411,14 @@ runInEachFileSystem(() => {
|
||||||
const refArr = Array.from(refs);
|
const refArr = Array.from(refs);
|
||||||
let fooRef = refArr.find(id => id.name === 'foo');
|
let fooRef = refArr.find(id => id.name === 'foo');
|
||||||
expect(fooRef).toBeDefined();
|
expect(fooRef).toBeDefined();
|
||||||
expect(fooRef !.kind).toBe(IdentifierKind.Reference);
|
expect(fooRef!.kind).toBe(IdentifierKind.Reference);
|
||||||
|
|
||||||
fooRef = fooRef as ReferenceIdentifier;
|
fooRef = fooRef as ReferenceIdentifier;
|
||||||
expect(fooRef.target).toBeDefined();
|
expect(fooRef.target).toBeDefined();
|
||||||
expect(fooRef.target !.node.kind).toBe(IdentifierKind.Element);
|
expect(fooRef.target!.node.kind).toBe(IdentifierKind.Element);
|
||||||
expect(fooRef.target !.node.name).toBe('div');
|
expect(fooRef.target!.node.name).toBe('div');
|
||||||
expect(fooRef.target !.node.span).toEqual(new AbsoluteSourceSpan(1, 4));
|
expect(fooRef.target!.node.span).toEqual(new AbsoluteSourceSpan(1, 4));
|
||||||
expect(fooRef.target !.directive).toEqual(declB);
|
expect(fooRef.target!.directive).toEqual(declB);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover references to references', () => {
|
it('should discover references to references', () => {
|
||||||
|
@ -455,10 +457,10 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const refArray = Array.from(refs);
|
const refArray = Array.from(refs);
|
||||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
kind: IdentifierKind.Variable,
|
kind: IdentifierKind.Variable,
|
||||||
span: new AbsoluteSourceSpan(17, 20),
|
span: new AbsoluteSourceSpan(17, 20),
|
||||||
}] as TopLevelIdentifier[]));
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover variables with let- syntax', () => {
|
it('should discover variables with let- syntax', () => {
|
||||||
|
@ -467,10 +469,10 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const refArray = Array.from(refs);
|
const refArray = Array.from(refs);
|
||||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||||
name: 'var',
|
name: 'var',
|
||||||
kind: IdentifierKind.Variable,
|
kind: IdentifierKind.Variable,
|
||||||
span: new AbsoluteSourceSpan(17, 20),
|
span: new AbsoluteSourceSpan(17, 20),
|
||||||
}] as TopLevelIdentifier[]));
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover nested variables', () => {
|
it('should discover nested variables', () => {
|
||||||
|
@ -479,10 +481,10 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const refArray = Array.from(refs);
|
const refArray = Array.from(refs);
|
||||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
kind: IdentifierKind.Variable,
|
kind: IdentifierKind.Variable,
|
||||||
span: new AbsoluteSourceSpan(23, 26),
|
span: new AbsoluteSourceSpan(23, 26),
|
||||||
}] as TopLevelIdentifier[]));
|
}] as TopLevelIdentifier[]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should discover references to variables', () => {
|
it('should discover references to variables', () => {
|
||||||
|
|
|
@ -68,7 +68,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const info = analysis.get(decl);
|
const info = analysis.get(decl);
|
||||||
expect(info).toBeDefined();
|
expect(info).toBeDefined();
|
||||||
expect(info !.template.file)
|
expect(info!.template.file)
|
||||||
.toEqual(new ParseSourceFile('class C {}', util.getTestFilePath()));
|
.toEqual(new ParseSourceFile('class C {}', util.getTestFilePath()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const info = analysis.get(decl);
|
const info = analysis.get(decl);
|
||||||
expect(info).toBeDefined();
|
expect(info).toBeDefined();
|
||||||
expect(info !.template.file)
|
expect(info!.template.file)
|
||||||
.toEqual(new ParseSourceFile('<div>{{foo}}</div>', util.getTestFilePath()));
|
.toEqual(new ParseSourceFile('<div>{{foo}}</div>', util.getTestFilePath()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -110,11 +110,11 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const infoA = analysis.get(declA);
|
const infoA = analysis.get(declA);
|
||||||
expect(infoA).toBeDefined();
|
expect(infoA).toBeDefined();
|
||||||
expect(infoA !.template.usedComponents).toEqual(new Set([declB]));
|
expect(infoA!.template.usedComponents).toEqual(new Set([declB]));
|
||||||
|
|
||||||
const infoB = analysis.get(declB);
|
const infoB = analysis.get(declB);
|
||||||
expect(infoB).toBeDefined();
|
expect(infoB).toBeDefined();
|
||||||
expect(infoB !.template.usedComponents).toEqual(new Set([declA]));
|
expect(infoB!.template.usedComponents).toEqual(new Set([declA]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {BoundTarget, CssSelector, ParseTemplateOptions, R3TargetBinder, SelectorMatcher, parseTemplate} from '@angular/compiler';
|
import {BoundTarget, CssSelector, parseTemplate, ParseTemplateOptions, R3TargetBinder, SelectorMatcher} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {AbsoluteFsPath, absoluteFrom} from '../../file_system';
|
|
||||||
|
import {absoluteFrom, AbsoluteFsPath} from '../../file_system';
|
||||||
import {Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {ClassDeclaration} from '../../reflection';
|
import {ClassDeclaration} from '../../reflection';
|
||||||
import {getDeclaration, makeProgram} from '../../testing';
|
import {getDeclaration, makeProgram} from '../../testing';
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
|
||||||
|
|
||||||
import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta} from './api';
|
import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta} from './api';
|
||||||
import {extractDirectiveGuards, extractReferencesFromType, readStringArrayType, readStringMapType, readStringType} from './util';
|
import {extractDirectiveGuards, extractReferencesFromType, readStringArrayType, readStringMapType, readStringType} from './util';
|
||||||
|
|
|
@ -25,7 +25,7 @@ export function flattenInheritedDirectiveMetadata(
|
||||||
throw new Error(`Metadata not found for directive: ${dir.debugName}`);
|
throw new Error(`Metadata not found for directive: ${dir.debugName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputs: {[key: string]: string | [string, string]} = {};
|
let inputs: {[key: string]: string|[string, string]} = {};
|
||||||
let outputs: {[key: string]: string} = {};
|
let outputs: {[key: string]: string} = {};
|
||||||
let coercedInputFields = new Set<string>();
|
let coercedInputFields = new Set<string>();
|
||||||
let isDynamic = false;
|
let isDynamic = false;
|
||||||
|
|
|
@ -22,18 +22,24 @@ export class LocalMetadataRegistry implements MetadataRegistry, MetadataReader {
|
||||||
private pipes = new Map<ClassDeclaration, PipeMeta>();
|
private pipes = new Map<ClassDeclaration, PipeMeta>();
|
||||||
|
|
||||||
getDirectiveMetadata(ref: Reference<ClassDeclaration>): DirectiveMeta|null {
|
getDirectiveMetadata(ref: Reference<ClassDeclaration>): DirectiveMeta|null {
|
||||||
return this.directives.has(ref.node) ? this.directives.get(ref.node) ! : null;
|
return this.directives.has(ref.node) ? this.directives.get(ref.node)! : null;
|
||||||
}
|
}
|
||||||
getNgModuleMetadata(ref: Reference<ClassDeclaration>): NgModuleMeta|null {
|
getNgModuleMetadata(ref: Reference<ClassDeclaration>): NgModuleMeta|null {
|
||||||
return this.ngModules.has(ref.node) ? this.ngModules.get(ref.node) ! : null;
|
return this.ngModules.has(ref.node) ? this.ngModules.get(ref.node)! : null;
|
||||||
}
|
}
|
||||||
getPipeMetadata(ref: Reference<ClassDeclaration>): PipeMeta|null {
|
getPipeMetadata(ref: Reference<ClassDeclaration>): PipeMeta|null {
|
||||||
return this.pipes.has(ref.node) ? this.pipes.get(ref.node) ! : null;
|
return this.pipes.has(ref.node) ? this.pipes.get(ref.node)! : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerDirectiveMetadata(meta: DirectiveMeta): void { this.directives.set(meta.ref.node, meta); }
|
registerDirectiveMetadata(meta: DirectiveMeta): void {
|
||||||
registerNgModuleMetadata(meta: NgModuleMeta): void { this.ngModules.set(meta.ref.node, meta); }
|
this.directives.set(meta.ref.node, meta);
|
||||||
registerPipeMetadata(meta: PipeMeta): void { this.pipes.set(meta.ref.node, meta); }
|
}
|
||||||
|
registerNgModuleMetadata(meta: NgModuleMeta): void {
|
||||||
|
this.ngModules.set(meta.ref.node, meta);
|
||||||
|
}
|
||||||
|
registerPipeMetadata(meta: PipeMeta): void {
|
||||||
|
this.pipes.set(meta.ref.node, meta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,7 +76,9 @@ export class InjectableClassRegistry {
|
||||||
|
|
||||||
constructor(private host: ReflectionHost) {}
|
constructor(private host: ReflectionHost) {}
|
||||||
|
|
||||||
registerInjectable(declaration: ClassDeclaration): void { this.classes.add(declaration); }
|
registerInjectable(declaration: ClassDeclaration): void {
|
||||||
|
this.classes.add(declaration);
|
||||||
|
}
|
||||||
|
|
||||||
isInjectable(declaration: ClassDeclaration): boolean {
|
isInjectable(declaration: ClassDeclaration): boolean {
|
||||||
// Figure out whether the class is injectable based on the registered classes, otherwise
|
// Figure out whether the class is injectable based on the registered classes, otherwise
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Reference} from '../../imports';
|
import {Reference} from '../../imports';
|
||||||
import {ClassDeclaration, ClassMember, ClassMemberKind, ReflectionHost, isNamedClassDeclaration, reflectTypeEntityToDeclaration} from '../../reflection';
|
import {ClassDeclaration, ClassMember, ClassMemberKind, isNamedClassDeclaration, ReflectionHost, reflectTypeEntityToDeclaration} from '../../reflection';
|
||||||
import {nodeDebugInfo} from '../../util/src/typescript';
|
import {nodeDebugInfo} from '../../util/src/typescript';
|
||||||
|
|
||||||
import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta, TemplateGuardMeta} from './api';
|
import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta, TemplateGuardMeta} from './api';
|
||||||
|
|
||||||
export function extractReferencesFromType(
|
export function extractReferencesFromType(
|
||||||
checker: ts.TypeChecker, def: ts.TypeNode, ngModuleImportedFrom: string | null,
|
checker: ts.TypeChecker, def: ts.TypeNode, ngModuleImportedFrom: string|null,
|
||||||
resolutionContext: string): Reference<ClassDeclaration>[] {
|
resolutionContext: string): Reference<ClassDeclaration>[] {
|
||||||
if (!ts.isTupleTypeNode(def)) {
|
if (!ts.isTupleTypeNode(def)) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -122,7 +122,7 @@ function extractTemplateGuard(member: ClassMember): TemplateGuardMeta|null {
|
||||||
|
|
||||||
function extractCoercedInput(member: ClassMember): string|null {
|
function extractCoercedInput(member: ClassMember): string|null {
|
||||||
if (member.kind !== ClassMemberKind.Property || !member.name.startsWith('ngAcceptInputType_')) {
|
if (member.kind !== ClassMemberKind.Property || !member.name.startsWith('ngAcceptInputType_')) {
|
||||||
return null !;
|
return null!;
|
||||||
}
|
}
|
||||||
return afterUnderscore(member.name);
|
return afterUnderscore(member.name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ import {ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
||||||
import {PartialEvaluator, ResolvedValueMap} from '../../partial_evaluator';
|
import {PartialEvaluator, ResolvedValueMap} from '../../partial_evaluator';
|
||||||
import {ReflectionHost} from '../../reflection';
|
import {ReflectionHost} from '../../reflection';
|
||||||
|
|
||||||
export interface DtsHandler { addTypeReplacement(node: ts.Declaration, type: Type): void; }
|
export interface DtsHandler {
|
||||||
|
addTypeReplacement(node: ts.Declaration, type: Type): void;
|
||||||
|
}
|
||||||
|
|
||||||
export class ModuleWithProvidersScanner {
|
export class ModuleWithProvidersScanner {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -12,9 +12,11 @@ import {PerfRecorder} from './api';
|
||||||
|
|
||||||
export const NOOP_PERF_RECORDER: PerfRecorder = {
|
export const NOOP_PERF_RECORDER: PerfRecorder = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
mark: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string):
|
mark: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
||||||
void => {},
|
void => {},
|
||||||
start: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string):
|
start: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
||||||
number => { return 0;},
|
number => {
|
||||||
stop: (span: number | false): void => {},
|
return 0;
|
||||||
|
},
|
||||||
|
stop: (span: number|false): void => {},
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,9 @@ export class PerfTracker implements PerfRecorder {
|
||||||
|
|
||||||
private constructor(private zeroTime: HrTime) {}
|
private constructor(private zeroTime: HrTime) {}
|
||||||
|
|
||||||
static zeroedToNow(): PerfTracker { return new PerfTracker(mark()); }
|
static zeroedToNow(): PerfTracker {
|
||||||
|
return new PerfTracker(mark());
|
||||||
|
}
|
||||||
|
|
||||||
mark(name: string, node?: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
mark(name: string, node?: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
||||||
void {
|
void {
|
||||||
|
@ -73,7 +75,9 @@ export class PerfTracker implements PerfRecorder {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
asJson(): unknown { return this.log; }
|
asJson(): unknown {
|
||||||
|
return this.log;
|
||||||
|
}
|
||||||
|
|
||||||
serializeToFile(target: string, host: ts.CompilerHost): void {
|
serializeToFile(target: string, host: ts.CompilerHost): void {
|
||||||
const json = JSON.stringify(this.log, null, 2);
|
const json = JSON.stringify(this.log, null, 2);
|
||||||
|
|
|
@ -77,7 +77,9 @@ export class NgtscProgram implements api.Program {
|
||||||
new NgCompiler(this.host, options, this.tsProgram, reuseProgram, this.perfRecorder);
|
new NgCompiler(this.host, options, this.tsProgram, reuseProgram, this.perfRecorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTsProgram(): ts.Program { return this.tsProgram; }
|
getTsProgram(): ts.Program {
|
||||||
|
return this.tsProgram;
|
||||||
|
}
|
||||||
|
|
||||||
getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken|
|
getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken|
|
||||||
undefined): readonly ts.Diagnostic[] {
|
undefined): readonly ts.Diagnostic[] {
|
||||||
|
@ -137,8 +139,8 @@ export class NgtscProgram implements api.Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
getNgSemanticDiagnostics(
|
getNgSemanticDiagnostics(
|
||||||
fileName?: string|undefined, cancellationToken?: ts.CancellationToken|
|
fileName?: string|undefined, cancellationToken?: ts.CancellationToken|undefined):
|
||||||
undefined): readonly(ts.Diagnostic|api.Diagnostic)[] {
|
readonly(ts.Diagnostic|api.Diagnostic)[] {
|
||||||
let sf: ts.SourceFile|undefined = undefined;
|
let sf: ts.SourceFile|undefined = undefined;
|
||||||
if (fileName !== undefined) {
|
if (fileName !== undefined) {
|
||||||
sf = this.tsProgram.getSourceFile(fileName);
|
sf = this.tsProgram.getSourceFile(fileName);
|
||||||
|
@ -161,14 +163,17 @@ export class NgtscProgram implements api.Program {
|
||||||
* This is used by the Angular CLI to allow for spawning (async) child compilations for things
|
* This is used by the Angular CLI to allow for spawning (async) child compilations for things
|
||||||
* like SASS files used in `styleUrls`.
|
* like SASS files used in `styleUrls`.
|
||||||
*/
|
*/
|
||||||
loadNgStructureAsync(): Promise<void> { return this.compiler.analyzeAsync(); }
|
loadNgStructureAsync(): Promise<void> {
|
||||||
|
return this.compiler.analyzeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] {
|
listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] {
|
||||||
return this.compiler.listLazyRoutes(entryRoute);
|
return this.compiler.listLazyRoutes(entryRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(opts?: {
|
emit(opts?: {
|
||||||
emitFlags?: api.EmitFlags | undefined; cancellationToken?: ts.CancellationToken | undefined;
|
emitFlags?: api.EmitFlags|undefined;
|
||||||
|
cancellationToken?: ts.CancellationToken | undefined;
|
||||||
customTransformers?: api.CustomTransformers | undefined;
|
customTransformers?: api.CustomTransformers | undefined;
|
||||||
emitCallback?: api.TsEmitCallback | undefined;
|
emitCallback?: api.TsEmitCallback | undefined;
|
||||||
mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback | undefined;
|
mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback | undefined;
|
||||||
|
@ -179,8 +184,8 @@ export class NgtscProgram implements api.Program {
|
||||||
|
|
||||||
const writeFile: ts.WriteFileCallback =
|
const writeFile: ts.WriteFileCallback =
|
||||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||||
onError: ((message: string) => void) | undefined,
|
onError: ((message: string) => void)|undefined,
|
||||||
sourceFiles: ReadonlyArray<ts.SourceFile>| undefined) => {
|
sourceFiles: ReadonlyArray<ts.SourceFile>|undefined) => {
|
||||||
if (sourceFiles !== undefined) {
|
if (sourceFiles !== undefined) {
|
||||||
// Record successful writes for any `ts.SourceFile` (that's not a declaration file)
|
// Record successful writes for any `ts.SourceFile` (that's not a declaration file)
|
||||||
// that's an input to this write.
|
// that's an input to this write.
|
||||||
|
@ -221,7 +226,8 @@ export class NgtscProgram implements api.Program {
|
||||||
program: this.tsProgram,
|
program: this.tsProgram,
|
||||||
host: this.host,
|
host: this.host,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
emitOnlyDtsFiles: false, writeFile,
|
emitOnlyDtsFiles: false,
|
||||||
|
writeFile,
|
||||||
customTransformers: {
|
customTransformers: {
|
||||||
before: beforeTransforms,
|
before: beforeTransforms,
|
||||||
after: customTransforms && customTransforms.afterTs,
|
after: customTransforms && customTransforms.afterTs,
|
||||||
|
@ -257,11 +263,16 @@ export class NgtscProgram implements api.Program {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultEmitCallback: api.TsEmitCallback =
|
const defaultEmitCallback: api.TsEmitCallback = ({
|
||||||
({program, targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles,
|
program,
|
||||||
customTransformers}) =>
|
targetSourceFile,
|
||||||
program.emit(
|
writeFile,
|
||||||
targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
cancellationToken,
|
||||||
|
emitOnlyDtsFiles,
|
||||||
|
customTransformers
|
||||||
|
}) =>
|
||||||
|
program.emit(
|
||||||
|
targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||||
|
|
||||||
function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult {
|
function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult {
|
||||||
const diagnostics: ts.Diagnostic[] = [];
|
const diagnostics: ts.Diagnostic[] = [];
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
||||||
* Metadata extracted from an instance of a decorator on another declaration, or synthesized from
|
* Metadata extracted from an instance of a decorator on another declaration, or synthesized from
|
||||||
* other information about a class.
|
* other information about a class.
|
||||||
*/
|
*/
|
||||||
export type Decorator = ConcreteDecorator | SyntheticDecorator;
|
export type Decorator = ConcreteDecorator|SyntheticDecorator;
|
||||||
|
|
||||||
export interface BaseDecorator {
|
export interface BaseDecorator {
|
||||||
/**
|
/**
|
||||||
|
@ -28,11 +28,11 @@ export interface BaseDecorator {
|
||||||
*/
|
*/
|
||||||
identifier: DecoratorIdentifier|null;
|
identifier: DecoratorIdentifier|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `Import` by which the decorator was brought into the module in which it was invoked, or `null`
|
* `Import` by which the decorator was brought into the module in which it was invoked, or `null`
|
||||||
* if the decorator was declared in the same module and not imported.
|
* if the decorator was declared in the same module and not imported.
|
||||||
*/
|
*/
|
||||||
import : Import | null;
|
import: Import|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TypeScript reference to the decorator itself, or `null` if the decorator is synthesized (e.g.
|
* TypeScript reference to the decorator itself, or `null` if the decorator is synthesized (e.g.
|
||||||
|
@ -87,8 +87,8 @@ export const Decorator = {
|
||||||
* A decorator is identified by either a simple identifier (e.g. `Decorator`) or, in some cases,
|
* A decorator is identified by either a simple identifier (e.g. `Decorator`) or, in some cases,
|
||||||
* a namespaced property access (e.g. `core.Decorator`).
|
* a namespaced property access (e.g. `core.Decorator`).
|
||||||
*/
|
*/
|
||||||
export type DecoratorIdentifier = ts.Identifier | NamespacedIdentifier;
|
export type DecoratorIdentifier = ts.Identifier|NamespacedIdentifier;
|
||||||
export type NamespacedIdentifier = ts.PropertyAccessExpression & {
|
export type NamespacedIdentifier = ts.PropertyAccessExpression&{
|
||||||
expression: ts.Identifier;
|
expression: ts.Identifier;
|
||||||
name: ts.Identifier
|
name: ts.Identifier
|
||||||
};
|
};
|
||||||
|
@ -113,7 +113,7 @@ export function isDecoratorIdentifier(exp: ts.Expression): exp is DecoratorIdent
|
||||||
* For `ReflectionHost` purposes, a class declaration should always have a `name` identifier,
|
* For `ReflectionHost` purposes, a class declaration should always have a `name` identifier,
|
||||||
* because we need to be able to reference it in other parts of the program.
|
* because we need to be able to reference it in other parts of the program.
|
||||||
*/
|
*/
|
||||||
export type ClassDeclaration<T extends ts.Declaration = ts.Declaration> = T & {name: ts.Identifier};
|
export type ClassDeclaration<T extends ts.Declaration = ts.Declaration> = T&{name: ts.Identifier};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enumeration of possible kinds of class members.
|
* An enumeration of possible kinds of class members.
|
||||||
|
@ -241,8 +241,7 @@ export interface ClassMember {
|
||||||
*/
|
*/
|
||||||
export type TypeValueReference = {
|
export type TypeValueReference = {
|
||||||
local: true; expression: ts.Expression; defaultImportStatement: ts.ImportDeclaration | null;
|
local: true; expression: ts.Expression; defaultImportStatement: ts.ImportDeclaration | null;
|
||||||
} |
|
}|{
|
||||||
{
|
|
||||||
local: false;
|
local: false;
|
||||||
name: string;
|
name: string;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
|
@ -447,7 +446,7 @@ export interface InlineDeclaration extends BaseDeclaration {
|
||||||
* downlevelings to a `ts.Expression` instead.
|
* downlevelings to a `ts.Expression` instead.
|
||||||
*/
|
*/
|
||||||
export type Declaration<T extends ts.Declaration = ts.Declaration> =
|
export type Declaration<T extends ts.Declaration = ts.Declaration> =
|
||||||
ConcreteDeclaration<T>| InlineDeclaration;
|
ConcreteDeclaration<T>|InlineDeclaration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstracts reflection operations on a TypeScript AST.
|
* Abstracts reflection operations on a TypeScript AST.
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {TypeValueReference} from './host';
|
||||||
* declaration, or if it is not possible to statically understand.
|
* declaration, or if it is not possible to statically understand.
|
||||||
*/
|
*/
|
||||||
export function typeToValue(
|
export function typeToValue(
|
||||||
typeNode: ts.TypeNode | null, checker: ts.TypeChecker): TypeValueReference|null {
|
typeNode: ts.TypeNode|null, checker: ts.TypeChecker): TypeValueReference|null {
|
||||||
// It's not possible to get a value expression if the parameter doesn't even have a type.
|
// It's not possible to get a value expression if the parameter doesn't even have a type.
|
||||||
if (typeNode === null || !ts.isTypeReferenceNode(typeNode)) {
|
if (typeNode === null || !ts.isTypeReferenceNode(typeNode)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -95,7 +95,7 @@ export function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression|null {
|
||||||
* give the identifier name within the current file by which the import is known.
|
* give the identifier name within the current file by which the import is known.
|
||||||
*/
|
*/
|
||||||
function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeChecker):
|
function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeChecker):
|
||||||
{local: ts.Symbol, decl: ts.Symbol, importName: string | null}|null {
|
{local: ts.Symbol, decl: ts.Symbol, importName: string|null}|null {
|
||||||
const typeName = typeRef.typeName;
|
const typeName = typeRef.typeName;
|
||||||
// typeRefSymbol is the ts.Symbol of the entire type reference.
|
// typeRefSymbol is the ts.Symbol of the entire type reference.
|
||||||
const typeRefSymbol: ts.Symbol|undefined = checker.getSymbolAtLocation(typeName);
|
const typeRefSymbol: ts.Symbol|undefined = checker.getSymbolAtLocation(typeName);
|
||||||
|
@ -156,8 +156,8 @@ function isImportSource(node: ts.Declaration): node is(ts.ImportSpecifier | ts.N
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractModuleAndNameFromImport(
|
function extractModuleAndNameFromImport(
|
||||||
node: ts.ImportSpecifier | ts.NamespaceImport | ts.ImportClause,
|
node: ts.ImportSpecifier|ts.NamespaceImport|ts.ImportClause,
|
||||||
localName: string | null): {name: string, moduleName: string} {
|
localName: string|null): {name: string, moduleName: string} {
|
||||||
let name: string;
|
let name: string;
|
||||||
let moduleSpecifier: ts.Expression;
|
let moduleSpecifier: ts.Expression;
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost, isDecoratorIdentifier} from './host';
|
import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, isDecoratorIdentifier, ReflectionHost} from './host';
|
||||||
import {typeToValue} from './type_to_value';
|
import {typeToValue} from './type_to_value';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,8 +76,10 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
nameNode: node.name, typeValueReference,
|
nameNode: node.name,
|
||||||
typeNode: originalTypeNode, decorators,
|
typeValueReference,
|
||||||
|
typeNode: originalTypeNode,
|
||||||
|
decorators,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -183,11 +185,17 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
return declaration.initializer || null;
|
return declaration.initializer || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDtsDeclaration(_: ts.Declaration): ts.Declaration|null { return null; }
|
getDtsDeclaration(_: ts.Declaration): ts.Declaration|null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier { return clazz.name; }
|
getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier {
|
||||||
|
return clazz.name;
|
||||||
|
}
|
||||||
|
|
||||||
getAdjacentNameOfClass(clazz: ClassDeclaration): ts.Identifier { return clazz.name; }
|
getAdjacentNameOfClass(clazz: ClassDeclaration): ts.Identifier {
|
||||||
|
return clazz.name;
|
||||||
|
}
|
||||||
|
|
||||||
protected getDirectImportOfIdentifier(id: ts.Identifier): Import|null {
|
protected getDirectImportOfIdentifier(id: ts.Identifier): Import|null {
|
||||||
const symbol = this.checker.getSymbolAtLocation(id);
|
const symbol = this.checker.getSymbolAtLocation(id);
|
||||||
|
@ -305,12 +313,14 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
if (symbol.valueDeclaration !== undefined) {
|
if (symbol.valueDeclaration !== undefined) {
|
||||||
return {
|
return {
|
||||||
node: symbol.valueDeclaration,
|
node: symbol.valueDeclaration,
|
||||||
known: null, viaModule,
|
known: null,
|
||||||
|
viaModule,
|
||||||
};
|
};
|
||||||
} else if (symbol.declarations !== undefined && symbol.declarations.length > 0) {
|
} else if (symbol.declarations !== undefined && symbol.declarations.length > 0) {
|
||||||
return {
|
return {
|
||||||
node: symbol.declarations[0],
|
node: symbol.declarations[0],
|
||||||
known: null, viaModule,
|
known: null,
|
||||||
|
viaModule,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -342,7 +352,9 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
return {
|
return {
|
||||||
name: decoratorIdentifier.text,
|
name: decoratorIdentifier.text,
|
||||||
identifier: decoratorExpr,
|
identifier: decoratorExpr,
|
||||||
import: importDecl, node, args,
|
import: importDecl,
|
||||||
|
node,
|
||||||
|
args,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,8 +394,14 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
implementation: node, kind,
|
implementation: node,
|
||||||
type: node.type || null, name, nameNode, decorators, value, isStatic,
|
kind,
|
||||||
|
type: node.type || null,
|
||||||
|
name,
|
||||||
|
nameNode,
|
||||||
|
decorators,
|
||||||
|
value,
|
||||||
|
isStatic,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +423,7 @@ export function reflectIdentifierOfDeclaration(decl: ts.Declaration): ts.Identif
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reflectTypeEntityToDeclaration(
|
export function reflectTypeEntityToDeclaration(
|
||||||
type: ts.EntityName, checker: ts.TypeChecker): {node: ts.Declaration, from: string | null} {
|
type: ts.EntityName, checker: ts.TypeChecker): {node: ts.Declaration, from: string|null} {
|
||||||
let realSymbol = checker.getSymbolAtLocation(type);
|
let realSymbol = checker.getSymbolAtLocation(type);
|
||||||
if (realSymbol === undefined) {
|
if (realSymbol === undefined) {
|
||||||
throw new Error(`Cannot resolve type entity ${type.getText()} to symbol`);
|
throw new Error(`Cannot resolve type entity ${type.getText()} to symbol`);
|
||||||
|
@ -434,8 +452,8 @@ export function reflectTypeEntityToDeclaration(
|
||||||
}
|
}
|
||||||
const decl = symbol.declarations[0];
|
const decl = symbol.declarations[0];
|
||||||
if (ts.isNamespaceImport(decl)) {
|
if (ts.isNamespaceImport(decl)) {
|
||||||
const clause = decl.parent !;
|
const clause = decl.parent!;
|
||||||
const importDecl = clause.parent !;
|
const importDecl = clause.parent!;
|
||||||
if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
||||||
throw new Error(`Module specifier is not a string`);
|
throw new Error(`Module specifier is not a string`);
|
||||||
}
|
}
|
||||||
|
@ -552,7 +570,7 @@ function getFarLeftIdentifier(propertyAccess: ts.PropertyAccessExpression): ts.I
|
||||||
* `NamespaceImport`. If not return `null`.
|
* `NamespaceImport`. If not return `null`.
|
||||||
*/
|
*/
|
||||||
function getContainingImportDeclaration(node: ts.Node): ts.ImportDeclaration|null {
|
function getContainingImportDeclaration(node: ts.Node): ts.ImportDeclaration|null {
|
||||||
return ts.isImportSpecifier(node) ? node.parent !.parent !.parent ! :
|
return ts.isImportSpecifier(node) ? node.parent!.parent!.parent! :
|
||||||
ts.isNamespaceImport(node) ? node.parent.parent : null;
|
ts.isNamespaceImport(node) ? node.parent.parent : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue