| /** |
| * @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), |
| ], |
| }); |
| |
| }, |
| }; |
| }, |
| }; |