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:
Alex Rickabaugh 2020-04-07 12:43:43 -07:00 committed by atscott
parent 717df13207
commit 0a69a2832b
205 changed files with 2949 additions and 2122 deletions

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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'),

View File

@ -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({

View File

@ -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]
})

View File

@ -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';
}
}

View File

@ -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');

View File

@ -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');
}
}

View File

@ -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)})

View File

@ -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()

View File

@ -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';

View File

@ -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}])
]
};
}

View File

@ -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>'})

View File

@ -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';

View File

@ -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', () => {

View File

@ -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],

View File

@ -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;

View File

@ -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;

View File

@ -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');
}

View File

@ -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';

View File

@ -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;
}

View File

@ -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);

View File

@ -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]);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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';

View File

@ -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;

View File

@ -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 {

View File

@ -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}.`);
}

View File

@ -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}) => {

View File

@ -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';

View File

@ -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};

View File

@ -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);
}

View File

@ -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}`);
}
});

View File

@ -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,

View File

@ -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;
}

View File

@ -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());
}
});

View File

@ -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();

View File

@ -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'}));
});
});
});
});

View File

@ -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';

View File

@ -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']);

View File

@ -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);

View File

@ -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;

View File

@ -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 {}

View File

@ -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,
};
}
}

View File

@ -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[];

View File

@ -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;

View File

@ -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);
});
}
/**

View File

@ -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 => {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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([

View File

@ -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();
});
});

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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() {

View File

@ -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):

View File

@ -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'), '..');
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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();
});
}
});
});

View File

@ -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';

View File

@ -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);
}

View File

@ -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(/[\\\/]/);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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';

View File

@ -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;
}
}
/**

View File

@ -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)!;
}

View File

@ -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 => {

View File

@ -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):

View File

@ -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

View File

@ -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"];`);
});

View File

@ -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');
});
});
});

View File

@ -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`.
*/

View File

@ -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).

View File

@ -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,

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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 = {

View File

@ -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()),

View File

@ -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', () => {

View File

@ -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]));
});
});
});

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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(

View File

@ -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 => {},
};

View File

@ -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);

View File

@ -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[] = [];

View File

@ -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.

View File

@ -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) {

View File

@ -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