From 5ff29cdb86df22fc32d7d9a067e61e517e223da2 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 28 Jan 2019 11:12:10 -0800 Subject: [PATCH 1/5] feat(eslint-plugin): add new rule no-for-in-array --- packages/eslint-plugin/README.md | 2 + packages/eslint-plugin/ROADMAP.md | 25 ++++--- .../docs/rules/no-for-in-array.md | 36 +++++++++ packages/eslint-plugin/jsconfig.json | 8 ++ .../lib/rules/no-for-in-array.js | 57 ++++++++++++++ packages/eslint-plugin/lib/util.js | 6 +- .../tests/lib/rules/no-for-in-array.js | 75 +++++++++++++++++++ 7 files changed, 196 insertions(+), 13 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/no-for-in-array.md create mode 100644 packages/eslint-plugin/jsconfig.json create mode 100644 packages/eslint-plugin/lib/rules/no-for-in-array.js create mode 100644 packages/eslint-plugin/tests/lib/rules/no-for-in-array.js diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 4f6f771d47c4..fc468e827ee8 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -96,6 +96,8 @@ See [@typescript-eslint/parser's README.md](../parser/README.md) for more inform | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces (`no-empty-interface` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type (`no-any` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces (`no-unnecessary-class` from TSLint) | | | +| [`typescript/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop (`no-for-in-array` from TSLint) + | | | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean. (`no-inferrable-types` from TSLint) | :heavy_check_mark: | :wrench: | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor`. (`no-misused-new` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces (`no-namespace` from TSLint) | :heavy_check_mark: | | diff --git a/packages/eslint-plugin/ROADMAP.md b/packages/eslint-plugin/ROADMAP.md index 1fce16992a9c..6d196bc48457 100644 --- a/packages/eslint-plugin/ROADMAP.md +++ b/packages/eslint-plugin/ROADMAP.md @@ -1,9 +1,9 @@ # Roadmap -βœ… (27) = done -🌟 (79) = in ESLint core -πŸ”Œ (33) = in another plugin -πŸŒ“ (16) = implementations differ or ESLint version is missing functionality +βœ… (27) = done +🌟 (79) = in ESLint core +πŸ”Œ (33) = in another plugin +πŸŒ“ (16) = implementations differ or ESLint version is missing functionality πŸ›‘ (71) = unimplemented ## TSLint rules @@ -59,6 +59,7 @@ | [`no-empty`] | 🌟 | [`no-empty`][no-empty] | | [`no-eval`] | 🌟 | [`no-eval`][no-eval] | | [`no-floating-promises`] | πŸ›‘ | N/A ([relevant plugin][plugin:promise]) | +| [`no-for-in-array`] | βœ… | [`typescript/no-for-in-array`] | | [`no-for-in-array`] | πŸ›‘ | N/A | | [`no-implicit-dependencies`] | πŸ”Œ | [`import/no-extraneous-dependencies`] | | [`no-inferred-empty-object-type`] | πŸ›‘ | N/A | @@ -96,7 +97,7 @@ | [`use-default-type-parameter`] | πŸ›‘ | N/A | | [`use-isnan`] | 🌟 | [`use-isnan`][use-isnan] | -[1] The ESLint rule also supports silencing with an extra set of parens (`if ((foo = bar)) {}`) +[1] The ESLint rule also supports silencing with an extra set of parens (`if ((foo = bar)) {}`) [2] Missing private class member support. [`@typescript-eslint/no-unused-vars`] adds support for some TS-specific features. ### Maintainability @@ -120,7 +121,7 @@ | [`prefer-readonly`] | πŸ›‘ | N/A | | [`trailing-comma`] | πŸŒ“ | [`comma-dangle`][comma-dangle] or [Prettier] | -[1] Only warns when importing deprecated symbols +[1] Only warns when importing deprecated symbols [2] Missing support for blank-line-delimited sections ### Style @@ -179,7 +180,7 @@ | [`variable-name`] | 🌟 | [2] | | [`whitespace`] | πŸ”Œ | Use [Prettier] | -[1] Recommended config: `["error", { blankLine: "always", prev: "*", next: "return" }]` +[1] Recommended config: `["error", { blankLine: "always", prev: "*", next: "return" }]` [2] [`camelcase`][camelcase], [`no-underscore-dangle`][no-underscore-dangle], [`id-blacklist`][id-blacklist], and/or [`id-match`][id-match] ## tslint-microsoft-contrib rules @@ -245,10 +246,10 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- | `use-named-parameter` | πŸ›‘ | N/A | | `use-simple-attributes` | πŸ›‘ | N/A | -[1] Enforces blank lines both at the beginning and end of a block -[2] Recommended config: `["error", "ForInStatement"]` -[3] Recommended config: `["error", "declaration", { "allowArrowFunctions": true }]` -[4] Recommended config: `["error", { "terms": ["BUG", "HACK", "FIXME", "LATER", "LATER2", "TODO"], "location": "anywhere" }]` +[1] Enforces blank lines both at the beginning and end of a block +[2] Recommended config: `["error", "ForInStatement"]` +[3] Recommended config: `["error", "declaration", { "allowArrowFunctions": true }]` +[4] Recommended config: `["error", { "terms": ["BUG", "HACK", "FIXME", "LATER", "LATER2", "TODO"], "location": "anywhere" }]` [5] Does not check class fields. [insecure-random]: https://github.com/desktop/desktop/blob/master/eslint-rules/insecure-random.js @@ -310,7 +311,7 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- | `react-a11y-titles` | πŸ›‘ | N/A | | `react-anchor-blank-noopener` | πŸ›‘ | N/A | -[1] TSLint rule is more strict +[1] TSLint rule is more strict [2] ESLint rule only reports for click handlers [prettier]: https://prettier.io diff --git a/packages/eslint-plugin/docs/rules/no-for-in-array.md b/packages/eslint-plugin/docs/rules/no-for-in-array.md new file mode 100644 index 000000000000..89aed236bac2 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-for-in-array.md @@ -0,0 +1,36 @@ +# Disallow iterating over an array with a for-in loop (no-for-in-array) + +This rule prohibits iterating over an array with a for-in loop. + +## Rule Details + +Rationale from TSLint: + +> A for-in loop (for (var k in o)) iterates over the properties of an Object. +> While it is legal to use for-in loops with array types, it is not common. for-in will iterate over the indices of the array as strings, omitting any β€œholes” in the array. +> More common is to use for-of, which iterates over the values of an array. If you want to iterate over the indices, alternatives include: +> array.forEach((value, index) => { … }); for (const [index, value] of array.entries()) { … } for (let i = 0; i < array.length; i++) { … } + +Examples of **incorrect** code for this rule: + +```js +for (const x in [3, 4, 5]) { + console.log(x); +} +``` + +Examples of **correct** code for this rule: + +```js +for (const x in { a: 3, b: 4, c: 5 }) { + console.log(x); +} +``` + +## When Not To Use It + +If you want to iterate through a loop using the indices in an array as strings, you can turn off this rule. + +## Related to + +- TSLint: ['no-for-in-array'](https://palantir.github.io/tslint/rules/no-for-in-array/) diff --git a/packages/eslint-plugin/jsconfig.json b/packages/eslint-plugin/jsconfig.json new file mode 100644 index 000000000000..d68b67d6e404 --- /dev/null +++ b/packages/eslint-plugin/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es2015", + "checkJs": true, + "strict": true, + "module": "commonjs" + } +} diff --git a/packages/eslint-plugin/lib/rules/no-for-in-array.js b/packages/eslint-plugin/lib/rules/no-for-in-array.js new file mode 100644 index 000000000000..3d8e9ad00eff --- /dev/null +++ b/packages/eslint-plugin/lib/rules/no-for-in-array.js @@ -0,0 +1,57 @@ +/** + * @fileoverview Disallow iterating over an array with a for-in loop + * @author Benjamin Lichtman + */ +'use strict'; +const ts = require('typescript'); +const util = require('../util'); + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +/** + * @type {import("eslint").Rule.RuleModule} + */ +module.exports = { + meta: { + docs: { + description: 'Disallow iterating over an array with a for-in loop', + category: 'Functionality', + recommended: false, + extraDescription: [util.tslintRule('no-for-in-array')], + url: util.metaDocsUrl('no-for-in-array') + }, + fixable: null, + schema: [], + type: 'problem' + }, + + create(context) { + return { + ForInStatement(node) { + const parserServices = util.getParserServices(context); + const checker = parserServices.program.getTypeChecker(); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); + + if (!originalNode) { + return; + } + + const type = checker.getTypeAtLocation(originalNode.expression); + + if ( + (typeof type.symbol !== 'undefined' && + type.symbol.name === 'Array') || + (type.flags & ts.TypeFlags.StringLike) !== 0 + ) { + context.report({ + node, + message: + 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.' + }); + } + } + }; + } +}; diff --git a/packages/eslint-plugin/lib/util.js b/packages/eslint-plugin/lib/util.js index e12e15f80413..6efcc7dfe219 100644 --- a/packages/eslint-plugin/lib/util.js +++ b/packages/eslint-plugin/lib/util.js @@ -1,5 +1,9 @@ 'use strict'; +/** @typedef {import("eslint").Rule.RuleContext} RuleContext */ +/** @typedef {WeakMap} NodeMap */ +/** @typedef {import("typescript").Program} Program */ + const version = require('../package.json').version; exports.tslintRule = name => `\`${name}\` from TSLint`; @@ -109,7 +113,7 @@ exports.upperCaseFirst = str => str[0].toUpperCase() + str.slice(1); /** * Try to retrieve typescript parser service from context * @param {RuleContext} context Rule context - * @returns {{esTreeNodeToTSNodeMap}|{program}|Object|*} parserServices + * @returns {{program: Program, esTreeNodeToTSNodeMap: NodeMap}} parserServices */ exports.getParserServices = context => { if ( diff --git a/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js b/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js new file mode 100644 index 000000000000..94a3200608a4 --- /dev/null +++ b/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js @@ -0,0 +1,75 @@ +/** + * @fileoverview Disallow iterating over an array with a for-in loop + * @author Benjamin Lichtman + */ +'use strict'; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-for-in-array'), + RuleTester = require('eslint').RuleTester, + path = require('path'); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +// RuleTester.it = function(text, method) { +// return method.call({ break: true }); +// }; + +const rootDir = path.join(process.cwd(), 'tests/fixtures/'); +const parserOptions = { + ecmaVersion: 2015, + tsconfigRootDir: rootDir, + project: './tsconfig.json' +}; +const ruleTester = new RuleTester({ + parserOptions, + parser: '@typescript-eslint/parser' +}); +const message = + 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.'; + +ruleTester.run('no-for-in-array', rule, { + valid: [ + ` +for (const x of [3, 4, 5]) { + console.log(x); +}`, + ` +for (const x in { a: 1, b: 2, c: 3 }) { + console.log(x); +}` + ], + + invalid: [ + { + code: ` +for (const x in [3, 4, 5]) { + console.log(x); +}`, + errors: [ + { + message, + type: 'ForInStatement' + } + ] + }, + { + code: ` +const z = [3, 4, 5]; +for (const x in z) { + console.log(x); +}`, + errors: [ + { + message, + type: 'ForInStatement' + } + ] + } + ] +}); From 7d9991e65b11f5b875d2a7468c540161cd910069 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 28 Jan 2019 12:59:38 -0800 Subject: [PATCH 2/5] chore(eslint-plugin): remove unnecessary typedefs --- packages/eslint-plugin/lib/util.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/eslint-plugin/lib/util.js b/packages/eslint-plugin/lib/util.js index 6efcc7dfe219..26cf0e454767 100644 --- a/packages/eslint-plugin/lib/util.js +++ b/packages/eslint-plugin/lib/util.js @@ -1,9 +1,5 @@ 'use strict'; -/** @typedef {import("eslint").Rule.RuleContext} RuleContext */ -/** @typedef {WeakMap} NodeMap */ -/** @typedef {import("typescript").Program} Program */ - const version = require('../package.json').version; exports.tslintRule = name => `\`${name}\` from TSLint`; From a33344877b5115dcb7ae66f3886468cc61b31fdf Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 28 Jan 2019 13:51:36 -0800 Subject: [PATCH 3/5] chore: fix README spacing --- packages/eslint-plugin/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index fc468e827ee8..a6082d5fc84f 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -96,8 +96,7 @@ See [@typescript-eslint/parser's README.md](../parser/README.md) for more inform | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces (`no-empty-interface` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type (`no-any` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces (`no-unnecessary-class` from TSLint) | | | -| [`typescript/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop (`no-for-in-array` from TSLint) - | | | +| [`typescript/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop (`no-for-in-array` from TSLint) | | | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean. (`no-inferrable-types` from TSLint) | :heavy_check_mark: | :wrench: | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor`. (`no-misused-new` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces (`no-namespace` from TSLint) | :heavy_check_mark: | | From 56fa66ee56ba3c657106dfdc7828924e8aa18842 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 4 Feb 2019 13:16:57 -0500 Subject: [PATCH 4/5] Update roadmap --- packages/eslint-plugin/ROADMAP.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/ROADMAP.md b/packages/eslint-plugin/ROADMAP.md index 20c3222089f5..c75debcb45ef 100644 --- a/packages/eslint-plugin/ROADMAP.md +++ b/packages/eslint-plugin/ROADMAP.md @@ -1,10 +1,15 @@ ο»Ώ# Roadmap -βœ… (28) = done -🌟 (79) = in ESLint core -πŸ”Œ (33) = in another plugin -πŸŒ“ (16) = implementations differ or ESLint version is missing functionality -πŸ›‘ (71) = unimplemented + + +βœ… (30) = done
+🌟 (79) = in ESLint core
+πŸ”Œ (33) = in another plugin
+πŸŒ“ (16) = implementations differ or ESLint version is missing functionality
+πŸ›‘ (68) = unimplemented
## TSLint rules From d5323342e569f4ca93904e95d5d302edaf7ea619 Mon Sep 17 00:00:00 2001 From: Benjamin Lichtman Date: Mon, 4 Feb 2019 17:12:56 -0800 Subject: [PATCH 5/5] fix: respond to review --- packages/eslint-plugin/README.md | 2 +- packages/eslint-plugin/ROADMAP.md | 4 ++-- .../eslint-plugin/docs/rules/no-for-in-array.md | 16 ++++++++++++---- packages/eslint-plugin/jsconfig.json | 8 -------- .../eslint-plugin/lib/rules/no-for-in-array.js | 11 +++++------ .../tests/lib/rules/no-for-in-array.js | 10 ++-------- 6 files changed, 22 insertions(+), 29 deletions(-) delete mode 100644 packages/eslint-plugin/jsconfig.json diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 8f93b37f0c96..3807877a073e 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -128,7 +128,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces (`no-empty-interface` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type (`no-any` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces (`no-unnecessary-class` from TSLint) | | | -| [`typescript/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop (`no-for-in-array` from TSLint) | | | +| [`@typescript-eslint/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop (`no-for-in-array` from TSLint) | | | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean. (`no-inferrable-types` from TSLint) | :heavy_check_mark: | :wrench: | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor`. (`no-misused-new` from TSLint) | :heavy_check_mark: | | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces (`no-namespace` from TSLint) | :heavy_check_mark: | | diff --git a/packages/eslint-plugin/ROADMAP.md b/packages/eslint-plugin/ROADMAP.md index c75debcb45ef..5abf9e26d4ef 100644 --- a/packages/eslint-plugin/ROADMAP.md +++ b/packages/eslint-plugin/ROADMAP.md @@ -64,8 +64,7 @@ | [`no-empty`] | 🌟 | [`no-empty`][no-empty] | | [`no-eval`] | 🌟 | [`no-eval`][no-eval] | | [`no-floating-promises`] | πŸ›‘ | N/A ([relevant plugin][plugin:promise]) | -| [`no-for-in-array`] | βœ… | [`typescript/no-for-in-array`] | -| [`no-for-in-array`] | πŸ›‘ | N/A | +| [`no-for-in-array`] | βœ… | [`@typescript-eslint/no-for-in-array`] | | [`no-implicit-dependencies`] | πŸ”Œ | [`import/no-extraneous-dependencies`] | | [`no-inferred-empty-object-type`] | πŸ›‘ | N/A | | [`no-invalid-template-strings`] | 🌟 | [`no-template-curly-in-string`][no-template-curly-in-string] | @@ -592,6 +591,7 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- [`@typescript-eslint/member-delimiter-style`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md [`@typescript-eslint/prefer-interface`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-interface.md [`@typescript-eslint/no-array-constructor`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md +[`@typescript-eslint/no-for-in-array`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-for-in-array.md diff --git a/packages/eslint-plugin/docs/rules/no-for-in-array.md b/packages/eslint-plugin/docs/rules/no-for-in-array.md index 89aed236bac2..3a1cf2bdd370 100644 --- a/packages/eslint-plugin/docs/rules/no-for-in-array.md +++ b/packages/eslint-plugin/docs/rules/no-for-in-array.md @@ -6,10 +6,18 @@ This rule prohibits iterating over an array with a for-in loop. Rationale from TSLint: -> A for-in loop (for (var k in o)) iterates over the properties of an Object. -> While it is legal to use for-in loops with array types, it is not common. for-in will iterate over the indices of the array as strings, omitting any β€œholes” in the array. -> More common is to use for-of, which iterates over the values of an array. If you want to iterate over the indices, alternatives include: -> array.forEach((value, index) => { … }); for (const [index, value] of array.entries()) { … } for (let i = 0; i < array.length; i++) { … } +A for-in loop (`for (var k in o)`) iterates over the properties of an Object. +While it is legal to use for-in loops with array types, it is not common. +for-in will iterate over the indices of the array as strings, omitting any "holes" in +the array. +More common is to use for-of, which iterates over the values of an array. +If you want to iterate over the indices, alternatives include: + +```js +array.forEach((value, index) => { ... }); +for (const [index, value] of array.entries()) { ... } +for (let i = 0; i < array.length; i++) { ... } +``` Examples of **incorrect** code for this rule: diff --git a/packages/eslint-plugin/jsconfig.json b/packages/eslint-plugin/jsconfig.json deleted file mode 100644 index d68b67d6e404..000000000000 --- a/packages/eslint-plugin/jsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "target": "es2015", - "checkJs": true, - "strict": true, - "module": "commonjs" - } -} diff --git a/packages/eslint-plugin/lib/rules/no-for-in-array.js b/packages/eslint-plugin/lib/rules/no-for-in-array.js index 3d8e9ad00eff..23a19732ac45 100644 --- a/packages/eslint-plugin/lib/rules/no-for-in-array.js +++ b/packages/eslint-plugin/lib/rules/no-for-in-array.js @@ -23,6 +23,10 @@ module.exports = { url: util.metaDocsUrl('no-for-in-array') }, fixable: null, + messages: { + forInViolation: + 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.' + }, schema: [], type: 'problem' }, @@ -34,10 +38,6 @@ module.exports = { const checker = parserServices.program.getTypeChecker(); const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); - if (!originalNode) { - return; - } - const type = checker.getTypeAtLocation(originalNode.expression); if ( @@ -47,8 +47,7 @@ module.exports = { ) { context.report({ node, - message: - 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.' + messageId: 'forInViolation' }); } } diff --git a/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js b/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js index 94a3200608a4..91984453000d 100644 --- a/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js +++ b/packages/eslint-plugin/tests/lib/rules/no-for-in-array.js @@ -16,10 +16,6 @@ const rule = require('../../../lib/rules/no-for-in-array'), // Tests //------------------------------------------------------------------------------ -// RuleTester.it = function(text, method) { -// return method.call({ break: true }); -// }; - const rootDir = path.join(process.cwd(), 'tests/fixtures/'); const parserOptions = { ecmaVersion: 2015, @@ -30,8 +26,6 @@ const ruleTester = new RuleTester({ parserOptions, parser: '@typescript-eslint/parser' }); -const message = - 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.'; ruleTester.run('no-for-in-array', rule, { valid: [ @@ -53,7 +47,7 @@ for (const x in [3, 4, 5]) { }`, errors: [ { - message, + messageId: 'forInViolation', type: 'ForInStatement' } ] @@ -66,7 +60,7 @@ for (const x in z) { }`, errors: [ { - message, + messageId: 'forInViolation', type: 'ForInStatement' } ]