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 {
|
||||
found: boolean;
|
||||
constructor(service: ShakeableService) { this.found = !!service.normal; }
|
||||
constructor(service: ShakeableService) {
|
||||
this.found = !!service.normal;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -29,7 +29,9 @@ export class AppComponent {
|
|||
export class ChildComponent {
|
||||
found: boolean;
|
||||
|
||||
constructor(@Optional() @Self() service: Service|null) { this.found = !!service; }
|
||||
constructor(@Optional() @Self() service: Service|null) {
|
||||
this.found = !!service;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -21,7 +21,9 @@ export class NormalService {
|
|||
})
|
||||
export class AppComponent {
|
||||
found: boolean;
|
||||
constructor(service: NormalService) { this.found = !!service.shakeable; }
|
||||
constructor(service: NormalService) {
|
||||
this.found = !!service.shakeable;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -17,7 +17,9 @@ import {ServerModule} from '@angular/platform-server';
|
|||
})
|
||||
export class AppComponent {
|
||||
data: string;
|
||||
constructor(service: Service) { this.data = service.data; }
|
||||
constructor(service: Service) {
|
||||
this.data = service.data;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
* 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 {ServerModule} from '@angular/platform-server';
|
||||
|
||||
export interface IService { readonly dep: {readonly data: string;}; }
|
||||
export interface IService {
|
||||
readonly dep: {readonly data: string;};
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class TokenModule {
|
||||
|
@ -28,7 +30,9 @@ export const TOKEN = new InjectionToken('test', {
|
|||
})
|
||||
export class AppComponent {
|
||||
data: string;
|
||||
constructor(@Inject(TOKEN) service: IService) { this.data = service.dep.data; }
|
||||
constructor(@Inject(TOKEN) service: IService) {
|
||||
this.data = service.dep.data;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {renderModuleFactory} from '@angular/platform-server';
|
||||
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', () => {
|
||||
|
||||
@NgModule()
|
||||
class Module {
|
||||
}
|
||||
|
@ -172,7 +171,9 @@ describe('ngInjectableDef Bazel Integration', () => {
|
|||
|
||||
// ChildServices exteds ParentService but does not have @Injectable
|
||||
class ChildService extends ParentService {
|
||||
constructor(value: string) { super(value); }
|
||||
constructor(value: string) {
|
||||
super(value);
|
||||
}
|
||||
static ngInjectableDef = {
|
||||
providedIn: 'root',
|
||||
factory: () => new ChildService('child'),
|
||||
|
|
|
@ -6,17 +6,23 @@
|
|||
* 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';
|
||||
|
||||
describe('Ivy NgModule', () => {
|
||||
describe('AOT', () => {
|
||||
let injector: Injector;
|
||||
|
||||
beforeEach(() => { injector = createInjector(AotModule); });
|
||||
it('works', () => { expect(injector.get(AotService) instanceof AotService).toBeTruthy(); });
|
||||
beforeEach(() => {
|
||||
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 {
|
||||
}
|
||||
|
||||
it('works', () => { createInjector(JitAppModule); });
|
||||
it('works', () => {
|
||||
createInjector(JitAppModule);
|
||||
});
|
||||
|
||||
it('throws an error on circular module dependencies', () => {
|
||||
@NgModule({
|
||||
|
|
|
@ -16,10 +16,8 @@ export class LazyFeatureComponent {
|
|||
@NgModule({
|
||||
imports: [RouterModule.forChild([
|
||||
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
|
||||
{path: 'feature', loadChildren: './feature.module#FeatureModule'}, {
|
||||
path: 'nested-feature',
|
||||
loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'
|
||||
}
|
||||
{path: 'feature', loadChildren: './feature.module#FeatureModule'},
|
||||
{path: 'nested-feature', loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'}
|
||||
])],
|
||||
declarations: [LazyFeatureComponent]
|
||||
})
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {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';
|
||||
|
||||
@Component({
|
||||
|
@ -30,8 +30,16 @@ import {Component} from '@angular/core';
|
|||
})
|
||||
export class AnimateCmp {
|
||||
stateExpression: string;
|
||||
constructor() { this.setAsClosed(); }
|
||||
setAsSomethingElse() { this.stateExpression = 'something'; }
|
||||
setAsOpen() { this.stateExpression = 'open'; }
|
||||
setAsClosed() { this.stateExpression = 'closed'; }
|
||||
constructor() {
|
||||
this.setAsClosed();
|
||||
}
|
||||
setAsSomethingElse() {
|
||||
this.stateExpression = 'something';
|
||||
}
|
||||
setAsOpen() {
|
||||
this.stateExpression = 'open';
|
||||
}
|
||||
setAsClosed() {
|
||||
this.stateExpression = 'closed';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
import {InjectionToken} from '@angular/core';
|
||||
|
||||
export interface Named { name: string; }
|
||||
export interface Named {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const CUSTOM = new InjectionToken<Named>('CUSTOM');
|
||||
|
|
|
@ -10,5 +10,7 @@ import {Component} from '@angular/core';
|
|||
|
||||
@Component({selector: 'comp-with-error', templateUrl: 'errors.html'})
|
||||
export class BindingErrorComp {
|
||||
createError() { throw new Error('Test'); }
|
||||
createError() {
|
||||
throw new Error('Test');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
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 {wrapInArray} from './funcs';
|
||||
|
@ -62,7 +62,9 @@ export class CompUsingCustomElements {
|
|||
})
|
||||
export class CompConsumingEvents {
|
||||
handleDomEventVoid(e: any): void {}
|
||||
handleDomEventPreventDefault(e: any): boolean { return false; }
|
||||
handleDomEventPreventDefault(e: any): boolean {
|
||||
return false;
|
||||
}
|
||||
handleDirEvent(e: any): void {}
|
||||
}
|
||||
|
||||
|
@ -70,8 +72,7 @@ export class CompConsumingEvents {
|
|||
selector: '[dirEvent]',
|
||||
})
|
||||
export class DirPublishingEvents {
|
||||
@Output('dirEvent')
|
||||
dirEvent: Observable<string> = new EventEmitter();
|
||||
@Output('dirEvent') dirEvent: Observable<string> = new EventEmitter();
|
||||
}
|
||||
|
||||
@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>();
|
||||
|
||||
export function expectInstanceCreated(type: any) {
|
||||
const instance = instances.get(type) !;
|
||||
const instance = instances.get(type)!;
|
||||
expect(instance).toBeDefined();
|
||||
expect(instance.dep instanceof SomeDep).toBe(true);
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ export function expectInstanceCreated(type: any) {
|
|||
export class SomeDep {}
|
||||
|
||||
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'})
|
||||
|
@ -36,7 +38,9 @@ export class SomeDirective extends Base {
|
|||
|
||||
@Pipe({name: 'somePipe'})
|
||||
export class SomePipe extends Base {
|
||||
transform(value: any) { return value; }
|
||||
transform(value: any) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {ServerModule} from '@angular/platform-server';
|
||||
import {FlatModule} from 'flat_module';
|
||||
|
|
|
@ -19,24 +19,26 @@ export class ServiceUsingLibModule {
|
|||
|
||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||
export class SomeDirectiveInRootModule {
|
||||
@Input()
|
||||
someDir: string;
|
||||
@Input() someDir: string;
|
||||
}
|
||||
|
||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||
export class SomeDirectiveInLibModule {
|
||||
@Input()
|
||||
someDir: string;
|
||||
@Input() someDir: string;
|
||||
}
|
||||
|
||||
@Pipe({name: 'somePipe'})
|
||||
export class SomePipeInRootModule {
|
||||
transform(value: string): any { return `transformed ${value}`; }
|
||||
transform(value: string): any {
|
||||
return `transformed ${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@Pipe({name: 'somePipe'})
|
||||
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>`})
|
||||
|
@ -66,8 +68,8 @@ export class SomeLibModule {
|
|||
return {
|
||||
ngModule: SomeLibModule,
|
||||
providers: [
|
||||
ServiceUsingLibModule, provideValueWithEntryComponents(
|
||||
[{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
||||
ServiceUsingLibModule,
|
||||
provideValueWithEntryComponents([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
import {Component} from '@angular/core';
|
||||
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';
|
||||
|
||||
describe('Jit Summaries', () => {
|
||||
|
@ -18,7 +18,9 @@ describe('Jit Summaries', () => {
|
|||
TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting(), SomeModuleNgSummary);
|
||||
});
|
||||
|
||||
afterEach(() => { TestBed.resetTestEnvironment(); });
|
||||
afterEach(() => {
|
||||
TestBed.resetTestEnvironment();
|
||||
});
|
||||
|
||||
it('should use directive metadata from summaries', () => {
|
||||
@Component({template: '<div someDir></div>'})
|
||||
|
|
|
@ -10,7 +10,7 @@ import './init';
|
|||
import {ComponentUsingThirdParty} from '../src/comp_using_3rdp';
|
||||
import {ComponentUsingFlatModule} from '../src/comp_using_flat_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';
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ describe('child queries', () => {
|
|||
debugElement.query(By.directive(CompWithChildQuery));
|
||||
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
|
||||
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
|
||||
|
||||
});
|
||||
|
||||
it('should support compiling children queries', () => {
|
||||
|
|
|
@ -31,7 +31,7 @@ function getSourcePositionForStack(stack: string): {source: string, line: number
|
|||
const htmlLocations = stack
|
||||
.split('\n')
|
||||
// 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)
|
||||
.map(match => ({
|
||||
source: match[1],
|
||||
|
|
|
@ -22,10 +22,15 @@ import {createProgram, readConfiguration} from '@angular/compiler-cli';
|
|||
* properly read and wrote.
|
||||
*/
|
||||
function main() {
|
||||
Promise.resolve().then(() => lazyRoutesTest()).then(() => { process.exit(0); }).catch((err) => {
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
Promise.resolve()
|
||||
.then(() => lazyRoutesTest())
|
||||
.then(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
function lazyRoutesTest() {
|
||||
|
@ -36,7 +41,8 @@ function lazyRoutesTest() {
|
|||
const host = ts.createCompilerHost(config.options, true);
|
||||
const program = createProgram({
|
||||
rootNames: config.rootNames,
|
||||
options: config.options, host,
|
||||
options: config.options,
|
||||
host,
|
||||
});
|
||||
|
||||
config.options.basePath = basePath;
|
||||
|
|
|
@ -13,7 +13,7 @@ import {platformServerTesting} from '@angular/platform-server/testing';
|
|||
import {MainModule} from '../src/module';
|
||||
import {MainModuleNgFactory} from '../src/module.ngfactory';
|
||||
|
||||
let mainModuleRef: NgModuleRef<MainModule> = null !;
|
||||
let mainModuleRef: NgModuleRef<MainModule> = null!;
|
||||
beforeEach((done) => {
|
||||
platformServerTesting().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
|
||||
mainModuleRef = moduleRef;
|
||||
|
|
|
@ -35,7 +35,8 @@ export function translateDiagnostics(
|
|||
const fileName = span.start.file.url;
|
||||
ng.push({
|
||||
messageText: diagnosticMessageToString(diagnostic.messageText),
|
||||
category: diagnostic.category, span,
|
||||
category: diagnostic.category,
|
||||
span,
|
||||
source: SOURCE,
|
||||
code: DEFAULT_ERROR_CODE
|
||||
});
|
||||
|
@ -53,6 +54,6 @@ function sourceSpanOf(host: TypeCheckHost, source: ts.SourceFile, start: number)
|
|||
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');
|
||||
}
|
||||
|
|
|
@ -16,4 +16,4 @@ to the language service.
|
|||
*/
|
||||
export {MetadataCollector, ModuleMetadata} from './metadata';
|
||||
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(
|
||||
args: string[], consoleError: (s: string) => void = console.error,
|
||||
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} =
|
||||
config || readNgcCommandLineAndConfiguration(args);
|
||||
if (configErrors.length) {
|
||||
|
@ -47,7 +47,9 @@ export function main(
|
|||
options,
|
||||
emitFlags,
|
||||
oldProgram,
|
||||
emitCallback: createEmitCallback(options), customTransformers, modifiedResourceFiles
|
||||
emitCallback: createEmitCallback(options),
|
||||
customTransformers,
|
||||
modifiedResourceFiles
|
||||
});
|
||||
if (programReuse !== undefined) {
|
||||
programReuse.program = program;
|
||||
|
@ -57,8 +59,8 @@ export function main(
|
|||
|
||||
export function mainDiagnosticsForTest(
|
||||
args: string[], config?: NgcParsedConfiguration,
|
||||
programReuse?: {program: api.Program | undefined},
|
||||
modifiedResourceFiles?: Set<string>| null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> {
|
||||
programReuse?: {program: api.Program|undefined},
|
||||
modifiedResourceFiles?: Set<string>|null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> {
|
||||
let {project, rootNames, options, errors: configErrors, watch, emitFlags} =
|
||||
config || readNgcCommandLineAndConfiguration(args);
|
||||
if (configErrors.length) {
|
||||
|
@ -100,9 +102,10 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un
|
|||
options.emitDecoratorMetadata = true;
|
||||
}
|
||||
const tsickleHost: Pick<
|
||||
tsickle.TsickleHost, 'shouldSkipTsickleProcessing'|'pathToModuleName'|
|
||||
'shouldIgnoreWarningsForPath'|'fileNameToModuleId'|'googmodule'|'untyped'|
|
||||
'convertIndexImportShorthand'|'transformDecorators'|'transformTypesToClosure'> = {
|
||||
tsickle.TsickleHost,
|
||||
'shouldSkipTsickleProcessing'|'pathToModuleName'|'shouldIgnoreWarningsForPath'|
|
||||
'fileNameToModuleId'|'googmodule'|'untyped'|'convertIndexImportShorthand'|
|
||||
'transformDecorators'|'transformTypesToClosure'> = {
|
||||
shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName) ||
|
||||
// View Engine's generated files were never intended to be processed with tsickle.
|
||||
(!options.enableIvy && GENERATED_FILES.test(fileName)),
|
||||
|
@ -111,7 +114,9 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un
|
|||
fileNameToModuleId: (fileName) => fileName,
|
||||
googmodule: false,
|
||||
untyped: true,
|
||||
convertIndexImportShorthand: false, transformDecorators, transformTypesToClosure,
|
||||
convertIndexImportShorthand: false,
|
||||
transformDecorators,
|
||||
transformTypesToClosure,
|
||||
};
|
||||
|
||||
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 {
|
||||
const options: api.CompilerOptions = {};
|
||||
|
@ -194,7 +201,8 @@ export function readCommandLineAndConfiguration(
|
|||
}
|
||||
return {
|
||||
project,
|
||||
rootNames: config.rootNames, options,
|
||||
rootNames: config.rootNames,
|
||||
options,
|
||||
errors: config.errors,
|
||||
emitFlags: config.emitFlags
|
||||
};
|
||||
|
@ -237,7 +245,7 @@ export function watchMode(
|
|||
|
||||
function printDiagnostics(
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,7 @@ function createSyntheticIndexHost<H extends ts.CompilerHost>(
|
|||
|
||||
newHost.writeFile =
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
onError: ((message: string) => void) | undefined,
|
||||
sourceFiles: Readonly<ts.SourceFile>[]) => {
|
||||
onError: ((message: string) => void)|undefined, sourceFiles: Readonly<ts.SourceFile>[]) => {
|
||||
delegate.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
if (fileName.match(DTS) && sourceFiles && sourceFiles.length == 1 &&
|
||||
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
|
||||
// with associated transforms, so the metadata will have lowered expressions, resource inlining,
|
||||
// etc.
|
||||
const getMetadataBundle = (cache: MetadataCache | null) => {
|
||||
const getMetadataBundle = (cache: MetadataCache|null) => {
|
||||
const bundler = new MetadataBundler(
|
||||
indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host, cache, ngOptions),
|
||||
ngOptions.flatModulePrivateSymbolPrefix);
|
||||
|
@ -113,7 +112,7 @@ export function createBundleIndexHost<H extends ts.CompilerHost>(
|
|||
// First, produce the bundle with no MetadataCache.
|
||||
const metadataBundle = getMetadataBundle(/* MetadataCache */ null);
|
||||
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 content = privateEntriesToIndex(libraryIndex, metadataBundle.privates);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
|||
import {MetadataCache} from '../transformers/metadata_cache';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export interface BundleEntries { [name: string]: MetadataEntry; }
|
||||
export interface BundleEntries {
|
||||
[name: string]: MetadataEntry;
|
||||
}
|
||||
|
||||
export interface BundlePrivateEntry {
|
||||
privateName: string;
|
||||
|
@ -77,7 +79,7 @@ export interface MetadataBundlerHost {
|
|||
}
|
||||
|
||||
type StaticsMetadata = {
|
||||
[name: string]: MetadataValue | FunctionMetadata;
|
||||
[name: string]: MetadataValue|FunctionMetadata;
|
||||
};
|
||||
|
||||
export class MetadataBundler {
|
||||
|
@ -87,7 +89,7 @@ export class MetadataBundler {
|
|||
private rootModule: string;
|
||||
private privateSymbolPrefix: string;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private exported !: Set<Symbol>;
|
||||
private exported!: Set<Symbol>;
|
||||
|
||||
constructor(
|
||||
private root: string, private importAs: string|undefined, private host: MetadataBundlerHost,
|
||||
|
@ -106,14 +108,14 @@ export class MetadataBundler {
|
|||
const privates = Array.from(this.symbolMap.values())
|
||||
.filter(s => s.referenced && s.isPrivate)
|
||||
.map(s => ({
|
||||
privateName: s.privateName !,
|
||||
name: s.declaration !.name,
|
||||
module: s.declaration !.module
|
||||
privateName: s.privateName!,
|
||||
name: s.declaration!.name,
|
||||
module: s.declaration!.module
|
||||
}));
|
||||
const origins = Array.from(this.symbolMap.values())
|
||||
.filter(s => s.referenced && !s.reexport)
|
||||
.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;
|
||||
}, {});
|
||||
const exports = this.getReExports(exportedSymbols);
|
||||
|
@ -121,8 +123,10 @@ export class MetadataBundler {
|
|||
metadata: {
|
||||
__symbolic: 'module',
|
||||
version: METADATA_VERSION,
|
||||
exports: exports.length ? exports : undefined, metadata, origins,
|
||||
importAs: this.importAs !
|
||||
exports: exports.length ? exports : undefined,
|
||||
metadata,
|
||||
origins,
|
||||
importAs: this.importAs!
|
||||
},
|
||||
privates
|
||||
};
|
||||
|
@ -156,7 +160,7 @@ export class MetadataBundler {
|
|||
|
||||
const exportSymbol = (exportedSymbol: Symbol, exportAs: string) => {
|
||||
const symbol = this.symbolOf(moduleName, exportAs);
|
||||
result !.push(symbol);
|
||||
result!.push(symbol);
|
||||
exportedSymbol.reexportedAs = symbol;
|
||||
symbol.exports = exportedSymbol;
|
||||
};
|
||||
|
@ -276,18 +280,18 @@ export class MetadataBundler {
|
|||
Array.from(this.symbolMap.values()).forEach(symbol => {
|
||||
if (symbol.referenced && !symbol.reexport) {
|
||||
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) {
|
||||
name = newPrivateName(this.privateSymbolPrefix);
|
||||
symbol.privateName = name;
|
||||
}
|
||||
if (symbolsMap.has(identifier)) {
|
||||
const names = symbolsMap.get(identifier);
|
||||
names !.push(name);
|
||||
names!.push(name);
|
||||
} else {
|
||||
symbolsMap.set(identifier, [name]);
|
||||
}
|
||||
result[name] = symbol.value !;
|
||||
result[name] = symbol.value!;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -320,9 +324,9 @@ export class MetadataBundler {
|
|||
for (const symbol of exportedSymbols) {
|
||||
if (symbol.reexport) {
|
||||
// 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;
|
||||
if (declaration !.name == '*') {
|
||||
if (declaration!.name == '*') {
|
||||
// Reexport all the symbols.
|
||||
exportAlls.add(declaration.module);
|
||||
} else {
|
||||
|
@ -346,12 +350,12 @@ export class MetadataBundler {
|
|||
|
||||
private convertSymbol(symbol: Symbol) {
|
||||
// canonicalSymbol is ensured to be defined before this is called.
|
||||
const canonicalSymbol = symbol.canonicalSymbol !;
|
||||
const canonicalSymbol = symbol.canonicalSymbol!;
|
||||
|
||||
if (!canonicalSymbol.referenced) {
|
||||
canonicalSymbol.referenced = true;
|
||||
// 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);
|
||||
if (module) {
|
||||
const value = module.metadata[declaration.name];
|
||||
|
@ -399,11 +403,11 @@ export class MetadataBundler {
|
|||
private convertMember(moduleName: string, member: MemberMetadata) {
|
||||
const result: MemberMetadata = {__symbolic: member.__symbolic};
|
||||
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)) {
|
||||
(result as MethodMetadata).parameterDecorators = member.parameterDecorators &&
|
||||
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 (member.parameters) {
|
||||
(result as ConstructorMetadata).parameters =
|
||||
|
@ -450,7 +454,7 @@ export class MetadataBundler {
|
|||
return this.convertError(moduleName, value);
|
||||
}
|
||||
if (isMetadataSymbolicExpression(value)) {
|
||||
return this.convertExpression(moduleName, value) !;
|
||||
return this.convertExpression(moduleName, value)!;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(v => this.convertValue(moduleName, v));
|
||||
|
@ -466,8 +470,8 @@ export class MetadataBundler {
|
|||
}
|
||||
|
||||
private convertExpression(
|
||||
moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|
|
||||
undefined): MetadataSymbolicExpression|MetadataError|undefined|null {
|
||||
moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|undefined):
|
||||
MetadataSymbolicExpression|MetadataError|undefined|null {
|
||||
if (value) {
|
||||
switch (value.__symbolic) {
|
||||
case 'error':
|
||||
|
@ -487,14 +491,15 @@ export class MetadataBundler {
|
|||
message: value.message,
|
||||
line: value.line,
|
||||
character: value.character,
|
||||
context: value.context, module
|
||||
context: value.context,
|
||||
module
|
||||
};
|
||||
}
|
||||
|
||||
private convertReference(moduleName: string, value: MetadataSymbolicReferenceExpression):
|
||||
MetadataSymbolicReferenceExpression|MetadataError|undefined {
|
||||
const createReference = (symbol: Symbol): MetadataSymbolicReferenceExpression => {
|
||||
const declaration = symbol.declaration !;
|
||||
const declaration = symbol.declaration!;
|
||||
if (declaration.module.startsWith('.')) {
|
||||
// Reference to a symbol defined in the module. Ensure it is converted then return a
|
||||
// references to the final symbol.
|
||||
|
@ -503,11 +508,11 @@ export class MetadataBundler {
|
|||
__symbolic: 'reference',
|
||||
get name() {
|
||||
// Resolved lazily because private names are assigned late.
|
||||
const canonicalSymbol = symbol.canonicalSymbol !;
|
||||
const canonicalSymbol = symbol.canonicalSymbol!;
|
||||
if (canonicalSymbol.isPrivate == null) {
|
||||
throw Error('Invalid state: isPrivate was not initialized');
|
||||
}
|
||||
return canonicalSymbol.isPrivate ? canonicalSymbol.privateName ! : canonicalSymbol.name;
|
||||
return canonicalSymbol.isPrivate ? canonicalSymbol.privateName! : canonicalSymbol.name;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
|
@ -584,7 +589,7 @@ export class MetadataBundler {
|
|||
|
||||
private convertExpressionNode(moduleName: string, value: MetadataSymbolicExpression):
|
||||
MetadataSymbolicExpression {
|
||||
const result: MetadataSymbolicExpression = { __symbolic: value.__symbolic } as any;
|
||||
const result: MetadataSymbolicExpression = {__symbolic: value.__symbolic} as any;
|
||||
for (const key in value) {
|
||||
(result as any)[key] = this.convertValue(moduleName, (value as any)[key]);
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {Evaluator, errorSymbol, 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 {errorSymbol, Evaluator, recordMapEntry} from './evaluator';
|
||||
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';
|
||||
|
||||
const isStatic = (node: ts.Declaration) =>
|
||||
|
@ -60,12 +60,12 @@ export class MetadataCollector {
|
|||
new Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>();
|
||||
const composedSubstituter = substituteExpression && this.options.substituteExpression ?
|
||||
(value: MetadataValue, node: ts.Node) =>
|
||||
this.options.substituteExpression !(substituteExpression(value, node), node) :
|
||||
this.options.substituteExpression!(substituteExpression(value, node), node) :
|
||||
substituteExpression;
|
||||
const evaluatorOptions = substituteExpression ?
|
||||
{...this.options, substituteExpression: composedSubstituter} :
|
||||
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) => {
|
||||
if (!metadata) metadata = {};
|
||||
metadata[name] = value;
|
||||
|
@ -88,9 +88,9 @@ export class MetadataCollector {
|
|||
return errorSymbol(message, node, context, sourceFile);
|
||||
}
|
||||
|
||||
function maybeGetSimpleFunction(
|
||||
functionDeclaration: ts.FunctionDeclaration |
|
||||
ts.MethodDeclaration): {func: FunctionMetadata, name: string}|undefined {
|
||||
function maybeGetSimpleFunction(functionDeclaration: ts.FunctionDeclaration|
|
||||
ts.MethodDeclaration): {func: FunctionMetadata, name: string}|
|
||||
undefined {
|
||||
if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
|
||||
const nameNode = <ts.Identifier>functionDeclaration.name;
|
||||
const functionName = nameNode.text;
|
||||
|
@ -119,8 +119,8 @@ export class MetadataCollector {
|
|||
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
|
||||
const result: ClassMetadata = {__symbolic: 'class'};
|
||||
|
||||
function getDecorators(decorators: ReadonlyArray<ts.Decorator>| undefined):
|
||||
MetadataSymbolicExpression[]|undefined {
|
||||
function getDecorators(decorators: ReadonlyArray<ts.Decorator>|
|
||||
undefined): MetadataSymbolicExpression[]|undefined {
|
||||
if (decorators && decorators.length)
|
||||
return decorators.map(decorator => objFromDecorator(decorator));
|
||||
return undefined;
|
||||
|
@ -167,8 +167,8 @@ export class MetadataCollector {
|
|||
}
|
||||
|
||||
// static member
|
||||
let statics: {[name: string]: MetadataValue | FunctionMetadata}|null = null;
|
||||
function recordStaticMember(name: string, value: MetadataValue | FunctionMetadata) {
|
||||
let statics: {[name: string]: MetadataValue|FunctionMetadata}|null = null;
|
||||
function recordStaticMember(name: string, value: MetadataValue|FunctionMetadata) {
|
||||
if (!statics) statics = {};
|
||||
statics[name] = value;
|
||||
}
|
||||
|
@ -189,11 +189,10 @@ export class MetadataCollector {
|
|||
}
|
||||
const methodDecorators = getDecorators(method.decorators);
|
||||
const parameters = method.parameters;
|
||||
const parameterDecoratorData:
|
||||
((MetadataSymbolicExpression | MetadataError)[] | undefined)[] = [];
|
||||
const parametersData:
|
||||
(MetadataSymbolicReferenceExpression | MetadataError |
|
||||
MetadataSymbolicSelectExpression | null)[] = [];
|
||||
const parameterDecoratorData: ((MetadataSymbolicExpression | MetadataError)[]|
|
||||
undefined)[] = [];
|
||||
const parametersData: (MetadataSymbolicReferenceExpression|MetadataError|
|
||||
MetadataSymbolicSelectExpression|null)[] = [];
|
||||
let hasDecoratorData: boolean = false;
|
||||
let hasParameterData: boolean = false;
|
||||
for (const parameter of parameters) {
|
||||
|
@ -282,15 +281,14 @@ export class MetadataCollector {
|
|||
ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export;
|
||||
const isExportedIdentifier = (identifier?: ts.Identifier) =>
|
||||
identifier && exportMap.has(identifier.text);
|
||||
const isExported =
|
||||
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration |
|
||||
ts.InterfaceDeclaration | ts.EnumDeclaration) =>
|
||||
isExport(node) || isExportedIdentifier(node.name);
|
||||
const isExported = (node: ts.FunctionDeclaration|ts.ClassDeclaration|ts.TypeAliasDeclaration|
|
||||
ts.InterfaceDeclaration|ts.EnumDeclaration) =>
|
||||
isExport(node) || isExportedIdentifier(node.name);
|
||||
const exportedIdentifierName = (identifier?: ts.Identifier) =>
|
||||
identifier && (exportMap.get(identifier.text) || identifier.text);
|
||||
const exportedName =
|
||||
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration |
|
||||
ts.TypeAliasDeclaration | ts.EnumDeclaration) => exportedIdentifierName(node.name);
|
||||
const exportedName = (node: ts.FunctionDeclaration|ts.ClassDeclaration|
|
||||
ts.InterfaceDeclaration|ts.TypeAliasDeclaration|ts.EnumDeclaration) =>
|
||||
exportedIdentifierName(node.name);
|
||||
|
||||
|
||||
// Pre-declare classes and functions
|
||||
|
@ -419,8 +417,8 @@ export class MetadataCollector {
|
|||
if (name) {
|
||||
if (!metadata) metadata = {};
|
||||
// TODO(alxhub): The literal here is not valid FunctionMetadata.
|
||||
metadata[name] = maybeFunc ? recordEntry(maybeFunc.func, node) :
|
||||
({ __symbolic: 'function' } as any);
|
||||
metadata[name] =
|
||||
maybeFunc ? recordEntry(maybeFunc.func, node) : ({__symbolic: 'function'} as any);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -456,7 +454,8 @@ export class MetadataCollector {
|
|||
operator: '+',
|
||||
left: {
|
||||
__symbolic: 'select',
|
||||
expression: recordEntry({__symbolic: 'reference', name: enumName}, node), name
|
||||
expression: recordEntry({__symbolic: 'reference', name: enumName}, node),
|
||||
name
|
||||
},
|
||||
} as any;
|
||||
} else {
|
||||
|
@ -555,7 +554,8 @@ export class MetadataCollector {
|
|||
}
|
||||
const result: ModuleMetadata = {
|
||||
__symbolic: 'module',
|
||||
version: this.options.version || METADATA_VERSION, metadata
|
||||
version: this.options.version || METADATA_VERSION,
|
||||
metadata
|
||||
};
|
||||
if (sourceFile.moduleName) result.importAs = sourceFile.moduleName;
|
||||
if (exports) result.exports = exports;
|
||||
|
@ -570,8 +570,7 @@ function validateMetadata(
|
|||
metadata: {[name: string]: MetadataEntry}) {
|
||||
let locals: Set<string> = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']);
|
||||
|
||||
function validateExpression(
|
||||
expression: MetadataValue | MetadataSymbolicExpression | MetadataError) {
|
||||
function validateExpression(expression: MetadataValue|MetadataSymbolicExpression|MetadataError) {
|
||||
if (!expression) {
|
||||
return;
|
||||
} else if (Array.isArray(expression)) {
|
||||
|
@ -648,11 +647,11 @@ function validateMetadata(
|
|||
}
|
||||
if (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) {
|
||||
Object.getOwnPropertyNames(classData.statics).forEach(name => {
|
||||
const staticMember = classData.statics ![name];
|
||||
const staticMember = classData.statics![name];
|
||||
if (isFunctionMetadata(staticMember)) {
|
||||
validateExpression(staticMember.value);
|
||||
} else {
|
||||
|
@ -675,7 +674,7 @@ function validateMetadata(
|
|||
}
|
||||
}
|
||||
|
||||
function shouldReportNode(node: ts.Node | undefined) {
|
||||
function shouldReportNode(node: ts.Node|undefined) {
|
||||
if (node) {
|
||||
const nodeStart = node.getStart();
|
||||
return !(
|
||||
|
@ -688,12 +687,13 @@ function validateMetadata(
|
|||
function reportError(error: MetadataError) {
|
||||
const node = nodeMap.get(error);
|
||||
if (shouldReportNode(node)) {
|
||||
const lineInfo = error.line != undefined ?
|
||||
error.character != undefined ? `:${error.line + 1}:${error.character + 1}` :
|
||||
`:${error.line + 1}` :
|
||||
'';
|
||||
throw new Error(
|
||||
`${sourceFile.fileName}${lineInfo}: Metadata collected contains an error that will be reported at runtime: ${expandedMessage(error)}.\n ${JSON.stringify(error)}`);
|
||||
const lineInfo = error.line != undefined ? error.character != undefined ?
|
||||
`:${error.line + 1}:${error.character + 1}` :
|
||||
`:${error.line + 1}` :
|
||||
'';
|
||||
throw new Error(`${sourceFile.fileName}${
|
||||
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 (node) {
|
||||
const {line, character} = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
||||
throw new Error(
|
||||
`${sourceFile.fileName}:${line + 1}:${character + 1}: Error encountered in metadata generated for exported symbol '${name}': \n ${e.message}`);
|
||||
throw new Error(`${sourceFile.fileName}:${line + 1}:${
|
||||
character + 1}: Error encountered in metadata generated for exported symbol '${
|
||||
name}': \n ${e.message}`);
|
||||
}
|
||||
throw new Error(
|
||||
`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[] {
|
||||
const result: string[] = [];
|
||||
|
||||
function addNamesOf(name: ts.Identifier | ts.BindingPattern) {
|
||||
function addNamesOf(name: ts.Identifier|ts.BindingPattern) {
|
||||
if (name.kind == ts.SyntaxKind.Identifier) {
|
||||
const identifier = <ts.Identifier>name;
|
||||
result.push(identifier.text);
|
||||
|
@ -752,7 +753,8 @@ function expandedMessage(error: any): string {
|
|||
switch (error.message) {
|
||||
case 'Reference to non-exported class':
|
||||
if (error.context && error.context.className) {
|
||||
return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`;
|
||||
return `Reference to a non-exported class ${
|
||||
error.context.className}. Consider exporting the class`;
|
||||
}
|
||||
break;
|
||||
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';
|
||||
case 'Reference to a local symbol':
|
||||
if (error.context && error.context.name) {
|
||||
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
|
||||
return `Reference to a local (non-exported) symbol '${
|
||||
error.context.name}'. Consider exporting the symbol`;
|
||||
}
|
||||
}
|
||||
return error.message;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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';
|
||||
|
||||
|
||||
|
@ -46,8 +46,9 @@ export function recordMapEntry<T extends MetadataEntry>(
|
|||
sourceFile?: ts.SourceFile) {
|
||||
if (!nodeMap.has(entry)) {
|
||||
nodeMap.set(entry, node);
|
||||
if (node && (isMetadataImportedSymbolReferenceExpression(entry) ||
|
||||
isMetadataImportDefaultReference(entry)) &&
|
||||
if (node &&
|
||||
(isMetadataImportedSymbolReferenceExpression(entry) ||
|
||||
isMetadataImportDefaultReference(entry)) &&
|
||||
entry.line == null) {
|
||||
const info = sourceInfo(node, sourceFile);
|
||||
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) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
|
|||
|
||||
/* @internal */
|
||||
export function sourceInfo(
|
||||
node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo {
|
||||
node: ts.Node|undefined, sourceFile: ts.SourceFile|undefined): MetadataSourceLocationInfo {
|
||||
if (node) {
|
||||
sourceFile = sourceFile || getSourceFileOfNode(node);
|
||||
if (sourceFile) {
|
||||
|
@ -435,7 +436,7 @@ export class Evaluator {
|
|||
case ts.SyntaxKind.TypeReference:
|
||||
const typeReferenceNode = <ts.TypeReferenceNode>node;
|
||||
const typeNameNode = typeReferenceNode.typeName;
|
||||
const getReference: (typeNameNode: ts.Identifier | ts.QualifiedName) => MetadataValue =
|
||||
const getReference: (typeNameNode: ts.Identifier|ts.QualifiedName) => MetadataValue =
|
||||
node => {
|
||||
if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) {
|
||||
const qualifiedName = <ts.QualifiedName>node;
|
||||
|
@ -691,6 +692,6 @@ function isPropertyAssignment(node: ts.Node): node is ts.PropertyAssignment {
|
|||
|
||||
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;
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
export const METADATA_VERSION = 4;
|
||||
|
||||
export type MetadataEntry = ClassMetadata | InterfaceMetadata | FunctionMetadata | MetadataValue;
|
||||
export type MetadataEntry = ClassMetadata|InterfaceMetadata|FunctionMetadata|MetadataValue;
|
||||
|
||||
export interface ModuleMetadata {
|
||||
__symbolic: 'module';
|
||||
|
@ -43,18 +43,22 @@ export interface ClassMetadata {
|
|||
arity?: number;
|
||||
decorators?: (MetadataSymbolicExpression|MetadataError)[];
|
||||
members?: MetadataMap;
|
||||
statics?: {[name: string]: MetadataValue | FunctionMetadata};
|
||||
statics?: {[name: string]: MetadataValue|FunctionMetadata};
|
||||
}
|
||||
export function isClassMetadata(value: any): value is ClassMetadata {
|
||||
return value && value.__symbolic === 'class';
|
||||
}
|
||||
|
||||
export interface InterfaceMetadata { __symbolic: 'interface'; }
|
||||
export interface InterfaceMetadata {
|
||||
__symbolic: 'interface';
|
||||
}
|
||||
export function isInterfaceMetadata(value: any): value is InterfaceMetadata {
|
||||
return value && value.__symbolic === 'interface';
|
||||
}
|
||||
|
||||
export interface MetadataMap { [name: string]: MemberMetadata[]; }
|
||||
export interface MetadataMap {
|
||||
[name: string]: MemberMetadata[];
|
||||
}
|
||||
|
||||
export interface MemberMetadata {
|
||||
__symbolic: 'constructor'|'method'|'property';
|
||||
|
@ -99,24 +103,26 @@ export function isFunctionMetadata(value: any): value is FunctionMetadata {
|
|||
return value && value.__symbolic === 'function';
|
||||
}
|
||||
|
||||
export type MetadataValue = string | number | boolean | undefined | null | MetadataObject |
|
||||
MetadataArray | MetadataSymbolicExpression | MetadataSymbolicReferenceExpression |
|
||||
MetadataSymbolicBinaryExpression | MetadataSymbolicIndexExpression |
|
||||
MetadataSymbolicCallExpression | MetadataSymbolicPrefixExpression |
|
||||
MetadataSymbolicIfExpression | MetadataSymbolicSpreadExpression |
|
||||
MetadataSymbolicSelectExpression | MetadataError;
|
||||
export type MetadataValue = string|number|boolean|undefined|null|MetadataObject|MetadataArray|
|
||||
MetadataSymbolicExpression|MetadataSymbolicReferenceExpression|MetadataSymbolicBinaryExpression|
|
||||
MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression|
|
||||
MetadataSymbolicIfExpression|MetadataSymbolicSpreadExpression|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 |
|
||||
MetadataSymbolicIndexExpression | MetadataSymbolicIndexExpression |
|
||||
MetadataSymbolicCallExpression | MetadataSymbolicCallExpression |
|
||||
MetadataSymbolicPrefixExpression | MetadataSymbolicIfExpression |
|
||||
MetadataGlobalReferenceExpression | MetadataModuleReferenceExpression |
|
||||
MetadataImportedSymbolReferenceExpression | MetadataImportedDefaultReferenceExpression |
|
||||
MetadataSymbolicSelectExpression | MetadataSymbolicSpreadExpression;
|
||||
export type MetadataSymbolicExpression = MetadataSymbolicBinaryExpression|
|
||||
MetadataSymbolicIndexExpression|MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression|
|
||||
MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression|MetadataSymbolicIfExpression|
|
||||
MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression|
|
||||
MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression|
|
||||
MetadataSymbolicSelectExpression|MetadataSymbolicSpreadExpression;
|
||||
|
||||
export function isMetadataSymbolicExpression(value: any): value is MetadataSymbolicExpression {
|
||||
if (value) {
|
||||
|
@ -234,18 +240,17 @@ export function isMetadataImportedSymbolReferenceExpression(value: any):
|
|||
export interface MetadataImportedDefaultReferenceExpression extends MetadataSourceLocationInfo {
|
||||
__symbolic: 'reference';
|
||||
module: string;
|
||||
default:
|
||||
boolean;
|
||||
arguments?: MetadataValue[];
|
||||
default: boolean;
|
||||
arguments?: MetadataValue[];
|
||||
}
|
||||
export function isMetadataImportDefaultReference(value: any):
|
||||
value is MetadataImportedDefaultReferenceExpression {
|
||||
return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value);
|
||||
}
|
||||
|
||||
export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression |
|
||||
MetadataModuleReferenceExpression | MetadataImportedSymbolReferenceExpression |
|
||||
MetadataImportedDefaultReferenceExpression;
|
||||
export type MetadataSymbolicReferenceExpression =
|
||||
MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression|
|
||||
MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression;
|
||||
export function isMetadataSymbolicReferenceExpression(value: any):
|
||||
value is MetadataSymbolicReferenceExpression {
|
||||
return value && value.__symbolic === 'reference';
|
||||
|
|
|
@ -12,7 +12,7 @@ import {MetadataSymbolicReferenceExpression, MetadataValue} from './schema';
|
|||
|
||||
export class Symbols {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
private _symbols !: Map<string, MetadataValue>;
|
||||
private _symbols!: Map<string, MetadataValue>;
|
||||
private references = new Map<string, MetadataSymbolicReferenceExpression>();
|
||||
|
||||
constructor(private sourceFile: ts.SourceFile) {}
|
||||
|
@ -21,12 +21,16 @@ export class Symbols {
|
|||
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) {
|
||||
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> {
|
||||
let result = this._symbols;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {CycleAnalyzer} from '../../cycles';
|
||||
|
@ -15,7 +15,7 @@ import {absoluteFrom, relative} from '../../file_system';
|
|||
import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
|
||||
import {DependencyTracker} from '../../incremental/api';
|
||||
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 {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
|
||||
|
@ -200,7 +200,7 @@ export class ComponentDecoratorHandler implements
|
|||
} else {
|
||||
return previous;
|
||||
}
|
||||
}, undefined) !;
|
||||
}, undefined)!;
|
||||
|
||||
|
||||
// Note that we could technically combine the `viewProvidersRequiringFactory` and
|
||||
|
@ -211,7 +211,7 @@ export class ComponentDecoratorHandler implements
|
|||
let wrappedViewProviders: Expression|null = null;
|
||||
|
||||
if (component.has('viewProviders')) {
|
||||
const viewProviders = component.get('viewProviders') !;
|
||||
const viewProviders = component.get('viewProviders')!;
|
||||
viewProvidersRequiringFactory =
|
||||
resolveProvidersRequiringFactory(viewProviders, this.reflector, this.evaluator);
|
||||
wrappedViewProviders = new WrappedNodeExpr(
|
||||
|
@ -221,7 +221,7 @@ export class ComponentDecoratorHandler implements
|
|||
|
||||
if (component.has('providers')) {
|
||||
providersRequiringFactory = resolveProvidersRequiringFactory(
|
||||
component.get('providers') !, this.reflector, this.evaluator);
|
||||
component.get('providers')!, this.reflector, this.evaluator);
|
||||
}
|
||||
|
||||
// Parse the template.
|
||||
|
@ -232,14 +232,14 @@ export class ComponentDecoratorHandler implements
|
|||
let template: ParsedTemplateWithSource;
|
||||
if (this.preanalyzeTemplateCache.has(node)) {
|
||||
// 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);
|
||||
|
||||
template = preanalyzed;
|
||||
} else {
|
||||
// The template was not already parsed. Either there's a templateUrl, or an inline template.
|
||||
if (component.has('templateUrl')) {
|
||||
const templateUrlExpr = component.get('templateUrl') !;
|
||||
const templateUrlExpr = component.get('templateUrl')!;
|
||||
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||
if (typeof templateUrl !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -303,7 +303,7 @@ export class ComponentDecoratorHandler implements
|
|||
|
||||
let animations: Expression|null = null;
|
||||
if (component.has('animations')) {
|
||||
animations = new WrappedNodeExpr(component.get('animations') !);
|
||||
animations = new WrappedNodeExpr(component.get('animations')!);
|
||||
}
|
||||
|
||||
const output: AnalysisOutput<ComponentAnalysisData> = {
|
||||
|
@ -323,7 +323,8 @@ export class ComponentDecoratorHandler implements
|
|||
// analyzed and the full compilation scope for the component can be realized.
|
||||
animations,
|
||||
viewProviders: wrappedViewProviders,
|
||||
i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath,
|
||||
i18nUseExternalIds: this.i18nUseExternalIds,
|
||||
relativeContextFilePath,
|
||||
},
|
||||
guards: extractDirectiveGuards(node, this.reflector),
|
||||
metadataStmt: generateSetClassMetadataCall(
|
||||
|
@ -335,7 +336,7 @@ export class ComponentDecoratorHandler implements
|
|||
},
|
||||
};
|
||||
if (changeDetection !== null) {
|
||||
output.analysis !.meta.changeDetection = changeDetection;
|
||||
output.analysis!.meta.changeDetection = changeDetection;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
@ -353,7 +354,8 @@ export class ComponentDecoratorHandler implements
|
|||
outputs: analysis.meta.outputs,
|
||||
queries: analysis.meta.queries.map(query => query.propertyName),
|
||||
isComponent: true,
|
||||
baseClass: analysis.baseClass, ...analysis.guards,
|
||||
baseClass: analysis.baseClass,
|
||||
...analysis.guards,
|
||||
});
|
||||
|
||||
this.injectableRegistry.registerInjectable(node);
|
||||
|
@ -415,8 +417,8 @@ export class ComponentDecoratorHandler implements
|
|||
}
|
||||
for (const {name, ref} of scope.compilation.pipes) {
|
||||
if (!ts.isClassDeclaration(ref.node)) {
|
||||
throw new Error(
|
||||
`Unexpected non-class declaration ${ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`);
|
||||
throw new Error(`Unexpected non-class declaration ${
|
||||
ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`);
|
||||
}
|
||||
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.
|
||||
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
|
||||
// import which needs to be generated would create a cycle.
|
||||
|
@ -539,7 +541,7 @@ export class ComponentDecoratorHandler implements
|
|||
if (analysis.providersRequiringFactory !== null &&
|
||||
analysis.meta.providers instanceof WrappedNodeExpr) {
|
||||
const providerDiagnostics = getProviderDiagnostics(
|
||||
analysis.providersRequiringFactory, analysis.meta.providers !.node,
|
||||
analysis.providersRequiringFactory, analysis.meta.providers!.node,
|
||||
this.injectableRegistry);
|
||||
diagnostics.push(...providerDiagnostics);
|
||||
}
|
||||
|
@ -547,7 +549,7 @@ export class ComponentDecoratorHandler implements
|
|||
if (analysis.viewProvidersRequiringFactory !== null &&
|
||||
analysis.meta.viewProviders instanceof WrappedNodeExpr) {
|
||||
const viewProviderDiagnostics = getProviderDiagnostics(
|
||||
analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders !.node,
|
||||
analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders!.node,
|
||||
this.injectableRegistry);
|
||||
diagnostics.push(...viewProviderDiagnostics);
|
||||
}
|
||||
|
@ -587,7 +589,7 @@ export class ComponentDecoratorHandler implements
|
|||
|
||||
private _resolveLiteral(decorator: Decorator): ts.ObjectLiteralExpression {
|
||||
if (this.literalCache.has(decorator)) {
|
||||
return this.literalCache.get(decorator) !;
|
||||
return this.literalCache.get(decorator)!;
|
||||
}
|
||||
if (decorator.args === null || decorator.args.length !== 1) {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -609,7 +611,7 @@ export class ComponentDecoratorHandler implements
|
|||
component: Map<string, ts.Expression>, field: string, enumSymbolName: string): number|null {
|
||||
let resolved: number|null = null;
|
||||
if (component.has(field)) {
|
||||
const expr = component.get(field) !;
|
||||
const expr = component.get(field)!;
|
||||
const value = this.evaluator.evaluate(expr) as any;
|
||||
if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) {
|
||||
resolved = value.resolved as number;
|
||||
|
@ -628,7 +630,7 @@ export class ComponentDecoratorHandler implements
|
|||
return extraUrls.length > 0 ? extraUrls : null;
|
||||
}
|
||||
|
||||
const styleUrlsExpr = component.get('styleUrls') !;
|
||||
const styleUrlsExpr = component.get('styleUrls')!;
|
||||
const styleUrls = this.evaluator.evaluate(styleUrlsExpr);
|
||||
if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -643,7 +645,7 @@ export class ComponentDecoratorHandler implements
|
|||
containingFile: string): Promise<ParsedTemplate|null> {
|
||||
if (component.has('templateUrl')) {
|
||||
// Extract the templateUrl and preload it.
|
||||
const templateUrlExpr = component.get('templateUrl') !;
|
||||
const templateUrlExpr = component.get('templateUrl')!;
|
||||
const templateUrl = this.evaluator.evaluate(templateUrlExpr);
|
||||
if (typeof templateUrl !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -703,7 +705,7 @@ export class ComponentDecoratorHandler implements
|
|||
ErrorCode.COMPONENT_MISSING_TEMPLATE, Decorator.nodeForError(decorator),
|
||||
'component is missing a template');
|
||||
}
|
||||
const templateExpr = component.get('template') !;
|
||||
const templateExpr = component.get('template')!;
|
||||
|
||||
let templateStr: string;
|
||||
let templateUrl: string = '';
|
||||
|
@ -721,7 +723,7 @@ export class ComponentDecoratorHandler implements
|
|||
escapedString = true;
|
||||
sourceMapping = {
|
||||
type: 'direct',
|
||||
node: templateExpr as(ts.StringLiteral | ts.NoSubstitutionTemplateLiteral),
|
||||
node: templateExpr as (ts.StringLiteral | ts.NoSubstitutionTemplateLiteral),
|
||||
};
|
||||
} else {
|
||||
const resolvedTemplate = this.evaluator.evaluate(templateExpr);
|
||||
|
@ -749,7 +751,7 @@ export class ComponentDecoratorHandler implements
|
|||
templateRange: LexerRange|undefined, escapedString: boolean): ParsedTemplate {
|
||||
let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces;
|
||||
if (component.has('preserveWhitespaces')) {
|
||||
const expr = component.get('preserveWhitespaces') !;
|
||||
const expr = component.get('preserveWhitespaces')!;
|
||||
const value = this.evaluator.evaluate(expr);
|
||||
if (typeof value !== 'boolean') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -760,7 +762,7 @@ export class ComponentDecoratorHandler implements
|
|||
|
||||
let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG;
|
||||
if (component.has('interpolation')) {
|
||||
const expr = component.get('interpolation') !;
|
||||
const expr = component.get('interpolation')!;
|
||||
const value = this.evaluator.evaluate(expr);
|
||||
if (!Array.isArray(value) || value.length !== 2 ||
|
||||
!value.every(element => typeof element === 'string')) {
|
||||
|
@ -768,14 +770,15 @@ export class ComponentDecoratorHandler implements
|
|||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr,
|
||||
'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} =
|
||||
parseTemplate(templateStr, templateUrl, {
|
||||
preserveWhitespaces,
|
||||
interpolationConfig: interpolation,
|
||||
range: templateRange, escapedString,
|
||||
range: templateRange,
|
||||
escapedString,
|
||||
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
||||
});
|
||||
|
||||
|
@ -795,7 +798,8 @@ export class ComponentDecoratorHandler implements
|
|||
const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, {
|
||||
preserveWhitespaces: true,
|
||||
interpolationConfig: interpolation,
|
||||
range: templateRange, escapedString,
|
||||
range: templateRange,
|
||||
escapedString,
|
||||
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat,
|
||||
leadingTriviaChars: [],
|
||||
});
|
||||
|
@ -808,7 +812,8 @@ export class ComponentDecoratorHandler implements
|
|||
styles,
|
||||
ngContentSelectors,
|
||||
errors,
|
||||
template: templateStr, templateUrl,
|
||||
template: templateStr,
|
||||
templateUrl,
|
||||
isInline: component.has('template'),
|
||||
file: new ParseSourceFile(templateStr, templateUrl),
|
||||
};
|
||||
|
@ -820,7 +825,7 @@ export class ComponentDecoratorHandler implements
|
|||
}
|
||||
|
||||
// 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 {
|
||||
|
|
|
@ -36,9 +36,13 @@ export function getProviderDiagnostics(
|
|||
const contextNode = provider.getOriginForDiagnostics(providersDeclaration);
|
||||
diagnostics.push(makeDiagnostic(
|
||||
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.`}]));
|
||||
}
|
||||
|
@ -52,7 +56,7 @@ export function getDirectiveDiagnostics(
|
|||
kind: string): 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) {
|
||||
return;
|
||||
} else if (diagnostics === null) {
|
||||
|
@ -121,14 +125,16 @@ export function checkInheritanceOfDirective(
|
|||
|
||||
function getInheritedUndecoratedCtorDiagnostic(
|
||||
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 baseClassName = baseClass.debugName;
|
||||
|
||||
return makeDiagnostic(
|
||||
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 ` +
|
||||
`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}.`);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
|
@ -14,7 +14,7 @@ import {DefaultImportRecorder, Reference} from '../../imports';
|
|||
import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
|
||||
import {extractDirectiveGuards} from '../../metadata/src/util';
|
||||
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 {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
||||
|
||||
|
@ -92,7 +92,7 @@ export class DirectiveDecoratorHandler implements
|
|||
let providersRequiringFactory: Set<Reference<ClassDeclaration>>|null = null;
|
||||
if (directiveResult !== undefined && directiveResult.decorator.has('providers')) {
|
||||
providersRequiringFactory = resolveProvidersRequiringFactory(
|
||||
directiveResult.decorator.get('providers') !, this.reflector, this.evaluator);
|
||||
directiveResult.decorator.get('providers')!, this.reflector, this.evaluator);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -102,7 +102,8 @@ export class DirectiveDecoratorHandler implements
|
|||
node, this.reflector, this.defaultImportRecorder, this.isCore,
|
||||
this.annotateForClosureCompiler),
|
||||
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,
|
||||
queries: analysis.meta.queries.map(query => query.propertyName),
|
||||
isComponent: false,
|
||||
baseClass: analysis.baseClass, ...analysis.guards,
|
||||
baseClass: analysis.baseClass,
|
||||
...analysis.guards,
|
||||
});
|
||||
|
||||
this.injectableRegistry.registerInjectable(node);
|
||||
|
@ -132,7 +134,7 @@ export class DirectiveDecoratorHandler implements
|
|||
if (analysis.providersRequiringFactory !== null &&
|
||||
analysis.meta.providers instanceof WrappedNodeExpr) {
|
||||
const providerDiagnostics = getProviderDiagnostics(
|
||||
analysis.providersRequiringFactory, analysis.meta.providers !.node,
|
||||
analysis.providersRequiringFactory, analysis.meta.providers!.node,
|
||||
this.injectableRegistry);
|
||||
diagnostics.push(...providerDiagnostics);
|
||||
}
|
||||
|
@ -176,9 +178,8 @@ export class DirectiveDecoratorHandler implements
|
|||
export function extractDirectiveMetadata(
|
||||
clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost,
|
||||
evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean,
|
||||
flags: HandlerFlags, annotateForClosureCompiler: boolean,
|
||||
defaultSelector: string | null =
|
||||
null): {decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined {
|
||||
flags: HandlerFlags, annotateForClosureCompiler: boolean, defaultSelector: string|null = null):
|
||||
{decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined {
|
||||
let directive: Map<string, ts.Expression>;
|
||||
if (decorator === null || decorator.args === null || decorator.args.length === 0) {
|
||||
directive = new Map<string, ts.Expression>();
|
||||
|
@ -220,9 +221,10 @@ export function extractDirectiveMetadata(
|
|||
|
||||
// And outputs.
|
||||
const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator);
|
||||
const outputsFromFields = parseDecoratedFields(
|
||||
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
|
||||
resolveOutput) as{[field: string]: string};
|
||||
const outputsFromFields =
|
||||
parseDecoratedFields(
|
||||
filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator,
|
||||
resolveOutput) as {[field: string]: string};
|
||||
// Construct the list of queries.
|
||||
const contentChildFromFields = queriesFromFields(
|
||||
filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector,
|
||||
|
@ -244,7 +246,7 @@ export function extractDirectiveMetadata(
|
|||
|
||||
if (directive.has('queries')) {
|
||||
const queriesFromDecorator =
|
||||
extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore);
|
||||
extractQueriesFromDecorator(directive.get('queries')!, reflector, evaluator, isCore);
|
||||
queries.push(...queriesFromDecorator.content);
|
||||
viewQueries.push(...queriesFromDecorator.view);
|
||||
}
|
||||
|
@ -252,7 +254,7 @@ export function extractDirectiveMetadata(
|
|||
// Parse the selector.
|
||||
let selector = defaultSelector;
|
||||
if (directive.has('selector')) {
|
||||
const expr = directive.get('selector') !;
|
||||
const expr = directive.get('selector')!;
|
||||
const resolved = evaluator.evaluate(expr);
|
||||
if (typeof resolved !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -272,8 +274,8 @@ export function extractDirectiveMetadata(
|
|||
const providers: Expression|null = directive.has('providers') ?
|
||||
new WrappedNodeExpr(
|
||||
annotateForClosureCompiler ?
|
||||
wrapFunctionExpressionsInParens(directive.get('providers') !) :
|
||||
directive.get('providers') !) :
|
||||
wrapFunctionExpressionsInParens(directive.get('providers')!) :
|
||||
directive.get('providers')!) :
|
||||
null;
|
||||
|
||||
// Determine if `ngOnChanges` is a lifecycle hook defined on the component.
|
||||
|
@ -284,7 +286,7 @@ export function extractDirectiveMetadata(
|
|||
// Parse exportAs.
|
||||
let exportAs: string[]|null = null;
|
||||
if (directive.has('exportAs')) {
|
||||
const expr = directive.get('exportAs') !;
|
||||
const expr = directive.get('exportAs')!;
|
||||
const resolved = evaluator.evaluate(expr);
|
||||
if (typeof resolved !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -312,15 +314,24 @@ export function extractDirectiveMetadata(
|
|||
|
||||
const metadata: R3DirectiveMetadata = {
|
||||
name: clazz.name.text,
|
||||
deps: ctorDeps, host,
|
||||
deps: ctorDeps,
|
||||
host,
|
||||
lifecycle: {
|
||||
usesOnChanges,
|
||||
usesOnChanges,
|
||||
},
|
||||
inputs: {...inputsFromMeta, ...inputsFromFields},
|
||||
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, viewQueries, selector,
|
||||
fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), type, internalType,
|
||||
outputs: {...outputsFromMeta, ...outputsFromFields},
|
||||
queries,
|
||||
viewQueries,
|
||||
selector,
|
||||
fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE),
|
||||
type,
|
||||
internalType,
|
||||
typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0,
|
||||
typeSourceSpan: createSourceSpan(clazz.name), usesInheritance, exportAs, providers
|
||||
typeSourceSpan: createSourceSpan(clazz.name),
|
||||
usesInheritance,
|
||||
exportAs,
|
||||
providers
|
||||
};
|
||||
return {decorator: directive, metadata};
|
||||
}
|
||||
|
@ -366,11 +377,11 @@ export function extractQueryMetadata(
|
|||
}
|
||||
const options = reflectObjectLiteral(optionsExpr);
|
||||
if (options.has('read')) {
|
||||
read = new WrappedNodeExpr(options.get('read') !);
|
||||
read = new WrappedNodeExpr(options.get('read')!);
|
||||
}
|
||||
|
||||
if (options.has('descendants')) {
|
||||
const descendantsExpr = options.get('descendants') !;
|
||||
const descendantsExpr = options.get('descendants')!;
|
||||
const descendantsValue = evaluator.evaluate(descendantsExpr);
|
||||
if (typeof descendantsValue !== 'boolean') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -381,7 +392,7 @@ export function extractQueryMetadata(
|
|||
}
|
||||
|
||||
if (options.has('static')) {
|
||||
const staticValue = evaluator.evaluate(options.get('static') !);
|
||||
const staticValue = evaluator.evaluate(options.get('static')!);
|
||||
if (typeof staticValue !== 'boolean') {
|
||||
throw new FatalDiagnosticError(
|
||||
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[].
|
||||
const expression = directive.get(field) !;
|
||||
const expression = directive.get(field)!;
|
||||
const value = evaluator.evaluate(expression);
|
||||
if (!isStringArrayOrDie(value, field, expression)) {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -489,15 +500,13 @@ function parseFieldToPropertyMapping(
|
|||
return EMPTY_OBJECT;
|
||||
}
|
||||
|
||||
return metaValues.reduce(
|
||||
(results, value) => {
|
||||
// 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.
|
||||
const [field, property] = value.split(':', 2).map(str => str.trim());
|
||||
results[field] = property || field;
|
||||
return results;
|
||||
},
|
||||
{} as{[field: string]: string});
|
||||
return metaValues.reduce((results, value) => {
|
||||
// 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.
|
||||
const [field, property] = value.split(':', 2).map(str => str.trim());
|
||||
results[field] = property || field;
|
||||
return results;
|
||||
}, {} as {[field: string]: string});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -507,33 +516,32 @@ function parseFieldToPropertyMapping(
|
|||
function parseDecoratedFields(
|
||||
fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator,
|
||||
mapValueResolver: (publicName: string, internalName: string) =>
|
||||
string | [string, string]): {[field: string]: string | [string, string]} {
|
||||
return fields.reduce(
|
||||
(results, field) => {
|
||||
const fieldName = field.member.name;
|
||||
field.decorators.forEach(decorator => {
|
||||
// The decorator either doesn't have an argument (@Input()) in which case the property
|
||||
// name is used, or it has one argument (@Output('named')).
|
||||
if (decorator.args == null || decorator.args.length === 0) {
|
||||
results[fieldName] = fieldName;
|
||||
} else if (decorator.args.length === 1) {
|
||||
const property = evaluator.evaluate(decorator.args[0]);
|
||||
if (typeof property !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||
`@${decorator.name} decorator argument must resolve to a string`);
|
||||
}
|
||||
results[fieldName] = mapValueResolver(property, fieldName);
|
||||
} else {
|
||||
// Too many arguments.
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
||||
`@${decorator.name} can have at most one argument, got ${decorator.args.length} argument(s)`);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
},
|
||||
{} as{[field: string]: string | [string, string]});
|
||||
string | [string, string]): {[field: string]: string|[string, string]} {
|
||||
return fields.reduce((results, field) => {
|
||||
const fieldName = field.member.name;
|
||||
field.decorators.forEach(decorator => {
|
||||
// The decorator either doesn't have an argument (@Input()) in which case the property
|
||||
// name is used, or it has one argument (@Output('named')).
|
||||
if (decorator.args == null || decorator.args.length === 0) {
|
||||
results[fieldName] = fieldName;
|
||||
} else if (decorator.args.length === 1) {
|
||||
const property = evaluator.evaluate(decorator.args[0]);
|
||||
if (typeof property !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||
`@${decorator.name} decorator argument must resolve to a string`);
|
||||
}
|
||||
results[fieldName] = mapValueResolver(property, fieldName);
|
||||
} else {
|
||||
// Too many arguments.
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
||||
`@${decorator.name} can have at most one argument, got ${
|
||||
decorator.args.length} argument(s)`);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}, {} as {[field: string]: 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);
|
||||
|
||||
// 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(
|
||||
ErrorCode.DECORATOR_COLLISION, node,
|
||||
'Cannot combine @Input decorators with query decorators');
|
||||
|
@ -626,38 +634,40 @@ function evaluateHostExpressionBindings(
|
|||
}
|
||||
|
||||
export function extractHostBindings(
|
||||
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined,
|
||||
members: ClassMember[], evaluator: PartialEvaluator, coreModule: string|undefined,
|
||||
metadata?: Map<string, ts.Expression>): ParsedHostBindings {
|
||||
let bindings: ParsedHostBindings;
|
||||
if (metadata && metadata.has('host')) {
|
||||
bindings = evaluateHostExpressionBindings(metadata.get('host') !, evaluator);
|
||||
bindings = evaluateHostExpressionBindings(metadata.get('host')!, evaluator);
|
||||
} else {
|
||||
bindings = parseHostBindings({});
|
||||
}
|
||||
|
||||
filterToMembersWithDecorator(members, 'HostBinding', coreModule).forEach(({member, decorators}) => {
|
||||
decorators.forEach(decorator => {
|
||||
let hostPropertyName: string = member.name;
|
||||
if (decorator.args !== null && decorator.args.length > 0) {
|
||||
if (decorator.args.length !== 1) {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator),
|
||||
`@HostBinding can have at most one argument, got ${decorator.args.length} argument(s)`);
|
||||
}
|
||||
filterToMembersWithDecorator(members, 'HostBinding', coreModule)
|
||||
.forEach(({member, decorators}) => {
|
||||
decorators.forEach(decorator => {
|
||||
let hostPropertyName: string = member.name;
|
||||
if (decorator.args !== null && decorator.args.length > 0) {
|
||||
if (decorator.args.length !== 1) {
|
||||
throw new FatalDiagnosticError(
|
||||
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]);
|
||||
if (typeof resolved !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||
`@HostBinding's argument must be a string`);
|
||||
}
|
||||
const resolved = evaluator.evaluate(decorator.args[0]);
|
||||
if (typeof resolved !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator),
|
||||
`@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)
|
||||
.forEach(({member, decorators}) => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {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[] {
|
||||
const res = compileIvyInjectable(analysis.meta);
|
||||
|
@ -165,12 +167,12 @@ function extractInjectableMetadata(
|
|||
const meta = reflectObjectLiteral(metaNode);
|
||||
let providedIn: Expression = new LiteralExpr(null);
|
||||
if (meta.has('providedIn')) {
|
||||
providedIn = new WrappedNodeExpr(meta.get('providedIn') !);
|
||||
providedIn = new WrappedNodeExpr(meta.get('providedIn')!);
|
||||
}
|
||||
|
||||
let userDeps: R3DependencyMetadata[]|undefined = undefined;
|
||||
if ((meta.has('useClass') || meta.has('useFactory')) && meta.has('deps')) {
|
||||
const depsExpr = meta.get('deps') !;
|
||||
const depsExpr = meta.get('deps')!;
|
||||
if (!ts.isArrayLiteralExpression(depsExpr)) {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_NOT_LITERAL, depsExpr,
|
||||
|
@ -186,7 +188,7 @@ function extractInjectableMetadata(
|
|||
typeArgumentCount,
|
||||
internalType,
|
||||
providedIn,
|
||||
useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue') !, reflector)),
|
||||
useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue')!, reflector)),
|
||||
};
|
||||
} else if (meta.has('useExisting')) {
|
||||
return {
|
||||
|
@ -195,7 +197,7 @@ function extractInjectableMetadata(
|
|||
typeArgumentCount,
|
||||
internalType,
|
||||
providedIn,
|
||||
useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting') !, reflector)),
|
||||
useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting')!, reflector)),
|
||||
};
|
||||
} else if (meta.has('useClass')) {
|
||||
return {
|
||||
|
@ -204,19 +206,20 @@ function extractInjectableMetadata(
|
|||
typeArgumentCount,
|
||||
internalType,
|
||||
providedIn,
|
||||
useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass') !, reflector)),
|
||||
useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass')!, reflector)),
|
||||
userDeps,
|
||||
};
|
||||
} else if (meta.has('useFactory')) {
|
||||
// useFactory is special - the 'deps' property must be analyzed.
|
||||
const factory = new WrappedNodeExpr(meta.get('useFactory') !);
|
||||
const factory = new WrappedNodeExpr(meta.get('useFactory')!);
|
||||
return {
|
||||
name,
|
||||
type,
|
||||
typeArgumentCount,
|
||||
internalType,
|
||||
providedIn,
|
||||
useFactory: factory, userDeps,
|
||||
useFactory: factory,
|
||||
userDeps,
|
||||
};
|
||||
} else {
|
||||
return {name, type, typeArgumentCount, internalType, providedIn};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {DefaultImportRecorder} from '../../imports';
|
||||
|
@ -71,7 +71,7 @@ export function generateSetClassMetadataCall(
|
|||
duplicateDecoratedMemberNames.join(', '));
|
||||
}
|
||||
const decoratedMembers =
|
||||
classMembers.map(member => classMemberToMetadata(member.name, member.decorators !, isCore));
|
||||
classMembers.map(member => classMemberToMetadata(member.name, member.decorators!, isCore));
|
||||
if (decoratedMembers.length > 0) {
|
||||
metaPropDecorators = ts.createObjectLiteral(decoratedMembers);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
||||
|
@ -40,7 +40,9 @@ export interface NgModuleAnalysis {
|
|||
providers: ts.Expression|null;
|
||||
}
|
||||
|
||||
export interface NgModuleResolution { injectorImports: Expression[]; }
|
||||
export interface NgModuleResolution {
|
||||
injectorImports: Expression[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles @NgModule annotations to ngModuleDef fields.
|
||||
|
@ -116,7 +118,7 @@ export class NgModuleDecoratorHandler implements
|
|||
let declarationRefs: Reference<ClassDeclaration>[] = [];
|
||||
let rawDeclarations: ts.Expression|null = null;
|
||||
if (ngModule.has('declarations')) {
|
||||
rawDeclarations = ngModule.get('declarations') !;
|
||||
rawDeclarations = ngModule.get('declarations')!;
|
||||
const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver);
|
||||
declarationRefs =
|
||||
this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations');
|
||||
|
@ -128,7 +130,9 @@ export class NgModuleDecoratorHandler implements
|
|||
|
||||
diagnostics.push(makeDiagnostic(
|
||||
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,
|
||||
messageText: `'${ref.node.name.text}' is declared here.`,
|
||||
|
@ -144,28 +148,28 @@ export class NgModuleDecoratorHandler implements
|
|||
let importRefs: Reference<ClassDeclaration>[] = [];
|
||||
let rawImports: ts.Expression|null = null;
|
||||
if (ngModule.has('imports')) {
|
||||
rawImports = ngModule.get('imports') !;
|
||||
rawImports = ngModule.get('imports')!;
|
||||
const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers);
|
||||
importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports');
|
||||
}
|
||||
let exportRefs: Reference<ClassDeclaration>[] = [];
|
||||
let rawExports: ts.Expression|null = null;
|
||||
if (ngModule.has('exports')) {
|
||||
rawExports = ngModule.get('exports') !;
|
||||
rawExports = ngModule.get('exports')!;
|
||||
const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers);
|
||||
exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports');
|
||||
this.referencesRegistry.add(node, ...exportRefs);
|
||||
}
|
||||
let bootstrapRefs: Reference<ClassDeclaration>[] = [];
|
||||
if (ngModule.has('bootstrap')) {
|
||||
const expr = ngModule.get('bootstrap') !;
|
||||
const expr = ngModule.get('bootstrap')!;
|
||||
const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver);
|
||||
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
||||
}
|
||||
|
||||
const schemas: SchemaMetadata[] = [];
|
||||
if (ngModule.has('schemas')) {
|
||||
const rawExpr = ngModule.get('schemas') !;
|
||||
const rawExpr = ngModule.get('schemas')!;
|
||||
const result = this.evaluator.evaluate(rawExpr);
|
||||
if (!Array.isArray(result)) {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -203,7 +207,7 @@ export class NgModuleDecoratorHandler implements
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
let typeContext = valueContext;
|
||||
|
@ -220,7 +224,7 @@ export class NgModuleDecoratorHandler implements
|
|||
const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext));
|
||||
|
||||
const isForwardReference = (ref: R3Reference) =>
|
||||
isExpressionForwardReference(ref.value, node.name !, valueContext);
|
||||
isExpressionForwardReference(ref.value, node.name!, valueContext);
|
||||
const containsForwardDecls = bootstrap.some(isForwardReference) ||
|
||||
declarations.some(isForwardReference) || imports.some(isForwardReference) ||
|
||||
exports.some(isForwardReference);
|
||||
|
@ -244,7 +248,7 @@ export class NgModuleDecoratorHandler implements
|
|||
schemas: [],
|
||||
};
|
||||
|
||||
const rawProviders = ngModule.has('providers') ? ngModule.get('providers') ! : null;
|
||||
const rawProviders = ngModule.has('providers') ? ngModule.get('providers')! : null;
|
||||
const wrapperProviders = rawProviders !== null ?
|
||||
new WrappedNodeExpr(
|
||||
this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) :
|
||||
|
@ -256,7 +260,7 @@ export class NgModuleDecoratorHandler implements
|
|||
// and pipes from the module exports.
|
||||
const injectorImports: WrappedNodeExpr<ts.Expression>[] = [];
|
||||
if (ngModule.has('imports')) {
|
||||
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports') !));
|
||||
injectorImports.push(new WrappedNodeExpr(ngModule.get('imports')!));
|
||||
}
|
||||
|
||||
if (this.routeAnalyzer !== null) {
|
||||
|
@ -279,7 +283,8 @@ export class NgModuleDecoratorHandler implements
|
|||
schemas: schemas,
|
||||
mod: ngModuleDef,
|
||||
inj: ngInjectorDef,
|
||||
declarations: declarationRefs, rawDeclarations,
|
||||
declarations: declarationRefs,
|
||||
rawDeclarations,
|
||||
imports: importRefs,
|
||||
exports: exportRefs,
|
||||
providers: rawProviders,
|
||||
|
@ -326,7 +331,7 @@ export class NgModuleDecoratorHandler implements
|
|||
|
||||
if (analysis.providersRequiringFactory !== null) {
|
||||
const providerDiagnostics = getProviderDiagnostics(
|
||||
analysis.providersRequiringFactory, analysis.providers !, this.injectableRegistry);
|
||||
analysis.providersRequiringFactory, analysis.providers!, this.injectableRegistry);
|
||||
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 directiveArray = new LiteralArrayExpr(directives);
|
||||
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 callExpr =
|
||||
new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
||||
|
@ -472,8 +477,9 @@ export class NgModuleDecoratorHandler implements
|
|||
return null;
|
||||
}
|
||||
|
||||
const typeName = type && (ts.isIdentifier(type.typeName) && type.typeName ||
|
||||
ts.isQualifiedName(type.typeName) && type.typeName.right) ||
|
||||
const typeName = type &&
|
||||
(ts.isIdentifier(type.typeName) && type.typeName ||
|
||||
ts.isQualifiedName(type.typeName) && type.typeName.right) ||
|
||||
null;
|
||||
if (typeName === null) {
|
||||
return null;
|
||||
|
@ -559,7 +565,7 @@ export class NgModuleDecoratorHandler implements
|
|||
// 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).
|
||||
if (entry instanceof Map && entry.has('ngModule')) {
|
||||
entry = entry.get('ngModule') !;
|
||||
entry = entry.get('ngModule')!;
|
||||
}
|
||||
|
||||
if (Array.isArray(entry)) {
|
||||
|
@ -569,14 +575,16 @@ export class NgModuleDecoratorHandler implements
|
|||
if (!this.isClassDeclarationReference(entry)) {
|
||||
throw new FatalDiagnosticError(
|
||||
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);
|
||||
} else {
|
||||
// TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
|
||||
throw new FatalDiagnosticError(
|
||||
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
|
||||
*/
|
||||
|
||||
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 {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
|
@ -79,7 +79,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
|||
throw new FatalDiagnosticError(
|
||||
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);
|
||||
if (typeof pipeName !== 'string') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -88,7 +88,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
|||
|
||||
let pure = true;
|
||||
if (pipe.has('pure')) {
|
||||
const expr = pipe.get('pure') !;
|
||||
const expr = pipe.get('pure')!;
|
||||
const pureValue = this.evaluator.evaluate(expr);
|
||||
if (typeof pureValue !== 'boolean') {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -103,7 +103,8 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
|
|||
name,
|
||||
type,
|
||||
internalType,
|
||||
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0, pipeName,
|
||||
typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0,
|
||||
pipeName,
|
||||
deps: getValidConstructorDependencies(
|
||||
clazz, this.reflector, this.defaultImportRecorder, this.isCore),
|
||||
pure,
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
|||
import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics';
|
||||
import {DefaultImportRecorder, ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
||||
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';
|
||||
|
||||
export enum ConstructorDepErrorKind {
|
||||
|
@ -21,8 +21,7 @@ export enum ConstructorDepErrorKind {
|
|||
|
||||
export type ConstructorDeps = {
|
||||
deps: R3DependencyMetadata[];
|
||||
} |
|
||||
{
|
||||
}|{
|
||||
deps: null;
|
||||
errors: ConstructorDepError[];
|
||||
};
|
||||
|
@ -53,7 +52,7 @@ export function getConstructorDependencies(
|
|||
let resolved = R3ResolvedDependencyType.Token;
|
||||
|
||||
(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 (dec.args === null || dec.args.length !== 1) {
|
||||
throw new FatalDiagnosticError(
|
||||
|
@ -97,7 +96,8 @@ export function getConstructorDependencies(
|
|||
if (token === null) {
|
||||
errors.push({
|
||||
index: idx,
|
||||
kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, param,
|
||||
kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN,
|
||||
param,
|
||||
});
|
||||
} else {
|
||||
deps.push({token, attribute, optional, self, skipSelf, host, resolved});
|
||||
|
@ -122,10 +122,10 @@ export function valueReferenceToExpression(
|
|||
export function valueReferenceToExpression(
|
||||
valueRef: null, defaultImportRecorder: DefaultImportRecorder): null;
|
||||
export function valueReferenceToExpression(
|
||||
valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||
valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||
null;
|
||||
export function valueReferenceToExpression(
|
||||
valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||
valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression|
|
||||
null {
|
||||
if (valueRef === null) {
|
||||
return null;
|
||||
|
@ -138,7 +138,7 @@ export function valueReferenceToExpression(
|
|||
return new WrappedNodeExpr(valueRef.expression);
|
||||
} else {
|
||||
// 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.
|
||||
*/
|
||||
export function unwrapConstructorDependencies(deps: ConstructorDeps | null): R3DependencyMetadata[]|
|
||||
export function unwrapConstructorDependencies(deps: ConstructorDeps|null): R3DependencyMetadata[]|
|
||||
'invalid'|null {
|
||||
if (deps === null) {
|
||||
return null;
|
||||
|
@ -176,18 +176,19 @@ export function getValidConstructorDependencies(
|
|||
* deps.
|
||||
*/
|
||||
export function validateConstructorDependencies(
|
||||
clazz: ClassDeclaration, deps: ConstructorDeps | null): R3DependencyMetadata[]|null {
|
||||
clazz: ClassDeclaration, deps: ConstructorDeps|null): R3DependencyMetadata[]|null {
|
||||
if (deps === null) {
|
||||
return null;
|
||||
} else if (deps.deps !== null) {
|
||||
return deps.deps;
|
||||
} else {
|
||||
// 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.
|
||||
throw new FatalDiagnosticError(
|
||||
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()}` :
|
||||
'no type or decorator'));
|
||||
}
|
||||
|
@ -319,8 +320,7 @@ export function forwardRefResolver(
|
|||
*/
|
||||
export function combineResolvers(resolvers: ForeignFunctionResolver[]): ForeignFunctionResolver {
|
||||
return (ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>,
|
||||
args: ReadonlyArray<ts.Expression>): ts.Expression |
|
||||
null => {
|
||||
args: ReadonlyArray<ts.Expression>): ts.Expression|null => {
|
||||
for (const resolver of resolvers) {
|
||||
const resolved = resolver(ref, args);
|
||||
if (resolved !== null) {
|
||||
|
@ -406,8 +406,8 @@ export function makeDuplicateDeclarationError(
|
|||
const contextNode = decl.ref.getOriginForDiagnostics(decl.rawDeclarations, decl.ngModule.name);
|
||||
context.push({
|
||||
node: contextNode,
|
||||
messageText:
|
||||
`'${node.name.text}' is listed in the declarations of the NgModule '${decl.ngModule.name.text}'.`,
|
||||
messageText: `'${node.name.text}' is listed in the declarations of the NgModule '${
|
||||
decl.ngModule.name.text}'.`,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,7 @@ export function resolveProvidersRequiringFactory(
|
|||
} else if (provider instanceof Reference) {
|
||||
tokenClass = provider;
|
||||
} 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) {
|
||||
tokenClass = useExisting;
|
||||
}
|
||||
|
|
|
@ -12,17 +12,23 @@ import {runInEachFileSystem} from '../../file_system/testing';
|
|||
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
||||
import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {ResourceLoader} from '../src/api';
|
||||
import {ComponentDecoratorHandler} from '../src/component';
|
||||
|
||||
export class NoopResourceLoader implements ResourceLoader {
|
||||
resolve(): string { throw new Error('Not implemented.'); }
|
||||
resolve(): string {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
canPreload = false;
|
||||
load(): string { throw new Error('Not implemented'); }
|
||||
preload(): Promise<void>|undefined { throw new Error('Not implemented'); }
|
||||
load(): string {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
preload(): Promise<void>|undefined {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
runInEachFileSystem(() => {
|
||||
describe('ComponentDecoratorHandler', () => {
|
||||
|
@ -83,10 +89,12 @@ runInEachFileSystem(() => {
|
|||
const diag = err.toDiagnostic();
|
||||
expect(diag.code).toEqual(ivyCode(ErrorCode.DECORATOR_ARG_NOT_LITERAL));
|
||||
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
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {absoluteFrom} from '../../file_system';
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
|
||||
import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {ClassDeclaration, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {DirectiveDecoratorHandler} from '../src/directive';
|
||||
|
@ -77,9 +78,13 @@ runInEachFileSystem(() => {
|
|||
// Helpers
|
||||
function analyzeDirective(program: ts.Program, dirName: string, hasBaseClass: boolean = false) {
|
||||
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();
|
||||
|
|
|
@ -10,7 +10,7 @@ import {absoluteFrom} from '../../file_system';
|
|||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports';
|
||||
import {InjectableClassRegistry} from '../../metadata';
|
||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {InjectableDecoratorHandler} from '../src/injectable';
|
||||
|
||||
|
@ -31,7 +31,7 @@ runInEachFileSystem(() => {
|
|||
const diag = err.toDiagnostic();
|
||||
expect(diag.code).toEqual(ngErrorCode(ErrorCode.INJECTABLE_DUPLICATE_PROV));
|
||||
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'}));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
|
||||
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 {TypeScriptReflectionHost} from '../../reflection';
|
||||
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 {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {NgModuleDecoratorHandler} from '../src/ng_module';
|
||||
|
@ -79,7 +79,7 @@ runInEachFileSystem(() => {
|
|||
if (detected === undefined) {
|
||||
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.exports)).toEqual(['TestComp']);
|
||||
|
|
|
@ -13,8 +13,9 @@ import {unwrapExpression} from '../src/util';
|
|||
describe('ngtsc annotation utilities', () => {
|
||||
describe('unwrapExpression', () => {
|
||||
const obj = ts.createObjectLiteral();
|
||||
it('should pass through an ObjectLiteralExpression',
|
||||
() => { expect(unwrapExpression(obj)).toBe(obj); });
|
||||
it('should pass through an ObjectLiteralExpression', () => {
|
||||
expect(unwrapExpression(obj)).toBe(obj);
|
||||
});
|
||||
|
||||
it('should unwrap an ObjectLiteralExpression in parentheses', () => {
|
||||
const wrapped = ts.createParen(obj);
|
||||
|
|
|
@ -56,7 +56,7 @@ export interface ResourceHost {
|
|||
* core interface.
|
||||
*/
|
||||
export interface ExtendedTsCompilerHost extends ts.CompilerHost, Partial<ResourceHost>,
|
||||
Partial<UnifiedModulesHost> {}
|
||||
Partial<UnifiedModulesHost> {}
|
||||
|
||||
export interface LazyRoute {
|
||||
route: string;
|
||||
|
|
|
@ -36,7 +36,8 @@ export interface TestOnlyOptions {
|
|||
*/
|
||||
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:'
|
||||
* 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.
|
||||
*/
|
||||
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 {CycleAnalyzer, ImportGraph} from '../../cycles';
|
||||
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
||||
import {ReferenceGraph, checkForPrivateExports} from '../../entry_point';
|
||||
import {LogicalFileSystem, getSourceFileOrError} from '../../file_system';
|
||||
import {AbsoluteModuleStrategy, AliasStrategy, AliasingHost, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports';
|
||||
import {checkForPrivateExports, ReferenceGraph} from '../../entry_point';
|
||||
import {getSourceFileOrError, LogicalFileSystem} from '../../file_system';
|
||||
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 {IndexedComponent, IndexingContext, generateAnalysis} from '../../indexer';
|
||||
import {generateAnalysis, IndexedComponent, IndexingContext} from '../../indexer';
|
||||
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, MetadataReader} from '../../metadata';
|
||||
import {ModuleWithProvidersScanner} from '../../modulewithproviders';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf';
|
||||
import {TypeScriptReflectionHost} from '../../reflection';
|
||||
import {HostResourceLoader} from '../../resource';
|
||||
import {NgModuleRouteAnalyzer, entryPointKeyFor} from '../../routing';
|
||||
import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing';
|
||||
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
|
||||
import {generatedFactoryTransform} from '../../shims';
|
||||
import {ivySwitchTransform} from '../../switch';
|
||||
import {DecoratorHandler, DtsTransformRegistry, TraitCompiler, aliasTransformFactory, declarationTransformFactory, ivyTransformFactory} from '../../transform';
|
||||
import {TypeCheckContext, TypeCheckingConfig, isTemplateDiagnostic} from '../../typecheck';
|
||||
import {aliasTransformFactory, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
||||
import {isTemplateDiagnostic, TypeCheckContext, TypeCheckingConfig} from '../../typecheck';
|
||||
import {getSourceFileOrNull, isDtsPath, resolveModuleName} from '../../util/src/typescript';
|
||||
import {LazyRoute, NgCompilerOptions} from '../api';
|
||||
|
||||
|
@ -191,7 +191,9 @@ export class NgCompiler {
|
|||
/**
|
||||
* 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
|
||||
|
@ -202,7 +204,9 @@ export class NgCompiler {
|
|||
* 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.
|
||||
*/
|
||||
getNextProgram(): ts.Program { return this.nextProgram; }
|
||||
getNextProgram(): ts.Program {
|
||||
return this.nextProgram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform Angular's analysis step (as a precursor to `getDiagnostics` or `prepareEmit`)
|
||||
|
@ -262,8 +266,8 @@ export class NgCompiler {
|
|||
|
||||
// Relative entry paths are disallowed.
|
||||
if (entryRoute.startsWith('.')) {
|
||||
throw new Error(
|
||||
`Failed to list lazy routes: Resolution of relative paths (${entryRoute}) is not supported.`);
|
||||
throw new Error(`Failed to list lazy routes: Resolution of relative paths (${
|
||||
entryRoute}) is not supported.`);
|
||||
}
|
||||
|
||||
// Non-relative entry paths fall into one of the following categories:
|
||||
|
@ -349,7 +353,7 @@ export class NgCompiler {
|
|||
if (this.compilation === null) {
|
||||
this.analyzeSync();
|
||||
}
|
||||
return this.compilation !;
|
||||
return this.compilation!;
|
||||
}
|
||||
|
||||
private analyzeSync(): void {
|
||||
|
@ -482,7 +486,7 @@ export class NgCompiler {
|
|||
// Execute the typeCheck phase of each decorator in the program.
|
||||
const prepSpan = this.perfRecorder.start('typeCheckPrep');
|
||||
const ctx = new TypeCheckContext(
|
||||
typeCheckingConfig, compilation.refEmitter !, compilation.reflector, host.typeCheckFile);
|
||||
typeCheckingConfig, compilation.refEmitter!, compilation.reflector, host.typeCheckFile);
|
||||
compilation.traitCompiler.typeCheck(ctx);
|
||||
this.perfRecorder.stop(prepSpan);
|
||||
|
||||
|
@ -505,7 +509,7 @@ export class NgCompiler {
|
|||
const recordSpan = this.perfRecorder.start('recordDependencies');
|
||||
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 ngModuleFile = scope.ngModule.getSourceFile();
|
||||
|
||||
|
@ -517,7 +521,7 @@ export class NgCompiler {
|
|||
depGraph.addDependency(file, ngModuleFile);
|
||||
|
||||
const meta =
|
||||
this.compilation !.metaReader.getDirectiveMetadata(new Reference(scope.declaration));
|
||||
this.compilation!.metaReader.getDirectiveMetadata(new Reference(scope.declaration));
|
||||
if (meta !== null && meta.isComponent) {
|
||||
// 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,
|
||||
|
@ -543,12 +547,11 @@ export class NgCompiler {
|
|||
}
|
||||
|
||||
private scanForMwp(sf: ts.SourceFile): void {
|
||||
this.compilation !.mwpScanner.scan(sf, {
|
||||
this.compilation!.mwpScanner.scan(sf, {
|
||||
addTypeReplacement: (node: ts.Declaration, type: Type): void => {
|
||||
// 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.
|
||||
this.compilation !.dtsTransforms !.getReturnTypeTransform(sf).addTypeReplacement(
|
||||
node, type);
|
||||
this.compilation!.dtsTransforms!.getReturnTypeTransform(sf).addTypeReplacement(node, type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -686,9 +689,18 @@ export class NgCompiler {
|
|||
this.options.compileNonExportedClasses !== false, dtsTransforms);
|
||||
|
||||
return {
|
||||
isCore, traitCompiler, reflector, scopeRegistry,
|
||||
dtsTransforms, exportReferenceGraph, routeAnalyzer, mwpScanner,
|
||||
metaReader, defaultImportTracker, aliasingHost, refEmitter,
|
||||
isCore,
|
||||
traitCompiler,
|
||||
reflector,
|
||||
scopeRegistry,
|
||||
dtsTransforms,
|
||||
exportReferenceGraph,
|
||||
routeAnalyzer,
|
||||
mwpScanner,
|
||||
metaReader,
|
||||
defaultImportTracker,
|
||||
aliasingHost,
|
||||
refEmitter,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, ngErrorCode} from '../../diagnostics';
|
||||
import {FlatIndexGenerator, findFlatIndexEntryPoint} from '../../entry_point';
|
||||
import {findFlatIndexEntryPoint, FlatIndexGenerator} from '../../entry_point';
|
||||
import {AbsoluteFsPath, resolve} from '../../file_system';
|
||||
import {FactoryGenerator, FactoryTracker, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator} from '../../shims';
|
||||
import {typeCheckFilePath} from '../../typecheck';
|
||||
|
@ -88,8 +88,7 @@ export class DelegatingCompilerHost implements
|
|||
* `ExtendedTsCompilerHost` methods whenever present.
|
||||
*/
|
||||
export class NgCompilerHost extends DelegatingCompilerHost implements
|
||||
RequiredCompilerHostDelegations,
|
||||
ExtendedTsCompilerHost {
|
||||
RequiredCompilerHostDelegations, ExtendedTsCompilerHost {
|
||||
readonly factoryTracker: FactoryTracker|null = null;
|
||||
readonly entryPoint: AbsoluteFsPath|null = null;
|
||||
readonly diagnostics: ts.Diagnostic[];
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
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 {NgCompilerOptions} from '../api';
|
||||
import {NgCompiler} from '../src/compiler';
|
||||
|
@ -16,7 +16,6 @@ import {NgCompilerHost} from '../src/host';
|
|||
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
|
||||
describe('NgCompiler', () => {
|
||||
let fs: FileSystem;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ export class ImportGraph {
|
|||
if (!this.map.has(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;
|
||||
}
|
||||
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()),
|
||||
file: ts.getOriginalNode(node).getSourceFile(),
|
||||
start: node.getStart(undefined, false),
|
||||
length: node.getWidth(), messageText,
|
||||
length: node.getWidth(),
|
||||
messageText,
|
||||
};
|
||||
if (relatedInfo !== undefined) {
|
||||
diag.relatedInformation = relatedInfo.map(info => {
|
||||
|
|
|
@ -24,7 +24,9 @@ export class FlatIndexGenerator implements ShimGenerator {
|
|||
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 {
|
||||
const relativeEntryPoint = relativePathBetween(this.flatIndexPath, this.entryPoint);
|
||||
|
|
|
@ -95,9 +95,11 @@ export function checkForPrivateExports(
|
|||
const diagnostic: ts.Diagnostic = {
|
||||
category: ts.DiagnosticCategory.Error,
|
||||
code: ngErrorCode(ErrorCode.SYMBOL_NOT_EXPORTED),
|
||||
file: transitiveReference.getSourceFile(), ...getPosOfDeclaration(transitiveReference),
|
||||
messageText:
|
||||
`Unsupported private ${descriptor} ${name}. This ${descriptor} is visible to consumers via ${visibleVia}, but is not exported from the top-level library entrypoint.`,
|
||||
file: transitiveReference.getSourceFile(),
|
||||
...getPosOfDeclaration(transitiveReference),
|
||||
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);
|
||||
|
|
|
@ -15,7 +15,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
|||
if (!this.references.has(from)) {
|
||||
this.references.set(from, new Set());
|
||||
}
|
||||
this.references.get(from) !.add(to);
|
||||
this.references.get(from)!.add(to);
|
||||
}
|
||||
|
||||
transitiveReferencesOf(target: T): Set<T> {
|
||||
|
@ -47,7 +47,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
|||
// Look through the outgoing edges of `source`.
|
||||
// TODO(alxhub): use proper iteration when the legacy build is removed. (#27762)
|
||||
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.
|
||||
if (candidatePath !== null) {
|
||||
return;
|
||||
|
@ -67,7 +67,7 @@ export class ReferenceGraph<T = ts.Declaration> {
|
|||
private collectTransitiveReferences(set: Set<T>, decl: T): void {
|
||||
if (this.references.has(decl)) {
|
||||
// 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)) {
|
||||
set.add(ref);
|
||||
this.collectTransitiveReferences(set, ref);
|
||||
|
|
|
@ -16,9 +16,9 @@ runInEachFileSystem(() => {
|
|||
beforeEach(() => _ = absoluteFrom);
|
||||
|
||||
describe('findFlatIndexEntryPoint', () => {
|
||||
|
||||
it('should use the only source file if only a single one is specified',
|
||||
() => { expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts')); });
|
||||
it('should use the only source file if only a single one is specified', () => {
|
||||
expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts'));
|
||||
});
|
||||
|
||||
it('should use the shortest source file ending with "index.ts" for multiple files', () => {
|
||||
expect(findFlatIndexEntryPoint([
|
||||
|
|
|
@ -12,8 +12,9 @@ import {ReferenceGraph} from '../src/reference_graph';
|
|||
describe('entry_point reference graph', () => {
|
||||
let graph: ReferenceGraph<string>;
|
||||
|
||||
const refs =
|
||||
(target: string) => { return Array.from(graph.transitiveReferencesOf(target)).sort(); };
|
||||
const refs = (target: string) => {
|
||||
return Array.from(graph.transitiveReferencesOf(target)).sort();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
graph = new ReferenceGraph();
|
||||
|
@ -45,6 +46,7 @@ describe('entry_point reference graph', () => {
|
|||
expect(graph.pathFrom('beta', 'alpha')).toEqual(['beta', 'delta', 'alpha']);
|
||||
});
|
||||
|
||||
it('should not report a path that doesn\'t exist',
|
||||
() => { expect(graph.pathFrom('gamma', 'beta')).toBeNull(); });
|
||||
it('should not report a path that doesn\'t exist', () => {
|
||||
expect(graph.pathFrom('gamma', 'beta')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ export class CachedFileSystem implements FileSystem {
|
|||
if (!this.existsCache.has(path)) {
|
||||
this.existsCache.set(path, this.delegate.exists(path));
|
||||
}
|
||||
return this.existsCache.get(path) !;
|
||||
return this.existsCache.get(path)!;
|
||||
}
|
||||
|
||||
invalidateCaches(path: AbsoluteFsPath) {
|
||||
|
@ -131,15 +131,33 @@ export class CachedFileSystem implements FileSystem {
|
|||
}
|
||||
|
||||
// The following methods simply call through to the delegate.
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { return this.delegate.readdir(path); }
|
||||
pwd(): AbsoluteFsPath { return this.delegate.pwd(); }
|
||||
chdir(path: AbsoluteFsPath): void { this.delegate.chdir(path); }
|
||||
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); }
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||
return this.delegate.readdir(path);
|
||||
}
|
||||
pwd(): AbsoluteFsPath {
|
||||
return this.delegate.pwd();
|
||||
}
|
||||
chdir(path: AbsoluteFsPath): void {
|
||||
this.delegate.chdir(path);
|
||||
}
|
||||
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 {
|
||||
return this.delegate.join(basePath, ...paths);
|
||||
}
|
||||
|
@ -149,7 +167,13 @@ export class CachedFileSystem implements FileSystem {
|
|||
basename(filePath: string, extension?: string|undefined): PathSegment {
|
||||
return this.delegate.basename(filePath, extension);
|
||||
}
|
||||
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { return this.delegate.realpath(filePath); }
|
||||
getDefaultLibLocation(): AbsoluteFsPath { return this.delegate.getDefaultLibLocation(); }
|
||||
normalize<T extends PathString>(path: T): T { return this.delegate.normalize(path); }
|
||||
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath {
|
||||
return this.delegate.realpath(filePath);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
getDefaultLibLocation(): string { return this.fs.getDefaultLibLocation(); }
|
||||
getDefaultLibLocation(): string {
|
||||
return this.fs.getDefaultLibLocation();
|
||||
}
|
||||
|
||||
writeFile(
|
||||
fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
|
@ -37,13 +39,17 @@ export class NgtscCompilerHost implements ts.CompilerHost {
|
|||
this.fs.writeFile(path, data);
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string { return this.fs.pwd(); }
|
||||
getCurrentDirectory(): string {
|
||||
return this.fs.pwd();
|
||||
}
|
||||
|
||||
getCanonicalFileName(fileName: string): string {
|
||||
return this.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
useCaseSensitiveFileNames(): boolean { return this.fs.isCaseSensitive(); }
|
||||
useCaseSensitiveFileNames(): boolean {
|
||||
return this.fs.isCaseSensitive();
|
||||
}
|
||||
|
||||
getNewLine(): string {
|
||||
switch (this.options.newLine) {
|
||||
|
|
|
@ -16,32 +16,84 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
|||
* the `FileSystem` under the hood.
|
||||
*/
|
||||
export class InvalidFileSystem implements FileSystem {
|
||||
exists(path: AbsoluteFsPath): boolean { throw makeError(); }
|
||||
readFile(path: AbsoluteFsPath): string { throw makeError(); }
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { throw makeError(); }
|
||||
removeFile(path: AbsoluteFsPath): void { throw makeError(); }
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); }
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); }
|
||||
lstat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
||||
stat(path: AbsoluteFsPath): FileStats { throw makeError(); }
|
||||
pwd(): AbsoluteFsPath { 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(); }
|
||||
exists(path: AbsoluteFsPath): boolean {
|
||||
throw makeError();
|
||||
}
|
||||
readFile(path: AbsoluteFsPath): string {
|
||||
throw makeError();
|
||||
}
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void {
|
||||
throw makeError();
|
||||
}
|
||||
removeFile(path: AbsoluteFsPath): void {
|
||||
throw makeError();
|
||||
}
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void {
|
||||
throw makeError();
|
||||
}
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||
throw makeError();
|
||||
}
|
||||
lstat(path: AbsoluteFsPath): FileStats {
|
||||
throw makeError();
|
||||
}
|
||||
stat(path: AbsoluteFsPath): FileStats {
|
||||
throw makeError();
|
||||
}
|
||||
pwd(): AbsoluteFsPath {
|
||||
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() {
|
||||
|
|
|
@ -91,7 +91,7 @@ export class LogicalFileSystem {
|
|||
}
|
||||
this.cache.set(physicalFile, logicalFile);
|
||||
}
|
||||
return this.cache.get(physicalFile) !;
|
||||
return this.cache.get(physicalFile)!;
|
||||
}
|
||||
|
||||
private createLogicalProjectPath(file: AbsoluteFsPath, rootDir: AbsoluteFsPath):
|
||||
|
|
|
@ -17,20 +17,42 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
|||
*/
|
||||
export class NodeJSFileSystem implements FileSystem {
|
||||
private _caseSensitive: boolean|undefined = undefined;
|
||||
exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); }
|
||||
readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); }
|
||||
exists(path: AbsoluteFsPath): boolean {
|
||||
return fs.existsSync(path);
|
||||
}
|
||||
readFile(path: AbsoluteFsPath): string {
|
||||
return fs.readFileSync(path, 'utf8');
|
||||
}
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
|
||||
fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined);
|
||||
}
|
||||
removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); }
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); }
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; }
|
||||
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); }
|
||||
removeFile(path: AbsoluteFsPath): void {
|
||||
fs.unlinkSync(path);
|
||||
}
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void {
|
||||
fs.symlinkSync(target, path);
|
||||
}
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] {
|
||||
return fs.readdirSync(path) as PathSegment[];
|
||||
}
|
||||
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 {
|
||||
const parents: AbsoluteFsPath[] = [];
|
||||
while (!this.isRoot(path) && !this.exists(path)) {
|
||||
|
@ -38,10 +60,12 @@ export class NodeJSFileSystem implements FileSystem {
|
|||
path = this.dirname(path);
|
||||
}
|
||||
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 {
|
||||
if (this._caseSensitive === undefined) {
|
||||
this._caseSensitive = this.exists(togglePathCase(__filename));
|
||||
|
@ -52,20 +76,30 @@ export class NodeJSFileSystem implements FileSystem {
|
|||
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 {
|
||||
return this.normalize(p.join(basePath, ...paths)) as T;
|
||||
}
|
||||
isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === this.normalize(path); }
|
||||
isRooted(path: string): boolean { return p.isAbsolute(path); }
|
||||
isRoot(path: AbsoluteFsPath): boolean {
|
||||
return this.dirname(path) === this.normalize(path);
|
||||
}
|
||||
isRooted(path: string): boolean {
|
||||
return p.isAbsolute(path);
|
||||
}
|
||||
relative<T extends PathString>(from: T, to: T): PathSegment {
|
||||
return relativeFrom(this.normalize(p.relative(from, to)));
|
||||
}
|
||||
basename(filePath: string, extension?: string): PathSegment {
|
||||
return p.basename(filePath, extension) as PathSegment;
|
||||
}
|
||||
extname(path: AbsoluteFsPath|PathSegment): string { return p.extname(path); }
|
||||
realpath(path: AbsoluteFsPath): AbsoluteFsPath { return this.resolve(fs.realpathSync(path)); }
|
||||
extname(path: AbsoluteFsPath|PathSegment): string {
|
||||
return p.extname(path);
|
||||
}
|
||||
realpath(path: AbsoluteFsPath): AbsoluteFsPath {
|
||||
return this.resolve(fs.realpathSync(path));
|
||||
}
|
||||
getDefaultLibLocation(): AbsoluteFsPath {
|
||||
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`.
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
@ -63,7 +63,7 @@ export interface FileSystem {
|
|||
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.
|
||||
|
|
|
@ -28,8 +28,8 @@ export function stripExtension(path: string): string {
|
|||
export function getSourceFileOrError(program: ts.Program, fileName: AbsoluteFsPath): ts.SourceFile {
|
||||
const sf = program.getSourceFile(fileName);
|
||||
if (sf === undefined) {
|
||||
throw new Error(
|
||||
`Program does not contain "${fileName}" - available files are ${program.getSourceFiles().map(sf => sf.fileName).join(', ')}`);
|
||||
throw new Error(`Program does not contain "${fileName}" - available files are ${
|
||||
program.getSourceFiles().map(sf => sf.fileName).join(', ')}`);
|
||||
}
|
||||
return sf;
|
||||
}
|
||||
|
|
|
@ -11,37 +11,49 @@ import {absoluteFrom, relativeFrom, setFileSystem} from '../src/helpers';
|
|||
import {NodeJSFileSystem} from '../src/node_js_file_system';
|
||||
|
||||
describe('path types', () => {
|
||||
beforeEach(() => { setFileSystem(new NodeJSFileSystem()); });
|
||||
beforeEach(() => {
|
||||
setFileSystem(new NodeJSFileSystem());
|
||||
});
|
||||
|
||||
describe('absoluteFrom', () => {
|
||||
it('should not throw when creating one from an absolute path',
|
||||
() => { expect(() => absoluteFrom('/test.txt')).not.toThrow(); });
|
||||
it('should not throw when creating one from an absolute path', () => {
|
||||
expect(() => absoluteFrom('/test.txt')).not.toThrow();
|
||||
});
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
it('should not throw when creating one from a windows absolute path',
|
||||
() => { expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt'); });
|
||||
it('should not throw when creating one from a windows absolute path', () => {
|
||||
expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt');
|
||||
});
|
||||
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('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'); });
|
||||
() => {
|
||||
expect(absoluteFrom('C:/test.txt')).toEqual('C:/test.txt');
|
||||
});
|
||||
it('should support windows drive letters', () => {
|
||||
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',
|
||||
() => { expect(() => absoluteFrom('test.txt')).toThrow(); });
|
||||
it('should throw when creating one from a non-absolute path', () => {
|
||||
expect(() => absoluteFrom('test.txt')).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('relativeFrom', () => {
|
||||
it('should not throw when creating one from a relative path',
|
||||
() => { expect(() => relativeFrom('a/b/c.txt')).not.toThrow(); });
|
||||
it('should not throw when creating one from a relative path', () => {
|
||||
expect(() => relativeFrom('a/b/c.txt')).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw when creating one from an absolute path',
|
||||
() => { expect(() => relativeFrom('/a/b/c.txt')).toThrow(); });
|
||||
it('should throw when creating one from an absolute path', () => {
|
||||
expect(() => relativeFrom('/a/b/c.txt')).toThrow();
|
||||
});
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
it('should throw when creating one from a Windows absolute path',
|
||||
() => { expect(() => relativeFrom('C:/a/b/c.txt')).toThrow(); });
|
||||
it('should throw when creating one from a Windows absolute path', () => {
|
||||
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 {MockFileSystemPosix} from './src/mock_file_system_posix';
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
const {entity} = this.findFromPath(path);
|
||||
|
@ -142,7 +146,9 @@ export abstract class MockFileSystem implements FileSystem {
|
|||
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 {
|
||||
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 {
|
||||
// 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;
|
||||
protected abstract splitPath<T extends PathString>(path: T): string[];
|
||||
|
||||
dump(): Folder { return cloneFolder(this._fileTree); }
|
||||
init(folder: Folder): void { this._fileTree = cloneFolder(folder); }
|
||||
dump(): Folder {
|
||||
return cloneFolder(this._fileTree);
|
||||
}
|
||||
init(folder: Folder): void {
|
||||
this._fileTree = cloneFolder(folder);
|
||||
}
|
||||
|
||||
protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult {
|
||||
const followSymLinks = !!options && options.followSymLinks;
|
||||
|
@ -215,7 +229,7 @@ export abstract class MockFileSystem implements FileSystem {
|
|||
segments[0] = '';
|
||||
let current: Entity|null = this._fileTree;
|
||||
while (segments.length) {
|
||||
current = current[segments.shift() !];
|
||||
current = current[segments.shift()!];
|
||||
if (current === undefined) {
|
||||
return {path, entity: null};
|
||||
}
|
||||
|
@ -239,7 +253,7 @@ export abstract class MockFileSystem implements FileSystem {
|
|||
|
||||
protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +261,10 @@ export interface FindResult {
|
|||
path: AbsoluteFsPath;
|
||||
entity: Entity|null;
|
||||
}
|
||||
export type Entity = Folder | File | SymLink;
|
||||
export interface Folder { [pathSegments: string]: Entity; }
|
||||
export type Entity = Folder|File|SymLink;
|
||||
export interface Folder {
|
||||
[pathSegments: string]: Entity;
|
||||
}
|
||||
export type File = string;
|
||||
export class SymLink {
|
||||
constructor(public path: AbsoluteFsPath) {}
|
||||
|
@ -256,24 +272,32 @@ export class SymLink {
|
|||
|
||||
class MockFileStats implements FileStats {
|
||||
constructor(private entity: Entity) {}
|
||||
isFile(): boolean { return isFile(this.entity); }
|
||||
isDirectory(): boolean { return isFolder(this.entity); }
|
||||
isSymbolicLink(): boolean { return isSymLink(this.entity); }
|
||||
isFile(): boolean {
|
||||
return isFile(this.entity);
|
||||
}
|
||||
isDirectory(): boolean {
|
||||
return isFolder(this.entity);
|
||||
}
|
||||
isSymbolicLink(): boolean {
|
||||
return isSymLink(this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
export function isSymLink(item: Entity | null): item is SymLink {
|
||||
export function isSymLink(item: Entity|null): item is 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@ import {MockFileSystem} from './mock_file_system';
|
|||
const isWindows = os.platform() === 'win32';
|
||||
|
||||
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
|
||||
|
||||
|
@ -36,9 +38,13 @@ export class MockFileSystemNative extends MockFileSystem {
|
|||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
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()));
|
||||
callback(os);
|
||||
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};
|
||||
}
|
||||
|
||||
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,
|
||||
// which is internal to the `ts` namespace.
|
||||
const tsMatchFiles: (
|
||||
path: string, extensions: ReadonlyArray<string>| undefined,
|
||||
excludes: ReadonlyArray<string>| undefined, includes: ReadonlyArray<string>| undefined,
|
||||
useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined,
|
||||
path: string, extensions: ReadonlyArray<string>|undefined,
|
||||
excludes: ReadonlyArray<string>|undefined, includes: ReadonlyArray<string>|undefined,
|
||||
useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number|undefined,
|
||||
getFileSystemEntries: (path: string) => FileSystemEntries,
|
||||
realpath: (path: string) => string) => string[] = (ts as any).matchFiles;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default';
|
||||
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 {UnifiedModulesHost} from '../../core/api';
|
||||
import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
|
||||
|
||||
import {ImportFlags, ReferenceEmitStrategy} from './emitter';
|
||||
import {Reference} from './references';
|
||||
|
@ -203,7 +203,9 @@ export class PrivateExportAliasingHost implements AliasingHost {
|
|||
*
|
||||
* 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.
|
||||
*/
|
||||
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 {
|
||||
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 {
|
||||
if (specifier !== CORE_MODULE) {
|
||||
|
@ -89,8 +97,8 @@ export class R3SymbolsImportRewriter implements ImportRewriter {
|
|||
|
||||
const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath);
|
||||
if (relativePathToR3Symbols === null) {
|
||||
throw new Error(
|
||||
`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${this.r3SymbolsPath}`);
|
||||
throw new Error(`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${
|
||||
this.r3SymbolsPath}`);
|
||||
}
|
||||
|
||||
return relativePathToR3Symbols;
|
||||
|
@ -101,5 +109,5 @@ export function validateAndRewriteCoreSymbol(name: string): string {
|
|||
if (!CORE_SUPPORTED_SYMBOLS.has(name)) {
|
||||
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
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
|
@ -96,7 +96,7 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
|||
if (!this.sourceFileToImportMap.has(sf)) {
|
||||
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 {
|
||||
|
@ -105,18 +105,18 @@ export class DefaultImportTracker implements DefaultImportRecorder {
|
|||
// The identifier's source file has no registered default imports at all.
|
||||
return;
|
||||
}
|
||||
const identiferToDeclaration = this.sourceFileToImportMap.get(sf) !;
|
||||
const identiferToDeclaration = this.sourceFileToImportMap.get(sf)!;
|
||||
if (!identiferToDeclaration.has(id)) {
|
||||
// The identifier isn't from a registered default import.
|
||||
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.
|
||||
if (!this.sourceFileToUsedImports.has(sf)) {
|
||||
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> {
|
||||
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.
|
||||
const importsToPreserve = this.sourceFileToUsedImports.get(originalSf) !;
|
||||
const importsToPreserve = this.sourceFileToUsedImports.get(originalSf)!;
|
||||
|
||||
// Generate a new statement list which preserves any imports present in `importsToPreserve`.
|
||||
const statements = sf.statements.map(stmt => {
|
||||
|
|
|
@ -9,7 +9,7 @@ import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@ang
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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 {ReflectionHost} from '../../reflection';
|
||||
import {getSourceFile, isDeclaration, isTypeDeclaration, nodeNameForError} from '../../util/src/typescript';
|
||||
|
@ -93,8 +93,8 @@ export class ReferenceEmitter {
|
|||
return emitted;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Unable to write a reference to ${nodeNameForError(ref.node)} in ${ref.node.getSourceFile().fileName} from ${context.fileName}`);
|
||||
throw new Error(`Unable to write a reference to ${nodeNameForError(ref.node)} in ${
|
||||
ref.node.getSourceFile().fileName} from ${context.fileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,11 +149,11 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
|||
return null;
|
||||
} else if (!isDeclaration(ref.node)) {
|
||||
// It's not possible to import something which isn't a declaration.
|
||||
throw new Error(
|
||||
`Debug assert: unable to import a Reference to non-declaration of type ${ts.SyntaxKind[ref.node.kind]}.`);
|
||||
throw new Error(`Debug assert: unable to import a Reference to non-declaration of type ${
|
||||
ts.SyntaxKind[ref.node.kind]}.`);
|
||||
} else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) {
|
||||
throw new Error(
|
||||
`Importing a type-only declaration of type ${ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`);
|
||||
throw new Error(`Importing a type-only declaration of type ${
|
||||
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.
|
||||
|
@ -162,8 +162,9 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
|||
if (symbolName === null) {
|
||||
// TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be
|
||||
// triggered.
|
||||
throw new Error(
|
||||
`Symbol ${ref.debugName} declared in ${getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${context.fileName})`);
|
||||
throw new Error(`Symbol ${ref.debugName} declared in ${
|
||||
getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${
|
||||
context.fileName})`);
|
||||
}
|
||||
|
||||
return new ExternalExpr(new ExternalReference(specifier, symbolName));
|
||||
|
@ -173,7 +174,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
|||
|null {
|
||||
const exports = this.getExportsOfModule(moduleName, fromFile);
|
||||
if (exports !== null && exports.has(target)) {
|
||||
return exports.get(target) !;
|
||||
return exports.get(target)!;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -184,7 +185,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy {
|
|||
if (!this.moduleExportsCache.has(moduleName)) {
|
||||
this.moduleExportsCache.set(moduleName, this.enumerateExportsOfModule(moduleName, fromFile));
|
||||
}
|
||||
return this.moduleExportsCache.get(moduleName) !;
|
||||
return this.moduleExportsCache.get(moduleName)!;
|
||||
}
|
||||
|
||||
protected enumerateExportsOfModule(specifier: string, fromFile: string):
|
||||
|
|
|
@ -80,7 +80,9 @@ export class Reference<T extends ts.Node = ts.Node> {
|
|||
*
|
||||
* 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.
|
||||
|
@ -93,14 +95,18 @@ export class Reference<T extends ts.Node = ts.Node> {
|
|||
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
|
||||
* `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
|
||||
|
|
|
@ -39,7 +39,7 @@ runInEachFileSystem(() => {
|
|||
module: ts.ModuleKind.ES2015,
|
||||
});
|
||||
const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause);
|
||||
const fooId = fooClause.name !;
|
||||
const fooId = fooClause.name!;
|
||||
const fooDecl = fooClause.parent;
|
||||
|
||||
const tracker = new DefaultImportTracker();
|
||||
|
@ -48,7 +48,7 @@ runInEachFileSystem(() => {
|
|||
program.emit(undefined, undefined, undefined, undefined, {
|
||||
before: [tracker.importPreservingTransformer()],
|
||||
});
|
||||
const testContents = host.readFile('/test.js') !;
|
||||
const testContents = host.readFile('/test.js')!;
|
||||
expect(testContents).toContain(`import Foo from './dep';`);
|
||||
|
||||
// The control should have the import elided.
|
||||
|
@ -69,7 +69,7 @@ runInEachFileSystem(() => {
|
|||
module: ts.ModuleKind.CommonJS,
|
||||
});
|
||||
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 tracker = new DefaultImportTracker();
|
||||
|
@ -81,7 +81,7 @@ runInEachFileSystem(() => {
|
|||
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 ref = dep_1["default"];`);
|
||||
});
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
import {ExternalExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {LogicalFileSystem, absoluteFrom as _} from '../../file_system';
|
||||
import {TestFile, runInEachFileSystem} from '../../file_system/testing';
|
||||
import {absoluteFrom as _, LogicalFileSystem} from '../../file_system';
|
||||
import {runInEachFileSystem, TestFile} from '../../file_system/testing';
|
||||
import {Declaration, TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
import {AbsoluteModuleStrategy, ImportFlags, LogicalProjectStrategy} from '../src/emitter';
|
||||
|
@ -42,7 +42,7 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
const decl =
|
||||
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 emitted = strategy.emit(reference, context, ImportFlags.None);
|
||||
|
@ -65,7 +65,7 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
const decl =
|
||||
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, {
|
||||
specifier: 'external',
|
||||
|
@ -92,7 +92,7 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
const decl = getDeclaration(
|
||||
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, {
|
||||
specifier: 'external',
|
||||
|
@ -116,7 +116,7 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
const decl = getDeclaration(
|
||||
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, {specifier: 'external', resolutionContext: context.fileName});
|
||||
|
@ -139,7 +139,9 @@ runInEachFileSystem(() => {
|
|||
return null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -158,12 +160,12 @@ runInEachFileSystem(() => {
|
|||
const logicalFs = new LogicalFileSystem([_('/')]);
|
||||
const strategy = new LogicalProjectStrategy(new TestHost(checker), logicalFs);
|
||||
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);
|
||||
expect(ref).not.toBeNull();
|
||||
|
||||
// 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.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
|
|
|
@ -23,11 +23,13 @@ import {DependencyTracker} from '../api';
|
|||
* 2. One of its 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> {
|
||||
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 {
|
||||
this.nodeFor(from).usesResources.add(resource);
|
||||
|
@ -103,7 +105,7 @@ export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> im
|
|||
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
|
||||
* 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>,
|
||||
changedResources: ReadonlySet<AbsoluteFsPath>): boolean {
|
||||
// A file is logically changed if it has physically changed itself (including being deleted).
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteFsPath, absoluteFrom} from '../../file_system';
|
||||
import {absoluteFrom, AbsoluteFsPath} from '../../file_system';
|
||||
import {ClassRecord, TraitCompiler} from '../../transform';
|
||||
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 {
|
||||
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 {
|
||||
Pending,
|
||||
|
|
|
@ -43,13 +43,19 @@ interface ExpressionIdentifier extends TemplateIdentifier {
|
|||
}
|
||||
|
||||
/** 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. */
|
||||
export interface MethodIdentifier extends ExpressionIdentifier { kind: IdentifierKind.Method; }
|
||||
export interface MethodIdentifier extends ExpressionIdentifier {
|
||||
kind: IdentifierKind.Method;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
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`. */
|
||||
target: {
|
||||
/** 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
|
||||
|
@ -96,14 +102,16 @@ export interface ReferenceIdentifier extends TemplateIdentifier {
|
|||
}
|
||||
|
||||
/** 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
|
||||
* they were discovered in.
|
||||
*/
|
||||
export type TopLevelIdentifier = PropertyIdentifier | MethodIdentifier | ElementIdentifier |
|
||||
TemplateNodeIdentifier | ReferenceIdentifier | VariableIdentifier;
|
||||
export type TopLevelIdentifier = PropertyIdentifier|MethodIdentifier|ElementIdentifier|
|
||||
TemplateNodeIdentifier|ReferenceIdentifier|VariableIdentifier;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
addComponent(info: ComponentInfo) { this.components.add(info); }
|
||||
addComponent(info: ComponentInfo) {
|
||||
this.components.add(info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ interface HTMLNode extends TmplAstNode {
|
|||
name?: string;
|
||||
}
|
||||
|
||||
type ExpressionIdentifier = PropertyIdentifier | MethodIdentifier;
|
||||
type TmplTarget = TmplAstReference | TmplAstVariable;
|
||||
type TargetIdentifier = ReferenceIdentifier | VariableIdentifier;
|
||||
type ExpressionIdentifier = PropertyIdentifier|MethodIdentifier;
|
||||
type TmplTarget = TmplAstReference|TmplAstVariable;
|
||||
type TargetIdentifier = ReferenceIdentifier|VariableIdentifier;
|
||||
type TargetIdentifierMap = Map<TmplTarget, TargetIdentifier>;
|
||||
|
||||
/**
|
||||
|
@ -62,7 +62,9 @@ class ExpressionVisitor extends RecursiveAstVisitor {
|
|||
return visitor.identifiers;
|
||||
}
|
||||
|
||||
visit(ast: AST) { ast.visit(this); }
|
||||
visit(ast: AST) {
|
||||
ast.visit(this);
|
||||
}
|
||||
|
||||
visitMethodCall(ast: MethodCall, context: {}) {
|
||||
this.visitIdentifier(ast, IdentifierKind.Method);
|
||||
|
@ -144,16 +146,22 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
*
|
||||
* @param boundTemplate bound template target
|
||||
*/
|
||||
constructor(private boundTemplate: BoundTarget<ComponentMeta>) { super(); }
|
||||
constructor(private boundTemplate: BoundTarget<ComponentMeta>) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a node in the template.
|
||||
*
|
||||
* @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.
|
||||
|
@ -204,8 +212,12 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
this.targetToIdentifier.bind(this));
|
||||
identifiers.forEach(id => this.identifiers.add(id));
|
||||
}
|
||||
visitBoundEvent(attribute: TmplAstBoundEvent) { this.visitExpression(attribute.handler); }
|
||||
visitBoundText(text: TmplAstBoundText) { this.visitExpression(text.value); }
|
||||
visitBoundEvent(attribute: TmplAstBoundEvent) {
|
||||
this.visitExpression(attribute.handler);
|
||||
}
|
||||
visitBoundText(text: TmplAstBoundText) {
|
||||
this.visitExpression(text.value);
|
||||
}
|
||||
visitReference(reference: TmplAstReference) {
|
||||
const referenceIdentifer = this.targetToIdentifier(reference);
|
||||
|
||||
|
@ -222,7 +234,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
|TemplateNodeIdentifier {
|
||||
// If this node has already been seen, return the cached result.
|
||||
if (this.elementAndTemplateIdentifierCache.has(node)) {
|
||||
return this.elementAndTemplateIdentifierCache.get(node) !;
|
||||
return this.elementAndTemplateIdentifierCache.get(node)!;
|
||||
}
|
||||
|
||||
let name: string;
|
||||
|
@ -254,7 +266,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
|
||||
const identifier = {
|
||||
name,
|
||||
span: absoluteSpan, kind,
|
||||
span: absoluteSpan,
|
||||
kind,
|
||||
attributes: new Set(attributes),
|
||||
usedDirectives: new Set(usedDirectives.map(dir => {
|
||||
return {
|
||||
|
@ -274,7 +287,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
private targetToIdentifier(node: TmplAstReference|TmplAstVariable): TargetIdentifier {
|
||||
// If this node has already been seen, return the cached result.
|
||||
if (this.targetIdentifierCache.has(node)) {
|
||||
return this.targetIdentifierCache.get(node) !;
|
||||
return this.targetIdentifierCache.get(node)!;
|
||||
}
|
||||
|
||||
const {name, sourceSpan} = node;
|
||||
|
@ -304,7 +317,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor {
|
|||
identifier = {
|
||||
name,
|
||||
span,
|
||||
kind: IdentifierKind.Reference, target,
|
||||
kind: IdentifierKind.Reference,
|
||||
target,
|
||||
};
|
||||
} else {
|
||||
identifier = {
|
||||
|
|
|
@ -19,7 +19,8 @@ runInEachFileSystem(() => {
|
|||
|
||||
context.addComponent({
|
||||
declaration,
|
||||
selector: 'c-selector', boundTemplate,
|
||||
selector: 'c-selector',
|
||||
boundTemplate,
|
||||
templateMeta: {
|
||||
isInline: false,
|
||||
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
||||
|
@ -29,7 +30,8 @@ runInEachFileSystem(() => {
|
|||
expect(context.components).toEqual(new Set([
|
||||
{
|
||||
declaration,
|
||||
selector: 'c-selector', boundTemplate,
|
||||
selector: 'c-selector',
|
||||
boundTemplate,
|
||||
templateMeta: {
|
||||
isInline: false,
|
||||
file: new ParseSourceFile('<div></div>', util.getTestFilePath()),
|
||||
|
|
|
@ -219,11 +219,11 @@ runInEachFileSystem(() => {
|
|||
|
||||
const refArr = Array.from(refs);
|
||||
expect(refArr).toEqual(jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Property,
|
||||
span: new AbsoluteSourceSpan(20, 23),
|
||||
target: null,
|
||||
}] as TopLevelIdentifier[]));
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Property,
|
||||
span: new AbsoluteSourceSpan(20, 23),
|
||||
target: null,
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should ignore property writes that are not implicitly received by the template', () => {
|
||||
|
@ -314,12 +314,13 @@ runInEachFileSystem(() => {
|
|||
};
|
||||
|
||||
const refArray = Array.from(refs);
|
||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Reference,
|
||||
span: new AbsoluteSourceSpan(6, 9),
|
||||
target: {node: elementReference, directive: null},
|
||||
}] as TopLevelIdentifier[]));
|
||||
expect(refArray).toEqual(
|
||||
jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Reference,
|
||||
span: new AbsoluteSourceSpan(6, 9),
|
||||
target: {node: elementReference, directive: null},
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should discover nested references', () => {
|
||||
|
@ -334,12 +335,13 @@ runInEachFileSystem(() => {
|
|||
};
|
||||
|
||||
const refArray = Array.from(refs);
|
||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Reference,
|
||||
span: new AbsoluteSourceSpan(12, 15),
|
||||
target: {node: elementReference, directive: null},
|
||||
}] as TopLevelIdentifier[]));
|
||||
expect(refArray).toEqual(
|
||||
jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Reference,
|
||||
span: new AbsoluteSourceSpan(12, 15),
|
||||
target: {node: elementReference, directive: null},
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should discover references to references', () => {
|
||||
|
@ -409,14 +411,14 @@ runInEachFileSystem(() => {
|
|||
const refArr = Array.from(refs);
|
||||
let fooRef = refArr.find(id => id.name === 'foo');
|
||||
expect(fooRef).toBeDefined();
|
||||
expect(fooRef !.kind).toBe(IdentifierKind.Reference);
|
||||
expect(fooRef!.kind).toBe(IdentifierKind.Reference);
|
||||
|
||||
fooRef = fooRef as ReferenceIdentifier;
|
||||
expect(fooRef.target).toBeDefined();
|
||||
expect(fooRef.target !.node.kind).toBe(IdentifierKind.Element);
|
||||
expect(fooRef.target !.node.name).toBe('div');
|
||||
expect(fooRef.target !.node.span).toEqual(new AbsoluteSourceSpan(1, 4));
|
||||
expect(fooRef.target !.directive).toEqual(declB);
|
||||
expect(fooRef.target!.node.kind).toBe(IdentifierKind.Element);
|
||||
expect(fooRef.target!.node.name).toBe('div');
|
||||
expect(fooRef.target!.node.span).toEqual(new AbsoluteSourceSpan(1, 4));
|
||||
expect(fooRef.target!.directive).toEqual(declB);
|
||||
});
|
||||
|
||||
it('should discover references to references', () => {
|
||||
|
@ -455,10 +457,10 @@ runInEachFileSystem(() => {
|
|||
|
||||
const refArray = Array.from(refs);
|
||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(17, 20),
|
||||
}] as TopLevelIdentifier[]));
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(17, 20),
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should discover variables with let- syntax', () => {
|
||||
|
@ -467,10 +469,10 @@ runInEachFileSystem(() => {
|
|||
|
||||
const refArray = Array.from(refs);
|
||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||
name: 'var',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(17, 20),
|
||||
}] as TopLevelIdentifier[]));
|
||||
name: 'var',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(17, 20),
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should discover nested variables', () => {
|
||||
|
@ -479,10 +481,10 @@ runInEachFileSystem(() => {
|
|||
|
||||
const refArray = Array.from(refs);
|
||||
expect(refArray).toEqual(jasmine.arrayContaining([{
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(23, 26),
|
||||
}] as TopLevelIdentifier[]));
|
||||
name: 'foo',
|
||||
kind: IdentifierKind.Variable,
|
||||
span: new AbsoluteSourceSpan(23, 26),
|
||||
}] as TopLevelIdentifier[]));
|
||||
});
|
||||
|
||||
it('should discover references to variables', () => {
|
||||
|
|
|
@ -68,7 +68,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
const info = analysis.get(decl);
|
||||
expect(info).toBeDefined();
|
||||
expect(info !.template.file)
|
||||
expect(info!.template.file)
|
||||
.toEqual(new ParseSourceFile('class C {}', util.getTestFilePath()));
|
||||
});
|
||||
|
||||
|
@ -83,7 +83,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
const info = analysis.get(decl);
|
||||
expect(info).toBeDefined();
|
||||
expect(info !.template.file)
|
||||
expect(info!.template.file)
|
||||
.toEqual(new ParseSourceFile('<div>{{foo}}</div>', util.getTestFilePath()));
|
||||
});
|
||||
|
||||
|
@ -110,11 +110,11 @@ runInEachFileSystem(() => {
|
|||
|
||||
const infoA = analysis.get(declA);
|
||||
expect(infoA).toBeDefined();
|
||||
expect(infoA !.template.usedComponents).toEqual(new Set([declB]));
|
||||
expect(infoA!.template.usedComponents).toEqual(new Set([declB]));
|
||||
|
||||
const infoB = analysis.get(declB);
|
||||
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
|
||||
*/
|
||||
|
||||
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 {AbsoluteFsPath, absoluteFrom} from '../../file_system';
|
||||
|
||||
import {absoluteFrom, AbsoluteFsPath} from '../../file_system';
|
||||
import {Reference} from '../../imports';
|
||||
import {ClassDeclaration} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing';
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as ts from 'typescript';
|
||||
|
||||
import {Reference} from '../../imports';
|
||||
import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection';
|
||||
import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
|
||||
|
||||
import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta} from './api';
|
||||
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}`);
|
||||
}
|
||||
|
||||
let inputs: {[key: string]: string | [string, string]} = {};
|
||||
let inputs: {[key: string]: string|[string, string]} = {};
|
||||
let outputs: {[key: string]: string} = {};
|
||||
let coercedInputFields = new Set<string>();
|
||||
let isDynamic = false;
|
||||
|
|
|
@ -22,18 +22,24 @@ export class LocalMetadataRegistry implements MetadataRegistry, MetadataReader {
|
|||
private pipes = new Map<ClassDeclaration, PipeMeta>();
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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); }
|
||||
registerNgModuleMetadata(meta: NgModuleMeta): void { this.ngModules.set(meta.ref.node, meta); }
|
||||
registerPipeMetadata(meta: PipeMeta): void { this.pipes.set(meta.ref.node, meta); }
|
||||
registerDirectiveMetadata(meta: DirectiveMeta): void {
|
||||
this.directives.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) {}
|
||||
|
||||
registerInjectable(declaration: ClassDeclaration): void { this.classes.add(declaration); }
|
||||
registerInjectable(declaration: ClassDeclaration): void {
|
||||
this.classes.add(declaration);
|
||||
}
|
||||
|
||||
isInjectable(declaration: ClassDeclaration): boolean {
|
||||
// Figure out whether the class is injectable based on the registered classes, otherwise
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
import * as ts from 'typescript';
|
||||
|
||||
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 {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta, TemplateGuardMeta} from './api';
|
||||
|
||||
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>[] {
|
||||
if (!ts.isTupleTypeNode(def)) {
|
||||
return [];
|
||||
|
@ -122,7 +122,7 @@ function extractTemplateGuard(member: ClassMember): TemplateGuardMeta|null {
|
|||
|
||||
function extractCoercedInput(member: ClassMember): string|null {
|
||||
if (member.kind !== ClassMemberKind.Property || !member.name.startsWith('ngAcceptInputType_')) {
|
||||
return null !;
|
||||
return null!;
|
||||
}
|
||||
return afterUnderscore(member.name);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ import {ImportFlags, Reference, ReferenceEmitter} from '../../imports';
|
|||
import {PartialEvaluator, ResolvedValueMap} from '../../partial_evaluator';
|
||||
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 {
|
||||
constructor(
|
||||
|
|
|
@ -12,9 +12,11 @@ import {PerfRecorder} from './api';
|
|||
|
||||
export const NOOP_PERF_RECORDER: PerfRecorder = {
|
||||
enabled: false,
|
||||
mark: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string):
|
||||
void => {},
|
||||
start: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string):
|
||||
number => { return 0;},
|
||||
stop: (span: number | false): void => {},
|
||||
mark: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
||||
void => {},
|
||||
start: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string):
|
||||
number => {
|
||||
return 0;
|
||||
},
|
||||
stop: (span: number|false): void => {},
|
||||
};
|
||||
|
|
|
@ -20,7 +20,9 @@ export class PerfTracker implements PerfRecorder {
|
|||
|
||||
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):
|
||||
void {
|
||||
|
@ -73,7 +75,9 @@ export class PerfTracker implements PerfRecorder {
|
|||
return msg;
|
||||
}
|
||||
|
||||
asJson(): unknown { return this.log; }
|
||||
asJson(): unknown {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
serializeToFile(target: string, host: ts.CompilerHost): void {
|
||||
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);
|
||||
}
|
||||
|
||||
getTsProgram(): ts.Program { return this.tsProgram; }
|
||||
getTsProgram(): ts.Program {
|
||||
return this.tsProgram;
|
||||
}
|
||||
|
||||
getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken|
|
||||
undefined): readonly ts.Diagnostic[] {
|
||||
|
@ -137,8 +139,8 @@ export class NgtscProgram implements api.Program {
|
|||
}
|
||||
|
||||
getNgSemanticDiagnostics(
|
||||
fileName?: string|undefined, cancellationToken?: ts.CancellationToken|
|
||||
undefined): readonly(ts.Diagnostic|api.Diagnostic)[] {
|
||||
fileName?: string|undefined, cancellationToken?: ts.CancellationToken|undefined):
|
||||
readonly(ts.Diagnostic|api.Diagnostic)[] {
|
||||
let sf: ts.SourceFile|undefined = undefined;
|
||||
if (fileName !== undefined) {
|
||||
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
|
||||
* 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[] {
|
||||
return this.compiler.listLazyRoutes(entryRoute);
|
||||
}
|
||||
|
||||
emit(opts?: {
|
||||
emitFlags?: api.EmitFlags | undefined; cancellationToken?: ts.CancellationToken | undefined;
|
||||
emitFlags?: api.EmitFlags|undefined;
|
||||
cancellationToken?: ts.CancellationToken | undefined;
|
||||
customTransformers?: api.CustomTransformers | undefined;
|
||||
emitCallback?: api.TsEmitCallback | undefined;
|
||||
mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback | undefined;
|
||||
|
@ -179,8 +184,8 @@ export class NgtscProgram implements api.Program {
|
|||
|
||||
const writeFile: ts.WriteFileCallback =
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
onError: ((message: string) => void) | undefined,
|
||||
sourceFiles: ReadonlyArray<ts.SourceFile>| undefined) => {
|
||||
onError: ((message: string) => void)|undefined,
|
||||
sourceFiles: ReadonlyArray<ts.SourceFile>|undefined) => {
|
||||
if (sourceFiles !== undefined) {
|
||||
// Record successful writes for any `ts.SourceFile` (that's not a declaration file)
|
||||
// that's an input to this write.
|
||||
|
@ -221,7 +226,8 @@ export class NgtscProgram implements api.Program {
|
|||
program: this.tsProgram,
|
||||
host: this.host,
|
||||
options: this.options,
|
||||
emitOnlyDtsFiles: false, writeFile,
|
||||
emitOnlyDtsFiles: false,
|
||||
writeFile,
|
||||
customTransformers: {
|
||||
before: beforeTransforms,
|
||||
after: customTransforms && customTransforms.afterTs,
|
||||
|
@ -257,11 +263,16 @@ export class NgtscProgram implements api.Program {
|
|||
}
|
||||
}
|
||||
|
||||
const defaultEmitCallback: api.TsEmitCallback =
|
||||
({program, targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles,
|
||||
customTransformers}) =>
|
||||
program.emit(
|
||||
targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||
const defaultEmitCallback: api.TsEmitCallback = ({
|
||||
program,
|
||||
targetSourceFile,
|
||||
writeFile,
|
||||
cancellationToken,
|
||||
emitOnlyDtsFiles,
|
||||
customTransformers
|
||||
}) =>
|
||||
program.emit(
|
||||
targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||
|
||||
function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult {
|
||||
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
|
||||
* other information about a class.
|
||||
*/
|
||||
export type Decorator = ConcreteDecorator | SyntheticDecorator;
|
||||
export type Decorator = ConcreteDecorator|SyntheticDecorator;
|
||||
|
||||
export interface BaseDecorator {
|
||||
/**
|
||||
|
@ -28,11 +28,11 @@ export interface BaseDecorator {
|
|||
*/
|
||||
identifier: DecoratorIdentifier|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.
|
||||
*/
|
||||
import : Import | 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.
|
||||
*/
|
||||
import: Import|null;
|
||||
|
||||
/**
|
||||
* 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 namespaced property access (e.g. `core.Decorator`).
|
||||
*/
|
||||
export type DecoratorIdentifier = ts.Identifier | NamespacedIdentifier;
|
||||
export type NamespacedIdentifier = ts.PropertyAccessExpression & {
|
||||
export type DecoratorIdentifier = ts.Identifier|NamespacedIdentifier;
|
||||
export type NamespacedIdentifier = ts.PropertyAccessExpression&{
|
||||
expression: 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,
|
||||
* 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.
|
||||
|
@ -241,8 +241,7 @@ export interface ClassMember {
|
|||
*/
|
||||
export type TypeValueReference = {
|
||||
local: true; expression: ts.Expression; defaultImportStatement: ts.ImportDeclaration | null;
|
||||
} |
|
||||
{
|
||||
}|{
|
||||
local: false;
|
||||
name: string;
|
||||
moduleName: string;
|
||||
|
@ -447,7 +446,7 @@ export interface InlineDeclaration extends BaseDeclaration {
|
|||
* downlevelings to a `ts.Expression` instead.
|
||||
*/
|
||||
export type Declaration<T extends ts.Declaration = ts.Declaration> =
|
||||
ConcreteDeclaration<T>| InlineDeclaration;
|
||||
ConcreteDeclaration<T>|InlineDeclaration;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
if (typeNode === null || !ts.isTypeReferenceNode(typeNode)) {
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
// typeRefSymbol is the ts.Symbol of the entire type reference.
|
||||
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(
|
||||
node: ts.ImportSpecifier | ts.NamespaceImport | ts.ImportClause,
|
||||
localName: string | null): {name: string, moduleName: string} {
|
||||
node: ts.ImportSpecifier|ts.NamespaceImport|ts.ImportClause,
|
||||
localName: string|null): {name: string, moduleName: string} {
|
||||
let name: string;
|
||||
let moduleSpecifier: ts.Expression;
|
||||
switch (node.kind) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
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';
|
||||
|
||||
/**
|
||||
|
@ -76,8 +76,10 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||
|
||||
return {
|
||||
name,
|
||||
nameNode: node.name, typeValueReference,
|
||||
typeNode: originalTypeNode, decorators,
|
||||
nameNode: node.name,
|
||||
typeValueReference,
|
||||
typeNode: originalTypeNode,
|
||||
decorators,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -183,11 +185,17 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||
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 {
|
||||
const symbol = this.checker.getSymbolAtLocation(id);
|
||||
|
@ -305,12 +313,14 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||
if (symbol.valueDeclaration !== undefined) {
|
||||
return {
|
||||
node: symbol.valueDeclaration,
|
||||
known: null, viaModule,
|
||||
known: null,
|
||||
viaModule,
|
||||
};
|
||||
} else if (symbol.declarations !== undefined && symbol.declarations.length > 0) {
|
||||
return {
|
||||
node: symbol.declarations[0],
|
||||
known: null, viaModule,
|
||||
known: null,
|
||||
viaModule,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
|
@ -342,7 +352,9 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||
return {
|
||||
name: decoratorIdentifier.text,
|
||||
identifier: decoratorExpr,
|
||||
import: importDecl, node, args,
|
||||
import: importDecl,
|
||||
node,
|
||||
args,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -382,8 +394,14 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||
|
||||
return {
|
||||
node,
|
||||
implementation: node, kind,
|
||||
type: node.type || null, name, nameNode, decorators, value, isStatic,
|
||||
implementation: node,
|
||||
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(
|
||||
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);
|
||||
if (realSymbol === undefined) {
|
||||
throw new Error(`Cannot resolve type entity ${type.getText()} to symbol`);
|
||||
|
@ -434,8 +452,8 @@ export function reflectTypeEntityToDeclaration(
|
|||
}
|
||||
const decl = symbol.declarations[0];
|
||||
if (ts.isNamespaceImport(decl)) {
|
||||
const clause = decl.parent !;
|
||||
const importDecl = clause.parent !;
|
||||
const clause = decl.parent!;
|
||||
const importDecl = clause.parent!;
|
||||
if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
||||
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`.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue