diff --git a/package.json b/package.json index 2e2c9ba855..f50d7322d5 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "ava": "^3.8.1", "babel-eslint": "^10.1.0", "chalk": "^4.0.0", - "eslint": "^6.8.0", + "eslint": "^7.0.0", "eslint-ava-rule-tester": "^4.0.0", "eslint-plugin-eslint-plugin": "^2.2.1", "execa": "^4.0.0", @@ -66,7 +66,7 @@ "xo": "^0.30.0" }, "peerDependencies": { - "eslint": ">=6.8.0" + "eslint": ">=7.0.0" }, "ava": { "babel": true, diff --git a/test/better-regex.js b/test/better-regex.js index dec6a47af0..58ba8b5287 100644 --- a/test/better-regex.js +++ b/test/better-regex.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const createError = (original, optimized) => [ { - ruleId: 'better-regex', message: `${original} can be optimized to ${optimized}` } ]; diff --git a/test/consistent-function-scoping.js b/test/consistent-function-scoping.js index 5cf0854945..a72317339e 100644 --- a/test/consistent-function-scoping.js +++ b/test/consistent-function-scoping.js @@ -17,12 +17,10 @@ const typescriptRuleTester = avaRuleTester(test, { parser: require.resolve('@typescript-eslint/parser') }); -const ruleId = 'consistent-function-scoping'; const MESSAGE_ID_NAMED = 'named'; const MESSAGE_ID_ANONYMOUS = 'anonymous'; const createError = ({name, arrow}) => ({ - ruleId, messageId: name ? MESSAGE_ID_NAMED : MESSAGE_ID_ANONYMOUS, data: { functionType: arrow ? 'arrow function' : 'function', diff --git a/test/custom-error-definition.js b/test/custom-error-definition.js index 9fb460e2e1..3f056c16d7 100644 --- a/test/custom-error-definition.js +++ b/test/custom-error-definition.js @@ -18,13 +18,12 @@ const typescriptRuleTester = avaRuleTester(test, { parser: require.resolve('@typescript-eslint/parser') }); -const invalidClassNameError = {ruleId: 'custom-error-definition', message: 'Invalid class name, use `FooError`.'}; -const constructorError = {ruleId: 'custom-error-definition', message: 'Add a constructor to your error.'}; -const noSuperCallError = {ruleId: 'custom-error-definition', message: 'Missing call to `super()` in constructor.'}; -const invalidNameError = name => ({ruleId: 'custom-error-definition', message: `The \`name\` property should be set to \`${name}\`.`}); -const passMessageToSuperError = {ruleId: 'custom-error-definition', message: 'Pass the error message to `super()` instead of setting `this.message`.'}; +const invalidClassNameError = {message: 'Invalid class name, use `FooError`.'}; +const constructorError = {message: 'Add a constructor to your error.'}; +const noSuperCallError = {message: 'Missing call to `super()` in constructor.'}; +const invalidNameError = name => ({message: `The \`name\` property should be set to \`${name}\`.`}); +const passMessageToSuperError = {message: 'Pass the error message to `super()` instead of setting `this.message`.'}; const invalidExportError = { - ruleId: 'custom-error-definition', messageId: 'invalidExport' }; diff --git a/test/error-message.js b/test/error-message.js index 4e3a24a6a0..962c350c42 100644 --- a/test/error-message.js +++ b/test/error-message.js @@ -10,12 +10,10 @@ const ruleTester = avaRuleTester(test, { }); const emptyStringError = { - ruleId: 'error-message', message: 'Error message should not be an empty string.' }; const noMessageError = { - ruleId: 'error-message', message: 'Pass a message to the error constructor.' }; diff --git a/test/escape-case.js b/test/escape-case.js index 1848d87b42..d14b3b3889 100644 --- a/test/escape-case.js +++ b/test/escape-case.js @@ -11,7 +11,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'escape-case', message: 'Use uppercase characters for the value of the escape sequence.' } ]; diff --git a/test/expiring-todo-comments.js b/test/expiring-todo-comments.js index 6edb5344fa..f88a137988 100644 --- a/test/expiring-todo-comments.js +++ b/test/expiring-todo-comments.js @@ -9,57 +9,46 @@ const ruleTester = avaRuleTester(test, { }); const expiredTodoError = (expirationDate, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO that is past due date: ${expirationDate}. ${message}` }); const avoidMultipleDatesError = (expirationDates, message) => ({ - ruleId: 'expiring-todo-comments', message: `Avoid using multiple expiration dates in TODO: ${expirationDates}. ${message}` }); const havePackageError = (package_, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO that is deprecated since you installed: ${package_}. ${message}` }); const dontHavePackageError = (package_, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO that is deprecated since you uninstalled: ${package_}. ${message}` }); const versionMatchesError = (comparison, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO match for package version: ${comparison}. ${message}` }); const engineMatchesError = (comparison, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO match for Node.js version: ${comparison}. ${message}` }); const reachedPackageVersionError = (version, message) => ({ - ruleId: 'expiring-todo-comments', message: `There is a TODO that is past due package version: ${version}. ${message}` }); const avoidMultiplePackageVersionsError = (versions, message) => ({ - ruleId: 'expiring-todo-comments', message: `Avoid using multiple package versions in TODO: ${versions}. ${message}` }); const removeWhitespacesError = (argument, message) => ({ - ruleId: 'expiring-todo-comments', message: `Avoid using whitespaces on TODO argument. On '${argument}' use '${argument.replace(/ /g, '')}'. ${message}` }); const missingAtSymbolError = (bad, good, message) => ({ - ruleId: 'expiring-todo-comments', message: `Missing '@' on TODO argument. On '${bad}' use '${good}'. ${message}` }); const noWarningCommentError = () => ({ - ruleId: 'expiring-todo-comments', message: 'Unexpected \'todo\' comment.' }); diff --git a/test/explicit-length-check.js b/test/explicit-length-check.js index d5d8e447e5..d3b1eeb903 100644 --- a/test/explicit-length-check.js +++ b/test/explicit-length-check.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const error = message => { return { - ruleId: 'explicit-length-check', message }; }; diff --git a/test/filename-case.js b/test/filename-case.js index bf921868cf..f12bcb2315 100644 --- a/test/filename-case.js +++ b/test/filename-case.js @@ -31,7 +31,6 @@ function testCaseWithOptions(filename, errorMessage, options = []) { options, errors: errorMessage && [ { - ruleId: 'filename-case', message: errorMessage } ] diff --git a/test/import-index.js b/test/import-index.js index 09d86a1a65..5ce8f26bc9 100644 --- a/test/import-index.js +++ b/test/import-index.js @@ -12,7 +12,6 @@ const ruleTester = avaRuleTester(test, { }); const error = { - ruleId: 'import-index', message: 'Do not reference the index file directly.' }; diff --git a/test/lint/lint.js b/test/lint/lint.js index 1dca29d261..c7ba7a4d0f 100755 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -1,62 +1,61 @@ #!/usr/bin/env node 'use strict'; -const {CLIEngine} = require('eslint'); +const {ESLint} = require('eslint'); const unicorn = require('../..'); const {recommended} = unicorn.configs; const files = [process.argv[2] || '.']; const fix = process.argv.includes('--fix'); -const ruleIds = Object.keys(unicorn.rules); -const unicornRules = new Map(Object.entries(unicorn.rules)); -const cli = new CLIEngine({ +const eslint = new ESLint({ baseConfig: recommended, useEslintrc: false, + plugins: { + unicorn + }, fix, - ignorePattern: [ - ] + overrideConfig: { + ignorePatterns: [ + 'coverage', + 'test/integration/fixtures' + ] + } }); -cli.addPlugin('eslint-plugin-unicorn', unicorn); - -// Make sure rules are loaded from codebase -const loadedRules = cli.getRules(); -if (!ruleIds.every(ruleId => unicornRules.get(ruleId) === loadedRules.get(`unicorn/${ruleId}`))) { - console.error('`eslint-plugin-unicorn` rules are not loaded from codebase.'); - process.exit(1); -} +(async function () { + const results = await eslint.lintFiles(files); -const report = cli.executeOnFiles(files); + if (fix) { + await ESLint.outputFixes(results); + } -const { - errorCount, - warningCount, - fixableErrorCount, - fixableWarningCount -} = report; + const errorCount = results.reduce((total, {errorCount}) => total + errorCount, 0); + const warningCount = results.reduce((total, {warningCount}) => total + warningCount, 0); + const fixableErrorCount = results.reduce((total, {fixableErrorCount}) => total + fixableErrorCount, 0); + const fixableWarningCount = results.reduce((total, {fixableWarningCount}) => total + fixableWarningCount, 0); -const hasFixable = fixableErrorCount || fixableWarningCount; + const hasFixable = fixableErrorCount || fixableWarningCount; -if (fix) { - CLIEngine.outputFixes(report); -} + if (errorCount || warningCount) { + const {format} = await eslint.loadFormatter(); + console.log(format(results)); -if (errorCount || warningCount) { - const formatter = cli.getFormatter(); - console.log(formatter(report.results)); + console.log(); + console.log(`You need to fix the failed test${errorCount + warningCount > 1 ? 's' : ''} above and run \`npm run lint \` to check again.`); - console.log(); - console.log(`You need to fix the failed test${errorCount + warningCount > 1 ? 's' : ''} above and run \`npm run lint \` to check again.`); + if (hasFixable) { + console.log(); + console.log('You may also want run `npm run lint --fix` to fix fixable problems.'); + } - if (hasFixable) { console.log(); - console.log('You may also want run `npm run lint --fix` to fix fixable problems.'); + console.log('* If you\'re making a new rule, you can fix this later. *'); + } else { + console.log('All tests have passed.'); } - console.log(); - console.log('* If you\'re making a new rule, you can fix this later. *'); -} else { - console.log('All tests have passed.'); -} - -process.exit(errorCount); + process.exit(errorCount); +})().catch(error => { + process.exitCode = 1; + console.error(error); +}); diff --git a/test/new-for-builtins.js b/test/new-for-builtins.js index 5723a8ecef..45e97047ff 100644 --- a/test/new-for-builtins.js +++ b/test/new-for-builtins.js @@ -20,12 +20,10 @@ const ruleTester = avaRuleTester(test, { }); const enforceNewError = builtin => ({ - ruleId: 'new-for-builtins', message: `Use \`new ${builtin}()\` instead of \`${builtin}()\`.` }); const disallowNewError = builtin => ({ - ruleId: 'new-for-builtins', message: `Use \`${builtin}()\` instead of \`new ${builtin}()\`.` }); diff --git a/test/no-abusive-eslint-disable.js b/test/no-abusive-eslint-disable.js index a2e302eafd..79d281931d 100644 --- a/test/no-abusive-eslint-disable.js +++ b/test/no-abusive-eslint-disable.js @@ -21,7 +21,6 @@ const ruleTester = avaRuleTester(test, { const error = [ { - ruleId: 'no-abusive-eslint-disable', message: 'Specify the rules you want to disable.' } ]; diff --git a/test/no-array-instanceof.js b/test/no-array-instanceof.js index c6402297dd..b33d2cc7b6 100644 --- a/test/no-array-instanceof.js +++ b/test/no-array-instanceof.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'no-array-instanceof', message: 'Use `Array.isArray()` instead of `instanceof Array`.' } ]; diff --git a/test/no-console-spaces.js b/test/no-console-spaces.js index 4e2040fc97..bbe7dbd89a 100644 --- a/test/no-console-spaces.js +++ b/test/no-console-spaces.js @@ -11,7 +11,6 @@ const ruleTester = avaRuleTester(test, { function buildError({method, column, line}) { const error = { - ruleId: 'no-console-spaces', message: `Do not use leading/trailing space between \`console.${method}\` parameters.` }; diff --git a/test/no-for-loop.js b/test/no-for-loop.js index 1f20fb9eb1..24dfcdbfd3 100644 --- a/test/no-for-loop.js +++ b/test/no-for-loop.js @@ -19,7 +19,7 @@ function testCase(code, output) { return { code, output: output || code, - errors: [{ruleId: 'no-for-loop'}] + errors: [{}] }; } diff --git a/test/no-hex-escape.js b/test/no-hex-escape.js index 75baf91f84..464def6945 100644 --- a/test/no-hex-escape.js +++ b/test/no-hex-escape.js @@ -16,7 +16,6 @@ const typescriptRuleTester = avaRuleTester(test, { }); const error = { - ruleId: 'no-hex-escape', message: 'Use Unicode escapes instead of hexadecimal escapes.' }; diff --git a/test/no-nested-ternary.js b/test/no-nested-ternary.js index b1359848b7..eae489e6d9 100644 --- a/test/no-nested-ternary.js +++ b/test/no-nested-ternary.js @@ -15,7 +15,6 @@ const typescriptRuleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'no-nested-ternary', message: 'Do not nest ternary expressions.' } ]; @@ -49,11 +48,9 @@ ruleTester.run('new-error', rule, { output: 'const foo = i > 5 ? (i < 100 ? true : false) : (i < 100 ? true : false);', errors: [ { - ruleId: 'no-nested-ternary', column: 21 }, { - ruleId: 'no-nested-ternary', column: 46 } ] diff --git a/test/no-new-buffer.js b/test/no-new-buffer.js index 947e5f90f6..dac72da64c 100644 --- a/test/no-new-buffer.js +++ b/test/no-new-buffer.js @@ -17,12 +17,10 @@ const typescriptRuleTester = avaRuleTester(test, { }); const allocError = { - ruleId: 'no-new-buffer', message: '`new Buffer()` is deprecated, use `Buffer.alloc()` instead.' }; const fromError = { - ruleId: 'no-new-buffer', message: '`new Buffer()` is deprecated, use `Buffer.from()` instead.' }; diff --git a/test/no-process-exit.js b/test/no-process-exit.js index 163fbfa180..d421813a16 100644 --- a/test/no-process-exit.js +++ b/test/no-process-exit.js @@ -12,7 +12,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'no-process-exit', message: 'Only use `process.exit()` in CLI apps. Throw an error instead.' } ]; diff --git a/test/no-unsafe-regex.js b/test/no-unsafe-regex.js index 7f1a81574c..8899033b4e 100644 --- a/test/no-unsafe-regex.js +++ b/test/no-unsafe-regex.js @@ -12,7 +12,6 @@ const ruleTester = avaRuleTester(test, { }); const error = { - ruleId: 'no-unsafe-regex', message: 'Unsafe regular expression.' }; diff --git a/test/no-unused-properties.js b/test/no-unused-properties.js index 7d0b67b391..5c194081f1 100644 --- a/test/no-unused-properties.js +++ b/test/no-unused-properties.js @@ -23,7 +23,6 @@ const babelEslintRuleTester = avaRuleTester(test, { }); const error = { - ruleId: 'no-unused-properties', message: 'Property `u` is defined but never used.' }; diff --git a/test/no-zero-fractions.js b/test/no-zero-fractions.js index 2cc3b1724c..048f6ab2f7 100644 --- a/test/no-zero-fractions.js +++ b/test/no-zero-fractions.js @@ -12,11 +12,9 @@ const ruleTester = avaRuleTester(test, { }); const errorZeroFraction = { - ruleId: 'no-zero-fractions', message: 'Don\'t use a zero fraction in the number.' }; const errorDanglingDot = { - ruleId: 'no-zero-fractions', message: 'Don\'t use a dangling dot in the number.' }; diff --git a/test/number-literal-case.js b/test/number-literal-case.js index c70abf55bb..83732a6421 100644 --- a/test/number-literal-case.js +++ b/test/number-literal-case.js @@ -13,7 +13,6 @@ const ruleTester = avaRuleTester(test, { }); const error = { - ruleId: 'number-literal-case', message: 'Invalid number literal casing.' }; diff --git a/test/prefer-dataset.js b/test/prefer-dataset.js index 1c8b3f9152..98aec89a6c 100644 --- a/test/prefer-dataset.js +++ b/test/prefer-dataset.js @@ -11,7 +11,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-dataset', message: 'Prefer `.dataset` over `setAttribute(…)`.' } ]; diff --git a/test/prefer-event-key.js b/test/prefer-event-key.js index bac4bfacd7..bd87e9c1b1 100644 --- a/test/prefer-event-key.js +++ b/test/prefer-event-key.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { }); const error = key => ({ - ruleId: 'prefer-event-key', message: `Use \`.key\` instead of \`.${key}\`` }); diff --git a/test/prefer-flat-map.js b/test/prefer-flat-map.js index 059f599da4..8f29098e6f 100644 --- a/test/prefer-flat-map.js +++ b/test/prefer-flat-map.js @@ -10,12 +10,10 @@ const ruleTester = avaRuleTester(test, { }); const errorFlatMap = { - ruleId: 'prefer-flat-map', messageId: 'flat-map' }; const errorSpread = { - ruleId: 'prefer-flat-map', messageId: 'spread' }; diff --git a/test/prefer-includes.js b/test/prefer-includes.js index 8b91cc8a0b..3bf7559b2d 100644 --- a/test/prefer-includes.js +++ b/test/prefer-includes.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-includes', message: 'Use `.includes()`, rather than `.indexOf()`, when checking for existence.' } ]; diff --git a/test/prefer-negative-index.js b/test/prefer-negative-index.js index 89ed279641..3cb673abcf 100644 --- a/test/prefer-negative-index.js +++ b/test/prefer-negative-index.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { }); const error = { - ruleId: 'prefer-negative-index' }; ruleTester.run('prefer-negative-index', rule, { diff --git a/test/prefer-reflect-apply.js b/test/prefer-reflect-apply.js index c45aeae36d..fd3fcc8752 100644 --- a/test/prefer-reflect-apply.js +++ b/test/prefer-reflect-apply.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-reflect-apply' } ]; diff --git a/test/prefer-replace-all.js b/test/prefer-replace-all.js index 93c748fc62..f325f8ad1b 100644 --- a/test/prefer-replace-all.js +++ b/test/prefer-replace-all.js @@ -9,7 +9,6 @@ const ruleTester = avaRuleTester(test, { }); const error = { - ruleId: 'prefer-replace-all', message: 'Prefer `String#replaceAll()` over `String#replace()`.' }; diff --git a/test/prefer-string-slice.js b/test/prefer-string-slice.js index 9396f6ebd0..fe4a3e79de 100644 --- a/test/prefer-string-slice.js +++ b/test/prefer-string-slice.js @@ -15,7 +15,6 @@ const typescriptRuleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-string-slice' } ]; @@ -134,18 +133,22 @@ ruleTester.run('prefer-string-slice', rule, { { code: 'foo.substr(start)', + output: 'foo.slice(start)', errors }, { code: '"foo".substr(1)', + output: '"foo".slice(1)', errors }, { code: 'foo.substr(start, length)', + output: 'foo.substr(start, length)', errors }, { code: '"foo".substr(1, 2)', + output: '"foo".slice(1, 3)', errors }, // Extra arguments @@ -219,10 +222,12 @@ ruleTester.run('prefer-string-slice', rule, { { code: 'foo.substring(start)', + output: 'foo.slice(Math.max(0, start))', errors }, { code: '"foo".substring(1)', + output: '"foo".slice(1)', errors }, { @@ -231,6 +236,7 @@ ruleTester.run('prefer-string-slice', rule, { }, { code: '"foo".substring(1, 3)', + output: '"foo".slice(1, 3)', errors }, // Extra arguments diff --git a/test/prefer-text-content.js b/test/prefer-text-content.js index 3e9c51d0ee..e7eb714a24 100644 --- a/test/prefer-text-content.js +++ b/test/prefer-text-content.js @@ -10,7 +10,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-text-content', message: 'Prefer `.textContent` over `.innerText`.' } ]; diff --git a/test/prefer-trim-start-end.js b/test/prefer-trim-start-end.js index 69bd119d0b..e9cbc352a3 100644 --- a/test/prefer-trim-start-end.js +++ b/test/prefer-trim-start-end.js @@ -9,12 +9,10 @@ const ruleTester = avaRuleTester(test, { }); const errorTrimLeft = { - ruleId: 'prefer-trim-start-end', messageId: 'trimLeft' }; const errorTrimRight = { - ruleId: 'prefer-trim-start-end', messageId: 'trimRight' }; diff --git a/test/prefer-type-error.js b/test/prefer-type-error.js index 6aa9932203..1543c8034d 100644 --- a/test/prefer-type-error.js +++ b/test/prefer-type-error.js @@ -11,7 +11,6 @@ const ruleTester = avaRuleTester(test, { const errors = [ { - ruleId: 'prefer-type-error', message: '`new Error()` is too unspecific for a type check. Use `new TypeError()` instead.' } ]; diff --git a/test/prevent-abbreviations.js b/test/prevent-abbreviations.js index f88bfe17d4..2d5c33c13f 100644 --- a/test/prevent-abbreviations.js +++ b/test/prevent-abbreviations.js @@ -37,7 +37,6 @@ const noFixingTestCase = test => ({...test, output: test.code}); const createErrors = message => { const error = { - ruleId: 'prevent-abbreviations' }; if (message) { @@ -354,6 +353,7 @@ ruleTester.run('prevent-abbreviations', rule, { }, { code: 'let stdDev', + output: 'let standardDeviation', errors: createErrors('The variable `stdDev` should be named `standardDeviation`. A more descriptive name will do too.') }, noFixingTestCase({ @@ -407,11 +407,13 @@ ruleTester.run('prevent-abbreviations', rule, { // This tests that the rule does not hang up on combinatoric explosion of possible replacements { code: 'let ' + 'CbE'.repeat(1024), + output: 'let ' + 'CallbackE'.repeat(1024), errors: createErrors() }, { code: 'let evt', + output: 'let event', errors: createErrors('The variable `evt` should be named `event`. A more descriptive name will do too.') }, noFixingTestCase({ diff --git a/test/string-content.js b/test/string-content.js index f4f6440ced..1a6b17c0c0 100644 --- a/test/string-content.js +++ b/test/string-content.js @@ -39,7 +39,6 @@ const createSuggestionError = (match, suggest, output) => [ message: `Prefer \`${suggest}\` over \`${match}\`.`, suggestions: [ { - desc: `Replace \`${match}\` with \`${suggest}\`.`, messageId: SUGGESTION_MESSAGE_ID, data: { match, @@ -221,7 +220,7 @@ ruleTester.run('string-content', rule, { code: 'const foo = `no${foo}no${foo}no`', output: 'const foo = `yes${foo}yes${foo}yes`', options: [{patterns: noToYesPattern}], - errors: Array.from({length: 3}).fill(createError('no', 'yes')) + errors: Array.from({length: 3}).fill(createError('no', 'yes')[0]) }, // Escape {