diff --git a/packages/babel-core/src/transformation/file/options/build-config-chain.js b/packages/babel-core/src/transformation/file/options/build-config-chain.js index 5542072f69..5902d4c16e 100644 --- a/packages/babel-core/src/transformation/file/options/build-config-chain.js +++ b/packages/babel-core/src/transformation/file/options/build-config-chain.js @@ -1,4 +1,3 @@ - import type Logger from "../logger"; import resolve from "../../../helpers/resolve"; import json5 from "json5"; @@ -8,9 +7,10 @@ import fs from "fs"; const existsCache = {}; const jsonCache = {}; -const BABELIGNORE_FILENAME = ".babelignore"; const BABELRC_FILENAME = ".babelrc"; +const BABELRC_JS_FILENAME = ".babelrc.js"; const PACKAGE_FILENAME = "package.json"; +const BABELIGNORE_FILENAME = ".babelignore"; function exists(filename) { const cached = existsCache[filename]; @@ -46,7 +46,12 @@ class ConfigChainBuilder { this.log = log; } - findConfigs(loc) { + errorMultipleConfigs(loc1: string, loc2: string) { + throw new Error(`Multiple configuration files found. Please remove one:\n- ${ + loc1}\n- ${loc2}`); + } + + findConfigs(loc: string) { if (!loc) return; if (!path.isAbsolute(loc)) { @@ -59,15 +64,26 @@ class ConfigChainBuilder { while (loc !== (loc = path.dirname(loc))) { if (!foundConfig) { const configLoc = path.join(loc, BABELRC_FILENAME); - if (exists(configLoc)) { - this.addConfig(configLoc); - foundConfig = true; - } - + const configJSLoc = path.join(loc, BABELRC_JS_FILENAME); const pkgLoc = path.join(loc, PACKAGE_FILENAME); - if (!foundConfig && exists(pkgLoc)) { - foundConfig = this.addConfig(pkgLoc, "babel", JSON); - } + const configLocs = [configLoc, configJSLoc, pkgLoc]; + const foundConfigs = configLocs.reduce((arr, config) => { + if (exists(config)) { + const configAdded = config === pkgLoc + ? this.addConfig(config, "babel", JSON) + : this.addConfig(config); + + if (configAdded && arr.length) { + this.errorMultipleConfigs(arr.pop(), config); + } + + arr.push(config); + } + + return arr; + }, []); + + foundConfig = !!foundConfigs.length; } if (!foundIgnore) { @@ -82,7 +98,7 @@ class ConfigChainBuilder { } } - addIgnoreConfig(loc) { + addIgnoreConfig(loc: string) { const file = fs.readFileSync(loc, "utf8"); let lines = file.split("\n"); @@ -106,15 +122,35 @@ class ConfigChainBuilder { this.resolvedConfigs.push(loc); - const content = fs.readFileSync(loc, "utf8"); let options; + if (path.extname(loc) === ".js") { + try { + const configModule = require(loc); + options = configModule && configModule.__esModule ? configModule.default : configModule; + } catch (err) { + err.message = `${loc}: Error while loading config - ${err.message}`; + throw err; + } - try { - options = jsonCache[content] = jsonCache[content] || json.parse(content); - if (key) options = options[key]; - } catch (err) { - err.message = `${loc}: Error while parsing JSON - ${err.message}`; - throw err; + if (!options || typeof options !== "object") { + throw new Error("Configuration should be an exported JavaScript object."); + } + } else { + const content = fs.readFileSync(loc, "utf8"); + try { + options = jsonCache[content] = jsonCache[content] || json.parse(content); + } catch (err) { + err.message = `${loc}: Error while parsing JSON - ${err.message}`; + throw err; + } + } + + if (key) { + if (!options[key]) { + return false; + } + + options = options[key]; } this.mergeConfig({ diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index 5032973e7d..f317eca7d8 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -294,4 +294,253 @@ describe("buildConfigChain", function () { assert.deepEqual(chain, expected); }); + + it("js-config", function () { + const chain = buildConfigChain({ + filename: fixture("js-config", "src.js"), + }); + + const expected = [ + { + options: { + plugins: [ + "foo", + "bar", + ], + }, + alias: fixture("js-config", ".babelrc.js"), + loc: fixture("js-config", ".babelrc.js"), + dirname: fixture("js-config"), + }, + { + options: { + ignore: [ + "root-ignore", + ], + }, + alias: fixture(".babelignore"), + loc: fixture(".babelignore"), + dirname: fixture(), + }, + { + options: { + filename: fixture("js-config", "src.js"), + }, + alias: "base", + loc: "base", + dirname: fixture("js-config"), + }, + ]; + + assert.deepEqual(chain, expected); + }); + + it("js-config-default - should read transpiled export default", function () { + const chain = buildConfigChain({ + filename: fixture("js-config-default", "src.js"), + }); + + const expected = [ + { + options: { + plugins: [ + "foo", + "bar", + ], + }, + alias: fixture("js-config-default", ".babelrc.js"), + loc: fixture("js-config-default", ".babelrc.js"), + dirname: fixture("js-config-default"), + }, + { + options: { + ignore: [ + "root-ignore", + ], + }, + alias: fixture(".babelignore"), + loc: fixture(".babelignore"), + dirname: fixture(), + }, + { + options: { + filename: fixture("js-config-default", "src.js"), + }, + alias: "base", + loc: "base", + dirname: fixture("js-config-default"), + }, + ]; + + assert.deepEqual(chain, expected); + }); + it("js-config-extended", function () { + const chain = buildConfigChain({ + filename: fixture("js-config-extended", "src.js"), + }); + + const expected = [ + { + options: { + plugins: [ + "extended", + ], + }, + alias: fixture("extended.babelrc.json"), + loc: fixture("extended.babelrc.json"), + dirname: fixture(), + }, + { + options: { + plugins: [ + "foo", + "bar", + ], + }, + alias: fixture("js-config-extended", ".babelrc.js"), + loc: fixture("js-config-extended", ".babelrc.js"), + dirname: fixture("js-config-extended"), + }, + { + options: { + ignore: [ + "root-ignore", + ], + }, + alias: fixture(".babelignore"), + loc: fixture(".babelignore"), + dirname: fixture(), + }, + { + options: { + filename: fixture("js-config-extended", "src.js"), + }, + alias: "base", + loc: "base", + dirname: fixture("js-config-extended"), + }, + ]; + + assert.deepEqual(chain, expected); + }); + + it("json-pkg-config-no-babel - should not throw if" + + " package.json doesn't contain a `babel` field", function () { + const chain = buildConfigChain({ + filename: fixture("json-pkg-config-no-babel", "src.js"), + }); + + const expected = [ + { + options: { + plugins: [ + "json", + ], + }, + alias: fixture("json-pkg-config-no-babel", ".babelrc"), + loc: fixture("json-pkg-config-no-babel", ".babelrc"), + dirname: fixture("json-pkg-config-no-babel"), + }, + { + options: { + ignore: [ + "root-ignore", + ], + }, + alias: fixture(".babelignore"), + loc: fixture(".babelignore"), + dirname: fixture(), + }, + { + options: { + filename: fixture("json-pkg-config-no-babel", "src.js"), + }, + alias: "base", + loc: "base", + dirname: fixture("json-pkg-config-no-babel"), + }, + ]; + + assert.deepEqual(chain, expected); + }); + + it("js-json-config - should throw an error if both a .babelrc" + + " and a .babelrc.js are present", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("js-json-config", "src.js"), + }); + }, + /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*\.babelrc\.js/ + ); + }); + + it("js-pkg-config - should throw an error if both a .babelrc.js" + + " and a package.json with a babel field are present", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("js-pkg-config", "src.js"), + }); + }, + /Multiple configuration files found\.(.|\n)*\.babelrc\.js(.|\n)*package\.json/ + ); + }); + + it("json-pkg-config - should throw an error if both a .babelrc" + + " and a package.json with a babel field are present", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("json-pkg-config", "src.js"), + }); + }, + /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*package\.json/ + ); + }); + + it("js-config-error", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("js-config-error", "src.js"), + }); + }, + /Error while loading config/ + ); + }); + + it("js-config-error2", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("js-config-error2", "src.js"), + }); + }, + /Configuration should be an exported JavaScript object/ + ); + }); + + it("js-config-error3", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("js-config-error3", "src.js"), + }); + }, + /Configuration should be an exported JavaScript object/ + ); + }); + + it("json-config-error", function () { + assert.throws( + function () { + buildConfigChain({ + filename: fixture("json-config-error", "src.js"), + }); + }, + /Error while parsing JSON/ + ); + }); }); diff --git a/packages/babel-core/test/fixtures/config/js-config-default/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config-default/.babelrc.js new file mode 100644 index 0000000000..de5f1c0244 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-default/.babelrc.js @@ -0,0 +1,10 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var plugins = ["foo", "bar"]; + +exports.default = { + plugins: plugins +}; diff --git a/packages/babel-core/test/fixtures/config/js-config-default/src.js b/packages/babel-core/test/fixtures/config/js-config-default/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-default/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-config-error/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config-error/.babelrc.js new file mode 100644 index 0000000000..d14a2b71a8 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error/.babelrc.js @@ -0,0 +1,2 @@ +throw new Error("Something bad happened!"); +module.exports = {} diff --git a/packages/babel-core/test/fixtures/config/js-config-error/src.js b/packages/babel-core/test/fixtures/config/js-config-error/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-config-error2/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config-error2/.babelrc.js new file mode 100644 index 0000000000..9dc5fc1e4a --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error2/.babelrc.js @@ -0,0 +1 @@ +module.exports = ''; diff --git a/packages/babel-core/test/fixtures/config/js-config-error2/src.js b/packages/babel-core/test/fixtures/config/js-config-error2/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error2/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-config-error3/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config-error3/.babelrc.js new file mode 100644 index 0000000000..b894a23a24 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error3/.babelrc.js @@ -0,0 +1 @@ +module.exports = null; diff --git a/packages/babel-core/test/fixtures/config/js-config-error3/src.js b/packages/babel-core/test/fixtures/config/js-config-error3/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-error3/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-config-extended/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config-extended/.babelrc.js new file mode 100644 index 0000000000..05741c6ef8 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-extended/.babelrc.js @@ -0,0 +1,6 @@ +var plugins = ["foo", "bar"]; + +module.exports = { + extends: "../extended.babelrc.json", + plugins: plugins +} diff --git a/packages/babel-core/test/fixtures/config/js-config-extended/src.js b/packages/babel-core/test/fixtures/config/js-config-extended/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config-extended/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-config/.babelrc.js b/packages/babel-core/test/fixtures/config/js-config/.babelrc.js new file mode 100644 index 0000000000..e6fa0742df --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config/.babelrc.js @@ -0,0 +1,5 @@ +var plugins = ["foo", "bar"]; + +module.exports = { + plugins: plugins +} diff --git a/packages/babel-core/test/fixtures/config/js-config/src.js b/packages/babel-core/test/fixtures/config/js-config/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-config/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-json-config/.babelrc b/packages/babel-core/test/fixtures/config/js-json-config/.babelrc new file mode 100644 index 0000000000..c80e833d70 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-json-config/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + "json" + ] +} diff --git a/packages/babel-core/test/fixtures/config/js-json-config/.babelrc.js b/packages/babel-core/test/fixtures/config/js-json-config/.babelrc.js new file mode 100644 index 0000000000..71bb3e5762 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-json-config/.babelrc.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + "js" + ] +} diff --git a/packages/babel-core/test/fixtures/config/js-json-config/src.js b/packages/babel-core/test/fixtures/config/js-json-config/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-json-config/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/js-pkg-config/.babelrc.js b/packages/babel-core/test/fixtures/config/js-pkg-config/.babelrc.js new file mode 100644 index 0000000000..71bb3e5762 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-pkg-config/.babelrc.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + "js" + ] +} diff --git a/packages/babel-core/test/fixtures/config/js-pkg-config/package.json b/packages/babel-core/test/fixtures/config/js-pkg-config/package.json new file mode 100644 index 0000000000..e25be3ecd2 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-pkg-config/package.json @@ -0,0 +1,3 @@ +{ + "babel": {} +} diff --git a/packages/babel-core/test/fixtures/config/js-pkg-config/src.js b/packages/babel-core/test/fixtures/config/js-pkg-config/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/js-pkg-config/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/json-config-error/.babelrc b/packages/babel-core/test/fixtures/config/json-config-error/.babelrc new file mode 100644 index 0000000000..a07fde17a3 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-config-error/.babelrc @@ -0,0 +1,3 @@ +{ + "bad: "json" +} diff --git a/packages/babel-core/test/fixtures/config/json-config-error/src.js b/packages/babel-core/test/fixtures/config/json-config-error/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-config-error/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/.babelrc b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/.babelrc new file mode 100644 index 0000000000..c80e833d70 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + "json" + ] +} diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/package.json b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/package.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/src.js b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config-no-babel/src.js @@ -0,0 +1 @@ +// empty diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config/.babelrc b/packages/babel-core/test/fixtures/config/json-pkg-config/.babelrc new file mode 100644 index 0000000000..c80e833d70 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + "json" + ] +} diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config/package.json b/packages/babel-core/test/fixtures/config/json-pkg-config/package.json new file mode 100644 index 0000000000..e25be3ecd2 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config/package.json @@ -0,0 +1,3 @@ +{ + "babel": {} +} diff --git a/packages/babel-core/test/fixtures/config/json-pkg-config/src.js b/packages/babel-core/test/fixtures/config/json-pkg-config/src.js new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/json-pkg-config/src.js @@ -0,0 +1 @@ +// empty