mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Merge pull request #25851 from Microsoft/configFileDiag
Report compiler options errors as well as part of configFileDiag event
This commit is contained in:
commit
9196b7db33
@ -2711,12 +2711,12 @@ namespace ts {
|
||||
|
||||
function createDiagnosticForReference(index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
|
||||
const referencesSyntax = getProjectReferencesSyntax();
|
||||
if (referencesSyntax) {
|
||||
if (createOptionDiagnosticInArrayLiteralSyntax(referencesSyntax, index, message, arg0, arg1)) {
|
||||
return;
|
||||
}
|
||||
if (referencesSyntax && referencesSyntax.elements.length > index) {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
|
||||
}
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
|
||||
}
|
||||
|
||||
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0: string | number, arg1?: string | number, arg2?: string | number) {
|
||||
@ -2769,15 +2769,6 @@ namespace ts {
|
||||
return !!props.length;
|
||||
}
|
||||
|
||||
function createOptionDiagnosticInArrayLiteralSyntax(arrayLiteral: ArrayLiteralExpression, index: number, message: DiagnosticMessage, arg0: string | number | undefined, arg1?: string | number, arg2?: string | number): boolean {
|
||||
if (arrayLiteral.elements.length <= index) {
|
||||
// Out-of-bounds
|
||||
return false;
|
||||
}
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, arrayLiteral.elements[index], message, arg0, arg1, arg2));
|
||||
return false; // TODO: GH#18217 This function always returns `false`!`
|
||||
}
|
||||
|
||||
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
|
||||
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
|
||||
programDiagnostics.add(diag);
|
||||
|
||||
@ -1683,10 +1683,12 @@ namespace ts.server {
|
||||
if (!this.eventHandler || this.suppressDiagnosticEvents) {
|
||||
return;
|
||||
}
|
||||
const diagnostics = project.getLanguageService().getCompilerOptionsDiagnostics();
|
||||
diagnostics.push(...project.getAllProjectErrors());
|
||||
|
||||
this.eventHandler(<ConfigFileDiagEvent>{
|
||||
eventName: ConfigFileDiagEvent,
|
||||
data: { configFileName: project.getConfigFilePath(), diagnostics: project.getAllProjectErrors(), triggerFile }
|
||||
data: { configFileName: project.getConfigFilePath(), diagnostics, triggerFile }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +176,18 @@ namespace ts.projectSystem {
|
||||
return { ts: 0, tsx: 0, dts: 0, js: 0, jsx: 0, deferred: 0, ...nonZeroStats };
|
||||
}
|
||||
|
||||
export interface ConfigFileDiagnostic {
|
||||
fileName: string | undefined;
|
||||
start: number | undefined;
|
||||
length: number | undefined;
|
||||
messageText: string;
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
reportsUnnecessary?: {};
|
||||
source?: string;
|
||||
relatedInformation?: DiagnosticRelatedInformation[];
|
||||
}
|
||||
|
||||
export class TestServerEventManager {
|
||||
private events: server.ProjectServiceEvent[] = [];
|
||||
readonly session: TestSession;
|
||||
@ -216,10 +228,14 @@ namespace ts.projectSystem {
|
||||
this.events.forEach(event => assert.notEqual(event.eventName, eventName));
|
||||
}
|
||||
|
||||
checkSingleConfigFileDiagEvent(configFileName: string, triggerFile: string) {
|
||||
checkSingleConfigFileDiagEvent(configFileName: string, triggerFile: string, errors: ReadonlyArray<ConfigFileDiagnostic>) {
|
||||
const eventData = this.getEvent<server.ConfigFileDiagEvent>(server.ConfigFileDiagEvent);
|
||||
assert.equal(eventData.configFileName, configFileName);
|
||||
assert.equal(eventData.triggerFile, triggerFile);
|
||||
const actual = eventData.diagnostics.map(({ file, messageText, ...rest }) => ({ fileName: file && file.fileName, messageText: isString(messageText) ? messageText : "", ...rest }));
|
||||
if (errors) {
|
||||
assert.deepEqual(actual, errors);
|
||||
}
|
||||
}
|
||||
|
||||
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>, configFile = "/tsconfig.json"): void {
|
||||
@ -4698,13 +4714,41 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem Configure file diagnostics events", () => {
|
||||
function getUnknownCompilerOptionDiagnostic(configFile: File, prop: string): ConfigFileDiagnostic {
|
||||
const d = Diagnostics.Unknown_compiler_option_0;
|
||||
const start = configFile.content.indexOf(prop) - 1; // start at "prop"
|
||||
return {
|
||||
fileName: configFile.path,
|
||||
start,
|
||||
length: prop.length + 2,
|
||||
messageText: formatStringFromArgs(d.message, [prop]),
|
||||
category: d.category,
|
||||
code: d.code,
|
||||
reportsUnnecessary: undefined
|
||||
};
|
||||
}
|
||||
|
||||
function getFileNotFoundDiagnostic(configFile: File, relativeFileName: string): ConfigFileDiagnostic {
|
||||
const findString = `{"path":"./${relativeFileName}"}`;
|
||||
const d = Diagnostics.File_0_does_not_exist;
|
||||
const start = configFile.content.indexOf(findString);
|
||||
return {
|
||||
fileName: configFile.path,
|
||||
start,
|
||||
length: findString.length,
|
||||
messageText: formatStringFromArgs(d.message, [`${getDirectoryPath(configFile.path)}/${relativeFileName}`]),
|
||||
category: d.category,
|
||||
code: d.code,
|
||||
reportsUnnecessary: undefined
|
||||
};
|
||||
}
|
||||
|
||||
it("are generated when the config file has errors", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
@ -4713,29 +4757,32 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}`
|
||||
};
|
||||
const serverEventManager = new TestServerEventManager([file, configFile]);
|
||||
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
|
||||
openFilesForSession([file], serverEventManager.session);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, [
|
||||
getUnknownCompilerOptionDiagnostic(configFile, "foo"),
|
||||
getUnknownCompilerOptionDiagnostic(configFile, "allowJS")
|
||||
]);
|
||||
});
|
||||
|
||||
it("are generated when the config file doesn't have errors", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {}
|
||||
}`
|
||||
};
|
||||
const serverEventManager = new TestServerEventManager([file, configFile]);
|
||||
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
|
||||
openFilesForSession([file], serverEventManager.session);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, emptyArray);
|
||||
});
|
||||
|
||||
it("are generated when the config file changes", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
@ -4746,37 +4793,40 @@ namespace ts.projectSystem {
|
||||
}`
|
||||
};
|
||||
|
||||
const serverEventManager = new TestServerEventManager([file, configFile]);
|
||||
const files = [file, libFile, configFile];
|
||||
const serverEventManager = new TestServerEventManager(files);
|
||||
openFilesForSession([file], serverEventManager.session);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, emptyArray);
|
||||
|
||||
configFile.content = `{
|
||||
"compilerOptions": {
|
||||
"haha": 123
|
||||
}
|
||||
}`;
|
||||
serverEventManager.host.reloadFS([file, configFile]);
|
||||
serverEventManager.host.reloadFS(files);
|
||||
serverEventManager.host.runQueuedTimeoutCallbacks();
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, [
|
||||
getUnknownCompilerOptionDiagnostic(configFile, "haha")
|
||||
]);
|
||||
|
||||
configFile.content = `{
|
||||
"compilerOptions": {}
|
||||
}`;
|
||||
serverEventManager.host.reloadFS([file, configFile]);
|
||||
serverEventManager.host.reloadFS(files);
|
||||
serverEventManager.host.runQueuedTimeoutCallbacks();
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, emptyArray);
|
||||
});
|
||||
|
||||
it("are not generated when the config file does not include file opened and config file has errors", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const file2 = {
|
||||
const file2: File = {
|
||||
path: "/a/b/test.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
@ -4792,11 +4842,11 @@ namespace ts.projectSystem {
|
||||
});
|
||||
|
||||
it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
@ -4805,21 +4855,21 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}`
|
||||
};
|
||||
const serverEventManager = new TestServerEventManager([file, configFile], /*suppressDiagnosticEvents*/ true);
|
||||
const serverEventManager = new TestServerEventManager([file, libFile, configFile], /*suppressDiagnosticEvents*/ true);
|
||||
openFilesForSession([file], serverEventManager.session);
|
||||
serverEventManager.hasZeroEvent("configFileDiag");
|
||||
});
|
||||
|
||||
it("are not generated when the config file does not include file opened and doesnt contain any errors", () => {
|
||||
const file = {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const file2 = {
|
||||
const file2: File = {
|
||||
path: "/a/b/test.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const configFile = {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"files": ["app.ts"]
|
||||
@ -4830,6 +4880,27 @@ namespace ts.projectSystem {
|
||||
openFilesForSession([file2], serverEventManager.session);
|
||||
serverEventManager.hasZeroEvent("configFileDiag");
|
||||
});
|
||||
|
||||
it("contains the project reference errors", () => {
|
||||
const file: File = {
|
||||
path: "/a/b/app.ts",
|
||||
content: "let x = 10"
|
||||
};
|
||||
const noSuchTsconfig = "no-such-tsconfig.json";
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"files": ["app.ts"],
|
||||
"references": [{"path":"./${noSuchTsconfig}"}]
|
||||
}`
|
||||
};
|
||||
|
||||
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
|
||||
openFilesForSession([file], serverEventManager.session);
|
||||
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, [
|
||||
getFileNotFoundDiagnostic(configFile, noSuchTsconfig)
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem skipLibCheck", () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user