From bee7ee00a5fd4ec5130cfc560665364d5b70d3e7 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 21 Nov 2019 18:06:27 -0800 Subject: [PATCH] sys: Use readdir withFileTypes option to skip lots of stat syscalls This makes walking large directory trees much more efficient on Node 10.10 or later. See: https://lwn.net/Articles/606995/ https://www.python.org/dev/peps/pep-0471/ https://github.com/nodejs/node/pull/22020 https://nodejs.org/en/blog/release/v10.10.0/ Signed-off-by: Anders Kaseorg --- src/compiler/sys.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index ad866cba13065..dfde77e465bc8 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1353,23 +1353,32 @@ namespace ts { function getAccessibleFileSystemEntries(path: string): FileSystemEntries { perfLogger.logEvent("ReadDir: " + (path || ".")); try { - const entries = _fs.readdirSync(path || ".").sort(); + const entries = _fs.readdirSync(path || ".", { withFileTypes: true }); const files: string[] = []; const directories: string[] = []; - for (const entry of entries) { + for (const dirent of entries) { + // withFileTypes is not supported before Node 10.10. + const entry = typeof dirent === "string" ? dirent : dirent.name; + // This is necessary because on some file system node fails to exclude // "." and "..". See https://github.com/nodejs/node/issues/4002 if (entry === "." || entry === "..") { continue; } - const name = combinePaths(path, entry); let stat: any; - try { - stat = _fs.statSync(name); + if (typeof dirent === "string" || dirent.isSymbolicLink()) { + const name = combinePaths(path, entry); + + try { + stat = _fs.statSync(name); + } + catch (e) { + continue; + } } - catch (e) { - continue; + else { + stat = dirent; } if (stat.isFile()) { @@ -1379,6 +1388,8 @@ namespace ts { directories.push(entry); } } + files.sort(); + directories.sort(); return { files, directories }; } catch (e) { @@ -1413,8 +1424,7 @@ namespace ts { } function getDirectories(path: string): string[] { - perfLogger.logEvent("ReadDir: " + path); - return filter(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory)); + return getAccessibleFileSystemEntries(path).directories.slice(); } function realpath(path: string): string {