diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 78fd3e5a3c..8337d1da57 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -13,7 +13,7 @@ jobs: with: versionsAsRoot: true type: 'majors' - preset: '^10 || ^12 || ^14 || ^16 || >= 17' + preset: '^12 || ^14 || ^16 || >= 17' base: needs: [matrix] @@ -25,11 +25,14 @@ jobs: matrix: node-version: ${{ fromJson(needs.matrix.outputs.latest) }} eslint: + - 8 - 7 - - 6 - - 5 package: - eslint-config-airbnb-base + exclude: + - node-version: 10 + eslint: 8 + package: eslint-config-airbnb-base defaults: run: @@ -60,15 +63,15 @@ jobs: node-version: ${{ fromJson(needs.matrix.outputs.latest) }} eslint: - 7 - - 6 - - 5 + # - 6 + # - 5 package: - eslint-config-airbnb react-hooks: - '' - - 3 - - 2.3 - - 1.7 + # - 3 # TODO: re-enable these once the react config uses eslint 8 + # - 2.3 + # - 1.7 defaults: run: @@ -97,9 +100,8 @@ jobs: fail-fast: false matrix: eslint: + - 8 - 7 - - 6 - - 5 package: - eslint-config-airbnb-base @@ -130,15 +132,15 @@ jobs: matrix: eslint: - 7 - - 6 - - 5 + # - 6 + # - 5 package: - eslint-config-airbnb react-hooks: - '' - - 3 - - 2.3 - - 1.7 + # - 3 # TODO: re-enable these once the react config uses eslint 8 + # - 2.3 + # - 1.7 defaults: run: diff --git a/packages/eslint-config-airbnb-base/package.json b/packages/eslint-config-airbnb-base/package.json index fdfc405fab..ef11845cae 100644 --- a/packages/eslint-config-airbnb-base/package.json +++ b/packages/eslint-config-airbnb-base/package.json @@ -72,19 +72,19 @@ "babel-preset-airbnb": "^4.5.0", "babel-tape-runner": "^3.0.0", "eclint": "^2.8.1", - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", - "eslint-find-rules": "^3.6.1", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-find-rules": "^4.0.0", "eslint-plugin-import": "^2.25.2", "in-publish": "^2.0.1", - "safe-publish-latest": "^1.1.4", + "safe-publish-latest": "^2.0.0", "tape": "^5.3.1" }, "peerDependencies": { - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint": "^7.32.0 || ^8.2.0", "eslint-plugin-import": "^2.25.2" }, "engines": { - "node": ">= 6" + "node": "^10.12.0 || >=12.0.0" }, "dependencies": { "confusing-browser-globals": "^1.0.10", diff --git a/packages/eslint-config-airbnb-base/rules/best-practices.js b/packages/eslint-config-airbnb-base/rules/best-practices.js index deb91cfb01..b91133de0a 100644 --- a/packages/eslint-config-airbnb-base/rules/best-practices.js +++ b/packages/eslint-config-airbnb-base/rules/best-practices.js @@ -36,12 +36,10 @@ module.exports = { // Enforce default clauses in switch statements to be last // https://eslint.org/docs/rules/default-case-last - // TODO: enable, semver-minor, when eslint v7 is required (which is a major) - 'default-case-last': 'off', + 'default-case-last': 'error', // https://eslint.org/docs/rules/default-param-last - // TODO: enable, semver-minor, when eslint v6.4 is required (which is a major) - 'default-param-last': 'off', + 'default-param-last': 'error', // encourages use of dot notation whenever possible // https://eslint.org/docs/rules/dot-notation @@ -57,8 +55,7 @@ module.exports = { // Require grouped accessor pairs in object literals and classes // https://eslint.org/docs/rules/grouped-accessor-pairs - // TODO: enable in next major, altho the guide forbids getters/setters anyways - 'grouped-accessor-pairs': 'off', + 'grouped-accessor-pairs': 'error', // make sure for-in loops have an if statement // https://eslint.org/docs/rules/guard-for-in @@ -82,8 +79,7 @@ module.exports = { // Disallow returning value in constructor // https://eslint.org/docs/rules/no-constructor-return - // TODO: enable, semver-major - 'no-constructor-return': 'off', + 'no-constructor-return': 'error', // disallow division operators explicitly at beginning of regular expression // https://eslint.org/docs/rules/no-div-regex @@ -213,8 +209,7 @@ module.exports = { // Disallow \8 and \9 escape sequences in string literals // https://eslint.org/docs/rules/no-nonoctal-decimal-escape - // todo: semver-major: enable when v7.14 is required - 'no-nonoctal-decimal-escape': 'off', + 'no-nonoctal-decimal-escape': 'error', // disallow use of (old style) octal literals // https://eslint.org/docs/rules/no-octal @@ -382,8 +377,9 @@ module.exports = { 'prefer-named-capture-group': 'off', // https://eslint.org/docs/rules/prefer-regex-literals - // TODO; enable, semver-minor, once eslint v6.4 is required (which is a major) - 'prefer-regex-literals': 'off', + 'prefer-regex-literals': ['error', { + disallowRedundantWrapping: true, + }], // require use of the second argument for parseInt() // https://eslint.org/docs/rules/radix diff --git a/packages/eslint-config-airbnb-base/rules/errors.js b/packages/eslint-config-airbnb-base/rules/errors.js index 71ebcdecc6..cdc8c26eb7 100644 --- a/packages/eslint-config-airbnb-base/rules/errors.js +++ b/packages/eslint-config-airbnb-base/rules/errors.js @@ -40,8 +40,7 @@ module.exports = { // Disallow duplicate conditions in if-else-if chains // https://eslint.org/docs/rules/no-dupe-else-if - // TODO: enable, semver-major - 'no-dupe-else-if': 'off', + 'no-dupe-else-if': 'error', // disallow duplicate keys when creating object literals 'no-dupe-keys': 'error', @@ -79,8 +78,7 @@ module.exports = { 'no-func-assign': 'error', // https://eslint.org/docs/rules/no-import-assign - // TODO: enable, semver-minor, once eslint v6.4 is required (which is a major) - 'no-import-assign': 'off', + 'no-import-assign': 'error', // disallow function or variable declarations in nested blocks 'no-inner-declarations': 'error', @@ -93,8 +91,7 @@ module.exports = { // Disallow Number Literals That Lose Precision // https://eslint.org/docs/rules/no-loss-of-precision - // TODO: enable, semver-minor, once eslint v7.1 is required (which is major) - 'no-loss-of-precision': 'off', + 'no-loss-of-precision': 'error', // Disallow characters which are made with multiple code points in character class syntax // https://eslint.org/docs/rules/no-misleading-character-class @@ -105,8 +102,7 @@ module.exports = { // Disallow returning values from Promise executor functions // https://eslint.org/docs/rules/no-promise-executor-return - // TODO: enable, semver-minor, once eslint v7.3 is required (which is major) - 'no-promise-executor-return': 'off', + 'no-promise-executor-return': 'error', // disallow use of Object.prototypes builtins directly // https://eslint.org/docs/rules/no-prototype-builtins @@ -117,8 +113,7 @@ module.exports = { // Disallow returning values from setters // https://eslint.org/docs/rules/no-setter-return - // TODO: enable, semver-major (altho the guide forbids getters/setters already) - 'no-setter-return': 'off', + 'no-setter-return': 'error', // disallow sparse arrays 'no-sparse-arrays': 'error', @@ -136,8 +131,7 @@ module.exports = { // Disallow loops with a body that allows only one iteration // https://eslint.org/docs/rules/no-unreachable-loop - // TODO: enable, semver-minor, once eslint v7.3 is required (which is major) - 'no-unreachable-loop': ['off', { + 'no-unreachable-loop': ['error', { ignore: [], // WhileStatement, DoWhileStatement, ForStatement, ForInStatement, ForOfStatement }], @@ -151,13 +145,16 @@ module.exports = { // disallow use of optional chaining in contexts where the undefined value is not allowed // https://eslint.org/docs/rules/no-unsafe-optional-chaining - // TODO: enable, semver-minor, once eslint v7.15 is required (which is major) - 'no-unsafe-optional-chaining': ['off', { disallowArithmeticOperators: true }], + 'no-unsafe-optional-chaining': ['error', { disallowArithmeticOperators: true }], + + // Disallow Unused Private Class Members + // https://eslint.org/docs/rules/no-unused-private-class-members + // TODO: enable once eslint 7 is dropped (which is semver-major) + 'no-unused-private-class-members': 'off', // Disallow useless backreferences in regular expressions // https://eslint.org/docs/rules/no-useless-backreference - // TODO: enable, semver-minor, once eslint v7 is required (which is major) - 'no-useless-backreference': 'off', + 'no-useless-backreference': 'error', // disallow negation of the left operand of an in expression // deprecated in favor of no-unsafe-negation diff --git a/packages/eslint-config-airbnb-base/rules/es6.js b/packages/eslint-config-airbnb-base/rules/es6.js index 835afdd319..79a4cdcc25 100644 --- a/packages/eslint-config-airbnb-base/rules/es6.js +++ b/packages/eslint-config-airbnb-base/rules/es6.js @@ -62,11 +62,10 @@ module.exports = { // Disallow specified names in exports // https://eslint.org/docs/rules/no-restricted-exports - // TODO enable, semver-minor, once eslint v7 is required (which is major) - 'no-restricted-exports': ['off', { + 'no-restricted-exports': ['error', { restrictedNamedExports: [ 'default', // use `export default` to provide a default export - 'then', // this will cause tons of confusion when your module is dynamically `import()`ed + 'then', // this will cause tons of confusion when your module is dynamically `import()`ed, and will break in most node ESM versions ], }], diff --git a/packages/eslint-config-airbnb-base/rules/imports.js b/packages/eslint-config-airbnb-base/rules/imports.js index f3a477b4b5..5f7f1bd470 100644 --- a/packages/eslint-config-airbnb-base/rules/imports.js +++ b/packages/eslint-config-airbnb-base/rules/imports.js @@ -253,7 +253,7 @@ module.exports = { // Reports modules without any exports, or with unused exports // https://github.com/benmosher/eslint-plugin-import/blob/f63dd261809de6883b13b6b5b960e6d7f42a7813/docs/rules/no-unused-modules.md - // TODO: enable, semver-major + // TODO: enable once it supports CJS 'import/no-unused-modules': ['off', { ignoreExports: [], missingExports: true, @@ -262,14 +262,12 @@ module.exports = { // Reports the use of import declarations with CommonJS exports in any module except for the main module. // https://github.com/benmosher/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-import-module-exports.md - // TODO: enable, semver-major - 'import/no-import-module-exports': ['off', { + 'import/no-import-module-exports': ['error', { exceptions: [], }], // Use this rule to prevent importing packages through relative paths. // https://github.com/benmosher/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-relative-packages.md - // TODO: enable, semver-major - 'import/no-relative-packages': 'off', + 'import/no-relative-packages': 'error', }, }; diff --git a/packages/eslint-config-airbnb-base/rules/style.js b/packages/eslint-config-airbnb-base/rules/style.js index d73ddefb1d..2973b258ac 100644 --- a/packages/eslint-config-airbnb-base/rules/style.js +++ b/packages/eslint-config-airbnb-base/rules/style.js @@ -80,8 +80,7 @@ module.exports = { 'eol-last': ['error', 'always'], // https://eslint.org/docs/rules/function-call-argument-newline - // TODO: enable, semver-minor, once eslint v6.2 is required (which is a major) - 'function-call-argument-newline': ['off', 'consistent'], + 'function-call-argument-newline': ['error', 'consistent'], // enforce spacing between functions and their invocations // https://eslint.org/docs/rules/func-call-spacing @@ -108,11 +107,6 @@ module.exports = { // https://eslint.org/docs/rules/function-paren-newline 'function-paren-newline': ['error', semver.satisfies(eslintPkg.version, '>= 6') ? 'multiline-arguments' : 'consistent'], - // Blacklist certain identifiers to prevent them being used - // https://eslint.org/docs/rules/id-blacklist - // TODO: semver-major, remove once eslint v7.4+ is required - 'id-blacklist': 'off', - // disallow specified identifiers // https://eslint.org/docs/rules/id-denylist 'id-denylist': 'off', @@ -444,8 +438,7 @@ module.exports = { // Disallow the use of Math.pow in favor of the ** operator // https://eslint.org/docs/rules/prefer-exponentiation-operator - // TODO: enable, semver-major when eslint 5 is dropped - 'prefer-exponentiation-operator': 'off', + 'prefer-exponentiation-operator': 'error', // Prefer use of an object spread over Object.assign // https://eslint.org/docs/rules/prefer-object-spread diff --git a/packages/eslint-config-airbnb-base/whitespace-async.js b/packages/eslint-config-airbnb-base/whitespace-async.js new file mode 100755 index 0000000000..ee7e8b4034 --- /dev/null +++ b/packages/eslint-config-airbnb-base/whitespace-async.js @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +const assign = require('object.assign'); +const entries = require('object.entries'); +const { ESLint } = require('eslint'); + +const baseConfig = require('.'); + +const severities = ['off', 'warn', 'error']; + +function getSeverity(ruleConfig) { + if (Array.isArray(ruleConfig)) { + return getSeverity(ruleConfig[0]); + } + if (typeof ruleConfig === 'number') { + return severities[ruleConfig]; + } + return ruleConfig; +} + +async function onlyErrorOnRules(rulesToError, config) { + const errorsOnly = assign({}, config); + const cli = new ESLint({ + useEslintrc: false, + baseConfig: config + }); + const baseRules = (await cli.calculateConfigForFile(require.resolve('./'))).rules; + + entries(baseRules).forEach((rule) => { + const ruleName = rule[0]; + const ruleConfig = rule[1]; + const severity = getSeverity(ruleConfig); + + if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') { + if (Array.isArray(ruleConfig)) { + errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1)); + } else if (typeof ruleConfig === 'number') { + errorsOnly.rules[ruleName] = 1; + } else { + errorsOnly.rules[ruleName] = 'warn'; + } + } + }); + + return errorsOnly; +} + +onlyErrorOnRules([ + 'array-bracket-newline', + 'array-bracket-spacing', + 'array-element-newline', + 'arrow-spacing', + 'block-spacing', + 'comma-spacing', + 'computed-property-spacing', + 'dot-location', + 'eol-last', + 'func-call-spacing', + 'function-paren-newline', + 'generator-star-spacing', + 'implicit-arrow-linebreak', + 'indent', + 'key-spacing', + 'keyword-spacing', + 'line-comment-position', + 'linebreak-style', + 'multiline-ternary', + 'newline-per-chained-call', + 'no-irregular-whitespace', + 'no-mixed-spaces-and-tabs', + 'no-multi-spaces', + 'no-regex-spaces', + 'no-spaced-func', + 'no-trailing-spaces', + 'no-whitespace-before-property', + 'nonblock-statement-body-position', + 'object-curly-newline', + 'object-curly-spacing', + 'object-property-newline', + 'one-var-declaration-per-line', + 'operator-linebreak', + 'padded-blocks', + 'padding-line-between-statements', + 'rest-spread-spacing', + 'semi-spacing', + 'semi-style', + 'space-before-blocks', + 'space-before-function-paren', + 'space-in-parens', + 'space-infix-ops', + 'space-unary-ops', + 'spaced-comment', + 'switch-colon-spacing', + 'template-tag-spacing', + 'import/newline-after-import', +], baseConfig).then((config) => console.log(JSON.stringify(config))); diff --git a/packages/eslint-config-airbnb-base/whitespace.js b/packages/eslint-config-airbnb-base/whitespace.js index 0b7bda8f6f..e60f7a7918 100644 --- a/packages/eslint-config-airbnb-base/whitespace.js +++ b/packages/eslint-config-airbnb-base/whitespace.js @@ -1,91 +1,102 @@ -const assign = require('object.assign'); -const entries = require('object.entries'); +/* eslint global-require: 0 */ + const { CLIEngine } = require('eslint'); -const baseConfig = require('.'); +if (CLIEngine) { + /* eslint no-inner-declarations: 0 */ + const assign = require('object.assign'); + const entries = require('object.entries'); -const severities = ['off', 'warn', 'error']; + const baseConfig = require('.'); -function getSeverity(ruleConfig) { - if (Array.isArray(ruleConfig)) { - return getSeverity(ruleConfig[0]); - } - if (typeof ruleConfig === 'number') { - return severities[ruleConfig]; + const severities = ['off', 'warn', 'error']; + + function getSeverity(ruleConfig) { + if (Array.isArray(ruleConfig)) { + return getSeverity(ruleConfig[0]); + } + if (typeof ruleConfig === 'number') { + return severities[ruleConfig]; + } + return ruleConfig; } - return ruleConfig; -} -function onlyErrorOnRules(rulesToError, config) { - const errorsOnly = assign({}, config); - const cli = new CLIEngine({ baseConfig: config, useEslintrc: false }); - const baseRules = cli.getConfigForFile(require.resolve('./')).rules; + function onlyErrorOnRules(rulesToError, config) { + const errorsOnly = assign({}, config); + const cli = new CLIEngine({ baseConfig: config, useEslintrc: false }); + const baseRules = cli.getConfigForFile(require.resolve('./')).rules; - entries(baseRules).forEach((rule) => { - const ruleName = rule[0]; - const ruleConfig = rule[1]; - const severity = getSeverity(ruleConfig); + entries(baseRules).forEach((rule) => { + const ruleName = rule[0]; + const ruleConfig = rule[1]; + const severity = getSeverity(ruleConfig); - if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') { - if (Array.isArray(ruleConfig)) { - errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1)); - } else if (typeof ruleConfig === 'number') { - errorsOnly.rules[ruleName] = 1; - } else { - errorsOnly.rules[ruleName] = 'warn'; + if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') { + if (Array.isArray(ruleConfig)) { + errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1)); + } else if (typeof ruleConfig === 'number') { + errorsOnly.rules[ruleName] = 1; + } else { + errorsOnly.rules[ruleName] = 'warn'; + } } - } - }); + }); - return errorsOnly; -} + return errorsOnly; + } -module.exports = onlyErrorOnRules([ - 'array-bracket-newline', - 'array-bracket-spacing', - 'array-element-newline', - 'arrow-spacing', - 'block-spacing', - 'comma-spacing', - 'computed-property-spacing', - 'dot-location', - 'eol-last', - 'func-call-spacing', - 'function-paren-newline', - 'generator-star-spacing', - 'implicit-arrow-linebreak', - 'indent', - 'key-spacing', - 'keyword-spacing', - 'line-comment-position', - 'linebreak-style', - 'multiline-ternary', - 'newline-per-chained-call', - 'no-irregular-whitespace', - 'no-mixed-spaces-and-tabs', - 'no-multi-spaces', - 'no-regex-spaces', - 'no-spaced-func', - 'no-trailing-spaces', - 'no-whitespace-before-property', - 'nonblock-statement-body-position', - 'object-curly-newline', - 'object-curly-spacing', - 'object-property-newline', - 'one-var-declaration-per-line', - 'operator-linebreak', - 'padded-blocks', - 'padding-line-between-statements', - 'rest-spread-spacing', - 'semi-spacing', - 'semi-style', - 'space-before-blocks', - 'space-before-function-paren', - 'space-in-parens', - 'space-infix-ops', - 'space-unary-ops', - 'spaced-comment', - 'switch-colon-spacing', - 'template-tag-spacing', - 'import/newline-after-import', -], baseConfig); + module.exports = onlyErrorOnRules([ + 'array-bracket-newline', + 'array-bracket-spacing', + 'array-element-newline', + 'arrow-spacing', + 'block-spacing', + 'comma-spacing', + 'computed-property-spacing', + 'dot-location', + 'eol-last', + 'func-call-spacing', + 'function-paren-newline', + 'generator-star-spacing', + 'implicit-arrow-linebreak', + 'indent', + 'key-spacing', + 'keyword-spacing', + 'line-comment-position', + 'linebreak-style', + 'multiline-ternary', + 'newline-per-chained-call', + 'no-irregular-whitespace', + 'no-mixed-spaces-and-tabs', + 'no-multi-spaces', + 'no-regex-spaces', + 'no-spaced-func', + 'no-trailing-spaces', + 'no-whitespace-before-property', + 'nonblock-statement-body-position', + 'object-curly-newline', + 'object-curly-spacing', + 'object-property-newline', + 'one-var-declaration-per-line', + 'operator-linebreak', + 'padded-blocks', + 'padding-line-between-statements', + 'rest-spread-spacing', + 'semi-spacing', + 'semi-style', + 'space-before-blocks', + 'space-before-function-paren', + 'space-in-parens', + 'space-infix-ops', + 'space-unary-ops', + 'spaced-comment', + 'switch-colon-spacing', + 'template-tag-spacing', + 'import/newline-after-import', + ], baseConfig); +} else { + const path = require('path'); + const { execSync } = require('child_process'); + + module.exports = JSON.parse(String(execSync(path.join(__dirname, 'whitespace-async.js')))); +}