diff --git a/packages/babel-core/src/transformation/file/options/option-manager.js b/packages/babel-core/src/transformation/file/options/option-manager.js index 808f8947f4..b14bdd1059 100644 --- a/packages/babel-core/src/transformation/file/options/option-manager.js +++ b/packages/babel-core/src/transformation/file/options/option-manager.js @@ -281,8 +281,20 @@ export default class OptionManager { val = require(presetLoc); } - // If the imported preset is a transpiled ES2015 module, grab the default export. - if (typeof val === "object" && val.__esModule) val = val.default; + // If the imported preset is a transpiled ES2015 module + if (typeof val === "object" && val.__esModule) { + // Try to grab the default export. + if (val.default) { + val = val.default; + } else { + // If there is no default export we treat all named exports as options + // and just remove the __esModule. This is to support presets that have been + // exporting named exports in the past, although we definitely want presets to + // only use the default export (with either an object or a function) + const { __esModule, ...rest } = val; // eslint-disable-line no-unused-vars + val = rest; + } + } // For compatibility with babel-core < 6.13.x, allow presets to export an object with a // a 'buildPreset' function that will return the preset itself, while still exporting a diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default.js new file mode 100644 index 0000000000..47cfcd223d --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default.js @@ -0,0 +1,12 @@ +// from code: +// export default { +// plugins: [ +// require('../../../../../babel-plugin-syntax-decorators'), +// ] +// }; +'use strict'; + +exports.__esModule = true; +exports.default = { + plugins: [require('../../../../../babel-plugin-syntax-decorators')] +}; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js new file mode 100644 index 0000000000..25ea910dec --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_function.js @@ -0,0 +1,17 @@ +// from code: +// export default function() { +// return { +// plugins: [require('../../../../../babel-plugin-syntax-decorators'),] +// }; +// } +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +exports.default = function () { + return { + plugins: [require('../../../../../babel-plugin-syntax-decorators')] + }; +}; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object_function.js new file mode 100644 index 0000000000..b5f1eef249 --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_default_object_function.js @@ -0,0 +1,18 @@ +// from code: +// export default { +// buildPreset: function() { +// return { +// plugins: [require('../../../../../babel-plugin-syntax-decorators'),] +// }; +// } +// } +'use strict'; + +exports.__esModule = true; +exports.default = { + buildPreset: function buildPreset() { + return { + plugins: [require('../../../../../babel-plugin-syntax-decorators')] + }; + } +}; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_function.js new file mode 100644 index 0000000000..eddcf7e294 --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_function.js @@ -0,0 +1,17 @@ +// from code: +// export const buildPreset = function() { +// return { +// plugins: [require('../../../../../babel-plugin-syntax-decorators'),] +// }; +// } +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var buildPreset = exports.buildPreset = function buildPreset() { + return { + plugins: [require('../../../../../babel-plugin-syntax-decorators')] + }; +}; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_function_fallback.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_function_fallback.js new file mode 100644 index 0000000000..d0c11d0258 --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_function_fallback.js @@ -0,0 +1,50 @@ +// from code: +// function preset() { +// return { +// plugins: [ +// require('../../../../../babel-plugin-syntax-decorators'), +// ] +// }; +// } +// +// const oldConfig = preset(); +// +// export default oldConfig; +// +// // However, for backward compatibility with babel-core < v6.13.x, we use the 'buildPreset' +// // property of the preset object for the preset creation function with the enumerability +// // caveat mentioned below. +// Object.defineProperty(oldConfig, "buildPreset", { +// configurable: true, +// writable: true, +// // We make this non-enumerable so old versions of babel-core won't see it as an unknown property, +// // while allowing new versions to see it as a preset builder function. +// enumerable: false, +// value: preset, +// }); +// + +"use strict"; + +exports.__esModule = true; +function preset() { + return { + plugins: [require('../../../../../babel-plugin-syntax-decorators')] + }; +} + +var oldConfig = preset(); + +exports.default = oldConfig; + +// However, for backward compatibility with babel-core < v6.13.x, we use the 'buildPreset' +// property of the preset object for the preset creation function with the enumerability +// caveat mentioned below. +Object.defineProperty(oldConfig, "buildPreset", { + configurable: true, + writable: true, + // We make this non-enumerable so old versions of babel-core won't see it as an unknown property, + // while allowing new versions to see it as a preset builder function. + enumerable: false, + value: preset +}); diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js b/packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js new file mode 100644 index 0000000000..dd3b12968d --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js @@ -0,0 +1,8 @@ +// from code: +// export const plugins = [ +// require('../../../../../babel-plugin-syntax-decorators'), +// ]; +'use strict'; + +exports.__esModule = true; +var plugins = exports.plugins = [require('../../../../../babel-plugin-syntax-decorators')]; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es5.js b/packages/babel-core/test/fixtures/option-manager/presets/es5.js new file mode 100644 index 0000000000..95cde4c4bf --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es5.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('../../../../../babel-plugin-syntax-decorators'), + ] +}; diff --git a/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js b/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js new file mode 100644 index 0000000000..31648d0600 --- /dev/null +++ b/packages/babel-core/test/fixtures/option-manager/presets/es5_function.js @@ -0,0 +1,9 @@ +module.exports = { + buildPreset: function () { + return { + plugins: [ + require('../../../../../babel-plugin-syntax-decorators'), + ] + }; + } +}; diff --git a/packages/babel-core/test/option-manager.js b/packages/babel-core/test/option-manager.js index c577723bdb..63f53b5d88 100644 --- a/packages/babel-core/test/option-manager.js +++ b/packages/babel-core/test/option-manager.js @@ -31,7 +31,8 @@ suite("option-manager", function () { }, /Unknown option: base.randomOption/ ); - }) + }); + test("throws for removed babel 5 options", function() { return assert.throws( function () { @@ -43,17 +44,42 @@ suite("option-manager", function () { }, /Using removed Babel 5 option: base.auxiliaryComment - Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`/ ); - }) + }); + test("throws for resolved but erroring preset", function() { return assert.throws( function () { var opt = new OptionManager(new Logger(null, "unknown")); opt.init({ - 'presets': [path.resolve(__dirname, "fixtures", "option-manager", "not-a-preset")] + 'presets': [path.join(__dirname, "fixtures/option-manager/not-a-preset")] }); }, /While processing preset: .*option-manager(?:\/|\\\\)not-a-preset\.js/ ); - }) + }); + }); + + suite("presets", function () { + function presetTest(name) { + test(name, function () { + var opt = new OptionManager(new Logger(null, "unknown")); + var options = opt.init({ + 'presets': [path.join(__dirname, "fixtures/option-manager/presets", name)] + }); + + assert.equal(true, Array.isArray(options.plugins)); + assert.equal(1, options.plugins.length); + }); + } + + presetTest('es5'); + presetTest('es5_function'); + presetTest('es2015_default'); + presetTest('es2015_default_function'); + presetTest('es2015_default_object_function'); + presetTest('es2015_function'); + presetTest('es2015_function_fallback'); + presetTest('es2015_named'); + }); });