mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Add disableReferencedProjectLoad to stop loading child projects to allow users to disable loading large solutions (#39593)
* Use disableReferencedProjectLoad to stop loading child projects to allow users to disable loading large solutions Fixes #39144 * Handle indirect references * PR feedback
This commit is contained in:
parent
5484687384
commit
e92afacc44
@ -882,6 +882,13 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Disable_solution_searching_for_this_project
|
||||
},
|
||||
{
|
||||
name: "disableReferencedProjectLoad",
|
||||
type: "boolean",
|
||||
isTSConfigOnly: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Disable_loading_referenced_projects
|
||||
},
|
||||
{
|
||||
name: "noImplicitUseStrict",
|
||||
type: "boolean",
|
||||
|
||||
@ -4469,6 +4469,10 @@
|
||||
"category": "Error",
|
||||
"code": 6234
|
||||
},
|
||||
"Disable loading referenced projects.": {
|
||||
"category": "Message",
|
||||
"code": 6235
|
||||
},
|
||||
|
||||
"Projects to reference": {
|
||||
"category": "Message",
|
||||
|
||||
@ -5671,6 +5671,7 @@ namespace ts {
|
||||
disableSizeLimit?: boolean;
|
||||
disableSourceOfProjectReferenceRedirect?: boolean;
|
||||
disableSolutionSearching?: boolean;
|
||||
disableReferencedProjectLoad?: boolean;
|
||||
downlevelIteration?: boolean;
|
||||
emitBOM?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
|
||||
@ -432,34 +432,55 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
export function forEachResolvedProjectReferenceProject<T>(
|
||||
project: ConfiguredProject,
|
||||
cb: (child: ConfiguredProject, configFileName: NormalizedPath) => T | undefined,
|
||||
projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind.Find | ProjectReferenceProjectLoadKind.FindCreate
|
||||
cb: (child: ConfiguredProject) => T | undefined,
|
||||
projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind.Find | ProjectReferenceProjectLoadKind.FindCreate,
|
||||
): T | undefined;
|
||||
/*@internal*/
|
||||
export function forEachResolvedProjectReferenceProject<T>(
|
||||
project: ConfiguredProject,
|
||||
cb: (child: ConfiguredProject, configFileName: NormalizedPath) => T | undefined,
|
||||
projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind.FindCreateLoad,
|
||||
cb: (child: ConfiguredProject) => T | undefined,
|
||||
projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind,
|
||||
reason: string
|
||||
): T | undefined;
|
||||
export function forEachResolvedProjectReferenceProject<T>(
|
||||
project: ConfiguredProject,
|
||||
cb: (child: ConfiguredProject, configFileName: NormalizedPath) => T | undefined,
|
||||
cb: (child: ConfiguredProject) => T | undefined,
|
||||
projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind,
|
||||
reason?: string
|
||||
): T | undefined {
|
||||
return forEachResolvedProjectReference(project, ref => {
|
||||
if (!ref) return undefined;
|
||||
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
|
||||
const child = project.projectService.findConfiguredProjectByProjectName(configFileName) || (
|
||||
projectReferenceProjectLoadKind === ProjectReferenceProjectLoadKind.FindCreate ?
|
||||
project.projectService.createConfiguredProject(configFileName) :
|
||||
projectReferenceProjectLoadKind === ProjectReferenceProjectLoadKind.FindCreateLoad ?
|
||||
project.projectService.createAndLoadConfiguredProject(configFileName, reason!) :
|
||||
undefined
|
||||
);
|
||||
return child && cb(child, configFileName);
|
||||
});
|
||||
let seenResolvedRefs: ESMap<string, ProjectReferenceProjectLoadKind> | undefined;
|
||||
return worker(project.getCurrentProgram()?.getResolvedProjectReferences(), project.getCompilerOptions());
|
||||
|
||||
function worker(resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, parentOptions: CompilerOptions): T | undefined {
|
||||
const loadKind = parentOptions.disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find : projectReferenceProjectLoadKind;
|
||||
return forEach(resolvedProjectReferences, ref => {
|
||||
if (!ref) return undefined;
|
||||
|
||||
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
|
||||
const canonicalPath = project.projectService.toCanonicalFileName(configFileName);
|
||||
const seenValue = seenResolvedRefs?.get(canonicalPath);
|
||||
if (seenValue !== undefined && seenValue >= loadKind) {
|
||||
return undefined;
|
||||
}
|
||||
const child = project.projectService.findConfiguredProjectByProjectName(configFileName) || (
|
||||
loadKind === ProjectReferenceProjectLoadKind.Find ?
|
||||
undefined :
|
||||
loadKind === ProjectReferenceProjectLoadKind.FindCreate ?
|
||||
project.projectService.createConfiguredProject(configFileName) :
|
||||
loadKind === ProjectReferenceProjectLoadKind.FindCreateLoad ?
|
||||
project.projectService.createAndLoadConfiguredProject(configFileName, reason!) :
|
||||
Debug.assertNever(loadKind)
|
||||
);
|
||||
|
||||
const result = child && cb(child);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
(seenResolvedRefs || (seenResolvedRefs = new Map())).set(canonicalPath, loadKind);
|
||||
return worker(ref.references, ref.commandLine.options);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@ -2773,6 +2794,12 @@ namespace ts.server {
|
||||
*/
|
||||
private reloadConfiguredProjectForFiles<T>(openFiles: ESMap<Path, T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean, reason: string) {
|
||||
const updatedProjects = new Map<string, true>();
|
||||
const reloadChildProject = (child: ConfiguredProject) => {
|
||||
if (!updatedProjects.has(child.canonicalConfigFilePath)) {
|
||||
updatedProjects.set(child.canonicalConfigFilePath, true);
|
||||
this.reloadConfiguredProject(child, reason);
|
||||
}
|
||||
};
|
||||
// try to reload config file for all open files
|
||||
openFiles.forEach((openFileValue, path) => {
|
||||
// Filter out the files that need to be ignored
|
||||
@ -2801,17 +2828,22 @@ namespace ts.server {
|
||||
this.reloadConfiguredProject(project, reason);
|
||||
// If this is solution, reload the project till the reloaded project contains the script info directly
|
||||
if (!project.containsScriptInfo(info) && project.isSolution()) {
|
||||
forEachResolvedProjectReferenceProject(
|
||||
const referencedProject = forEachResolvedProjectReferenceProject(
|
||||
project,
|
||||
child => {
|
||||
if (!updatedProjects.has(child.canonicalConfigFilePath)) {
|
||||
updatedProjects.set(child.canonicalConfigFilePath, true);
|
||||
this.reloadConfiguredProject(child, reason);
|
||||
}
|
||||
reloadChildProject(child);
|
||||
return projectContainsInfoDirectly(child, info);
|
||||
},
|
||||
ProjectReferenceProjectLoadKind.FindCreate
|
||||
);
|
||||
if (referencedProject) {
|
||||
// Reload the project's tree that is already present
|
||||
forEachResolvedProjectReferenceProject(
|
||||
project,
|
||||
reloadChildProject,
|
||||
ProjectReferenceProjectLoadKind.Find
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2913,7 +2945,7 @@ namespace ts.server {
|
||||
const info = this.getScriptInfo(fileName);
|
||||
return info && projectContainsInfoDirectly(child, info) ? child : undefined;
|
||||
},
|
||||
ProjectReferenceProjectLoadKind.FindCreateLoad,
|
||||
configuredProject.getCompilerOptions().disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find : ProjectReferenceProjectLoadKind.FindCreateLoad,
|
||||
`Creating project referenced in solution ${configuredProject.projectName} to find possible configured project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`
|
||||
);
|
||||
if (!configuredProject) return undefined;
|
||||
@ -2965,8 +2997,9 @@ namespace ts.server {
|
||||
let configFileName: NormalizedPath | undefined;
|
||||
let configFileErrors: readonly Diagnostic[] | undefined;
|
||||
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
|
||||
let defaultConfigProject: ConfiguredProject | undefined;
|
||||
let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined;
|
||||
let projectForConfigFileDiag: ConfiguredProject | undefined;
|
||||
let defaultConfigProjectIsCreated = false;
|
||||
if (this.syntaxOnly) {
|
||||
// Invalidate resolutions in the file since this file is now open
|
||||
info.containingProjects.forEach(project => {
|
||||
@ -2981,30 +3014,22 @@ namespace ts.server {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${info.fileName} to open`);
|
||||
// Send the event only if the project got created as part of this open request and info is part of the project
|
||||
if (!project.containsScriptInfo(info)) {
|
||||
// Since the file isnt part of configured project, do not send config file info
|
||||
configFileName = undefined;
|
||||
}
|
||||
else {
|
||||
configFileErrors = project.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(project, info.fileName);
|
||||
}
|
||||
defaultConfigProjectIsCreated = true;
|
||||
}
|
||||
else {
|
||||
// Ensure project is ready to check if it contains opened script info
|
||||
updateProjectIfDirty(project);
|
||||
}
|
||||
|
||||
defaultConfigProject = project;
|
||||
retainProjects = defaultConfigProject;
|
||||
projectForConfigFileDiag = project.containsScriptInfo(info) ? project : undefined;
|
||||
retainProjects = project;
|
||||
|
||||
// If this configured project doesnt contain script info but
|
||||
// it is solution with project references, try those project references
|
||||
if (!project.containsScriptInfo(info) && project.isSolution()) {
|
||||
if (project.isSolution()) {
|
||||
forEachResolvedProjectReferenceProject(
|
||||
project,
|
||||
(child, childConfigFileName) => {
|
||||
child => {
|
||||
updateProjectIfDirty(child);
|
||||
// Retain these projects
|
||||
if (!isArray(retainProjects)) {
|
||||
@ -3016,20 +3041,35 @@ namespace ts.server {
|
||||
|
||||
// If script info belongs to this child project, use this as default config project
|
||||
if (projectContainsInfoDirectly(child, info)) {
|
||||
configFileName = childConfigFileName;
|
||||
configFileErrors = child.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(child, info.fileName);
|
||||
projectForConfigFileDiag = child;
|
||||
return child;
|
||||
}
|
||||
|
||||
// If this project uses the script info (even through project reference), if default project is not found, use this for configFileDiag
|
||||
if (!projectForConfigFileDiag && child.containsScriptInfo(info)) {
|
||||
projectForConfigFileDiag = child;
|
||||
}
|
||||
},
|
||||
ProjectReferenceProjectLoadKind.FindCreateLoad,
|
||||
`Creating project referenced in solution ${project.projectName} to find possible configured project for ${info.fileName} to open`
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Create ancestor configured project
|
||||
this.createAncestorProjects(info, defaultConfigProject || project);
|
||||
|
||||
// Send the event only if the project got created as part of this open request and info is part of the project
|
||||
if (projectForConfigFileDiag) {
|
||||
configFileName = projectForConfigFileDiag.getConfigFilePath();
|
||||
if (projectForConfigFileDiag !== project || defaultConfigProjectIsCreated) {
|
||||
configFileErrors = projectForConfigFileDiag.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(projectForConfigFileDiag, info.fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Since the file isnt part of configured project, do not send config file info
|
||||
configFileName = undefined;
|
||||
}
|
||||
|
||||
// Create ancestor configured project
|
||||
this.createAncestorProjects(info, project);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2264,9 +2264,16 @@ namespace ts.server {
|
||||
// The project is referenced only if open files impacted by this project are present in this project
|
||||
return forEachEntry(
|
||||
configFileExistenceInfo.openFilesImpactedByConfigFile,
|
||||
(_value, infoPath) => isSolution ?
|
||||
!!this.getDefaultChildProjectFromSolution(this.projectService.getScriptInfoForPath(infoPath)!) :
|
||||
this.containsScriptInfo(this.projectService.getScriptInfoForPath(infoPath)!)
|
||||
(_value, infoPath) => {
|
||||
const info = this.projectService.getScriptInfoForPath(infoPath)!;
|
||||
return isSolution ?
|
||||
!!forEachResolvedProjectReferenceProject(
|
||||
this,
|
||||
child => child.containsScriptInfo(info),
|
||||
ProjectReferenceProjectLoadKind.Find
|
||||
) :
|
||||
this.containsScriptInfo(info);
|
||||
}
|
||||
) || false;
|
||||
}
|
||||
|
||||
|
||||
@ -449,11 +449,11 @@ namespace ts.projectSystem {
|
||||
}
|
||||
|
||||
export function checkProjectActualFiles(project: server.Project, expectedFiles: readonly string[]) {
|
||||
checkArray(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
|
||||
checkArray(`${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}:: actual files`, project.getFileNames(), expectedFiles);
|
||||
}
|
||||
|
||||
export function checkProjectRootFiles(project: server.Project, expectedFiles: readonly string[]) {
|
||||
checkArray(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
|
||||
checkArray(`${server.ProjectKind[project.projectKind]} project: ${project.getProjectName()}::, rootFileNames`, project.getRootFiles(), expectedFiles);
|
||||
}
|
||||
|
||||
export function mapCombinedPathsInAncestor(dir: string, path2: string, mapAncestor: (ancestor: string) => boolean) {
|
||||
|
||||
@ -1825,11 +1825,14 @@ bar();
|
||||
});
|
||||
|
||||
describe("when default project is solution project", () => {
|
||||
interface VerifySolutionScenario {
|
||||
interface Setup {
|
||||
solutionOptions?: CompilerOptions;
|
||||
configRefs: string[];
|
||||
additionalFiles: readonly File[];
|
||||
additionalProjects: readonly { projectName: string, files: readonly string[] }[];
|
||||
expectedOpenEvents: protocol.Event[];
|
||||
}
|
||||
interface VerifySolutionScenario extends Setup {
|
||||
additionalProjects: readonly { projectName: string, files: readonly string[] }[];
|
||||
expectedReloadEvents: protocol.Event[];
|
||||
expectedReferences: protocol.ReferencesResponseBody;
|
||||
expectedReferencesFromDtsProject: protocol.ReferencesResponseBody;
|
||||
@ -1877,11 +1880,8 @@ foo;`
|
||||
};
|
||||
const tsconfigSrcPath = `${tscWatch.projectRoot}/tsconfig-src.json`;
|
||||
const tsconfigPath = `${tscWatch.projectRoot}/tsconfig.json`;
|
||||
function verifySolutionScenario({
|
||||
configRefs, additionalFiles, additionalProjects,
|
||||
expectedOpenEvents, expectedReloadEvents,
|
||||
expectedReferences, expectedReferencesFromDtsProject
|
||||
}: VerifySolutionScenario) {
|
||||
const dummyFilePath = "/dummy/dummy.ts";
|
||||
function setup({ solutionOptions, configRefs, additionalFiles, expectedOpenEvents }: Setup) {
|
||||
const tsconfigSrc: File = {
|
||||
path: tsconfigSrcPath,
|
||||
content: JSON.stringify({
|
||||
@ -1896,12 +1896,13 @@ foo;`
|
||||
const tsconfig: File = {
|
||||
path: tsconfigPath,
|
||||
content: JSON.stringify({
|
||||
... (solutionOptions ? { compilerOptions: solutionOptions } : {}),
|
||||
references: configRefs.map(path => ({ path })),
|
||||
files: []
|
||||
})
|
||||
};
|
||||
const dummyFile: File = {
|
||||
path: "/dummy/dummy.ts",
|
||||
path: dummyFilePath,
|
||||
content: "let a = 10;"
|
||||
};
|
||||
const host = createServerHost([
|
||||
@ -1913,8 +1914,17 @@ foo;`
|
||||
const session = createSession(host, { canUseEvents: true });
|
||||
const service = session.getProjectService();
|
||||
service.openClientFile(main.path);
|
||||
verifyProjects(/*includeConfigured*/ true, /*includeDummy*/ false);
|
||||
checkEvents(session, expectedOpenEvents);
|
||||
return { session, service, host, tsconfigSrc, tsconfig };
|
||||
}
|
||||
|
||||
function verifySolutionScenario(input: VerifySolutionScenario) {
|
||||
const { session, service, host, tsconfigSrc, tsconfig } = setup(input);
|
||||
const {
|
||||
additionalProjects, expectedReloadEvents,
|
||||
expectedReferences, expectedReferencesFromDtsProject
|
||||
} = input;
|
||||
verifyProjects(/*includeConfigured*/ true, /*includeDummy*/ false);
|
||||
const info = service.getScriptInfoForPath(main.path as Path)!;
|
||||
const project = service.configuredProjects.get(tsconfigSrc.path)!;
|
||||
assert.equal(info.getDefaultProject(), project);
|
||||
@ -1924,17 +1934,17 @@ foo;`
|
||||
verifyGetErrRequestNoErrors({ session, host, files: [main] });
|
||||
|
||||
// Verify collection of script infos
|
||||
service.openClientFile(dummyFile.path);
|
||||
service.openClientFile(dummyFilePath);
|
||||
verifyProjects(/*includeConfigured*/ true, /*includeDummy*/ true);
|
||||
|
||||
service.closeClientFile(main.path);
|
||||
service.closeClientFile(dummyFile.path);
|
||||
service.openClientFile(dummyFile.path);
|
||||
service.closeClientFile(dummyFilePath);
|
||||
service.openClientFile(dummyFilePath);
|
||||
verifyProjects(/*includeConfigured*/ false, /*includeDummy*/ true);
|
||||
|
||||
service.openClientFile(main.path);
|
||||
service.closeClientFile(dummyFile.path);
|
||||
service.openClientFile(dummyFile.path);
|
||||
service.closeClientFile(dummyFilePath);
|
||||
service.openClientFile(dummyFilePath);
|
||||
verifyProjects(/*includeConfigured*/ true, /*includeDummy*/ true);
|
||||
|
||||
// Verify Reload projects
|
||||
@ -1951,7 +1961,7 @@ foo;`
|
||||
assert.deepEqual(response, expectedReferences);
|
||||
|
||||
service.closeClientFile(main.path);
|
||||
service.closeClientFile(dummyFile.path);
|
||||
service.closeClientFile(dummyFilePath);
|
||||
|
||||
// Verify when declaration map references the file
|
||||
service.openClientFile(fileResolvingToMainDts.path);
|
||||
@ -1976,7 +1986,7 @@ foo;`
|
||||
checkProjectActualFiles(service.configuredProjects.get(projectName)!, files));
|
||||
}
|
||||
if (includeDummy) {
|
||||
checkProjectActualFiles(service.inferredProjects[0], [dummyFile.path, libFile.path]);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [dummyFilePath, libFile.path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2061,14 +2071,15 @@ foo;`
|
||||
];
|
||||
}
|
||||
|
||||
function getIndirectProject(postfix: string) {
|
||||
function getIndirectProject(postfix: string, optionsToExtend?: CompilerOptions) {
|
||||
const tsconfigIndirect: File = {
|
||||
path: `${tscWatch.projectRoot}/tsconfig-indirect${postfix}.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
outDir: "./target/",
|
||||
baseUrl: "./src/"
|
||||
baseUrl: "./src/",
|
||||
...optionsToExtend
|
||||
},
|
||||
files: [`./indirect${postfix}/main.ts`],
|
||||
references: [{ path: "./tsconfig-src.json" }]
|
||||
@ -2081,6 +2092,66 @@ foo;`
|
||||
return { tsconfigIndirect, indirect };
|
||||
}
|
||||
|
||||
interface VerifyProjects {
|
||||
configuredProjects: readonly { projectName: string, files: readonly string[] }[];
|
||||
inferredProjects: readonly (readonly string[])[];
|
||||
}
|
||||
|
||||
interface VerifyDisableReferencedProjectLoad extends Setup {
|
||||
expectedProjectsOnOpen: VerifyProjects;
|
||||
expectedProjectsOnDummyOpen?: VerifyProjects;
|
||||
expectedProjectsOnReload?: VerifyProjects;
|
||||
expectedDefaultProject: (service: server.ProjectService) => server.Project;
|
||||
expectedDefaultConfiguredProject: (service: server.ProjectService) => server.ConfiguredProject | undefined;
|
||||
expectedReloadEvents: protocol.Event[];
|
||||
}
|
||||
|
||||
function verifyDisableReferencedProjectLoad(input: VerifyDisableReferencedProjectLoad) {
|
||||
const { session, service } = setup(input);
|
||||
const { expectedProjectsOnOpen, expectedDefaultProject, expectedDefaultConfiguredProject, expectedReloadEvents } = input;
|
||||
const expectedProjectsOnOnlyDummy: VerifyProjects = {
|
||||
configuredProjects: emptyArray,
|
||||
inferredProjects: [
|
||||
[dummyFilePath, libFile.path],
|
||||
]
|
||||
};
|
||||
const expectedProjectsOnDummyOpen = input.expectedProjectsOnDummyOpen || {
|
||||
configuredProjects: expectedProjectsOnOpen.configuredProjects,
|
||||
inferredProjects: expectedProjectsOnOnlyDummy.inferredProjects,
|
||||
};
|
||||
const expectedProjectsOnReload = input.expectedProjectsOnReload || expectedProjectsOnDummyOpen;
|
||||
|
||||
verifyProjects(expectedProjectsOnOpen);
|
||||
const info = service.getScriptInfoForPath(main.path as Path)!;
|
||||
assert.equal(info.getDefaultProject(), expectedDefaultProject(service));
|
||||
assert.equal(service.findDefaultConfiguredProject(info), expectedDefaultConfiguredProject(service));
|
||||
|
||||
// Verify collection of script infos
|
||||
service.openClientFile(dummyFilePath);
|
||||
verifyProjects(expectedProjectsOnDummyOpen);
|
||||
|
||||
service.closeClientFile(main.path);
|
||||
service.closeClientFile(dummyFilePath);
|
||||
service.openClientFile(dummyFilePath);
|
||||
verifyProjects(expectedProjectsOnOnlyDummy);
|
||||
|
||||
service.openClientFile(main.path);
|
||||
|
||||
// Verify Reload projects
|
||||
session.clearMessages();
|
||||
service.reloadProjects();
|
||||
checkEvents(session, expectedReloadEvents);
|
||||
verifyProjects(expectedProjectsOnReload);
|
||||
|
||||
function verifyProjects(expected: VerifyProjects) {
|
||||
checkNumberOfProjects(service, { configuredProjects: expected.configuredProjects.length, inferredProjects: expected.inferredProjects.length });
|
||||
expected.configuredProjects.forEach(({ projectName, files }) =>
|
||||
checkProjectActualFiles(service.configuredProjects.get(projectName)!, files));
|
||||
expected.inferredProjects.forEach((files, index) =>
|
||||
checkProjectActualFiles(service.inferredProjects[index], files));
|
||||
}
|
||||
}
|
||||
|
||||
it("when project is directly referenced by solution", () => {
|
||||
const expectedReferences = expectedReferencesResponse();
|
||||
verifySolutionScenario({
|
||||
@ -2150,6 +2221,105 @@ foo;`
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("disables looking into the child project if disableReferencedProjectLoad is set", () => {
|
||||
const expectedProjectsOnOpen: VerifyProjects = {
|
||||
configuredProjects: [
|
||||
{ projectName: tsconfigPath, files: [tsconfigPath] },
|
||||
],
|
||||
inferredProjects: [
|
||||
[main.path, libFile.path],
|
||||
]
|
||||
};
|
||||
verifyDisableReferencedProjectLoad({
|
||||
solutionOptions: { disableReferencedProjectLoad: true },
|
||||
configRefs: ["./tsconfig-src.json"],
|
||||
additionalFiles: emptyArray,
|
||||
expectedOpenEvents: [
|
||||
...expectedSolutionLoadAndTelemetry(),
|
||||
configFileDiagEvent(main.path, tsconfigPath, [])
|
||||
],
|
||||
expectedDefaultProject: service => service.inferredProjects[0],
|
||||
expectedDefaultConfiguredProject: returnUndefined,
|
||||
expectedProjectsOnOpen,
|
||||
expectedProjectsOnDummyOpen: {
|
||||
configuredProjects: emptyArray,
|
||||
inferredProjects: [
|
||||
...expectedProjectsOnOpen.inferredProjects,
|
||||
[dummyFilePath, libFile.path],
|
||||
]
|
||||
},
|
||||
expectedProjectsOnReload: {
|
||||
configuredProjects: expectedProjectsOnOpen.configuredProjects,
|
||||
inferredProjects: [
|
||||
[dummyFilePath, libFile.path],
|
||||
...expectedProjectsOnOpen.inferredProjects,
|
||||
]
|
||||
},
|
||||
expectedReloadEvents: expectedReloadEvent(tsconfigPath)
|
||||
});
|
||||
});
|
||||
|
||||
it("disables looking into the child project if disableReferencedProjectLoad is set in indirect project", () => {
|
||||
const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true });
|
||||
const expectedProjectsOnOpen: VerifyProjects = {
|
||||
configuredProjects: [
|
||||
{ projectName: tsconfigPath, files: [tsconfigPath] },
|
||||
{ projectName: tsconfigIndirect.path, files: [tsconfigIndirect.path, main.path, helper.path, indirect.path, libFile.path] },
|
||||
],
|
||||
inferredProjects: emptyArray
|
||||
};
|
||||
verifyDisableReferencedProjectLoad({
|
||||
configRefs: ["./tsconfig-indirect1.json"],
|
||||
additionalFiles: [tsconfigIndirect, indirect],
|
||||
expectedOpenEvents: [
|
||||
...expectedSolutionLoadAndTelemetry(),
|
||||
...expectedProjectReferenceLoadAndTelemetry(tsconfigIndirect.path),
|
||||
configFileDiagEvent(main.path, tsconfigIndirect.path, [])
|
||||
],
|
||||
expectedDefaultProject: service => service.configuredProjects.get(tsconfigIndirect.path)!,
|
||||
expectedDefaultConfiguredProject: returnUndefined,
|
||||
expectedProjectsOnOpen,
|
||||
expectedReloadEvents: [
|
||||
...expectedReloadEvent(tsconfigPath),
|
||||
...expectedReloadEvent(tsconfigIndirect.path),
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it("disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", () => {
|
||||
const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true });
|
||||
const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2");
|
||||
const expectedProjectsOnOpen: VerifyProjects = {
|
||||
configuredProjects: [
|
||||
{ projectName: tsconfigPath, files: [tsconfigPath] },
|
||||
{ projectName: tsconfigIndirect.path, files: [tsconfigIndirect.path, main.path, helper.path, indirect.path, libFile.path] },
|
||||
{ projectName: tsconfigIndirect2.path, files: [tsconfigIndirect2.path, main.path, helper.path, indirect2.path, libFile.path] },
|
||||
{ projectName: tsconfigSrcPath, files: [tsconfigSrcPath, main.path, helper.path, libFile.path] },
|
||||
],
|
||||
inferredProjects: emptyArray
|
||||
};
|
||||
verifyDisableReferencedProjectLoad({
|
||||
configRefs: ["./tsconfig-indirect1.json", "./tsconfig-indirect2.json"],
|
||||
additionalFiles: [tsconfigIndirect, indirect, tsconfigIndirect2, indirect2],
|
||||
expectedOpenEvents: [
|
||||
...expectedSolutionLoadAndTelemetry(),
|
||||
...expectedProjectReferenceLoadAndTelemetry(tsconfigIndirect.path),
|
||||
...expectedProjectReferenceLoadAndTelemetry(tsconfigIndirect2.path),
|
||||
...expectedProjectReferenceLoadAndTelemetry(tsconfigSrcPath),
|
||||
configFileDiagEvent(main.path, tsconfigSrcPath, [])
|
||||
],
|
||||
expectedDefaultProject: service => service.configuredProjects.get(tsconfigSrcPath)!,
|
||||
expectedDefaultConfiguredProject: service => service.configuredProjects.get(tsconfigSrcPath)!,
|
||||
expectedProjectsOnOpen,
|
||||
expectedReloadEvents: [
|
||||
...expectedReloadEvent(tsconfigPath),
|
||||
...expectedReloadEvent(tsconfigIndirect.path),
|
||||
...expectedReloadEvent(tsconfigSrcPath),
|
||||
...expectedReloadEvent(tsconfigIndirect2.path),
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("auto import with referenced project", () => {
|
||||
|
||||
@ -2762,6 +2762,7 @@ declare namespace ts {
|
||||
disableSizeLimit?: boolean;
|
||||
disableSourceOfProjectReferenceRedirect?: boolean;
|
||||
disableSolutionSearching?: boolean;
|
||||
disableReferencedProjectLoad?: boolean;
|
||||
downlevelIteration?: boolean;
|
||||
emitBOM?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
|
||||
@ -2762,6 +2762,7 @@ declare namespace ts {
|
||||
disableSizeLimit?: boolean;
|
||||
disableSourceOfProjectReferenceRedirect?: boolean;
|
||||
disableSolutionSearching?: boolean;
|
||||
disableReferencedProjectLoad?: boolean;
|
||||
downlevelIteration?: boolean;
|
||||
emitBOM?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"disableReferencedProjectLoad": true
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user