Skip to content

Commit 4ec809d

Browse files
authored
Fix issue with trailing directory separator not present if symlink wasnt detected by program (#55865)
1 parent d7b4cee commit 4ec809d

File tree

6 files changed

+2242
-10
lines changed

6 files changed

+2242
-10
lines changed

src/compiler/utilities.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8802,9 +8802,15 @@ export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
88028802

88038803
/** @internal */
88048804
export interface SymlinkedDirectory {
8805-
/** Matches the casing returned by `realpath`. Used to compute the `realpath` of children. */
8805+
/**
8806+
* Matches the casing returned by `realpath`. Used to compute the `realpath` of children.
8807+
* Always has trailing directory separator
8808+
*/
88068809
real: string;
8807-
/** toPath(real). Stored to avoid repeated recomputation. */
8810+
/**
8811+
* toPath(real). Stored to avoid repeated recomputation.
8812+
* Always has trailing directory separator
8813+
*/
88088814
realPath: Path;
88098815
}
88108816

@@ -8859,7 +8865,7 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic
88598865
if (!containsIgnoredPath(symlinkPath)) {
88608866
symlinkPath = ensureTrailingDirectorySeparator(symlinkPath);
88618867
if (real !== false && !symlinkedDirectories?.has(symlinkPath)) {
8862-
(symlinkedDirectoriesByRealpath ||= createMultiMap()).add(ensureTrailingDirectorySeparator(real.realPath), symlink);
8868+
(symlinkedDirectoriesByRealpath ||= createMultiMap()).add(real.realPath, symlink);
88638869
}
88648870
(symlinkedDirectories || (symlinkedDirectories = new Map())).set(symlinkPath, real);
88658871
}
@@ -8882,7 +8888,10 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic
88828888
if (commonResolved && commonOriginal) {
88838889
cache.setSymlinkedDirectory(
88848890
commonOriginal,
8885-
{ real: commonResolved, realPath: toPath(commonResolved, cwd, getCanonicalFileName) },
8891+
{
8892+
real: ensureTrailingDirectorySeparator(commonResolved),
8893+
realPath: ensureTrailingDirectorySeparator(toPath(commonResolved, cwd, getCanonicalFileName)),
8894+
},
88868895
);
88878896
}
88888897
}

src/server/project.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
DirectoryWatcherCallback,
3131
DocumentPositionMapper,
3232
DocumentRegistry,
33+
ensureTrailingDirectorySeparator,
3334
enumerateInsertsAndDeletes,
3435
every,
3536
explainFiles,
@@ -2520,8 +2521,8 @@ export class AutoImportProviderProject extends Project {
25202521
const isSymlink = realPath && realPath !== hostProject.toPath(packageJson.packageDirectory);
25212522
if (isSymlink) {
25222523
symlinkCache.setSymlinkedDirectory(packageJson.packageDirectory, {
2523-
real: real!,
2524-
realPath,
2524+
real: ensureTrailingDirectorySeparator(real!),
2525+
realPath: ensureTrailingDirectorySeparator(realPath),
25252526
});
25262527
}
25272528

src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export interface SymLink {
109109

110110
export type FileOrFolderOrSymLink = File | Folder | SymLink;
111111
export interface FileOrFolderOrSymLinkMap {
112-
[path: string]: string | Omit<FileOrFolderOrSymLink, "path">;
112+
[path: string]: string | Omit<File, "path"> | Omit<SymLink, "path"> | undefined;
113113
}
114114
export function isFile(fileOrFolderOrSymLink: FileOrFolderOrSymLink): fileOrFolderOrSymLink is File {
115115
return isString((fileOrFolderOrSymLink as File).content);

src/testRunner/unittests/tsserver/moduleResolution.ts

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
1-
import * as Utils from "../../_namespaces/Utils";
1+
import * as ts from "../../_namespaces/ts";
2+
import {
3+
dedent,
4+
} from "../../_namespaces/Utils";
5+
import {
6+
libContent,
7+
} from "../helpers/contents";
28
import {
39
getFsConentsForNode10ResultAtTypesPackageJson,
410
getFsContentsForNode10Result,
511
getFsContentsForNode10ResultDts,
612
getFsContentsForNode10ResultPackageJson,
713
} from "../helpers/node10Result";
14+
import {
15+
solutionBuildWithBaseline,
16+
} from "../helpers/solutionBuilder";
817
import {
918
baselineTsserverLogs,
1019
createLoggerWithInMemoryLogs,
1120
createSession,
1221
openFilesForSession,
22+
protocolTextSpanFromSubstring,
1323
verifyGetErrRequest,
1424
} from "../helpers/tsserver";
1525
import {
@@ -38,14 +48,14 @@ describe("unittests:: tsserver:: moduleResolution", () => {
3848
};
3949
const fileA: File = {
4050
path: `/user/username/projects/myproject/src/fileA.ts`,
41-
content: Utils.dedent`
51+
content: dedent`
4252
import { foo } from "./fileB.mjs";
4353
foo();
4454
`,
4555
};
4656
const fileB: File = {
4757
path: `/user/username/projects/myproject/src/fileB.mts`,
48-
content: Utils.dedent`
58+
content: dedent`
4959
export function foo() {
5060
}
5161
`,
@@ -195,4 +205,116 @@ describe("unittests:: tsserver:: moduleResolution", () => {
195205
});
196206
}
197207
});
208+
209+
describe("using referenced project", () => {
210+
it("not built", () => {
211+
verify();
212+
});
213+
it("built", () => {
214+
verify(/*built*/ true);
215+
});
216+
function verify(built?: boolean) {
217+
const indexContent = dedent`
218+
import { FOO } from "package-a";
219+
console.log(FOO);
220+
`;
221+
const host = createServerHost({
222+
"/home/src/projects/project/packages/package-a/package.json": getPackageJson("package-a"),
223+
"/home/src/projects/project/packages/package-a/tsconfig.json": getTsConfig(),
224+
"/home/src/projects/project/packages/package-a/src/index.ts": `export * from "./subfolder";`,
225+
"/home/src/projects/project/packages/package-a/src/subfolder/index.ts": `export const FOO = "bar";`,
226+
"/home/src/projects/project/packages/package-b/package.json": getPackageJson("package-b"),
227+
"/home/src/projects/project/packages/package-b/tsconfig.json": getTsConfig([{ path: "../package-a" }]),
228+
"/home/src/projects/project/packages/package-b/src/index.ts": indexContent,
229+
"/home/src/projects/project/node_modules/package-a": { symLink: "/home/src/projects/project/packages/package-a" },
230+
"/home/src/projects/project/node_modules/package-b": { symLink: "/home/src/projects/project/packages/package-b" },
231+
"/a/lib/lib.es2021.d.ts": libContent,
232+
}, { currentDirectory: "/home/src/projects/project" });
233+
if (built) {
234+
solutionBuildWithBaseline(host, ["packages/package-b"]);
235+
host.clearOutput();
236+
}
237+
const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host), canUseEvents: true });
238+
openFilesForSession(["/home/src/projects/project/packages/package-b/src/index.ts"], session);
239+
verifyGetErrRequest({
240+
session,
241+
files: ["/home/src/projects/project/packages/package-b/src/index.ts"],
242+
});
243+
const { end } = protocolTextSpanFromSubstring(indexContent, "package-a");
244+
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
245+
command: ts.server.protocol.CommandTypes.UpdateOpen,
246+
arguments: {
247+
changedFiles: [{
248+
fileName: "/home/src/projects/project/packages/package-b/src/index.ts",
249+
textChanges: [{
250+
start: end,
251+
end,
252+
newText: "X",
253+
}],
254+
}],
255+
},
256+
});
257+
verifyGetErrRequest({
258+
session,
259+
files: ["/home/src/projects/project/packages/package-b/src/index.ts"],
260+
});
261+
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
262+
command: ts.server.protocol.CommandTypes.UpdateOpen,
263+
arguments: {
264+
changedFiles: [{
265+
fileName: "/home/src/projects/project/packages/package-b/src/index.ts",
266+
textChanges: [{
267+
start: end,
268+
end: { ...end, offset: end.offset + 1 },
269+
newText: "",
270+
}],
271+
}],
272+
},
273+
});
274+
verifyGetErrRequest({
275+
session,
276+
files: ["/home/src/projects/project/packages/package-b/src/index.ts"],
277+
});
278+
baselineTsserverLogs("moduleResolution", `using referenced project${built ? " built" : ""}`, session);
279+
}
280+
function getPackageJson(packageName: string) {
281+
return JSON.stringify(
282+
{
283+
name: packageName,
284+
version: "1.0.0",
285+
type: "module",
286+
main: "build/index.js",
287+
exports: {
288+
".": "./build/index.js",
289+
"./package.json": "./package.json",
290+
"./*": ["./build/*/index.js", "./build/*.js"],
291+
},
292+
},
293+
undefined,
294+
" ",
295+
);
296+
}
297+
298+
function getTsConfig(references?: object[]) {
299+
return JSON.stringify({
300+
compilerOptions: {
301+
allowSyntheticDefaultImports: true,
302+
baseUrl: "./",
303+
composite: true,
304+
declarationMap: true,
305+
esModuleInterop: true,
306+
lib: ["es2021"],
307+
module: "esnext",
308+
moduleResolution: "bundler",
309+
outDir: "build",
310+
rootDir: "./src",
311+
target: "ES2021",
312+
traceResolution: true,
313+
tsBuildInfoFile: "./build/tsconfig.tsbuildinfo",
314+
},
315+
include: ["./src/**/*.ts"],
316+
references,
317+
});
318+
}
319+
});
198320
});

0 commit comments

Comments
 (0)