mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-16 05:58:32 -06:00
Do not report config file errors if the file opened isnt from configured project and that project doesnt have the config errors
Fixes #16635
This commit is contained in:
parent
8b2a219dd4
commit
249725d4b7
@ -7,7 +7,7 @@ namespace ts.projectSystem {
|
||||
const file = makeFile("/a.js");
|
||||
const et = new EventTracker([file]);
|
||||
et.service.openClientFile(file.path);
|
||||
assert.equal(et.getEvents().length, 0);
|
||||
assert.equal(et.getEventsWithName(ts.server.ProjectInfoTelemetryEvent).length, 0);
|
||||
});
|
||||
|
||||
it("only sends an event once", () => {
|
||||
@ -25,12 +25,12 @@ namespace ts.projectSystem {
|
||||
et.service.openClientFile(file2.path);
|
||||
checkNumberOfProjects(et.service, { inferredProjects: 1 });
|
||||
|
||||
assert.equal(et.getEvents().length, 0);
|
||||
assert.equal(et.getEventsWithName(ts.server.ProjectInfoTelemetryEvent).length, 0);
|
||||
|
||||
et.service.openClientFile(file.path);
|
||||
checkNumberOfProjects(et.service, { configuredProjects: 1, inferredProjects: 1 });
|
||||
|
||||
assert.equal(et.getEvents().length, 0);
|
||||
assert.equal(et.getEventsWithName(ts.server.ProjectInfoTelemetryEvent).length, 0);
|
||||
});
|
||||
|
||||
it("counts files by extension", () => {
|
||||
@ -219,7 +219,7 @@ namespace ts.projectSystem {
|
||||
const et = new EventTracker([tsconfig, file]);
|
||||
et.host.getFileSize = () => server.maxProgramSizeForNonTsFiles + 1;
|
||||
et.service.openClientFile(file.path);
|
||||
et.getEvent<server.ProjectLanguageServiceStateEvent>(server.ProjectLanguageServiceStateEvent, /*mayBeMore*/ true);
|
||||
et.getEvent<server.ProjectLanguageServiceStateEvent>(server.ProjectLanguageServiceStateEvent);
|
||||
et.assertProjectInfoTelemetryEvent({
|
||||
projectId: Harness.mockHash("/jsconfig.json"),
|
||||
fileStats: fileStats({ js: 1 }),
|
||||
@ -255,6 +255,17 @@ namespace ts.projectSystem {
|
||||
return events;
|
||||
}
|
||||
|
||||
getEventsWithName<T extends server.ProjectServiceEvent>(eventName: T["eventName"]): ReadonlyArray<T> {
|
||||
let events: T[];
|
||||
removeWhere(this.events, event => {
|
||||
if (event.eventName === eventName) {
|
||||
(events || (events = [])).push(event as T);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return events || emptyArray;
|
||||
}
|
||||
|
||||
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>, configFile?: string): void {
|
||||
assert.deepEqual(this.getEvent<server.ProjectInfoTelemetryEvent>(ts.server.ProjectInfoTelemetryEvent), {
|
||||
projectId: Harness.mockHash(configFile || "/tsconfig.json"),
|
||||
@ -278,10 +289,17 @@ namespace ts.projectSystem {
|
||||
});
|
||||
}
|
||||
|
||||
getEvent<T extends server.ProjectServiceEvent>(eventName: T["eventName"], mayBeMore = false): T["data"] {
|
||||
if (mayBeMore) { assert(this.events.length !== 0); }
|
||||
else { assert.equal(this.events.length, 1); }
|
||||
const event = this.events.shift();
|
||||
getEvent<T extends server.ProjectServiceEvent>(eventName: T["eventName"]): T["data"] {
|
||||
let event: server.ProjectServiceEvent;
|
||||
removeWhere(this.events, e => {
|
||||
if (e.eventName === eventName) {
|
||||
if (event) {
|
||||
assert(false, "more than one event found");
|
||||
}
|
||||
event = e;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assert.equal(event.eventName, eventName);
|
||||
return event.data;
|
||||
}
|
||||
|
||||
@ -463,7 +463,7 @@ namespace ts.projectSystem {
|
||||
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
|
||||
|
||||
assert(configFileName, "should find config file");
|
||||
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
||||
assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
|
||||
@ -503,7 +503,7 @@ namespace ts.projectSystem {
|
||||
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
|
||||
|
||||
assert(configFileName, "should find config file");
|
||||
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
||||
assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
|
||||
@ -3169,6 +3169,69 @@ namespace ts.projectSystem {
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 3);
|
||||
});
|
||||
|
||||
it("are generated when the config file doesnot include file opened but has errors", () => {
|
||||
const serverEventManager = new TestServerEventManager();
|
||||
const file = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const file2 = {
|
||||
path: "/a/b/test.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"foo": "bar",
|
||||
"allowJS": true
|
||||
},
|
||||
"files": ["app.ts"]
|
||||
}`
|
||||
};
|
||||
|
||||
const host = createServerHost([file, file2, libFile, configFile]);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file2], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
for (const event of serverEventManager.events) {
|
||||
if (event.eventName === "configFileDiag") {
|
||||
assert.equal(event.data.configFileName, configFile.path);
|
||||
assert.equal(event.data.triggerFile, file2.path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("are not generated when the config file doesnot include file opened and doesnt contain any errors", () => {
|
||||
const serverEventManager = new TestServerEventManager();
|
||||
const file = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const file2 = {
|
||||
path: "/a/b/test.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"files": ["app.ts"]
|
||||
}`
|
||||
};
|
||||
|
||||
const host = createServerHost([file, file2, libFile, configFile]);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file2], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("skipLibCheck", () => {
|
||||
|
||||
@ -1561,14 +1561,17 @@ namespace ts.server {
|
||||
project.watchWildcards(projectOptions.wildcardDirectories);
|
||||
}
|
||||
this.updateNonInferredProject(project, projectOptions.files, fileNamePropertyReader, projectOptions.compilerOptions, projectOptions.typeAcquisition, projectOptions.compileOnSave);
|
||||
this.sendConfigFileDiagEvent(project, configFileName);
|
||||
}
|
||||
|
||||
private sendConfigFileDiagEvent(project: ConfiguredProject, triggerFile: NormalizedPath) {
|
||||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventHandler(<ConfigFileDiagEvent>{
|
||||
eventName: ConfigFileDiagEvent,
|
||||
data: { configFileName, diagnostics: project.getGlobalProjectErrors() || [], triggerFile: configFileName }
|
||||
data: { configFileName: project.getConfigFilePath(), diagnostics: project.getAllProjectErrors(), triggerFile }
|
||||
});
|
||||
}
|
||||
|
||||
@ -1888,6 +1891,7 @@ namespace ts.server {
|
||||
|
||||
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
|
||||
let configFileName: NormalizedPath;
|
||||
let sendConfigFileDiagEvent = false;
|
||||
let configFileErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, fileContent, scriptKind, hasMixedContent);
|
||||
@ -1898,14 +1902,8 @@ namespace ts.server {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
project = this.createConfiguredProject(configFileName);
|
||||
|
||||
// even if opening config file was successful, it could still
|
||||
// contain errors that were tolerated.
|
||||
const errors = project.getGlobalProjectErrors();
|
||||
if (errors && errors.length > 0) {
|
||||
// set configFileErrors only when the errors array is non-empty
|
||||
configFileErrors = errors;
|
||||
}
|
||||
// Send the event only if the project got created as part of this open request
|
||||
sendConfigFileDiagEvent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1919,10 +1917,21 @@ namespace ts.server {
|
||||
// At this point if file is part of any any configured or external project, then it would be present in the containing projects
|
||||
// So if it still doesnt have any containing projects, it needs to be part of inferred project
|
||||
if (info.isOrphan()) {
|
||||
// Since the file isnt part of configured project,
|
||||
// report config file and its error only if config file found had errors (and hence may be didnt include the file)
|
||||
if (sendConfigFileDiagEvent && !project.getAllProjectErrors().length) {
|
||||
configFileName = undefined;
|
||||
sendConfigFileDiagEvent = false;
|
||||
}
|
||||
this.assignOrphanScriptInfoToInferredProject(info, projectRootPath);
|
||||
}
|
||||
this.addToListOfOpenFiles(info);
|
||||
|
||||
if (sendConfigFileDiagEvent) {
|
||||
configFileErrors = project.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(project as ConfiguredProject, fileName);
|
||||
}
|
||||
|
||||
// Remove the configured projects that have zero references from open files.
|
||||
// This was postponed from closeOpenFile to after opening next file,
|
||||
// so that we can reuse the project if we need to right away
|
||||
@ -1938,6 +1947,7 @@ namespace ts.server {
|
||||
// the file from that old project is reopened because of opening file from here.
|
||||
this.deleteOrphanScriptInfoNotInAnyProject();
|
||||
this.printProjects();
|
||||
|
||||
return { configFileName, configFileErrors };
|
||||
}
|
||||
|
||||
|
||||
@ -1271,14 +1271,14 @@ namespace ts.server {
|
||||
* Get the errors that dont have any file name associated
|
||||
*/
|
||||
getGlobalProjectErrors(): ReadonlyArray<Diagnostic> {
|
||||
return filter(this.projectErrors, diagnostic => !diagnostic.file);
|
||||
return filter(this.projectErrors, diagnostic => !diagnostic.file) || emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the project errors
|
||||
*/
|
||||
getAllProjectErrors(): ReadonlyArray<Diagnostic> {
|
||||
return this.projectErrors;
|
||||
return this.projectErrors || emptyArray;
|
||||
}
|
||||
|
||||
setProjectErrors(projectErrors: Diagnostic[]) {
|
||||
@ -1335,6 +1335,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
this.stopWatchingWildCards();
|
||||
this.projectErrors = undefined;
|
||||
this.configFileSpecs = undefined;
|
||||
}
|
||||
|
||||
addOpenRef() {
|
||||
|
||||
@ -969,13 +969,7 @@ namespace ts.server {
|
||||
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
|
||||
*/
|
||||
private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: NormalizedPath) {
|
||||
const { configFileName, configFileErrors } = this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath);
|
||||
if (this.eventHandler) {
|
||||
this.eventHandler({
|
||||
eventName: "configFileDiag",
|
||||
data: { triggerFile: fileName, configFileName, diagnostics: configFileErrors || emptyArray }
|
||||
});
|
||||
}
|
||||
this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath);
|
||||
}
|
||||
|
||||
private getPosition(args: protocol.FileLocationRequestArgs, scriptInfo: ScriptInfo): number {
|
||||
|
||||
@ -7517,6 +7517,7 @@ declare namespace ts.server {
|
||||
private createConfiguredProject(configFileName);
|
||||
private updateNonInferredProjectFiles<T>(project, files, propertyReader);
|
||||
private updateNonInferredProject<T>(project, newUncheckedFiles, propertyReader, newOptions, newTypeAcquisition, compileOnSave);
|
||||
private sendConfigFileDiagEvent(project, triggerFile);
|
||||
private getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath);
|
||||
private getOrCreateSingleInferredProjectIfEnabled();
|
||||
private createInferredProject(rootDirectoryForResolution, isSingleInferredProject?, projectRootPath?);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user