diff --git a/lib/config/config-file.js b/lib/config/config-file.js index dde79cb40c8..f76b92830c4 100644 --- a/lib/config/config-file.js +++ b/lib/config/config-file.js @@ -280,15 +280,38 @@ function writeYAMLConfigFile(config, filePath) { * Writes a configuration file in JavaScript format. * @param {Object} config The configuration object to write. * @param {string} filePath The filename to write to. + * @throws {Error} If an error occurs linting the config file contents. * @returns {void} * @private */ function writeJSConfigFile(config, filePath) { debug(`Writing JS config file: ${filePath}`); - const content = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};`; + let contentToWrite; + const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};`; - fs.writeFileSync(filePath, content, "utf8"); + try { + const CLIEngine = require("../cli-engine"); + const linter = new CLIEngine({ + baseConfig: config, + fix: true, + useEslintrc: false + }); + const report = linter.executeOnText(stringifiedContent); + + contentToWrite = report.results[0].output || stringifiedContent; + } catch (e) { + debug("Error linting JavaScript config file, writing unlinted version"); + const errorMessage = e.message; + + contentToWrite = stringifiedContent; + e.message = "An error occurred while generating your JavaScript config file. "; + e.message += "A config file was still generated, but the config file itself may not follow your linting rules."; + e.message += `\nError: ${errorMessage}`; + throw e; + } finally { + fs.writeFileSync(filePath, contentToWrite, "utf8"); + } } /** diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js index 944ed84260f..c884c7b155b 100644 --- a/tests/lib/config/config-file.js +++ b/tests/lib/config/config-file.js @@ -20,6 +20,7 @@ const Module = require("module"), espree = require("espree"), ConfigFile = require("../../../lib/config/config-file"), Linter = require("../../../lib/linter"), + CLIEngine = require("../../../lib/cli-engine"), Config = require("../../../lib/config"); const userHome = os.homedir(); @@ -1262,6 +1263,51 @@ describe("ConfigFile", () => { }); + it("should make sure js config files match linting rules", () => { + const fakeFS = leche.fake(fs); + + const singleQuoteConfig = { + rules: { + quotes: [2, "single"] + } + }; + + sandbox.mock(fakeFS).expects("writeFileSync").withExactArgs( + "test-config.js", + sinon.match(value => !value.includes("\"")), + "utf8" + ); + + const StubbedConfigFile = proxyquire("../../../lib/config/config-file", { + fs: fakeFS + }); + + StubbedConfigFile.write(singleQuoteConfig, "test-config.js"); + }); + + it("should still write a js config file even if linting fails", () => { + const fakeFS = leche.fake(fs); + const fakeCLIEngine = sandbox.mock().withExactArgs(sinon.match({ + baseConfig: config, + fix: true, + useEslintrc: false + })); + + fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype); + sandbox.stub(fakeCLIEngine.prototype, "executeOnText").throws(); + + sandbox.mock(fakeFS).expects("writeFileSync").once(); + + const StubbedConfigFile = proxyquire("../../../lib/config/config-file", { + fs: fakeFS, + "../cli-engine": fakeCLIEngine + }); + + assert.throws(() => { + StubbedConfigFile.write(config, "test-config.js"); + }); + }); + it("should throw error if file extension is not valid", () => { assert.throws(() => { ConfigFile.write({}, getFixturePath("yaml/.eslintrc.class"));