Skip to content
This repository has been archived by the owner on May 11, 2018. It is now read-only.

[WIP] Add node's "engines" option #114

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2d51bba
Parse engines node’s version from package.json.
yavorsky Dec 28, 2016
3f60aeb
Remove logs, move some staff to utils.
yavorsky Dec 28, 2016
3036ac5
Fix linting.
yavorsky Dec 28, 2016
0f1b25f
Fix indentation.
yavorsky Jan 1, 2017
3134576
Add engines option to package.json.
yavorsky Jan 1, 2017
b88e5f8
Use options for isPluginRequired.
yavorsky Jan 1, 2017
67f9c15
Add node-engines to fixtures.
yavorsky Jan 1, 2017
7a5da94
Add engines and getLowestFromSemverValue tests.
yavorsky Jan 1, 2017
b97d48b
Fix lint warns.
yavorsky Jan 1, 2017
568e0dc
Remove yarn.lock
yavorsky Jan 6, 2017
899b906
Add yarn.lock to gitignore.
yavorsky Jan 6, 2017
f1e3efd
Consider devEngines.
yavorsky Jan 6, 2017
29f7b6a
devEngines gt 4.x.
yavorsky Jan 6, 2017
f71eac9
Add BABEL_ENV production/development cases.
yavorsky Jan 6, 2017
2d22e03
Cover ‘*’ and wrong semver format.
yavorsky Jan 6, 2017
0696ea9
Fix indentation.
yavorsky Jan 6, 2017
ef95087
Use chrome is a number in node-engines fixtures.
yavorsky Jan 6, 2017
1838b68
Update engines and devEngines.
yavorsky Jan 7, 2017
b20ff6c
Merge branch 'master' into node-engines
yavorsky Jan 30, 2017
be36460
Refactor config parsing. Add annotations.
yavorsky Jan 31, 2017
f6cafdc
Update tests
yavorsky Jan 31, 2017
f4c75bc
Concat root path with process.cwd()
yavorsky Jan 31, 2017
9048897
Add engines/devEngines fixtures.
yavorsky Jan 31, 2017
1667ab7
Update yarn.lock
yavorsky Jan 31, 2017
419b3bc
Update yarn.lock.
yavorsky Jan 31, 2017
4db8341
Remove yarn.lock from gitignore
yavorsky Jan 31, 2017
8d0c085
Merge branch '2.0' into node-engines
yavorsky Apr 10, 2017
20153f0
After merge fixes.
yavorsky Apr 10, 2017
a42a0a8
Fix environment
yavorsky Apr 10, 2017
ac38247
Fix all supported versions list
yavorsky Apr 10, 2017
9268e16
Remove unused vars
yavorsky Apr 10, 2017
f16683e
Find package.json recursively.
yavorsky Apr 10, 2017
d8a97f0
Fix package path.
yavorsky Apr 10, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
lib
.DS_Store
*.log
.vscode
.vscode
yarn.lock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you ignore yarn.lock?

Copy link
Member Author

@yavorsky yavorsky Jan 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abouthiroppy yarn support will be added with the separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, to prevent commiting it every time unless it will be added, let's place it to .gitignore.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
"license": "MIT",
"repository": "https://github.com/babel/babel-preset-env",
"main": "lib/index.js",
"engines" : {
"node" : ">=0.12.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.10 here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, updated

},
"devEngines" : {
"node" : ">= 4.x"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can do 6 here (I dont remember)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

},
"scripts": {
"build": "rimraf lib && babel src -d lib",
"build-data": "node ./scripts/build-data.js",
Expand Down Expand Up @@ -60,6 +66,7 @@
"eslint-plugin-babel": "^4.0.0",
"eslint-plugin-flow-vars": "^0.5.0",
"eslint-plugin-flowtype": "^2.29.1",
"semver": "^5.3.0",
"lodash": "^4.15.0",
"mocha": "^3.0.2",
"rimraf": "^2.5.4"
Expand Down
125 changes: 94 additions & 31 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import pluginList from "../data/plugins.json";
import pluginFeatures from "../data/plugin-features";
import builtInsList from "../data/built-ins.json";
import browserslist from "browserslist";
import semver from "semver";
import path from "path";
import transformPolyfillRequirePlugin from "./transform-polyfill-require-plugin";
import electronToChromium from "../data/electron-to-chromium";
import { _extends, desemverify, semverify, getEnv } from "./utils";

export const MODULE_TRANSFORMATIONS = {
"amd": "transform-es2015-modules-amd",
Expand All @@ -18,13 +21,44 @@ const defaultInclude = [
"web.dom.iterable"
];

const browserNameMap = {
chrome: "chrome",
edge: "edge",
firefox: "firefox",
ie: "ie",
ios_saf: "ios",
safari: "safari"
};

export const validIncludesAndExcludes = [
...Object.keys(pluginFeatures),
...Object.keys(MODULE_TRANSFORMATIONS).map((m) => MODULE_TRANSFORMATIONS[m]),
...Object.keys(builtInsList),
...defaultInclude
];

const getVersionsFromList = (list) => {
return Object.keys(list).reduce((allVersions, currentItem) => {
const currentVersions = list[currentItem];
for (let envName in currentVersions) {
const currentVersion = allVersions[envName];
const envVersion = currentVersions[envName];

if (!currentVersion) {
allVersions[envName] = [envVersion];
} else if (currentVersion.indexOf(envVersion) === -1) {
allVersions[envName].push(envVersion);
}
}

for (let env in allVersions) {
allVersions[env].sort((a, b) => a - b);
}

return allVersions;
}, {});
};

/**
* Determine if a transformation is required
* @param {Object} supportedEnvironments An Object containing environment keys and the lowest
Expand All @@ -33,9 +67,9 @@ export const validIncludesAndExcludes = [
* version the feature was implmented in as a value
* @return {Boolean} Whether or not the transformation is required
*/
export const isPluginRequired = (supportedEnvironments, plugin) => {
export const isPluginRequired = (supportedEnvironments, plugin, options) => {
if (supportedEnvironments.browsers) {
supportedEnvironments = getTargets(supportedEnvironments);
supportedEnvironments = getTargets(supportedEnvironments, options);
}

const targetEnvironments = Object.keys(supportedEnvironments);
Expand Down Expand Up @@ -64,15 +98,6 @@ const isBrowsersQueryValid = (browsers) => {
return typeof browsers === "string" || Array.isArray(browsers);
};

const browserNameMap = {
chrome: "chrome",
edge: "edge",
firefox: "firefox",
ie: "ie",
ios_saf: "ios",
safari: "safari"
};

const getLowestVersions = (browsers) => {
return browsers.reduce((all, browser) => {
const [browserName, browserVersion] = browser.split(" ");
Expand All @@ -93,7 +118,47 @@ const mergeBrowsers = (fromQuery, fromTarget) => {
};

export const getCurrentNodeVersion = () => {
return parseFloat(process.versions.node);
return desemverify(process.versions.node);
};

const filterSatisfiedVersions = (range, versions) => {
return versions.filter((targ) => semver.satisfies(targ, range));
};

export const getLowestFromSemverValue = (version, versionsList) => {
let lowestSupported;
if (version === "*") {
return null;
}

if (semver.valid(version)) {
lowestSupported = parseFloat(version);
} else if (semver.validRange(version)) {
const versions = versionsList.map(semverify);
const allSupported = filterSatisfiedVersions(version, versions);
if (allSupported.length) {
lowestSupported = allSupported[0];
}
}
return lowestSupported ? desemverify(lowestSupported) : null;
};

export const getEnginesNodeVersion = (packageRoot, supportedVersions) => {
const env = getEnv(process.env);
const pkgPath = path.join(packageRoot, "package.json");

try {
const pkg = require(pkgPath);
const engines = env === "development" && pkg.devEngines || pkg.engines;
if (engines && engines.node) {
const version = engines.node;
return getLowestFromSemverValue(version, supportedVersions);
} else {
console.warn(`Can't get node.js version from \`engines\` field in ${pkgPath}.`);
}
} catch (e) {
console.warn(`Can't parse ${pkgPath} while trying to get node.js version from \`engines\` field.`);
}
};

export const electronVersionToChromeVersion = (semverVer) => {
Expand All @@ -116,24 +181,22 @@ export const electronVersionToChromeVersion = (semverVer) => {
return result;
};

const _extends = Object.assign || function (target) {
for (let i = 1; i < arguments.length; i++) {
const source = arguments[i];
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};


export const getTargets = (targets = {}) => {
export const getTargets = (targets = {}, options = {}) => {
const targetOps = _extends({}, targets);
const {node} = targetOps;

if (targetOps.node === true || targetOps.node === "current") {
if (node === true || node === "current") {
targetOps.node = getCurrentNodeVersion();
} else if (node === "engines") {
const lists = [pluginList];
if (options.useBuiltIns) {
lists.push(builtInsList);
}

const allSupportedVersions = getVersionsFromList(_extends({}, ...lists));
const supportedNodeVersions = allSupportedVersions["node"];
targetOps.node = getEnginesNodeVersion(process.cwd(), supportedNodeVersions);
}

// Rewrite Electron versions to their Chrome equivalents
Expand Down Expand Up @@ -237,17 +300,17 @@ export default function buildPreset(context, opts = {}) {
const include = validateIncludeOption(opts.whitelist || opts.include);
const exclude = validateExcludeOption(opts.exclude);
checkDuplicateIncludeExcludes(include.all, exclude.all);
const targets = getTargets(opts.targets);
const targets = getTargets(opts.targets, opts);
const debug = opts.debug;
const useBuiltIns = opts.useBuiltIns;

let transformations = Object.keys(pluginList)
.filter((pluginName) => isPluginRequired(targets, pluginList[pluginName]));
.filter((pluginName) => isPluginRequired(targets, pluginList[pluginName], opts));

let polyfills;
if (useBuiltIns) {
polyfills = Object.keys(builtInsList)
.filter((builtInName) => isPluginRequired(targets, builtInsList[builtInName]))
.filter((builtInName) => isPluginRequired(targets, builtInsList[builtInName], opts))
.concat(defaultInclude)
.filter((plugin) => exclude.builtIns.indexOf(plugin) === -1)
.concat(include.builtIns);
Expand All @@ -274,8 +337,8 @@ export default function buildPreset(context, opts = {}) {
}

const allTransformations = transformations
.filter((plugin) => exclude.plugins.indexOf(plugin) === -1)
.concat(include.plugins);
.filter((plugin) => exclude.plugins.indexOf(plugin) === -1)
.concat(include.plugins);

const regenerator = allTransformations.indexOf("transform-regenerator") >= 0;
const modulePlugin = moduleType !== false && MODULE_TRANSFORMATIONS[moduleType];
Expand Down
28 changes: 28 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const DEFAULT_ENV = "development";

export const _extends = Object.assign || function (target) {
for (let i = 1; i < arguments.length; i++) {
const source = arguments[i];
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};

export const desemverify = (version) => {
return parseFloat(version);
};

export const semverify = (version) => {
const isInt = version % 1 === 0;
const stringified = version.toString();
const strEnd = isInt ? ".0.0" : ".0";
return stringified + strEnd;
};

export const getEnv = (env) => {
return env.BABEL_ENV || env.NODE_ENV || DEFAULT_ENV;
};
1 change: 1 addition & 0 deletions test/fixtures/preset-options/node-engines/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const a = "1";
3 changes: 3 additions & 0 deletions test/fixtures/preset-options/node-engines/expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";

var a = "1";
10 changes: 10 additions & 0 deletions test/fixtures/preset-options/node-engines/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": [
["../../../../lib", {
"targets": {
"node": "engines",
"chrome": 55
}
}]
]
}
43 changes: 43 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,49 @@ describe("babel-preset-env", () => {
}), {
node: parseFloat(process.versions.node)
});

});

it("should return the current node version with option 'engines' with BABEL_ENV='development'", function() {
const prevEnv = process.env.BABEL_ENV;
process.env.BABEL_ENV = "development";

assert.deepEqual(babelPresetEnv.getTargets({
node: "engines"
}), {
node: 4
});

process.env.BABEL_ENV = prevEnv;
});

it("should return the current node version with option 'engines' with BABEL_ENV='production'", function() {
const prevEnv = process.env.BABEL_ENV;
process.env.BABEL_ENV = "production";

assert.deepEqual(babelPresetEnv.getTargets({
node: "engines"
}), {
node: 0.12
});
process.env.BABEL_ENV = prevEnv;
});
});

describe("getLowestFromSemverValue", () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but may want a test * returns null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Need to cover * as well. Thanks!

it("should return the lowest supported version from semver value '>=0.12'", function() {
const lowestNodeVersion = babelPresetEnv.getLowestFromSemverValue(">=0.12", [4, 5, 6]);
assert.equal(lowestNodeVersion, 4);
});

it("should return null from semver value '*'", function() {
const lowestNodeVersion = babelPresetEnv.getLowestFromSemverValue("*", [4, 5, 6]);
assert.equal(lowestNodeVersion, null);
});

it("should return null if version isnt a semver value", function() {
const lowestNodeVersion = babelPresetEnv.getLowestFromSemverValue("💩", [4, 5, 6]);
assert.equal(lowestNodeVersion, null);
});
});

Expand Down