From 13e7ae76e025768537bdd8b07115e8dfa0b4e8fb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 15 Jun 2021 13:33:23 -0700 Subject: [PATCH] Pass throwIfNoEntry to fs.statSync (#41604) (#44584) Future versions of node will be able to return undefined, rather than allocating and throwing an exception, when a file is not found. See https://github.com/nodejs/node/pull/33716 Co-authored-by: Andrew Casey --- src/compiler/sys.ts | 28 ++++++++++++++++++++++------ src/tsserver/server.ts | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index efa51678f4da0..af53b9de220e8 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1235,8 +1235,8 @@ namespace ts { }, getFileSize(path) { try { - const stat = _fs.statSync(path); - if (stat.isFile()) { + const stat = statSync(path); + if (stat?.isFile()) { return stat.size; } } @@ -1283,6 +1283,16 @@ namespace ts { }; return nodeSystem; + /** + * `throwIfNoEntry` was added so recently that it's not in the node types. + * This helper encapsulates the mitigating usage of `any`. + * See https://github.com/nodejs/node/pull/33716 + */ + function statSync(path: string): import("fs").Stats | undefined { + // throwIfNoEntry will be ignored by older versions of node + return (_fs as any).statSync(path, { throwIfNoEntry: false }); + } + /** * Uses the builtin inspector APIs to capture a CPU profile * See https://nodejs.org/api/inspector.html#inspector_example_usage for details @@ -1341,7 +1351,7 @@ namespace ts { activeSession.post("Profiler.stop", (err, { profile }) => { if (!err) { try { - if (_fs.statSync(profilePath).isDirectory()) { + if (statSync(profilePath)?.isDirectory()) { profilePath = _path.join(profilePath, `${(new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`); } } @@ -1631,7 +1641,10 @@ namespace ts { const name = combinePaths(path, entry); try { - stat = _fs.statSync(name); + stat = statSync(name); + if (!stat) { + continue; + } } catch (e) { continue; @@ -1668,7 +1681,10 @@ namespace ts { Error.stackTraceLimit = 0; try { - const stat = _fs.statSync(path); + const stat = statSync(path); + if (!stat) { + return false; + } switch (entryKind) { case FileSystemEntryKind.File: return stat.isFile(); case FileSystemEntryKind.Directory: return stat.isDirectory(); @@ -1706,7 +1722,7 @@ namespace ts { function getModifiedTime(path: string) { try { - return _fs.statSync(path).mtime; + return statSync(path)?.mtime; } catch (e) { return undefined; diff --git a/src/tsserver/server.ts b/src/tsserver/server.ts index 306cbd7bba393..099d1e162716a 100644 --- a/src/tsserver/server.ts +++ b/src/tsserver/server.ts @@ -675,6 +675,7 @@ namespace ts.server { return { getModifiedTime, poll, startWatchTimer, addFile, removeFile }; function getModifiedTime(fileName: string): Date { + // Caller guarantees that `fileName` exists, so there'd be no benefit from throwIfNoEntry return fs.statSync(fileName).mtime; }