[7.0] Remove bc code from preset handling and preset-es2015 (#5128)

* Remove bc code from preset handling and preset-es2015

* Add more tests

* Only allow functions for presets

* Fix lint
This commit is contained in:
Daniel Tschinder
2017-02-22 14:58:01 +01:00
committed by GitHub
parent 45087b258b
commit 87ca6150ae
21 changed files with 185 additions and 303 deletions

View File

@@ -181,12 +181,10 @@ export default class OptionManager {
this.log.error(`Using removed Babel 5 option: ${alias}.${key} - ${removed[key].message}`,
ReferenceError);
} else {
/* eslint-disable max-len */
// eslint-disable-next-line max-len
const unknownOptErr = `Unknown option: ${alias}.${key}. Check out http://babeljs.io/docs/usage/options/ for more information about options.`;
const presetConfigErr = "A common cause of this error is the presence of a configuration options object without the corresponding preset name. Example:\n\nInvalid:\n `{ presets: [{option: value}] }`\nValid:\n `{ presets: [['presetName', {option: value}]] }`\n\nFor more detailed information on preset configuration, please see http://babeljs.io/docs/plugins/#pluginpresets-options.";
/* eslint-enable max-len */
this.log.error(`${unknownOptErr}\n\n${presetConfigErr}`, ReferenceError);
this.log.error(unknownOptErr, ReferenceError);
}
}
}
@@ -250,72 +248,65 @@ export default class OptionManager {
* or a module name to require.
*/
resolvePresets(presets: Array<string | Object>, dirname: string, onResolve?) {
return presets.map((val) => {
return presets.map((preset) => {
let options;
if (Array.isArray(val)) {
if (val.length > 2) {
throw new Error(`Unexpected extra options ${JSON.stringify(val.slice(2))} passed to preset.`);
if (Array.isArray(preset)) {
if (preset.length > 2) {
throw new Error(`Unexpected extra options ${JSON.stringify(preset.slice(2))} passed to preset.`);
}
[val, options] = val;
[preset, options] = preset;
}
let presetLoc;
try {
if (typeof val === "string") {
presetLoc = resolvePreset(val, dirname);
if (typeof preset === "string") {
presetLoc = resolvePreset(preset, dirname);
if (!presetLoc) {
throw new Error(`Couldn't find preset ${JSON.stringify(val)} relative to directory ` +
throw new Error(`Couldn't find preset ${JSON.stringify(preset)} relative to directory ` +
JSON.stringify(dirname));
}
val = require(presetLoc);
}
const presetFactory = this.getPresetFactoryForPreset(presetLoc || preset);
// 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;
}
}
preset = presetFactory(context, options);
// 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
// simple object (rather than a function), for supporting old Babel versions.
if (typeof val === "object" && val.buildPreset) val = val.buildPreset;
if (typeof val !== "function" && options !== undefined) {
throw new Error(`Options ${JSON.stringify(options)} passed to ` +
(presetLoc || "a preset") + " which does not accept options.");
}
if (typeof val === "function") val = val(context, options);
if (typeof val !== "object") {
throw new Error(`Unsupported preset format: ${val}.`);
}
onResolve && onResolve(val, presetLoc);
if (onResolve) onResolve(preset, presetLoc);
} catch (e) {
if (presetLoc) {
e.message += ` (While processing preset: ${JSON.stringify(presetLoc)})`;
}
throw e;
}
return val;
return preset;
});
}
getPresetFactoryForPreset(preset) {
let presetFactory = preset;
if (typeof presetFactory === "string") {
presetFactory = require(presetFactory);
}
// If the imported preset is a transpiled ES2015 module
if (typeof presetFactory === "object" && presetFactory.__esModule) {
if (presetFactory.default) {
presetFactory = presetFactory.default;
} else {
throw new Error("Preset must export a default export when using ES6 modules.");
}
}
if (typeof presetFactory !== "function") {
// eslint-disable-next-line max-len
throw new Error(`Unsupported preset format: ${typeof presetFactory}. Expected preset to return a function.`);
}
return presetFactory;
}
normaliseOptions() {
const opts = this.options;

View File

@@ -194,38 +194,42 @@ describe("api", function () {
passPerPreset: passPerPreset,
presets: [
// First preset with our plugin, "before"
{
plugins: [
new Plugin({
visitor: {
Function: function(path) {
const alias = path.scope.getProgramParent().path.get("body")[0].node;
if (!babel.types.isTypeAlias(alias)) return;
function () {
return {
plugins: [
new Plugin({
visitor: {
Function: function (path) {
const alias = path.scope.getProgramParent().path.get("body")[0].node;
if (!babel.types.isTypeAlias(alias)) return;
// In case of `passPerPreset` being `false`, the
// alias node is already removed by Flow plugin.
if (!alias) {
return;
// In case of `passPerPreset` being `false`, the
// alias node is already removed by Flow plugin.
if (!alias) {
return;
}
// In case of `passPerPreset` being `true`, the
// alias node should still exist.
aliasBaseType = alias.right.type; // NumberTypeAnnotation
}
// In case of `passPerPreset` being `true`, the
// alias node should still exist.
aliasBaseType = alias.right.type; // NumberTypeAnnotation
}
}
})
]
})
]
};
},
// ES2015 preset
require(__dirname + "/../../babel-preset-es2015"),
// Third preset for Flow.
{
plugins: [
require(__dirname + "/../../babel-plugin-syntax-flow"),
require(__dirname + "/../../babel-plugin-transform-flow-strip-types"),
]
function () {
return {
plugins: [
require(__dirname + "/../../babel-plugin-syntax-flow"),
require(__dirname + "/../../babel-plugin-transform-flow-strip-types"),
]
};
}
],
});

View File

@@ -1,3 +1,3 @@
module.exports = function () {
throw new Error('Not a real preset');
}
};

View File

@@ -1,18 +0,0 @@
// 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')]
};
}
};

View File

@@ -1,17 +0,0 @@
// 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')]
};
};

View File

@@ -1,50 +0,0 @@
// 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
});

View File

@@ -1,9 +1,7 @@
module.exports = {
buildPreset: function () {
return {
plugins: [
require('../../../../../babel-plugin-syntax-decorators'),
]
};
}
module.exports = function () {
return {
plugins: [
require('../../../../../babel-plugin-syntax-decorators'),
]
};
};

View File

@@ -0,0 +1,2 @@
'use strict';
module.exports = "invalid";

View File

@@ -1,5 +1,7 @@
module.exports = {
plugins: [plugin],
module.exports = function () {
return {
plugins: [plugin],
}
};
function plugin () {

View File

@@ -51,19 +51,6 @@ describe("option-manager", () => {
/While processing preset: .*option-manager(?:\/|\\\\)not-a-preset\.js/
);
});
it("throws for invalid preset configuration", function() {
return assert.throws(
function () {
const opt = new OptionManager(new Logger(null, "unknown"));
opt.init({
"presets": [{ option: "value" }]
});
},
// eslint-disable-next-line max-len
/Unknown option: foreign.option\.(?:.|\n)+A common cause of this error is the presence of a configuration options object without the corresponding preset name/
);
});
});
describe("presets", function () {
@@ -79,14 +66,21 @@ describe("option-manager", () => {
});
}
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");
function presetThrowsTest(name, msg) {
it(name, function () {
const opt = new OptionManager(new Logger(null, "unknown"));
assert.throws(() => opt.init({
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)]
}), msg);
});
}
presetTest("es5_function");
presetTest("es2015_default_function");
presetThrowsTest("es5", /Expected preset to return a function./);
presetThrowsTest("es2015_default", /Expected preset to return a function./);
presetThrowsTest("es2015_named", /Preset must export a default export when using ES6 modules/);
presetThrowsTest("es5_invalid", /Unsupported preset format: string/);
});
});

View File

@@ -1,11 +1,3 @@
/**
* This file is not the canonical way of writing a Babel preset since it strives for
* backward compatibility with babel-core < v6.13.x. If you're looking at it as a
* reference for how to write a preset, it's probably best to look at the other presets
* such as babel-preset-es2016 & babel-preset-latest noting that the former example
* exports via a default object and the latter via a default function.
*/
import transformES2015TemplateLiterals from "babel-plugin-transform-es2015-template-literals";
import transformES2015Literals from "babel-plugin-transform-es2015-literals";
import transformES2015FunctionName from "babel-plugin-transform-es2015-function-name";
@@ -31,7 +23,7 @@ import transformES2015ModulesAMD from "babel-plugin-transform-es2015-modules-amd
import transformES2015ModulesUMD from "babel-plugin-transform-es2015-modules-umd";
import transformRegenerator from "babel-plugin-transform-regenerator";
function preset(context, opts = {}) {
export default function (context, opts = {}) {
const moduleTypes = ["commonjs", "amd", "umd", "systemjs"];
let loose = false;
let modules = "commonjs";
@@ -82,24 +74,3 @@ function preset(context, opts = {}) {
].filter(Boolean) // filter out falsy values
};
}
/**
* This preset was originally an object, before function-based configurable presets were introduced.
* For backward-compatibility with anything that may have been loading this preset and expecting
* it to be a simple Babel config object, we export the old config here via default object.
*/
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,
});

View File

@@ -2,18 +2,10 @@ import es2015 from "../lib";
import { expect } from "chai";
describe("es2015 preset", function () {
it("exposes an object", function () {
// Changing this will break compatibility with babel-core < 6.13.x.
expect(typeof es2015).to.equal("object");
});
it("exposes a separate list of plugins", function () {
expect(Array.isArray(es2015.plugins)).to.equal(true);
});
it("doesn't throw with no options passed", function () {
expect(function () {
es2015.buildPreset(null);
es2015(null);
}).not.to.throw();
});
@@ -21,7 +13,7 @@ describe("es2015 preset", function () {
describe("loose", function () {
it("throws on non-boolean value", function () {
expect(function () {
es2015.buildPreset(null, { loose: 1 });
es2015(null, { loose: 1 });
}).to.throw(/must be a boolean/);
});
});
@@ -29,25 +21,25 @@ describe("es2015 preset", function () {
describe("modules", function () {
it("doesn't throw when passing one false", function () {
expect(function () {
es2015.buildPreset(null, { modules: false });
es2015(null, { modules: false });
}).not.to.throw();
});
it("doesn't throw when passing one of: 'commonjs', 'amd', 'umd', 'systemjs", function () {
expect(function () {
es2015.buildPreset(null, { modules: "commonjs" });
es2015(null, { modules: "commonjs" });
}).not.to.throw();
expect(function () {
es2015.buildPreset(null, { modules: "amd" });
es2015(null, { modules: "amd" });
}).not.to.throw();
expect(function () {
es2015.buildPreset(null, { modules: "umd" });
es2015(null, { modules: "umd" });
}).not.to.throw();
expect(function () {
es2015.buildPreset(null, { modules: "systemjs" });
es2015(null, { modules: "systemjs" });
}).not.to.throw();
});
});

View File

@@ -1,7 +1,9 @@
import transformExponentiationOperator from "babel-plugin-transform-exponentiation-operator";
export default {
plugins: [
transformExponentiationOperator
]
};
export default function () {
return {
plugins: [
transformExponentiationOperator
]
};
}

View File

@@ -1,9 +1,11 @@
import syntaxTrailingFunctionCommas from "babel-plugin-syntax-trailing-function-commas";
import transformAsyncToGenerator from "babel-plugin-transform-async-to-generator";
export default {
plugins: [
syntaxTrailingFunctionCommas,
transformAsyncToGenerator
]
};
export default function () {
return {
plugins: [
syntaxTrailingFunctionCommas,
transformAsyncToGenerator
]
};
}

View File

@@ -1,7 +1,9 @@
import transformFlowStripTypes from "babel-plugin-transform-flow-strip-types";
export default {
plugins: [
transformFlowStripTypes
]
};
export default function () {
return {
plugins: [
transformFlowStripTypes
]
};
}

View File

@@ -2,13 +2,10 @@ import presetES2015 from "babel-preset-es2015";
import presetES2016 from "babel-preset-es2016";
import presetES2017 from "babel-preset-es2017";
// Rather than exporting a default object to represent the preset, we can
// also export a default function instead, as this preset demonstrates.
// This allows one to further configure a preset by way of specific options.
export default function (context, opts = {}) {
return {
presets: [
opts.es2015 !== false && [presetES2015.buildPreset, opts.es2015],
opts.es2015 !== false && [presetES2015, opts.es2015],
opts.es2016 !== false && presetES2016,
opts.es2017 !== false && presetES2017
].filter(Boolean) // filter out falsy values

View File

@@ -7,21 +7,23 @@ import transformReactDisplayName from "babel-plugin-transform-react-display-name
// import transformReactJSXSource from "babel-plugin-transform-react-jsx-source";
// import transformReactJSXSelf from "babel-plugin-transform-react-jsx-self";
export default {
presets: [
presetFlow
],
plugins: [
transformReactJSX,
transformSyntaxJSX,
transformReactDisplayName
],
env: {
development: {
plugins: [
// transformReactJSXSource,
// transformReactJSXSelf
]
export default function () {
return {
presets: [
presetFlow
],
plugins: [
transformReactJSX,
transformSyntaxJSX,
transformReactDisplayName
],
env: {
development: {
plugins: [
// transformReactJSXSource,
// transformReactJSXSelf
]
}
}
}
};
};
}

View File

@@ -3,12 +3,14 @@ import presetStage1 from "babel-preset-stage-1";
import transformDoExpressions from "babel-plugin-transform-do-expressions";
import transformFunctionBind from "babel-plugin-transform-function-bind";
export default {
presets: [
presetStage1
],
plugins: [
transformDoExpressions,
transformFunctionBind
]
};
export default function () {
return {
presets: [
presetStage1
],
plugins: [
transformDoExpressions,
transformFunctionBind
]
};
}

View File

@@ -3,12 +3,14 @@ import presetStage2 from "babel-preset-stage-2";
import transformDecorators from "babel-plugin-transform-decorators";
import transformExportExtensions from "babel-plugin-transform-export-extensions";
export default {
presets: [
presetStage2
],
plugins: [
transformDecorators,
transformExportExtensions
]
};
export default function () {
return {
presets: [
presetStage2
],
plugins: [
transformDecorators,
transformExportExtensions
]
};
}

View File

@@ -4,13 +4,15 @@ import syntaxDynamicImport from "babel-plugin-syntax-dynamic-import";
import transformClassProperties from "babel-plugin-transform-class-properties";
import transformUnicodePropertyRegex from "babel-plugin-transform-unicode-property-regex";
export default {
presets: [
presetStage3
],
plugins: [
syntaxDynamicImport,
transformClassProperties,
transformUnicodePropertyRegex
]
};
export default function () {
return {
presets: [
presetStage3
],
plugins: [
syntaxDynamicImport,
transformClassProperties,
transformUnicodePropertyRegex
]
};
}

View File

@@ -1,9 +1,11 @@
import transformObjectRestSpread from "babel-plugin-transform-object-rest-spread";
import transformAsyncGeneratorFunctions from "babel-plugin-transform-async-generator-functions";
export default {
plugins: [
transformAsyncGeneratorFunctions,
transformObjectRestSpread
]
};
export default function () {
return {
plugins: [
transformAsyncGeneratorFunctions,
transformObjectRestSpread
]
};
}