mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-05 00:32:41 -05:00
Merge pull request #19118 from Microsoft/caseSensitivityInferredProjectRoot
Handles case sensitivity of project root with respect to inferred projects
This commit is contained in:
@@ -281,11 +281,11 @@ namespace ts.projectSystem {
|
||||
checkNumberOfProjects(this, count);
|
||||
}
|
||||
}
|
||||
export function createProjectService(host: server.ServerHost, parameters: CreateProjectServiceParameters = {}) {
|
||||
export function createProjectService(host: server.ServerHost, parameters: CreateProjectServiceParameters = {}, options?: Partial<server.ProjectServiceOptions>) {
|
||||
const cancellationToken = parameters.cancellationToken || server.nullCancellationToken;
|
||||
const logger = parameters.logger || nullLogger;
|
||||
const useSingleInferredProject = parameters.useSingleInferredProject !== undefined ? parameters.useSingleInferredProject : false;
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller, parameters.eventHandler);
|
||||
return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller, parameters.eventHandler, options);
|
||||
}
|
||||
|
||||
export function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
||||
@@ -3784,6 +3784,113 @@ namespace ts.projectSystem {
|
||||
assert.equal(projectService.inferredProjects[1].getCompilationSettings().target, ScriptTarget.ESNext);
|
||||
assert.equal(projectService.inferredProjects[2].getCompilationSettings().target, ScriptTarget.ES2015);
|
||||
});
|
||||
|
||||
function checkInferredProject(inferredProject: server.InferredProject, actualFiles: FileOrFolder[], target: ScriptTarget) {
|
||||
checkProjectActualFiles(inferredProject, actualFiles.map(f => f.path));
|
||||
assert.equal(inferredProject.getCompilationSettings().target, target);
|
||||
}
|
||||
|
||||
function verifyProjectRootWithCaseSensitivity(useCaseSensitiveFileNames: boolean) {
|
||||
const files: [FileOrFolder, FileOrFolder, FileOrFolder, FileOrFolder] = [
|
||||
{ path: "/a/file1.ts", content: "let x = 1;" },
|
||||
{ path: "/A/file2.ts", content: "let y = 2;" },
|
||||
{ path: "/b/file2.ts", content: "let x = 3;" },
|
||||
{ path: "/c/file3.ts", content: "let z = 4;" }
|
||||
];
|
||||
const host = createServerHost(files, { useCaseSensitiveFileNames });
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, }, { useInferredProjectPerProjectRoot: true });
|
||||
projectService.setCompilerOptionsForInferredProjects({
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ESNext
|
||||
});
|
||||
projectService.setCompilerOptionsForInferredProjects({
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ES2015
|
||||
}, "/a");
|
||||
|
||||
openClientFiles(["/a", "/a", "/b", undefined]);
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0], files[1]], ScriptTarget.ES2015],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
closeClientFiles();
|
||||
|
||||
openClientFiles(["/a", "/A", "/b", undefined]);
|
||||
if (useCaseSensitiveFileNames) {
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0]], ScriptTarget.ES2015],
|
||||
[[files[1]], ScriptTarget.ESNext],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
}
|
||||
else {
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0], files[1]], ScriptTarget.ES2015],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
}
|
||||
closeClientFiles();
|
||||
|
||||
projectService.setCompilerOptionsForInferredProjects({
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ES2017
|
||||
}, "/A");
|
||||
|
||||
openClientFiles(["/a", "/a", "/b", undefined]);
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0], files[1]], useCaseSensitiveFileNames ? ScriptTarget.ES2015 : ScriptTarget.ES2017],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
closeClientFiles();
|
||||
|
||||
openClientFiles(["/a", "/A", "/b", undefined]);
|
||||
if (useCaseSensitiveFileNames) {
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0]], ScriptTarget.ES2015],
|
||||
[[files[1]], ScriptTarget.ES2017],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
}
|
||||
else {
|
||||
verifyInferredProjectsState([
|
||||
[[files[3]], ScriptTarget.ESNext],
|
||||
[[files[0], files[1]], ScriptTarget.ES2017],
|
||||
[[files[2]], ScriptTarget.ESNext]
|
||||
]);
|
||||
}
|
||||
closeClientFiles();
|
||||
|
||||
function openClientFiles(projectRoots: [string | undefined, string | undefined, string | undefined, string | undefined]) {
|
||||
files.forEach((file, index) => {
|
||||
projectService.openClientFile(file.path, file.content, ScriptKind.JS, projectRoots[index]);
|
||||
});
|
||||
}
|
||||
|
||||
function closeClientFiles() {
|
||||
files.forEach(file => projectService.closeClientFile(file.path));
|
||||
}
|
||||
|
||||
function verifyInferredProjectsState(expected: [FileOrFolder[], ScriptTarget][]) {
|
||||
checkNumberOfProjects(projectService, { inferredProjects: expected.length });
|
||||
projectService.inferredProjects.forEach((p, index) => {
|
||||
const [actualFiles, target] = expected[index];
|
||||
checkInferredProject(p, actualFiles, target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
it("inferred projects per project root with case sensitive system", () => {
|
||||
verifyProjectRootWithCaseSensitivity(/*useCaseSensitiveFileNames*/ true);
|
||||
});
|
||||
|
||||
it("inferred projects per project root with case insensitive system", () => {
|
||||
verifyProjectRootWithCaseSensitivity(/*useCaseSensitiveFileNames*/ false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("No overwrite emit error", () => {
|
||||
|
||||
@@ -590,9 +590,9 @@ namespace ts.server {
|
||||
// always set 'allowNonTsExtensions' for inferred projects since user cannot configure it from the outside
|
||||
// previously we did not expose a way for user to change these settings and this option was enabled by default
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
|
||||
if (projectRootPath) {
|
||||
this.compilerOptionsForInferredProjectsPerProjectRoot.set(projectRootPath, compilerOptions);
|
||||
const canonicalProjectRootPath = projectRootPath && this.toCanonicalFileName(projectRootPath);
|
||||
if (canonicalProjectRootPath) {
|
||||
this.compilerOptionsForInferredProjectsPerProjectRoot.set(canonicalProjectRootPath, compilerOptions);
|
||||
}
|
||||
else {
|
||||
this.compilerOptionsForInferredProjects = compilerOptions;
|
||||
@@ -608,9 +608,9 @@ namespace ts.server {
|
||||
// root path
|
||||
// - Inferred projects with a projectRootPath, if the new options apply to that
|
||||
// project root path.
|
||||
if (projectRootPath ?
|
||||
project.projectRootPath === projectRootPath :
|
||||
!project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath)) {
|
||||
if (canonicalProjectRootPath ?
|
||||
project.projectRootPath === canonicalProjectRootPath :
|
||||
!project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath)) {
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
project.compileOnSaveEnabled = compilerOptions.compileOnSave;
|
||||
project.markAsDirty();
|
||||
@@ -1599,9 +1599,10 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
if (projectRootPath) {
|
||||
const canonicalProjectRootPath = this.toCanonicalFileName(projectRootPath);
|
||||
// if we have an explicit project root path, find (or create) the matching inferred project.
|
||||
for (const project of this.inferredProjects) {
|
||||
if (project.projectRootPath === projectRootPath) {
|
||||
if (project.projectRootPath === canonicalProjectRootPath) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,12 +1047,15 @@ namespace ts.server {
|
||||
super.setCompilerOptions(newOptions);
|
||||
}
|
||||
|
||||
/** this is canonical project root path */
|
||||
readonly projectRootPath: string | undefined;
|
||||
|
||||
/*@internal*/
|
||||
constructor(
|
||||
projectService: ProjectService,
|
||||
documentRegistry: DocumentRegistry,
|
||||
compilerOptions: CompilerOptions,
|
||||
readonly projectRootPath: string | undefined,
|
||||
projectRootPath: string | undefined,
|
||||
currentDirectory: string | undefined) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
@@ -1064,6 +1067,7 @@ namespace ts.server {
|
||||
/*compileOnSaveEnabled*/ false,
|
||||
projectService.host,
|
||||
currentDirectory);
|
||||
this.projectRootPath = projectRootPath && projectService.toCanonicalFileName(projectRootPath);
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
|
||||
@@ -7188,11 +7188,12 @@ declare namespace ts.server {
|
||||
* the file and its imports/references are put into an InferredProject.
|
||||
*/
|
||||
class InferredProject extends Project {
|
||||
readonly projectRootPath: string | undefined;
|
||||
private static readonly newName;
|
||||
private _isJsInferredProject;
|
||||
toggleJsInferredProject(isJsInferredProject: boolean): void;
|
||||
setCompilerOptions(options?: CompilerOptions): void;
|
||||
/** this is canonical project root path */
|
||||
readonly projectRootPath: string | undefined;
|
||||
addRoot(info: ScriptInfo): void;
|
||||
removeRoot(info: ScriptInfo): void;
|
||||
isProjectWithSingleRoot(): boolean;
|
||||
|
||||
Reference in New Issue
Block a user