From 78c21a282a10cd3ee3e8335e9e0a95e7dbfd93c2 Mon Sep 17 00:00:00 2001 From: Eric Baer Date: Thu, 1 Sep 2016 08:55:50 -0700 Subject: [PATCH] Implement very basic (but working) functionality (#3) * Implement very basic (but working) functionality * Correct PR based on feedback --- experimental/babel-preset-env/package.json | 45 ++-- experimental/babel-preset-env/src/index.js | 237 ++++++------------- experimental/babel-preset-env/src/plugins.js | 131 ++++++++++ experimental/babel-preset-env/test/index.js | 32 +++ 4 files changed, 262 insertions(+), 183 deletions(-) create mode 100644 experimental/babel-preset-env/src/plugins.js create mode 100644 experimental/babel-preset-env/test/index.js diff --git a/experimental/babel-preset-env/package.json b/experimental/babel-preset-env/package.json index 8004ef0a21..ef4e7e6ebd 100644 --- a/experimental/babel-preset-env/package.json +++ b/experimental/babel-preset-env/package.json @@ -13,18 +13,16 @@ "lint": "eslint src test", "fix": "eslint src test --fix", "ci": "npm run lint && npm run test", - "prepublish": "npm run build" + "prepublish": "npm run build", + "test": "mocha ./test" }, "dependencies": { - "babel-plugin-transform-es2015-modules-amd": "^6.8.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.6.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.12.0", - "babel-plugin-transform-es2015-modules-umd": "^6.12.0", - "babel-plugin-transform-es3-member-expression-literals": "^6.3.13", - "babel-plugin-transform-es3-property-literals": "^6.3.13", - "babel-plugin-transform-proto-to-assign": "^6.9.0", - "babel-plugin-transform-es5-property-mutators": "^6.3.13", "babel-plugin-check-es2015-constants": "^6.3.13", + "babel-plugin-syntax-trailing-function-commas": "^6.13.0", + "babel-plugin-transform-async-to-generator": "^6.8.0", + "babel-plugin-transform-class-properties": "^6.11.5", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-do-expressions": "^6.8.0", "babel-plugin-transform-es2015-arrow-functions": "^6.3.13", "babel-plugin-transform-es2015-block-scoped-functions": "^6.3.13", "babel-plugin-transform-es2015-block-scoping": "^6.6.0", @@ -35,6 +33,10 @@ "babel-plugin-transform-es2015-for-of": "^6.6.0", "babel-plugin-transform-es2015-function-name": "^6.3.13", "babel-plugin-transform-es2015-literals": "^6.3.13", + "babel-plugin-transform-es2015-modules-amd": "^6.8.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.6.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.12.0", + "babel-plugin-transform-es2015-modules-umd": "^6.12.0", "babel-plugin-transform-es2015-object-super": "^6.3.13", "babel-plugin-transform-es2015-parameters": "^6.6.0", "babel-plugin-transform-es2015-shorthand-properties": "^6.3.13", @@ -43,16 +45,16 @@ "babel-plugin-transform-es2015-template-literals": "^6.6.0", "babel-plugin-transform-es2015-typeof-symbol": "^6.6.0", "babel-plugin-transform-es2015-unicode-regex": "^6.3.13", - "babel-plugin-transform-regenerator": "^6.6.0", + "babel-plugin-transform-es3-member-expression-literals": "^6.3.13", + "babel-plugin-transform-es3-property-literals": "^6.3.13", + "babel-plugin-transform-es5-property-mutators": "^6.3.13", "babel-plugin-transform-exponentiation-operator": "^6.8.0", - "babel-plugin-syntax-trailing-function-commas": "^6.13.0", - "babel-plugin-transform-async-to-generator": "^6.8.0", - "babel-plugin-transform-class-properties": "^6.11.5", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-do-expressions": "^6.8.0", "babel-plugin-transform-export-extensions": "^6.8.0", "babel-plugin-transform-function-bind": "^6.8.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0" + "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-plugin-transform-proto-to-assign": "^6.9.0", + "babel-plugin-transform-regenerator": "^6.6.0", + "lodash.includes": "^4.3.0" }, "devDependencies": { "babel-cli": "^6.11.4", @@ -61,10 +63,19 @@ "eslint": "^3.3.1", "eslint-config-babel": "^1.0.1", "eslint-plugin-babel": "^3.3.0", - "eslint-plugin-flow-vars": "^0.5.0" + "eslint-plugin-flow-vars": "^0.5.0", + "mocha": "^3.0.2" }, "babel": { "plugins": [ + "babel-plugin-transform-es2015-destructuring", + "babel-plugin-transform-es2015-function-name", + "babel-plugin-transform-es2015-modules-commonjs", + "babel-plugin-transform-es2015-parameters", + "babel-plugin-transform-es2015-shorthand-properties", + "babel-plugin-transform-es2015-spread", + "babel-plugin-transform-es2015-sticky-regex", + "babel-plugin-transform-es2015-unicode-regex", "transform-class-properties", "transform-flow-strip-types" ] diff --git a/experimental/babel-preset-env/src/index.js b/experimental/babel-preset-env/src/index.js index d7c6533265..9c5cf26225 100644 --- a/experimental/babel-preset-env/src/index.js +++ b/experimental/babel-preset-env/src/index.js @@ -4,172 +4,14 @@ // "proto-to-assign", // "es5-property-mutators", -export const pluginsList = { - // es2015 - "transform-es2015-arrow-functions": { - edge: 13, - firefox: 45, - chrome: 49, - opera: 36, - }, - "transform-es2015-block-scoped-functions": { - edge: 11, - firefox: 46, - chrome: 41, - opera: 28, - }, - "transform-es2015-block-scoping": { - edge: 11, - firefox: 36, - chrome: 49, - opera: 36, - }, - "transform-es2015-classes": { - edge: 13, - firefox: 45, - chrome: 49, - opera: 36, - }, - "transform-es2015-computed-properties": { - edge: 12, - firefox: 34, - chrome: 44, - opera: 31 - }, - "check-es2015-constants": { - edge: 11, - firefox: 36, - chrome: 49, - opera: 36, - }, - "transform-es2015-destructuring": { - edge: 14, - firefox: Infinity, - chrome: 52, - opera: 39, - }, - "transform-es2015-for-of": { - edge: Infinity, - firefox: Infinity, - chrome: 51, - opera: 38, - }, - "transform-es2015-function-name": { - edge: Infinity, - firefox: Infinity, - chrome: 52, - opera: 39, - }, - "transform-es2015-literals": { - edge: 12, - firefox: 36, - chrome: 41, - opera: 28 - }, - "transform-es2015-object-super": { - edge: 13, - firefox: 45, - chrome: 49, - opera: 36, - }, - "transform-es2015-parameters": { - edge: 14, - firefox: Infinity, - chrome: 49, - opera: 36, - }, - "transform-es2015-shorthand-properties": { - edge: 12, - firefox: 33, - chrome: 43, - opera: 30 - }, - "transform-es2015-spread": { - edge: 13, - firefox: 36, - chrome: 46, - opera: 33, - }, - "transform-es2015-sticky-regex": { - edge: 13, - firefox: 31, - chrome: 49, - opera: 36 - }, - "transform-es2015-template-literals": { - edge: 13, - firefox: 34, - chrome: 41, - opera: 28, - }, - "transform-es2015-typeof-symbol": { - edge: 12, - firefox: 36, - chrome: 38, - opera: 25, - }, - "transform-es2015-unicode-regex": { - edge: 12, - firefox: 46, - chrome: 51, - opera: 38, - }, - "transform-regenerator": { - edge: 13, - firefox: 45, - chrome: 49, - opera: 36, - }, - - // es2016 - "transform-exponentiation-operator": { - edge: 14, - chrome: 52, - }, - - // es2017 - "transform-async-to-generator": { - edge: 14, - }, - "syntax-trailing-function-commas": { - edge: 14, - } -}; +import includes from "lodash.includes"; +import pluginList from "./plugins.js"; export const plugins = [ "es3-member-expression-literals", "es3-property-literals", "proto-to-assign", - "es5-property-mutators", - - // es2015 - "transform-es2015-arrow-functions", - "transform-es2015-block-scoped-functions", - "transform-es2015-block-scoping", - "transform-es2015-classes", - "transform-es2015-computed-properties", - "check-es2015-constants", - "transform-es2015-destructuring", - "transform-es2015-for-of", - "transform-es2015-function-name", - "transform-es2015-literals", - "transform-es2015-object-super", - "transform-es2015-parameters", - "transform-es2015-shorthand-properties", - "transform-es2015-spread", - "transform-es2015-sticky-regex", - "transform-es2015-template-literals", - "transform-es2015-typeof-symbol", - "transform-es2015-unicode-regex", - "transform-regenerator", - - // es2016 - "transform-exponentiation-operator", - - // es2017 - "transform-async-to-generator", - "syntax-trailing-function-commas" ]; // modules? @@ -190,12 +32,75 @@ export const stagePlugins = [ "transform-object-rest-spread", ]; -export default function(opts) { - let stage = 4; - if (opts !== undefined){ - if (opts.stage !== undefined) stage = opts.stage; - } +/** + * Determine if a transformation is required + * @param {Object} supportedEnvironments An Object containing environment keys and the lowest + * supported version as a value + * @param {Object} plugin An Object containing environment keys and the lowest + * version the feature was implmented in as a value + * @return {Boolean} Whether or not the transformation is required + */ +export const isPluginRequired = (supportedEnvironments, plugin) => { + const targetEnvironments = Object.keys(supportedEnvironments); - if (typeof stage !== "boolean") throw new Error("Preset es2015 'loose' option must be a boolean."); + if (targetEnvironments.length === 0) { return true; } + const isRequiredForEnvironments = targetEnvironments + .filter(environemt => { + // Feature is not implemented in that environment + if (!plugin[environemt]) { return true; } + + const lowestImplementedVersion = plugin[environemt]; + const lowestTargetedVersion = targetEnvironments[environemt]; + if (lowestTargetedVersion <= lowestImplementedVersion) { return true; } + + return false; + }); + + return isRequiredForEnvironments.length > 0 ? true : false; +}; + +const getTargets = targetOpts => { + return targetOpts || {}; +} + +// TODO: Allow specifying plugins as either shortened or full name +// babel-plugin-transform-es2015-classes +// transform-es2015-classes +const getLooseMode = looseOpts => { + if (!looseOpts) { return []; } + return looseOpts; +} + +// TODO: Allow specifying modules as: Boolean, String or Array of module types +const getModules = modulesOpts => { + if (!modulesOpts) { return []; } + return modulesOpts; +} + +export default function(opts) { + const looseMode = getLooseMode(opts.loose); + const modulesMode = getModules(opts.modules); + const targets = getTargets(opts.targets); + + const transformations = Object.keys(pluginList) + .filter(pluginName => isPluginRequired(targets, pluginList[pluginName])) + .map(pluginName => { + return includes(looseMode, pluginName) + ? [require(`babel-plugin-${pluginName}`), { loose: true }] + : require(`babel-plugin-${pluginName}`); + }); + + // TODO: Support loose mode + const modules = Object.keys(modulesMode) + .map(moduleType => { + return [require(`babel-plugin-transform-es2015-modules-${moduleType}`)] + }); + + return { + plugins: [ + ...modules, + ...transformations + ] + } } diff --git a/experimental/babel-preset-env/src/plugins.js b/experimental/babel-preset-env/src/plugins.js new file mode 100644 index 0000000000..377f8196cf --- /dev/null +++ b/experimental/babel-preset-env/src/plugins.js @@ -0,0 +1,131 @@ +export default { + // es2015 + "transform-es2015-arrow-functions": { + edge: 13, + firefox: 45, + chrome: 49, + opera: 36, + }, + "transform-es2015-block-scoped-functions": { + edge: 11, + firefox: 46, + chrome: 41, + opera: 28, + }, + "transform-es2015-block-scoping": { + edge: 11, + firefox: 36, + chrome: 49, + opera: 36, + }, + "transform-es2015-classes": { + edge: 13, + firefox: 45, + chrome: 49, + opera: 36, + }, + "transform-es2015-computed-properties": { + edge: 12, + firefox: 34, + chrome: 44, + opera: 31 + }, + "check-es2015-constants": { + edge: 11, + firefox: 36, + chrome: 49, + opera: 36, + }, + "transform-es2015-destructuring": { + edge: 14, + firefox: Number.NEGATIVE_INFINITY, + chrome: 52, + opera: 39, + }, + "transform-es2015-for-of": { + edge: Number.NEGATIVE_INFINITY, + firefox: Number.NEGATIVE_INFINITY, + chrome: 51, + opera: 38, + }, + "transform-es2015-function-name": { + edge: Number.NEGATIVE_INFINITY, + firefox: Number.NEGATIVE_INFINITY, + chrome: 52, + opera: 39, + }, + "transform-es2015-literals": { + edge: 12, + firefox: 36, + chrome: 41, + opera: 28 + }, + "transform-es2015-object-super": { + edge: 13, + firefox: 45, + chrome: 49, + opera: 36, + }, + "transform-es2015-parameters": { + edge: 14, + firefox: Number.NEGATIVE_INFINITY, + chrome: 49, + opera: 36, + }, + "transform-es2015-shorthand-properties": { + edge: 12, + firefox: 33, + chrome: 43, + opera: 30 + }, + "transform-es2015-spread": { + edge: 13, + firefox: 36, + chrome: 46, + opera: 33, + }, + "transform-es2015-sticky-regex": { + edge: 13, + firefox: 31, + chrome: 49, + opera: 36 + }, + "transform-es2015-template-literals": { + edge: 13, + firefox: 34, + chrome: 41, + opera: 28, + }, + "transform-es2015-typeof-symbol": { + edge: 12, + firefox: 36, + chrome: 38, + opera: 25, + }, + "transform-es2015-unicode-regex": { + edge: 12, + firefox: 46, + chrome: 51, + opera: 38, + }, + "transform-regenerator": { + edge: 13, + firefox: 45, + chrome: 49, + opera: 36, + }, + + // es2016 + "transform-exponentiation-operator": { + edge: 14, + chrome: 52, + }, + + // es2017 + "transform-async-to-generator": { + edge: 14, + }, + "syntax-trailing-function-commas": { + edge: 14, + } +}; diff --git a/experimental/babel-preset-env/test/index.js b/experimental/babel-preset-env/test/index.js new file mode 100644 index 0000000000..b1720bdf01 --- /dev/null +++ b/experimental/babel-preset-env/test/index.js @@ -0,0 +1,32 @@ +"use strict"; + +const babelPresetEnv = require("../lib/index.js"); +const assert = require("assert"); + +describe("babel-preset-env", () => { + describe("isPluginRequired", () => { + it("returns true if no targets are specified", () => { + const isRequired = babelPresetEnv.isPluginRequired({}, {}); + assert(isRequired); + }); + it("returns true if plugin feature is not implemented in one or more targets", () => { + let targets; + const plugin = { + edge: false, + firefox: 45, + chrome: 49, + } + + targets = { + "chrome": Number.MAX_SAFE_INTEGER, + "firefox": Number.MAX_SAFE_INTEGER + }; + assert(babelPresetEnv.isPluginRequired(targets, plugin) === false); + + targets = { + "edge": 12, + }; + assert(babelPresetEnv.isPluginRequired(plugin, plugin) === true); + }); + }); +});