refactor(tsc-wrapped): update tsc-wrapped to pass strictNullCheck (#18160)

PR Close #18160
This commit is contained in:
Chuck Jazdzewski 2017-07-18 12:52:48 -07:00 committed by Miško Hevery
parent 619e625ee2
commit abee785821
18 changed files with 269 additions and 230 deletions

View File

@ -419,6 +419,11 @@ if [[ ${BUILD_TOOLS} == true || ${BUILD_ALL} == true ]]; then
$(npm bin)/tsc -p packages/tsc-wrapped/tsconfig-build.json
cp ./packages/tsc-wrapped/package.json ./dist/packages-dist/tsc-wrapped
cp ./packages/tsc-wrapped/README.md ./dist/packages-dist/tsc-wrapped
(
cd dist/packages-dist/tsc-wrapped
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
)
fi
for PACKAGE in ${PACKAGES[@]}

View File

@ -100,8 +100,8 @@ export class CodeGenerator {
}
const {compiler: aotCompiler} = compiler.createAotCompiler(ngCompilerHost, {
translations: transContent,
i18nFormat: cliOptions.i18nFormat,
locale: cliOptions.locale, missingTranslation,
i18nFormat: cliOptions.i18nFormat || undefined,
locale: cliOptions.locale || undefined, missingTranslation,
enableLegacyTemplate: options.enableLegacyTemplate !== false,
enableSummariesForJit: options.enableSummariesForJit !== false,
});

View File

@ -405,7 +405,7 @@ export class MockMetadataBundlerHost implements MetadataBundlerHost {
constructor(private host: ts.CompilerHost) {}
getMetadataFor(moduleName: string): ModuleMetadata {
getMetadataFor(moduleName: string): ModuleMetadata|undefined {
const source = this.host.getSourceFile(moduleName + '.ts', ts.ScriptTarget.Latest);
return this.collector.getMetadata(source);
}

View File

@ -70,7 +70,9 @@ export interface BundledModule {
privates: BundlePrivateEntry[];
}
export interface MetadataBundlerHost { getMetadataFor(moduleName: string): ModuleMetadata; }
export interface MetadataBundlerHost {
getMetadataFor(moduleName: string): ModuleMetadata|undefined;
}
type StaticsMetadata = {
[name: string]: MetadataValue | FunctionMetadata;
@ -78,7 +80,7 @@ type StaticsMetadata = {
export class MetadataBundler {
private symbolMap = new Map<string, Symbol>();
private metadataCache = new Map<string, ModuleMetadata>();
private metadataCache = new Map<string, ModuleMetadata|undefined>();
private exports = new Map<string, Symbol[]>();
private rootModule: string;
private exported: Set<Symbol>;
@ -98,14 +100,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);
@ -114,7 +116,7 @@ export class MetadataBundler {
__symbolic: 'module',
version: VERSION,
exports: exports.length ? exports : undefined, metadata, origins,
importAs: this.importAs
importAs: this.importAs !
},
privates
};
@ -124,7 +126,7 @@ export class MetadataBundler {
return resolveModule(importName, from);
}
private getMetadata(moduleName: string): ModuleMetadata {
private getMetadata(moduleName: string): ModuleMetadata|undefined {
let result = this.metadataCache.get(moduleName);
if (!result) {
if (moduleName.startsWith('.')) {
@ -138,7 +140,7 @@ export class MetadataBundler {
private exportAll(moduleName: string): Symbol[] {
const module = this.getMetadata(moduleName);
let result: Symbol[] = this.exports.get(moduleName);
let result = this.exports.get(moduleName);
if (result) {
return result;
@ -148,7 +150,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;
};
@ -266,7 +268,7 @@ export class MetadataBundler {
name = newPrivateName();
symbol.privateName = name;
}
result[name] = symbol.value;
result[name] = symbol.value !;
}
});
@ -279,9 +281,10 @@ export class MetadataBundler {
const exportAlls = new Set<string>();
for (const symbol of exportedSymbols) {
if (symbol.reexport) {
const declaration = symbol.declaration;
// symbol.declaration is guarenteed to be defined during the phase this method is called.
const declaration = symbol.declaration !;
const module = declaration.module;
if (declaration.name == '*') {
if (declaration !.name == '*') {
// Reexport all the symbols.
exportAlls.add(declaration.module);
} else {
@ -304,11 +307,13 @@ export class MetadataBundler {
}
private convertSymbol(symbol: Symbol) {
const canonicalSymbol = symbol.canonicalSymbol;
// canonicalSymbol is ensured to be defined before this is called.
const canonicalSymbol = symbol.canonicalSymbol !;
if (!canonicalSymbol.referenced) {
canonicalSymbol.referenced = true;
const declaration = canonicalSymbol.declaration;
// declaration is ensured to be definded before this method is called.
const declaration = canonicalSymbol.declaration !;
const module = this.getMetadata(declaration.module);
if (module) {
const value = module.metadata[declaration.name];
@ -336,10 +341,10 @@ export class MetadataBundler {
return {
__symbolic: 'class',
arity: value.arity,
extends: this.convertExpression(moduleName, value.extends),
extends: this.convertExpression(moduleName, value.extends) !,
decorators:
value.decorators && value.decorators.map(d => this.convertExpression(moduleName, d)),
members: this.convertMembers(moduleName, value.members),
value.decorators && value.decorators.map(d => this.convertExpression(moduleName, d) !),
members: this.convertMembers(moduleName, value.members !),
statics: value.statics && this.convertStatics(moduleName, value.statics)
};
}
@ -356,11 +361,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 =
@ -397,7 +402,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));
@ -413,8 +418,8 @@ export class MetadataBundler {
}
private convertExpression(
moduleName: string, value: MetadataSymbolicExpression|MetadataError|
undefined): MetadataSymbolicExpression|MetadataError|undefined {
moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|
undefined): MetadataSymbolicExpression|MetadataError|undefined|null {
if (value) {
switch (value.__symbolic) {
case 'error':
@ -439,9 +444,9 @@ export class MetadataBundler {
}
private convertReference(moduleName: string, value: MetadataSymbolicReferenceExpression):
MetadataSymbolicReferenceExpression|MetadataError {
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.
@ -450,11 +455,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 {
@ -564,7 +569,7 @@ export class CompilerHostAdapter implements MetadataBundlerHost {
constructor(private host: ts.CompilerHost) {}
getMetadataFor(fileName: string): ModuleMetadata {
getMetadataFor(fileName: string): ModuleMetadata|undefined {
const sourceFile = this.host.getSourceFile(fileName + '.ts', ts.ScriptTarget.Latest);
return this.collector.getMetadata(sourceFile);
}

View File

@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
export class CliOptions {
public basePath: string;
constructor({basePath = null}: {basePath?: string}) { this.basePath = basePath; }
public basePath: string|null;
constructor({basePath = null}: {basePath?: string | null}) { this.basePath = basePath; }
}
export class I18nExtractionCliOptions extends CliOptions {
@ -28,18 +28,18 @@ export class I18nExtractionCliOptions extends CliOptions {
}
export class NgcCliOptions extends CliOptions {
public i18nFormat: string;
public i18nFile: string;
public locale: string;
public missingTranslation: string;
public i18nFormat: string|null;
public i18nFile: string|null;
public locale: string|null;
public missingTranslation: string|null;
constructor({i18nFormat = null, i18nFile = null, locale = null, missingTranslation = null,
basePath = null}: {
i18nFormat?: string,
i18nFile?: string,
locale?: string,
missingTranslation?: string,
basePath?: string
i18nFormat?: string | null,
i18nFile?: string|null,
locale?: string|null,
missingTranslation?: string|null,
basePath?: string|null
}) {
super({basePath: basePath});
this.i18nFormat = i18nFormat;

View File

@ -54,13 +54,13 @@ export class MetadataCollector {
* Returns a JSON.stringify friendly form describing the decorators of the exported classes from
* the source file that is expected to correspond to a module.
*/
public getMetadata(sourceFile: ts.SourceFile, strict: boolean = false): ModuleMetadata {
public getMetadata(sourceFile: ts.SourceFile, strict: boolean = false): ModuleMetadata|undefined {
const locals = new Symbols(sourceFile);
const nodeMap =
new Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>();
const evaluator = new Evaluator(locals, nodeMap, this.options);
let metadata: {[name: string]: MetadataValue | ClassMetadata | FunctionMetadata}|undefined;
let exports: ModuleExportMetadata[];
let exports: ModuleExportMetadata[]|undefined = undefined;
function objFromDecorator(decoratorNode: ts.Decorator): MetadataSymbolicExpression {
return <MetadataSymbolicExpression>evaluator.evaluateNode(decoratorNode.expression);
@ -79,7 +79,7 @@ export class MetadataCollector {
function maybeGetSimpleFunction(
functionDeclaration: ts.FunctionDeclaration |
ts.MethodDeclaration): {func: FunctionMetadata, name: string}|undefined {
if (functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
const nameNode = <ts.Identifier>functionDeclaration.name;
const functionName = nameNode.text;
const functionBody = functionDeclaration.body;
@ -107,7 +107,8 @@ export class MetadataCollector {
function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata {
const result: ClassMetadata = {__symbolic: 'class'};
function getDecorators(decorators: ts.Decorator[]): MetadataSymbolicExpression[] {
function getDecorators(decorators: ts.Decorator[] | undefined): MetadataSymbolicExpression[]|
undefined {
if (decorators && decorators.length)
return decorators.map(decorator => objFromDecorator(decorator));
return undefined;
@ -145,7 +146,7 @@ export class MetadataCollector {
}
// member decorators
let members: MetadataMap = null;
let members: MetadataMap|null = null;
function recordMember(name: string, metadata: MemberMetadata) {
if (!members) members = {};
const data = members.hasOwnProperty(name) ? members[name] : [];
@ -154,7 +155,7 @@ export class MetadataCollector {
}
// static member
let statics: {[name: string]: MetadataValue | FunctionMetadata} = null;
let statics: {[name: string]: MetadataValue | FunctionMetadata}|null = null;
function recordStaticMember(name: string, value: MetadataValue | FunctionMetadata) {
if (!statics) statics = {};
statics[name] = value;
@ -176,7 +177,8 @@ export class MetadataCollector {
}
const methodDecorators = getDecorators(method.decorators);
const parameters = method.parameters;
const parameterDecoratorData: (MetadataSymbolicExpression | MetadataError)[][] = [];
const parameterDecoratorData:
((MetadataSymbolicExpression | MetadataError)[] | undefined)[] = [];
const parametersData:
(MetadataSymbolicReferenceExpression | MetadataError |
MetadataSymbolicSelectExpression | null)[] = [];
@ -254,7 +256,8 @@ export class MetadataCollector {
const {moduleSpecifier, exportClause} = exportDeclaration;
if (!moduleSpecifier) {
exportClause.elements.forEach(spec => {
// If there is a module specifier there is also an exportClause
exportClause !.elements.forEach(spec => {
const exportedAs = spec.name.text;
const name = (spec.propertyName || spec.name).text;
exportMap.set(name, exportedAs);
@ -263,12 +266,13 @@ export class MetadataCollector {
}
});
const isExportedIdentifier = (identifier: ts.Identifier) => exportMap.has(identifier.text);
const isExportedIdentifier = (identifier?: ts.Identifier) =>
identifier && exportMap.has(identifier.text);
const isExported =
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration |
ts.EnumDeclaration) => isExport(node) || isExportedIdentifier(node.name);
const exportedIdentifierName = (identifier: ts.Identifier) =>
exportMap.get(identifier.text) || identifier.text;
const exportedIdentifierName = (identifier?: ts.Identifier) =>
identifier && (exportMap.get(identifier.text) || identifier.text);
const exportedName =
(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration |
ts.EnumDeclaration) => exportedIdentifierName(node.name);
@ -358,8 +362,11 @@ export class MetadataCollector {
const classDeclaration = <ts.ClassDeclaration>node;
if (classDeclaration.name) {
if (isExported(classDeclaration)) {
if (!metadata) metadata = {};
metadata[exportedName(classDeclaration)] = classMetadataOf(classDeclaration);
const name = exportedName(classDeclaration);
if (name) {
if (!metadata) metadata = {};
metadata[name] = classMetadataOf(classDeclaration);
}
}
}
// Otherwise don't record metadata for the class.
@ -368,8 +375,11 @@ export class MetadataCollector {
case ts.SyntaxKind.InterfaceDeclaration:
const interfaceDeclaration = <ts.InterfaceDeclaration>node;
if (interfaceDeclaration.name && isExported(interfaceDeclaration)) {
if (!metadata) metadata = {};
metadata[exportedName(interfaceDeclaration)] = {__symbolic: 'interface'};
const name = exportedName(interfaceDeclaration);
if (name) {
if (!metadata) metadata = {};
metadata[name] = {__symbolic: 'interface'};
}
}
break;
@ -378,11 +388,13 @@ export class MetadataCollector {
// names substitution will be performed by the StaticReflector.
const functionDeclaration = <ts.FunctionDeclaration>node;
if (isExported(functionDeclaration) && functionDeclaration.name) {
if (!metadata) metadata = {};
const name = exportedName(functionDeclaration);
const maybeFunc = maybeGetSimpleFunction(functionDeclaration);
metadata[name] =
maybeFunc ? recordEntry(maybeFunc.func, node) : {__symbolic: 'function'};
if (name) {
if (!metadata) metadata = {};
metadata[name] =
maybeFunc ? recordEntry(maybeFunc.func, node) : {__symbolic: 'function'};
}
}
break;
@ -400,7 +412,7 @@ export class MetadataCollector {
} else {
enumValue = evaluator.evaluateNode(member.initializer);
}
let name: string = undefined;
let name: string|undefined = undefined;
if (member.name.kind == ts.SyntaxKind.Identifier) {
const identifier = <ts.Identifier>member.name;
name = identifier.text;
@ -424,8 +436,10 @@ export class MetadataCollector {
}
}
if (writtenMembers) {
if (!metadata) metadata = {};
metadata[enumName] = recordEntry(enumValueHolder, node);
if (enumName) {
if (!metadata) metadata = {};
metadata[enumName] = recordEntry(enumValueHolder, node);
}
}
}
break;
@ -444,8 +458,11 @@ export class MetadataCollector {
let exported = false;
if (isExport(variableStatement) || isExport(variableDeclaration) ||
isExportedIdentifier(nameNode)) {
if (!metadata) metadata = {};
metadata[exportedIdentifierName(nameNode)] = recordEntry(varValue, node);
const name = exportedIdentifierName(nameNode);
if (name) {
if (!metadata) metadata = {};
metadata[name] = recordEntry(varValue, node);
}
exported = true;
}
if (typeof varValue == 'string' || typeof varValue == 'number' ||
@ -601,11 +618,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 {
@ -628,7 +645,7 @@ function validateMetadata(
}
}
function shouldReportNode(node: ts.Node) {
function shouldReportNode(node: ts.Node | undefined) {
if (node) {
const nodeStart = node.getStart();
return !(

View File

@ -33,10 +33,10 @@ export abstract class DelegatingHost implements ts.CompilerHost {
(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void) =>
this.delegate.getSourceFile(fileName, languageVersion, onError);
getCancellationToken = () => this.delegate.getCancellationToken();
getCancellationToken = () => this.delegate.getCancellationToken !();
getDefaultLibFileName = (options: ts.CompilerOptions) =>
this.delegate.getDefaultLibFileName(options);
getDefaultLibLocation = () => this.delegate.getDefaultLibLocation();
getDefaultLibLocation = () => this.delegate.getDefaultLibLocation !();
writeFile: ts.WriteFileCallback = this.delegate.writeFile;
getCurrentDirectory = () => this.delegate.getCurrentDirectory();
getDirectories = (path: string): string[] =>
@ -46,8 +46,8 @@ export abstract class DelegatingHost implements ts.CompilerHost {
getNewLine = () => this.delegate.getNewLine();
fileExists = (fileName: string) => this.delegate.fileExists(fileName);
readFile = (fileName: string) => this.delegate.readFile(fileName);
trace = (s: string) => this.delegate.trace(s);
directoryExists = (directoryName: string) => this.delegate.directoryExists(directoryName);
trace = (s: string) => this.delegate.trace !(s);
directoryExists = (directoryName: string) => this.delegate.directoryExists !(directoryName);
}
const IGNORED_FILES = /\.ngfactory\.js$|\.ngstyle\.js$/;
@ -79,7 +79,8 @@ export class MetadataWriterHost extends DelegatingHost {
const metadata =
this.metadataCollector.getMetadata(collectableFile, !!this.ngOptions.strictMetadataEmit);
const metadata1 = this.metadataCollector1.getMetadata(collectableFile, false);
const metadatas: ModuleMetadata[] = [metadata, metadata1].filter(e => !!e);
const metadatas: ModuleMetadata[] =
[metadata, metadata1].filter(e => !!e) as ModuleMetadata[];
if (metadatas.length) {
const metadataText = JSON.stringify(metadatas);
writeFileSync(path, metadataText, {encoding: 'utf-8'});
@ -163,7 +164,7 @@ export class SyntheticIndexHost extends DelegatingHost {
normalize(sourceFiles[0].fileName) == this.normalSyntheticIndexName) {
// If we are writing the synthetic index, write the metadata along side.
const metadataName = fileName.replace(DTS, '.metadata.json');
writeFileSync(metadataName, this.indexMetadata, 'utf8');
writeFileSync(metadataName, this.indexMetadata, {encoding: 'utf8'});
}
}
}

View File

@ -68,7 +68,7 @@ export interface ImportMetadata {
}
function getSourceFileOfNode(node: ts.Node): ts.SourceFile {
function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile {
while (node && node.kind != ts.SyntaxKind.SourceFile) {
node = node.parent;
}
@ -79,7 +79,7 @@ function getSourceFileOfNode(node: ts.Node): ts.SourceFile {
export function errorSymbol(
message: string, node?: ts.Node, context?: {[name: string]: string},
sourceFile?: ts.SourceFile): MetadataError {
let result: MetadataError;
let result: MetadataError|undefined = undefined;
if (node) {
sourceFile = sourceFile || getSourceFileOfNode(node);
if (sourceFile) {
@ -106,15 +106,16 @@ export class Evaluator {
private symbols: Symbols, private nodeMap: Map<MetadataEntry, ts.Node>,
private options: CollectorOptions = {}) {}
nameOf(node: ts.Node): string|MetadataError {
if (node.kind == ts.SyntaxKind.Identifier) {
nameOf(node: ts.Node|undefined): string|MetadataError {
if (node && node.kind == ts.SyntaxKind.Identifier) {
return (<ts.Identifier>node).text;
}
const result = this.evaluateNode(node);
const result = node && this.evaluateNode(node);
if (isMetadataError(result) || typeof result === 'string') {
return result;
} else {
return errorSymbol('Name expected', node, {received: node.getText()});
return errorSymbol(
'Name expected', node, {received: (node && node.getText()) || '<missing>'});
}
}
@ -138,7 +139,7 @@ export class Evaluator {
return this.isFoldableWorker(node, new Map<ts.Node, boolean>());
}
private isFoldableWorker(node: ts.Node, folding: Map<ts.Node, boolean>): boolean {
private isFoldableWorker(node: ts.Node|undefined, folding: Map<ts.Node, boolean>): boolean {
if (node) {
switch (node.kind) {
case ts.SyntaxKind.ObjectLiteralExpression:
@ -518,11 +519,11 @@ export class Evaluator {
if (isDefined(operand) && isPrimitive(operand)) {
switch (prefixUnaryExpression.operator) {
case ts.SyntaxKind.PlusToken:
return +operand;
return +(operand as any);
case ts.SyntaxKind.MinusToken:
return -operand;
return -(operand as any);
case ts.SyntaxKind.TildeToken:
return ~operand;
return ~(operand as any);
case ts.SyntaxKind.ExclamationToken:
return !operand;
}
@ -661,8 +662,8 @@ function isPropertyAssignment(node: ts.Node): node is ts.PropertyAssignment {
return node.kind == ts.SyntaxKind.PropertyAssignment;
}
const empty = [] as ts.NodeArray<any>;
const empty = ts.createNodeArray<any>();
function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>): ts.NodeArray<T> {
function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>| undefined): ts.NodeArray<T> {
return v || empty;
}

View File

@ -41,9 +41,9 @@ export function createBundleIndexHost(
return {
host,
errors: [{
file: null,
start: null,
length: null,
file: null as any as ts.SourceFile,
start: null as any as number,
length: null as any as number,
messageText:
'Angular compiler option "flatModuleIndex" requires one and only one .ts file in the "files" field.',
category: ts.DiagnosticCategory.Error,
@ -58,7 +58,7 @@ export function createBundleIndexHost(
const metadataBundle = bundler.getMetadataBundle();
const metadata = JSON.stringify(metadataBundle.metadata);
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);
host = new SyntheticIndexHost(host, {name, content, metadata});
@ -201,7 +201,7 @@ if (require.main === module) {
const project = options.project || '.';
// TODO(alexeagle): command line should be TSC-compatible, remove "CliOptions" here
const cliOptions = new CliOptions(require('minimist')(args));
main(project, cliOptions, null, options)
main(project, cliOptions, undefined, options)
.then((exitCode: any) => process.exit(exitCode))
.catch((e: any) => {
console.error(e.stack);

View File

@ -73,7 +73,7 @@ export function isMemberMetadata(value: any): value is MemberMetadata {
export interface MethodMetadata extends MemberMetadata {
__symbolic: 'constructor'|'method';
parameterDecorators?: (MetadataSymbolicExpression|MetadataError)[][];
parameterDecorators?: ((MetadataSymbolicExpression | MetadataError)[]|undefined)[];
}
export function isMethodMetadata(value: any): value is MethodMetadata {
return value && (value.__symbolic === 'constructor' || value.__symbolic === 'method');
@ -81,7 +81,7 @@ export function isMethodMetadata(value: any): value is MethodMetadata {
export interface ConstructorMetadata extends MethodMetadata {
__symbolic: 'constructor';
parameters?: (MetadataSymbolicExpression|MetadataError|null)[];
parameters?: (MetadataSymbolicExpression|MetadataError|null|undefined)[];
}
export function isConstructorMetadata(value: any): value is ConstructorMetadata {
return value && value.__symbolic === 'constructor';
@ -97,8 +97,8 @@ export function isFunctionMetadata(value: any): value is FunctionMetadata {
return value && value.__symbolic === 'function';
}
export type MetadataValue = string | number | boolean | MetadataObject | MetadataArray |
MetadataSymbolicExpression | MetadataError;
export type MetadataValue = string | number | boolean | undefined | null | MetadataObject |
MetadataArray | MetadataSymbolicExpression | MetadataError;
export interface MetadataObject { [name: string]: MetadataValue; }

View File

@ -49,23 +49,26 @@ export class Symbols {
ts.SyntaxKind.ExternalModuleReference) {
const externalReference =
<ts.ExternalModuleReference>importEqualsDeclaration.moduleReference;
// An `import <identifier> = require(<module-specifier>);
if (!externalReference.expression.parent) {
// The `parent` field of a node is set by the TypeScript binder (run as
// part of the type checker). Setting it here allows us to call `getText()`
// even if the `SourceFile` was not type checked (which looks for `SourceFile`
// in the parent chain). This doesn't damage the node as the binder unconditionally
// sets the parent.
externalReference.expression.parent = externalReference;
externalReference.parent = this.sourceFile as any;
if (externalReference.expression) {
// An `import <identifier> = require(<module-specifier>);
if (!externalReference.expression.parent) {
// The `parent` field of a node is set by the TypeScript binder (run as
// part of the type checker). Setting it here allows us to call `getText()`
// even if the `SourceFile` was not type checked (which looks for `SourceFile`
// in the parent chain). This doesn't damage the node as the binder unconditionally
// sets the parent.
externalReference.expression.parent = externalReference;
externalReference.parent = this.sourceFile as any;
}
const from = stripQuotes(externalReference.expression.getText());
symbols.set(
importEqualsDeclaration.name.text, {__symbolic: 'reference', module: from});
break;
}
const from = stripQuotes(externalReference.expression.getText());
symbols.set(importEqualsDeclaration.name.text, {__symbolic: 'reference', module: from});
} else {
symbols.set(
importEqualsDeclaration.name.text,
{__symbolic: 'error', message: `Unsupported import syntax`});
}
symbols.set(
importEqualsDeclaration.name.text,
{__symbolic: 'error', message: `Unsupported import syntax`});
break;
case ts.SyntaxKind.ImportDeclaration:
const importDecl = <ts.ImportDeclaration>node;

View File

@ -33,7 +33,7 @@ export class UserError extends Error {
super(message);
// Required for TS 2.1, see
// https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
Object.setPrototypeOf(this, UserError.prototype);
(Object as any).setPrototypeOf(this, UserError.prototype);
const nativeError = new Error(message) as any as Error;
this._nativeError = nativeError;
@ -76,13 +76,14 @@ export function formatDiagnostics(diags: ts.Diagnostic[]): string {
.join('\n');
}
export function check(diags: ts.Diagnostic[]) {
export function check(diags: ts.Diagnostic[] | undefined) {
if (diags && diags.length && diags[0]) {
throw new UserError(formatDiagnostics(diags));
}
}
export function validateAngularCompilerOptions(options: AngularCompilerOptions): ts.Diagnostic[] {
export function validateAngularCompilerOptions(options: AngularCompilerOptions): ts.Diagnostic[]|
undefined {
if (options.annotationsAs) {
switch (options.annotationsAs) {
case 'decorators':
@ -90,9 +91,9 @@ export function validateAngularCompilerOptions(options: AngularCompilerOptions):
break;
default:
return [{
file: null,
start: null,
length: null,
file: null as any as ts.SourceFile,
start: null as any as number,
length: null as any as number,
messageText:
'Angular compiler options "annotationsAs" only supports "static fields" and "decorators"',
category: ts.DiagnosticCategory.Error,
@ -136,7 +137,7 @@ export class Tsc implements CompilerInterface {
return ts.readConfigFile(project, this.readFile);
}
})();
check([error]);
check([error !]);
const parsed =
ts.parseJsonConfigFileContent(config, this.parseConfigHost, basePath, existingOptions);

View File

@ -29,7 +29,7 @@ describe('metadata bundler', () => {
const originalTwo = './src/two/index';
expect(Object.keys(result.metadata.origins)
.sort()
.map(name => ({name, value: result.metadata.origins[name]})))
.map(name => ({name, value: result.metadata.origins ![name]})))
.toEqual([
{name: 'ONE_CLASSES', value: originalOne}, {name: 'One', value: originalOne},
{name: 'OneMore', value: originalOne}, {name: 'TWO_CLASSES', value: originalTwo},
@ -190,7 +190,7 @@ describe('metadata bundler', () => {
from: 'external_one'
}
]);
expect(result.metadata.origins['E']).toBeUndefined();
expect(result.metadata.origins !['E']).toBeUndefined();
});
});
@ -199,7 +199,7 @@ export class MockStringBundlerHost implements MetadataBundlerHost {
constructor(private dirName: string, private directory: Directory) {}
getMetadataFor(moduleName: string): ModuleMetadata {
getMetadataFor(moduleName: string): ModuleMetadata|undefined {
const fileName = path.join(this.dirName, moduleName) + '.ts';
const text = open(this.directory, fileName);
if (typeof text == 'string') {

View File

@ -196,13 +196,13 @@ describe('Collector', () => {
beforeEach(() => {
casesFile = program.getSourceFile('/app/cases-data.ts');
casesMetadata = collector.getMetadata(casesFile);
casesMetadata = collector.getMetadata(casesFile) !;
});
it('should provide any reference for an any ctor parameter type', () => {
const casesAny = <ClassMetadata>casesMetadata.metadata['CaseAny'];
expect(casesAny).toBeTruthy();
const ctorData = casesAny.members['__ctor__'];
const ctorData = casesAny.members !['__ctor__'];
expect(ctorData).toEqual(
[{__symbolic: 'constructor', parameters: [{__symbolic: 'reference', name: 'any'}]}]);
});
@ -265,10 +265,10 @@ describe('Collector', () => {
it('should report an error for references to unexpected types', () => {
const unsupported1 = program.getSourceFile('/unsupported-2.ts');
const metadata = collector.getMetadata(unsupported1);
const metadata = collector.getMetadata(unsupported1) !;
const barClass = <ClassMetadata>metadata.metadata['Bar'];
const ctor = <ConstructorMetadata>barClass.members['__ctor__'][0];
const parameter = ctor.parameters[0];
const ctor = <ConstructorMetadata>barClass.members !['__ctor__'][0];
const parameter = ctor.parameters ![0];
expect(parameter).toEqual({
__symbolic: 'error',
message: 'Reference to non-exported class',
@ -280,9 +280,9 @@ describe('Collector', () => {
it('should be able to handle import star type references', () => {
const importStar = program.getSourceFile('/import-star.ts');
const metadata = collector.getMetadata(importStar);
const metadata = collector.getMetadata(importStar) !;
const someClass = <ClassMetadata>metadata.metadata['SomeClass'];
const ctor = <ConstructorMetadata>someClass.members['__ctor__'][0];
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
const parameters = ctor.parameters;
expect(parameters).toEqual([
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
@ -365,9 +365,9 @@ describe('Collector', () => {
it('should be able to handle import star type references', () => {
const importStar = program.getSourceFile('/import-star.ts');
const metadata = collector.getMetadata(importStar);
const metadata = collector.getMetadata(importStar) !;
const someClass = <ClassMetadata>metadata.metadata['SomeClass'];
const ctor = <ConstructorMetadata>someClass.members['__ctor__'][0];
const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0];
const parameters = ctor.parameters;
expect(parameters).toEqual([
{__symbolic: 'reference', module: 'angular2/common', name: 'NgFor'}
@ -376,14 +376,14 @@ describe('Collector', () => {
it('should be able to collect the value of an enum', () => {
const enumSource = program.getSourceFile('/exported-enum.ts');
const metadata = collector.getMetadata(enumSource);
const metadata = collector.getMetadata(enumSource) !;
const someEnum: any = metadata.metadata['SomeEnum'];
expect(someEnum).toEqual({A: 0, B: 1, C: 100, D: 101});
});
it('should ignore a non-export enum', () => {
const enumSource = program.getSourceFile('/private-enum.ts');
const metadata = collector.getMetadata(enumSource);
const metadata = collector.getMetadata(enumSource) !;
const publicEnum: any = metadata.metadata['PublicEnum'];
const privateEnum: any = metadata.metadata['PrivateEnum'];
expect(publicEnum).toEqual({a: 0, b: 1, c: 2});
@ -392,7 +392,7 @@ describe('Collector', () => {
it('should be able to collect enums initialized from consts', () => {
const enumSource = program.getSourceFile('/exported-enum.ts');
const metadata = collector.getMetadata(enumSource);
const metadata = collector.getMetadata(enumSource) !;
const complexEnum: any = metadata.metadata['ComplexEnum'];
expect(complexEnum).toEqual({
A: 0,
@ -405,7 +405,7 @@ describe('Collector', () => {
it('should be able to collect a simple static method', () => {
const staticSource = program.getSourceFile('/static-method.ts');
const metadata = collector.getMetadata(staticSource);
const metadata = collector.getMetadata(staticSource) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['MyModule'];
expect(classData).toBeDefined();
@ -423,7 +423,7 @@ describe('Collector', () => {
it('should be able to collect a call to a static method', () => {
const staticSource = program.getSourceFile('/static-method-call.ts');
const metadata = collector.getMetadata(staticSource);
const metadata = collector.getMetadata(staticSource) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['Foo'];
expect(classData).toBeDefined();
@ -446,7 +446,7 @@ describe('Collector', () => {
it('should be able to collect a static field', () => {
const staticSource = program.getSourceFile('/static-field.ts');
const metadata = collector.getMetadata(staticSource);
const metadata = collector.getMetadata(staticSource) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['MyModule'];
expect(classData).toBeDefined();
@ -455,7 +455,7 @@ describe('Collector', () => {
it('should be able to collect a reference to a static field', () => {
const staticSource = program.getSourceFile('/static-field-reference.ts');
const metadata = collector.getMetadata(staticSource);
const metadata = collector.getMetadata(staticSource) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['Foo'];
expect(classData).toBeDefined();
@ -477,7 +477,7 @@ describe('Collector', () => {
it('should be able to collect a method with a conditional expression', () => {
const source = program.getSourceFile('/static-method-with-if.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['MyModule'];
expect(classData).toBeDefined();
@ -502,7 +502,7 @@ describe('Collector', () => {
it('should be able to collect a method with a default parameter', () => {
const source = program.getSourceFile('/static-method-with-default.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata).toBeDefined();
const classData = <ClassMetadata>metadata.metadata['MyModule'];
expect(classData).toBeDefined();
@ -531,7 +531,7 @@ describe('Collector', () => {
it('should be able to collect re-exported symbols', () => {
const source = program.getSourceFile('/re-exports.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.exports).toEqual([
{from: './static-field', export: ['MyModule']},
{from: './static-field-reference', export: [{name: 'Foo', as: 'OtherModule'}]},
@ -541,13 +541,13 @@ describe('Collector', () => {
it('should be able to collect a export as symbol', () => {
const source = program.getSourceFile('export-as.d.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({SomeFunction: {__symbolic: 'function'}});
});
it('should be able to collect exports with no module specifier', () => {
const source = program.getSourceFile('/re-exports-2.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({
MyClass: Object({__symbolic: 'class'}),
OtherModule: {__symbolic: 'reference', module: './static-field-reference', name: 'Foo'},
@ -557,7 +557,7 @@ describe('Collector', () => {
it('should collect an error symbol if collecting a reference to a non-exported symbol', () => {
const source = program.getSourceFile('/local-symbol-ref.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({
REQUIRED_VALIDATOR: {
__symbolic: 'error',
@ -579,7 +579,7 @@ describe('Collector', () => {
it('should collect an error symbol if collecting a reference to a non-exported function', () => {
const source = program.getSourceFile('/local-function-ref.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({
REQUIRED_VALIDATOR: {
__symbolic: 'error',
@ -601,7 +601,7 @@ describe('Collector', () => {
it('should collect an error for a simple function that references a local variable', () => {
const source = program.getSourceFile('/local-symbol-ref-func.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({
foo: {
__symbolic: 'function',
@ -619,7 +619,7 @@ describe('Collector', () => {
it('should collect any for interface parameter reference', () => {
const source = program.getSourceFile('/interface-reference.ts');
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect((metadata.metadata['SomeClass'] as ClassMetadata).members).toEqual({
__ctor__: [{
__symbolic: 'constructor',
@ -734,7 +734,7 @@ describe('Collector', () => {
toString(): string { return \`InjectionToken ${this._desc}\`; }
} as any;`,
ts.ScriptTarget.Latest, true);
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata).toEqual({InjectionToken: {__symbolic: 'class'}});
});
@ -781,19 +781,19 @@ describe('Collector', () => {
describe('inheritance', () => {
it('should record `extends` clauses for declared classes', () => {
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts'));
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts')) !;
expect(metadata.metadata['DeclaredChildClass'])
.toEqual({__symbolic: 'class', extends: {__symbolic: 'reference', name: 'ParentClass'}});
});
it('should record `extends` clauses for classes in the same file', () => {
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts'));
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts')) !;
expect(metadata.metadata['ChildClassSameFile'])
.toEqual({__symbolic: 'class', extends: {__symbolic: 'reference', name: 'ParentClass'}});
});
it('should record `extends` clauses for classes in a different file', () => {
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts'));
const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts')) !;
expect(metadata.metadata['ChildClassOtherFile']).toEqual({
__symbolic: 'class',
extends: {
@ -811,7 +811,7 @@ describe('Collector', () => {
}
it('should collect the correct arity for a class', () => {
const metadata = collector.getMetadata(program.getSourceFile('/class-arity.ts'));
const metadata = collector.getMetadata(program.getSourceFile('/class-arity.ts')) !;
const zero = metadata.metadata['Zero'];
if (expectClass(zero)) expect(zero.arity).toBeUndefined();
@ -883,7 +883,7 @@ describe('Collector', () => {
})
export class MyComponent {}
`);
const metadata = collector.getMetadata(source);
const metadata = collector.getMetadata(source) !;
expect(metadata.metadata.MyComponent).toEqual({
__symbolic: 'class',
decorators: [{
@ -947,7 +947,7 @@ describe('Collector', () => {
function collectSource(content: string): ModuleMetadata {
const sourceFile = createSource(content);
return collector.getMetadata(sourceFile);
return collector.getMetadata(sourceFile) !;
}
});

View File

@ -12,7 +12,7 @@ import * as ts from 'typescript';
import {Evaluator} from '../src/evaluator';
import {Symbols} from '../src/symbols';
import {Directory, Host, expectNoDiagnostics, findVar} from './typescript.mocks';
import {Directory, Host, expectNoDiagnostics, findVar, findVarInitializer} from './typescript.mocks';
describe('Evaluator', () => {
const documentRegistry = ts.createDocumentRegistry();
@ -31,7 +31,7 @@ describe('Evaluator', () => {
service = ts.createLanguageService(host, documentRegistry);
program = service.getProgram();
typeChecker = program.getTypeChecker();
symbols = new Symbols(null);
symbols = new Symbols(null as any as ts.SourceFile);
evaluator = new Evaluator(symbols, new Map());
});
@ -48,10 +48,10 @@ describe('Evaluator', () => {
it('should be able to fold literal expressions', () => {
const consts = program.getSourceFile('consts.ts');
expect(evaluator.isFoldable(findVar(consts, 'someName').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVar(consts, 'someBool').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVar(consts, 'one').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVar(consts, 'two').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(consts, 'someName'))).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(consts, 'someBool'))).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(consts, 'one'))).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(consts, 'two'))).toBeTruthy();
});
it('should be able to fold expressions with foldable references', () => {
@ -60,20 +60,20 @@ describe('Evaluator', () => {
symbols.define('someBool', true);
symbols.define('one', 1);
symbols.define('two', 2);
expect(evaluator.isFoldable(findVar(expressions, 'three').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVar(expressions, 'four').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(expressions, 'three'))).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(expressions, 'four'))).toBeTruthy();
symbols.define('three', 3);
symbols.define('four', 4);
expect(evaluator.isFoldable(findVar(expressions, 'obj').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVar(expressions, 'arr').initializer)).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(expressions, 'obj'))).toBeTruthy();
expect(evaluator.isFoldable(findVarInitializer(expressions, 'arr'))).toBeTruthy();
});
it('should be able to evaluate literal expressions', () => {
const consts = program.getSourceFile('consts.ts');
expect(evaluator.evaluateNode(findVar(consts, 'someName').initializer)).toBe('some-name');
expect(evaluator.evaluateNode(findVar(consts, 'someBool').initializer)).toBe(true);
expect(evaluator.evaluateNode(findVar(consts, 'one').initializer)).toBe(1);
expect(evaluator.evaluateNode(findVar(consts, 'two').initializer)).toBe(2);
expect(evaluator.evaluateNode(findVarInitializer(consts, 'someName'))).toBe('some-name');
expect(evaluator.evaluateNode(findVarInitializer(consts, 'someBool'))).toBe(true);
expect(evaluator.evaluateNode(findVarInitializer(consts, 'one'))).toBe(1);
expect(evaluator.evaluateNode(findVarInitializer(consts, 'two'))).toBe(2);
});
it('should be able to evaluate expressions', () => {
@ -82,78 +82,77 @@ describe('Evaluator', () => {
symbols.define('someBool', true);
symbols.define('one', 1);
symbols.define('two', 2);
expect(evaluator.evaluateNode(findVar(expressions, 'three').initializer)).toBe(3);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'three'))).toBe(3);
symbols.define('three', 3);
expect(evaluator.evaluateNode(findVar(expressions, 'four').initializer)).toBe(4);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'four'))).toBe(4);
symbols.define('four', 4);
expect(evaluator.evaluateNode(findVar(expressions, 'obj').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'obj')))
.toEqual({one: 1, two: 2, three: 3, four: 4});
expect(evaluator.evaluateNode(findVar(expressions, 'arr').initializer)).toEqual([1, 2, 3, 4]);
expect(evaluator.evaluateNode(findVar(expressions, 'bTrue').initializer)).toEqual(true);
expect(evaluator.evaluateNode(findVar(expressions, 'bFalse').initializer)).toEqual(false);
expect(evaluator.evaluateNode(findVar(expressions, 'bAnd').initializer)).toEqual(true);
expect(evaluator.evaluateNode(findVar(expressions, 'bOr').initializer)).toEqual(true);
expect(evaluator.evaluateNode(findVar(expressions, 'nDiv').initializer)).toEqual(2);
expect(evaluator.evaluateNode(findVar(expressions, 'nMod').initializer)).toEqual(1);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'arr'))).toEqual([1, 2, 3, 4]);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bTrue'))).toEqual(true);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bFalse'))).toEqual(false);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bAnd'))).toEqual(true);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bOr'))).toEqual(true);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'nDiv'))).toEqual(2);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'nMod'))).toEqual(1);
expect(evaluator.evaluateNode(findVar(expressions, 'bLOr').initializer)).toEqual(false || true);
expect(evaluator.evaluateNode(findVar(expressions, 'bLAnd').initializer)).toEqual(true && true);
expect(evaluator.evaluateNode(findVar(expressions, 'bBOr').initializer)).toEqual(0x11 | 0x22);
expect(evaluator.evaluateNode(findVar(expressions, 'bBAnd').initializer)).toEqual(0x11 & 0x03);
expect(evaluator.evaluateNode(findVar(expressions, 'bXor').initializer)).toEqual(0x11 ^ 0x21);
expect(evaluator.evaluateNode(findVar(expressions, 'bEqual').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLOr'))).toEqual(false || true);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLAnd'))).toEqual(true && true);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bBOr'))).toEqual(0x11 | 0x22);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bBAnd'))).toEqual(0x11 & 0x03);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bXor'))).toEqual(0x11 ^ 0x21);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bEqual')))
.toEqual(1 == <any>'1');
expect(evaluator.evaluateNode(findVar(expressions, 'bNotEqual').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bNotEqual')))
.toEqual(1 != <any>'1');
expect(evaluator.evaluateNode(findVar(expressions, 'bIdentical').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bIdentical')))
.toEqual(1 === <any>'1');
expect(evaluator.evaluateNode(findVar(expressions, 'bNotIdentical').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bNotIdentical')))
.toEqual(1 !== <any>'1');
expect(evaluator.evaluateNode(findVar(expressions, 'bLessThan').initializer)).toEqual(1 < 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bGreaterThan').initializer)).toEqual(1 > 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bLessThanEqual').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLessThan'))).toEqual(1 < 2);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bGreaterThan'))).toEqual(1 > 2);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bLessThanEqual')))
.toEqual(1 <= 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bGreaterThanEqual').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bGreaterThanEqual')))
.toEqual(1 >= 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bShiftLeft').initializer)).toEqual(1 << 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bShiftRight').initializer))
.toEqual(-1 >> 2);
expect(evaluator.evaluateNode(findVar(expressions, 'bShiftRightU').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftLeft'))).toEqual(1 << 2);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRight'))).toEqual(-1 >> 2);
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRightU')))
.toEqual(-1 >>> 2);
});
it('should report recursive references as symbolic', () => {
const expressions = program.getSourceFile('expressions.ts');
expect(evaluator.evaluateNode(findVar(expressions, 'recursiveA').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveA')))
.toEqual({__symbolic: 'reference', name: 'recursiveB'});
expect(evaluator.evaluateNode(findVar(expressions, 'recursiveB').initializer))
expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveB')))
.toEqual({__symbolic: 'reference', name: 'recursiveA'});
});
it('should correctly handle special cases for CONST_EXPR', () => {
const const_expr = program.getSourceFile('const_expr.ts');
expect(evaluator.evaluateNode(findVar(const_expr, 'bTrue').initializer)).toEqual(true);
expect(evaluator.evaluateNode(findVar(const_expr, 'bFalse').initializer)).toEqual(false);
expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bTrue'))).toEqual(true);
expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bFalse'))).toEqual(false);
});
it('should resolve a forwardRef', () => {
const forwardRef = program.getSourceFile('forwardRef.ts');
expect(evaluator.evaluateNode(findVar(forwardRef, 'bTrue').initializer)).toEqual(true);
expect(evaluator.evaluateNode(findVar(forwardRef, 'bFalse').initializer)).toEqual(false);
expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bTrue'))).toEqual(true);
expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bFalse'))).toEqual(false);
});
it('should return new expressions', () => {
symbols.define('Value', {__symbolic: 'reference', module: './classes', name: 'Value'});
evaluator = new Evaluator(symbols, new Map());
const newExpression = program.getSourceFile('newExpression.ts');
expect(evaluator.evaluateNode(findVar(newExpression, 'someValue').initializer)).toEqual({
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({
__symbolic: 'new',
expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
arguments: ['name', 12]
});
expect(evaluator.evaluateNode(findVar(newExpression, 'complex').initializer)).toEqual({
expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'complex'))).toEqual({
__symbolic: 'new',
expression: {__symbolic: 'reference', name: 'Value', module: './classes'},
arguments: ['name', 12]
@ -162,8 +161,8 @@ describe('Evaluator', () => {
it('should support referene to a declared module type', () => {
const declared = program.getSourceFile('declared.ts');
const aDecl = findVar(declared, 'a');
expect(evaluator.evaluateNode(aDecl.type)).toEqual({
const aDecl = findVar(declared, 'a') !;
expect(evaluator.evaluateNode(aDecl.type !)).toEqual({
__symbolic: 'select',
expression: {__symbolic: 'reference', name: 'Foo'},
member: 'A'
@ -172,28 +171,28 @@ describe('Evaluator', () => {
it('should return errors for unsupported expressions', () => {
const errors = program.getSourceFile('errors.ts');
const fDecl = findVar(errors, 'f');
expect(evaluator.evaluateNode(fDecl.initializer))
const fDecl = findVar(errors, 'f') !;
expect(evaluator.evaluateNode(fDecl.initializer !))
.toEqual(
{__symbolic: 'error', message: 'Function call not supported', line: 1, character: 12});
const eDecl = findVar(errors, 'e');
expect(evaluator.evaluateNode(eDecl.type)).toEqual({
const eDecl = findVar(errors, 'e') !;
expect(evaluator.evaluateNode(eDecl.type !)).toEqual({
__symbolic: 'error',
message: 'Could not resolve type',
line: 2,
character: 11,
context: {typeName: 'NotFound'}
});
const sDecl = findVar(errors, 's');
expect(evaluator.evaluateNode(sDecl.initializer)).toEqual({
const sDecl = findVar(errors, 's') !;
expect(evaluator.evaluateNode(sDecl.initializer !)).toEqual({
__symbolic: 'error',
message: 'Name expected',
line: 3,
character: 14,
context: {received: '1'}
});
const tDecl = findVar(errors, 't');
expect(evaluator.evaluateNode(tDecl.initializer)).toEqual({
const tDecl = findVar(errors, 't') !;
expect(evaluator.evaluateNode(tDecl.initializer !)).toEqual({
__symbolic: 'error',
message: 'Expression form not supported',
line: 4,
@ -204,14 +203,14 @@ describe('Evaluator', () => {
it('should be able to fold an array spread', () => {
const expressions = program.getSourceFile('expressions.ts');
symbols.define('arr', [1, 2, 3, 4]);
const arrSpread = findVar(expressions, 'arrSpread');
expect(evaluator.evaluateNode(arrSpread.initializer)).toEqual([0, 1, 2, 3, 4, 5]);
const arrSpread = findVar(expressions, 'arrSpread') !;
expect(evaluator.evaluateNode(arrSpread.initializer !)).toEqual([0, 1, 2, 3, 4, 5]);
});
it('should be able to produce a spread expression', () => {
const expressions = program.getSourceFile('expressions.ts');
const arrSpreadRef = findVar(expressions, 'arrSpreadRef');
expect(evaluator.evaluateNode(arrSpreadRef.initializer)).toEqual([
const arrSpreadRef = findVar(expressions, 'arrSpreadRef') !;
expect(evaluator.evaluateNode(arrSpreadRef.initializer !)).toEqual([
0, {__symbolic: 'spread', expression: {__symbolic: 'reference', name: 'arrImport'}}, 5
]);
});
@ -220,8 +219,8 @@ describe('Evaluator', () => {
const source = sourceFileOf(`
export var a = new f;
`);
const expr = findVar(source, 'a');
expect(evaluator.evaluateNode(expr.initializer))
const expr = findVar(source, 'a') !;
expect(evaluator.evaluateNode(expr.initializer !))
.toEqual({__symbolic: 'new', expression: {__symbolic: 'reference', name: 'f'}});
});
});

View File

@ -17,7 +17,7 @@ describe('Symbols', () => {
let symbols: Symbols;
const someValue = 'some-value';
beforeEach(() => symbols = new Symbols(null));
beforeEach(() => symbols = new Symbols(null as any as ts.SourceFile));
it('should be able to add a symbol', () => symbols.define('someSymbol', someValue));
@ -110,7 +110,7 @@ describe('Symbols', () => {
}
return false;
};
ts.forEachChild(core, visit);
ts.forEachChild(core !, visit);
});
});

View File

@ -21,7 +21,7 @@ export class Host implements ts.LanguageServiceHost {
getScriptVersion(fileName: string): string { return this.version.toString(); }
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
getScriptSnapshot(fileName: string): ts.IScriptSnapshot|undefined {
const content = this.getFileContent(fileName);
if (content) return ts.ScriptSnapshot.fromString(content);
}
@ -40,7 +40,7 @@ export class Host implements ts.LanguageServiceHost {
this.version++;
}
private getFileContent(fileName: string): string {
private getFileContent(fileName: string): string|undefined {
if (this.overrides.has(fileName)) {
return this.overrides.get(fileName);
}
@ -69,9 +69,9 @@ export class MockNode implements ts.Node {
constructor(
public kind: ts.SyntaxKind = ts.SyntaxKind.Identifier, public flags: ts.NodeFlags = 0,
public pos: number = 0, public end: number = 0) {}
getSourceFile(): ts.SourceFile { return null; }
getSourceFile(): ts.SourceFile { return null as any as ts.SourceFile; }
getChildCount(sourceFile?: ts.SourceFile): number { return 0 }
getChildAt(index: number, sourceFile?: ts.SourceFile): ts.Node { return null; }
getChildAt(index: number, sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; }
getChildren(sourceFile?: ts.SourceFile): ts.Node[] { return []; }
getStart(sourceFile?: ts.SourceFile): number { return 0; }
getFullStart(): number { return 0; }
@ -81,10 +81,10 @@ export class MockNode implements ts.Node {
getLeadingTriviaWidth(sourceFile?: ts.SourceFile): number { return 0; }
getFullText(sourceFile?: ts.SourceFile): string { return ''; }
getText(sourceFile?: ts.SourceFile): string { return ''; }
getFirstToken(sourceFile?: ts.SourceFile): ts.Node { return null; }
getLastToken(sourceFile?: ts.SourceFile): ts.Node { return null; }
getFirstToken(sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; }
getLastToken(sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; }
forEachChild<T>(cbNode: (node: ts.Node) => T, cbNodeArray?: (nodes: ts.Node[]) => T): T {
return null;
return null as any as T;
}
}
@ -162,22 +162,28 @@ export function allChildren<T>(node: ts.Node, cb: (node: ts.Node) => T): T {
})
}
export function findClass(sourceFile: ts.SourceFile, name: string): ts.ClassDeclaration {
export function findClass(sourceFile: ts.SourceFile, name: string): ts.ClassDeclaration|undefined {
return ts.forEachChild(
sourceFile, node => isClass(node) && isNamed(node.name, name) ? node : undefined);
}
export function findVar(sourceFile: ts.SourceFile, name: string): ts.VariableDeclaration {
export function findVar(sourceFile: ts.SourceFile, name: string): ts.VariableDeclaration|undefined {
return allChildren(
sourceFile, node => isVar(node) && isNamed(node.name, name) ? node : undefined);
}
export function findVarInitializer(sourceFile: ts.SourceFile, name: string): ts.Expression {
const v = findVar(sourceFile, name);
expect(v && v.initializer).toBeDefined();
return v !.initializer !;
}
export function isClass(node: ts.Node): node is ts.ClassDeclaration {
return node.kind === ts.SyntaxKind.ClassDeclaration;
}
export function isNamed(node: ts.Node, name: string): node is ts.Identifier {
return node.kind === ts.SyntaxKind.Identifier && (<ts.Identifier>node).text === name;
export function isNamed(node: ts.Node | undefined, name: string): node is ts.Identifier {
return !!node && node.kind === ts.SyntaxKind.Identifier && (<ts.Identifier>node).text === name;
}
export function isVar(node: ts.Node): node is ts.VariableDeclaration {

View File

@ -7,6 +7,7 @@
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../../dist/all/@angular/tsc-wrapped",
"strictNullChecks": true,
"noImplicitAny": true,
"noFallthroughCasesInSwitch": true,
"paths": {