Handle when output file would be in subFolder specified by outDir/declarationDir (#35366)
Fixes #35328
This commit is contained in:
parent
ea4e6b31ba
commit
25ec62f892
|
@ -1765,7 +1765,11 @@ namespace ts.server {
|
|||
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
|
||||
return forEachKey(
|
||||
this.mapOfDeclarationDirectories!,
|
||||
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
|
||||
declDirPath => dirPath === declDirPath ||
|
||||
// Any parent directory of declaration dir
|
||||
startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) ||
|
||||
// Any directory inside declaration dir
|
||||
startsWith(dirPath, `${declDirPath}/`)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1802,6 +1806,16 @@ namespace ts.server {
|
|||
return this.fileOrDirectoryExistsUsingSource(path, /*isFile*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call super.getDirectories only if directory actually present on the host
|
||||
* This is needed to ensure that we arent getting directories that we fake about presence for
|
||||
*/
|
||||
getDirectories(path: string): string[] {
|
||||
return !this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks || super.directoryExists(path) ?
|
||||
super.getDirectories(path) :
|
||||
[];
|
||||
}
|
||||
|
||||
private realpathIfSymlinkedProjectReferenceDts(s: string): string | undefined {
|
||||
return this.symlinkedFiles && this.symlinkedFiles.get(this.toPath(s));
|
||||
}
|
||||
|
@ -1820,7 +1834,7 @@ namespace ts.server {
|
|||
const directoryPath = ensureTrailingDirectorySeparator(this.toPath(directory));
|
||||
if (this.symlinkedDirectories.has(directoryPath)) return;
|
||||
|
||||
const real = this.projectService.host.realpath!(directory);
|
||||
const real = normalizePath(this.projectService.host.realpath!(directory));
|
||||
let realPath: Path;
|
||||
if (real === directory ||
|
||||
(realPath = ensureTrailingDirectorySeparator(this.toPath(real))) === directoryPath) {
|
||||
|
|
|
@ -1375,78 +1375,70 @@ function foo() {
|
|||
});
|
||||
|
||||
describe("when references are monorepo like with symlinks", () => {
|
||||
function verifySession(alreadyBuilt: boolean, extraOptions: CompilerOptions) {
|
||||
const bPackageJson: File = {
|
||||
path: `${projectRoot}/packages/B/package.json`,
|
||||
content: JSON.stringify({
|
||||
main: "lib/index.js",
|
||||
types: "lib/index.d.ts"
|
||||
})
|
||||
};
|
||||
interface Packages {
|
||||
bPackageJson: File;
|
||||
aTest: File;
|
||||
bFoo: File;
|
||||
bBar: File;
|
||||
}
|
||||
function verifySymlinkScenario(packages: () => Packages) {
|
||||
describe("when solution is not built", () => {
|
||||
it("with preserveSymlinks turned off", () => {
|
||||
verifySession(packages(), /*alreadyBuilt*/ false, {});
|
||||
});
|
||||
|
||||
it("with preserveSymlinks turned on", () => {
|
||||
verifySession(packages(), /*alreadyBuilt*/ false, { preserveSymlinks: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("when solution is already built", () => {
|
||||
it("with preserveSymlinks turned off", () => {
|
||||
verifySession(packages(), /*alreadyBuilt*/ true, {});
|
||||
});
|
||||
|
||||
it("with preserveSymlinks turned on", () => {
|
||||
verifySession(packages(), /*alreadyBuilt*/ true, { preserveSymlinks: true });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function verifySession({ bPackageJson, aTest, bFoo, bBar }: Packages, alreadyBuilt: boolean, extraOptions: CompilerOptions) {
|
||||
const aConfig = config("A", extraOptions, ["../B"]);
|
||||
const bConfig = config("B", extraOptions);
|
||||
const aIndex = index("A", `import { foo } from 'b';
|
||||
import { bar } from 'b/lib/bar';
|
||||
foo();
|
||||
bar();`);
|
||||
const bIndex = index("B", `export function foo() { }`);
|
||||
const bBar: File = {
|
||||
path: `${projectRoot}/packages/B/src/bar.ts`,
|
||||
content: `export function bar() { }`
|
||||
};
|
||||
const bSymlink: SymLink = {
|
||||
path: `${projectRoot}/node_modules/b`,
|
||||
symLink: `${projectRoot}/packages/B`
|
||||
};
|
||||
|
||||
const files = [libFile, bPackageJson, aConfig, bConfig, aIndex, bIndex, bBar, bSymlink];
|
||||
const files = [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink];
|
||||
const host = alreadyBuilt ?
|
||||
createHost(files, [aConfig.path]) :
|
||||
createServerHost(files);
|
||||
|
||||
// Create symlink in node module
|
||||
const session = createSession(host, { canUseEvents: true });
|
||||
openFilesForSession([aIndex], session);
|
||||
openFilesForSession([aTest], session);
|
||||
const service = session.getProjectService();
|
||||
const project = service.configuredProjects.get(aConfig.path.toLowerCase())!;
|
||||
assert.deepEqual(project.getAllProjectErrors(), []);
|
||||
checkProjectActualFiles(
|
||||
project,
|
||||
[aConfig.path, aIndex.path, bIndex.path, bBar.path, libFile.path]
|
||||
[aConfig.path, aTest.path, bFoo.path, bBar.path, libFile.path]
|
||||
);
|
||||
verifyGetErrRequest({
|
||||
host,
|
||||
session,
|
||||
expected: [
|
||||
{ file: aIndex, syntax: [], semantic: [], suggestion: [] }
|
||||
{ file: aTest, syntax: [], semantic: [], suggestion: [] }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function verifySymlinkScenario(alreadyBuilt: boolean) {
|
||||
it("with preserveSymlinks turned off", () => {
|
||||
verifySession(alreadyBuilt, {});
|
||||
});
|
||||
|
||||
it("with preserveSymlinks turned on", () => {
|
||||
verifySession(alreadyBuilt, { preserveSymlinks: true });
|
||||
});
|
||||
}
|
||||
|
||||
describe("when solution is not built", () => {
|
||||
verifySymlinkScenario(/*alreadyBuilt*/ false);
|
||||
});
|
||||
|
||||
describe("when solution is already built", () => {
|
||||
verifySymlinkScenario(/*alreadyBuilt*/ true);
|
||||
});
|
||||
|
||||
function config(packageName: string, extraOptions: CompilerOptions, references?: string[]): File {
|
||||
return {
|
||||
path: `${projectRoot}/packages/${packageName}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
baseUrl: ".",
|
||||
outDir: "lib",
|
||||
rootDir: "src",
|
||||
composite: true,
|
||||
|
@ -1458,12 +1450,45 @@ bar();`);
|
|||
};
|
||||
}
|
||||
|
||||
function index(packageName: string, content: string): File {
|
||||
function file(packageName: string, fileName: string, content: string): File {
|
||||
return {
|
||||
path: `${projectRoot}/packages/${packageName}/src/index.ts`,
|
||||
path: `${projectRoot}/packages/${packageName}/src/${fileName}`,
|
||||
content
|
||||
};
|
||||
}
|
||||
|
||||
describe("when packageJson has types field and has index.ts", () => {
|
||||
verifySymlinkScenario(() => ({
|
||||
bPackageJson: {
|
||||
path: `${projectRoot}/packages/B/package.json`,
|
||||
content: JSON.stringify({
|
||||
main: "lib/index.js",
|
||||
types: "lib/index.d.ts"
|
||||
})
|
||||
},
|
||||
aTest: file("A", "index.ts", `import { foo } from 'b';
|
||||
import { bar } from 'b/lib/bar';
|
||||
foo();
|
||||
bar();`),
|
||||
bFoo: file("B", "index.ts", `export function foo() { }`),
|
||||
bBar: file("B", "bar.ts", `export function bar() { }`)
|
||||
}));
|
||||
});
|
||||
|
||||
describe("when referencing file from subFolder", () => {
|
||||
verifySymlinkScenario(() => ({
|
||||
bPackageJson: {
|
||||
path: `${projectRoot}/packages/B/package.json`,
|
||||
content: "{}"
|
||||
},
|
||||
aTest: file("A", "test.ts", `import { foo } from 'b/lib/foo';
|
||||
import { bar } from 'b/lib/bar/foo';
|
||||
foo();
|
||||
bar();`),
|
||||
bFoo: file("B", "foo.ts", `export function foo() { }`),
|
||||
bBar: file("B", "bar/foo.ts", `export function bar() { }`)
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8707,6 +8707,11 @@ declare namespace ts.server {
|
|||
* If it is it returns true irrespective of whether that directory exists on host
|
||||
*/
|
||||
directoryExists(path: string): boolean;
|
||||
/**
|
||||
* Call super.getDirectories only if directory actually present on the host
|
||||
* This is needed to ensure that we arent getting directories that we fake about presence for
|
||||
*/
|
||||
getDirectories(path: string): string[];
|
||||
private realpathIfSymlinkedProjectReferenceDts;
|
||||
private getRealpath;
|
||||
private handleDirectoryCouldBeSymlink;
|
||||
|
|
Loading…
Reference in a new issue