Skip to content

Commit 585a670

Browse files
clydinhansl
authored andcommitted
refactor(@ngtools/webpack): support strict null checks
1 parent e3c1102 commit 585a670

File tree

8 files changed

+69
-59
lines changed

8 files changed

+69
-59
lines changed

packages/@ngtools/webpack/src/compiler_host.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class VirtualDirStats extends VirtualStats {
5959
}
6060

6161
export class VirtualFileStats extends VirtualStats {
62-
private _sourceFile: ts.SourceFile;
62+
private _sourceFile: ts.SourceFile | null;
6363
constructor(_fileName: string, private _content: string) {
6464
super(_fileName);
6565
}
@@ -93,8 +93,8 @@ export class VirtualFileStats extends VirtualStats {
9393

9494
export class WebpackCompilerHost implements ts.CompilerHost {
9595
private _delegate: ts.CompilerHost;
96-
private _files: {[path: string]: VirtualFileStats} = Object.create(null);
97-
private _directories: {[path: string]: VirtualDirStats} = Object.create(null);
96+
private _files: {[path: string]: VirtualFileStats | null} = Object.create(null);
97+
private _directories: {[path: string]: VirtualDirStats | null} = Object.create(null);
9898

9999
private _changedFiles: {[path: string]: boolean} = Object.create(null);
100100
private _changedDirs: {[path: string]: boolean} = Object.create(null);
@@ -233,7 +233,9 @@ export class WebpackCompilerHost implements ts.CompilerHost {
233233

234234
readFile(fileName: string): string {
235235
fileName = this._resolve(fileName);
236-
if (this._files[fileName] == null) {
236+
237+
const stats = this._files[fileName];
238+
if (stats == null) {
237239
const result = this._delegate.readFile(fileName);
238240
if (result !== undefined && this._cache) {
239241
this._setFileContent(fileName, result);
@@ -242,13 +244,14 @@ export class WebpackCompilerHost implements ts.CompilerHost {
242244
return result;
243245
}
244246
}
245-
return this._files[fileName].content;
247+
return stats.content;
246248
}
247249

248250
directoryExists(directoryName: string): boolean {
249251
directoryName = this._resolve(directoryName);
250252
return (this._directories[directoryName] != null)
251-
|| this._delegate.directoryExists(directoryName);
253+
|| (this._delegate.directoryExists != undefined
254+
&& this._delegate.directoryExists(directoryName));
252255
}
253256

254257
getFiles(path: string): string[] {
@@ -276,18 +279,19 @@ export class WebpackCompilerHost implements ts.CompilerHost {
276279
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, _onError?: OnErrorFn) {
277280
fileName = this._resolve(fileName);
278281

279-
if (this._files[fileName] == null) {
282+
const stats = this._files[fileName];
283+
if (stats == null) {
280284
const content = this.readFile(fileName);
281285
if (!this._cache) {
282286
return ts.createSourceFile(fileName, content, languageVersion, this._setParentNodes);
283287
}
284288
}
285289

286-
return this._files[fileName].getSourceFile(languageVersion, this._setParentNodes);
290+
return this._files[fileName]!.getSourceFile(languageVersion, this._setParentNodes);
287291
}
288292

289293
getCancellationToken() {
290-
return this._delegate.getCancellationToken();
294+
return this._delegate.getCancellationToken!();
291295
}
292296

293297
getDefaultLibFileName(options: ts.CompilerOptions) {

packages/@ngtools/webpack/src/entry_resolver.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function _recursiveSymbolExportLookup(refactor: TypeScriptFileRefactor,
1212
// Check this file.
1313
const hasSymbol = refactor.findAstNodes(null, ts.SyntaxKind.ClassDeclaration)
1414
.some((cd: ts.ClassDeclaration) => {
15-
return cd.name && cd.name.text == symbolName;
15+
return cd.name != undefined && cd.name.text == symbolName;
1616
});
1717
if (hasSymbol) {
1818
return refactor.fileName;
@@ -64,7 +64,7 @@ function _recursiveSymbolExportLookup(refactor: TypeScriptFileRefactor,
6464
const source = new TypeScriptFileRefactor(module, host, program);
6565
const hasSymbol = source.findAstNodes(null, ts.SyntaxKind.ClassDeclaration)
6666
.some((cd: ts.ClassDeclaration) => {
67-
return cd.name && cd.name.text == symbolName;
67+
return cd.name != undefined && cd.name.text == symbolName;
6868
});
6969

7070
if (hasSymbol) {
@@ -101,13 +101,15 @@ function _symbolImportLookup(refactor: TypeScriptFileRefactor,
101101
}
102102

103103
const module = resolvedModule.resolvedModule.resolvedFileName;
104-
if (decl.importClause.namedBindings.kind == ts.SyntaxKind.NamespaceImport) {
104+
if (decl.importClause.namedBindings
105+
&& decl.importClause.namedBindings.kind == ts.SyntaxKind.NamespaceImport) {
105106
const binding = decl.importClause.namedBindings as ts.NamespaceImport;
106107
if (binding.name.text == symbolName) {
107108
// This is a default export.
108109
return module;
109110
}
110-
} else if (decl.importClause.namedBindings.kind == ts.SyntaxKind.NamedImports) {
111+
} else if (decl.importClause.namedBindings
112+
&& decl.importClause.namedBindings.kind == ts.SyntaxKind.NamedImports) {
111113
const binding = decl.importClause.namedBindings as ts.NamedImports;
112114
for (const specifier of binding.elements) {
113115
if (specifier.name.text == symbolName) {

packages/@ngtools/webpack/src/extract_i18n_plugin.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface ExtractI18nPluginOptions {
2121
export class ExtractI18nPlugin implements Tapable {
2222
private _resourceLoader: WebpackResourceLoader;
2323

24-
private _donePromise: Promise<void>;
24+
private _donePromise: Promise<void> | null;
2525
private _compiler: any = null;
2626
private _compilation: any = null;
2727

@@ -35,9 +35,9 @@ export class ExtractI18nPlugin implements Tapable {
3535
private _compilerHost: ts.CompilerHost;
3636
private _program: ts.Program;
3737

38-
private _i18nFormat: string;
39-
private _locale: string;
40-
private _outFile: string;
38+
private _i18nFormat?: string;
39+
private _locale?: string;
40+
private _outFile?: string;
4141

4242
constructor(options: ExtractI18nPluginOptions) {
4343
this._setupOptions(options);
@@ -67,7 +67,7 @@ export class ExtractI18nPlugin implements Tapable {
6767
throw new Error(`An error happened while parsing ${this._tsConfigPath} JSON: ${err}.`);
6868
}
6969
const tsConfig = ts.parseJsonConfigFileContent(
70-
tsConfigJson, ts.sys, basePath, null, this._tsConfigPath);
70+
tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath);
7171

7272
let fileNames = tsConfig.fileNames;
7373
if (options.hasOwnProperty('exclude')) {

packages/@ngtools/webpack/src/lazy_routes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as ts from 'typescript';
44
import {TypeScriptFileRefactor} from './refactor';
55

66

7-
function _getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string {
7+
function _getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null {
88
if (node.kind == ts.SyntaxKind.Identifier) {
99
return (node as ts.Identifier).text;
1010
} else if (node.kind == ts.SyntaxKind.StringLiteral) {
@@ -16,7 +16,7 @@ function _getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string
1616

1717

1818
export interface LazyRouteMap {
19-
[path: string]: string;
19+
[path: string]: string | null;
2020
}
2121

2222

packages/@ngtools/webpack/src/loader.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const changeMap: {[key: string]: Platform} = {
2424
}
2525
};
2626

27-
function _getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string {
27+
function _getContentOfKeyLiteral(_source: ts.SourceFile, node?: ts.Node): string | null {
2828
if (!node) {
2929
return null;
3030
} else if (node.kind == ts.SyntaxKind.Identifier) {
@@ -73,6 +73,7 @@ function _angularImportsFromNode(node: ts.ImportDeclaration, _sourceFile: ts.Sou
7373
// This is of the form `import 'path';`. Nothing to do.
7474
return [];
7575
}
76+
return [];
7677
}
7778

7879

@@ -224,8 +225,8 @@ function _replacePlatform(
224225

225226
function _replaceBootstrapOrRender(refactor: TypeScriptFileRefactor, call: ts.CallExpression) {
226227
// If neither bootstrapModule or renderModule can't be found, bail out early.
227-
let replacementTarget: string;
228-
let identifier: ts.Identifier;
228+
let replacementTarget: string | undefined;
229+
let identifier: ts.Identifier | undefined;
229230
if (call.getText().includes('bootstrapModule')) {
230231
if (call.expression.kind != ts.SyntaxKind.PropertyAccessExpression) {
231232
return;
@@ -252,8 +253,9 @@ function _replaceBootstrapOrRender(refactor: TypeScriptFileRefactor, call: ts.Ca
252253
}
253254

254255

255-
function _getCaller(node: ts.Node): ts.CallExpression {
256-
while (node = node.parent) {
256+
function _getCaller(node: ts.Node): ts.CallExpression | null {
257+
while (node.parent) {
258+
node = node.parent;
257259
if (node.kind === ts.SyntaxKind.CallExpression) {
258260
return node as ts.CallExpression;
259261
}
@@ -266,8 +268,9 @@ function _replaceEntryModule(plugin: AotPlugin, refactor: TypeScriptFileRefactor
266268
const modules = refactor.findAstNodes(refactor.sourceFile, ts.SyntaxKind.Identifier, true)
267269
.filter(identifier => identifier.getText() === plugin.entryModule.className)
268270
.filter(identifier =>
269-
identifier.parent.kind === ts.SyntaxKind.CallExpression ||
270-
identifier.parent.kind === ts.SyntaxKind.PropertyAssignment)
271+
identifier.parent &&
272+
(identifier.parent.kind === ts.SyntaxKind.CallExpression ||
273+
identifier.parent.kind === ts.SyntaxKind.PropertyAssignment))
271274
.filter(node => !!_getCaller(node));
272275

273276
if (modules.length == 0) {
@@ -282,7 +285,9 @@ function _replaceEntryModule(plugin: AotPlugin, refactor: TypeScriptFileRefactor
282285
.forEach(reference => {
283286
refactor.replaceNode(reference, factoryClassName);
284287
const caller = _getCaller(reference);
285-
_replaceBootstrapOrRender(refactor, caller);
288+
if (caller) {
289+
_replaceBootstrapOrRender(refactor, caller);
290+
}
286291
});
287292
}
288293

@@ -309,7 +314,7 @@ function _removeModuleId(refactor: TypeScriptFileRefactor) {
309314
refactor.findAstNodes(sourceFile, ts.SyntaxKind.Decorator, true)
310315
.reduce((acc, node) => {
311316
return acc.concat(refactor.findAstNodes(node, ts.SyntaxKind.ObjectLiteralExpression, true));
312-
}, [])
317+
}, new Array<ts.Node>())
313318
// Get all their property assignments.
314319
.filter((node: ts.ObjectLiteralExpression) => {
315320
return node.properties.some(prop => {
@@ -496,7 +501,7 @@ export function _exportModuleMap(plugin: AotPlugin, refactor: TypeScriptFileRefa
496501
});
497502

498503
modules.forEach((module, index) => {
499-
const relativePath = path.relative(dirName, module.modulePath).replace(/\\/g, '/');
504+
const relativePath = path.relative(dirName, module.modulePath!).replace(/\\/g, '/');
500505
refactor.prependBefore(node, `import * as __lazy_${index}__ from './${relativePath}'`);
501506
});
502507

@@ -577,7 +582,7 @@ export function ngcLoader(this: LoaderContext & { _compilation: any }, source: s
577582
const messageText = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
578583

579584
if (diagnostic.file) {
580-
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
585+
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
581586
const fileName = diagnostic.file.fileName;
582587
const {line, character} = position;
583588
message += `${fileName} (${line + 1},${character + 1}): ${messageText}\n`;

packages/@ngtools/webpack/src/paths-plugin.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ export class PathsPlugin implements Tapable {
6767
}
6868
this._tsConfigPath = options.tsConfigPath;
6969

70-
if (options.hasOwnProperty('compilerOptions')) {
71-
this._compilerOptions = Object.assign({}, options.compilerOptions);
70+
if (options.compilerOptions) {
71+
this._compilerOptions = options.compilerOptions;
7272
} else {
73-
this._compilerOptions = PathsPlugin._loadOptionsFromTsConfig(this._tsConfigPath, null);
73+
this._compilerOptions = PathsPlugin._loadOptionsFromTsConfig(this._tsConfigPath);
7474
}
7575

76-
if (options.hasOwnProperty('compilerHost')) {
76+
if (options.compilerHost) {
7777
this._host = options.compilerHost;
7878
} else {
7979
this._host = ts.createCompilerHost(this._compilerOptions, false);

packages/@ngtools/webpack/src/plugin.ts

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class AotPlugin implements Tapable {
5656
private _tsConfigPath: string;
5757
private _entryModule: string;
5858

59-
private _donePromise: Promise<void>;
59+
private _donePromise: Promise<void> | null;
6060
private _compiler: any = null;
6161
private _compilation: any = null;
6262

@@ -66,10 +66,10 @@ export class AotPlugin implements Tapable {
6666
private _basePath: string;
6767
private _genDir: string;
6868

69-
private _i18nFile: string;
70-
private _i18nFormat: string;
71-
private _locale: string;
72-
private _missingTranslation: string;
69+
private _i18nFile?: string;
70+
private _i18nFormat?: string;
71+
private _locale?: string;
72+
private _missingTranslation?: string;
7373

7474
private _diagnoseFiles: { [path: string]: boolean } = {};
7575
private _firstRun = true;
@@ -128,7 +128,7 @@ export class AotPlugin implements Tapable {
128128
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
129129

130130
if (diagnostic.file) {
131-
const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
131+
const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
132132
throw new Error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message})`);
133133
} else {
134134
throw new Error(message);
@@ -166,7 +166,7 @@ export class AotPlugin implements Tapable {
166166
}
167167

168168
const tsConfig = ts.parseJsonConfigFileContent(
169-
tsConfigJson, ts.sys, basePath, null, this._tsConfigPath);
169+
tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath);
170170

171171
let fileNames = tsConfig.fileNames;
172172
this._rootFilePath = fileNames;
@@ -192,23 +192,23 @@ export class AotPlugin implements Tapable {
192192
this._basePath = basePath;
193193
this._genDir = genDir;
194194

195-
if (options.hasOwnProperty('typeChecking')) {
195+
if (options.typeChecking !== undefined) {
196196
this._typeCheck = options.typeChecking;
197197
}
198-
if (options.hasOwnProperty('skipCodeGeneration')) {
198+
if (options.skipCodeGeneration !== undefined) {
199199
this._skipCodeGeneration = options.skipCodeGeneration;
200200
}
201201

202202
this._compilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath);
203203

204204
// Override some files in the FileSystem.
205-
if (options.hasOwnProperty('hostOverrideFileSystem')) {
205+
if (options.hostOverrideFileSystem) {
206206
for (const filePath of Object.keys(options.hostOverrideFileSystem)) {
207207
this._compilerHost.writeFile(filePath, options.hostOverrideFileSystem[filePath], false);
208208
}
209209
}
210210
// Override some files in the FileSystem with paths from the actual file system.
211-
if (options.hasOwnProperty('hostReplacementPaths')) {
211+
if (options.hostReplacementPaths) {
212212
for (const filePath of Object.keys(options.hostReplacementPaths)) {
213213
const replacementFilePath = options.hostReplacementPaths[filePath];
214214
const content = this._compilerHost.readFile(replacementFilePath);
@@ -345,7 +345,7 @@ export class AotPlugin implements Tapable {
345345
return callback(null, result);
346346
}
347347

348-
this.done.then(() => {
348+
this.done!.then(() => {
349349
result.resource = this.genDir;
350350
result.dependencies.forEach((d: any) => d.critical = false);
351351
result.resolveDependencies = (_fs: any, _resource: any, _recursive: any,
@@ -380,7 +380,7 @@ export class AotPlugin implements Tapable {
380380
// Virtual file system.
381381
compiler.resolvers.normal.plugin('before-resolve', (request: any, cb: () => void) => {
382382
if (request.request.match(/\.ts$/)) {
383-
this.done.then(() => cb(), () => cb());
383+
this.done!.then(() => cb(), () => cb());
384384
} else {
385385
cb();
386386
}
@@ -432,21 +432,20 @@ export class AotPlugin implements Tapable {
432432
return;
433433
}
434434

435-
const diagnostics: ts.Diagnostic[] = []
436-
.concat(
437-
this._program.getCompilerOptions().declaration
438-
? this._program.getDeclarationDiagnostics(sourceFile) : [],
439-
this._program.getSyntacticDiagnostics(sourceFile),
440-
this._program.getSemanticDiagnostics(sourceFile)
441-
);
435+
const diagnostics: Array<ts.Diagnostic> = [
436+
...(this._program.getCompilerOptions().declaration
437+
? this._program.getDeclarationDiagnostics(sourceFile) : []),
438+
...this._program.getSyntacticDiagnostics(sourceFile),
439+
...this._program.getSemanticDiagnostics(sourceFile)
440+
];
442441

443442
if (diagnostics.length > 0) {
444443
diagnostics.forEach(diagnostic => {
445444
const messageText = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
446445
let message;
447446

448447
if (diagnostic.file) {
449-
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
448+
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
450449

451450
const sourceText = diagnostic.file.getFullText();
452451
let {line, character, fileName} = this._translateSourceMap(sourceText,
@@ -532,7 +531,7 @@ export class AotPlugin implements Tapable {
532531

533532
if (diagnostic.file) {
534533
const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(
535-
diagnostic.start);
534+
diagnostic.start!);
536535
return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message})`;
537536
} else {
538537
return message;

0 commit comments

Comments
 (0)