Extract targets parser and compat data from preset-env (#10899)
* Extract targets parser and compat data from preset-env * Review by Jùnliàng * isItemRequired -> targetsSupported * Export isRequired
This commit is contained in:
parent
5f807ae45b
commit
04354d1556
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,6 +20,8 @@ dist
|
||||
package-lock.json
|
||||
!/.github/actions/*/package-lock.json
|
||||
|
||||
/packages/babel-compat-data/build
|
||||
|
||||
/packages/babel-runtime/helpers/*.js
|
||||
!/packages/babel-runtime/helpers/toArray.js
|
||||
!/packages/babel-runtime/helpers/iterableToArray.js
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package.json
|
||||
packages/babel-preset-env/data
|
||||
packages/babel-compat-data/data
|
||||
packages/babel-compat-data/scripts/data/overlapping-plugins.js
|
||||
packages/*/test/fixtures/**/input.*
|
||||
packages/*/test/fixtures/**/exec.*
|
||||
packages/*/test/fixtures/**/output.*
|
||||
|
||||
@ -181,7 +181,12 @@ function buildRollup(packages) {
|
||||
},
|
||||
}),
|
||||
rollupCommonJs({
|
||||
include: [/node_modules/, "packages/babel-preset-env/data/**"],
|
||||
include: [
|
||||
/node_modules/,
|
||||
"packages/babel-preset-env/data/*.js",
|
||||
// Rollup doesn't read export maps, so it loads the cjs fallback
|
||||
"packages/babel-compat-data/*.js",
|
||||
],
|
||||
namedExports: {
|
||||
"babel-plugin-dynamic-import-node/utils.js": [
|
||||
"createDynamicImportTransform",
|
||||
|
||||
@ -30,24 +30,16 @@ module.exports = function(api) {
|
||||
switch (env) {
|
||||
// Configs used during bundling builds.
|
||||
case "rollup":
|
||||
convertESM = false;
|
||||
ignoreLib = false;
|
||||
// rollup-commonjs will converts node_modules to ESM
|
||||
unambiguousSources.push(
|
||||
"**/node_modules",
|
||||
// todo: remove this after it is rewritten into ESM
|
||||
"packages/babel-preset-env/data"
|
||||
);
|
||||
envOpts.targets = {
|
||||
node: nodeVersion,
|
||||
};
|
||||
break;
|
||||
case "standalone":
|
||||
convertESM = false;
|
||||
ignoreLib = false;
|
||||
unambiguousSources.push(
|
||||
"**/node_modules",
|
||||
"packages/babel-preset-env/data"
|
||||
"packages/babel-preset-env/data",
|
||||
"packages/babel-compat-data"
|
||||
);
|
||||
// targets to browserslists: defaults
|
||||
break;
|
||||
|
||||
4
packages/babel-compat-data/.npmignore
Normal file
4
packages/babel-compat-data/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
scripts
|
||||
src
|
||||
test
|
||||
*.log
|
||||
4
packages/babel-compat-data/corejs2-built-ins.js
Normal file
4
packages/babel-compat-data/corejs2-built-ins.js
Normal file
@ -0,0 +1,4 @@
|
||||
// Node < 13.3 doesn't support export maps in package.json.
|
||||
// Use this proxy file as a fallback.
|
||||
|
||||
module.exports = require("./data/corejs2-built-ins.json");
|
||||
12
packages/babel-compat-data/data/built-in-modules.json
Normal file
12
packages/babel-compat-data/data/built-in-modules.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"es6.module": {
|
||||
"edge": "16",
|
||||
"firefox": "60",
|
||||
"chrome": "61",
|
||||
"safari": "10.1",
|
||||
"opera": "48",
|
||||
"ios_saf": "10.3",
|
||||
"and_chr": "74",
|
||||
"and_ff": "66"
|
||||
}
|
||||
}
|
||||
3
packages/babel-compat-data/data/overlapping-plugins.json
Normal file
3
packages/babel-compat-data/data/overlapping-plugins.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"transform-regenerator": []
|
||||
}
|
||||
4
packages/babel-compat-data/native-modules.js
Normal file
4
packages/babel-compat-data/native-modules.js
Normal file
@ -0,0 +1,4 @@
|
||||
// Node < 13.3 doesn't support export maps in package.json.
|
||||
// Use this proxy file as a fallback.
|
||||
|
||||
module.exports = require("./data/native-modules.json");
|
||||
4
packages/babel-compat-data/overlapping-plugins.js
Normal file
4
packages/babel-compat-data/overlapping-plugins.js
Normal file
@ -0,0 +1,4 @@
|
||||
// Node < 13.3 doesn't support export maps in package.json.
|
||||
// Use this proxy file as a fallback.
|
||||
|
||||
module.exports = require("./data/overlapping-plugins.json");
|
||||
36
packages/babel-compat-data/package.json
Normal file
36
packages/babel-compat-data/package.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@babel/compat-data",
|
||||
"version": "0.0.0",
|
||||
"author": "The Babel Team (https://babeljs.io/team)",
|
||||
"license": "MIT",
|
||||
"description": "",
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-compat-data",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"exports": {
|
||||
"./plugins": "./data/plugins.json",
|
||||
"./native-modules": "./data/native-modules.json",
|
||||
"./corejs2-built-ins": "./data/corejs2-built-ins.json",
|
||||
"./overlapping-plugins": "./data/overlapping-plugins.json"
|
||||
},
|
||||
"scripts": {
|
||||
"build-data": "./scripts/download-compat-table.sh; node ./scripts/build-data.js; node ./scripts/build-modules-support.js; node ./scripts/build-overlapping-plugins.js"
|
||||
},
|
||||
"keywords": [
|
||||
"babel",
|
||||
"compat-table",
|
||||
"compat-data"
|
||||
],
|
||||
"dependencies": {
|
||||
"browserslist": "^4.8.2",
|
||||
"invariant": "^2.2.4",
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"caniuse-db": "1.0.30000969",
|
||||
"electron-to-chromium": "1.3.113",
|
||||
"lodash": "^4.17.15",
|
||||
"@babel/helper-compilation-targets": "^0.0.0"
|
||||
}
|
||||
}
|
||||
4
packages/babel-compat-data/plugins.js
Normal file
4
packages/babel-compat-data/plugins.js
Normal file
@ -0,0 +1,4 @@
|
||||
// Node < 13.3 doesn't support export maps in package.json.
|
||||
// Use this proxy file as a fallback.
|
||||
|
||||
module.exports = require("./data/plugins.json");
|
||||
@ -7,7 +7,7 @@ const flattenDeep = require("lodash/flattenDeep");
|
||||
const isEqual = require("lodash/isEqual");
|
||||
const mapValues = require("lodash/mapValues");
|
||||
const pickBy = require("lodash/pickBy");
|
||||
const unreleasedLabels = require("../data/unreleased-labels");
|
||||
const { unreleasedLabels } = require("babel/helper-compilation-targets");
|
||||
const electronToChromiumVersions = require("electron-to-chromium").versions;
|
||||
|
||||
const electronToChromiumKeys = Object.keys(
|
||||
@ -293,7 +293,7 @@ const generateData = (environments, features) => {
|
||||
["plugin", "corejs2-built-in"].forEach(target => {
|
||||
const newData = generateData(
|
||||
environments,
|
||||
require(`../data/${target}-features`)
|
||||
require(`./data/${target}-features`)
|
||||
);
|
||||
const dataPath = path.join(__dirname, `../data/${target}s.json`);
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const overlappingPlugins = require("./data/overlapping-plugins");
|
||||
|
||||
fs.writeFileSync(
|
||||
__dirname + "/../data/overlapping-plugins.json",
|
||||
JSON.stringify(overlappingPlugins, replacer, 2)
|
||||
);
|
||||
|
||||
function replacer(key, val) {
|
||||
if (val instanceof Set) return Array.from(val);
|
||||
if (val instanceof Map) return Object.fromEntries(val);
|
||||
return val;
|
||||
}
|
||||
@ -26,7 +26,7 @@ const typedArrayMethods = [
|
||||
"typed arrays / %TypedArray%[Symbol.species]",
|
||||
];
|
||||
|
||||
const es = {
|
||||
module.exports = {
|
||||
// compat-table missing babel6 mapping
|
||||
// "es6.array.concat": {
|
||||
// features: [
|
||||
@ -34,7 +34,8 @@ const es = {
|
||||
// "well-known symbols / Symbol.species, Array.prototype.concat",
|
||||
// ]
|
||||
// },
|
||||
"es6.array.copy-within": "Array.prototype methods / Array.prototype.copyWithin",
|
||||
"es6.array.copy-within":
|
||||
"Array.prototype methods / Array.prototype.copyWithin",
|
||||
"es6.array.every": "Array methods / Array.prototype.every",
|
||||
"es6.array.fill": "Array.prototype methods / Array.prototype.fill",
|
||||
"es6.array.filter": {
|
||||
@ -46,7 +47,8 @@ const es = {
|
||||
},
|
||||
"es6.array.find": "Array.prototype methods / Array.prototype.find",
|
||||
"es6.array.find-index": "Array.prototype methods / Array.prototype.findIndex",
|
||||
"es7.array.flat-map": "Array.prototype.{flat, flatMap} / Array.prototype.flatMap",
|
||||
"es7.array.flat-map":
|
||||
"Array.prototype.{flat, flatMap} / Array.prototype.flatMap",
|
||||
"es6.array.for-each": "Array methods / Array.prototype.forEach",
|
||||
"es6.array.from": "Array static methods / Array.from",
|
||||
"es7.array.includes": "Array.prototype.includes",
|
||||
@ -90,8 +92,8 @@ const es = {
|
||||
"es6.function.has-instance": "well-known symbols / Symbol.hasInstance",
|
||||
"es6.function.name": {
|
||||
features: [
|
||||
"function \"name\" property / function statements",
|
||||
"function \"name\" property / function expressions",
|
||||
'function "name" property / function statements',
|
||||
'function "name" property / function expressions',
|
||||
],
|
||||
},
|
||||
|
||||
@ -174,13 +176,19 @@ const es = {
|
||||
],
|
||||
},
|
||||
"es6.object.define-property": "Object static methods / Object.defineProperty",
|
||||
"es6.object.define-properties": "Object static methods / Object.defineProperties",
|
||||
"es6.object.define-properties":
|
||||
"Object static methods / Object.defineProperties",
|
||||
"es7.object.entries": "Object static methods / Object.entries",
|
||||
"es6.object.freeze": "Object static methods accept primitives / Object.freeze",
|
||||
"es6.object.get-own-property-descriptor": "Object static methods accept primitives / Object.getOwnPropertyDescriptor",
|
||||
"es7.object.get-own-property-descriptors": "Object static methods / Object.getOwnPropertyDescriptors",
|
||||
"es6.object.get-own-property-names": "Object static methods accept primitives / Object.getOwnPropertyNames",
|
||||
"es6.object.get-prototype-of": "Object static methods accept primitives / Object.getPrototypeOf",
|
||||
"es6.object.freeze":
|
||||
"Object static methods accept primitives / Object.freeze",
|
||||
"es6.object.get-own-property-descriptor":
|
||||
"Object static methods accept primitives / Object.getOwnPropertyDescriptor",
|
||||
"es7.object.get-own-property-descriptors":
|
||||
"Object static methods / Object.getOwnPropertyDescriptors",
|
||||
"es6.object.get-own-property-names":
|
||||
"Object static methods accept primitives / Object.getOwnPropertyNames",
|
||||
"es6.object.get-prototype-of":
|
||||
"Object static methods accept primitives / Object.getPrototypeOf",
|
||||
"es7.object.lookup-getter": {
|
||||
features: [
|
||||
"Object.prototype getter/setter methods / __lookupGetter__",
|
||||
@ -199,15 +207,20 @@ const es = {
|
||||
"Object.prototype getter/setter methods / __lookupSetter__, data properties can shadow accessors",
|
||||
],
|
||||
},
|
||||
"es6.object.prevent-extensions": "Object static methods accept primitives / Object.preventExtensions",
|
||||
"es6.object.prevent-extensions":
|
||||
"Object static methods accept primitives / Object.preventExtensions",
|
||||
"es6.object.to-string": "well-known symbols / Symbol.toStringTag",
|
||||
"es6.object.is": "Object static methods / Object.is",
|
||||
"es6.object.is-frozen": "Object static methods accept primitives / Object.isFrozen",
|
||||
"es6.object.is-sealed": "Object static methods accept primitives / Object.isSealed",
|
||||
"es6.object.is-extensible": "Object static methods accept primitives / Object.isExtensible",
|
||||
"es6.object.is-frozen":
|
||||
"Object static methods accept primitives / Object.isFrozen",
|
||||
"es6.object.is-sealed":
|
||||
"Object static methods accept primitives / Object.isSealed",
|
||||
"es6.object.is-extensible":
|
||||
"Object static methods accept primitives / Object.isExtensible",
|
||||
"es6.object.keys": "Object static methods accept primitives / Object.keys",
|
||||
"es6.object.seal": "Object static methods accept primitives / Object.seal",
|
||||
"es6.object.set-prototype-of": "Object static methods / Object.setPrototypeOf",
|
||||
"es6.object.set-prototype-of":
|
||||
"Object static methods / Object.setPrototypeOf",
|
||||
"es7.object.values": "Object static methods / Object.values",
|
||||
|
||||
"es6.promise": {
|
||||
@ -224,7 +237,8 @@ const es = {
|
||||
"es6.reflect.define-property": "Reflect / Reflect.defineProperty",
|
||||
"es6.reflect.delete-property": "Reflect / Reflect.deleteProperty",
|
||||
"es6.reflect.get": "Reflect / Reflect.get",
|
||||
"es6.reflect.get-own-property-descriptor": "Reflect / Reflect.getOwnPropertyDescriptor",
|
||||
"es6.reflect.get-own-property-descriptor":
|
||||
"Reflect / Reflect.getOwnPropertyDescriptor",
|
||||
"es6.reflect.get-prototype-of": "Reflect / Reflect.getPrototypeOf",
|
||||
"es6.reflect.has": "Reflect / Reflect.has",
|
||||
"es6.reflect.is-extensible": "Reflect / Reflect.isExtensible",
|
||||
@ -240,11 +254,16 @@ const es = {
|
||||
],
|
||||
},
|
||||
"es6.regexp.flags": "RegExp.prototype properties / RegExp.prototype.flags",
|
||||
"es6.regexp.match": "RegExp.prototype properties / RegExp.prototype[Symbol.match]",
|
||||
"es6.regexp.replace": "RegExp.prototype properties / RegExp.prototype[Symbol.replace]",
|
||||
"es6.regexp.split": "RegExp.prototype properties / RegExp.prototype[Symbol.split]",
|
||||
"es6.regexp.search": "RegExp.prototype properties / RegExp.prototype[Symbol.search]",
|
||||
"es6.regexp.to-string": "miscellaneous / RegExp.prototype.toString generic and uses \"flags\" property",
|
||||
"es6.regexp.match":
|
||||
"RegExp.prototype properties / RegExp.prototype[Symbol.match]",
|
||||
"es6.regexp.replace":
|
||||
"RegExp.prototype properties / RegExp.prototype[Symbol.replace]",
|
||||
"es6.regexp.split":
|
||||
"RegExp.prototype properties / RegExp.prototype[Symbol.split]",
|
||||
"es6.regexp.search":
|
||||
"RegExp.prototype properties / RegExp.prototype[Symbol.search]",
|
||||
"es6.regexp.to-string":
|
||||
'miscellaneous / RegExp.prototype.toString generic and uses "flags" property',
|
||||
|
||||
// This is explicit due to prevent the stage-1 Set proposals under the
|
||||
// category "Set methods" from being included.
|
||||
@ -295,15 +314,18 @@ const es = {
|
||||
"es6.string.big": "String.prototype HTML methods",
|
||||
"es6.string.blink": "String.prototype HTML methods",
|
||||
"es6.string.bold": "String.prototype HTML methods",
|
||||
"es6.string.code-point-at": "String.prototype methods / String.prototype.codePointAt",
|
||||
"es6.string.ends-with": "String.prototype methods / String.prototype.endsWith",
|
||||
"es6.string.code-point-at":
|
||||
"String.prototype methods / String.prototype.codePointAt",
|
||||
"es6.string.ends-with":
|
||||
"String.prototype methods / String.prototype.endsWith",
|
||||
"es6.string.fixed": "String.prototype HTML methods",
|
||||
"es6.string.fontcolor": "String.prototype HTML methods",
|
||||
"es6.string.fontsize": "String.prototype HTML methods",
|
||||
"es6.string.from-code-point": "String static methods / String.fromCodePoint",
|
||||
"es6.string.includes": "String.prototype methods / String.prototype.includes",
|
||||
"es6.string.italics": "String.prototype HTML methods",
|
||||
"es6.string.iterator": "String.prototype methods / String.prototype[Symbol.iterator]",
|
||||
"es6.string.iterator":
|
||||
"String.prototype methods / String.prototype[Symbol.iterator]",
|
||||
"es6.string.link": "String.prototype HTML methods",
|
||||
// "String.prototype methods / String.prototype.normalize" not implemented
|
||||
"es7.string.pad-start": "String padding / String.prototype.padStart",
|
||||
@ -311,7 +333,8 @@ const es = {
|
||||
"es6.string.raw": "String static methods / String.raw",
|
||||
"es6.string.repeat": "String.prototype methods / String.prototype.repeat",
|
||||
"es6.string.small": "String.prototype HTML methods",
|
||||
"es6.string.starts-with": "String.prototype methods / String.prototype.startsWith",
|
||||
"es6.string.starts-with":
|
||||
"String.prototype methods / String.prototype.startsWith",
|
||||
"es6.string.strike": "String.prototype HTML methods",
|
||||
"es6.string.sub": "String.prototype HTML methods",
|
||||
"es6.string.sup": "String.prototype HTML methods",
|
||||
@ -353,7 +376,3 @@ const es = {
|
||||
|
||||
"es6.weak-set": "WeakSet",
|
||||
};
|
||||
|
||||
const proposals = require("./shipped-proposals").builtIns;
|
||||
|
||||
module.exports = Object.assign({}, es, proposals);
|
||||
@ -4,13 +4,13 @@ module.exports = new Map();
|
||||
|
||||
// async -> regenerator is better than async -> generator -> regenerator
|
||||
ifIncluded("transform-regenerator")
|
||||
// https://github.com/babel/babel/issues/10678
|
||||
// Temporarly disabled: https://github.com/babel/babel/issues/10678
|
||||
// .isUnnecessary("transform-async-to-generator");
|
||||
|
||||
function ifIncluded(name) {
|
||||
const set = new Set();
|
||||
module.exports.set(name, set);
|
||||
return {
|
||||
isUnnecessary(name) { set.add(name); return this; }
|
||||
isUnnecessary(name) { set.add(name); return this; },
|
||||
};
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
const es = {
|
||||
module.exports = {
|
||||
"transform-template-literals": {
|
||||
features: ["template literals"],
|
||||
},
|
||||
@ -65,10 +65,7 @@ const es = {
|
||||
],
|
||||
},
|
||||
"transform-destructuring": {
|
||||
features: [
|
||||
"destructuring, assignment",
|
||||
"destructuring, declarations",
|
||||
],
|
||||
features: ["destructuring, assignment", "destructuring, declarations"],
|
||||
},
|
||||
"transform-block-scoping": {
|
||||
features: ["const", "let"],
|
||||
@ -98,11 +95,9 @@ const es = {
|
||||
"proposal-json-strings": "JSON superset",
|
||||
"proposal-optional-catch-binding": "optional catch binding",
|
||||
"transform-named-capturing-groups-regex": "RegExp named capture groups",
|
||||
"transform-member-expression-literals": "Object/array literal extensions / Reserved words as property names",
|
||||
"transform-property-literals": "Object/array literal extensions / Reserved words as property names",
|
||||
"transform-member-expression-literals":
|
||||
"Object/array literal extensions / Reserved words as property names",
|
||||
"transform-property-literals":
|
||||
"Object/array literal extensions / Reserved words as property names",
|
||||
"transform-reserved-words": "Miscellaneous / Unreserved words",
|
||||
};
|
||||
|
||||
const proposals = require("./shipped-proposals").features;
|
||||
|
||||
module.exports = Object.assign({}, es, proposals);
|
||||
3
packages/babel-helper-compilation-targets/.npmignore
Normal file
3
packages/babel-helper-compilation-targets/.npmignore
Normal file
@ -0,0 +1,3 @@
|
||||
src
|
||||
test
|
||||
*.log
|
||||
32
packages/babel-helper-compilation-targets/package.json
Normal file
32
packages/babel-helper-compilation-targets/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@babel/helper-compilation-targets",
|
||||
"version": "0.0.0",
|
||||
"author": "The Babel Team (https://babeljs.io/team)",
|
||||
"license": "MIT",
|
||||
"description": "Engine compat data used in @babel/preset-env",
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-compilation-targets",
|
||||
"main": "lib/index.js",
|
||||
"type": "commonjs",
|
||||
"exports": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keywords": [
|
||||
"babel",
|
||||
"babel-plugin"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^0.0.0",
|
||||
"browserslist": "^4.8.2",
|
||||
"levenary": "^1.1.0",
|
||||
"invariant": "^2.2.4",
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.7.5",
|
||||
"@babel/helper-plugin-test-runner": "^7.7.4"
|
||||
}
|
||||
}
|
||||
40
packages/babel-helper-compilation-targets/src/debug.js
Normal file
40
packages/babel-helper-compilation-targets/src/debug.js
Normal file
@ -0,0 +1,40 @@
|
||||
// @flow
|
||||
|
||||
import semver from "semver";
|
||||
import { prettifyVersion } from "./pretty";
|
||||
import {
|
||||
semverify,
|
||||
isUnreleasedVersion,
|
||||
getLowestImplementedVersion,
|
||||
} from "./utils";
|
||||
import type { Targets } from "./types";
|
||||
|
||||
export function getInclusionReasons(
|
||||
item: string,
|
||||
targetVersions: Targets,
|
||||
list: { [key: string]: Targets },
|
||||
) {
|
||||
const minVersions = list[item] || {};
|
||||
|
||||
return Object.keys(targetVersions).reduce((result, env) => {
|
||||
const minVersion = getLowestImplementedVersion(minVersions, env);
|
||||
const targetVersion = targetVersions[env];
|
||||
|
||||
if (!minVersion) {
|
||||
result[env] = prettifyVersion(targetVersion);
|
||||
} else {
|
||||
const minIsUnreleased = isUnreleasedVersion(minVersion, env);
|
||||
const targetIsUnreleased = isUnreleasedVersion(targetVersion, env);
|
||||
|
||||
if (
|
||||
!targetIsUnreleased &&
|
||||
(minIsUnreleased ||
|
||||
semver.lt(targetVersion.toString(), semverify(minVersion)))
|
||||
) {
|
||||
result[env] = prettifyVersion(targetVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
111
packages/babel-helper-compilation-targets/src/filter-items.js
Normal file
111
packages/babel-helper-compilation-targets/src/filter-items.js
Normal file
@ -0,0 +1,111 @@
|
||||
// @flow
|
||||
|
||||
import semver from "semver";
|
||||
|
||||
import pluginsCompatData from "@babel/compat-data/plugins";
|
||||
|
||||
import type { Targets } from "./types";
|
||||
import {
|
||||
getLowestImplementedVersion,
|
||||
isUnreleasedVersion,
|
||||
semverify,
|
||||
} from "./utils";
|
||||
|
||||
export function targetsSupported(target: Targets, support: Targets) {
|
||||
const targetEnvironments = Object.keys(target);
|
||||
|
||||
if (targetEnvironments.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsupportedEnvironments = targetEnvironments.filter(environment => {
|
||||
const lowestImplementedVersion = getLowestImplementedVersion(
|
||||
support,
|
||||
environment,
|
||||
);
|
||||
|
||||
// Feature is not implemented in that environment
|
||||
if (!lowestImplementedVersion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lowestTargetedVersion = target[environment];
|
||||
|
||||
// If targets has unreleased value as a lowest version, then don't require a plugin.
|
||||
if (isUnreleasedVersion(lowestTargetedVersion, environment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Include plugin if it is supported in the unreleased environment, which wasn't specified in targets
|
||||
if (isUnreleasedVersion(lowestImplementedVersion, environment)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!semver.valid(lowestTargetedVersion.toString())) {
|
||||
throw new Error(
|
||||
`Invalid version passed for target "${environment}": "${lowestTargetedVersion}". ` +
|
||||
"Versions must be in semver format (major.minor.patch)",
|
||||
);
|
||||
}
|
||||
|
||||
return semver.gt(
|
||||
semverify(lowestImplementedVersion),
|
||||
lowestTargetedVersion.toString(),
|
||||
);
|
||||
});
|
||||
|
||||
return unsupportedEnvironments.length === 0;
|
||||
}
|
||||
|
||||
export function isRequired(
|
||||
name: string,
|
||||
targets: Targets,
|
||||
{
|
||||
compatData = pluginsCompatData,
|
||||
includes,
|
||||
excludes,
|
||||
}: {
|
||||
compatData?: { [feature: string]: Targets },
|
||||
includes?: Set<string>,
|
||||
excludes?: Set<string>,
|
||||
} = {},
|
||||
) {
|
||||
if (excludes && excludes.has(name)) return false;
|
||||
if (includes && includes.has(name)) return true;
|
||||
return !targetsSupported(targets, compatData[name]);
|
||||
}
|
||||
|
||||
export default function filterItems(
|
||||
list: { [feature: string]: Targets },
|
||||
includes: Set<string>,
|
||||
excludes: Set<string>,
|
||||
targets: Targets,
|
||||
defaultIncludes: Array<string> | null,
|
||||
defaultExcludes?: Array<string> | null,
|
||||
pluginSyntaxMap?: Map<string, string | null>,
|
||||
) {
|
||||
const result = new Set<string>();
|
||||
const options = { compatData: list, includes, excludes };
|
||||
|
||||
for (const item in list) {
|
||||
if (isRequired(item, targets, options)) {
|
||||
result.add(item);
|
||||
} else if (pluginSyntaxMap) {
|
||||
const shippedProposalsSyntax = pluginSyntaxMap.get(item);
|
||||
|
||||
if (shippedProposalsSyntax) {
|
||||
result.add(shippedProposalsSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIncludes) {
|
||||
defaultIncludes.forEach(item => !excludes.has(item) && result.add(item));
|
||||
}
|
||||
|
||||
if (defaultExcludes) {
|
||||
defaultExcludes.forEach(item => !includes.has(item) && result.delete(item));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
256
packages/babel-helper-compilation-targets/src/index.js
Normal file
256
packages/babel-helper-compilation-targets/src/index.js
Normal file
@ -0,0 +1,256 @@
|
||||
// @flow
|
||||
|
||||
import browserslist from "browserslist";
|
||||
import findSuggestion from "levenary";
|
||||
import invariant from "invariant";
|
||||
import browserModulesData from "@babel/compat-data/native-modules";
|
||||
|
||||
import {
|
||||
semverify,
|
||||
semverMin,
|
||||
isUnreleasedVersion,
|
||||
getLowestUnreleased,
|
||||
} from "./utils";
|
||||
import { browserNameMap } from "./targets";
|
||||
import { TargetNames } from "./options";
|
||||
import type { Targets } from "./types";
|
||||
|
||||
export type { Targets };
|
||||
|
||||
export { prettifyTargets } from "./pretty";
|
||||
export { getInclusionReasons } from "./debug";
|
||||
export { default as filterItems, isRequired } from "./filter-items";
|
||||
export { unreleasedLabels } from "./targets";
|
||||
|
||||
const browserslistDefaults = browserslist.defaults;
|
||||
|
||||
const validBrowserslistTargets = [
|
||||
...Object.keys(browserslist.data),
|
||||
...Object.keys(browserslist.aliases),
|
||||
];
|
||||
|
||||
function objectToBrowserslist(object: Targets): Array<string> {
|
||||
return Object.keys(object).reduce((list, targetName) => {
|
||||
if (validBrowserslistTargets.indexOf(targetName) >= 0) {
|
||||
const targetVersion = object[targetName];
|
||||
return list.concat(`${targetName} ${targetVersion}`);
|
||||
}
|
||||
return list;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function validateTargetNames(targets: Targets): void {
|
||||
const validTargets = Object.keys(TargetNames);
|
||||
for (const target in targets) {
|
||||
if (!TargetNames[target]) {
|
||||
throw new Error(
|
||||
`Invalid Option: '${target}' is not a valid target
|
||||
Maybe you meant to use '${findSuggestion(target, validTargets)}'?`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isBrowsersQueryValid(
|
||||
browsers: string | Array<string> | Targets,
|
||||
): boolean {
|
||||
return typeof browsers === "string" || Array.isArray(browsers);
|
||||
}
|
||||
|
||||
function validateBrowsers(browsers) {
|
||||
invariant(
|
||||
typeof browsers === "undefined" || isBrowsersQueryValid(browsers),
|
||||
`Invalid Option: '${browsers}' is not a valid browserslist query`,
|
||||
);
|
||||
|
||||
return browsers;
|
||||
}
|
||||
|
||||
function mergeBrowsers(fromQuery: Targets, fromTarget: Targets) {
|
||||
return Object.keys(fromTarget).reduce((queryObj, targKey) => {
|
||||
if (targKey !== TargetNames.browsers) {
|
||||
queryObj[targKey] = fromTarget[targKey];
|
||||
}
|
||||
return queryObj;
|
||||
}, fromQuery);
|
||||
}
|
||||
|
||||
function getLowestVersions(browsers: Array<string>): Targets {
|
||||
return browsers.reduce((all: Object, browser: string): Object => {
|
||||
const [browserName, browserVersion] = browser.split(" ");
|
||||
const normalizedBrowserName = browserNameMap[browserName];
|
||||
|
||||
if (!normalizedBrowserName) {
|
||||
return all;
|
||||
}
|
||||
|
||||
try {
|
||||
// Browser version can return as "10.0-10.2"
|
||||
const splitVersion = browserVersion.split("-")[0].toLowerCase();
|
||||
const isSplitUnreleased = isUnreleasedVersion(splitVersion, browserName);
|
||||
|
||||
if (!all[normalizedBrowserName]) {
|
||||
all[normalizedBrowserName] = isSplitUnreleased
|
||||
? splitVersion
|
||||
: semverify(splitVersion);
|
||||
return all;
|
||||
}
|
||||
|
||||
const version = all[normalizedBrowserName];
|
||||
const isUnreleased = isUnreleasedVersion(version, browserName);
|
||||
|
||||
if (isUnreleased && isSplitUnreleased) {
|
||||
all[normalizedBrowserName] = getLowestUnreleased(
|
||||
version,
|
||||
splitVersion,
|
||||
browserName,
|
||||
);
|
||||
} else if (isUnreleased) {
|
||||
all[normalizedBrowserName] = semverify(splitVersion);
|
||||
} else if (!isUnreleased && !isSplitUnreleased) {
|
||||
const parsedBrowserVersion = semverify(splitVersion);
|
||||
|
||||
all[normalizedBrowserName] = semverMin(version, parsedBrowserVersion);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return all;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function outputDecimalWarning(decimalTargets: Array<Object>): void {
|
||||
if (!decimalTargets || !decimalTargets.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Warning, the following targets are using a decimal version:");
|
||||
console.log("");
|
||||
decimalTargets.forEach(({ target, value }) =>
|
||||
console.log(` ${target}: ${value}`),
|
||||
);
|
||||
console.log("");
|
||||
console.log(
|
||||
"We recommend using a string for minor/patch versions to avoid numbers like 6.10",
|
||||
);
|
||||
console.log("getting parsed as 6.1, which can lead to unexpected behavior.");
|
||||
console.log("");
|
||||
}
|
||||
|
||||
function semverifyTarget(target, value) {
|
||||
try {
|
||||
return semverify(value);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Invalid Option: '${value}' is not a valid value for 'targets.${target}'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const targetParserMap = {
|
||||
__default(target, value) {
|
||||
const version = isUnreleasedVersion(value, target)
|
||||
? value.toLowerCase()
|
||||
: semverifyTarget(target, value);
|
||||
return [target, version];
|
||||
},
|
||||
|
||||
// Parse `node: true` and `node: "current"` to version
|
||||
node(target, value) {
|
||||
const parsed =
|
||||
value === true || value === "current"
|
||||
? process.versions.node
|
||||
: semverifyTarget(target, value);
|
||||
return [target, parsed];
|
||||
},
|
||||
};
|
||||
|
||||
type ParsedResult = {
|
||||
targets: Targets,
|
||||
decimalWarnings: Array<Object>,
|
||||
};
|
||||
|
||||
export default function getTargets(
|
||||
targets: Object = {},
|
||||
options: Object = {},
|
||||
): Targets {
|
||||
const targetOpts: Targets = {};
|
||||
|
||||
validateTargetNames(targets);
|
||||
|
||||
// `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
|
||||
// These values OVERRIDE the `browsers` field.
|
||||
if (targets.esmodules) {
|
||||
const supportsESModules = browserModulesData["es6.module"];
|
||||
targets.browsers = Object.keys(supportsESModules)
|
||||
.map(browser => `${browser} ${supportsESModules[browser]}`)
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
// Parse browsers target via browserslist
|
||||
const browsersquery = validateBrowsers(targets.browsers);
|
||||
|
||||
const hasTargets = Object.keys(targets).length > 0;
|
||||
const shouldParseBrowsers = !!targets.browsers;
|
||||
const shouldSearchForConfig =
|
||||
!options.ignoreBrowserslistConfig && !hasTargets;
|
||||
|
||||
if (shouldParseBrowsers || shouldSearchForConfig) {
|
||||
// If no targets are passed, we need to overwrite browserslist's defaults
|
||||
// so that we enable all transforms (acting like the now deprecated
|
||||
// preset-latest).
|
||||
//
|
||||
// Note, if browserslist resolves the config (ex. package.json), then usage
|
||||
// of `defaults` in queries will be different since we don't want to break
|
||||
// the behavior of "no targets is the same as preset-latest".
|
||||
if (!hasTargets) {
|
||||
browserslist.defaults = objectToBrowserslist(targets);
|
||||
}
|
||||
|
||||
const browsers = browserslist(browsersquery, {
|
||||
path: options.configPath,
|
||||
mobileToDesktop: true,
|
||||
});
|
||||
|
||||
const queryBrowsers = getLowestVersions(browsers);
|
||||
targets = mergeBrowsers(queryBrowsers, targets);
|
||||
|
||||
// Reset browserslist defaults
|
||||
browserslist.defaults = browserslistDefaults;
|
||||
}
|
||||
|
||||
// Parse remaining targets
|
||||
const parsed = Object.keys(targets)
|
||||
.filter(value => value !== TargetNames.esmodules)
|
||||
.sort()
|
||||
.reduce(
|
||||
(results: ParsedResult, target: string): ParsedResult => {
|
||||
if (target !== TargetNames.browsers) {
|
||||
const value = targets[target];
|
||||
|
||||
// Warn when specifying minor/patch as a decimal
|
||||
if (typeof value === "number" && value % 1 !== 0) {
|
||||
results.decimalWarnings.push({ target, value });
|
||||
}
|
||||
|
||||
// Check if we have a target parser?
|
||||
const parser = targetParserMap[target] || targetParserMap.__default;
|
||||
const [parsedTarget, parsedValue] = parser(target, value);
|
||||
|
||||
if (parsedValue) {
|
||||
// Merge (lowest wins)
|
||||
results.targets[parsedTarget] = parsedValue;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
{
|
||||
targets: targetOpts,
|
||||
decimalWarnings: [],
|
||||
},
|
||||
);
|
||||
|
||||
outputDecimalWarning(parsed.decimalWarnings);
|
||||
|
||||
return parsed.targets;
|
||||
}
|
||||
20
packages/babel-helper-compilation-targets/src/options.js
Normal file
20
packages/babel-helper-compilation-targets/src/options.js
Normal file
@ -0,0 +1,20 @@
|
||||
// @flow
|
||||
|
||||
export const TargetNames = {
|
||||
esmodules: "esmodules",
|
||||
node: "node",
|
||||
browsers: "browsers",
|
||||
chrome: "chrome",
|
||||
opera: "opera",
|
||||
edge: "edge",
|
||||
firefox: "firefox",
|
||||
safari: "safari",
|
||||
ie: "ie",
|
||||
ios: "ios",
|
||||
android: "android",
|
||||
electron: "electron",
|
||||
samsung: "samsung",
|
||||
|
||||
// deprecated
|
||||
uglify: "uglify",
|
||||
};
|
||||
36
packages/babel-helper-compilation-targets/src/pretty.js
Normal file
36
packages/babel-helper-compilation-targets/src/pretty.js
Normal file
@ -0,0 +1,36 @@
|
||||
import semver from "semver";
|
||||
import { unreleasedLabels } from "./targets";
|
||||
|
||||
export function prettifyVersion(version: string) {
|
||||
if (typeof version !== "string") {
|
||||
return version;
|
||||
}
|
||||
|
||||
const parts = [semver.major(version)];
|
||||
const minor = semver.minor(version);
|
||||
const patch = semver.patch(version);
|
||||
|
||||
if (minor || patch) {
|
||||
parts.push(minor);
|
||||
}
|
||||
|
||||
if (patch) {
|
||||
parts.push(patch);
|
||||
}
|
||||
|
||||
return parts.join(".");
|
||||
}
|
||||
|
||||
export function prettifyTargets(targets: Targets): Targets {
|
||||
return Object.keys(targets).reduce((results, target) => {
|
||||
let value = targets[target];
|
||||
|
||||
const unreleasedLabel = unreleasedLabels[target];
|
||||
if (typeof value === "string" && unreleasedLabel !== value) {
|
||||
value = prettifyVersion(value);
|
||||
}
|
||||
|
||||
results[target] = value;
|
||||
return results;
|
||||
}, {});
|
||||
}
|
||||
20
packages/babel-helper-compilation-targets/src/targets.js
Normal file
20
packages/babel-helper-compilation-targets/src/targets.js
Normal file
@ -0,0 +1,20 @@
|
||||
export const unreleasedLabels = {
|
||||
safari: "tp",
|
||||
};
|
||||
|
||||
export const browserNameMap = {
|
||||
and_chr: "chrome",
|
||||
and_ff: "firefox",
|
||||
android: "android",
|
||||
chrome: "chrome",
|
||||
edge: "edge",
|
||||
firefox: "firefox",
|
||||
ie: "ie",
|
||||
ie_mob: "ie",
|
||||
ios_saf: "ios",
|
||||
node: "node",
|
||||
op_mob: "opera",
|
||||
opera: "opera",
|
||||
safari: "safari",
|
||||
samsung: "samsung",
|
||||
};
|
||||
19
packages/babel-helper-compilation-targets/src/types.js
Normal file
19
packages/babel-helper-compilation-targets/src/types.js
Normal file
@ -0,0 +1,19 @@
|
||||
// @flow
|
||||
|
||||
// Targets
|
||||
export type Target =
|
||||
| "node"
|
||||
| "chrome"
|
||||
| "opera"
|
||||
| "edge"
|
||||
| "firefox"
|
||||
| "safari"
|
||||
| "ie"
|
||||
| "ios"
|
||||
| "android"
|
||||
| "electron"
|
||||
| "samsung";
|
||||
|
||||
export type Targets = {
|
||||
[target: Target]: string,
|
||||
};
|
||||
64
packages/babel-helper-compilation-targets/src/utils.js
Normal file
64
packages/babel-helper-compilation-targets/src/utils.js
Normal file
@ -0,0 +1,64 @@
|
||||
// @flow
|
||||
|
||||
import invariant from "invariant";
|
||||
import semver from "semver";
|
||||
|
||||
import { unreleasedLabels } from "./targets";
|
||||
import type { Target, Targets } from "./types";
|
||||
|
||||
const versionRegExp = /^(\d+|\d+.\d+)$/;
|
||||
|
||||
export function semverMin(first: ?string, second: string): string {
|
||||
return first && semver.lt(first, second) ? first : second;
|
||||
}
|
||||
|
||||
// Convert version to a semver value.
|
||||
// 2.5 -> 2.5.0; 1 -> 1.0.0;
|
||||
export function semverify(version: number | string): string {
|
||||
if (typeof version === "string" && semver.valid(version)) {
|
||||
return version;
|
||||
}
|
||||
|
||||
invariant(
|
||||
typeof version === "number" ||
|
||||
(typeof version === "string" && versionRegExp.test(version)),
|
||||
`'${version}' is not a valid version`,
|
||||
);
|
||||
|
||||
const split = version.toString().split(".");
|
||||
while (split.length < 3) {
|
||||
split.push("0");
|
||||
}
|
||||
return split.join(".");
|
||||
}
|
||||
|
||||
export function isUnreleasedVersion(
|
||||
version: string | number,
|
||||
env: string,
|
||||
): boolean {
|
||||
const unreleasedLabel = unreleasedLabels[env];
|
||||
return (
|
||||
!!unreleasedLabel && unreleasedLabel === version.toString().toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
export function getLowestUnreleased(a: string, b: string, env: string): string {
|
||||
const unreleasedLabel = unreleasedLabels[env];
|
||||
const hasUnreleased = [a, b].some(item => item === unreleasedLabel);
|
||||
if (hasUnreleased) {
|
||||
return a === hasUnreleased ? b : a || b;
|
||||
}
|
||||
return semverMin(a, b);
|
||||
}
|
||||
|
||||
export function getLowestImplementedVersion(
|
||||
plugin: Targets,
|
||||
environment: Target,
|
||||
): string {
|
||||
const result = plugin[environment];
|
||||
// When Android support data is absent, use Chrome data as fallback
|
||||
if (!result && environment === "android") {
|
||||
return plugin.chrome;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1,27 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const utils = require("../lib/utils");
|
||||
|
||||
const { prettifyTargets, prettifyVersion, semverify } = utils;
|
||||
|
||||
describe("utils", () => {
|
||||
describe("semverify", () => {
|
||||
it("returns", () => {
|
||||
expect(semverify("1")).toBe("1.0.0");
|
||||
expect(semverify("1.0")).toBe("1.0.0");
|
||||
expect(semverify("1.0.0")).toBe("1.0.0");
|
||||
expect(semverify(1)).toBe("1.0.0");
|
||||
expect(semverify(1.2)).toBe("1.2.0");
|
||||
});
|
||||
|
||||
it("throws", () => {
|
||||
const invalidSemver = () => {
|
||||
semverify("invalid");
|
||||
};
|
||||
expect(invalidSemver).toThrow();
|
||||
});
|
||||
});
|
||||
import { prettifyTargets, prettifyVersion } from "../lib/pretty";
|
||||
|
||||
describe("pretty", () => {
|
||||
describe("prettifyVersion", () => {
|
||||
it("returns", () => {
|
||||
expect(prettifyVersion(true)).toBe(true);
|
||||
@ -1,5 +1,5 @@
|
||||
import browserslist from "browserslist";
|
||||
import getTargets from "../lib/targets-parser";
|
||||
import getTargets from "..";
|
||||
|
||||
describe("getTargets", () => {
|
||||
it("parses", () => {
|
||||
@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
|
||||
const { targetsSupported } = require("../lib/filter-items");
|
||||
|
||||
describe("targetsSupported", () => {
|
||||
const MAX_VERSION = `${Number.MAX_SAFE_INTEGER}.0.0`;
|
||||
|
||||
it("returns false if no targets are specified", () => {
|
||||
expect(targetsSupported({}, {})).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false if plugin feature is not implemented in one or more targets", () => {
|
||||
let targets;
|
||||
const plugin = {
|
||||
edge: false,
|
||||
firefox: 45,
|
||||
chrome: 49,
|
||||
};
|
||||
|
||||
targets = {
|
||||
chrome: MAX_VERSION,
|
||||
firefox: MAX_VERSION,
|
||||
};
|
||||
expect(targetsSupported(targets, plugin)).toBe(true);
|
||||
|
||||
targets = {
|
||||
edge: "12",
|
||||
};
|
||||
expect(targetsSupported(targets, plugin)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns true if plugin feature is implemented by lower than target", () => {
|
||||
const plugin = {
|
||||
chrome: 49,
|
||||
};
|
||||
const targets = {
|
||||
chrome: MAX_VERSION,
|
||||
};
|
||||
|
||||
expect(targetsSupported(targets, plugin)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true if plugin feature is implemented is equal to target", () => {
|
||||
const plugin = {
|
||||
chrome: 49,
|
||||
};
|
||||
const targets = {
|
||||
chrome: "49.0.0",
|
||||
};
|
||||
expect(targetsSupported(targets, plugin)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false if plugin feature is implemented is greater than target", () => {
|
||||
const plugin = {
|
||||
chrome: 50,
|
||||
};
|
||||
const targets = {
|
||||
chrome: "49.0.0",
|
||||
};
|
||||
expect(targetsSupported(targets, plugin)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns when target is a decimal", () => {
|
||||
const plugin = {
|
||||
node: 6.9,
|
||||
};
|
||||
const targets = {
|
||||
node: "6.10.0",
|
||||
};
|
||||
expect(targetsSupported(targets, plugin)).toBe(true);
|
||||
});
|
||||
|
||||
it("throws an error if target version is invalid", () => {
|
||||
const plugin = {
|
||||
chrome: 50,
|
||||
};
|
||||
const targets = {
|
||||
chrome: 55,
|
||||
};
|
||||
expect(() => targetsSupported(targets, plugin)).toThrow();
|
||||
});
|
||||
});
|
||||
20
packages/babel-helper-compilation-targets/test/utils.spec.js
Normal file
20
packages/babel-helper-compilation-targets/test/utils.spec.js
Normal file
@ -0,0 +1,20 @@
|
||||
import { semverify } from "../lib/utils";
|
||||
|
||||
describe("utils", () => {
|
||||
describe("semverify", () => {
|
||||
it("returns", () => {
|
||||
expect(semverify("1")).toBe("1.0.0");
|
||||
expect(semverify("1.0")).toBe("1.0.0");
|
||||
expect(semverify("1.0.0")).toBe("1.0.0");
|
||||
expect(semverify(1)).toBe("1.0.0");
|
||||
expect(semverify(1.2)).toBe("1.2.0");
|
||||
});
|
||||
|
||||
it("throws", () => {
|
||||
const invalidSemver = () => {
|
||||
semverify("invalid");
|
||||
};
|
||||
expect(invalidSemver).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
3
packages/babel-preset-env/data/built-in-modules.js
Normal file
3
packages/babel-preset-env/data/built-in-modules.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/native-modules");
|
||||
3
packages/babel-preset-env/data/built-in-modules.json.js
Normal file
3
packages/babel-preset-env/data/built-in-modules.json.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/native-modules");
|
||||
4
packages/babel-preset-env/data/built-ins.js
Normal file
4
packages/babel-preset-env/data/built-ins.js
Normal file
@ -0,0 +1,4 @@
|
||||
// TODO: Remove in Babel 8
|
||||
// https://github.com/vuejs/vue-cli/issues/3671
|
||||
|
||||
module.exports = require("./corejs2-built-ins.json");
|
||||
3
packages/babel-preset-env/data/corejs2-built-ins.js
Normal file
3
packages/babel-preset-env/data/corejs2-built-ins.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/corejs2-built-ins");
|
||||
3
packages/babel-preset-env/data/corejs2-built-ins.json.js
Normal file
3
packages/babel-preset-env/data/corejs2-built-ins.json.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/corejs2-built-ins");
|
||||
3
packages/babel-preset-env/data/plugins.js
Normal file
3
packages/babel-preset-env/data/plugins.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/plugins");
|
||||
3
packages/babel-preset-env/data/plugins.json.js
Normal file
3
packages/babel-preset-env/data/plugins.json.js
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/compat-data/plugins");
|
||||
@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
safari: "tp",
|
||||
};
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
module.exports = require("@babel/helper-compilation-targets").unreleasedLabels;
|
||||
|
||||
@ -10,10 +10,9 @@
|
||||
},
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-preset-env",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"build-data": "./scripts/download-compat-table.sh; node ./scripts/build-data.js; node ./scripts/build-modules-support.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^0.0.0",
|
||||
"@babel/helper-compilation-targets": "^0.0.0",
|
||||
"@babel/helper-module-imports": "^7.7.4",
|
||||
"@babel/helper-plugin-utils": "^7.0.0",
|
||||
"@babel/plugin-proposal-async-generator-functions": "^7.7.4",
|
||||
@ -74,8 +73,6 @@
|
||||
"@babel/core": "^7.7.7",
|
||||
"@babel/helper-fixtures": "^7.6.3",
|
||||
"@babel/helper-plugin-test-runner": "^7.7.4",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"caniuse-db": "1.0.30000969",
|
||||
"electron-to-chromium": "1.3.113"
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,9 @@
|
||||
// @flow
|
||||
/*eslint quotes: ["error", "double", { "avoidEscape": true }]*/
|
||||
import semver from "semver";
|
||||
import {
|
||||
isUnreleasedVersion,
|
||||
prettifyVersion,
|
||||
semverify,
|
||||
getLowestImplementedVersion,
|
||||
} from "./utils";
|
||||
|
||||
import type { Targets } from "./types";
|
||||
import {
|
||||
getInclusionReasons,
|
||||
type Targets,
|
||||
} from "@babel/helper-compilation-targets";
|
||||
|
||||
const wordEnds = (size: number) => {
|
||||
return size > 1 ? "s" : "";
|
||||
@ -21,29 +16,7 @@ export const logPluginOrPolyfill = (
|
||||
targetVersions: Targets,
|
||||
list: { [key: string]: Targets },
|
||||
) => {
|
||||
const minVersions = list[item] || {};
|
||||
|
||||
const filteredList = Object.keys(targetVersions).reduce((result, env) => {
|
||||
const minVersion = getLowestImplementedVersion(minVersions, env);
|
||||
const targetVersion = targetVersions[env];
|
||||
|
||||
if (!minVersion) {
|
||||
result[env] = prettifyVersion(targetVersion);
|
||||
} else {
|
||||
const minIsUnreleased = isUnreleasedVersion(minVersion, env);
|
||||
const targetIsUnreleased = isUnreleasedVersion(targetVersion, env);
|
||||
|
||||
if (
|
||||
!targetIsUnreleased &&
|
||||
(minIsUnreleased ||
|
||||
semver.lt(targetVersion.toString(), semverify(minVersion)))
|
||||
) {
|
||||
result[env] = prettifyVersion(targetVersion);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
const filteredList = getInclusionReasons(item, targetVersions, list);
|
||||
|
||||
const formattedTargets = JSON.stringify(filteredList)
|
||||
.replace(/,/g, ", ")
|
||||
|
||||
@ -1,103 +1,11 @@
|
||||
// @flow
|
||||
import semver from "semver";
|
||||
import {
|
||||
semverify,
|
||||
isUnreleasedVersion,
|
||||
getLowestImplementedVersion,
|
||||
} from "./utils";
|
||||
|
||||
import type { Targets } from "./types";
|
||||
|
||||
export function isPluginRequired(
|
||||
supportedEnvironments: Targets,
|
||||
plugin: Targets,
|
||||
) {
|
||||
const targetEnvironments = Object.keys(supportedEnvironments);
|
||||
|
||||
if (targetEnvironments.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const isRequiredForEnvironments = targetEnvironments.filter(environment => {
|
||||
const lowestImplementedVersion = getLowestImplementedVersion(
|
||||
plugin,
|
||||
environment,
|
||||
);
|
||||
// Feature is not implemented in that environment
|
||||
if (!lowestImplementedVersion) {
|
||||
return true;
|
||||
}
|
||||
const lowestTargetedVersion = supportedEnvironments[environment];
|
||||
|
||||
// If targets has unreleased value as a lowest version, then don't require a plugin.
|
||||
if (isUnreleasedVersion(lowestTargetedVersion, environment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Include plugin if it is supported in the unreleased environment, which wasn't specified in targets
|
||||
if (isUnreleasedVersion(lowestImplementedVersion, environment)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!semver.valid(lowestTargetedVersion.toString())) {
|
||||
throw new Error(
|
||||
`Invalid version passed for target "${environment}": "${lowestTargetedVersion}". ` +
|
||||
"Versions must be in semver format (major.minor.patch)",
|
||||
);
|
||||
}
|
||||
|
||||
return semver.gt(
|
||||
semverify(lowestImplementedVersion),
|
||||
lowestTargetedVersion.toString(),
|
||||
);
|
||||
});
|
||||
|
||||
return isRequiredForEnvironments.length > 0;
|
||||
}
|
||||
|
||||
export default function(
|
||||
list: { [feature: string]: Targets },
|
||||
includes: Set<string>,
|
||||
excludes: Set<string>,
|
||||
targets: Targets,
|
||||
defaultIncludes: Array<string> | null,
|
||||
defaultExcludes?: Array<string> | null,
|
||||
pluginSyntaxMap?: Map<string, string | null>,
|
||||
) {
|
||||
const result = new Set<string>();
|
||||
|
||||
for (const item in list) {
|
||||
if (
|
||||
!excludes.has(item) &&
|
||||
(isPluginRequired(targets, list[item]) || includes.has(item))
|
||||
) {
|
||||
result.add(item);
|
||||
} else if (pluginSyntaxMap) {
|
||||
const shippedProposalsSyntax = pluginSyntaxMap.get(item);
|
||||
|
||||
if (shippedProposalsSyntax) {
|
||||
result.add(shippedProposalsSyntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIncludes) {
|
||||
defaultIncludes.forEach(item => !excludes.has(item) && result.add(item));
|
||||
}
|
||||
|
||||
if (defaultExcludes) {
|
||||
defaultExcludes.forEach(item => !includes.has(item) && result.delete(item));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function removeUnnecessaryItems(
|
||||
items: Set<string>,
|
||||
overlapping: Map<string, Set<string>>,
|
||||
overlapping: { [name: string]: string[] },
|
||||
) {
|
||||
items.forEach(item => {
|
||||
const names = overlapping.get(item);
|
||||
if (names) names.forEach(name => items.delete(name));
|
||||
// $FlowIgnore Flow doesn't support calls in optional chains
|
||||
overlapping[item]?.forEach(name => items.delete(name));
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
import { SemVer } from "semver";
|
||||
import { logPluginOrPolyfill } from "./debug";
|
||||
import getOptionSpecificExcludesFor from "./get-option-specific-excludes";
|
||||
import filterItems, { removeUnnecessaryItems } from "./filter-items";
|
||||
import { removeUnnecessaryItems } from "./filter-items";
|
||||
import moduleTransformations from "./module-transformations";
|
||||
import normalizeOptions from "./normalize-options";
|
||||
import pluginList from "../data/plugins.json";
|
||||
import pluginList from "@babel/compat-data/plugins";
|
||||
import { proposalPlugins, pluginSyntaxMap } from "../data/shipped-proposals";
|
||||
import overlappingPlugins from "../data/overlapping-plugins";
|
||||
import overlappingPlugins from "@babel/compat-data/overlapping-plugins";
|
||||
|
||||
import addCoreJS2UsagePlugin from "./polyfills/corejs2/usage-plugin";
|
||||
import addCoreJS3UsagePlugin from "./polyfills/corejs3/usage-plugin";
|
||||
@ -17,15 +17,25 @@ import replaceCoreJS2EntryPlugin from "./polyfills/corejs2/entry-plugin";
|
||||
import replaceCoreJS3EntryPlugin from "./polyfills/corejs3/entry-plugin";
|
||||
import removeRegeneratorEntryPlugin from "./polyfills/regenerator/entry-plugin";
|
||||
|
||||
import getTargets from "./targets-parser";
|
||||
import getTargets, {
|
||||
prettifyTargets,
|
||||
filterItems,
|
||||
isRequired,
|
||||
type Targets,
|
||||
} from "@babel/helper-compilation-targets";
|
||||
import availablePlugins from "./available-plugins";
|
||||
import { filterStageFromList, prettifyTargets } from "./utils";
|
||||
import { filterStageFromList } from "./utils";
|
||||
import { declare } from "@babel/helper-plugin-utils";
|
||||
|
||||
import typeof ModuleTransformationsType from "./module-transformations";
|
||||
import type { BuiltInsOption, Targets, ModuleOption } from "./types";
|
||||
import type { BuiltInsOption, ModuleOption } from "./types";
|
||||
|
||||
export { isPluginRequired } from "./filter-items";
|
||||
// TODO: Remove in Babel 8
|
||||
export function isPluginRequired(targets: Targets, support: Targets) {
|
||||
return !isRequired("fake-name", targets, {
|
||||
compatData: { "fake-name": support },
|
||||
});
|
||||
}
|
||||
|
||||
const pluginListWithoutProposals = filterStageFromList(
|
||||
pluginList,
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
// @flow
|
||||
import corejs3Polyfills from "core-js-compat/data";
|
||||
import findSuggestion from "levenary";
|
||||
import invariant from "invariant";
|
||||
import { coerce, SemVer } from "semver";
|
||||
import corejs2Polyfills from "../data/corejs2-built-ins.json";
|
||||
import pluginsList from "../data/plugins.json";
|
||||
import corejs2Polyfills from "@babel/compat-data/corejs2-built-ins";
|
||||
import pluginsList from "@babel/compat-data/plugins";
|
||||
import moduleTransformations from "./module-transformations";
|
||||
import { TopLevelOptions, ModulesOption, UseBuiltInsOption } from "./options";
|
||||
import { defaultWebIncludes } from "./polyfills/corejs2/get-platform-specific-default";
|
||||
import { isBrowsersQueryValid } from "./targets-parser";
|
||||
import findSuggestion from "levenary";
|
||||
|
||||
import type {
|
||||
BuiltInsOption,
|
||||
@ -26,7 +25,7 @@ const validateTopLevelOptions = (options: Options) => {
|
||||
if (!TopLevelOptions[option]) {
|
||||
throw new Error(
|
||||
`Invalid Option: ${option} is not a valid top-level option.
|
||||
Maybe you meant to use '${findSuggestion(validOptions, option)}'?`,
|
||||
Maybe you meant to use '${findSuggestion(option, validOptions)}'?`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -121,7 +120,7 @@ export const checkDuplicateIncludeExcludes = (
|
||||
|
||||
const normalizeTargets = targets => {
|
||||
// TODO: Allow to use only query or strings as a targets from next breaking change.
|
||||
if (isBrowsersQueryValid(targets)) {
|
||||
if (typeof targets === "string" || Array.isArray(targets)) {
|
||||
return { browsers: targets };
|
||||
}
|
||||
return {
|
||||
|
||||
@ -31,22 +31,3 @@ export const UseBuiltInsOption = {
|
||||
entry: "entry",
|
||||
usage: "usage",
|
||||
};
|
||||
|
||||
export const TargetNames = {
|
||||
esmodules: "esmodules",
|
||||
node: "node",
|
||||
browsers: "browsers",
|
||||
chrome: "chrome",
|
||||
opera: "opera",
|
||||
edge: "edge",
|
||||
firefox: "firefox",
|
||||
safari: "safari",
|
||||
ie: "ie",
|
||||
ios: "ios",
|
||||
android: "android",
|
||||
electron: "electron",
|
||||
samsung: "samsung",
|
||||
|
||||
// deprecated
|
||||
uglify: "uglify",
|
||||
};
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import corejs2Polyfills from "../../../data/corejs2-built-ins.json";
|
||||
import corejs2Polyfills from "@babel/compat-data/corejs2-built-ins";
|
||||
import { filterItems } from "@babel/helper-compilation-targets";
|
||||
import getPlatformSpecificDefaultFor from "./get-platform-specific-default";
|
||||
import filterItems from "../../filter-items";
|
||||
import {
|
||||
createImport,
|
||||
isPolyfillSource,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import type { Targets } from "../../types";
|
||||
import type { Targets } from "@babel/helper-compilation-targets";
|
||||
|
||||
export const defaultWebIncludes = [
|
||||
"web.timers",
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import corejs2Polyfills from "../../../data/corejs2-built-ins.json";
|
||||
import corejs2Polyfills from "@babel/compat-data/corejs2-built-ins";
|
||||
import { filterItems } from "@babel/helper-compilation-targets";
|
||||
import getPlatformSpecificDefaultFor from "./get-platform-specific-default";
|
||||
import filterItems from "../../filter-items";
|
||||
import {
|
||||
BuiltIns,
|
||||
StaticProperties,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import corejs3Polyfills from "core-js-compat/data";
|
||||
import corejsEntries from "core-js-compat/entries";
|
||||
import getModulesListForTargetVersion from "core-js-compat/get-modules-list-for-target-version";
|
||||
import filterItems from "../../filter-items";
|
||||
import { filterItems } from "@babel/helper-compilation-targets";
|
||||
import {
|
||||
has,
|
||||
intersection,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import corejs3Polyfills from "core-js-compat/data";
|
||||
import corejs3ShippedProposalsList from "./shipped-proposals";
|
||||
import getModulesListForTargetVersion from "core-js-compat/get-modules-list-for-target-version";
|
||||
import filterItems from "../../filter-items";
|
||||
import { filterItems } from "@babel/helper-compilation-targets";
|
||||
import {
|
||||
BuiltIns,
|
||||
StaticProperties,
|
||||
|
||||
@ -1,261 +1,7 @@
|
||||
// @flow
|
||||
// TODO: Remove in Babel 8
|
||||
|
||||
import browserslist from "browserslist";
|
||||
import invariant from "invariant";
|
||||
import semver from "semver";
|
||||
import findSuggestion from "levenary";
|
||||
import { semverify, isUnreleasedVersion, getLowestUnreleased } from "./utils";
|
||||
import browserModulesData from "../data/built-in-modules.json";
|
||||
import { TargetNames } from "./options";
|
||||
import type { Targets } from "./types";
|
||||
|
||||
const browserslistDefaults = browserslist.defaults;
|
||||
|
||||
const validBrowserslistTargets = [
|
||||
...Object.keys(browserslist.data),
|
||||
...Object.keys(browserslist.aliases),
|
||||
];
|
||||
|
||||
const objectToBrowserslist = (object: Targets): Array<string> => {
|
||||
return Object.keys(object).reduce((list, targetName) => {
|
||||
if (validBrowserslistTargets.indexOf(targetName) >= 0) {
|
||||
const targetVersion = object[targetName];
|
||||
return list.concat(`${targetName} ${targetVersion}`);
|
||||
}
|
||||
return list;
|
||||
}, []);
|
||||
};
|
||||
|
||||
const validateTargetNames = (targets: Targets): void => {
|
||||
const validTargets = Object.keys(TargetNames);
|
||||
for (const target in targets) {
|
||||
if (!TargetNames[target]) {
|
||||
throw new Error(
|
||||
`Invalid Option: '${target}' is not a valid target
|
||||
Maybe you meant to use '${findSuggestion(validTargets, target)}'?`,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const browserNameMap = {
|
||||
and_chr: "chrome",
|
||||
and_ff: "firefox",
|
||||
android: "android",
|
||||
chrome: "chrome",
|
||||
edge: "edge",
|
||||
firefox: "firefox",
|
||||
ie: "ie",
|
||||
ie_mob: "ie",
|
||||
ios_saf: "ios",
|
||||
node: "node",
|
||||
op_mob: "opera",
|
||||
opera: "opera",
|
||||
safari: "safari",
|
||||
samsung: "samsung",
|
||||
};
|
||||
|
||||
export const isBrowsersQueryValid = (
|
||||
browsers: string | Array<string> | Targets,
|
||||
): boolean => typeof browsers === "string" || Array.isArray(browsers);
|
||||
|
||||
const validateBrowsers = browsers => {
|
||||
invariant(
|
||||
typeof browsers === "undefined" || isBrowsersQueryValid(browsers),
|
||||
`Invalid Option: '${browsers}' is not a valid browserslist query`,
|
||||
);
|
||||
|
||||
return browsers;
|
||||
};
|
||||
|
||||
export const semverMin = (first: ?string, second: string): string => {
|
||||
return first && semver.lt(first, second) ? first : second;
|
||||
};
|
||||
|
||||
const mergeBrowsers = (fromQuery: Targets, fromTarget: Targets) => {
|
||||
return Object.keys(fromTarget).reduce((queryObj, targKey) => {
|
||||
if (targKey !== TargetNames.browsers) {
|
||||
queryObj[targKey] = fromTarget[targKey];
|
||||
}
|
||||
return queryObj;
|
||||
}, fromQuery);
|
||||
};
|
||||
|
||||
const getLowestVersions = (browsers: Array<string>): Targets => {
|
||||
return browsers.reduce((all: Object, browser: string): Object => {
|
||||
const [browserName, browserVersion] = browser.split(" ");
|
||||
const normalizedBrowserName = browserNameMap[browserName];
|
||||
|
||||
if (!normalizedBrowserName) {
|
||||
return all;
|
||||
}
|
||||
|
||||
try {
|
||||
// Browser version can return as "10.0-10.2"
|
||||
const splitVersion = browserVersion.split("-")[0].toLowerCase();
|
||||
const isSplitUnreleased = isUnreleasedVersion(splitVersion, browserName);
|
||||
|
||||
if (!all[normalizedBrowserName]) {
|
||||
all[normalizedBrowserName] = isSplitUnreleased
|
||||
? splitVersion
|
||||
: semverify(splitVersion);
|
||||
return all;
|
||||
}
|
||||
|
||||
const version = all[normalizedBrowserName];
|
||||
const isUnreleased = isUnreleasedVersion(version, browserName);
|
||||
|
||||
if (isUnreleased && isSplitUnreleased) {
|
||||
all[normalizedBrowserName] = getLowestUnreleased(
|
||||
version,
|
||||
splitVersion,
|
||||
browserName,
|
||||
);
|
||||
} else if (isUnreleased) {
|
||||
all[normalizedBrowserName] = semverify(splitVersion);
|
||||
} else if (!isUnreleased && !isSplitUnreleased) {
|
||||
const parsedBrowserVersion = semverify(splitVersion);
|
||||
|
||||
all[normalizedBrowserName] = semverMin(version, parsedBrowserVersion);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return all;
|
||||
}, {});
|
||||
};
|
||||
|
||||
const outputDecimalWarning = (decimalTargets: Array<Object>): void => {
|
||||
if (!decimalTargets || !decimalTargets.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Warning, the following targets are using a decimal version:");
|
||||
console.log("");
|
||||
decimalTargets.forEach(({ target, value }) =>
|
||||
console.log(` ${target}: ${value}`),
|
||||
);
|
||||
console.log("");
|
||||
console.log(
|
||||
"We recommend using a string for minor/patch versions to avoid numbers like 6.10",
|
||||
);
|
||||
console.log("getting parsed as 6.1, which can lead to unexpected behavior.");
|
||||
console.log("");
|
||||
};
|
||||
|
||||
const semverifyTarget = (target, value) => {
|
||||
try {
|
||||
return semverify(value);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Invalid Option: '${value}' is not a valid value for 'targets.${target}'.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const targetParserMap = {
|
||||
__default: (target, value) => {
|
||||
const version = isUnreleasedVersion(value, target)
|
||||
? value.toLowerCase()
|
||||
: semverifyTarget(target, value);
|
||||
return [target, version];
|
||||
},
|
||||
|
||||
// Parse `node: true` and `node: "current"` to version
|
||||
node: (target, value) => {
|
||||
const parsed =
|
||||
value === true || value === "current"
|
||||
? process.versions.node
|
||||
: semverifyTarget(target, value);
|
||||
return [target, parsed];
|
||||
},
|
||||
};
|
||||
|
||||
type ParsedResult = {
|
||||
targets: Targets,
|
||||
decimalWarnings: Array<Object>,
|
||||
};
|
||||
|
||||
const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
|
||||
const targetOpts: Targets = {};
|
||||
|
||||
validateTargetNames(targets);
|
||||
|
||||
// `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
|
||||
// These values OVERRIDE the `browsers` field.
|
||||
if (targets.esmodules) {
|
||||
const supportsESModules = browserModulesData["es6.module"];
|
||||
targets.browsers = Object.keys(supportsESModules)
|
||||
.map(browser => `${browser} ${supportsESModules[browser]}`)
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
// Parse browsers target via browserslist
|
||||
const browsersquery = validateBrowsers(targets.browsers);
|
||||
|
||||
const hasTargets = Object.keys(targets).length > 0;
|
||||
const shouldParseBrowsers = !!targets.browsers;
|
||||
const shouldSearchForConfig =
|
||||
!options.ignoreBrowserslistConfig && !hasTargets;
|
||||
|
||||
if (shouldParseBrowsers || shouldSearchForConfig) {
|
||||
// If no targets are passed, we need to overwrite browserslist's defaults
|
||||
// so that we enable all transforms (acting like the now deprecated
|
||||
// preset-latest).
|
||||
//
|
||||
// Note, if browserslist resolves the config (ex. package.json), then usage
|
||||
// of `defaults` in queries will be different since we don't want to break
|
||||
// the behavior of "no targets is the same as preset-latest".
|
||||
if (!hasTargets) {
|
||||
browserslist.defaults = objectToBrowserslist(targets);
|
||||
}
|
||||
|
||||
const browsers = browserslist(browsersquery, {
|
||||
path: options.configPath,
|
||||
mobileToDesktop: true,
|
||||
});
|
||||
|
||||
const queryBrowsers = getLowestVersions(browsers);
|
||||
targets = mergeBrowsers(queryBrowsers, targets);
|
||||
|
||||
// Reset browserslist defaults
|
||||
browserslist.defaults = browserslistDefaults;
|
||||
}
|
||||
|
||||
// Parse remaining targets
|
||||
const parsed = Object.keys(targets)
|
||||
.filter(value => value !== TargetNames.esmodules)
|
||||
.sort()
|
||||
.reduce(
|
||||
(results: ParsedResult, target: string): ParsedResult => {
|
||||
if (target !== TargetNames.browsers) {
|
||||
const value = targets[target];
|
||||
|
||||
// Warn when specifying minor/patch as a decimal
|
||||
if (typeof value === "number" && value % 1 !== 0) {
|
||||
results.decimalWarnings.push({ target, value });
|
||||
}
|
||||
|
||||
// Check if we have a target parser?
|
||||
const parser = targetParserMap[target] || targetParserMap.__default;
|
||||
const [parsedTarget, parsedValue] = parser(target, value);
|
||||
|
||||
if (parsedValue) {
|
||||
// Merge (lowest wins)
|
||||
results.targets[parsedTarget] = parsedValue;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
{
|
||||
targets: targetOpts,
|
||||
decimalWarnings: [],
|
||||
},
|
||||
);
|
||||
|
||||
outputDecimalWarning(parsed.decimalWarnings);
|
||||
|
||||
return parsed.targets;
|
||||
};
|
||||
|
||||
export default getTargets;
|
||||
export {
|
||||
default,
|
||||
isBrowsersQueryValid,
|
||||
semverMin,
|
||||
} from "@babel/helper-compilation-targets";
|
||||
|
||||
@ -2,24 +2,7 @@
|
||||
|
||||
import { ModulesOption, UseBuiltInsOption } from "./options";
|
||||
import type { NormalizedCorejsOption } from "./normalize-options";
|
||||
|
||||
// Targets
|
||||
export type Target =
|
||||
| "node"
|
||||
| "chrome"
|
||||
| "opera"
|
||||
| "edge"
|
||||
| "firefox"
|
||||
| "safari"
|
||||
| "ie"
|
||||
| "ios"
|
||||
| "android"
|
||||
| "electron"
|
||||
| "samsung";
|
||||
|
||||
export type Targets = {
|
||||
[target: Target]: string,
|
||||
};
|
||||
import type { Targets } from "@babel/helper-compilation-targets";
|
||||
|
||||
// Options
|
||||
// Use explicit modules to prevent typo errors.
|
||||
|
||||
@ -2,12 +2,8 @@
|
||||
|
||||
import * as t from "@babel/types";
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import invariant from "invariant";
|
||||
import semver from "semver";
|
||||
import { addSideEffect } from "@babel/helper-module-imports";
|
||||
import unreleasedLabels from "../data/unreleased-labels";
|
||||
import { semverMin } from "./targets-parser";
|
||||
import type { Target, Targets } from "./types";
|
||||
import type { Targets } from "@babel/helper-compilation-targets";
|
||||
|
||||
export const has = Object.hasOwnProperty.call.bind(Object.hasOwnProperty);
|
||||
|
||||
@ -18,28 +14,6 @@ export function getType(target: any): string {
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
const versionRegExp = /^(\d+|\d+.\d+)$/;
|
||||
|
||||
// Convert version to a semver value.
|
||||
// 2.5 -> 2.5.0; 1 -> 1.0.0;
|
||||
export function semverify(version: number | string): string {
|
||||
if (typeof version === "string" && semver.valid(version)) {
|
||||
return version;
|
||||
}
|
||||
|
||||
invariant(
|
||||
typeof version === "number" ||
|
||||
(typeof version === "string" && versionRegExp.test(version)),
|
||||
`'${version}' is not a valid version`,
|
||||
);
|
||||
|
||||
const split = version.toString().split(".");
|
||||
while (split.length < 3) {
|
||||
split.push("0");
|
||||
}
|
||||
return split.join(".");
|
||||
}
|
||||
|
||||
export function intersection<T>(
|
||||
first: Set<T>,
|
||||
second: Set<T>,
|
||||
@ -52,71 +26,6 @@ export function intersection<T>(
|
||||
return result;
|
||||
}
|
||||
|
||||
export function prettifyVersion(version: string) {
|
||||
if (typeof version !== "string") {
|
||||
return version;
|
||||
}
|
||||
|
||||
const parts = [semver.major(version)];
|
||||
const minor = semver.minor(version);
|
||||
const patch = semver.patch(version);
|
||||
|
||||
if (minor || patch) {
|
||||
parts.push(minor);
|
||||
}
|
||||
|
||||
if (patch) {
|
||||
parts.push(patch);
|
||||
}
|
||||
|
||||
return parts.join(".");
|
||||
}
|
||||
|
||||
export function prettifyTargets(targets: Targets): Targets {
|
||||
return Object.keys(targets).reduce((results, target) => {
|
||||
let value = targets[target];
|
||||
|
||||
const unreleasedLabel = unreleasedLabels[target];
|
||||
if (typeof value === "string" && unreleasedLabel !== value) {
|
||||
value = prettifyVersion(value);
|
||||
}
|
||||
|
||||
results[target] = value;
|
||||
return results;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function isUnreleasedVersion(
|
||||
version: string | number,
|
||||
env: string,
|
||||
): boolean {
|
||||
const unreleasedLabel = unreleasedLabels[env];
|
||||
return (
|
||||
!!unreleasedLabel && unreleasedLabel === version.toString().toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
export function getLowestUnreleased(a: string, b: string, env: string): string {
|
||||
const unreleasedLabel = unreleasedLabels[env];
|
||||
const hasUnreleased = [a, b].some(item => item === unreleasedLabel);
|
||||
if (hasUnreleased) {
|
||||
return a === hasUnreleased ? b : a || b;
|
||||
}
|
||||
return semverMin(a, b);
|
||||
}
|
||||
|
||||
export function getLowestImplementedVersion(
|
||||
plugin: Targets,
|
||||
environment: Target,
|
||||
): string {
|
||||
const result = plugin[environment];
|
||||
// When Android support data is absent, use Chrome data as fallback
|
||||
if (!result && environment === "android") {
|
||||
return plugin.chrome;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filterStageFromList(
|
||||
list: { [feature: string]: Targets },
|
||||
stageList: { [feature: string]: boolean },
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const presetEnv = require("../");
|
||||
|
||||
describe("isPluginRequired", () => {
|
||||
const MAX_VERSION = `${Number.MAX_SAFE_INTEGER}.0.0`;
|
||||
|
||||
it("returns true if no targets are specified", () => {
|
||||
expect(presetEnv.isPluginRequired({}, {})).toBe(true);
|
||||
});
|
||||
|
||||
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: MAX_VERSION,
|
||||
firefox: MAX_VERSION,
|
||||
};
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(false);
|
||||
|
||||
targets = {
|
||||
edge: "12",
|
||||
};
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false if plugin feature is implemented by lower than target", () => {
|
||||
const plugin = {
|
||||
chrome: 49,
|
||||
};
|
||||
const targets = {
|
||||
chrome: MAX_VERSION,
|
||||
};
|
||||
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false if plugin feature is implemented is equal to target", () => {
|
||||
const plugin = {
|
||||
chrome: 49,
|
||||
};
|
||||
const targets = {
|
||||
chrome: "49.0.0",
|
||||
};
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns true if plugin feature is implemented is greater than target", () => {
|
||||
const plugin = {
|
||||
chrome: 50,
|
||||
};
|
||||
const targets = {
|
||||
chrome: "49.0.0",
|
||||
};
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns when target is a decimal", () => {
|
||||
const plugin = {
|
||||
node: 6.9,
|
||||
};
|
||||
const targets = {
|
||||
node: "6.10.0",
|
||||
};
|
||||
expect(presetEnv.isPluginRequired(targets, plugin)).toBe(false);
|
||||
});
|
||||
|
||||
it("throws an error if target version is invalid", () => {
|
||||
const plugin = {
|
||||
chrome: 50,
|
||||
};
|
||||
const targets = {
|
||||
chrome: 55,
|
||||
};
|
||||
expect(() => presetEnv.isPluginRequired(targets, plugin)).toThrow();
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user