Report config file parsing diagnostics correctly with tsc --b (#36520)

* Refactor the test

* Add tests for syntax errors in tsconfig not being reported

* Report config file parsing diagnostics correctly
Fixes #36515

* Fix errors in existing tests for unintended tsconfig parse errors

* Fix lint
This commit is contained in:
Sheetal Nandi
2020-01-30 11:18:06 -08:00
committed by GitHub
parent c1e45ac8af
commit 4c378c09dc
34 changed files with 543 additions and 84 deletions
+1 -1
View File
@@ -107,6 +107,7 @@
"unittests/services/textChanges.ts",
"unittests/services/transpile.ts",
"unittests/tsbuild/amdModulesWithOut.ts",
"unittests/tsbuild/configFileErrors.ts",
"unittests/tsbuild/containerOnlyReferenced.ts",
"unittests/tsbuild/demo.ts",
"unittests/tsbuild/emitDeclarationOnly.ts",
@@ -116,7 +117,6 @@
"unittests/tsbuild/inferredTypeFromTransitiveModule.ts",
"unittests/tsbuild/javascriptProjectEmit.ts",
"unittests/tsbuild/lateBoundSymbol.ts",
"unittests/tsbuild/missingExtendedFile.ts",
"unittests/tsbuild/moduleSpecifiers.ts",
"unittests/tsbuild/noEmitOnError.ts",
"unittests/tsbuild/outFile.ts",
@@ -0,0 +1,57 @@
namespace ts {
describe("unittests:: tsbuild:: configFileErrors:: when tsconfig extends the missing file", () => {
verifyTsc({
scenario: "configFileErrors",
subScenario: "when tsconfig extends the missing file",
fs: () => loadProjectFromDisk("tests/projects/missingExtendedConfig"),
commandLineArgs: ["--b", "/src/tsconfig.json"],
});
});
describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in config file", () => {
verifyTscIncrementalEdits({
scenario: "configFileErrors",
subScenario: "reports syntax errors in config file",
fs: () => loadProjectFromFiles({
"/src/a.ts": "export function foo() { }",
"/src/b.ts": "export function bar() { }",
"/src/tsconfig.json": Utils.dedent`
{
"compilerOptions": {
"composite": true,
},
"files": [
"a.ts"
"b.ts"
]
}`
}),
commandLineArgs: ["--b", "/src/tsconfig.json"],
incrementalScenarios: [
{
buildKind: BuildKind.IncrementalDtsUnchanged,
modifyFs: fs => replaceText(fs, "/src/tsconfig.json", ",", `,
"declaration": true,`),
subScenario: "reports syntax errors after change to config file"
},
{
buildKind: BuildKind.IncrementalDtsUnchanged,
modifyFs: fs => appendText(fs, "/src/a.ts", "export function fooBar() { }"),
subScenario: "reports syntax errors after change to ts file"
},
noChangeRun,
{
buildKind: BuildKind.IncrementalDtsChange,
modifyFs: fs => fs.writeFileSync(
"/src/tsconfig.json",
JSON.stringify({
compilerOptions: { composite: true, declaration: true },
files: ["a.ts", "b.ts"]
})
),
subScenario: "builds after fixing config file errors"
},
]
});
});
}
@@ -1,18 +1,9 @@
namespace ts {
describe("unittests:: tsbuild:: when containerOnly project is referenced", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromDisk("tests/projects/containerOnlyReferenced");
});
after(() => {
projFs = undefined!; // Release the contents
});
verifyTscIncrementalEdits({
scenario: "containerOnlyReferenced",
subScenario: "verify that subsequent builds after initial build doesnt build anything",
fs: () => projFs,
fs: () => loadProjectFromDisk("tests/projects/containerOnlyReferenced"),
commandLineArgs: ["--b", "/src", "--verbose"],
incrementalScenarios: [noChangeRun]
});
@@ -212,7 +212,7 @@ namespace ts {
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": null
"outDir": null,
"composite": true
},
"include": ["index.ts", "obj.json"]
@@ -1,16 +1,8 @@
namespace ts {
describe("unittests:: tsbuild:: lateBoundSymbol:: interface is merged and contains late bound member", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromDisk("tests/projects/lateBoundSymbol");
});
after(() => {
projFs = undefined!; // Release the contents
});
verifyTscIncrementalEdits({
subScenario: "interface is merged and contains late bound member",
fs: () => projFs,
fs: () => loadProjectFromDisk("tests/projects/lateBoundSymbol"),
scenario: "lateBoundSymbol",
commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"],
incrementalScenarios: [{
@@ -1,17 +0,0 @@
namespace ts {
describe("unittests:: tsbuild:: when tsconfig extends the missing file", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromDisk("tests/projects/missingExtendedConfig");
});
after(() => {
projFs = undefined!;
});
verifyTsc({
scenario: "missingExtendedConfig",
subScenario: "when tsconfig extends the missing file",
fs: () => projFs,
commandLineArgs: ["--b", "/src/tsconfig.json"],
});
});
}
@@ -1,16 +1,9 @@
namespace ts {
describe("unittests:: tsbuild - with noEmitOnError", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromDisk("tests/projects/noEmitOnError");
});
after(() => {
projFs = undefined!;
});
verifyTsc({
scenario: "noEmitOnError",
subScenario: "has empty files diagnostic when files is empty and no references are provided",
fs: () => projFs,
fs: () => loadProjectFromDisk("tests/projects/noEmitOnError"),
commandLineArgs: ["--b", "/src/tsconfig.json"],
});
});
+1 -1
View File
@@ -453,7 +453,7 @@ namespace ts {
function stripInternalOfThird(fs: vfs.FileSystem) {
replaceText(fs, sources[project.third][source.config], `"declaration": true,`, `"declaration": true,
"stripInternal": true`);
"stripInternal": true,`);
}
function stripInternalScenario(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) {
@@ -71,19 +71,10 @@ export default hello.hello`);
});
describe("unittests:: tsbuild:: with resolveJsonModule option on project importJsonFromProjectReference", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromDisk("tests/projects/importJsonFromProjectReference");
});
after(() => {
projFs = undefined!; // Release the contents
});
verifyTscIncrementalEdits({
scenario: "resolveJsonModule",
subScenario: "importing json module from project reference",
fs: () => projFs,
fs: () => loadProjectFromDisk("tests/projects/importJsonFromProjectReference"),
commandLineArgs: ["--b", "src/tsconfig.json", "--verbose"],
incrementalScenarios: [noChangeRun]
});
+61 -4
View File
@@ -1266,8 +1266,7 @@ const a = {
),
changes: [
sys => {
const content = sys.readFile(`${projectsLocation}/reexport/src/pure/session.ts`)!;
sys.writeFile(`${projectsLocation}/reexport/src/pure/session.ts`, content.replace("// ", ""));
replaceFileText(sys, `${projectsLocation}/reexport/src/pure/session.ts`, "// ", "");
sys.checkTimeoutQueueLengthAndRun(1); // build src/pure
sys.checkTimeoutQueueLengthAndRun(1); // build src/main
sys.checkTimeoutQueueLengthAndRun(1); // build src
@@ -1275,8 +1274,7 @@ const a = {
return "Introduce error";
},
sys => {
const content = sys.readFile(`${projectsLocation}/reexport/src/pure/session.ts`)!;
sys.writeFile(`${projectsLocation}/reexport/src/pure/session.ts`, content.replace("bar: ", "// bar: "));
replaceFileText(sys, `${projectsLocation}/reexport/src/pure/session.ts`, "bar: ", "// bar: ");
sys.checkTimeoutQueueLengthAndRun(1); // build src/pure
sys.checkTimeoutQueueLengthAndRun(1); // build src/main
sys.checkTimeoutQueueLengthAndRun(1); // build src
@@ -1286,4 +1284,63 @@ const a = {
]
});
});
describe("unittests:: tsbuild:: watchMode:: configFileErrors:: reports syntax errors in config file", () => {
verifyTscWatch({
scenario: "configFileErrors",
subScenario: "reports syntax errors in config file",
sys: () => createWatchedSystem(
[
{ path: `${projectRoot}/a.ts`, content: "export function foo() { }" },
{ path: `${projectRoot}/b.ts`, content: "export function bar() { }" },
{
path: `${projectRoot}/tsconfig.json`,
content: Utils.dedent`
{
"compilerOptions": {
"composite": true,
},
"files": [
"a.ts"
"b.ts"
]
}`
},
libFile
],
{ currentDirectory: projectRoot }
),
commandLineArgs: ["--b", "-w"],
changes: [
sys => {
replaceFileText(sys, `${projectRoot}/tsconfig.json`, ",", `,
"declaration": true,`);
sys.checkTimeoutQueueLengthAndRun(1); // build the project
sys.checkTimeoutQueueLength(0);
return "reports syntax errors after change to config file";
},
sys => {
replaceFileText(sys, `${projectRoot}/a.ts`, "foo", "fooBar");
sys.checkTimeoutQueueLengthAndRun(1); // build the project
sys.checkTimeoutQueueLength(0);
return "reports syntax errors after change to ts file";
},
sys => {
replaceFileText(sys, `${projectRoot}/tsconfig.json`, "", "");
sys.checkTimeoutQueueLengthAndRun(1); // build the project
sys.checkTimeoutQueueLength(0);
return "reports error when there is no change to tsconfig file";
},
sys => {
sys.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify({
compilerOptions: { composite: true, declaration: true },
files: ["a.ts", "b.ts"]
}));
sys.checkTimeoutQueueLengthAndRun(1); // build the project
sys.checkTimeoutQueueLength(0);
return "builds after fixing config file errors";
}
]
});
});
}
@@ -417,4 +417,9 @@ namespace ts.tscWatch {
});
});
}
export function replaceFileText(sys: WatchedSystem, file: string, searchValue: string | RegExp, replaceValue: string) {
const content = Debug.assertDefined(sys.readFile(file));
sys.writeFile(file, content.replace(searchValue, replaceValue));
}
}
@@ -1086,8 +1086,7 @@ export function two() {
});
function changeParameterTypeOfBFile(sys: WatchedSystem, parameterName: string, toType: string) {
const oldContent = sys.readFile(`${projectRoot}/b.ts`)!;
sys.writeFile(`${projectRoot}/b.ts`, oldContent.replace(new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`));
replaceFileText(sys, `${projectRoot}/b.ts`, new RegExp(`${parameterName}\: [a-z]*`), `${parameterName}: ${toType}`);
sys.runQueuedTimeoutCallbacks();
return `Changed ${parameterName} type to ${toType}`;
}