From 37c9122c50722b06039f1cc2306a7c176fd3c786 Mon Sep 17 00:00:00 2001 From: Nick Jaggars Date: Fri, 27 Oct 2017 08:22:06 -0700 Subject: [PATCH] Include syntax-object-rest-spread in default Babel options for Node.js >= 8.3.0 Fixes #1554. --- docs/recipes/babelrc.md | 6 +++++ lib/babel-config.js | 8 +++++++ package-lock.json | 21 ++++++++++------- package.json | 2 ++ test/babel-config.js | 51 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 8 deletions(-) diff --git a/docs/recipes/babelrc.md b/docs/recipes/babelrc.md index 1c6131297..2e2604fe2 100644 --- a/docs/recipes/babelrc.md +++ b/docs/recipes/babelrc.md @@ -15,6 +15,12 @@ There are multiple options for configuring how AVA transpiles your tests using B AVA lets you use some nifty JavaScript features, like [async functions](https://github.com/avajs/ava#async-function-support). To make this work on older Node.js versions AVA transpiles the tests and helper files using the [`@ava/stage-4`](https://github.com/avajs/babel-preset-stage-4) Babel preset. This is great for projects where you do not use Babel for your source, but do want to use the newest JavaScript features for your tests. +### Using object rest/spread properties + +As of Node.js [8.3.0](https://github.com/nodejs/node/blob/v8.3.0/doc/changelogs/CHANGELOG_V8.md#8.3.0) [object rest/spread properties](https://github.com/tc39/proposal-object-rest-spread) is supported directly. This new language feature however has not yet reached [stage 4](http://2ality.com/2015/11/tc39-process.html#stage-4-finished), which means that AVA won't support it by default. That said, if you're using Node.js 8.3.0 or newer, AVA will load the [`syntax-object-rest-spread`](https://www.npmjs.com/package/babel-plugin-syntax-object-rest-spread) plugin for you. This means you *can* use object rest/spread properties in your tests as long as you're not targeting older Node.js versions. + +Note that if you customize the Babel configuration you'll have to explicitly specify the `syntax-object-rest-spread` plugin. + ## Customizing how AVA transpiles your tests You can override the default Babel configuration AVA uses for test transpilation in `package.json`. For example, the configuration below adds the Babel `rewire` plugin, and adds the Babel [`stage-3`](http://babeljs.io/docs/plugins/preset-stage-3/) preset. diff --git a/lib/babel-config.js b/lib/babel-config.js index 62e841f05..d58b700b8 100644 --- a/lib/babel-config.js +++ b/lib/babel-config.js @@ -6,6 +6,7 @@ const figures = require('figures'); const configManager = require('hullabaloo-config-manager'); const md5Hex = require('md5-hex'); const makeDir = require('make-dir'); +const semver = require('semver'); const colors = require('./colors'); function validate(conf) { @@ -99,6 +100,7 @@ function build(projectDir, cacheDir, userOptions, powerAssert) { const baseOptions = { babelrc: false, + plugins: [], presets: [ ['@ava/transform-test-files', {powerAssert}] ] @@ -107,6 +109,12 @@ function build(projectDir, cacheDir, userOptions, powerAssert) { baseOptions.presets.unshift('@ava/stage-4'); } + // Include object rest spread support for node versions that support it + // natively. + if (userOptions === 'default' && semver.satisfies(process.versions.node, '>= 8.3.0')) { + baseOptions.plugins.push('babel-plugin-syntax-object-rest-spread'); + } + const baseConfig = configManager.createConfig({ dir: AVA_DIR, // Presets are resolved relative to this directory hash: md5Hex(JSON.stringify(baseOptions)), diff --git a/package-lock.json b/package-lock.json index 911f88977..1b273f5ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -537,6 +537,11 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" + }, "babel-plugin-syntax-trailing-function-commas": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", @@ -1210,7 +1215,7 @@ "lodash.flattendeep": "4.4.0", "lodash.merge": "4.6.0", "md5-hex": "2.0.0", - "semver": "5.3.0", + "semver": "5.4.1", "well-known-symbols": "1.0.0" }, "dependencies": { @@ -4682,7 +4687,7 @@ "requires": { "hosted-git-info": "2.4.2", "is-builtin-module": "1.0.0", - "semver": "5.3.0", + "semver": "5.4.1", "validate-npm-package-license": "3.0.1" } }, @@ -4702,7 +4707,7 @@ "requires": { "hosted-git-info": "2.4.2", "osenv": "0.1.4", - "semver": "5.3.0", + "semver": "5.4.1", "validate-npm-package-name": "3.0.0" } }, @@ -6535,7 +6540,7 @@ "got": "6.7.1", "registry-auth-token": "3.3.1", "registry-url": "3.1.0", - "semver": "5.3.0" + "semver": "5.4.1" } }, "parse-glob": { @@ -7171,16 +7176,16 @@ "dev": true }, "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "semver-diff": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "requires": { - "semver": "5.3.0" + "semver": "5.4.1" } }, "set-blocking": { diff --git a/package.json b/package.json index 893a34e6e..408034265 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "ava-init": "^0.2.0", "babel-core": "^6.17.0", "babel-generator": "^6.26.0", + "babel-plugin-syntax-object-rest-spread": "^6.13.0", "bluebird": "^3.0.0", "caching-transform": "^1.0.0", "chalk": "^2.0.1", @@ -165,6 +166,7 @@ "require-precompiled": "^0.1.0", "resolve-cwd": "^2.0.0", "safe-buffer": "^5.1.1", + "semver": "^5.4.1", "slash": "^1.0.0", "source-map-support": "^0.4.0", "stack-utils": "^1.0.1", diff --git a/test/babel-config.js b/test/babel-config.js index ca09dfa00..ab1898fd6 100644 --- a/test/babel-config.js +++ b/test/babel-config.js @@ -9,6 +9,19 @@ const configManager = require('hullabaloo-config-manager'); const babelConfigHelper = require('../lib/babel-config'); const fixture = name => path.join(__dirname, 'fixture', name); +const setNodeVersion = value => Object.defineProperty(process.versions, 'node', {value}); +const resetNodeVersion = setNodeVersion.bind(null, process.versions.node); + +// Execute `run` with a given stubbed node version, then reset to the real +// version. +function withNodeVersion(version, run) { + setNodeVersion(version); + const promise = new Promise(resolve => { + resolve(run()); + }); + promise.then(resetNodeVersion, resetNodeVersion); + return promise; +} test('uses default presets when userOptions is "default"', t => { const userOptions = 'default'; @@ -46,6 +59,7 @@ test('uses options from babelrc when userOptions is "inherit"', t => { t.same(options.presets, [require.resolve('@ava/babel-preset-stage-4')]); const envOptions = options.env[configManager.currentEnv()]; t.same(envOptions, { + plugins: [], presets: [ [ require.resolve('@ava/babel-preset-transform-test-files'), @@ -82,6 +96,43 @@ test('uses userOptions for babel options when userOptions is an object', t => { }); }); +test('adds babel-plugin-syntax-object-rest-spread for node versions > 8.3.0', t => { + const projectDir = uniqueTempDir(); + const cacheDir = path.join(projectDir, 'cache'); + + return withNodeVersion('9.0.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true)) + .then(result => { + const options = result.getOptions(); + t.same(options.plugins, [ + require.resolve('babel-plugin-syntax-object-rest-spread') + ]); + }); +}); + +test('adds babel-plugin-syntax-object-rest-spread for node versions == 8.3.0', t => { + const projectDir = uniqueTempDir(); + const cacheDir = path.join(projectDir, 'cache'); + + return withNodeVersion('8.3.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true)) + .then(result => { + const options = result.getOptions(); + t.same(options.plugins, [ + require.resolve('babel-plugin-syntax-object-rest-spread') + ]); + }); +}); + +test('does not add babel-plugin-syntax-object-rest-spread for node versions < 8.3.0', t => { + const projectDir = uniqueTempDir(); + const cacheDir = path.join(projectDir, 'cache'); + + return withNodeVersion('8.2.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true)) + .then(result => { + const options = result.getOptions(); + t.same(options.plugins, []); + }); +}); + test('should disable power-assert when powerAssert is false', t => { const userOptions = 'default'; const powerAssert = false;