From d3040ab013ac8b67a2dbbb07229265e461106ac1 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Tue, 31 Oct 2017 23:07:51 +0100 Subject: [PATCH] report errors from parsing and validating tsconfig.json (#3410) --- src/linter.ts | 22 +++++++++++-- test/executable/executableTests.ts | 31 +++++++++++++++++++ test/files/tsconfig-invalid/empty-files.json | 3 ++ test/files/tsconfig-invalid/no-match.json | 5 +++ test/files/tsconfig-invalid/syntax-error.json | 1 + 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 test/files/tsconfig-invalid/empty-files.json create mode 100644 test/files/tsconfig-invalid/no-match.json create mode 100644 test/files/tsconfig-invalid/syntax-error.json diff --git a/src/linter.ts b/src/linter.ts index 00749eff108..c5c4143f386 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -57,14 +57,32 @@ class Linter { * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. */ public static createProgram(configFile: string, projectDirectory: string = path.dirname(configFile)): ts.Program { - const { config } = ts.readConfigFile(configFile, ts.sys.readFile); + const config = ts.readConfigFile(configFile, ts.sys.readFile); + if (config.error !== undefined) { + throw new FatalError(ts.formatDiagnostics([config.error], { + getCanonicalFileName: (f) => f, + getCurrentDirectory: process.cwd, + getNewLine: () => "\n", + })); + } const parseConfigHost: ts.ParseConfigHost = { fileExists: fs.existsSync, readDirectory: ts.sys.readDirectory, readFile: (file) => fs.readFileSync(file, "utf8"), useCaseSensitiveFileNames: true, }; - const parsed = ts.parseJsonConfigFileContent(config, parseConfigHost, path.resolve(projectDirectory), {noEmit: true}); + const parsed = ts.parseJsonConfigFileContent(config.config, parseConfigHost, path.resolve(projectDirectory), {noEmit: true}); + if (parsed.errors !== undefined) { + // ignore warnings and 'TS18003: No inputs were found in config file ...' + const errors = parsed.errors.filter((d) => d.category === ts.DiagnosticCategory.Error && d.code !== 18003); + if (errors.length !== 0) { + throw new FatalError(ts.formatDiagnostics(errors, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: process.cwd, + getNewLine: () => "\n", + })); + } + } const host = ts.createCompilerHost(parsed.options, true); const program = ts.createProgram(parsed.fileNames, parsed.options, host); diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index 1ce5759e282..cb3076de004 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -392,6 +392,37 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { }); }); + it("reports errors from parsing tsconfig.json", (done) => { + execCli( + ["-p", "test/files/tsconfig-invalid/syntax-error.json"], + (err, _stdout, stderr) => { + assert.isNotNull(err, "process should exit with an error"); + assert.equal(err.code, 1, "exit code should be 1"); + assert.include(stderr, "error TS"); + done(); + }); + }); + + it("reports errors from validating tsconfig.json", (done) => { + execCli( + ["-p", "test/files/tsconfig-invalid/empty-files.json"], + (err, _stdout, stderr) => { + assert.isNotNull(err, "process should exit with an error"); + assert.equal(err.code, 1, "exit code should be 1"); + assert.include(stderr, "error TS"); + done(); + }); + }); + + it("does not report an error if tsconfig.json matches no files", (done) => { + execCli( + ["-p", "test/files/tsconfig-invalid/no-match.json"], + (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + it("can extend `tsconfig.json` with relative path", (done) => { execCli( ["-c", "test/files/tsconfig-extends-relative/tslint-ok.json", "-p", diff --git a/test/files/tsconfig-invalid/empty-files.json b/test/files/tsconfig-invalid/empty-files.json new file mode 100644 index 00000000000..158547c24cd --- /dev/null +++ b/test/files/tsconfig-invalid/empty-files.json @@ -0,0 +1,3 @@ +{ + "files": [] +} diff --git a/test/files/tsconfig-invalid/no-match.json b/test/files/tsconfig-invalid/no-match.json new file mode 100644 index 00000000000..667e8fa7108 --- /dev/null +++ b/test/files/tsconfig-invalid/no-match.json @@ -0,0 +1,5 @@ +{ + "include": [ + "*.js" + ] +} diff --git a/test/files/tsconfig-invalid/syntax-error.json b/test/files/tsconfig-invalid/syntax-error.json new file mode 100644 index 00000000000..7edb2fa5bce --- /dev/null +++ b/test/files/tsconfig-invalid/syntax-error.json @@ -0,0 +1 @@ +,