From 1fde5685ceb205cf1765654270eb822dd76b1a9d Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Sun, 22 Jul 2018 00:29:49 -0400 Subject: [PATCH] Add `node/no-unsupported-features` rules --- config/plugins.js | 3 --- lib/options-manager.js | 6 ++++++ readme.md | 23 ++++++++++++++++++----- test/options-manager.js | 41 ++++++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/config/plugins.js b/config/plugins.js index 2a1d8d0d..3c04334a 100644 --- a/config/plugins.js +++ b/config/plugins.js @@ -185,9 +185,6 @@ module.exports = { // } // ], - // Disabled as the rule doesn't allow to exclude compiled sources - // 'node/no-unsupported-features': 'error', - 'node/process-exit-as-throw': 'error', // Disabled as the rule doesn't exclude scripts executed with `node` but not referenced in 'bin'. See https://github.com/mysticatea/eslint-plugin-node/issues/96 diff --git a/lib/options-manager.js b/lib/options-manager.js index 0f5d72f3..dd48820c 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -195,6 +195,12 @@ const buildXOConfig = options => config => { } } + if (options.nodeVersion) { + config.rules['node/no-unsupported-features/es-builtins'] = ['error', {version: options.nodeVersion}]; + config.rules['node/no-unsupported-features/es-syntax'] = ['error', {version: options.nodeVersion, ignores: ['modules']}]; + config.rules['node/no-unsupported-features/node-builtins'] = ['error', {version: options.nodeVersion}]; + } + if (options.space && !options.prettier) { config.rules.indent = ['error', spaces, {SwitchCase: 1}]; diff --git a/readme.md b/readme.md index 8983232c..37f80a33 100644 --- a/readme.md +++ b/readme.md @@ -336,23 +336,37 @@ Put a `package.json` with your config at the root and omit the `xo` property in ### Transpilation -If some files in your project are transpiled in order to support an older Node.js version, you can use the [config overrides](#config-overrides) option to set a specific [`nodeVersion`](#nodeversion) target for these files. +If some files in your project are transpiled in order to support an older Node.js version, you can use the [config overrides](#config-overrides) option to set a specific [`nodeVersion`](#nodeversion) to target your sources files. -For example, if your project targets Node.js 4 (your `package.json` is configured with `engines.node` set to `>=4`) and you are using [AVA](https://github.com/avajs/ava), then your test files are automatically transpiled. You can override `nodeVersion` for the tests files: +For example, if your project targets Node.js 8 but you want to use the latest JavaScript syntax as supported in Node.js 12: +1. Set the `engines.node` property of your `package.json` to `>=8` +2. Configure [Babel](https://babeljs.io) to transpile your source files (in `src` directory in this example) +3. Make sure to include the transpiled files in your published package with the [`files`](https://docs.npmjs.com/files/package.json#files) and [`main`](https://docs.npmjs.com/files/package.json#main) properties of your `package.json` +4. Configure the XO `overrides` option to set `nodeVersion` to `>=12` for your source files directory ```json { + "engines": { + "node": ">=8" + }, + "scripts": { + "build": "babel src --out-dir dist" + }, + "main": "dist/index.js", + "files": ["dist/**/*.js"], "xo": { "overrides": [ { - "files": "{test,tests,spec,__tests__}/**/*.js", - "nodeVersion": ">=9" + "files": "{src}/**/*.js", + "nodeVersion": ">=12" } ] } } ``` +This way your `package.json` will contain the actual minimum Node.js version supported by your published code, but XO will lint your source code as if it targets Node.js 12. + ### Including files ignored by default To include files that XO [ignores by default](https://github.com/xojs/xo/blob/master/lib/constants.js#L1), add them as negative globs in the `ignores` option: @@ -367,7 +381,6 @@ To include files that XO [ignores by default](https://github.com/xojs/xo/blob/ma } ``` - ## FAQ #### What does XO mean? diff --git a/test/options-manager.js b/test/options-manager.js index 7afc6a14..042b07ef 100644 --- a/test/options-manager.js +++ b/test/options-manager.js @@ -67,13 +67,8 @@ test('buildConfig: space: 4', t => { test('buildConfig: semicolon', t => { const config = manager.buildConfig({semicolon: false, nodeVersion: '12'}); - t.deepEqual(config.rules, { - semi: ['error', 'never'], - 'semi-spacing': ['error', { - before: false, - after: true - }] - }); + t.deepEqual(config.rules.semi, ['error', 'never']); + t.deepEqual(config.rules['semi-spacing'], ['error', {before: false, after: true}]); }); test('buildConfig: prettier: true', t => { @@ -211,6 +206,9 @@ test('buildConfig: engines: undefined', t => { t.is(config.rules['unicorn/prefer-flat-map'], 'off'); t.is(config.rules['node/prefer-promises/dns'], 'off'); t.is(config.rules['node/prefer-promises/fs'], 'off'); + t.is(config.rules['node/no-unsupported-features/es-builtins'], undefined); + t.is(config.rules['node/no-unsupported-features/es-syntax'], undefined); + t.is(config.rules['node/no-unsupported-features/node-builtins'], undefined); }); test('buildConfig: nodeVersion: false', t => { @@ -226,24 +224,18 @@ test('buildConfig: nodeVersion: false', t => { t.is(config.rules['node/prefer-promises/fs'], 'off'); }); -test('buildConfig: nodeVersion: invalid range', t => { - const config = manager.buildConfig({nodeVersion: '4'}); - - // Override all the rules specific to Node.js version - t.is(config.rules['prefer-object-spread'], 'off'); - t.is(config.rules['prefer-rest-params'], 'off'); - t.is(config.rules['prefer-destructuring'], 'off'); - t.is(config.rules['promise/prefer-await-to-then'], 'off'); - t.is(config.rules['unicorn/prefer-flat-map'], 'off'); - t.is(config.rules['node/prefer-promises/dns'], 'off'); - t.is(config.rules['node/prefer-promises/fs'], 'off'); -}); - test('buildConfig: nodeVersion: >=6', t => { const config = manager.buildConfig({nodeVersion: '>=6'}); // Turn off rule if we support Node.js below 7.6.0 t.is(config.rules['promise/prefer-await-to-then'], 'off'); + // Set node/no-unsupported-features rules with the nodeVersion + t.deepEqual(config.rules['node/no-unsupported-features/es-builtins'], ['error', {version: '>=6'}]); + t.deepEqual( + config.rules['node/no-unsupported-features/es-syntax'], + ['error', {version: '>=6', ignores: ['modules']}] + ); + t.deepEqual(config.rules['node/no-unsupported-features/node-builtins'], ['error', {version: '>=6'}]); }); test('buildConfig: nodeVersion: >=8', t => { @@ -251,6 +243,13 @@ test('buildConfig: nodeVersion: >=8', t => { // Do not turn off rule if we support only Node.js above 7.6.0 t.is(config.rules['promise/prefer-await-to-then'], undefined); + // Set node/no-unsupported-features rules with the nodeVersion + t.deepEqual(config.rules['node/no-unsupported-features/es-builtins'], ['error', {version: '>=8'}]); + t.deepEqual( + config.rules['node/no-unsupported-features/es-syntax'], + ['error', {version: '>=8', ignores: ['modules']}] + ); + t.deepEqual(config.rules['node/no-unsupported-features/node-builtins'], ['error', {version: '>=8'}]); }); test('mergeWithPrettierConfig: use `singleQuote`, `trailingComma`, `bracketSpacing` and `jsxBracketSameLine` from `prettier` config if defined', t => { @@ -344,7 +343,7 @@ test('mergeWithPrettierConfig: throw error is `space`/`tabWidth` conflicts', t = test('buildConfig: rules', t => { const rules = {'object-curly-spacing': ['error', 'always']}; const config = manager.buildConfig({rules, nodeVersion: '12'}); - t.deepEqual(config.rules, rules); + t.deepEqual(config.rules['object-curly-spacing'], rules['object-curly-spacing']); }); test('buildConfig: parser', t => {