From bd8c4c6e6c20ccce948df6f72e8d02c4e7f4080f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 27 Oct 2022 14:52:03 +0700 Subject: [PATCH] Require Node.js 14 and ESLint 8 --- .github/workflows/ci.yml | 14 +++++++------- create-ava-rule.js | 12 ++++++------ package.json | 10 +++++----- rules/assertion-arguments.js | 4 ++-- rules/hooks-order.js | 8 ++++---- rules/max-asserts.js | 2 +- rules/no-async-fn-without-await.js | 2 +- rules/no-identical-title.js | 2 +- rules/no-ignored-test-files.js | 2 +- rules/no-import-test-files.js | 4 ++-- rules/prefer-t-regex.js | 6 +++--- rules/test-title-format.js | 2 +- rules/use-t-well.js | 4 ++-- rules/use-t.js | 2 +- rules/use-test.js | 4 ++-- test/create-ava-rule.js | 4 ++-- test/integration/test.js | 2 +- test/no-async-fn-without-await.js | 2 +- test/no-ignored-test-files.js | 2 +- test/no-import-test-files.js | 2 +- util.js | 3 +-- 21 files changed, 46 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42ee93e..1c0efd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,22 +13,22 @@ jobs: strategy: fail-fast: false matrix: - node-version: [^12.22, ^14.17, ^16.4] + node-version: [^14.17, ^16.4] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install --no-audit - run: npm test - - uses: codecov/codecov-action@v2 + - uses: codecov/codecov-action@v3 integration: name: Integration tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 - run: npm install --no-audit - run: npm run integration - - uses: codecov/codecov-action@v2 + - uses: codecov/codecov-action@v3 diff --git a/create-ava-rule.js b/create-ava-rule.js index 8c039da..4c0f438 100644 --- a/create-ava-rule.js +++ b/create-ava-rule.js @@ -188,36 +188,36 @@ module.exports = () => { /* eslint quote-props: [2, "as-needed"] */ const predefinedRules = { - ImportDeclaration: node => { + ImportDeclaration(node) { if (!isTestFile && avaImportDeclarationAsts.some(ast => isDeepStrictEqual(espurify(node), ast))) { isTestFile = true; } }, - VariableDeclarator: node => { + VariableDeclarator(node) { if (!isTestFile && avaVariableDeclaratorAsts.some(ast => isDeepStrictEqual(espurify(node), ast))) { isTestFile = true; } }, - CallExpression: node => { + CallExpression(node) { if (isTestFunctionCall(node.callee)) { // Entering test function currentTestNode = node; } }, - 'CallExpression:exit': node => { + 'CallExpression:exit'(node) { if (currentTestNode === node) { // Leaving test function currentTestNode = undefined; } }, - 'Program:exit': () => { + 'Program:exit'() { isTestFile = false; }, }; return { hasTestModifier: mod => getTestModifierNames(currentTestNode).includes(mod), - hasNoUtilityModifier: () => { + hasNoUtilityModifier() { const modifiers = getTestModifierNames(currentTestNode); return !modifiers.includes('before') && !modifiers.includes('beforeEach') diff --git a/package.json b/package.json index 1188e66..8e7308d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "repository": "avajs/eslint-plugin-ava", "engines": { - "node": ">=12.22 <13 || >=14.17 <15 || >=16.4" + "node": ">=14.17 <15 || >=16.4" }, "scripts": { "test": "xo && c8 ava", @@ -45,18 +45,18 @@ "c8": "^7.7.3", "chalk": "^4.1.1", "del": "^6.0.0", - "eslint": "^8.0.1", + "eslint": "^8.26.0", "eslint-ava-rule-tester": "^4.0.0", - "eslint-plugin-eslint-plugin": "^4.0.1", + "eslint-plugin-eslint-plugin": "^5.0.6", "execa": "^5.1.1", "listr": "^0.14.3", "outdent": "^0.8.0", "pify": "^5.0.0", "tempy": "^1.0.1", - "xo": "^0.46.4" + "xo": "^0.52.4" }, "peerDependencies": { - "eslint": ">=7.22.0" + "eslint": ">=8.26.0" }, "ava": { "files": [ diff --git a/rules/assertion-arguments.js b/rules/assertion-arguments.js index c1fb845..53b4253 100644 --- a/rules/assertion-arguments.js +++ b/rules/assertion-arguments.js @@ -211,7 +211,7 @@ function isString(node) { const create = context => { const ava = createAvaRule(); - const options = context.options[0] || {}; + const options = context.options[0] ?? {}; const enforcesMessage = Boolean(options.message); const shouldHaveMessage = options.message !== 'never'; @@ -285,7 +285,7 @@ const create = context => { const variable = findVariable(context.getScope(), lastArg); let value; for (const ref of variable.references) { - value = ref.writeExpr || value; + value = ref.writeExpr ?? value; } lastArg = value; diff --git a/rules/hooks-order.js b/rules/hooks-order.js index 752ef65..ed49b55 100644 --- a/rules/hooks-order.js +++ b/rules/hooks-order.js @@ -22,7 +22,7 @@ const buildOrders = names => { }; const buildMessage = (name, orders, visited) => { - const checks = orders[name] || []; + const checks = orders[name] ?? []; for (const check of checks) { const nodeEarlier = visited[check]; @@ -90,7 +90,7 @@ const create = context => { const sourceCode = context.getSourceCode(); // TODO: Remove `.reduce()` usage. - // eslint-disable-next-line unicorn/no-array-reduce, unicorn/prefer-object-from-entries + // eslint-disable-next-line unicorn/no-array-reduce const selectors = checks.reduce((result, check) => { result[check.selector] = visitIf([ ava.isInTestFile, @@ -106,10 +106,10 @@ const create = context => { node, messageId: message.messageId, data: message.data, - fix: fixer => { + fix(fixer) { const tokensBetween = sourceCode.getTokensBetween(nodeEarlier.parent, node.parent); - if (tokensBetween && tokensBetween.length > 0) { + if (tokensBetween?.length > 0) { return; } diff --git a/rules/max-asserts.js b/rules/max-asserts.js index faa4849..f201805 100644 --- a/rules/max-asserts.js +++ b/rules/max-asserts.js @@ -12,7 +12,7 @@ const create = context => { const ava = createAvaRule(); // TODO: Convert options to object JSON Schema default works properly // https://github.com/avajs/eslint-plugin-ava/issues/260 - const maxAssertions = context.options[0] || MAX_ASSERTIONS_DEFAULT; + const maxAssertions = context.options[0] ?? MAX_ASSERTIONS_DEFAULT; let assertionCount = 0; let nodeToReport; diff --git a/rules/no-async-fn-without-await.js b/rules/no-async-fn-without-await.js index 08f1a50..a4b156e 100644 --- a/rules/no-async-fn-without-await.js +++ b/rules/no-async-fn-without-await.js @@ -15,7 +15,7 @@ const create = context => { } }; - const isAsync = node => Boolean(node && node.async); + const isAsync = node => Boolean(node?.async); return ava.merge({ CallExpression: visitIf([ diff --git a/rules/no-identical-title.js b/rules/no-identical-title.js index 7a2eef6..0a6811a 100644 --- a/rules/no-identical-title.js +++ b/rules/no-identical-title.js @@ -52,7 +52,7 @@ const create = context => { usedTitleNodes.push(purify(titleNode)); }), - 'Program:exit': () => { + 'Program:exit'() { usedTitleNodes = []; }, }); diff --git a/rules/no-ignored-test-files.js b/rules/no-ignored-test-files.js index e58a7d0..265f3b5 100644 --- a/rules/no-ignored-test-files.js +++ b/rules/no-ignored-test-files.js @@ -22,7 +22,7 @@ const create = context => { ])(() => { hasTestCall = true; }), - 'Program:exit': node => { + 'Program:exit'(node) { if (!hasTestCall) { return; } diff --git a/rules/no-import-test-files.js b/rules/no-import-test-files.js index 24a22f1..2e84076 100644 --- a/rules/no-import-test-files.js +++ b/rules/no-import-test-files.js @@ -47,10 +47,10 @@ const create = context => { }; return { - ImportDeclaration: node => { + ImportDeclaration(node) { validateImportPath(node, node.source.value); }, - CallExpression: node => { + CallExpression(node) { if (!(node.callee.type === 'Identifier' && node.callee.name === 'require')) { return; } diff --git a/rules/prefer-t-regex.js b/rules/prefer-t-regex.js index 0dbaa7f..04f923f 100644 --- a/rules/prefer-t-regex.js +++ b/rules/prefer-t-regex.js @@ -23,7 +23,7 @@ const create = context => { const findReference = name => { const reference = context.getScope().references.find(reference => reference.identifier.name === name); - if (reference && reference.resolved) { + if (reference?.resolved) { const definitions = reference.resolved.defs; if (definitions.length === 0) { @@ -54,7 +54,7 @@ const create = context => { if (node.type === 'Identifier') { const reference = findReference(node.name); - if (reference && reference.init) { + if (reference?.init) { return findRootReference(reference.init); } @@ -86,7 +86,7 @@ const create = context => { // Look up references in case it's a variable or RegExp declaration. const reference = findRootReference(lookup); - return reference.regex || reference.name === 'RegExp'; + return reference.regex ?? reference.name === 'RegExp'; }; const booleanHandler = node => { diff --git a/rules/test-title-format.js b/rules/test-title-format.js index acf3da3..dbe57e4 100644 --- a/rules/test-title-format.js +++ b/rules/test-title-format.js @@ -8,7 +8,7 @@ const create = context => { const ava = createAvaRule(); let titleRegExp; - if (context.options[0] && context.options[0].format) { + if (context.options[0]?.format) { titleRegExp = new RegExp(context.options[0].format); } else { return {}; diff --git a/rules/use-t-well.js b/rules/use-t-well.js index b636ca4..a4d7b45 100644 --- a/rules/use-t-well.js +++ b/rules/use-t-well.js @@ -125,7 +125,7 @@ const create = context => { context.report({ node, message: 'Too many chained uses of `.skip`.', - fix: fixer => { + fix(fixer) { const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip']; return fixer.replaceText(node, chain.join('.')); }, @@ -136,7 +136,7 @@ const create = context => { context.report({ node, message: '`.skip` modifier should be the last in chain.', - fix: fixer => { + fix(fixer) { const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip']; return fixer.replaceText(node, chain.join('.')); }, diff --git a/rules/use-t.js b/rules/use-t.js index bf0c1ee..94b5853 100644 --- a/rules/use-t.js +++ b/rules/use-t.js @@ -20,7 +20,7 @@ const create = context => { let implementationArg = node.arguments[index]; if (ava.hasTestModifier('macro') && implementationArg.type === 'ObjectExpression') { const execProperty = implementationArg.properties.find(p => p.key.name === 'exec'); - implementationArg = execProperty && execProperty.value; + implementationArg = execProperty?.value; } if (!implementationArg || !implementationArg.params || implementationArg.params.length === 0) { diff --git a/rules/use-test.js b/rules/use-test.js index ff671b3..357ec4d 100644 --- a/rules/use-test.js +++ b/rules/use-test.js @@ -31,7 +31,7 @@ const create = context => { const isTypeScript = ext === '.ts' || ext === '.tsx'; return { - 'ImportDeclaration[importKind!="type"]': node => { + 'ImportDeclaration[importKind!="type"]'(node) { if (node.source.value === 'ava') { const {name} = node.specifiers[0].local; if (name !== 'test' && (!isTypeScript || name !== 'anyTest')) { @@ -39,7 +39,7 @@ const create = context => { } } }, - VariableDeclarator: node => { + VariableDeclarator(node) { if (node.init && isDeepStrictEqual(espurify(node.init), avaVariableDeclaratorInitAst)) { const {name} = node.id; if (name !== 'test' && (!isTypeScript || name !== 'anyTest')) { diff --git a/test/create-ava-rule.js b/test/create-ava-rule.js index fe5bb22..5edf972 100644 --- a/test/create-ava-rule.js +++ b/test/create-ava-rule.js @@ -5,11 +5,11 @@ const avaRuleTester = require('eslint-ava-rule-tester'); const createAvaRule = require('../create-ava-rule'); const rule = { - create: context => { + create(context) { const ava = createAvaRule(); return ava.merge({ - 'Program:exit': node => { + 'Program:exit'(node) { if (!ava.isInTestFile()) { context.report({node, message: 'not a test file'}); } diff --git a/test/integration/test.js b/test/integration/test.js index 21e0003..de9b07d 100644 --- a/test/integration/test.js +++ b/test/integration/test.js @@ -146,7 +146,7 @@ const list = new Listr([ }, { title: 'Integration tests', - task: () => { + task() { const tests = new Listr({concurrent: true}); for (const [name] of packages) { diff --git a/test/no-async-fn-without-await.js b/test/no-async-fn-without-await.js index d5741cf..989ca2e 100644 --- a/test/no-async-fn-without-await.js +++ b/test/no-async-fn-without-await.js @@ -25,7 +25,7 @@ const ruleTesterOptions = [ for (const options of ruleTesterOptions) { const ruleTester = avaRuleTester(test, options); - ruleTester.run(`no-async-fn-without-await - parser:${options.parser || 'default'}`, rule, { + ruleTester.run(`no-async-fn-without-await - parser:${options.parser ?? 'default'}`, rule, { valid: [ `${header}test(fn);`, `${header}test(t => {});`, diff --git a/test/no-ignored-test-files.js b/test/no-ignored-test-files.js index d5c9141..cd16d78 100644 --- a/test/no-ignored-test-files.js +++ b/test/no-ignored-test-files.js @@ -19,7 +19,7 @@ const toPath = subPath => path.join(rootDir, subPath); const code = hasHeader => (hasHeader ? header : '') + 'test(t => { t.pass(); });'; util.loadAvaHelper = () => ({ - classifyFile: file => { + classifyFile(file) { switch (file) { case toPath('lib/foo.test.js'): return {isHelper: false, isTest: true}; diff --git a/test/no-import-test-files.js b/test/no-import-test-files.js index 0699ed8..54959cf 100644 --- a/test/no-import-test-files.js +++ b/test/no-import-test-files.js @@ -19,7 +19,7 @@ const rootDir = path.dirname(__dirname); const toPath = subPath => path.join(rootDir, subPath); util.loadAvaHelper = () => ({ - classifyImport: importPath => { + classifyImport(importPath) { switch (importPath) { case toPath('lib/foo.test.js'): return {isHelper: false, isTest: true}; diff --git a/util.js b/util.js index b36932d..17c728d 100644 --- a/util.js +++ b/util.js @@ -84,9 +84,8 @@ exports.getMembers = getMembers; const repoUrl = 'https://github.com/avajs/eslint-plugin-ava'; -const getDocsUrl = (filename, commitHash) => { +const getDocsUrl = (filename, commitHash = `v${pkg.version}`) => { const ruleName = path.basename(filename, '.js'); - commitHash = commitHash || `v${pkg.version}`; return `${repoUrl}/blob/${commitHash}/docs/rules/${ruleName}.md`; };