Skip to content

Commit 19ab8ab

Browse files
committed
Fix strictNullChecks breaks
1 parent 8936b03 commit 19ab8ab

4 files changed

Lines changed: 54 additions & 27 deletions

File tree

src/compiler/program.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ namespace ts {
190190
getDirectories: (path: string) => sys.getDirectories(path),
191191
realpath,
192192
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
193-
getModifiedTime: path => sys.getModifiedTime(path),
194-
setModifiedTime: (path, date) => sys.setModifiedTime(path, date),
195-
deleteFile: path => sys.deleteFile(path)
193+
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
194+
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
195+
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
196196
};
197197
}
198198

src/compiler/tsbuild.ts

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,14 @@ namespace ts {
248248
}
249249

250250
function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine) {
251-
const relativePath = getRelativePathFromDirectory(rootDirOfOptions(configFile.options, configFile.options.configFilePath), inputFileName, /*ignoreCase*/ true);
252-
const outputPath = resolvePath(configFile.options.declarationDir || configFile.options.outDir || getDirectoryPath(configFile.options.configFilePath), relativePath);
251+
const relativePath = getRelativePathFromDirectory(rootDirOfOptions(configFile.options, configFile.options.configFilePath!), inputFileName, /*ignoreCase*/ true);
252+
const outputPath = resolvePath(configFile.options.declarationDir || configFile.options.outDir || getDirectoryPath(configFile.options.configFilePath!), relativePath);
253253
return changeExtension(outputPath, ".d.ts");
254254
}
255255

256256
function getOutputJavaScriptFileName(inputFileName: string, configFile: ParsedCommandLine) {
257-
const relativePath = getRelativePathFromDirectory(rootDirOfOptions(configFile.options, configFile.options.configFilePath), inputFileName, /*ignoreCase*/ true);
258-
const outputPath = resolvePath(configFile.options.outDir || getDirectoryPath(configFile.options.configFilePath), relativePath);
257+
const relativePath = getRelativePathFromDirectory(rootDirOfOptions(configFile.options, configFile.options.configFilePath!), inputFileName, /*ignoreCase*/ true);
258+
const outputPath = resolvePath(configFile.options.outDir || getDirectoryPath(configFile.options.configFilePath!), relativePath);
259259
return changeExtension(outputPath, (fileExtensionIs(inputFileName, ".tsx") && configFile.options.jsx === JsxEmit.Preserve) ? ".jsx" : ".js");
260260
}
261261

@@ -276,7 +276,9 @@ namespace ts {
276276
}
277277

278278
function getOutFileOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
279-
Debug.assert(!!project.options.outFile, "outFile must be set");
279+
if (!project.options.outFile) {
280+
throw new Error("Assert - outFile must be set");
281+
}
280282
const outputs: string[] = [];
281283
outputs.push(project.options.outFile);
282284
if (project.options.declaration) {
@@ -328,9 +330,7 @@ namespace ts {
328330
options,
329331
projectStatus: createFileMap(),
330332
unchangedOutputs: createFileMap(),
331-
verbose: options.verbose ? (diag, ...args) => {
332-
verboseDiag(createCompilerDiagnostic(diag, ...args));
333-
} : () => undefined
333+
verbose: verboseDiag ? (diag, ...args) => verboseDiag(createCompilerDiagnostic(diag, ...args)) : () => undefined
334334
};
335335
}
336336

@@ -379,6 +379,11 @@ namespace ts {
379379
function addProject(projectSpecification: string) {
380380
const fileName = resolvePath(host.getCurrentDirectory(), projectSpecification);
381381
const refPath = resolveProjectReferencePath(host, { path: fileName });
382+
if (!refPath) {
383+
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, projectSpecification));
384+
return;
385+
}
386+
382387
if (!host.fileExists(refPath)) {
383388
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
384389
}
@@ -388,6 +393,10 @@ namespace ts {
388393
}
389394

390395
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, options: BuildOptions) {
396+
if (!host.getModifiedTime || !host.setModifiedTime) {
397+
throw new Error("Host must support timestamp APIs");
398+
}
399+
391400
const configFileCache = createConfigFileCache(host);
392401
let context = createBuildContext(options, reportDiagnostic);
393402

@@ -407,13 +416,17 @@ namespace ts {
407416
return getUpToDateStatus(configFileCache.parseConfigFile(configFileName));
408417
}
409418

410-
function getUpToDateStatus(project: ParsedCommandLine): UpToDateStatus {
411-
const prior = context.projectStatus.getValueOrUndefined(project.options.configFilePath);
419+
function getUpToDateStatus(project: ParsedCommandLine | undefined): UpToDateStatus {
420+
if (project === undefined) {
421+
return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" };
422+
}
423+
424+
const prior = context.projectStatus.getValueOrUndefined(project.options.configFilePath!);
412425
if (prior !== undefined) {
413426
return prior;
414427
}
415428
const actual = getUpToDateStatusWorker(project);
416-
context.projectStatus.setValue(project.options.configFilePath, actual);
429+
context.projectStatus.setValue(project.options.configFilePath!, actual);
417430
return actual;
418431
}
419432

@@ -442,7 +455,7 @@ namespace ts {
442455
};
443456
}
444457

445-
const inputTime = host.getModifiedTime(inputFile);
458+
const inputTime = host.getModifiedTime!(inputFile);
446459
if (inputTime > newestInputFileTime) {
447460
newestInputFileName = inputFile;
448461
newestInputFileTime = inputTime;
@@ -466,7 +479,7 @@ namespace ts {
466479
};
467480
}
468481

469-
const outputTime = host.getModifiedTime(output);
482+
const outputTime = host.getModifiedTime!(output);
470483
// If an output is older than the newest input, we can stop checking
471484
if (outputTime < newestInputFileTime) {
472485
return {
@@ -492,7 +505,7 @@ namespace ts {
492505
newestDeclarationFileContentChangedTime = newer(unchangedTime, newestDeclarationFileContentChangedTime);
493506
}
494507
else {
495-
newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, host.getModifiedTime(output));
508+
newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, host.getModifiedTime!(output));
496509
}
497510
}
498511
}
@@ -609,10 +622,10 @@ namespace ts {
609622
}
610623

611624
// TODO Accept parsedCommandLine instead?
612-
function buildSingleProject(proj: ResolvedConfigFileName) {
625+
function buildSingleProject(proj: ResolvedConfigFileName): BuildResultFlags {
613626
if (context.options.dry) {
614627
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj));
615-
return;
628+
return BuildResultFlags.Success;
616629
}
617630

618631
context.verbose(Diagnostics.Building_project_0, proj);
@@ -707,17 +720,17 @@ namespace ts {
707720
let priorNewestUpdateTime = minimumDate;
708721
for (const file of outputs) {
709722
if (isDeclarationFile(file)) {
710-
priorNewestUpdateTime = newer(priorNewestUpdateTime, host.getModifiedTime(file));
723+
priorNewestUpdateTime = newer(priorNewestUpdateTime, host.getModifiedTime!(file));
711724
}
712-
host.setModifiedTime(file, now);
725+
host.setModifiedTime!(file, now);
713726
}
714727

715-
context.projectStatus.setValue(proj.options.configFilePath, { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: priorNewestUpdateTime } as UpToDateStatus);
728+
context.projectStatus.setValue(proj.options.configFilePath!, { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: priorNewestUpdateTime } as UpToDateStatus);
716729
}
717730

718731
function getFilesToClean(configFileNames: ResolvedConfigFileName[]): string[] | undefined {
719732
const resolvedNames: ResolvedConfigFileName[] | undefined = resolveProjectNames(configFileNames);
720-
if (resolvedNames === undefined) return;
733+
if (resolvedNames === undefined) return undefined;
721734

722735
// Get the same graph for cleaning we'd use for building
723736
const graph = createDependencyGraph(resolvedNames);
@@ -726,6 +739,10 @@ namespace ts {
726739
for (const level of graph.buildQueue) {
727740
for (const proj of level) {
728741
const parsed = configFileCache.parseConfigFile(proj);
742+
if (parsed === undefined) {
743+
// File has gone missing; fine to ignore here
744+
continue;
745+
}
729746
const outputs = getAllProjectOutputs(parsed);
730747
for (const output of outputs) {
731748
if (host.fileExists(output)) {
@@ -742,6 +759,9 @@ namespace ts {
742759
if (resolvedNames === undefined) return;
743760

744761
const filesToDelete = getFilesToClean(resolvedNames);
762+
if (filesToDelete === undefined) {
763+
return;
764+
}
745765

746766
if (context.options.dry) {
747767
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")));
@@ -786,9 +806,13 @@ namespace ts {
786806
const queue = graph.buildQueue;
787807
reportBuildQueue(graph);
788808

789-
let next: ResolvedConfigFileName;
809+
let next: ResolvedConfigFileName | undefined;
790810
while (next = getNext()) {
791811
const proj = configFileCache.parseConfigFile(next);
812+
if (proj === undefined) {
813+
break;
814+
}
815+
792816
const status = getUpToDateStatus(proj);
793817
reportProjectStatus(next, status);
794818

src/harness/unittests/tsbuild.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace ts {
77
const sampleRoot = resolvePath(__dirname, "../../tests/projects/sample1");
88
loadFsMirror(bfs, sampleRoot, "/src");
99
bfs.mkdirpSync("/lib");
10-
bfs.writeFileSync("/lib/lib.d.ts", Harness.IO.readFile(combinePaths(Harness.libFolder, "lib.d.ts")));
10+
bfs.writeFileSync("/lib/lib.d.ts", Harness.IO.readFile(combinePaths(Harness.libFolder, "lib.d.ts"))!);
1111
bfs.meta.set("defaultLibLocation", "/lib");
1212
bfs.makeReadonly();
1313
tick();
@@ -196,7 +196,7 @@ namespace ts {
196196
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
197197
const actual = lastDiagnostics.slice();
198198
if (actual.length !== expected.length) {
199-
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\ngot\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
199+
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
200200
}
201201
for (let i = 0; i < actual.length; i++) {
202202
if (actual[i].code !== expected[i].code) {
@@ -229,7 +229,7 @@ namespace ts {
229229
vfs.mkdirpSync(virtualRoot);
230230
for (const path of Harness.IO.readDirectory(localRoot)) {
231231
const file = getBaseFileName(path);
232-
vfs.writeFileSync(virtualRoot + "/" + file, Harness.IO.readFile(localRoot + "/" + file));
232+
vfs.writeFileSync(virtualRoot + "/" + file, Harness.IO.readFile(localRoot + "/" + file)!);
233233
}
234234
for (const dir of Harness.IO.getDirectories(localRoot)) {
235235
loadFsMirror(vfs, localRoot + "/" + dir, virtualRoot + "/" + dir);

src/harness/vfs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ namespace vfs {
415415
*/
416416
public utimesSync(path: string, atime: Date, mtime: Date) {
417417
const entry = this._walk(this._resolve(path));
418+
if (!entry || !entry.node) {
419+
throw createIOError("ENOENT");
420+
}
418421
entry.node.atimeMs = +atime;
419422
entry.node.mtimeMs = +mtime;
420423
}

0 commit comments

Comments
 (0)