diff options
author | Antoine du Hamel <duhamelantoine1995@gmail.com> | 2021-01-06 21:19:36 +0300 |
---|---|---|
committer | Danielle Adams <adamzdanielle@gmail.com> | 2021-03-16 15:55:09 +0300 |
commit | 057c6a842a55fbbf59db5c422f943c770568ce3d (patch) | |
tree | b8cc6fa1a69586185ed18e80e33fdbe796e0d5c3 /tools | |
parent | daa4ac54c5a46ab17fa40178170e0e96aecba849 (diff) |
tools: add ESLint rule no-array-destructuring
Iterating over arrays should be avoided because it relies on
user-mutable global methods (`Array.prototype[Symbol.iterator]`
and `%ArrayIteratorPrototype%.next`), we should instead use
other alternatives. This commit adds a rule that disallow
array destructuring syntax in favor of object destructuring syntax.
Note that you can ignore this rule if you are using
the array destructuring syntax over a safe iterable, or
actually want to iterate over a user-provided object.
PR-URL: https://github.com/nodejs/node/pull/36818
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/eslint-rules/no-array-destructuring.js | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/tools/eslint-rules/no-array-destructuring.js b/tools/eslint-rules/no-array-destructuring.js new file mode 100644 index 00000000000..81667e698fb --- /dev/null +++ b/tools/eslint-rules/no-array-destructuring.js @@ -0,0 +1,83 @@ +/** + * @fileoverview Iterating over arrays should be avoided because it relies on + * user-mutable global methods (`Array.prototype[Symbol.iterator]` + * and `%ArrayIteratorPrototype%.next`), we should instead use + * other alternatives. This file defines a rule that disallow + * array destructuring syntax in favor of object destructuring + * syntax. Note that you can ignore this rule if you are using + * the array destructuring syntax over a safe iterable, or + * actually want to iterate over a user-provided object. + * @author aduh95 <duhamelantoine1995@gmail.com> + */ +'use strict'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +const USE_OBJ_DESTRUCTURING = + 'Use object destructuring instead of array destructuring.'; +const USE_ARRAY_METHODS = + 'Use primordials.ArrayPrototypeSlice to avoid unsafe array iteration.'; + +const findComma = (sourceCode, elements, i, start) => { + if (i === 0) + return sourceCode.getTokenAfter(sourceCode.getTokenByRangeStart(start)); + + let element; + const originalIndex = i; + while (i && !element) { + element = elements[--i]; + } + let token = sourceCode.getTokenAfter( + element ?? sourceCode.getTokenByRangeStart(start) + ); + for (; i < originalIndex; i++) { + token = sourceCode.getTokenAfter(token); + } + return token; +}; +const createFix = (fixer, sourceCode, { range: [start, end], elements }) => [ + fixer.replaceTextRange([start, start + 1], '{'), + fixer.replaceTextRange([end - 1, end], '}'), + ...elements.map((node, i) => + (node === null ? + fixer.remove(findComma(sourceCode, elements, i, start)) : + fixer.insertTextBefore(node, i + ':')) + ), +]; +const arrayPatternContainsRestOperator = ({ elements }) => + elements?.find((node) => node?.type === 'RestElement'); + +module.exports = { + meta: { + type: 'suggestion', + fixable: 'code', + schema: [], + }, + create(context) { + const sourceCode = context.getSourceCode(); + + return { + ArrayPattern(node) { + const hasRest = arrayPatternContainsRestOperator(node); + context.report({ + message: hasRest ? USE_ARRAY_METHODS : USE_OBJ_DESTRUCTURING, + node: hasRest || node, + fix: hasRest ? + undefined : + (fixer) => [ + ...(node.parent.type === 'AssignmentExpression' ? + [ + fixer.insertTextBefore(node.parent, '('), + fixer.insertTextAfter(node.parent, ')'), + ] : + []), + ...createFix(fixer, sourceCode, node), + ], + }); + + }, + }; + }, +}; |