From 45070c4b4054786ffba4f458c1959ceb41c9df08 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 13 Dec 2024 00:53:42 +0000 Subject: [PATCH 01/11] Avoid allocation for normalized absolute paths. --- src/compiler/path.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index b05216adc47b5..85705667c55f3 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -625,7 +625,41 @@ export function getNormalizedPathComponents(path: string, currentDirectory: stri /** @internal */ export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string | undefined): string { + if (isNotNormalizedOrAbsolute(fileName)) { return getPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); + } + + return fileName; +} + +function isNotNormalizedOrAbsolute(s: string) { + // The path is not absolute. + if (getEncodedRootLength(s) === 0) return true; + + if (s.length > 0) { + const lastChar = s.charCodeAt(s.length - 1); + if (lastChar === CharacterCodes.slash || lastChar === CharacterCodes.backslash) return true; + } + + for (let i = 0, n = s.length - 1; i < n; i++) { + const curr = s.charCodeAt(i); + const next = s.charCodeAt(i + 1); + if (curr === CharacterCodes.dot) { + if (next === CharacterCodes.slash) { + return true; + } + } + else if (curr === CharacterCodes.slash) { + if (next === CharacterCodes.slash) { + return true; + } + } + else if (curr === CharacterCodes.backslash) { + return true; + } + } + + return false; } /** @internal */ From 209073e0f1066b4dbccaf2d729ab951fe72f4e50 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 13 Dec 2024 18:50:29 +0000 Subject: [PATCH 02/11] Indent. --- src/compiler/path.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 85705667c55f3..17b8d26520112 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -626,7 +626,7 @@ export function getNormalizedPathComponents(path: string, currentDirectory: stri /** @internal */ export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string | undefined): string { if (isNotNormalizedOrAbsolute(fileName)) { - return getPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); + return getPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); } return fileName; From baaa8508af35f4c233b078bb74b16067e6c467ec Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 17 Dec 2024 22:37:46 +0000 Subject: [PATCH 03/11] Comment implementation. --- src/compiler/path.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 17b8d26520112..dc54f368b91f8 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -636,6 +636,7 @@ function isNotNormalizedOrAbsolute(s: string) { // The path is not absolute. if (getEncodedRootLength(s) === 0) return true; + // Apart from the root segment, paths should not have a trailing slash. if (s.length > 0) { const lastChar = s.charCodeAt(s.length - 1); if (lastChar === CharacterCodes.slash || lastChar === CharacterCodes.backslash) return true; @@ -645,16 +646,22 @@ function isNotNormalizedOrAbsolute(s: string) { const curr = s.charCodeAt(i); const next = s.charCodeAt(i + 1); if (curr === CharacterCodes.dot) { + // A ./ or ../ must be reduced - not normalized. if (next === CharacterCodes.slash) { return true; } } else if (curr === CharacterCodes.slash) { + // Multiple slashes in a row (outside of the root, + // and there is no root) must be reduced to a single slash. + // So the path is not normalized. if (next === CharacterCodes.slash) { return true; } } else if (curr === CharacterCodes.backslash) { + // A backslash anywhere must be normalized to + // a regular slash. return true; } } From 3a27437d2eed8151f94315ff84598f6a43412107 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 17 Dec 2024 22:42:30 +0000 Subject: [PATCH 04/11] Only fetch the next character when necessary. --- src/compiler/path.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index dc54f368b91f8..48541c155426a 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -644,10 +644,9 @@ function isNotNormalizedOrAbsolute(s: string) { for (let i = 0, n = s.length - 1; i < n; i++) { const curr = s.charCodeAt(i); - const next = s.charCodeAt(i + 1); if (curr === CharacterCodes.dot) { // A ./ or ../ must be reduced - not normalized. - if (next === CharacterCodes.slash) { + if (s.charCodeAt(i + 1) === CharacterCodes.slash) { return true; } } @@ -655,7 +654,7 @@ function isNotNormalizedOrAbsolute(s: string) { // Multiple slashes in a row (outside of the root, // and there is no root) must be reduced to a single slash. // So the path is not normalized. - if (next === CharacterCodes.slash) { + if (s.charCodeAt(i + 1) === CharacterCodes.slash) { return true; } } From a117f5adffc7bd0a082e305402a134201816a64e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 17 Dec 2024 22:45:43 +0000 Subject: [PATCH 05/11] Style. --- src/compiler/path.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 48541c155426a..3859d634924c8 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -634,12 +634,16 @@ export function getNormalizedAbsolutePath(fileName: string, currentDirectory: st function isNotNormalizedOrAbsolute(s: string) { // The path is not absolute. - if (getEncodedRootLength(s) === 0) return true; + if (getEncodedRootLength(s) === 0) { + return true; + } // Apart from the root segment, paths should not have a trailing slash. if (s.length > 0) { const lastChar = s.charCodeAt(s.length - 1); - if (lastChar === CharacterCodes.slash || lastChar === CharacterCodes.backslash) return true; + if (lastChar === CharacterCodes.slash || lastChar === CharacterCodes.backslash) { + return true; + } } for (let i = 0, n = s.length - 1; i < n; i++) { @@ -659,8 +663,7 @@ function isNotNormalizedOrAbsolute(s: string) { } } else if (curr === CharacterCodes.backslash) { - // A backslash anywhere must be normalized to - // a regular slash. + // A backslash anywhere must be normalized to a regular slash. return true; } } From f7da1e6561449b4325a45ff426e568c877567efc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 00:02:52 +0000 Subject: [PATCH 06/11] Add tests for `getNormalizedAbsolutePath`. --- src/testRunner/unittests/paths.ts | 104 ++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/testRunner/unittests/paths.ts b/src/testRunner/unittests/paths.ts index 56a49f57f392a..9d503eba8a603 100644 --- a/src/testRunner/unittests/paths.ts +++ b/src/testRunner/unittests/paths.ts @@ -269,6 +269,110 @@ describe("unittests:: core paths", () => { assert.strictEqual(ts.resolvePath("a", "b", "/c"), "/c"); assert.strictEqual(ts.resolvePath("a", "b", "../c"), "a/c"); }); + it("getNormalizedAbsolutePath", () => { + assert.strictEqual(ts.getNormalizedAbsolutePath("/", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/.", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/./", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/../", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a", ""), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/", ""), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/.", ""), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/foo.", ""), "/a/foo."); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/./", ""), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/./b", ""), "/a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/./b/", ""), "/a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/../", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/../", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/../b", ""), "/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/../b/", ""), "/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", "/"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", "b/"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", "/b"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/.", "b"), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/.", "."), "/a"); + + // Tests as above, but with backslashes. + assert.strictEqual(ts.getNormalizedAbsolutePath("\\", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\.", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\.\\", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\..\\", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\.\\", ""), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\.\\b", ""), "/a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\.\\b\\", ""), "/a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..\\", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..\\", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..\\b", ""), "/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..\\b\\", ""), "/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..", ""), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..", "\\"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..", "b\\"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\..", "\\b"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\.", "b"), "/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\.", "."), "/a"); + + // Relative paths on an empty currentDirectory. + assert.strictEqual(ts.getNormalizedAbsolutePath("", ""), ""); + assert.strictEqual(ts.getNormalizedAbsolutePath(".", ""), ""); + assert.strictEqual(ts.getNormalizedAbsolutePath("./", ""), ""); + // Strangely, these do not normalize to the empty string. + assert.strictEqual(ts.getNormalizedAbsolutePath("..", ""), ".."); + assert.strictEqual(ts.getNormalizedAbsolutePath("../", ""), ".."); + + // Interaction between relative paths and currentDirectory. + assert.strictEqual(ts.getNormalizedAbsolutePath("", "/home"), "/home"); + assert.strictEqual(ts.getNormalizedAbsolutePath(".", "/home"), "/home"); + assert.strictEqual(ts.getNormalizedAbsolutePath("./", "/home"), "/home"); + assert.strictEqual(ts.getNormalizedAbsolutePath("..", "/home"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("../", "/home"), "/"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a", "b"), "b/a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a", "b/c"), "b/c/a"); + + // Base names starting or ending with a dot do not affect normalization. + assert.strictEqual(ts.getNormalizedAbsolutePath(".a", ""), ".a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("..a", ""), "..a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a.", ""), "a."); + assert.strictEqual(ts.getNormalizedAbsolutePath("a..", ""), "a.."); + + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./.a", ""), "/base/.a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../.a", ""), "/.a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./..a", ""), "/base/..a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../..a", ""), "/..a"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./..a/b", ""), "/base/..a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../..a/b", ""), "/..a/b"); + + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./a.", ""), "/base/a."); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../a.", ""), "/a."); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./a..", ""), "/base/a.."); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../a..", ""), "/a.."); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/./a../b", ""), "/base/a../b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/base/../a../b", ""), "/a../b"); + + // Consecutive intermediate slashes are normalized to a single slash. + assert.strictEqual(ts.getNormalizedAbsolutePath("a//b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a///b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a/b//c", ""), "a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("/a/b//c", ""), "/a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("//a/b//c", ""), "//a/b/c"); + + // Backslashes are converted to slashes, + // and then consecutive intermediate slashes are normalized to a single slash + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\\\b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\\\\\b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\b\\\\c", ""), "a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\b\\\\c", ""), "/a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\\\a\\b\\\\c", ""), "//a/b/c"); + + // The same occurs for mixed slashes. + assert.strictEqual(ts.getNormalizedAbsolutePath("a/\\b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\/b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\/\\b", ""), "a/b"); + assert.strictEqual(ts.getNormalizedAbsolutePath("a\\b//c", ""), "a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\a\\b\\\\c", ""), "/a/b/c"); + assert.strictEqual(ts.getNormalizedAbsolutePath("\\\\a\\b\\\\c", ""), "//a/b/c"); + }); it("getPathRelativeTo", () => { assert.strictEqual(ts.getRelativePathFromDirectory("/", "/", /*ignoreCase*/ false), ""); assert.strictEqual(ts.getRelativePathFromDirectory("/a", "/a", /*ignoreCase*/ false), ""); From 4ff74c9fc3ec1c029d5bb1d6a3f3a44a4e1dc2f9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 00:09:54 +0000 Subject: [PATCH 07/11] Work on points for style. --- src/testRunner/unittests/paths.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testRunner/unittests/paths.ts b/src/testRunner/unittests/paths.ts index 9d503eba8a603..e76bdc7cd26de 100644 --- a/src/testRunner/unittests/paths.ts +++ b/src/testRunner/unittests/paths.ts @@ -292,7 +292,7 @@ describe("unittests:: core paths", () => { assert.strictEqual(ts.getNormalizedAbsolutePath("/a/..", "/b"), "/"); assert.strictEqual(ts.getNormalizedAbsolutePath("/a/.", "b"), "/a"); assert.strictEqual(ts.getNormalizedAbsolutePath("/a/.", "."), "/a"); - + // Tests as above, but with backslashes. assert.strictEqual(ts.getNormalizedAbsolutePath("\\", ""), "/"); assert.strictEqual(ts.getNormalizedAbsolutePath("\\.", ""), "/"); From eade65acc4e674c93af363a0a73984f5c1ac0900 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 01:47:22 +0000 Subject: [PATCH 08/11] Harden against cases where `undefined` may be passed into `getNormalizedAbsolutePath`. --- src/compiler/builder.ts | 18 +++++++++++++----- src/compiler/moduleSpecifiers.ts | 4 +++- src/services/stringCompletions.ts | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 1c472cebead0d..4f7e31c567bff 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -62,6 +62,7 @@ import { isNumber, isString, map, + mapDefined, mapDefinedIterator, maybeBind, noop, @@ -1236,7 +1237,7 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo { const currentDirectory = state.program.getCurrentDirectory(); const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory)); // Convert the file name to Path here if we set the fileName instead to optimize multiple d.ts file emits and having to compute Canonical path - const latestChangedDtsFile = state.latestChangedDtsFile ? relativeToBuildInfoEnsuringAbsolutePath(state.latestChangedDtsFile) : undefined; + const latestChangedDtsFile = state.latestChangedDtsFile ? relativePathToBuildInfo(state.latestChangedDtsFile) : undefined; const fileNames: string[] = []; const fileNameToFileId = new Map(); const rootFileNames = new Set(state.program.getRootFileNames().map(f => toPath(f, currentDirectory, state.program.getCanonicalFileName))); @@ -1377,10 +1378,17 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo { }; return buildInfo; - function relativeToBuildInfoEnsuringAbsolutePath(path: string) { + function relativePathToBuildInfo(path: string) { return relativeToBuildInfo(getNormalizedAbsolutePath(path, currentDirectory)); } + function relativePathToBuildInfoOrOriginalValue(path: unknown): string | undefined { + if (typeof path === "string") { + return relativePathToBuildInfo(path); + } + return undefined; + } + function relativeToBuildInfo(path: string) { return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, state.program.getCanonicalFileName)); } @@ -1457,13 +1465,13 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo { if (option) { Debug.assert(option.type !== "listOrElement"); if (option.type === "list") { - const values = value as readonly string[]; + const values = value as readonly unknown[]; if (option.element.isFilePath && values.length) { - return values.map(relativeToBuildInfoEnsuringAbsolutePath); + return mapDefined(values, relativePathToBuildInfoOrOriginalValue); } } else if (option.isFilePath) { - return relativeToBuildInfoEnsuringAbsolutePath(value as string); + return relativePathToBuildInfoOrOriginalValue(value); } } return value; diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index eacba122e496c..459360cb917ba 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -594,7 +594,9 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt return pathsOnly ? undefined : relativePath; } - const baseDirectory = getNormalizedAbsolutePath(getPathsBasePath(compilerOptions, host) || baseUrl!, host.getCurrentDirectory()); + const currentDirectory = host.getCurrentDirectory(); + const basePath = getPathsBasePath(compilerOptions, host) ?? baseUrl ?? currentDirectory; + const baseDirectory = getNormalizedAbsolutePath(basePath, currentDirectory); const relativeToBaseUrl = getRelativePathIfInSameVolume(moduleFileName, baseDirectory, getCanonicalFileName); if (!relativeToBaseUrl) { return pathsOnly ? undefined : relativePath; diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 63cac4d49cca2..79a23383ef247 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -986,7 +986,7 @@ function getCompletionEntriesForNonRelativeModules( } if (paths) { - const absolute = getPathsBasePath(compilerOptions, host)!; + const absolute = getPathsBasePath(compilerOptions, host)!; // Always defined when 'paths' is defined addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, program, host, moduleSpecifierResolutionHost, paths); } From cc3722c199c669df53b793ef812dec1e3cac1b89 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 01:47:28 +0000 Subject: [PATCH 09/11] Accept baselines. --- ...cts-with-non-moved-json-files-and-emits-them-correctly.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-with-non-moved-json-files-and-emits-them-correctly.js b/tests/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-with-non-moved-json-files-and-emits-them-correctly.js index c4a526fefe66b..49e711e9a48ea 100644 --- a/tests/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-with-non-moved-json-files-and-emits-them-correctly.js +++ b/tests/baselines/reference/tsbuild/javascriptProjectEmit/loads-js-based-projects-with-non-moved-json-files-and-emits-them-correctly.js @@ -144,7 +144,7 @@ export = x; //// [/home/src/workspaces/solution/common/tsconfig.tsbuildinfo] -{"fileNames":["../../../tslibs/ts/lib/lib.d.ts","./obj.json","./index.ts"],"fileIdsList":[[2]],"fileInfos":[{"version":"-32082413277-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };\ninterface SymbolConstructor {\n readonly species: symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\n","affectsGlobalScope":true},"2353615672-{\n \"val\": 42\n}","-5032674136-import x = require(\"./obj.json\");\nexport = x;\n"],"root":[2,3],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"outDir":"..","rootDir":"..","skipLibCheck":true},"referencedMap":[[3,1]],"latestChangedDtsFile":"./index.d.ts","version":"FakeTSVersion"} +{"fileNames":["../../../tslibs/ts/lib/lib.d.ts","./obj.json","./index.ts"],"fileIdsList":[[2]],"fileInfos":[{"version":"-32082413277-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };\ninterface SymbolConstructor {\n readonly species: symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\n","affectsGlobalScope":true},"2353615672-{\n \"val\": 42\n}","-5032674136-import x = require(\"./obj.json\");\nexport = x;\n"],"root":[2,3],"options":{"allowJs":true,"checkJs":true,"composite":true,"declaration":true,"esModuleInterop":true,"rootDir":"..","skipLibCheck":true},"referencedMap":[[3,1]],"latestChangedDtsFile":"./index.d.ts","version":"FakeTSVersion"} //// [/home/src/workspaces/solution/common/tsconfig.tsbuildinfo.readable.baseline.txt] { @@ -193,7 +193,6 @@ export = x; "composite": true, "declaration": true, "esModuleInterop": true, - "outDir": "..", "rootDir": "..", "skipLibCheck": true }, @@ -204,7 +203,7 @@ export = x; }, "latestChangedDtsFile": "./index.d.ts", "version": "FakeTSVersion", - "size": 1148 + "size": 1134 } //// [/home/src/workspaces/out/sub-project/index.js] From 28b7cdf1ab0b9ebad8135477f068db9c00fad117 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 01:48:24 +0000 Subject: [PATCH 10/11] Use `relativePathSegmentRegExp` and other similarly used helpers instead of custom loop. --- src/compiler/path.ts | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 3859d634924c8..538dbf6276b09 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -625,6 +625,8 @@ export function getNormalizedPathComponents(path: string, currentDirectory: stri /** @internal */ export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string | undefined): string { + fileName = normalizeSlashes(fileName); + if (isNotNormalizedOrAbsolute(fileName)) { return getPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory)); } @@ -633,42 +635,18 @@ export function getNormalizedAbsolutePath(fileName: string, currentDirectory: st } function isNotNormalizedOrAbsolute(s: string) { - // The path is not absolute. if (getEncodedRootLength(s) === 0) { + // An absolute path must have a root component. return true; } - // Apart from the root segment, paths should not have a trailing slash. - if (s.length > 0) { - const lastChar = s.charCodeAt(s.length - 1); - if (lastChar === CharacterCodes.slash || lastChar === CharacterCodes.backslash) { - return true; - } - } - - for (let i = 0, n = s.length - 1; i < n; i++) { - const curr = s.charCodeAt(i); - if (curr === CharacterCodes.dot) { - // A ./ or ../ must be reduced - not normalized. - if (s.charCodeAt(i + 1) === CharacterCodes.slash) { - return true; - } - } - else if (curr === CharacterCodes.slash) { - // Multiple slashes in a row (outside of the root, - // and there is no root) must be reduced to a single slash. - // So the path is not normalized. - if (s.charCodeAt(i + 1) === CharacterCodes.slash) { - return true; - } - } - else if (curr === CharacterCodes.backslash) { - // A backslash anywhere must be normalized to a regular slash. - return true; - } + const lastChar = s.charCodeAt(s.length - 1); + if (lastChar === CharacterCodes.slash) { + // A normalized path cannot end in a trailing separator. + return true; } - - return false; + + return relativePathSegmentRegExp.test(s); } /** @internal */ From 2886cc7e13c2387eb699b09a720f61326232245d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Dec 2024 01:48:42 +0000 Subject: [PATCH 11/11] Format. --- src/compiler/path.ts | 2 +- src/services/stringCompletions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 538dbf6276b09..9e1fc17a24099 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -645,7 +645,7 @@ function isNotNormalizedOrAbsolute(s: string) { // A normalized path cannot end in a trailing separator. return true; } - + return relativePathSegmentRegExp.test(s); } diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 79a23383ef247..448f02b765717 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -986,7 +986,7 @@ function getCompletionEntriesForNonRelativeModules( } if (paths) { - const absolute = getPathsBasePath(compilerOptions, host)!; // Always defined when 'paths' is defined + const absolute = getPathsBasePath(compilerOptions, host)!; // Always defined when 'paths' is defined addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, program, host, moduleSpecifierResolutionHost, paths); }