From 87f000caa6f6ff273e61f57398f72c29bd1fd48e Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 09:04:27 +0800 Subject: [PATCH 01/63] docs: add tips of how to install for new developers --- docs/new-rule.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/new-rule.md b/docs/new-rule.md index de48f32446..28f30f3a17 100644 --- a/docs/new-rule.md +++ b/docs/new-rule.md @@ -2,6 +2,7 @@ ## Prerequisite +- Use npm to install. - Ensure ESLint doesn't already have the [rule built-in](https://eslint.org/docs/rules/). - [Read the ESLint docs on creating a new rule.](https://eslint.org/docs/developer-guide/working-with-rules) - Look at the commit for how previous rules were added as inspiration. For example, the [`no-unused-properties` rule](https://github.com/sindresorhus/eslint-plugin-unicorn/commit/0179443f24326fb01342a0bf799f7ac66e0e2c23). From a8f6d3f81cb0471e552e6d3d5874d4f9ed73ac81 Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 09:06:36 +0800 Subject: [PATCH 02/63] fix: error when npm run create-rule > Cannot find package 'lodash-es' imported from ...create-rule.js --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6cd7837355..4c85ff73ec 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "eslint-remote-tester-repositories": "^2.0.1", "espree": "^10.3.0", "listr2": "^8.3.3", + "lodash-es": "^4.17.21", "markdownlint-cli": "^0.44.0", "memoize": "^10.1.0", "nano-spawn": "^0.2.0", From ea97dd1aefb4bc1b85414a9dfee0a5fe15f68c6e Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 10:58:01 +0800 Subject: [PATCH 03/63] feat: add new rule no-array-fill-with-reference-type without fix solution --- .../no-array-fill-with-reference-type.md | 27 ++ rules/index.js | 2 + rules/no-array-fill-with-reference-type.js | 154 +++++++++++ test/no-array-fill-with-reference-type.js | 44 +++ .../no-array-fill-with-reference-type.js.md | 255 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 0 -> 1061 bytes 6 files changed, 482 insertions(+) create mode 100644 docs/rules/no-array-fill-with-reference-type.md create mode 100644 rules/no-array-fill-with-reference-type.js create mode 100644 test/no-array-fill-with-reference-type.js create mode 100644 test/snapshots/no-array-fill-with-reference-type.js.md create mode 100644 test/snapshots/no-array-fill-with-reference-type.js.snap diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md new file mode 100644 index 0000000000..6ff80b94ec --- /dev/null +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -0,0 +1,27 @@ + + + + + +## Examples + +```js +// ❌ +const foo = 'unicorn'; + +// ✅ +const foo = '🦄'; +``` + +```js +// ❌ +function foo() { + var replace = 'me'; + return replace; +} + +// ✅ +function foo() { + return 'me'; +} +``` diff --git a/rules/index.js b/rules/index.js index df4fe31c36..a416d22628 100644 --- a/rules/index.js +++ b/rules/index.js @@ -22,6 +22,7 @@ import noAbusiveEslintDisable from './no-abusive-eslint-disable.js'; import noAccessorRecursion from './no-accessor-recursion.js'; import noAnonymousDefaultExport from './no-anonymous-default-export.js'; import noArrayCallbackReference from './no-array-callback-reference.js'; +import noArrayFillWithReferenceType from './no-array-fill-with-reference-type.js'; import noArrayForEach from './no-array-for-each.js'; import noArrayMethodThisArgument from './no-array-method-this-argument.js'; import noArrayReduce from './no-array-reduce.js'; @@ -154,6 +155,7 @@ const rules = { 'no-accessor-recursion': createRule(noAccessorRecursion, 'no-accessor-recursion'), 'no-anonymous-default-export': createRule(noAnonymousDefaultExport, 'no-anonymous-default-export'), 'no-array-callback-reference': createRule(noArrayCallbackReference, 'no-array-callback-reference'), + 'no-array-fill-with-reference-type': createRule(noArrayFillWithReferenceType, 'no-array-fill-with-reference-type'), 'no-array-for-each': createRule(noArrayForEach, 'no-array-for-each'), 'no-array-method-this-argument': createRule(noArrayMethodThisArgument, 'no-array-method-this-argument'), 'no-array-reduce': createRule(noArrayReduce, 'no-array-reduce'), diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js new file mode 100644 index 0000000000..9ffa61c2f7 --- /dev/null +++ b/rules/no-array-fill-with-reference-type.js @@ -0,0 +1,154 @@ +// @ts-check +import {} from './ast/index.js'; +import {} from './fix/index.js'; +import {} from './utils/index.js'; + +const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; +// Const MESSAGE_ID_SUGGESTION = 'no-array-fill-with-reference-type/suggestion'; +const messages = { + [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', + // [MESSAGE_ID_SUGGESTION]: 'Replace the reference type ({{type}}) to an independent instance.', +}; + +/** + @param {*} node + @param {import('eslint').Rule.RuleContext} context + @returns + */ +function isReferenceType(node, context) { + if (!node) { + return false; + } + + // 原始类型:字面量(null, number, string, boolean) + if (node.type === 'Literal') { + // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + return node.regex !== undefined; + } + + // 特殊处理:模板字符串(`hello`)属于原始类型 + if (node.type === 'TemplateLiteral') { + return false; + } + + // 变量标识符(递归检查其声明) + if (node.type === 'Identifier') { + const {variables} = context.sourceCode.getScope(node); + const variable = variables.find(v => v.name === node.name); + // Console.log('variables:', variables); + // console.log('variable:', variable); + // console.log('variable.defs[0].node:', variable.defs[0].node); + if (!variable || !variable.defs[0]?.node) { + return false; + } + + return isReferenceType(variable.defs[0].node, context); + } + + // Symbol(如 Symbol('name')) + if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { + const {variables} = context.sourceCode.getScope(node); + + // Console.log('variables 2:', variables); + if (!variables || variables.length === 0) { + // 未找到变量声明,可能是全局变量 + return false; + } + } + + // 其他情况:对象、数组、函数、new表达式、正则表达式等 + return true; +} + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => ({ + CallExpression(node) { + const isFill = node.callee.type === 'MemberExpression' + && node.callee.property.name === 'fill' + && node.arguments.length > 0; + + if (!isFill) { + return; + } + + const fillArgument = node.arguments[0]; + // Console.log('fillArgument:', fillArgument); + + if (!isReferenceType(fillArgument, context)) { + return; + } + + let type = 'unknown'; + switch (fillArgument.type) { + case 'ObjectExpression': { + type = 'Object'; + break; + } + + case 'ArrayExpression': { + type = 'Array'; + break; + } + + case 'NewExpression': { + type = `new ${fillArgument.callee.name}()`; + break; + } + + case 'FunctionExpression': + case 'ArrowFunctionExpression': { + type = 'Function'; + break; + } + + default: { + // 正则表达式字面量 + if (fillArgument.type === 'Literal' && fillArgument.regex) { + type = 'RegExp'; + } else if (fillArgument.type === 'Identifier') { + type = `variable (${fillArgument.name})`; + } + } + } + + return { + node, + messageId: MESSAGE_ID_ERROR, + data: { + type, + replacement: '🦄', + }, + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + // fix: fixer => fixer.replaceText(node, '\'🦄\''), + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + // suggest: [ + // { + // messageId: MESSAGE_ID_SUGGESTION, + // data: { + // type, + // }, + // }, + // ], + + }; + }, +}); + +/** @type {import('eslint').Rule.RuleModule} */ +const config = { + create, + meta: { + type: 'problem', + docs: { + description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', + recommended: true, + }, + fixable: 'code', + hasSuggestions: true, + messages, + }, +}; + +export default config; diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js new file mode 100644 index 0000000000..8e51a738f9 --- /dev/null +++ b/test/no-array-fill-with-reference-type.js @@ -0,0 +1,44 @@ +import {getTester} from './utils/test.js'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'const foo = "🦄";', + 'new Array(3).fill(0); // ✓ number (primitive) ', + 'new Array(3).fill(10n); // ✓ bigint (primitive) ', + 'new Array(3).fill(null); // ✓ null (primitive) ', + 'new Array(3).fill(undefined); // ✓ undefined(primitive) ', + 'new Array(3).fill(\'foo\'); // ✓ string (primitive) ', + 'new Array(3).fill(false); // ✓ boolean (primitive) ', + 'new Array(3).fill(Symbol(\'foo\')); // ✓ Symbol(primitive) ', + + 'Array.from({ length: 3 }, () => ({})); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return {} }); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => (new Map)); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return new Map }); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return new Map() }); // ✓ Safe alternative', + + // 'Array(3).fill(0); // ✓ number (primitive) ', + // 'new Foo(3).fill({}); // ✓ Not Array ', + // 'Foo(3).fill({}); // ✓ Not Array ', + ], + invalid: [ + 'new Array(3).fill({}); // ✗ Object ', + 'new Array(3).fill(new Map()); // ✗ Map', + 'new Array(3).fill(new Set()); // ✗ Set', + 'new Array(3).fill(/pattern/); // ✗ RegExp ', + 'new Array(3).fill(new String(\'fff\')); // ✗ new String', + + 'new Array(3).fill(new Foo(\'fff\')); // ✗ new Class', + 'class BarClass {}; new Array(3).fill(BarClass); // ✗ Class', + 'class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance', + 'new Array(3).fill(() => 1); // ✗ arrow function', + 'new Array(3).fill(() => {}); // ✗ arrow function', + 'new Array(3).fill(function () {}); // ✗ normal function', + 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', + + // 'Array(3).fill({}); // ✗ Object ', + // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', + ], +}); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md new file mode 100644 index 0000000000..c67b1cc576 --- /dev/null +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -0,0 +1,255 @@ +# Snapshot report for `test/no-array-fill-with-reference-type.js` + +The actual snapshot is saved in `no-array-fill-with-reference-type.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## invalid(1): new Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | new Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill({}); // ✗ Object ␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(2): new Array(3).fill(new Map()); // ✗ Map + +> Input + + `␊ + 1 | new Array(3).fill(new Map()); // ✗ Map␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Map()); // ✗ Map␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Map()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(3): new Array(3).fill(new Set()); // ✗ Set + +> Input + + `␊ + 1 | new Array(3).fill(new Set()); // ✗ Set␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Set()); // ✗ Set␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Set()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp + +> Input + + `␊ + 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (RegExp). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String + +> Input + + `␊ + 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new String()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class + +> Input + + `␊ + 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Foo()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (BarClass)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new BarClass()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(11): new Array(3).fill(function () {}); // ✗ normal function + +> Input + + `␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(12): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(10): new Array(3).fill(function () {}); // ✗ normal function + +> Input + + `␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(11): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(8): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(1): const foo = "unicorn"; + +> Input + + `␊ + 1 | const foo = "unicorn";␊ + ` + +> Output + + `␊ + 1 | const foo = '🦄';␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = "unicorn";␊ + | ^^^^^^^^^ Prefer \`🦄\` over \`unicorn\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace \`unicorn\` with \`🦄\`.␊ + 1 | const foo = '🦄';␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..481b0baea051baea40fef91c8c281f37d169a919 GIT binary patch literal 1061 zcmV+=1ls#SRzV47OJz4MDJh8p4K#rwr2$s7 z$%SU(9d8WI*c#6!L`g2RKY&{=l`3-Jhj8nq5>i$5QVyU>y;Q2;&>JAHch-LK%zC|9 zOH{vd!x!O$gGPf0vU2&v$jOmt8~tG9qtU4ffCYQHSn-A; z0#v9+)~QFoVnIuEqCQPW9eXlTxmY}Gv~LgYs5Y42^4$isLYFn;fN?Yvwq3CSoH~?K zW>XM50S&>3W13aC9a4Ed_csj_TowvS8X$b2ENpQKE^E+$vIb?MeUvbphSknZx(l59 z9ITop38o~$r%Hlo&k_j?Gm%&#L6+f5#Bg5AkdBACZHWXbh(8g;uX>1{fqPI4D3YWr z73G{3rA|c}rA`&KQ3OTCLw#4L;>al4z~!LC>B>NvmMBw7lv+T9pq$kblv}j9a9>d@ z{mxn1kjgph52W&oUZqFa;hV&fO98neK|a%0iQq148WWD=Or)wMIh4hzBbWt`%1|x9tp!NnxvaHXTXl`11=NZz9HD%pH*~+Je)Xc3|Elh^^RfD z9H_H(n5&~7BF)!Qa|qdDR>d|%<1NBnvhGnxuB8<1Z>9F<{c1;hoyNxU9#w-MY`EnFr6 zevH9sRDLg!-wVB8u}mdBHkFEbvx^yhd9i&K3fLq8%t80tf@*QuBtZiEO?S Date: Thu, 29 May 2025 11:16:09 +0800 Subject: [PATCH 04/63] feat(no-array-fill-with-reference-type): only check fill on builtin Array --- rules/no-array-fill-with-reference-type.js | 109 +++++++++--------- test/no-array-fill-with-reference-type.js | 8 +- .../no-array-fill-with-reference-type.js.md | 15 +++ .../no-array-fill-with-reference-type.js.snap | Bin 1061 -> 1092 bytes 4 files changed, 74 insertions(+), 58 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 9ffa61c2f7..3e1f7b4969 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -4,70 +4,21 @@ import {} from './fix/index.js'; import {} from './utils/index.js'; const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; -// Const MESSAGE_ID_SUGGESTION = 'no-array-fill-with-reference-type/suggestion'; const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', - // [MESSAGE_ID_SUGGESTION]: 'Replace the reference type ({{type}}) to an independent instance.', }; -/** - @param {*} node - @param {import('eslint').Rule.RuleContext} context - @returns - */ -function isReferenceType(node, context) { - if (!node) { - return false; - } - - // 原始类型:字面量(null, number, string, boolean) - if (node.type === 'Literal') { - // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) - return node.regex !== undefined; - } - - // 特殊处理:模板字符串(`hello`)属于原始类型 - if (node.type === 'TemplateLiteral') { - return false; - } - - // 变量标识符(递归检查其声明) - if (node.type === 'Identifier') { - const {variables} = context.sourceCode.getScope(node); - const variable = variables.find(v => v.name === node.name); - // Console.log('variables:', variables); - // console.log('variable:', variable); - // console.log('variable.defs[0].node:', variable.defs[0].node); - if (!variable || !variable.defs[0]?.node) { - return false; - } - - return isReferenceType(variable.defs[0].node, context); - } - - // Symbol(如 Symbol('name')) - if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { - const {variables} = context.sourceCode.getScope(node); - - // Console.log('variables 2:', variables); - if (!variables || variables.length === 0) { - // 未找到变量声明,可能是全局变量 - return false; - } - } - - // 其他情况:对象、数组、函数、new表达式、正则表达式等 - return true; -} - /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { - const isFill = node.callee.type === 'MemberExpression' + const isArrayDotFill = node.callee.type === 'MemberExpression' + && node.callee.object.callee?.name === 'Array' && node.callee.property.name === 'fill' && node.arguments.length > 0; - if (!isFill) { + // Console.log('isArrayDotFill:', isArrayDotFill); + + if (!isArrayDotFill) { return; } @@ -136,6 +87,56 @@ const create = context => ({ }, }); +/** + @param {*} node + @param {import('eslint').Rule.RuleContext} context + @returns + */ +function isReferenceType(node, context) { + if (!node) { + return false; + } + + // 原始类型:字面量(null, number, string, boolean) + if (node.type === 'Literal') { + // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + return node.regex !== undefined; + } + + // 特殊处理:模板字符串(`hello`)属于原始类型 + if (node.type === 'TemplateLiteral') { + return false; + } + + // 变量标识符(递归检查其声明) + if (node.type === 'Identifier') { + const {variables} = context.sourceCode.getScope(node); + const variable = variables.find(v => v.name === node.name); + // Console.log('variables:', variables); + // console.log('variable:', variable); + // console.log('variable.defs[0].node:', variable.defs[0].node); + if (!variable || !variable.defs[0]?.node) { + return false; + } + + return isReferenceType(variable.defs[0].node, context); + } + + // Symbol(如 Symbol('name')) + if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { + const {variables} = context.sourceCode.getScope(node); + + // Console.log('variables 2:', variables); + if (!variables || variables.length === 0) { + // 未找到变量声明,可能是全局变量 + return false; + } + } + + // 其他情况:对象、数组、函数、new表达式、正则表达式等 + return true; +} + /** @type {import('eslint').Rule.RuleModule} */ const config = { create, diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 8e51a738f9..2455fd5251 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -19,9 +19,9 @@ test.snapshot({ 'Array.from({ length: 3 }, () => { return new Map }); // ✓ Safe alternative', 'Array.from({ length: 3 }, () => { return new Map() }); // ✓ Safe alternative', - // 'Array(3).fill(0); // ✓ number (primitive) ', - // 'new Foo(3).fill({}); // ✓ Not Array ', - // 'Foo(3).fill({}); // ✓ Not Array ', + 'Array(3).fill(0); // ✓ number (primitive)', + 'new Foo(3).fill({}); // ✓ Not Array', + 'Foo(3).fill({}); // ✓ Not Array', ], invalid: [ 'new Array(3).fill({}); // ✗ Object ', @@ -38,7 +38,7 @@ test.snapshot({ 'new Array(3).fill(function () {}); // ✗ normal function', 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', - // 'Array(3).fill({}); // ✗ Object ', + 'Array(3).fill({}); // ✗ Object ', // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index c67b1cc576..cb1c27b5f8 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -184,6 +184,21 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ ` +## invalid(13): Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array(3).fill({}); // ✗ Object ␊ + | ^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + ` + ## invalid(10): new Array(3).fill(function () {}); // ✗ normal function > Input diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 481b0baea051baea40fef91c8c281f37d169a919..3bf8ddb0e8da10ff06165a5ffa8880505b8b2e3d 100644 GIT binary patch literal 1092 zcmV-K1iSk|RzV{tSwV-N$i0e#{Lx}Jt zOp;c9{~wD800000000B++0Ad%Mic<>1cZ=Q0*Ny!ddelX1iNtwUx^Y3kN}lJfE8bt zl8JY`7@V;+o=rf&1^5RzaX~`m&_AL_Zd@u=swysU09EP*3BiF|TY0^+_KRoM>&;pM z5uYM^=RJFVGjHt4FV2eR+qc6fFQ{;ZNAFCyY>jws!?4ULV00bkI45_FgJ#unJjPx?^O|=wt=Jg8RBy@qr=& zRH#Q*s7KGSpd~s{|42vO_Hv{$TRd!Z?mqmiI$&f zgH^L6!K5VkQArS;StNmBCK8Jz$TFNp42QK0>3FEy7D=Fjc!MB**F*FS+=F63ktAKI zCl(Slba)~zQ?}?jIi#N@g1f9~j604qo|-Mmr7TVz;mr4*G#kRB zF`oQDrS%1A{gX3?`plEhx2dTW-$gmI>$t=`ti@dLeWm0nkAz_satT4s^@K#BGrikR zphEnB5a0Gj>?cQ`fP?5o>C2%zE9s7yQ(#BW0VfG>KM>q|Fs^7+yn$KXnX? z=0KgT!@NGa3u*op+RG+razB`Y3<2L5n zuJefNL=IQ>(>dSkZ{+n?o>y*)-1YXW5?knssrO6dV}W5JH|FzI;`M;LjNr~_;W7#E zYYa}K^81AR-s}B}Wh&{lsZ`91UCe0b#r9b!V3hBf&}(Tcg>GZXI*a~ z*NbumEtV_Y@i?J!<=l;k|LeX*4K1m5#ni8wgTG5f8B5_m(B+Tzc#7|P&LY~04((?4 zJYONW-z3~-_dCC$z0QT46>qD4ev|dn+Nz)5U;Vs*K0~+kzc2l<^gj;c&T)JnW?-zv zT-)btY&!9L)bZSpJoh2bjjdJ1*F^32D%y{KeE#d>aoN~eYKau>Hbnaw(`NE#of3}= z?JkGqDBCjlYti4Gmdn*j<-m}SO1;%=(y+apST$=3F44dvHcgVo10lYjYHq(Ioc{wz KrO(3=9smG47#HUN literal 1061 zcmV+=1ls#SRzV47OJz4MDJh8p4K#rwr2$s7 z$%SU(9d8WI*c#6!L`g2RKY&{=l`3-Jhj8nq5>i$5QVyU>y;Q2;&>JAHch-LK%zC|9 zOH{vd!x!O$gGPf0vU2&v$jOmt8~tG9qtU4ffCYQHSn-A; z0#v9+)~QFoVnIuEqCQPW9eXlTxmY}Gv~LgYs5Y42^4$isLYFn;fN?Yvwq3CSoH~?K zW>XM50S&>3W13aC9a4Ed_csj_TowvS8X$b2ENpQKE^E+$vIb?MeUvbphSknZx(l59 z9ITop38o~$r%Hlo&k_j?Gm%&#L6+f5#Bg5AkdBACZHWXbh(8g;uX>1{fqPI4D3YWr z73G{3rA|c}rA`&KQ3OTCLw#4L;>al4z~!LC>B>NvmMBw7lv+T9pq$kblv}j9a9>d@ z{mxn1kjgph52W&oUZqFa;hV&fO98neK|a%0iQq148WWD=Or)wMIh4hzBbWt`%1|x9tp!NnxvaHXTXl`11=NZz9HD%pH*~+Je)Xc3|Elh^^RfD z9H_H(n5&~7BF)!Qa|qdDR>d|%<1NBnvhGnxuB8<1Z>9F<{c1;hoyNxU9#w-MY`EnFr6 zevH9sRDLg!-wVB8u}mdBHkFEbvx^yhd9i&K3fLq8%t80tf@*QuBtZiEO?S Date: Thu, 29 May 2025 11:31:41 +0800 Subject: [PATCH 05/63] test(no-array-fill-with-reference-type): add more valid cases --- test/no-array-fill-with-reference-type.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 2455fd5251..a57b8fdcad 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -22,6 +22,17 @@ test.snapshot({ 'Array(3).fill(0); // ✓ number (primitive)', 'new Foo(3).fill({}); // ✓ Not Array', 'Foo(3).fill({}); // ✓ Not Array', + + 'const map = new Map(); Array.from({ length: 3 }, () => map); // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable (map).', + + ` + // Due to the rule name it will not check other than \`Array.fill\`., + const map = new Map(); + const list = []; + for (let i = 0; i < 3; i++) { + list.push(map); + } + `, ], invalid: [ 'new Array(3).fill({}); // ✗ Object ', @@ -39,6 +50,5 @@ test.snapshot({ 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', 'Array(3).fill({}); // ✗ Object ', - // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', ], }); From 57f4d74cad48c3dbb443dafbe32556287b11f6b2 Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 11:42:12 +0800 Subject: [PATCH 06/63] docs(no-array-fill-with-reference-type): remove comments --- rules/no-array-fill-with-reference-type.js | 39 ++++++++-------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 3e1f7b4969..3d8f3fcb62 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -8,6 +8,9 @@ const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', }; +const debugging = false; +const log = (...arguments_) => debugging && console.log(...arguments_); + /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { @@ -16,14 +19,14 @@ const create = context => ({ && node.callee.property.name === 'fill' && node.arguments.length > 0; - // Console.log('isArrayDotFill:', isArrayDotFill); + log('isArrayDotFill:', isArrayDotFill); if (!isArrayDotFill) { return; } const fillArgument = node.arguments[0]; - // Console.log('fillArgument:', fillArgument); + log('fillArgument:', fillArgument); if (!isReferenceType(fillArgument, context)) { return; @@ -53,7 +56,6 @@ const create = context => ({ } default: { - // 正则表达式字面量 if (fillArgument.type === 'Literal' && fillArgument.regex) { type = 'RegExp'; } else if (fillArgument.type === 'Identifier') { @@ -69,20 +71,6 @@ const create = context => ({ type, replacement: '🦄', }, - - /** @param {import('eslint').Rule.RuleFixer} fixer */ - // fix: fixer => fixer.replaceText(node, '\'🦄\''), - - /** @param {import('eslint').Rule.RuleFixer} fixer */ - // suggest: [ - // { - // messageId: MESSAGE_ID_SUGGESTION, - // data: { - // type, - // }, - // }, - // ], - }; }, }); @@ -97,24 +85,24 @@ function isReferenceType(node, context) { return false; } - // 原始类型:字面量(null, number, string, boolean) + // For null, number, string, boolean. if (node.type === 'Literal') { - // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). return node.regex !== undefined; } - // 特殊处理:模板字符串(`hello`)属于原始类型 + // For template literals. if (node.type === 'TemplateLiteral') { return false; } - // 变量标识符(递归检查其声明) + // For variable identifiers (recursively check its declaration). if (node.type === 'Identifier') { const {variables} = context.sourceCode.getScope(node); const variable = variables.find(v => v.name === node.name); - // Console.log('variables:', variables); - // console.log('variable:', variable); - // console.log('variable.defs[0].node:', variable.defs[0].node); + log('variables:', variables); + log('variable:', variable); + log('variable.defs[0].node:', variable?.defs[0].node); if (!variable || !variable.defs[0]?.node) { return false; } @@ -126,7 +114,7 @@ function isReferenceType(node, context) { if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { const {variables} = context.sourceCode.getScope(node); - // Console.log('variables 2:', variables); + log('variables 2:', variables); if (!variables || variables.length === 0) { // 未找到变量声明,可能是全局变量 return false; @@ -143,6 +131,7 @@ const config = { meta: { type: 'problem', docs: { + // eslint-disable-next-line @stylistic/max-len description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', recommended: true, }, From 85bb03a5e3015935ee9231e8475d63e89106d1cf Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 11:50:49 +0800 Subject: [PATCH 07/63] docs(no-array-fill-with-reference-type): gen code by npm run fix:eslint-docs using Node.js v22.16.0 --- .../no-array-fill-with-reference-type.md | 6 + readme.md | 265 +++++++++--------- 2 files changed, 139 insertions(+), 132 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 6ff80b94ec..ee1d82415f 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -1,3 +1,9 @@ +# Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances + +💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). + +🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). + diff --git a/readme.md b/readme.md index 7b9dd9c850..41e9c9ad34 100644 --- a/readme.md +++ b/readme.md @@ -54,138 +54,139 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name                                    | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | -| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | -| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | -| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | -| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | -| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | -| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | -| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | -| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | -| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | -| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | -| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | -| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | -| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | -| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | -| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | -| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | -| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | -| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | -| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | -| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | -| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | -| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | -| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | +| Name                                    | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | +| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | +| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | +| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | +| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances. | ✅ | 🔧 | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | +| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | +| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | +| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | +| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | +| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | +| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | +| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | +| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | +| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | +| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | +| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | +| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | +| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | +| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | +| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | +| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | +| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | From 397722407e401c4eb3f70ad6ed8405e05278c921 Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 12:09:16 +0800 Subject: [PATCH 08/63] docs(no-array-fill-with-reference-type): brief the desc and recover readme.md to main generated by npm run fix:eslint-docs using Node.js v22.16.0 --- .../no-array-fill-with-reference-type.md | 2 +- readme.md | 266 +++++++++--------- rules/no-array-fill-with-reference-type.js | 7 +- 3 files changed, 135 insertions(+), 140 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index ee1d82415f..70a3c1b401 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -1,4 +1,4 @@ -# Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances +# Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). diff --git a/readme.md b/readme.md index 41e9c9ad34..5ce9943303 100644 --- a/readme.md +++ b/readme.md @@ -54,139 +54,139 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name                                    | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | -| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | -| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | -| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | -| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | -| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | -| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances. | ✅ | 🔧 | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | -| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | -| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | -| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | -| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | -| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | -| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | -| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | -| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | -| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | -| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | -| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | -| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | -| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | -| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | -| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | -| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | -| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | +| Name | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | +| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | +| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | +| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | +| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | | 💡 | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | +| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | +| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | +| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | +| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | +| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | +| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | +| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | +| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | +| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | +| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | +| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | +| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | +| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | +| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | +| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | +| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | +| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 3d8f3fcb62..457b429c04 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,8 +1,4 @@ // @ts-check -import {} from './ast/index.js'; -import {} from './fix/index.js'; -import {} from './utils/index.js'; - const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', @@ -131,8 +127,7 @@ const config = { meta: { type: 'problem', docs: { - // eslint-disable-next-line @stylistic/max-len - description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', + description: 'Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, fixable: 'code', From 8243f141e6bb2e59cef04569d9c19e9cc78e227e Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 13:45:07 +0800 Subject: [PATCH 09/63] docs: no file configs/recommended.js --- docs/new-rule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/new-rule.md b/docs/new-rule.md index 28f30f3a17..bb82966e9a 100644 --- a/docs/new-rule.md +++ b/docs/new-rule.md @@ -18,7 +18,7 @@ Use the [`astexplorer` site](https://astexplorer.net) with the `espree` parser a - Open “rules/{RULE_ID}.js” and implement the rule logic. - Add the correct [`meta.type`](https://eslint.org/docs/developer-guide/working-with-rules#rule-basics) to the rule. - Open “docs/rules/{RULE_ID}.js” and write some documentation. -- Double check `configs/recommended.js` and `readme.md`, make sure the new rule is correctly added. +- Double check `readme.md`, make sure the new rule is correctly added. - Run `npm test` to ensure the tests pass. - Run `npm run integration` to run the rules against real projects to ensure your rule does not fail on real-world code. - Open a pull request with a title in exactly the format `` Add `rule-name` rule ``, for example, `` Add `no-unused-properties` rule ``. From 3635dd302d3ae00779ade2fc16d587580eaed332 Mon Sep 17 00:00:00 2001 From: liuchuanzong Date: Thu, 29 May 2025 13:46:17 +0800 Subject: [PATCH 10/63] docs(no-array-fill-with-reference-type): gen code by npm run fix:eslint-docs using Node.js v22.16.0 --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 5ce9943303..e2c9e5f292 100644 --- a/readme.md +++ b/readme.md @@ -54,7 +54,7 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name | Description | 💼 | 🔧 | 💡 | +| Name                                    | Description | 💼 | 🔧 | 💡 | | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | | [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | | [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | @@ -77,8 +77,8 @@ export default [ | [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | | [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | 🔧 | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | | [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | | [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | From fcd690ef78f67aa9f7b4bd8a74d01f21f6064017 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 09:04:27 +0800 Subject: [PATCH 11/63] docs: add tips of how to install for new developers --- docs/new-rule.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/new-rule.md b/docs/new-rule.md index de48f32446..28f30f3a17 100644 --- a/docs/new-rule.md +++ b/docs/new-rule.md @@ -2,6 +2,7 @@ ## Prerequisite +- Use npm to install. - Ensure ESLint doesn't already have the [rule built-in](https://eslint.org/docs/rules/). - [Read the ESLint docs on creating a new rule.](https://eslint.org/docs/developer-guide/working-with-rules) - Look at the commit for how previous rules were added as inspiration. For example, the [`no-unused-properties` rule](https://github.com/sindresorhus/eslint-plugin-unicorn/commit/0179443f24326fb01342a0bf799f7ac66e0e2c23). From 51af337c165cf0e087d1c8937e40c42451aee252 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 09:06:36 +0800 Subject: [PATCH 12/63] fix: error when npm run create-rule > Cannot find package 'lodash-es' imported from ...create-rule.js --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6cd7837355..4c85ff73ec 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "eslint-remote-tester-repositories": "^2.0.1", "espree": "^10.3.0", "listr2": "^8.3.3", + "lodash-es": "^4.17.21", "markdownlint-cli": "^0.44.0", "memoize": "^10.1.0", "nano-spawn": "^0.2.0", From 09ca3b530e5c1a64bcc69a16ba756f8fe0dcf6cf Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 10:58:01 +0800 Subject: [PATCH 13/63] feat: add new rule no-array-fill-with-reference-type without fix solution --- .../no-array-fill-with-reference-type.md | 27 ++ rules/index.js | 2 + rules/no-array-fill-with-reference-type.js | 154 +++++++++++ test/no-array-fill-with-reference-type.js | 44 +++ .../no-array-fill-with-reference-type.js.md | 255 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 0 -> 1061 bytes 6 files changed, 482 insertions(+) create mode 100644 docs/rules/no-array-fill-with-reference-type.md create mode 100644 rules/no-array-fill-with-reference-type.js create mode 100644 test/no-array-fill-with-reference-type.js create mode 100644 test/snapshots/no-array-fill-with-reference-type.js.md create mode 100644 test/snapshots/no-array-fill-with-reference-type.js.snap diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md new file mode 100644 index 0000000000..6ff80b94ec --- /dev/null +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -0,0 +1,27 @@ + + + + + +## Examples + +```js +// ❌ +const foo = 'unicorn'; + +// ✅ +const foo = '🦄'; +``` + +```js +// ❌ +function foo() { + var replace = 'me'; + return replace; +} + +// ✅ +function foo() { + return 'me'; +} +``` diff --git a/rules/index.js b/rules/index.js index df4fe31c36..a416d22628 100644 --- a/rules/index.js +++ b/rules/index.js @@ -22,6 +22,7 @@ import noAbusiveEslintDisable from './no-abusive-eslint-disable.js'; import noAccessorRecursion from './no-accessor-recursion.js'; import noAnonymousDefaultExport from './no-anonymous-default-export.js'; import noArrayCallbackReference from './no-array-callback-reference.js'; +import noArrayFillWithReferenceType from './no-array-fill-with-reference-type.js'; import noArrayForEach from './no-array-for-each.js'; import noArrayMethodThisArgument from './no-array-method-this-argument.js'; import noArrayReduce from './no-array-reduce.js'; @@ -154,6 +155,7 @@ const rules = { 'no-accessor-recursion': createRule(noAccessorRecursion, 'no-accessor-recursion'), 'no-anonymous-default-export': createRule(noAnonymousDefaultExport, 'no-anonymous-default-export'), 'no-array-callback-reference': createRule(noArrayCallbackReference, 'no-array-callback-reference'), + 'no-array-fill-with-reference-type': createRule(noArrayFillWithReferenceType, 'no-array-fill-with-reference-type'), 'no-array-for-each': createRule(noArrayForEach, 'no-array-for-each'), 'no-array-method-this-argument': createRule(noArrayMethodThisArgument, 'no-array-method-this-argument'), 'no-array-reduce': createRule(noArrayReduce, 'no-array-reduce'), diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js new file mode 100644 index 0000000000..9ffa61c2f7 --- /dev/null +++ b/rules/no-array-fill-with-reference-type.js @@ -0,0 +1,154 @@ +// @ts-check +import {} from './ast/index.js'; +import {} from './fix/index.js'; +import {} from './utils/index.js'; + +const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; +// Const MESSAGE_ID_SUGGESTION = 'no-array-fill-with-reference-type/suggestion'; +const messages = { + [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', + // [MESSAGE_ID_SUGGESTION]: 'Replace the reference type ({{type}}) to an independent instance.', +}; + +/** + @param {*} node + @param {import('eslint').Rule.RuleContext} context + @returns + */ +function isReferenceType(node, context) { + if (!node) { + return false; + } + + // 原始类型:字面量(null, number, string, boolean) + if (node.type === 'Literal') { + // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + return node.regex !== undefined; + } + + // 特殊处理:模板字符串(`hello`)属于原始类型 + if (node.type === 'TemplateLiteral') { + return false; + } + + // 变量标识符(递归检查其声明) + if (node.type === 'Identifier') { + const {variables} = context.sourceCode.getScope(node); + const variable = variables.find(v => v.name === node.name); + // Console.log('variables:', variables); + // console.log('variable:', variable); + // console.log('variable.defs[0].node:', variable.defs[0].node); + if (!variable || !variable.defs[0]?.node) { + return false; + } + + return isReferenceType(variable.defs[0].node, context); + } + + // Symbol(如 Symbol('name')) + if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { + const {variables} = context.sourceCode.getScope(node); + + // Console.log('variables 2:', variables); + if (!variables || variables.length === 0) { + // 未找到变量声明,可能是全局变量 + return false; + } + } + + // 其他情况:对象、数组、函数、new表达式、正则表达式等 + return true; +} + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => ({ + CallExpression(node) { + const isFill = node.callee.type === 'MemberExpression' + && node.callee.property.name === 'fill' + && node.arguments.length > 0; + + if (!isFill) { + return; + } + + const fillArgument = node.arguments[0]; + // Console.log('fillArgument:', fillArgument); + + if (!isReferenceType(fillArgument, context)) { + return; + } + + let type = 'unknown'; + switch (fillArgument.type) { + case 'ObjectExpression': { + type = 'Object'; + break; + } + + case 'ArrayExpression': { + type = 'Array'; + break; + } + + case 'NewExpression': { + type = `new ${fillArgument.callee.name}()`; + break; + } + + case 'FunctionExpression': + case 'ArrowFunctionExpression': { + type = 'Function'; + break; + } + + default: { + // 正则表达式字面量 + if (fillArgument.type === 'Literal' && fillArgument.regex) { + type = 'RegExp'; + } else if (fillArgument.type === 'Identifier') { + type = `variable (${fillArgument.name})`; + } + } + } + + return { + node, + messageId: MESSAGE_ID_ERROR, + data: { + type, + replacement: '🦄', + }, + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + // fix: fixer => fixer.replaceText(node, '\'🦄\''), + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + // suggest: [ + // { + // messageId: MESSAGE_ID_SUGGESTION, + // data: { + // type, + // }, + // }, + // ], + + }; + }, +}); + +/** @type {import('eslint').Rule.RuleModule} */ +const config = { + create, + meta: { + type: 'problem', + docs: { + description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', + recommended: true, + }, + fixable: 'code', + hasSuggestions: true, + messages, + }, +}; + +export default config; diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js new file mode 100644 index 0000000000..8e51a738f9 --- /dev/null +++ b/test/no-array-fill-with-reference-type.js @@ -0,0 +1,44 @@ +import {getTester} from './utils/test.js'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'const foo = "🦄";', + 'new Array(3).fill(0); // ✓ number (primitive) ', + 'new Array(3).fill(10n); // ✓ bigint (primitive) ', + 'new Array(3).fill(null); // ✓ null (primitive) ', + 'new Array(3).fill(undefined); // ✓ undefined(primitive) ', + 'new Array(3).fill(\'foo\'); // ✓ string (primitive) ', + 'new Array(3).fill(false); // ✓ boolean (primitive) ', + 'new Array(3).fill(Symbol(\'foo\')); // ✓ Symbol(primitive) ', + + 'Array.from({ length: 3 }, () => ({})); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return {} }); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => (new Map)); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return new Map }); // ✓ Safe alternative', + 'Array.from({ length: 3 }, () => { return new Map() }); // ✓ Safe alternative', + + // 'Array(3).fill(0); // ✓ number (primitive) ', + // 'new Foo(3).fill({}); // ✓ Not Array ', + // 'Foo(3).fill({}); // ✓ Not Array ', + ], + invalid: [ + 'new Array(3).fill({}); // ✗ Object ', + 'new Array(3).fill(new Map()); // ✗ Map', + 'new Array(3).fill(new Set()); // ✗ Set', + 'new Array(3).fill(/pattern/); // ✗ RegExp ', + 'new Array(3).fill(new String(\'fff\')); // ✗ new String', + + 'new Array(3).fill(new Foo(\'fff\')); // ✗ new Class', + 'class BarClass {}; new Array(3).fill(BarClass); // ✗ Class', + 'class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance', + 'new Array(3).fill(() => 1); // ✗ arrow function', + 'new Array(3).fill(() => {}); // ✗ arrow function', + 'new Array(3).fill(function () {}); // ✗ normal function', + 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', + + // 'Array(3).fill({}); // ✗ Object ', + // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', + ], +}); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md new file mode 100644 index 0000000000..c67b1cc576 --- /dev/null +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -0,0 +1,255 @@ +# Snapshot report for `test/no-array-fill-with-reference-type.js` + +The actual snapshot is saved in `no-array-fill-with-reference-type.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## invalid(1): new Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | new Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill({}); // ✗ Object ␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(2): new Array(3).fill(new Map()); // ✗ Map + +> Input + + `␊ + 1 | new Array(3).fill(new Map()); // ✗ Map␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Map()); // ✗ Map␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Map()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(3): new Array(3).fill(new Set()); // ✗ Set + +> Input + + `␊ + 1 | new Array(3).fill(new Set()); // ✗ Set␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Set()); // ✗ Set␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Set()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp + +> Input + + `␊ + 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (RegExp). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String + +> Input + + `␊ + 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new String()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class + +> Input + + `␊ + 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Foo()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (BarClass)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new BarClass()). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(11): new Array(3).fill(function () {}); // ✗ normal function + +> Input + + `␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(12): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(10): new Array(3).fill(function () {}); // ✗ normal function + +> Input + + `␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(11): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(8): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + ` + +## invalid(1): const foo = "unicorn"; + +> Input + + `␊ + 1 | const foo = "unicorn";␊ + ` + +> Output + + `␊ + 1 | const foo = '🦄';␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = "unicorn";␊ + | ^^^^^^^^^ Prefer \`🦄\` over \`unicorn\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Replace \`unicorn\` with \`🦄\`.␊ + 1 | const foo = '🦄';␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..481b0baea051baea40fef91c8c281f37d169a919 GIT binary patch literal 1061 zcmV+=1ls#SRzV47OJz4MDJh8p4K#rwr2$s7 z$%SU(9d8WI*c#6!L`g2RKY&{=l`3-Jhj8nq5>i$5QVyU>y;Q2;&>JAHch-LK%zC|9 zOH{vd!x!O$gGPf0vU2&v$jOmt8~tG9qtU4ffCYQHSn-A; z0#v9+)~QFoVnIuEqCQPW9eXlTxmY}Gv~LgYs5Y42^4$isLYFn;fN?Yvwq3CSoH~?K zW>XM50S&>3W13aC9a4Ed_csj_TowvS8X$b2ENpQKE^E+$vIb?MeUvbphSknZx(l59 z9ITop38o~$r%Hlo&k_j?Gm%&#L6+f5#Bg5AkdBACZHWXbh(8g;uX>1{fqPI4D3YWr z73G{3rA|c}rA`&KQ3OTCLw#4L;>al4z~!LC>B>NvmMBw7lv+T9pq$kblv}j9a9>d@ z{mxn1kjgph52W&oUZqFa;hV&fO98neK|a%0iQq148WWD=Or)wMIh4hzBbWt`%1|x9tp!NnxvaHXTXl`11=NZz9HD%pH*~+Je)Xc3|Elh^^RfD z9H_H(n5&~7BF)!Qa|qdDR>d|%<1NBnvhGnxuB8<1Z>9F<{c1;hoyNxU9#w-MY`EnFr6 zevH9sRDLg!-wVB8u}mdBHkFEbvx^yhd9i&K3fLq8%t80tf@*QuBtZiEO?S Date: Thu, 29 May 2025 11:16:09 +0800 Subject: [PATCH 14/63] feat(no-array-fill-with-reference-type): only check fill on builtin Array --- rules/no-array-fill-with-reference-type.js | 109 +++++++++--------- test/no-array-fill-with-reference-type.js | 8 +- .../no-array-fill-with-reference-type.js.md | 15 +++ .../no-array-fill-with-reference-type.js.snap | Bin 1061 -> 1092 bytes 4 files changed, 74 insertions(+), 58 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 9ffa61c2f7..3e1f7b4969 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -4,70 +4,21 @@ import {} from './fix/index.js'; import {} from './utils/index.js'; const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; -// Const MESSAGE_ID_SUGGESTION = 'no-array-fill-with-reference-type/suggestion'; const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', - // [MESSAGE_ID_SUGGESTION]: 'Replace the reference type ({{type}}) to an independent instance.', }; -/** - @param {*} node - @param {import('eslint').Rule.RuleContext} context - @returns - */ -function isReferenceType(node, context) { - if (!node) { - return false; - } - - // 原始类型:字面量(null, number, string, boolean) - if (node.type === 'Literal') { - // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) - return node.regex !== undefined; - } - - // 特殊处理:模板字符串(`hello`)属于原始类型 - if (node.type === 'TemplateLiteral') { - return false; - } - - // 变量标识符(递归检查其声明) - if (node.type === 'Identifier') { - const {variables} = context.sourceCode.getScope(node); - const variable = variables.find(v => v.name === node.name); - // Console.log('variables:', variables); - // console.log('variable:', variable); - // console.log('variable.defs[0].node:', variable.defs[0].node); - if (!variable || !variable.defs[0]?.node) { - return false; - } - - return isReferenceType(variable.defs[0].node, context); - } - - // Symbol(如 Symbol('name')) - if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { - const {variables} = context.sourceCode.getScope(node); - - // Console.log('variables 2:', variables); - if (!variables || variables.length === 0) { - // 未找到变量声明,可能是全局变量 - return false; - } - } - - // 其他情况:对象、数组、函数、new表达式、正则表达式等 - return true; -} - /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { - const isFill = node.callee.type === 'MemberExpression' + const isArrayDotFill = node.callee.type === 'MemberExpression' + && node.callee.object.callee?.name === 'Array' && node.callee.property.name === 'fill' && node.arguments.length > 0; - if (!isFill) { + // Console.log('isArrayDotFill:', isArrayDotFill); + + if (!isArrayDotFill) { return; } @@ -136,6 +87,56 @@ const create = context => ({ }, }); +/** + @param {*} node + @param {import('eslint').Rule.RuleContext} context + @returns + */ +function isReferenceType(node, context) { + if (!node) { + return false; + } + + // 原始类型:字面量(null, number, string, boolean) + if (node.type === 'Literal') { + // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + return node.regex !== undefined; + } + + // 特殊处理:模板字符串(`hello`)属于原始类型 + if (node.type === 'TemplateLiteral') { + return false; + } + + // 变量标识符(递归检查其声明) + if (node.type === 'Identifier') { + const {variables} = context.sourceCode.getScope(node); + const variable = variables.find(v => v.name === node.name); + // Console.log('variables:', variables); + // console.log('variable:', variable); + // console.log('variable.defs[0].node:', variable.defs[0].node); + if (!variable || !variable.defs[0]?.node) { + return false; + } + + return isReferenceType(variable.defs[0].node, context); + } + + // Symbol(如 Symbol('name')) + if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { + const {variables} = context.sourceCode.getScope(node); + + // Console.log('variables 2:', variables); + if (!variables || variables.length === 0) { + // 未找到变量声明,可能是全局变量 + return false; + } + } + + // 其他情况:对象、数组、函数、new表达式、正则表达式等 + return true; +} + /** @type {import('eslint').Rule.RuleModule} */ const config = { create, diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 8e51a738f9..2455fd5251 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -19,9 +19,9 @@ test.snapshot({ 'Array.from({ length: 3 }, () => { return new Map }); // ✓ Safe alternative', 'Array.from({ length: 3 }, () => { return new Map() }); // ✓ Safe alternative', - // 'Array(3).fill(0); // ✓ number (primitive) ', - // 'new Foo(3).fill({}); // ✓ Not Array ', - // 'Foo(3).fill({}); // ✓ Not Array ', + 'Array(3).fill(0); // ✓ number (primitive)', + 'new Foo(3).fill({}); // ✓ Not Array', + 'Foo(3).fill({}); // ✓ Not Array', ], invalid: [ 'new Array(3).fill({}); // ✗ Object ', @@ -38,7 +38,7 @@ test.snapshot({ 'new Array(3).fill(function () {}); // ✗ normal function', 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', - // 'Array(3).fill({}); // ✗ Object ', + 'Array(3).fill({}); // ✗ Object ', // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index c67b1cc576..cb1c27b5f8 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -184,6 +184,21 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ ` +## invalid(13): Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array(3).fill({}); // ✗ Object ␊ + | ^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + ` + ## invalid(10): new Array(3).fill(function () {}); // ✗ normal function > Input diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 481b0baea051baea40fef91c8c281f37d169a919..3bf8ddb0e8da10ff06165a5ffa8880505b8b2e3d 100644 GIT binary patch literal 1092 zcmV-K1iSk|RzV{tSwV-N$i0e#{Lx}Jt zOp;c9{~wD800000000B++0Ad%Mic<>1cZ=Q0*Ny!ddelX1iNtwUx^Y3kN}lJfE8bt zl8JY`7@V;+o=rf&1^5RzaX~`m&_AL_Zd@u=swysU09EP*3BiF|TY0^+_KRoM>&;pM z5uYM^=RJFVGjHt4FV2eR+qc6fFQ{;ZNAFCyY>jws!?4ULV00bkI45_FgJ#unJjPx?^O|=wt=Jg8RBy@qr=& zRH#Q*s7KGSpd~s{|42vO_Hv{$TRd!Z?mqmiI$&f zgH^L6!K5VkQArS;StNmBCK8Jz$TFNp42QK0>3FEy7D=Fjc!MB**F*FS+=F63ktAKI zCl(Slba)~zQ?}?jIi#N@g1f9~j604qo|-Mmr7TVz;mr4*G#kRB zF`oQDrS%1A{gX3?`plEhx2dTW-$gmI>$t=`ti@dLeWm0nkAz_satT4s^@K#BGrikR zphEnB5a0Gj>?cQ`fP?5o>C2%zE9s7yQ(#BW0VfG>KM>q|Fs^7+yn$KXnX? z=0KgT!@NGa3u*op+RG+razB`Y3<2L5n zuJefNL=IQ>(>dSkZ{+n?o>y*)-1YXW5?knssrO6dV}W5JH|FzI;`M;LjNr~_;W7#E zYYa}K^81AR-s}B}Wh&{lsZ`91UCe0b#r9b!V3hBf&}(Tcg>GZXI*a~ z*NbumEtV_Y@i?J!<=l;k|LeX*4K1m5#ni8wgTG5f8B5_m(B+Tzc#7|P&LY~04((?4 zJYONW-z3~-_dCC$z0QT46>qD4ev|dn+Nz)5U;Vs*K0~+kzc2l<^gj;c&T)JnW?-zv zT-)btY&!9L)bZSpJoh2bjjdJ1*F^32D%y{KeE#d>aoN~eYKau>Hbnaw(`NE#of3}= z?JkGqDBCjlYti4Gmdn*j<-m}SO1;%=(y+apST$=3F44dvHcgVo10lYjYHq(Ioc{wz KrO(3=9smG47#HUN literal 1061 zcmV+=1ls#SRzV47OJz4MDJh8p4K#rwr2$s7 z$%SU(9d8WI*c#6!L`g2RKY&{=l`3-Jhj8nq5>i$5QVyU>y;Q2;&>JAHch-LK%zC|9 zOH{vd!x!O$gGPf0vU2&v$jOmt8~tG9qtU4ffCYQHSn-A; z0#v9+)~QFoVnIuEqCQPW9eXlTxmY}Gv~LgYs5Y42^4$isLYFn;fN?Yvwq3CSoH~?K zW>XM50S&>3W13aC9a4Ed_csj_TowvS8X$b2ENpQKE^E+$vIb?MeUvbphSknZx(l59 z9ITop38o~$r%Hlo&k_j?Gm%&#L6+f5#Bg5AkdBACZHWXbh(8g;uX>1{fqPI4D3YWr z73G{3rA|c}rA`&KQ3OTCLw#4L;>al4z~!LC>B>NvmMBw7lv+T9pq$kblv}j9a9>d@ z{mxn1kjgph52W&oUZqFa;hV&fO98neK|a%0iQq148WWD=Or)wMIh4hzBbWt`%1|x9tp!NnxvaHXTXl`11=NZz9HD%pH*~+Je)Xc3|Elh^^RfD z9H_H(n5&~7BF)!Qa|qdDR>d|%<1NBnvhGnxuB8<1Z>9F<{c1;hoyNxU9#w-MY`EnFr6 zevH9sRDLg!-wVB8u}mdBHkFEbvx^yhd9i&K3fLq8%t80tf@*QuBtZiEO?S Date: Thu, 29 May 2025 11:31:41 +0800 Subject: [PATCH 15/63] test(no-array-fill-with-reference-type): add more valid cases --- test/no-array-fill-with-reference-type.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 2455fd5251..a57b8fdcad 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -22,6 +22,17 @@ test.snapshot({ 'Array(3).fill(0); // ✓ number (primitive)', 'new Foo(3).fill({}); // ✓ Not Array', 'Foo(3).fill({}); // ✓ Not Array', + + 'const map = new Map(); Array.from({ length: 3 }, () => map); // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable (map).', + + ` + // Due to the rule name it will not check other than \`Array.fill\`., + const map = new Map(); + const list = []; + for (let i = 0; i < 3; i++) { + list.push(map); + } + `, ], invalid: [ 'new Array(3).fill({}); // ✗ Object ', @@ -39,6 +50,5 @@ test.snapshot({ 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', 'Array(3).fill({}); // ✗ Object ', - // 'const map = new Map(); Array.from({ length: 3 }, () => map); // Array.from is also checked when filled with referenced variable (map)', ], }); From 7c7fa38ebb0820f0ea79e6a01becfc4fe7b89980 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 11:42:12 +0800 Subject: [PATCH 16/63] docs(no-array-fill-with-reference-type): remove comments --- rules/no-array-fill-with-reference-type.js | 39 ++++++++-------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 3e1f7b4969..3d8f3fcb62 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -8,6 +8,9 @@ const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', }; +const debugging = false; +const log = (...arguments_) => debugging && console.log(...arguments_); + /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { @@ -16,14 +19,14 @@ const create = context => ({ && node.callee.property.name === 'fill' && node.arguments.length > 0; - // Console.log('isArrayDotFill:', isArrayDotFill); + log('isArrayDotFill:', isArrayDotFill); if (!isArrayDotFill) { return; } const fillArgument = node.arguments[0]; - // Console.log('fillArgument:', fillArgument); + log('fillArgument:', fillArgument); if (!isReferenceType(fillArgument, context)) { return; @@ -53,7 +56,6 @@ const create = context => ({ } default: { - // 正则表达式字面量 if (fillArgument.type === 'Literal' && fillArgument.regex) { type = 'RegExp'; } else if (fillArgument.type === 'Identifier') { @@ -69,20 +71,6 @@ const create = context => ({ type, replacement: '🦄', }, - - /** @param {import('eslint').Rule.RuleFixer} fixer */ - // fix: fixer => fixer.replaceText(node, '\'🦄\''), - - /** @param {import('eslint').Rule.RuleFixer} fixer */ - // suggest: [ - // { - // messageId: MESSAGE_ID_SUGGESTION, - // data: { - // type, - // }, - // }, - // ], - }; }, }); @@ -97,24 +85,24 @@ function isReferenceType(node, context) { return false; } - // 原始类型:字面量(null, number, string, boolean) + // For null, number, string, boolean. if (node.type === 'Literal') { - // 排除正则表达式字面量(如 /pattern/,虽然属于 Literal,但实际是对象) + // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). return node.regex !== undefined; } - // 特殊处理:模板字符串(`hello`)属于原始类型 + // For template literals. if (node.type === 'TemplateLiteral') { return false; } - // 变量标识符(递归检查其声明) + // For variable identifiers (recursively check its declaration). if (node.type === 'Identifier') { const {variables} = context.sourceCode.getScope(node); const variable = variables.find(v => v.name === node.name); - // Console.log('variables:', variables); - // console.log('variable:', variable); - // console.log('variable.defs[0].node:', variable.defs[0].node); + log('variables:', variables); + log('variable:', variable); + log('variable.defs[0].node:', variable?.defs[0].node); if (!variable || !variable.defs[0]?.node) { return false; } @@ -126,7 +114,7 @@ function isReferenceType(node, context) { if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { const {variables} = context.sourceCode.getScope(node); - // Console.log('variables 2:', variables); + log('variables 2:', variables); if (!variables || variables.length === 0) { // 未找到变量声明,可能是全局变量 return false; @@ -143,6 +131,7 @@ const config = { meta: { type: 'problem', docs: { + // eslint-disable-next-line @stylistic/max-len description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', recommended: true, }, From d3a41791879cc2d4f3c8251386c9f483e9b2e72d Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 11:50:49 +0800 Subject: [PATCH 17/63] docs(no-array-fill-with-reference-type): gen code by npm run fix:eslint-docs using Node.js v22.16.0 --- .../no-array-fill-with-reference-type.md | 6 + readme.md | 265 +++++++++--------- 2 files changed, 139 insertions(+), 132 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 6ff80b94ec..ee1d82415f 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -1,3 +1,9 @@ +# Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances + +💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). + +🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). + diff --git a/readme.md b/readme.md index 7b9dd9c850..41e9c9ad34 100644 --- a/readme.md +++ b/readme.md @@ -54,138 +54,139 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name                                    | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | -| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | -| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | -| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | -| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | -| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | -| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | -| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | -| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | -| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | -| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | -| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | -| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | -| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | -| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | -| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | -| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | -| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | -| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | -| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | -| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | -| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | -| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | -| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | +| Name                                    | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | +| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | +| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | +| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | +| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances. | ✅ | 🔧 | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | +| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | +| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | +| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | +| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | +| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | +| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | +| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | +| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | +| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | +| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | +| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | +| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | +| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | +| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | +| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | +| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | +| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | From 681827d63703d9150ec86586864728e1a041773f Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 12:09:16 +0800 Subject: [PATCH 18/63] docs(no-array-fill-with-reference-type): brief the desc and recover readme.md to main generated by npm run fix:eslint-docs using Node.js v22.16.0 --- .../no-array-fill-with-reference-type.md | 2 +- readme.md | 266 +++++++++--------- rules/no-array-fill-with-reference-type.js | 7 +- 3 files changed, 135 insertions(+), 140 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index ee1d82415f..70a3c1b401 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -1,4 +1,4 @@ -# Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances +# Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). diff --git a/readme.md b/readme.md index 41e9c9ad34..5ce9943303 100644 --- a/readme.md +++ b/readme.md @@ -54,139 +54,139 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name                                    | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | -| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | -| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | -| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | -| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | -| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | -| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances. | ✅ | 🔧 | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | -| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | -| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | -| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | -| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | -| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | -| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | -| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | -| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | -| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | -| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | -| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | -| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | -| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | -| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | -| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | -| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | -| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | +| Name | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | +| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | +| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | +| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | +| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | | 💡 | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | +| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | +| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | +| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | +| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | +| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | +| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | +| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | +| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | +| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | +| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | +| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | +| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | +| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | +| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | +| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | +| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | +| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 3d8f3fcb62..457b429c04 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,8 +1,4 @@ // @ts-check -import {} from './ast/index.js'; -import {} from './fix/index.js'; -import {} from './utils/index.js'; - const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', @@ -131,8 +127,7 @@ const config = { meta: { type: 'problem', docs: { - // eslint-disable-next-line @stylistic/max-len - description: 'Disallows using `Array.fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances.', + description: 'Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, fixable: 'code', From a6ca7894c493bb59ccd06e3410518c3c53df7788 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 13:45:07 +0800 Subject: [PATCH 19/63] docs: no file configs/recommended.js --- docs/new-rule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/new-rule.md b/docs/new-rule.md index 28f30f3a17..bb82966e9a 100644 --- a/docs/new-rule.md +++ b/docs/new-rule.md @@ -18,7 +18,7 @@ Use the [`astexplorer` site](https://astexplorer.net) with the `espree` parser a - Open “rules/{RULE_ID}.js” and implement the rule logic. - Add the correct [`meta.type`](https://eslint.org/docs/developer-guide/working-with-rules#rule-basics) to the rule. - Open “docs/rules/{RULE_ID}.js” and write some documentation. -- Double check `configs/recommended.js` and `readme.md`, make sure the new rule is correctly added. +- Double check `readme.md`, make sure the new rule is correctly added. - Run `npm test` to ensure the tests pass. - Run `npm run integration` to run the rules against real projects to ensure your rule does not fail on real-world code. - Open a pull request with a title in exactly the format `` Add `rule-name` rule ``, for example, `` Add `no-unused-properties` rule ``. From 2091479f1e826846986bdf87204987cd491f7b64 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 13:46:17 +0800 Subject: [PATCH 20/63] docs(no-array-fill-with-reference-type): gen code by npm run fix:eslint-docs using Node.js v22.16.0 --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 5ce9943303..e2c9e5f292 100644 --- a/readme.md +++ b/readme.md @@ -54,7 +54,7 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name | Description | 💼 | 🔧 | 💡 | +| Name                                    | Description | 💼 | 🔧 | 💡 | | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | | [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | | [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | @@ -77,8 +77,8 @@ export default [ | [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | | [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | 💡 | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | 🔧 | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | | [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | | [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | From 90b768b4386d12e441149d74ff3009149722c039 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 14:07:53 +0800 Subject: [PATCH 21/63] feat(no-array-fill-with-reference-type): no fixable --- rules/no-array-fill-with-reference-type.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 457b429c04..bf702fa98d 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -65,7 +65,6 @@ const create = context => ({ messageId: MESSAGE_ID_ERROR, data: { type, - replacement: '🦄', }, }; }, @@ -96,9 +95,11 @@ function isReferenceType(node, context) { if (node.type === 'Identifier') { const {variables} = context.sourceCode.getScope(node); const variable = variables.find(v => v.name === node.name); + log('variables:', variables); log('variable:', variable); log('variable.defs[0].node:', variable?.defs[0].node); + if (!variable || !variable.defs[0]?.node) { return false; } @@ -106,18 +107,18 @@ function isReferenceType(node, context) { return isReferenceType(variable.defs[0].node, context); } - // Symbol(如 Symbol('name')) + // Symbol (such as `Symbol('name')`) if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { const {variables} = context.sourceCode.getScope(node); log('variables 2:', variables); if (!variables || variables.length === 0) { - // 未找到变量声明,可能是全局变量 + // Variable declaration not found; it might be a global variable. return false; } } - // 其他情况:对象、数组、函数、new表达式、正则表达式等 + // Other cases: objects, arrays, functions, new expressions, regular expressions, etc. return true; } @@ -130,8 +131,6 @@ const config = { description: 'Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, - fixable: 'code', - hasSuggestions: true, messages, }, }; From a0841ad2443f57cbf44f3bd277c4a88b1698d038 Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 14:08:14 +0800 Subject: [PATCH 22/63] docs(no-array-fill-with-reference-type): no fixable --- docs/rules/no-array-fill-with-reference-type.md | 2 -- readme.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 70a3c1b401..1593d360ad 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -2,8 +2,6 @@ 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). -🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). - diff --git a/readme.md b/readme.md index e2c9e5f292..1ad41714c2 100644 --- a/readme.md +++ b/readme.md @@ -77,7 +77,7 @@ export default [ | [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | | [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | 🔧 | 💡 | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | | | [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | | [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | From ab37dcb38e5a3189a51d96e98295ffd986d3c17a Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 15:06:36 +0800 Subject: [PATCH 23/63] feat(no-array-fill-with-reference-type): check Array.from().fill --- .../no-array-fill-with-reference-type.md | 94 ++++++++++++++++-- rules/no-array-fill-with-reference-type.js | 15 +-- test/no-array-fill-with-reference-type.js | 17 +++- .../no-array-fill-with-reference-type.js.md | 92 ++++++++--------- .../no-array-fill-with-reference-type.js.snap | Bin 1092 -> 1156 bytes 5 files changed, 149 insertions(+), 69 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 1593d360ad..ea9bcf2cd9 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -5,27 +5,99 @@ - +Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** (objects, arrays, functions, Maps, Sets, RegExp literals, etc.) to prevent unintended shared references across array elements. Encourages `Array.from()` or explicit iteration for creating independent instances. + +**Reason**: +`Array(len).fill(value)` fills all elements with the **same reference** if `value` is non-primitive (e.g., `fill([])`), leading to bugs when one element’s mutations affect others. + +**Key Features**: + +- Catches **all reference types**: Objects, Arrays, Functions, `new` expressions, RegExp literals, and variables referencing them. +- **Clear error messages**: Identifies the reference type (e.g., `Object`, `RegExp`, `variable (name)`). + +**Note**: Primitive types (`number`, `string`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) are always allowed. ## Examples ```js -// ❌ -const foo = 'unicorn'; +// ❌ Object +new Array(3).fill({}); +Array(3).fill({}); +Array.from({ length: 3 }).fill({}); + +// ✅ +Array.from({ length: 3 }, () => ({})); +``` + +```js +// ❌ Array +new Array(3).fill([]); +Array(3).fill([]); +Array.from({ length: 3 }).fill([]); + +// ✅ +Array.from({ length: 3 }, () => []); +``` + +```js +// ❌ Map +new Array(3).fill(new Map()); +Array(3).fill(new Map()); +Array.from({ length: 3 }).fill(new Map()); + +// ✅ +Array.from({ length: 3 }, () => new Map()); +``` + +```js +// ❌ Date +new Array(3).fill(new Date()); +Array(3).fill(new Date()); +Array.from({ length: 3 }).fill(new Date()); // ✅ -const foo = '🦄'; +Array.from({ length: 3 }, () => new Date()); +``` + +```js +// ❌ Class +class BarClass {}; +new Array(3).fill(new BarClass()); +Array(3).fill(new BarClass()); +Array.from({ length: 3 }).fill(new BarClass()); + +// ✅ +Array.from({ length: 3 }, () => new BarClass()); ``` ```js // ❌ -function foo() { - var replace = 'me'; - return replace; -} +new Array(3).fill(function () {}) +Array(3).fill(function () {}) +Array.from({ length: 3 }).fill(function () {}); + +// ✅ +Array.from({ length: 3 }, () => function () {}); +``` + +```js +// ❌ RegExp literal +new Array(3).fill(/pattern/); +Array(3).fill(/pattern/); +Array.from({ length: 3 }).fill(/pattern/); + +// ✅ +Array.from({ length: 3 }, () => /pattern/); +``` + +```js +const box = [] + +// ❌ RegExp literal +new Array(3).fill(box); +Array(3).fill(box); +Array.from({ length: 3 }).fill(box); // ✅ -function foo() { - return 'me'; -} +Array.from({ length: 3 }, () => []); ``` diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index bf702fa98d..6856af57e3 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,7 +1,7 @@ // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { - [MESSAGE_ID_ERROR]: 'Avoid using Array.fill() with reference types ({{type}}). Use Array.from() instead to ensure independent instances.', + [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference types ({{type}}). Use `Array.from({ ... }, () => { ... })` instead to ensure independent instances.', }; const debugging = false; @@ -10,14 +10,14 @@ const log = (...arguments_) => debugging && console.log(...arguments_); /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { - const isArrayDotFill = node.callee.type === 'MemberExpression' - && node.callee.object.callee?.name === 'Array' + const isArrayFill = node.callee.type === 'MemberExpression' + && ((node.callee.object.callee?.name === 'Array') || (context.sourceCode.getText(node.callee.object.callee) === 'Array.from')) && node.callee.property.name === 'fill' && node.arguments.length > 0; - log('isArrayDotFill:', isArrayDotFill); + log('isArrayFill:', isArrayFill); - if (!isArrayDotFill) { + if (!isArrayFill) { return; } @@ -60,10 +60,13 @@ const create = context => ({ } } + const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; + return { node, messageId: MESSAGE_ID_ERROR, data: { + actual, type, }, }; @@ -128,7 +131,7 @@ const config = { meta: { type: 'problem', docs: { - description: 'Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements.', + description: 'Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, messages, diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index a57b8fdcad..4ea81844ad 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -23,14 +23,15 @@ test.snapshot({ 'new Foo(3).fill({}); // ✓ Not Array', 'Foo(3).fill({}); // ✓ Not Array', - 'const map = new Map(); Array.from({ length: 3 }, () => map); // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable (map).', - + // Below are the cases though have the same reference problem but are not covered by the rule. + // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable. + // It cannot be exhaustively checked, we only check `Array.fill`. + 'const map = new Map(); Array.from({ length: 3 }, () => map);', ` - // Due to the rule name it will not check other than \`Array.fill\`., const map = new Map(); const list = []; for (let i = 0; i < 3; i++) { - list.push(map); + list.push(map); } `, ], @@ -46,9 +47,17 @@ test.snapshot({ 'class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance', 'new Array(3).fill(() => 1); // ✗ arrow function', 'new Array(3).fill(() => {}); // ✗ arrow function', + `new Array(3).fill(() => { + return {} + });`, 'new Array(3).fill(function () {}); // ✗ normal function', 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', 'Array(3).fill({}); // ✗ Object ', + // ✗ Object + 'Array.from({ length: 3 }).fill({});', + + 'new Array(3).fill(new Date())', + 'Array.from({ length: 3 }).fill(new Date())', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index cb1c27b5f8..0e1e50a694 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -16,7 +16,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(2): new Array(3).fill(new Map()); // ✗ Map @@ -31,7 +31,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Map()); // ✗ Map␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Map()). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(3): new Array(3).fill(new Set()); // ✗ Set @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Set()); // ✗ Set␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Set()). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp @@ -61,7 +61,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (RegExp). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String @@ -76,7 +76,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new String()). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class @@ -91,7 +91,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new Foo()). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (BarClass)). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance @@ -121,7 +121,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (new BarClass()). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function @@ -136,7 +136,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function @@ -151,120 +151,116 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(11): new Array(3).fill(function () {}); // ✗ normal function +## invalid(11): new Array(3).fill(() => { return {} }); > Input `␊ - 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + 1 | new Array(3).fill(() => {␊ + 2 | return {}␊ + 3 | });␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + > 1 | new Array(3).fill(() => {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | return {}␊ + | ^^^^^^^^^^^^␊ + > 3 | });␊ + | ^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(12): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) +## invalid(12): new Array(3).fill(function () {}); // ✗ normal function > Input `␊ - 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ ` > Error 1/1 `␊ - > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(13): Array(3).fill({}); // ✗ Object +## invalid(13): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) > Input `␊ - 1 | Array(3).fill({}); // ✗ Object ␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ ` > Error 1/1 `␊ - > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Object). Use Array.from() instead to ensure independent instances.␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(10): new Array(3).fill(function () {}); // ✗ normal function +## invalid(14): Array(3).fill({}); // ✗ Object > Input `␊ - 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + 1 | Array(3).fill({}); // ✗ Object ␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (Function). Use Array.from() instead to ensure independent instances.␊ + > 1 | Array(3).fill({}); // ✗ Object ␊ + | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(11): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) +## invalid(15): Array.from({ length: 3 }).fill({}); > Input `␊ - 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + 1 | Array.from({ length: 3 }).fill({});␊ ` > Error 1/1 `␊ - > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + > 1 | Array.from({ length: 3 }).fill({});␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(8): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) +## invalid(16): new Array(3).fill(new Date()) > Input `␊ - 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + 1 | new Array(3).fill(new Date())␊ ` > Error 1/1 `␊ - > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using Array.fill() with reference types (variable (map)). Use Array.from() instead to ensure independent instances.␊ + > 1 | new Array(3).fill(new Date())␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(1): const foo = "unicorn"; +## invalid(17): Array.from({ length: 3 }).fill(new Date()) > Input `␊ - 1 | const foo = "unicorn";␊ - ` - -> Output - - `␊ - 1 | const foo = '🦄';␊ + 1 | Array.from({ length: 3 }).fill(new Date())␊ ` > Error 1/1 `␊ - > 1 | const foo = "unicorn";␊ - | ^^^^^^^^^ Prefer \`🦄\` over \`unicorn\`.␊ - ␊ - --------------------------------------------------------------------------------␊ - Suggestion 1/1: Replace \`unicorn\` with \`🦄\`.␊ - 1 | const foo = '🦄';␊ + > 1 | Array.from({ length: 3 }).fill(new Date())␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference types (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 3bf8ddb0e8da10ff06165a5ffa8880505b8b2e3d..2314b2294bed2888581a54e97bb6e1dbf784919b 100644 GIT binary patch literal 1156 zcmV-~1bh2IRzV4MhYfQ=4p1 zn?7W2R}7;57LR)Fm$7oAcvyemK76m*U}4*_TF~_@)`9hY#2}ox4m+0E1WwzOQ`V#) zc3tX$5kxgB@Wi9xFSxU1>_Mecf!=j6Oqg%L;G?+?7V`upEf5Y+=5;v*i?ygrS&K5! zKT24WdX>TDTT7ff9BS2?#F>^jQ%W3v&kAu3GcsBsZW8DL0=lIIipN7YbcMJoqQ4Q* zJ3Ucq;1r}ITSW;^g{!XRTBRb+wMrHJRD?^$Lw9wRilMo*flrDnNH|Ka8Ob%R%8nZO5{bG zcwW-@5i(v#HAbNm_r0G$>3b3R{*yki=1G#%_GqyF35-_tOQ||z&O+0_Lby+O|59PE zH>bE!@^D0~;eCpDzZ&os&4C#7&J)P_6WPbdkSzdLY{#mKs1&Nx2a_t=Qo+ z!n+*us@I)lJ^PvC4a*$9MeLN0eS*Nh(1Irt;CV7mqjbN7+~4avw^*tZo0y-9^W)Ij zU$AOA%oDIhT$qP&{Y*7U*&=Ra{%ts?^mix8e?a7q{tSwV-N$i0e#{Lx}Jt zOp;c9{~wD800000000B++0Ad%Mic<>1cZ=Q0*Ny!ddelX1iNtwUx^Y3kN}lJfE8bt zl8JY`7@V;+o=rf&1^5RzaX~`m&_AL_Zd@u=swysU09EP*3BiF|TY0^+_KRoM>&;pM z5uYM^=RJFVGjHt4FV2eR+qc6fFQ{;ZNAFCyY>jws!?4ULV00bkI45_FgJ#unJjPx?^O|=wt=Jg8RBy@qr=& zRH#Q*s7KGSpd~s{|42vO_Hv{$TRd!Z?mqmiI$&f zgH^L6!K5VkQArS;StNmBCK8Jz$TFNp42QK0>3FEy7D=Fjc!MB**F*FS+=F63ktAKI zCl(Slba)~zQ?}?jIi#N@g1f9~j604qo|-Mmr7TVz;mr4*G#kRB zF`oQDrS%1A{gX3?`plEhx2dTW-$gmI>$t=`ti@dLeWm0nkAz_satT4s^@K#BGrikR zphEnB5a0Gj>?cQ`fP?5o>C2%zE9s7yQ(#BW0VfG>KM>q|Fs^7+yn$KXnX? z=0KgT!@NGa3u*op+RG+razB`Y3<2L5n zuJefNL=IQ>(>dSkZ{+n?o>y*)-1YXW5?knssrO6dV}W5JH|FzI;`M;LjNr~_;W7#E zYYa}K^81AR-s}B}Wh&{lsZ`91UCe0b#r9b!V3hBf&}(Tcg>GZXI*a~ z*NbumEtV_Y@i?J!<=l;k|LeX*4K1m5#ni8wgTG5f8B5_m(B+Tzc#7|P&LY~04((?4 zJYONW-z3~-_dCC$z0QT46>qD4ev|dn+Nz)5U;Vs*K0~+kzc2l<^gj;c&T)JnW?-zv zT-)btY&!9L)bZSpJoh2bjjdJ1*F^32D%y{KeE#d>aoN~eYKau>Hbnaw(`NE#of3}= z?JkGqDBCjlYti4Gmdn*j<-m}SO1;%=(y+apST$=3F44dvHcgVo10lYjYHq(Ioc{wz KrO(3=9smG47#HUN From 6b146290ab6d2587702734ce24e610f2515e85bc Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 15:08:46 +0800 Subject: [PATCH 24/63] docs(no-array-fill-with-reference-type): correct docs --- docs/rules/no-array-fill-with-reference-type.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index ea9bcf2cd9..62c4abb874 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -71,7 +71,7 @@ Array.from({ length: 3 }, () => new BarClass()); ``` ```js -// ❌ +// ❌ Function new Array(3).fill(function () {}) Array(3).fill(function () {}) Array.from({ length: 3 }).fill(function () {}); @@ -93,7 +93,7 @@ Array.from({ length: 3 }, () => /pattern/); ```js const box = [] -// ❌ RegExp literal +// ❌ Shared reference new Array(3).fill(box); Array(3).fill(box); Array.from({ length: 3 }).fill(box); From b6bf56cbcca701903a4b1a0573428967a64f794b Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 29 May 2025 15:09:20 +0800 Subject: [PATCH 25/63] docs(no-array-fill-with-reference-type): correct docs by npm run fix:eslint-docs --- docs/rules/no-array-fill-with-reference-type.md | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 62c4abb874..4019b9c120 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -1,4 +1,4 @@ -# Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements +# Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). diff --git a/readme.md b/readme.md index 1ad41714c2..73b83ae09e 100644 --- a/readme.md +++ b/readme.md @@ -77,7 +77,7 @@ export default [ | [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | | [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | | +| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | | | [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | | [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | From 928e51a46104e5f8773d481aa3c9fe4b9479ff23 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 30 May 2025 11:54:45 +0800 Subject: [PATCH 26/63] test: disable no-array-fill-with-reference-type because it is safe due to no mutation to `errors` --- test/catch-error-name.js | 3 +++ test/string-content.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/catch-error-name.js b/test/catch-error-name.js index fdd2fdcba2..a8b2e996c1 100644 --- a/test/catch-error-name.js +++ b/test/catch-error-name.js @@ -496,6 +496,9 @@ test({ obj.then(err => {}, error => {}); obj.then(err => {}, error => {}); `, + + // It's safe due to no mutation to `errors` + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 4}).fill(generateError('err', 'error')), }, diff --git a/test/string-content.js b/test/string-content.js index d36a06da66..e505964660 100644 --- a/test/string-content.js +++ b/test/string-content.js @@ -223,6 +223,9 @@ test({ code: 'const foo = `no${foo}no${foo}no`', output: 'const foo = `yes${foo}yes${foo}yes`', options: [{patterns: noToYesPattern}], + + // It's safe due to no mutation to `errors` + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 3}).fill(createError('no', 'yes')[0]), }, // Escape From 36b04e32c6faf16227f1f738e326c5570c5061e7 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 30 May 2025 13:36:16 +0800 Subject: [PATCH 27/63] feat: hide unknown type in error message --- rules/no-array-fill-with-reference-type.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 6856af57e3..c6a723ec74 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,7 +1,7 @@ // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { - [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference types ({{type}}). Use `Array.from({ ... }, () => { ... })` instead to ensure independent instances.', + [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { ... })` instead to ensure independent instances.', }; const debugging = false; @@ -28,7 +28,7 @@ const create = context => ({ return; } - let type = 'unknown'; + let type = ''; switch (fillArgument.type) { case 'ObjectExpression': { type = 'Object'; @@ -67,7 +67,7 @@ const create = context => ({ messageId: MESSAGE_ID_ERROR, data: { actual, - type, + type: type ? ` (${type})` : '', }, }; }, From 4f4cf654b219f1e272d131ca9d053ff49d9e2249 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 30 May 2025 13:41:46 +0800 Subject: [PATCH 28/63] test: hide unknown type in error message --- .../no-array-fill-with-reference-type.js.md | 34 +++++++++--------- .../no-array-fill-with-reference-type.js.snap | Bin 1156 -> 1155 bytes 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 0e1e50a694..1665b27ab5 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -16,7 +16,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(2): new Array(3).fill(new Map()); // ✗ Map @@ -31,7 +31,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Map()); // ✗ Map␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(3): new Array(3).fill(new Set()); // ✗ Set @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Set()); // ✗ Set␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp @@ -61,7 +61,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String @@ -76,7 +76,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class @@ -91,7 +91,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance @@ -121,7 +121,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function @@ -136,7 +136,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function @@ -151,7 +151,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(11): new Array(3).fill(() => { return {} }); @@ -172,7 +172,7 @@ Generated by [AVA](https://avajs.dev). > 2 | return {}␊ | ^^^^^^^^^^^^␊ > 3 | });␊ - | ^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(12): new Array(3).fill(function () {}); // ✗ normal function @@ -187,7 +187,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(13): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) @@ -202,7 +202,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(14): Array(3).fill({}); // ✗ Object @@ -217,7 +217,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(15): Array.from({ length: 3 }).fill({}); @@ -232,7 +232,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference types (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(16): new Array(3).fill(new Date()) @@ -247,7 +247,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Date())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference types (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(17): Array.from({ length: 3 }).fill(new Date()) @@ -262,5 +262,5 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference types (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 2314b2294bed2888581a54e97bb6e1dbf784919b..3c35296932ac9c52633ae2e1375788fc30f254f7 100644 GIT binary patch literal 1155 zcmV-}1bq8JRzV8hdgR_E!|D1atckkb+1-E0XVj~yR< zEZrc0A0LYd00000000Bk*-vlOMic<>Y!S3sdZ4Ewae0>#o0i>dHY6oc76K#`q!iJJ zmRw3EyR#b?XKamU6Hu}jzClmDa4BD@7bI>ufP_?4J+xINR8?N@*nW7%f3nGj__p@$ zd$xb?jc3Qdwl{32`PlpU1r?UC>61x|Z4=vS88veb7~O$I&dF1wZdTfsZ5z8ia~`Ty z*nj>D+}rqxHihLe;(D8o@SeSBwTK`OZ=4$Yc+B5Qr^h}kO_u>`u&0X^Y$zf?nc8H7 z+Vl={yJ8UaZ9M8nug1!a;$i)Ld+?)bgT-yfYC+etSO?bo5rc5%I_y|t6F6;CPFa(J zczeUViY=Y+xrQWyk`*aKk1`to+LSG59I3SA1&%P5_Q&`gQkChaD(vvmBMas zUU8q~;Ye7c`w;2g9q1O#ffV%27ZLO4vWpKPTi~tO4ikTyaEol%6rz(EX&L+=%i!z0 zW#I3TUx`ndg5SuL$*Sm}s#q&h6^WEdtuV2&NM=xxOcW}TLdg$OGeZm;vGW>b(JaWK zxvG311o>)FX%Nnx9cXu1Q&)sK0Y4CEd$j1yL#rlawNWh06*1Fx}zMaLgj|)9Nzy)xe+_9*x{3* zyBzAOSDR!t`l|UvY$ol@AQ3JEY(p>$&ZEke#q=E zQ#Bpt3D_boEI_zwrkbB@5jP_LKAcYayOZLNkobK$2`iQ>E`k#(?I)1^`Ec@eXi2q` zF8#!7hou<#$fl(`}?WJ;T| zj@X=oI`m?j-2jU!$b!td%}NJpblw Vn1WV^(mx~i`ycz;1G#`6008EIJZ%5~ literal 1156 zcmV-~1bh2IRzV4MhYfQ=4p1 zn?7W2R}7;57LR)Fm$7oAcvyemK76m*U}4*_TF~_@)`9hY#2}ox4m+0E1WwzOQ`V#) zc3tX$5kxgB@Wi9xFSxU1>_Mecf!=j6Oqg%L;G?+?7V`upEf5Y+=5;v*i?ygrS&K5! zKT24WdX>TDTT7ff9BS2?#F>^jQ%W3v&kAu3GcsBsZW8DL0=lIIipN7YbcMJoqQ4Q* zJ3Ucq;1r}ITSW;^g{!XRTBRb+wMrHJRD?^$Lw9wRilMo*flrDnNH|Ka8Ob%R%8nZO5{bG zcwW-@5i(v#HAbNm_r0G$>3b3R{*yki=1G#%_GqyF35-_tOQ||z&O+0_Lby+O|59PE zH>bE!@^D0~;eCpDzZ&os&4C#7&J)P_6WPbdkSzdLY{#mKs1&Nx2a_t=Qo+ z!n+*us@I)lJ^PvC4a*$9MeLN0eS*Nh(1Irt;CV7mqjbN7+~4avw^*tZo0y-9^W)Ij zU$AOA%oDIhT$qP&{Y*7U*&=Ra{%ts?^mix8e?a7q Date: Fri, 30 May 2025 13:42:39 +0800 Subject: [PATCH 29/63] test: add a case of hiding unknown type in error message --- test/no-array-fill-with-reference-type.js | 2 ++ .../no-array-fill-with-reference-type.js.md | 15 +++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 1155 -> 1210 bytes 3 files changed, 17 insertions(+) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 4ea81844ad..f766669b89 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -59,5 +59,7 @@ test.snapshot({ 'new Array(3).fill(new Date())', 'Array.from({ length: 3 }).fill(new Date())', + + 'Array.from({length: 3}).fill(createError(\'no\', \'yes\')[0])', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 1665b27ab5..cec313e935 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -264,3 +264,18 @@ Generated by [AVA](https://avajs.dev). > 1 | Array.from({ length: 3 }).fill(new Date())␊ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` + +## invalid(18): Array.from({length: 3}).fill(createError('no', 'yes')[0]) + +> Input + + `␊ + 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 3c35296932ac9c52633ae2e1375788fc30f254f7..402fbbb6967a1bcbd154c1aa5a86e00d03ab5610 100644 GIT binary patch literal 1210 zcmV;r1V#HnRzVuPzebk4uFs;b1O$|-A5 z5JxTrqaV~P!vl{7AK=cuaSY{h8M;@&Fk!V0gO}zGSj-cYG(k8(nb+YIEY_qhWlhRN z?XirI-dg9};ZUtqrOkr0nOEBQXEupzm?6<7apOLBkrWKzm38{lhEz^}e;}??Jy$~5bHM6{o~YCvDRoWXSAtutZIoKARw>e7 z;ib6R7E)VJZnHDtQCEa-P%v&6UPq3FLUP+>Oq32gS~vD@W3ml-Q!+1VnKv9qX?({f zo);&+hltk_iBag-u=f%ud0$4ne<#nXS(0R=9m>_uKUvfdCF+v73=RJa!fnEP-xQ9! zD~fTFmqTHV?jxl8@jy3k4y2%Geg`qXDZ6+K+4|m!W1RR0gj;0SrV!rDM9bhaSq9g$ zmVtjpz9qV3>VHP2j8{b)RmFCms)(hGYXymwMY4#Bq?D^jawQ+8W=5DcBKI}PqFI$i zb3^$+=;y13r9n7%4x!ay4PiMfUK*RIG;V4i2Vr1jfWxbnY|oMZZ~A9JwhU=cg4~uH zgUHi)tXJm}7^B+^X^x*D$6G0m@!f%R$bS*!?`e>!DN>*57lShRfm>DY70HC0iVkOR z+=Z^WGO}M0U>;6jc6K(1TLh@}PIb){5P5_A^J@l{tK$*a`jm0C|6)^^PULD`cET$^I&0f3EM_e5uZBNj??k`vJ4R zP1SIiCt#nrunNJhnQDEqPu!6FVX&O^Pshc-LgM%3A}n97s0dD|v@aq1w}Qpj*pg}& zUHXOB2Qw z))srqP=jt{2;v?$kjHybkK|A)ia!y>FNh)~TE@v!&EiKk|93j?20Hq!s=Gu`!&J8hdgR_E!|D1atckkb+1-E0XVj~yR< zEZrc0A0LYd00000000Bk*-vlOMic<>Y!S3sdZ4Ewae0>#o0i>dHY6oc76K#`q!iJJ zmRw3EyR#b?XKamU6Hu}jzClmDa4BD@7bI>ufP_?4J+xINR8?N@*nW7%f3nGj__p@$ zd$xb?jc3Qdwl{32`PlpU1r?UC>61x|Z4=vS88veb7~O$I&dF1wZdTfsZ5z8ia~`Ty z*nj>D+}rqxHihLe;(D8o@SeSBwTK`OZ=4$Yc+B5Qr^h}kO_u>`u&0X^Y$zf?nc8H7 z+Vl={yJ8UaZ9M8nug1!a;$i)Ld+?)bgT-yfYC+etSO?bo5rc5%I_y|t6F6;CPFa(J zczeUViY=Y+xrQWyk`*aKk1`to+LSG59I3SA1&%P5_Q&`gQkChaD(vvmBMas zUU8q~;Ye7c`w;2g9q1O#ffV%27ZLO4vWpKPTi~tO4ikTyaEol%6rz(EX&L+=%i!z0 zW#I3TUx`ndg5SuL$*Sm}s#q&h6^WEdtuV2&NM=xxOcW}TLdg$OGeZm;vGW>b(JaWK zxvG311o>)FX%Nnx9cXu1Q&)sK0Y4CEd$j1yL#rlawNWh06*1Fx}zMaLgj|)9Nzy)xe+_9*x{3* zyBzAOSDR!t`l|UvY$ol@AQ3JEY(p>$&ZEke#q=E zQ#Bpt3D_boEI_zwrkbB@5jP_LKAcYayOZLNkobK$2`iQ>E`k#(?I)1^`Ec@eXi2q` zF8#!7hou<#$fl(`}?WJ;T| zj@X=oI`m?j-2jU!$b!td%}NJpblw Vn1WV^(mx~i`ycz;1G#`6008EIJZ%5~ From 2a7ffee8b91b88536aef0b5f67a386f005af1060 Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 4 Jun 2025 10:23:52 +0800 Subject: [PATCH 30/63] feat: report precisely on node.arguments[0] only. Co-authored-by: fisker Cheung --- rules/no-array-fill-with-reference-type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index c6a723ec74..fcd67cdd83 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -63,7 +63,7 @@ const create = context => ({ const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; return { - node, + node: node.arguments[0], messageId: MESSAGE_ID_ERROR, data: { actual, From d5f239821666f05a7eebefa3a146e296267da28a Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 4 Jun 2025 10:27:58 +0800 Subject: [PATCH 31/63] feat(no-array-fill-with-reference-type): report precisely on node.arguments[0] only --- rules/no-array-fill-with-reference-type.js | 2 +- .../no-array-fill-with-reference-type.js.md | 38 +++++++++--------- .../no-array-fill-with-reference-type.js.snap | Bin 1210 -> 1218 bytes 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index c6a723ec74..a3676a3db1 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -63,7 +63,7 @@ const create = context => ({ const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; return { - node, + node: fillArgument, messageId: MESSAGE_ID_ERROR, data: { actual, diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index cec313e935..1d504ce45d 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -16,7 +16,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(2): new Array(3).fill(new Map()); // ✗ Map @@ -31,7 +31,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Map()); // ✗ Map␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(3): new Array(3).fill(new Set()); // ✗ Set @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Set()); // ✗ Set␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp @@ -61,7 +61,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String @@ -76,7 +76,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class @@ -91,7 +91,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance @@ -121,7 +121,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function @@ -136,7 +136,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function @@ -151,7 +151,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(11): new Array(3).fill(() => { return {} }); @@ -168,11 +168,11 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => {␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^␊ + | ^^^^^^^␊ > 2 | return {}␊ | ^^^^^^^^^^^^␊ > 3 | });␊ - | ^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(12): new Array(3).fill(function () {}); // ✗ normal function @@ -187,7 +187,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(13): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) @@ -202,7 +202,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(14): Array(3).fill({}); // ✗ Object @@ -217,7 +217,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(15): Array.from({ length: 3 }).fill({}); @@ -232,7 +232,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(16): new Array(3).fill(new Date()) @@ -247,7 +247,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Date())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(17): Array.from({ length: 3 }).fill(new Date()) @@ -262,7 +262,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` ## invalid(18): Array.from({length: 3}).fill(createError('no', 'yes')[0]) @@ -277,5 +277,5 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 402fbbb6967a1bcbd154c1aa5a86e00d03ab5610..cb087e5d918caad8fb11ffdc7a05a94baf2b0a90 100644 GIT binary patch literal 1218 zcmV;z1U>sfRzVQK@(4L8P~(e$k)IEzR~PuIm;> zIJWT2lOKx+00000000Bk+1+p3R1^U41T;;}9;Uqj;_19>vA2;lO}lQbnyuSfKBO{@ zYOrcz^ftLkJ=|;S`lemg=7m3j7hZT_e-bZ9ybXy-NC@!&2x&q>PJC^j`d)uDC8d6= zot$I)caD8?`dxR+cG_QhU%#Nj5;lE4ZLwWqTOFfeE&!u@u*^BxH=1UxYuUDOFfbRP zUWcE){RSRvJ)>=5d5pN;wj;c+UUWJ{kjHo5ES)d;Tlrk+QhBxl(11f-tkH%d0#v9? zwx~@%WNu#sQGba?edEVcrBytvzwZ!|+ta78yz5vU=zA9H!R9dFD4MwmdzRP+PP>#- z)}|o#T?)o1rdfkW9u2?1ogL!UqpJXfC42Y;vgx=}Dxk3aF5wp0vMEI8GSMpd zOjg0oyj9@ukspb#mPX%^DU(IfLq)Msq$m<8lUQM5WsS_C8o5%aMhYcAM#+rv(1@MZ zBx`0#*32#C+hCNh5mg4^+}VR}pS6YMuw-Sdp~|?eeHTQ55djXbTCKfC{J-j71o<*# zyaozWt_Fcm=at@=PEm|c7qS>XMvQkd7?VSRY{!3)<8N7xnJF?L&xmCB!?vNG5Xpp` ziauv>Fo1!%I5uAeUUaj0##b7bMU_sf3#Lw zvD1nUpAFpA5LZ28lC|t-jyEfF_ztmCy7dv_eqYO-NPrsZNE)Sj1*yN*cWtp$S<_2f4)X-;5EqspoRz7TCOgE9#6JyJlK$=__!kKLpWVN|<{a*I+So8j~G3$^14KpV# zWJ;T|p4eW1CJbVCAjxqHaa@aYq=!;T{DCBXMiLp(ay5-c#Sd)$?{Kb$IQjwAeIlq~ zDjtkY#Bw=x6cq$ffxJQ>Kcr8aWSs1m*s*>X2H{U-V&9n0?vGTDJIG@uUz?=kY?RL< zoxgLoOCG8sZaKQ=l=z}`=FKB~;a!n8rOhc3bQr;?GN*bSs{7Qdnop)bS7@pSy~j?V g#C-?hPL&n7#ggQ(PE7O1rJscMzvz#=gk2y20C|^GW&i*H literal 1210 zcmV;r1V#HnRzVuPzebk4uFs;b1O$|-A5 z5JxTrqaV~P!vl{7AK=cuaSY{h8M;@&Fk!V0gO}zGSj-cYG(k8(nb+YIEY_qhWlhRN z?XirI-dg9};ZUtqrOkr0nOEBQXEupzm?6<7apOLBkrWKzm38{lhEz^}e;}??Jy$~5bHM6{o~YCvDRoWXSAtutZIoKARw>e7 z;ib6R7E)VJZnHDtQCEa-P%v&6UPq3FLUP+>Oq32gS~vD@W3ml-Q!+1VnKv9qX?({f zo);&+hltk_iBag-u=f%ud0$4ne<#nXS(0R=9m>_uKUvfdCF+v73=RJa!fnEP-xQ9! zD~fTFmqTHV?jxl8@jy3k4y2%Geg`qXDZ6+K+4|m!W1RR0gj;0SrV!rDM9bhaSq9g$ zmVtjpz9qV3>VHP2j8{b)RmFCms)(hGYXymwMY4#Bq?D^jawQ+8W=5DcBKI}PqFI$i zb3^$+=;y13r9n7%4x!ay4PiMfUK*RIG;V4i2Vr1jfWxbnY|oMZZ~A9JwhU=cg4~uH zgUHi)tXJm}7^B+^X^x*D$6G0m@!f%R$bS*!?`e>!DN>*57lShRfm>DY70HC0iVkOR z+=Z^WGO}M0U>;6jc6K(1TLh@}PIb){5P5_A^J@l{tK$*a`jm0C|6)^^PULD`cET$^I&0f3EM_e5uZBNj??k`vJ4R zP1SIiCt#nrunNJhnQDEqPu!6FVX&O^Pshc-LgM%3A}n97s0dD|v@aq1w}Qpj*pg}& zUHXOB2Qw z))srqP=jt{2;v?$kjHybkK|A)ia!y>FNh)~TE@v!&EiKk|93j?20Hq!s=Gu`!&J Date: Wed, 4 Jun 2025 10:44:19 +0800 Subject: [PATCH 32/63] test(no-array-fill-with-reference-type): add more case to improve coverage --- test/no-array-fill-with-reference-type.js | 8 + .../no-array-fill-with-reference-type.js.md | 321 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 1218 -> 1541 bytes 3 files changed, 329 insertions(+) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index f766669b89..75433d617b 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -10,6 +10,11 @@ test.snapshot({ 'new Array(3).fill(null); // ✓ null (primitive) ', 'new Array(3).fill(undefined); // ✓ undefined(primitive) ', 'new Array(3).fill(\'foo\'); // ✓ string (primitive) ', + 'new Array(3).fill(``); // ✓ TemplateLiteral (primitive) ', + // eslint-disable-next-line no-template-curly-in-string + 'new Array(3).fill(`${10}`); // ✓ TemplateLiteral (primitive)', + // eslint-disable-next-line no-template-curly-in-string + 'const foo = "foo"; new Array(3).fill(`Hi ${foo}`); // ✓ TemplateLiteral (primitive)', 'new Array(3).fill(false); // ✓ boolean (primitive) ', 'new Array(3).fill(Symbol(\'foo\')); // ✓ Symbol(primitive) ', @@ -36,6 +41,9 @@ test.snapshot({ `, ], invalid: [ + 'new Array(3).fill([]);', // ✗ Array + 'new Array(3).fill(Array());', // ✗ Array + 'new Array(3).fill(new Array());', // ✗ Array 'new Array(3).fill({}); // ✗ Object ', 'new Array(3).fill(new Map()); // ✗ Map', 'new Array(3).fill(new Set()); // ✗ Set', diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 1d504ce45d..10d5fd539e 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -4,6 +4,327 @@ The actual snapshot is saved in `no-array-fill-with-reference-type.js.snap`. Generated by [AVA](https://avajs.dev). +## invalid(1): new Array(3).fill([]); + +> Input + + `␊ + 1 | new Array(3).fill([]);␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill([]);␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(2): new Array(3).fill(Array()); + +> Input + + `␊ + 1 | new Array(3).fill(Array());␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(Array());␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(3): new Array(3).fill(new Array()); + +> Input + + `␊ + 1 | new Array(3).fill(new Array());␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Array());␊ + | ^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Array()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(4): new Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | new Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill({}); // ✗ Object ␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(5): new Array(3).fill(new Map()); // ✗ Map + +> Input + + `␊ + 1 | new Array(3).fill(new Map()); // ✗ Map␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Map()); // ✗ Map␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(6): new Array(3).fill(new Set()); // ✗ Set + +> Input + + `␊ + 1 | new Array(3).fill(new Set()); // ✗ Set␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Set()); // ✗ Set␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(7): new Array(3).fill(/pattern/); // ✗ RegExp + +> Input + + `␊ + 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(8): new Array(3).fill(new String('fff')); // ✗ new String + +> Input + + `␊ + 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ + | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(9): new Array(3).fill(new Foo('fff')); // ✗ new Class + +> Input + + `␊ + 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(10): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(11): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance + +> Input + + `␊ + 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + ` + +> Error 1/1 + + `␊ + > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(12): new Array(3).fill(() => 1); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(13): new Array(3).fill(() => {}); // ✗ arrow function + +> Input + + `␊ + 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(14): new Array(3).fill(() => { return {} }); + +> Input + + `␊ + 1 | new Array(3).fill(() => {␊ + 2 | return {}␊ + 3 | });␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(() => {␊ + | ^^^^^^^␊ + > 2 | return {}␊ + | ^^^^^^^^^^^^␊ + > 3 | });␊ + | ^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(15): new Array(3).fill(function () {}); // ✗ normal function + +> Input + + `␊ + 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(16): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) + +> Input + + `␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(17): Array(3).fill({}); // ✗ Object + +> Input + + `␊ + 1 | Array(3).fill({}); // ✗ Object ␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array(3).fill({}); // ✗ Object ␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(18): Array.from({ length: 3 }).fill({}); + +> Input + + `␊ + 1 | Array.from({ length: 3 }).fill({});␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from({ length: 3 }).fill({});␊ + | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(19): new Array(3).fill(new Date()) + +> Input + + `␊ + 1 | new Array(3).fill(new Date())␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new Date())␊ + | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(20): Array.from({ length: 3 }).fill(new Date()) + +> Input + + `␊ + 1 | Array.from({ length: 3 }).fill(new Date())␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from({ length: 3 }).fill(new Date())␊ + | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(21): Array.from({length: 3}).fill(createError('no', 'yes')[0]) + +> Input + + `␊ + 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + ## invalid(1): new Array(3).fill({}); // ✗ Object > Input diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index cb087e5d918caad8fb11ffdc7a05a94baf2b0a90..b542e854d06243f2e550e8a93ca70f394c184eb4 100644 GIT binary patch literal 1541 zcmV+g2KxCyRzV_` z8nl`=dYjy|2G@@4+jdo(7yb!&;D!Awh<{*0LV~9uF$sha4}g#+B;+L5_Nnjnk0dw= zvfpC+o@1ZSIrmt^j!`-{S3$~30aM{jDz0nxR3QB~%_pog$*S>&i#QA!O> z*NgWbC<~fxkfyzBGW)Z~^*Ui>W9o&8a}&;yJ3H}m?u|Tv3MZ1$d8(6bs?*y>bDwp` zKk<)0^Yui&8fE|h-~@ul!-ueZU}|;Pw>4u2w%S8GoQ;j^$KA-Q=LI%BzZ5nz2(XG#ZV9ue!WTL1^m;+DdqloidMV!n;90aWnT4 z!Z?u&FS?kHVr)M8sm0Dyq+5pg_~9VzaB15{9_+z6@X5%uTts!ir9s(8n#gzvhPo&HqKG;9WYqzQ}Qw#!6& zlReV(h=1trC7shj;2$I4clib^nJ+&O>`;jQ0z&_)yYU*BQ&|#7j{f%Oj>lBf;%zrA zoK9Hs)_)ZtpXnm+r|tg~0e!-2xv!T0c(nW7e`3_DoCSBOQ)7qi&O-%Sz6b!bYCMy^@S%F+xmB|VuyO1%I704x7 znXI5Mtm(@N-t{ZDGF5@Vn+$hI28^Am;3K~*EE5%EqJkJXvluQi%QOY!@Hf^HQk7+z zf`QEDL)H|CJ4BhL;D4bh5cileO~HWI)gfyNDw(Dr(-Z_X1+$r^U}Q7}bD5@K)Zko1 rnygGyFicH>r+>;c1!Jfw2uP+fO+f_dczykm&=mX&^rzQj3q=3`54G&^ literal 1218 zcmV;z1U>sfRzVQK@(4L8P~(e$k)IEzR~PuIm;> zIJWT2lOKx+00000000Bk+1+p3R1^U41T;;}9;Uqj;_19>vA2;lO}lQbnyuSfKBO{@ zYOrcz^ftLkJ=|;S`lemg=7m3j7hZT_e-bZ9ybXy-NC@!&2x&q>PJC^j`d)uDC8d6= zot$I)caD8?`dxR+cG_QhU%#Nj5;lE4ZLwWqTOFfeE&!u@u*^BxH=1UxYuUDOFfbRP zUWcE){RSRvJ)>=5d5pN;wj;c+UUWJ{kjHo5ES)d;Tlrk+QhBxl(11f-tkH%d0#v9? zwx~@%WNu#sQGba?edEVcrBytvzwZ!|+ta78yz5vU=zA9H!R9dFD4MwmdzRP+PP>#- z)}|o#T?)o1rdfkW9u2?1ogL!UqpJXfC42Y;vgx=}Dxk3aF5wp0vMEI8GSMpd zOjg0oyj9@ukspb#mPX%^DU(IfLq)Msq$m<8lUQM5WsS_C8o5%aMhYcAM#+rv(1@MZ zBx`0#*32#C+hCNh5mg4^+}VR}pS6YMuw-Sdp~|?eeHTQ55djXbTCKfC{J-j71o<*# zyaozWt_Fcm=at@=PEm|c7qS>XMvQkd7?VSRY{!3)<8N7xnJF?L&xmCB!?vNG5Xpp` ziauv>Fo1!%I5uAeUUaj0##b7bMU_sf3#Lw zvD1nUpAFpA5LZ28lC|t-jyEfF_ztmCy7dv_eqYO-NPrsZNE)Sj1*yN*cWtp$S<_2f4)X-;5EqspoRz7TCOgE9#6JyJlK$=__!kKLpWVN|<{a*I+So8j~G3$^14KpV# zWJ;T|p4eW1CJbVCAjxqHaa@aYq=!;T{DCBXMiLp(ay5-c#Sd)$?{Kb$IQjwAeIlq~ zDjtkY#Bw=x6cq$ffxJQ>Kcr8aWSs1m*s*>X2H{U-V&9n0?vGTDJIG@uUz?=kY?RL< zoxgLoOCG8sZaKQ=l=z}`=FKB~;a!n8rOhc3bQr;?GN*bSs{7Qdnop)bS7@pSy~j?V g#C-?hPL&n7#ggQ(PE7O1rJscMzvz#=gk2y20C|^GW&i*H From 9ab3fb07b030251152748920b244814a0508c496 Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 4 Jun 2025 11:32:05 +0800 Subject: [PATCH 33/63] test(no-array-fill-with-reference-type): fix ci failed. code gen by -u --- .../no-array-fill-with-reference-type.js.md | 276 ------------------ .../no-array-fill-with-reference-type.js.snap | Bin 1541 -> 1344 bytes 2 files changed, 276 deletions(-) diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 10d5fd539e..6fa96ec4a8 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -324,279 +324,3 @@ Generated by [AVA](https://avajs.dev). > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` - -## invalid(1): new Array(3).fill({}); // ✗ Object - -> Input - - `␊ - 1 | new Array(3).fill({}); // ✗ Object ␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill({}); // ✗ Object ␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(2): new Array(3).fill(new Map()); // ✗ Map - -> Input - - `␊ - 1 | new Array(3).fill(new Map()); // ✗ Map␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(new Map()); // ✗ Map␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(3): new Array(3).fill(new Set()); // ✗ Set - -> Input - - `␊ - 1 | new Array(3).fill(new Set()); // ✗ Set␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(new Set()); // ✗ Set␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(4): new Array(3).fill(/pattern/); // ✗ RegExp - -> Input - - `␊ - 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(5): new Array(3).fill(new String('fff')); // ✗ new String - -> Input - - `␊ - 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(6): new Array(3).fill(new Foo('fff')); // ✗ new Class - -> Input - - `␊ - 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(7): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class - -> Input - - `␊ - 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - ` - -> Error 1/1 - - `␊ - > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(8): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance - -> Input - - `␊ - 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - ` - -> Error 1/1 - - `␊ - > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(9): new Array(3).fill(() => 1); // ✗ arrow function - -> Input - - `␊ - 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(10): new Array(3).fill(() => {}); // ✗ arrow function - -> Input - - `␊ - 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(11): new Array(3).fill(() => { return {} }); - -> Input - - `␊ - 1 | new Array(3).fill(() => {␊ - 2 | return {}␊ - 3 | });␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(() => {␊ - | ^^^^^^^␊ - > 2 | return {}␊ - | ^^^^^^^^^^^^␊ - > 3 | });␊ - | ^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(12): new Array(3).fill(function () {}); // ✗ normal function - -> Input - - `␊ - 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(13): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) - -> Input - - `␊ - 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - ` - -> Error 1/1 - - `␊ - > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(14): Array(3).fill({}); // ✗ Object - -> Input - - `␊ - 1 | Array(3).fill({}); // ✗ Object ␊ - ` - -> Error 1/1 - - `␊ - > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(15): Array.from({ length: 3 }).fill({}); - -> Input - - `␊ - 1 | Array.from({ length: 3 }).fill({});␊ - ` - -> Error 1/1 - - `␊ - > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(16): new Array(3).fill(new Date()) - -> Input - - `␊ - 1 | new Array(3).fill(new Date())␊ - ` - -> Error 1/1 - - `␊ - > 1 | new Array(3).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(17): Array.from({ length: 3 }).fill(new Date()) - -> Input - - `␊ - 1 | Array.from({ length: 3 }).fill(new Date())␊ - ` - -> Error 1/1 - - `␊ - > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` - -## invalid(18): Array.from({length: 3}).fill(createError('no', 'yes')[0]) - -> Input - - `␊ - 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - ` - -> Error 1/1 - - `␊ - > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ - ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index b542e854d06243f2e550e8a93ca70f394c184eb4..14aed1a1cb3f841cf53931f37301f5939b009bc3 100644 GIT binary patch literal 1344 zcmV-G1;6@1RzVW0VtNJI60?%TN%ybSvUOXFhE%3e z4Yis!dYYW12KU&qPuf*&Zuky}8*bQFL41J;2??%-#3T?xTmV9vkdTuc+i!i2|0Knw zzH4khkNy1K*FJvxRd>_0+Ml|gKcU>i(L4b!YV zc&IHHE+e+PWpVejC!G%AWNr4P!kL1%6;BslEuJj_=y0GoyF^X0Nlki(*?m4f|7rOA zQ(qTKtvCSyfCGqbj~>C|j%9S9?;5NJ8^cpa=V=?TYw#^_XqP&awJGpDn?hxHh*pLB zF7=OhtnJD^RI61O%tA$jYb_Z6scnG4Tuw;`xCNBCeTRai8~= zCC9NG&}+KLw=D8)Nb?>2rO86pQOIvAL-r+PNq>uy{zjd2prVd@xMj>d&#W(qteeuT zgI}b1UqpGAm3bo>S?0f>%zsd4j+GK}pCEfc4tbKO3leiu68i&f0cth)@yjpZ?&c@7 z&7(MOA{=u{97C#`J9%_f{vht&dDAJX2^V@Y$RefB9OrO&?K5v^xxS~0Rm&uXNc zE2vun)D?ACamQf2O1azZmP6eY?21BLMbMVwo9vK0>WSb03B~o|D+ptu7~ga$jZ!Q= zrs>7eRpi@_*9GOPO3KTYB}IJ8B(57Jd>0X3j3tbuBdHG!q;yXsx_`w#Qq!2EBRdgR z&puzKcl@u_x;77O?*`!}afWva`-25ZPGWaJSV4CU(S3hRH>(GtpvHU-VSY_C@e#PG zc*m4LX81eAG03J#A-I-Y%V5nf13hgSc)y54!t15cIl?nq6+KiH>shKIVi~378%v7> zeUY9zpQ%VPnNLtNQ#>|8mz8JHwEUuxk77oKdQcj~ajaeF_F0=77K@g~3M!53%GW_4 zj2K{f*@Eo_;{U7qU69Tp;Z2a4kgc;4!|e8@949Hhti0m67A0b_J7kj(KP#PPQz zj)@itAWsNM|JzoV4~c}KLwVm}us?u-Y;2biUkRWA2QV`;0!@-dUBWzRX>tjuz@i5b(a_Yv;*l(-`X zsG$zoNU4_)^%v@{&1RLA+ zj}h>DVgZ)TD+~l1O3|N3=wJ62UPorCDgwne-5T9<%(X1u^~=JWgk>N7w-ECB82L0~ z|7Qs3Q_;&)jr>o>xZnRzjDAJ15SAuoJ-#&$O&Ej{h~l`4a9jxEh?kO)_ydvn36V%p zOVuEPm)JyKhGY3- z8QM4M$^8+_;|Aio@2u2uQMC^A$)!+B9yj638zDa zN|{;ZSt##Ox2!#=Ka|jv&w3{|kivZf!JR2e;AS&P!8$U~pB8-{wEqPPUjVGOBme*g C#EyUf literal 1541 zcmV+g2KxCyRzV_` z8nl`=dYjy|2G@@4+jdo(7yb!&;D!Awh<{*0LV~9uF$sha4}g#+B;+L5_Nnjnk0dw= zvfpC+o@1ZSIrmt^j!`-{S3$~30aM{jDz0nxR3QB~%_pog$*S>&i#QA!O> z*NgWbC<~fxkfyzBGW)Z~^*Ui>W9o&8a}&;yJ3H}m?u|Tv3MZ1$d8(6bs?*y>bDwp` zKk<)0^Yui&8fE|h-~@ul!-ueZU}|;Pw>4u2w%S8GoQ;j^$KA-Q=LI%BzZ5nz2(XG#ZV9ue!WTL1^m;+DdqloidMV!n;90aWnT4 z!Z?u&FS?kHVr)M8sm0Dyq+5pg_~9VzaB15{9_+z6@X5%uTts!ir9s(8n#gzvhPo&HqKG;9WYqzQ}Qw#!6& zlReV(h=1trC7shj;2$I4clib^nJ+&O>`;jQ0z&_)yYU*BQ&|#7j{f%Oj>lBf;%zrA zoK9Hs)_)ZtpXnm+r|tg~0e!-2xv!T0c(nW7e`3_DoCSBOQ)7qi&O-%Sz6b!bYCMy^@S%F+xmB|VuyO1%I704x7 znXI5Mtm(@N-t{ZDGF5@Vn+$hI28^Am;3K~*EE5%EqJkJXvluQi%QOY!@Hf^HQk7+z zf`QEDL)H|CJ4BhL;D4bh5cileO~HWI)gfyNDw(Dr(-Z_X1+$r^U}Q7}bD5@K)Zko1 rnygGyFicH>r+>;c1!Jfw2uP+fO+f_dczykm&=mX&^rzQj3q=3`54G&^ From 4f3849ff38e0b5faea3d151fe0caa300d9cf96ae Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 5 Jun 2025 11:04:57 +0800 Subject: [PATCH 34/63] feat: add option to not check for function expressions by default because it is rare to fill an array with a function and add properties to it --- rules/no-array-fill-with-reference-type.js | 115 +++++++++----- test/no-array-fill-with-reference-type.js | 58 ++++++- .../no-array-fill-with-reference-type.js.md | 141 ++++++++++++------ .../no-array-fill-with-reference-type.js.snap | Bin 1344 -> 1393 bytes 4 files changed, 226 insertions(+), 88 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index a3676a3db1..52bcff93ea 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,3 +1,5 @@ +import {isFunction} from './ast/index.js'; + // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { @@ -28,39 +30,8 @@ const create = context => ({ return; } - let type = ''; - switch (fillArgument.type) { - case 'ObjectExpression': { - type = 'Object'; - break; - } - - case 'ArrayExpression': { - type = 'Array'; - break; - } - - case 'NewExpression': { - type = `new ${fillArgument.callee.name}()`; - break; - } - - case 'FunctionExpression': - case 'ArrowFunctionExpression': { - type = 'Function'; - break; - } - - default: { - if (fillArgument.type === 'Literal' && fillArgument.regex) { - type = 'RegExp'; - } else if (fillArgument.type === 'Identifier') { - type = `variable (${fillArgument.name})`; - } - } - } - const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; + const type = getType(fillArgument); return { node: fillArgument, @@ -73,6 +44,48 @@ const create = context => ({ }, }); +/** + + @param {*} fillArgument + @returns {string} + */ +function getType(fillArgument) { + let type = ''; + + switch (fillArgument.type) { + case 'ObjectExpression': { + type = 'Object'; + break; + } + + case 'ArrayExpression': { + type = 'Array'; + break; + } + + case 'NewExpression': { + type = `new ${fillArgument.callee.name}()`; + break; + } + + case 'FunctionExpression': + case 'ArrowFunctionExpression': { + type = 'Function'; + break; + } + + default: { + if (fillArgument.type === 'Literal' && fillArgument.regex) { + type = 'RegExp'; + } else if (fillArgument.type === 'Identifier') { + type = `variable (${fillArgument.name})`; + } + } + } + + return type; +} + /** @param {*} node @param {import('eslint').Rule.RuleContext} context @@ -98,16 +111,22 @@ function isReferenceType(node, context) { if (node.type === 'Identifier') { const {variables} = context.sourceCode.getScope(node); const variable = variables.find(v => v.name === node.name); + const definitionNode = variable?.defs[0].node; log('variables:', variables); log('variable:', variable); - log('variable.defs[0].node:', variable?.defs[0].node); + log('variable.defs[0].node:', definitionNode); - if (!variable || !variable.defs[0]?.node) { + if (!variable || !definitionNode) { return false; } - return isReferenceType(variable.defs[0].node, context); + // Check `const foo = []; Array(3).fill(foo);` + if (definitionNode.type === 'VariableDeclarator') { + return isReferenceType(definitionNode.init, context); + } + + return isReferenceType(definitionNode, context); } // Symbol (such as `Symbol('name')`) @@ -121,10 +140,32 @@ function isReferenceType(node, context) { } } - // Other cases: objects, arrays, functions, new expressions, regular expressions, etc. + const options = { + // Not check for function expressions by default because it is rare to fill an array with a function and add properties to it. + canFillWithFunction: true, + ...context.options[0], + }; + + if (options.canFillWithFunction && isFunction(node)) { + return false; + } + + // Other cases: objects, arrays, new expressions, regular expressions, etc. return true; } +const schema = [ + { + type: 'object', + additionalProperties: false, + properties: { + canFillWithFunction: { + type: 'boolean', + }, + }, + }, +]; + /** @type {import('eslint').Rule.RuleModule} */ const config = { create, @@ -134,6 +175,8 @@ const config = { description: 'Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, + schema, + defaultOptions: [{}], messages, }, }; diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 75433d617b..4107b318cd 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -39,6 +39,30 @@ test.snapshot({ list.push(map); } `, + + 'const foo = 0; new Array(8).fill(foo);', + + // Not check functions + // function expression + 'new Array(1).fill(() => 1);', + 'new Array(2).fill(() => {});', + `new Array(3).fill(() => { + return {} + });`, + 'new Array(4).fill(function () {});', + + // Set canFillWithFunction explicitly to true + { + code: 'new Array(41).fill(function () {});', + options: [{ + canFillWithFunction: true, + }], + }, + + // Function declaration + 'const foo = () => 0; new Array(5).fill(foo);', + 'const foo = function () {}; new Array(6).fill(foo);', + 'function foo() {}; new Array(7).fill(foo);', ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -53,12 +77,7 @@ test.snapshot({ 'new Array(3).fill(new Foo(\'fff\')); // ✗ new Class', 'class BarClass {}; new Array(3).fill(BarClass); // ✗ Class', 'class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance', - 'new Array(3).fill(() => 1); // ✗ arrow function', - 'new Array(3).fill(() => {}); // ✗ arrow function', - `new Array(3).fill(() => { - return {} - });`, - 'new Array(3).fill(function () {}); // ✗ normal function', + 'const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)', 'Array(3).fill({}); // ✗ Object ', @@ -69,5 +88,32 @@ test.snapshot({ 'Array.from({ length: 3 }).fill(new Date())', 'Array.from({length: 3}).fill(createError(\'no\', \'yes\')[0])', + 'const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)', + + // Should not fill with function + { + code: 'new Array(3).fill(() => 1);', + options: [{ + canFillWithFunction: false, + }], + }, + { + code: 'new Array(3).fill(() => {});', + options: [{ + canFillWithFunction: false, + }], + }, + { + code: 'new Array(3).fill(() => { return {} });', + options: [{ + canFillWithFunction: false, + }], + }, + { + code: 'new Array(3).fill(function () {});', + options: [{ + canFillWithFunction: false, + }], + }, ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 6fa96ec4a8..4dabdd4bd0 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -169,158 +169,207 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(12): new Array(3).fill(() => 1); // ✗ arrow function +## invalid(12): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) > Input `␊ - 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ + 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(() => 1); // ✗ arrow function␊ - | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(13): new Array(3).fill(() => {}); // ✗ arrow function +## invalid(13): Array(3).fill({}); // ✗ Object > Input `␊ - 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ + 1 | Array(3).fill({}); // ✗ Object ␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(() => {}); // ✗ arrow function␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | Array(3).fill({}); // ✗ Object ␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(14): new Array(3).fill(() => { return {} }); +## invalid(14): Array.from({ length: 3 }).fill({}); > Input `␊ - 1 | new Array(3).fill(() => {␊ - 2 | return {}␊ - 3 | });␊ + 1 | Array.from({ length: 3 }).fill({});␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(() => {␊ - | ^^^^^^^␊ - > 2 | return {}␊ - | ^^^^^^^^^^^^␊ - > 3 | });␊ - | ^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | Array.from({ length: 3 }).fill({});␊ + | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(15): new Array(3).fill(function () {}); // ✗ normal function +## invalid(15): new Array(3).fill(new Date()) > Input `␊ - 1 | new Array(3).fill(function () {}); // ✗ normal function␊ + 1 | new Array(3).fill(new Date())␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(function () {}); // ✗ normal function␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | new Array(3).fill(new Date())␊ + | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(16): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) +## invalid(16): Array.from({ length: 3 }).fill(new Date()) > Input `␊ - 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ + 1 | Array.from({ length: 3 }).fill(new Date())␊ ` > Error 1/1 `␊ - > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | Array.from({ length: 3 }).fill(new Date())␊ + | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(17): Array(3).fill({}); // ✗ Object +## invalid(17): Array.from({length: 3}).fill(createError('no', 'yes')[0]) > Input `␊ - 1 | Array(3).fill({}); // ✗ Object ␊ + 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ ` > Error 1/1 `␊ - > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(18): Array.from({ length: 3 }).fill({}); +## invalid(18): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) > Input `␊ - 1 | Array.from({ length: 3 }).fill({});␊ + 1 | const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)␊ ` > Error 1/1 `␊ - > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)␊ + | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (initialArray)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(19): new Array(3).fill(new Date()) +## invalid(19): new Array(3).fill(() => 1); > Input `␊ - 1 | new Array(3).fill(new Date())␊ + 1 | new Array(3).fill(() => 1);␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithFunction": false␊ + }␊ + ]␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | new Array(3).fill(() => 1);␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(20): Array.from({ length: 3 }).fill(new Date()) +## invalid(20): new Array(3).fill(() => {}); > Input `␊ - 1 | Array.from({ length: 3 }).fill(new Date())␊ + 1 | new Array(3).fill(() => {});␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithFunction": false␊ + }␊ + ]␊ ` > Error 1/1 `␊ - > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | new Array(3).fill(() => {});␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(21): Array.from({length: 3}).fill(createError('no', 'yes')[0]) +## invalid(21): new Array(3).fill(() => { return {} }); > Input `␊ - 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ + 1 | new Array(3).fill(() => { return {} });␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithFunction": false␊ + }␊ + ]␊ ` > Error 1/1 `␊ - > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + > 1 | new Array(3).fill(() => { return {} });␊ + | ^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(22): new Array(3).fill(function () {}); + +> Input + + `␊ + 1 | new Array(3).fill(function () {});␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithFunction": false␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(function () {});␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 14aed1a1cb3f841cf53931f37301f5939b009bc3..2d5cb8065e7f68333c358f813d610c63f160324c 100644 GIT binary patch literal 1393 zcmV-%1&;bbRzV0V#QbhM(@Ik>yndV)hIPg%PQ{d z8jGgKh~pjF-23D~y-qmUntX2T;+X%+T^M^Y_i7%X0{1mn=cz>ws6}rxr^UnTANF29 z{?%B1IZglo;66lOdwZ~QY@2mxc_wSZesF2$I%6O1n*0!4+Mq6FH46O1p->D?F-q{B zN9FmheN;S!QmF*(Nhlhyv<%@}V;@ZBaZ2jIZJ^9+xfD!Rrw(Ox%6M>;up0GB;kPtb zUDtM@QmzPp3&P)NrN5nbhRWm$GWj*F$x=e)^tZ_Auk}uMRrGcTuaur=>Gf6Nbyewg z_Y%>t3`Wpdy9N#=z;l8~zP$zZDoeQj4Ev!w-dtq%-MK7g+CG?P|o0Ja? zODp{U!0MFC64so6HK&ACb_nOxW#ulccWHC=o}#&u&V5=*<=potqV-5mD@JzotUAh> zg1RX{&Fj00yC!QE3ynsj(9>PrLs4j(2-<3Vlbw-AJ<&ZuL2*0x0>U_!i*LGwg%T`2 zhUvx5D6(zGw*=+uTFPs-twem&BAyo|ynzU>#1cl*5!ZtPO1c*i-GAbz)FefcksS!D zUp`x=x8>97l(7Ic{|mwm;s)OoPTPwLpTyxVVGZ3aME9MLZrU1%f*$iFg!v`W#3QJt z;~f)$)bNjqYmx(tLU$~g#$ZdvpprBO{wLy;-t|)F8c{QviY7|McA8W~N=9kP!pe}K zC(`lDsX~&f_yCz1V%q2#R+gc;BSYhF#nf!(aX2ClEP-6xtBgD%PB$&@%i#MTN7M2l zO3NLQmUOjxLE(bRlw3wBd0D1pWJOb?BTUE;6N+Ck(^$MAW8v=_rQfGmM#!f^}!$qNGJxlOHZX71})xL~&e4IIi~Mh?i24_zRKv1(E2Z zmZ)hoRD5CMse^Mx!qM*>-6EV84aLM*MOZGyE}cUW6_CdW$anFpW1*u%G30G5ls}gp zhRSUJ{)pxAHsUdztWDzKZ09Z_I{zhXmn5jta7)lV=Y(%f;+s2zPr4#ZskxMJ8YmPC z%q~nq;e>hxV`pktK~w!;I&c9c+*c6X=W`0U>53#^9oc;t7JZhq_ayCkx!yFH$xUJf z^Yn>15-H_(@&Km+hlv_tYo=v=VDiJY7OQd7W)ln0AeQGpQ?~QF zpW0VtNJI60?%TN%ybSvUOXFhE%3e z4Yis!dYYW12KU&qPuf*&Zuky}8*bQFL41J;2??%-#3T?xTmV9vkdTuc+i!i2|0Knw zzH4khkNy1K*FJvxRd>_0+Ml|gKcU>i(L4b!YV zc&IHHE+e+PWpVejC!G%AWNr4P!kL1%6;BslEuJj_=y0GoyF^X0Nlki(*?m4f|7rOA zQ(qTKtvCSyfCGqbj~>C|j%9S9?;5NJ8^cpa=V=?TYw#^_XqP&awJGpDn?hxHh*pLB zF7=OhtnJD^RI61O%tA$jYb_Z6scnG4Tuw;`xCNBCeTRai8~= zCC9NG&}+KLw=D8)Nb?>2rO86pQOIvAL-r+PNq>uy{zjd2prVd@xMj>d&#W(qteeuT zgI}b1UqpGAm3bo>S?0f>%zsd4j+GK}pCEfc4tbKO3leiu68i&f0cth)@yjpZ?&c@7 z&7(MOA{=u{97C#`J9%_f{vht&dDAJX2^V@Y$RefB9OrO&?K5v^xxS~0Rm&uXNc zE2vun)D?ACamQf2O1azZmP6eY?21BLMbMVwo9vK0>WSb03B~o|D+ptu7~ga$jZ!Q= zrs>7eRpi@_*9GOPO3KTYB}IJ8B(57Jd>0X3j3tbuBdHG!q;yXsx_`w#Qq!2EBRdgR z&puzKcl@u_x;77O?*`!}afWva`-25ZPGWaJSV4CU(S3hRH>(GtpvHU-VSY_C@e#PG zc*m4LX81eAG03J#A-I-Y%V5nf13hgSc)y54!t15cIl?nq6+KiH>shKIVi~378%v7> zeUY9zpQ%VPnNLtNQ#>|8mz8JHwEUuxk77oKdQcj~ajaeF_F0=77K@g~3M!53%GW_4 zj2K{f*@Eo_;{U7qU69Tp;Z2a4kgc;4!|e8@949Hhti0m67A0b_J7kj(KP#PPQz zj)@itAWsNM|JzoV4~c}KLwVm}us?u-Y;2biUkRWA2QV`;0!@-dUBWzRX>tjuz@i5b(a_Yv;*l(-`X zsG$zoNU4_)^%v@{&1RLA+ zj}h>DVgZ)TD+~l1O3|N3=wJ62UPorCDgwne-5T9<%(X1u^~=JWgk>N7w-ECB82L0~ z|7Qs3Q_;&)jr>o>xZnRzjDAJ15SAuoJ-#&$O&Ej{h~l`4a9jxEh?kO)_ydvn36V%p zOVuEPm)JyKhGY3- z8QM4M$^8+_;|Aio@2u2uQMC^A$)!+B9yj638zDa zN|{;ZSt##Ox2!#=Ka|jv&w3{|kivZf!JR2e;AS&P!8$U~pB8-{wEqPPUjVGOBme*g C#EyUf From ef37d4844d1339c19d558ef46ce0fab076e2cf6d Mon Sep 17 00:00:00 2001 From: legend80s Date: Thu, 5 Jun 2025 11:21:27 +0800 Subject: [PATCH 35/63] docs: add option to not check for function --- .../no-array-fill-with-reference-type.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 4019b9c120..c1432c7671 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -101,3 +101,33 @@ Array.from({ length: 3 }).fill(box); // ✅ Array.from({ length: 3 }, () => []); ``` + +## Options + +### canFillWithFunction + +Type: `boolean`\ +Default: `true` + +Should check function when filling an array? + +This would pass by default: + +```js +new Array(3).fill(function () {}) +``` + +```js +"unicorn/catch-error-name": [ + "error", + { + "canFillWithFunction": false + } +] +``` + +with `canFillWithFunction: false`, this would fail: + +```js +new Array(3).fill(function () {}) +``` From bac577bd892e8fb194f19a5425f8af214d63f755 Mon Sep 17 00:00:00 2001 From: legend80s Date: Tue, 10 Jun 2025 14:02:40 +0800 Subject: [PATCH 36/63] style: add new line to fix lint errors --- rules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/index.js b/rules/index.js index 5e2783be43..89dab08df0 100644 --- a/rules/index.js +++ b/rules/index.js @@ -130,4 +130,4 @@ export {default as 'string-content'} from './string-content.js'; export {default as 'switch-case-braces'} from './switch-case-braces.js'; export {default as 'template-indent'} from './template-indent.js'; export {default as 'text-encoding-identifier-case'} from './text-encoding-identifier-case.js'; -export {default as 'throw-new-error'} from './throw-new-error.js'; \ No newline at end of file +export {default as 'throw-new-error'} from './throw-new-error.js'; From 59b4ae89be29cb00b3a6eba1939367939a67c7df Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 13 Jun 2025 16:35:46 +0800 Subject: [PATCH 37/63] feat(no-array-fill-with-reference-type): ignore regexp literal and new expression by default --- rules/no-array-fill-with-reference-type.js | 37 ++++-- test/no-array-fill-with-reference-type.js | 38 +++++- .../no-array-fill-with-reference-type.js.md | 119 +++++++++++++++--- .../no-array-fill-with-reference-type.js.snap | Bin 1393 -> 1554 bytes 4 files changed, 168 insertions(+), 26 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 52bcff93ea..99e06e726c 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,4 +1,4 @@ -import {isFunction} from './ast/index.js'; +import {isFunction, isRegexLiteral} from './ast/index.js'; // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; @@ -6,6 +6,13 @@ const messages = { [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { ... })` instead to ensure independent instances.', }; +const DEFAULTS = { + // Not check for function expressions by default because it is rare to fill an array with a function and add properties to it. + canFillWithFunction: true, + // The same reason as above. + canFillWithRegexp: true, +}; + const debugging = false; const log = (...arguments_) => debugging && console.log(...arguments_); @@ -96,10 +103,22 @@ function isReferenceType(node, context) { return false; } + /** + @type {typeof DEFAULTS} + */ + const options = { + ...DEFAULTS, + ...context.options[0], + }; + // For null, number, string, boolean. if (node.type === 'Literal') { // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). - return node.regex !== undefined; + if (!options.canFillWithRegexp && isRegexLiteral(node)) { + return true; + } + + return false; } // For template literals. @@ -140,16 +159,15 @@ function isReferenceType(node, context) { } } - const options = { - // Not check for function expressions by default because it is rare to fill an array with a function and add properties to it. - canFillWithFunction: true, - ...context.options[0], - }; - if (options.canFillWithFunction && isFunction(node)) { return false; } + const isNewRegexp = node.type === 'NewExpression' && node.callee.name === 'RegExp'; + if (options.canFillWithRegexp && isNewRegexp) { + return false; + } + // Other cases: objects, arrays, new expressions, regular expressions, etc. return true; } @@ -162,6 +180,9 @@ const schema = [ canFillWithFunction: { type: 'boolean', }, + canFillWithRegexp: { + type: 'boolean', + }, }, }, ]; diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 4107b318cd..4457859da4 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -63,6 +63,12 @@ test.snapshot({ 'const foo = () => 0; new Array(5).fill(foo);', 'const foo = function () {}; new Array(6).fill(foo);', 'function foo() {}; new Array(7).fill(foo);', + + // RegExp is not check by default + 'new Array(3).fill(/pattern/);', + 'new Array(3).fill(new RegExp("pattern"));', + 'const p = /pattern/; new Array(3).fill(p);', + 'const p = new RegExp("pattern"); new Array(3).fill(p);', ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -71,7 +77,32 @@ test.snapshot({ 'new Array(3).fill({}); // ✗ Object ', 'new Array(3).fill(new Map()); // ✗ Map', 'new Array(3).fill(new Set()); // ✗ Set', - 'new Array(3).fill(/pattern/); // ✗ RegExp ', + + { + code: 'new Array(3).fill(/pattern/); // ✗ RegExp', + options: [{ + canFillWithRegexp: false, + }], + }, + { + code: 'new Array(3).fill(new RegExp("pattern")); // ✗ RegExp', + options: [{ + canFillWithRegexp: false, + }], + }, + { + code: 'const p = /pattern/; new Array(3).fill(p); // ✗ RegExp', + options: [{ + canFillWithRegexp: false, + }], + }, + { + code: 'const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp', + options: [{ + canFillWithRegexp: false, + }], + }, + 'new Array(3).fill(new String(\'fff\')); // ✗ new String', 'new Array(3).fill(new Foo(\'fff\')); // ✗ new Class', @@ -90,6 +121,11 @@ test.snapshot({ 'Array.from({length: 3}).fill(createError(\'no\', \'yes\')[0])', 'const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)', + // ` + // const object = {} + // Array.from({length: 3}, () => object) + // `, + // Should not fill with function { code: 'new Array(3).fill(() => 1);', diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 4dabdd4bd0..f6a75f3bf3 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -99,17 +99,102 @@ Generated by [AVA](https://avajs.dev). > Input `␊ - 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + 1 | new Array(3).fill(/pattern/); // ✗ RegExp␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithRegexp": false␊ + }␊ + ]␊ ` > Error 1/1 `␊ - > 1 | new Array(3).fill(/pattern/); // ✗ RegExp ␊ + > 1 | new Array(3).fill(/pattern/); // ✗ RegExp␊ | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(8): new Array(3).fill(new String('fff')); // ✗ new String +## invalid(8): new Array(3).fill(new RegExp("pattern")); // ✗ RegExp + +> Input + + `␊ + 1 | new Array(3).fill(new RegExp("pattern")); // ✗ RegExp␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithRegexp": false␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new RegExp("pattern")); // ✗ RegExp␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new RegExp()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(9): const p = /pattern/; new Array(3).fill(p); // ✗ RegExp + +> Input + + `␊ + 1 | const p = /pattern/; new Array(3).fill(p); // ✗ RegExp␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithRegexp": false␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + > 1 | const p = /pattern/; new Array(3).fill(p); // ✗ RegExp␊ + | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(10): const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp + +> Input + + `␊ + 1 | const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp␊ + ` + +> Options + + `␊ + [␊ + {␊ + "canFillWithRegexp": false␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + > 1 | const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp␊ + | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + ` + +## invalid(11): new Array(3).fill(new String('fff')); // ✗ new String > Input @@ -124,7 +209,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(9): new Array(3).fill(new Foo('fff')); // ✗ new Class +## invalid(12): new Array(3).fill(new Foo('fff')); // ✗ new Class > Input @@ -139,7 +224,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(10): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class +## invalid(13): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class > Input @@ -154,7 +239,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(11): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance +## invalid(14): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance > Input @@ -169,7 +254,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(12): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) +## invalid(15): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) > Input @@ -184,7 +269,7 @@ Generated by [AVA](https://avajs.dev). | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(13): Array(3).fill({}); // ✗ Object +## invalid(16): Array(3).fill({}); // ✗ Object > Input @@ -199,7 +284,7 @@ Generated by [AVA](https://avajs.dev). | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(14): Array.from({ length: 3 }).fill({}); +## invalid(17): Array.from({ length: 3 }).fill({}); > Input @@ -214,7 +299,7 @@ Generated by [AVA](https://avajs.dev). | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(15): new Array(3).fill(new Date()) +## invalid(18): new Array(3).fill(new Date()) > Input @@ -229,7 +314,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(16): Array.from({ length: 3 }).fill(new Date()) +## invalid(19): Array.from({ length: 3 }).fill(new Date()) > Input @@ -244,7 +329,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(17): Array.from({length: 3}).fill(createError('no', 'yes')[0]) +## invalid(20): Array.from({length: 3}).fill(createError('no', 'yes')[0]) > Input @@ -259,7 +344,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(18): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) +## invalid(21): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) > Input @@ -274,7 +359,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (initialArray)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(19): new Array(3).fill(() => 1); +## invalid(22): new Array(3).fill(() => 1); > Input @@ -299,7 +384,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(20): new Array(3).fill(() => {}); +## invalid(23): new Array(3).fill(() => {}); > Input @@ -324,7 +409,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(21): new Array(3).fill(() => { return {} }); +## invalid(24): new Array(3).fill(() => { return {} }); > Input @@ -349,7 +434,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ ` -## invalid(22): new Array(3).fill(function () {}); +## invalid(25): new Array(3).fill(function () {}); > Input diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 2d5cb8065e7f68333c358f813d610c63f160324c..f1bef7981761fceff0790b073e2ff0dc85603e35 100644 GIT binary patch literal 1554 zcmV+t2JQJlRzV6_e&>GE|;M*0wo1z=fHod?0~9UHYE+P+dy^ez@(t+4Qf!mL3P{xl<0M8 zmHl6-E}3TAgleVA^er-d$AtQNuN0BURV4C@QjvKGk%YmOtu=-z|&fHLGsVw8~>7m_&XC^Jy0z>lAN z1gpF6(YhVRaTDPfm*Q|^c?XIJAY$_iV)M0}O+?r}?nhqCT+xg(G!xPySs{kwNcO{5 zh!MuKi11vGtQHmz$+WUwZMuqpwR99Ht`B`(7Z9(Sl$SK52-Y+T zI#Spy0Gznu57&vltZLfZs=arYw&;;DJPl2vS+oGqDQx-CTC0Ywwsp&o_dA0By&S%L zmHj901vv_lyi zBYzF~ZW4>kEmO)g)Z4mcg8{R^Yh*?sm=SN6HxSKv-!8qz&&4lKBfks``hMwo%`(FX zkMxc?B&JGsH3}soU&q|xcj%+YGQu+I(LV1WxUYxo(|fL5tW-o+x)iojhV`ei)j72o z-;}E2DUjPw*`}(uO2uZgSq$vf-H*a;=NjU?6y0{73hy1EBmz50cam(05?_CM>rTB@ zI_dL; zdYeOare1aD2f|Hay1x`oI-*UEecUB1p}UUgzQ!&KDRUqSa?FsXTXo_!4 zdrlyPdkMjPa!>#_U6KT>h2!rm=<}q#&1qM8zp3h~trE@653{hjC2GimUlO&R#Qh-g ztxCTW3*CVpU>K_5CbXZ)6YUT(4`t{}(eiTLHA>t^;z5>|uo`TJ*rYq@Q&l{K=$iWq z3R0E~u$K??x-+Iu@@MLI$ShyTuj1Wx#azQvgJsLjm88N+il5o?6Lv%>#}I{=Vo=H& z+WxbY+^j?{EC%K|p~)Xt852ME#S)s-J}`AS>3|UIEJ9L=1B=7u!}xE+_~%&0r`8yU zJIe-rCgdxey!f%QroSjBv$&dXAVycE&`(Fohxc!Y_qTH1q2(n*{diOU51Vp4_%|*9 E07G2+VE_OC literal 1393 zcmV-%1&;bbRzV0V#QbhM(@Ik>yndV)hIPg%PQ{d z8jGgKh~pjF-23D~y-qmUntX2T;+X%+T^M^Y_i7%X0{1mn=cz>ws6}rxr^UnTANF29 z{?%B1IZglo;66lOdwZ~QY@2mxc_wSZesF2$I%6O1n*0!4+Mq6FH46O1p->D?F-q{B zN9FmheN;S!QmF*(Nhlhyv<%@}V;@ZBaZ2jIZJ^9+xfD!Rrw(Ox%6M>;up0GB;kPtb zUDtM@QmzPp3&P)NrN5nbhRWm$GWj*F$x=e)^tZ_Auk}uMRrGcTuaur=>Gf6Nbyewg z_Y%>t3`Wpdy9N#=z;l8~zP$zZDoeQj4Ev!w-dtq%-MK7g+CG?P|o0Ja? zODp{U!0MFC64so6HK&ACb_nOxW#ulccWHC=o}#&u&V5=*<=potqV-5mD@JzotUAh> zg1RX{&Fj00yC!QE3ynsj(9>PrLs4j(2-<3Vlbw-AJ<&ZuL2*0x0>U_!i*LGwg%T`2 zhUvx5D6(zGw*=+uTFPs-twem&BAyo|ynzU>#1cl*5!ZtPO1c*i-GAbz)FefcksS!D zUp`x=x8>97l(7Ic{|mwm;s)OoPTPwLpTyxVVGZ3aME9MLZrU1%f*$iFg!v`W#3QJt z;~f)$)bNjqYmx(tLU$~g#$ZdvpprBO{wLy;-t|)F8c{QviY7|McA8W~N=9kP!pe}K zC(`lDsX~&f_yCz1V%q2#R+gc;BSYhF#nf!(aX2ClEP-6xtBgD%PB$&@%i#MTN7M2l zO3NLQmUOjxLE(bRlw3wBd0D1pWJOb?BTUE;6N+Ck(^$MAW8v=_rQfGmM#!f^}!$qNGJxlOHZX71})xL~&e4IIi~Mh?i24_zRKv1(E2Z zmZ)hoRD5CMse^Mx!qM*>-6EV84aLM*MOZGyE}cUW6_CdW$anFpW1*u%G30G5ls}gp zhRSUJ{)pxAHsUdztWDzKZ09Z_I{zhXmn5jta7)lV=Y(%f;+s2zPr4#ZskxMJ8YmPC z%q~nq;e>hxV`pktK~w!;I&c9c+*c6X=W`0U>53#^9oc;t7JZhq_ayCkx!yFH$xUJf z^Yn>15-H_(@&Km+hlv_tYo=v=VDiJY7OQd7W)ln0AeQGpQ?~QF zp Date: Fri, 13 Jun 2025 16:37:17 +0800 Subject: [PATCH 38/63] docs(no-array-fill-with-reference-type): ignore regexp literal and new expression by default --- .../no-array-fill-with-reference-type.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index c1432c7671..5aa274f7de 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -131,3 +131,31 @@ with `canFillWithFunction: false`, this would fail: ```js new Array(3).fill(function () {}) ``` + +### canFillWithRegexp + +Type: `boolean`\ +Default: `true` + +Should check function when filling an array? + +This would pass by default: + +```js +new Array(3).fill(/pattern/) +``` + +```js +"unicorn/catch-error-name": [ + "error", + { + "canFillWithRegexp": false + } +] +``` + +with `canFillWithRegexp: false`, this would fail: + +```js +new Array(3).fill(/pattern/) +``` From 9b80603b8e2bcb5771b1426918d8847141fabc8b Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 13 Jun 2025 16:41:51 +0800 Subject: [PATCH 39/63] docs(no-array-fill-with-reference-type): more precise suggestion tips --- rules/no-array-fill-with-reference-type.js | 2 +- .../no-array-fill-with-reference-type.js.md | 50 +++++++++--------- .../no-array-fill-with-reference-type.js.snap | Bin 1554 -> 1574 bytes 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 99e06e726c..5fdb32202f 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -3,7 +3,7 @@ import {isFunction, isRegexLiteral} from './ast/index.js'; // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { - [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { ... })` instead to ensure independent instances.', + [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { return independent instance })` instead to ensure no reference shared.', }; const DEFAULTS = { diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index f6a75f3bf3..8f4ac6c854 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -16,7 +16,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill([]);␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(2): new Array(3).fill(Array()); @@ -31,7 +31,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(Array());␊ - | ^^^^^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(3): new Array(3).fill(new Array()); @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Array());␊ - | ^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Array()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Array()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(4): new Array(3).fill({}); // ✗ Object @@ -61,7 +61,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill({}); // ✗ Object ␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(5): new Array(3).fill(new Map()); // ✗ Map @@ -76,7 +76,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Map()); // ✗ Map␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(6): new Array(3).fill(new Set()); // ✗ Set @@ -91,7 +91,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Set()); // ✗ Set␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Set()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(7): new Array(3).fill(/pattern/); // ✗ RegExp @@ -116,7 +116,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(/pattern/); // ✗ RegExp␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(8): new Array(3).fill(new RegExp("pattern")); // ✗ RegExp @@ -141,7 +141,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new RegExp("pattern")); // ✗ RegExp␊ - | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new RegExp()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new RegExp()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(9): const p = /pattern/; new Array(3).fill(p); // ✗ RegExp @@ -166,7 +166,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const p = /pattern/; new Array(3).fill(p); // ✗ RegExp␊ - | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(10): const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp @@ -191,7 +191,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp␊ - | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(11): new Array(3).fill(new String('fff')); // ✗ new String @@ -206,7 +206,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new String('fff')); // ✗ new String␊ - | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new String()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(12): new Array(3).fill(new Foo('fff')); // ✗ new Class @@ -221,7 +221,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Foo('fff')); // ✗ new Class␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Foo()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(13): class BarClass {}; new Array(3).fill(BarClass); // ✗ Class @@ -236,7 +236,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(14): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance @@ -251,7 +251,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new BarClass()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(15): const map = new Map(); new Array(3).fill(map); // ✗ Variable (map) @@ -266,7 +266,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(16): Array(3).fill({}); // ✗ Object @@ -281,7 +281,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array(3).fill({}); // ✗ Object ␊ - | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(17): Array.from({ length: 3 }).fill({}); @@ -296,7 +296,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(18): new Array(3).fill(new Date()) @@ -311,7 +311,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(19): Array.from({ length: 3 }).fill(new Date()) @@ -326,7 +326,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(20): Array.from({length: 3}).fill(createError('no', 'yes')[0]) @@ -341,7 +341,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(21): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) @@ -356,7 +356,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)␊ - | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (initialArray)). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (initialArray)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(22): new Array(3).fill(() => 1); @@ -381,7 +381,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => 1);␊ - | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(23): new Array(3).fill(() => {}); @@ -406,7 +406,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => {});␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(24): new Array(3).fill(() => { return {} }); @@ -431,7 +431,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(() => { return {} });␊ - | ^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(25): new Array(3).fill(function () {}); @@ -456,5 +456,5 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | new Array(3).fill(function () {});␊ - | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { ... })\` instead to ensure independent instances.␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index f1bef7981761fceff0790b073e2ff0dc85603e35..e0e7724f73d7925a571674000365072c89d45df1 100644 GIT binary patch literal 1574 zcmV+>2HE*RRzVQCML;i7ZeCm7sBkmd(za_EH zIXR#2IX=GE-#2%)cKu81+czFlTeUTMG^px_L{l5(nlc4CeF*cWNsh~-N~Ni4T6uFz znN}^G7}j3fw!V7YXb_vM4_zL3VZb>GR|Z}!yj=vS!6V7lMXHfqs?lZLII#Wep9HVJ z^us`LHp&11z#|AB+uJaI*j5{GV5xcwcHB$7>y#aMsM>pA(k3;jUZ-Fm8x+d!DM|%C zwkSW}Z10y(pi-$oX9&s)%*?_GnAAQnbx`#NHK^X8x(%vs*~Br`QFh!9lr+F@1J$hq zlY-t3c(eA1NgEaazpIO;**2k8t+A|^Sk^~`S@%9EqSV(=>aR*u&rOK({|n0hkMjI? zt;iv`M@ka?Cvbxi7!?xeej}tXjwqC*6p$GKiH*VlLh-vC1vV9fqX#5_JoF#XFatCu z1a#6-rlDGepT7GBR(HRkbvsPyE}}FhrR3W34rCEPR6NfRvESsxBFvs)OY>~z0N5A< zHZHBG6=FE*W$9QUMi|-xf_5viw3t1VuIc7{^R&xfJsuKx@t7{du6!>U1So0@vH%kTkhEgl6*@oOLB zJi<6C#V9o?YM)cc=umO92yo&e8LSh1N!7GZReSFNZP6oRa0;44vuF{ZQ{3{cwN?#V zZR-}(#1*88zvP;bhk5pb@C@fb4fmKDZc8iLi?uxHr)N-!SH=p0_+Dgz$C^JEm0U$C zd94uHIpRZ3Fn?v7#QYfY&`}nch9;FMsJC^?1_Ne**VD8hjYhnPK0=J=d=d3(|6Ejb z4XNmLrlOu>mdQwXq}S0QF;%jwQ79XE(9wOq)-a5OBrLfeMfDj%{$WT|z56;Bfz2R+ zRl)+x5PvGM{jY?_8(2-e%H@u4wyEl^a;e#DmID30`%`$#T|@L2qsQD+=Dj22L^$=>xHm!=Fa* zhxlzEySEfKfu1GN?fyKL9Ef9`i(@RQIGk_TDZxb#?-~|dSSu~0m5nr73Aqe2hz~myYUd8p&P_aho`usCn(=j$q4_u-b0C(RTrAF_YWiJ_StNvEUkF)tF#blE zpRg6POuH8sdFO&}HPt26^_IOi1*6aj>bAWy%!P$!~`6qoPj++qO%h97xp(0tyUpmn1&U$@ZLBd5($6_e&>GE|;M*0wo1z=fHod?0~9UHYE+P+dy^ez@(t+4Qf!mL3P{xl<0M8 zmHl6-E}3TAgleVA^er-d$AtQNuN0BURV4C@QjvKGk%YmOtu=-z|&fHLGsVw8~>7m_&XC^Jy0z>lAN z1gpF6(YhVRaTDPfm*Q|^c?XIJAY$_iV)M0}O+?r}?nhqCT+xg(G!xPySs{kwNcO{5 zh!MuKi11vGtQHmz$+WUwZMuqpwR99Ht`B`(7Z9(Sl$SK52-Y+T zI#Spy0Gznu57&vltZLfZs=arYw&;;DJPl2vS+oGqDQx-CTC0Ywwsp&o_dA0By&S%L zmHj901vv_lyi zBYzF~ZW4>kEmO)g)Z4mcg8{R^Yh*?sm=SN6HxSKv-!8qz&&4lKBfks``hMwo%`(FX zkMxc?B&JGsH3}soU&q|xcj%+YGQu+I(LV1WxUYxo(|fL5tW-o+x)iojhV`ei)j72o z-;}E2DUjPw*`}(uO2uZgSq$vf-H*a;=NjU?6y0{73hy1EBmz50cam(05?_CM>rTB@ zI_dL; zdYeOare1aD2f|Hay1x`oI-*UEecUB1p}UUgzQ!&KDRUqSa?FsXTXo_!4 zdrlyPdkMjPa!>#_U6KT>h2!rm=<}q#&1qM8zp3h~trE@653{hjC2GimUlO&R#Qh-g ztxCTW3*CVpU>K_5CbXZ)6YUT(4`t{}(eiTLHA>t^;z5>|uo`TJ*rYq@Q&l{K=$iWq z3R0E~u$K??x-+Iu@@MLI$ShyTuj1Wx#azQvgJsLjm88N+il5o?6Lv%>#}I{=Vo=H& z+WxbY+^j?{EC%K|p~)Xt852ME#S)s-J}`AS>3|UIEJ9L=1B=7u!}xE+_~%&0r`8yU zJIe-rCgdxey!f%QroSjBv$&dXAVycE&`(Fohxc!Y_qTH1q2(n*{diOU51Vp4_%|*9 E07G2+VE_OC From 00eb9a32019bc9ebb8911e5139f3b0f862ef8c1f Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 13 Jun 2025 17:10:47 +0800 Subject: [PATCH 40/63] feat(no-array-fill-with-reference-type): try the best to retrie type even when callee.name is undefined --- rules/no-array-fill-with-reference-type.js | 32 +++++++++++-- test/no-array-fill-with-reference-type.js | 4 ++ .../no-array-fill-with-reference-type.js.md | 45 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 1574 -> 1701 bytes 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 5fdb32202f..e01740196f 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -38,7 +38,7 @@ const create = context => ({ } const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; - const type = getType(fillArgument); + const type = getType(fillArgument, context); return { node: fillArgument, @@ -54,9 +54,10 @@ const create = context => ({ /** @param {*} fillArgument + @param {import('eslint').Rule.RuleContext} context @returns {string} */ -function getType(fillArgument) { +function getType(fillArgument, context) { let type = ''; switch (fillArgument.type) { @@ -71,7 +72,8 @@ function getType(fillArgument) { } case 'NewExpression': { - type = `new ${fillArgument.callee.name}()`; + type = getNewExpressionType(fillArgument, context); + break; } @@ -93,6 +95,30 @@ function getType(fillArgument) { return type; } +/** + + @param {*} fillArgument + @param {import('eslint').Rule.RuleContext} context + @returns {string} + */ +function getNewExpressionType(fillArgument, context) { + if (fillArgument.callee.name) { + return `new ${fillArgument.callee.name}()`; + } + + // NewExpression.callee not always have a name. + // new A.B() and new class {} + // Try the best to get the type from source code + const matches = context.sourceCode.getText(fillArgument.callee).split('\n')[0].match(/\S+/); + + if (matches) { + // Limit the length to avoid too long tips + return 'new ' + matches[0].slice(0, 32); + } + + return 'new ()'; +} + /** @param {*} node @param {import('eslint').Rule.RuleContext} context diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 4457859da4..7ffa364f03 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -151,5 +151,9 @@ test.snapshot({ canFillWithFunction: false, }], }, + + 'new Array(3).fill(new Class {});', + 'new Array(3).fill(new A.B());', + 'const cls = new Class {}; new Array(3).fill(cls);', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 8f4ac6c854..fe20ec9f5f 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -458,3 +458,48 @@ Generated by [AVA](https://avajs.dev). > 1 | new Array(3).fill(function () {});␊ | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` + +## invalid(26): new Array(3).fill(new class {}); + +> Input + + `␊ + 1 | new Array(3).fill(new class {});␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new class {});␊ + | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new class). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(27): new Array(3).fill(new A.B()); + +> Input + + `␊ + 1 | new Array(3).fill(new A.B());␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Array(3).fill(new A.B());␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new A.B). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(28): const cls = new class {}; new Array(3).fill(cls); + +> Input + + `␊ + 1 | const cls = new class {}; new Array(3).fill(cls);␊ + ` + +> Error 1/1 + + `␊ + > 1 | const cls = new class {}; new Array(3).fill(cls);␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (cls)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index e0e7724f73d7925a571674000365072c89d45df1..3689e95a18804d3e7380f875877621a11d3132a7 100644 GIT binary patch literal 1701 zcmV;W23q++RzV}PJ00000000Bsnp?{pmdi-*l7amf0}>7i$a+^ckE=*7|-Wq>+7kUU+cI@zW=y!z2kkLqzO(3sA2C} z6pT*5o4rFU+N}EjUAt~s9SiEUIve#08}%{asP{gpqM@&&p+74fdTv5A{y(Gf|6V@+ zeJgSZ-j$NX;0at{1jdB~`gepBCJ}{-lmap%AhA&zLMVQdqrj$OaAZIN$iv_PjWR$J zLO=&ybrxzh_~DzcV0HU5+Hk^@mJp>0DJ9QV??M&(f0LwfmHm` z$GC_vj!Q90O^T+^8Dw;%yjcb~@Q@5Qh_S5c`p25HbBng=J#%;lT12;L8K7I<@~yR3 zO-Jh(Hq*ozq=`S}nvjQi^n&OaE`S=YGBsS5W^^xBW!N8{VKrVED+uD-kqI7a{#aCU z7OCW=Qsm4LA98~FD`zF<$54bBq_v^oQgj$u1s!W{5?niUMA884y_5aR`3L|N@0 zi;B)66}`+ExXfKc^sh&kxrfa6u8g|Y+hOpl2>fCscw{;R!*d{n{wjk0 zTr~6~PLcu7MB8;=1k^V;YPYM`aQ`+e5zG7kaL^S^lkDq0cM0=##Qa_MVoB)(v5~`{ zMes-XYaqY36fc3ylIYL=JeC58W1Wj*BB?msJM1UHrbq7?7F<{>ZKRcrG+GI{3^U}8 zh0=KsN#{x`>7;U=K}k8Lm_S&Amr}owo#ch=E@9=F*US?Q?=A@xWgqb*ac_q;^eNKN zO;pGx_7%j39SXH`1!?CZu0D^#X$sBwy2&y5xE>22mWy00Zc{b=F2+0(!l*BVJUbYF zAJke|-Q&x`R7=>4W8Ajpi z5_jo(Vbp`Q7i;+^Jrc)Fh~DLB=~JpoI{C|cM#JsbC+Ov`|A8d*qr5uk#}!i>q{hv{ zEdXDY^A#Vs^TX(h0FNOyZ^ZzXRMk&`uw)$-8CVSB6U~^P9vTy$**g@*K^KI$(H>Z- z7Ka;~I~MXArRNd)e`3)e3NlUwdFJ>638KaYAwCn>@AnK`6dt3OLE|dEaYHeweV~H={)@l_`WviCm=j?c_gX9k7)IQl{0q=c53Oco$_% zd|1%CQ(Y1tf=|;$@r{Vm@-c$*Q_Kl?-%c!2HE*RRzVQCML;i7ZeCm7sBkmd(za_EH zIXR#2IX=GE-#2%)cKu81+czFlTeUTMG^px_L{l5(nlc4CeF*cWNsh~-N~Ni4T6uFz znN}^G7}j3fw!V7YXb_vM4_zL3VZb>GR|Z}!yj=vS!6V7lMXHfqs?lZLII#Wep9HVJ z^us`LHp&11z#|AB+uJaI*j5{GV5xcwcHB$7>y#aMsM>pA(k3;jUZ-Fm8x+d!DM|%C zwkSW}Z10y(pi-$oX9&s)%*?_GnAAQnbx`#NHK^X8x(%vs*~Br`QFh!9lr+F@1J$hq zlY-t3c(eA1NgEaazpIO;**2k8t+A|^Sk^~`S@%9EqSV(=>aR*u&rOK({|n0hkMjI? zt;iv`M@ka?Cvbxi7!?xeej}tXjwqC*6p$GKiH*VlLh-vC1vV9fqX#5_JoF#XFatCu z1a#6-rlDGepT7GBR(HRkbvsPyE}}FhrR3W34rCEPR6NfRvESsxBFvs)OY>~z0N5A< zHZHBG6=FE*W$9QUMi|-xf_5viw3t1VuIc7{^R&xfJsuKx@t7{du6!>U1So0@vH%kTkhEgl6*@oOLB zJi<6C#V9o?YM)cc=umO92yo&e8LSh1N!7GZReSFNZP6oRa0;44vuF{ZQ{3{cwN?#V zZR-}(#1*88zvP;bhk5pb@C@fb4fmKDZc8iLi?uxHr)N-!SH=p0_+Dgz$C^JEm0U$C zd94uHIpRZ3Fn?v7#QYfY&`}nch9;FMsJC^?1_Ne**VD8hjYhnPK0=J=d=d3(|6Ejb z4XNmLrlOu>mdQwXq}S0QF;%jwQ79XE(9wOq)-a5OBrLfeMfDj%{$WT|z56;Bfz2R+ zRl)+x5PvGM{jY?_8(2-e%H@u4wyEl^a;e#DmID30`%`$#T|@L2qsQD+=Dj22L^$=>xHm!=Fa* zhxlzEySEfKfu1GN?fyKL9Ef9`i(@RQIGk_TDZxb#?-~|dSSu~0m5nr73Aqe2hz~myYUd8p&P_aho`usCn(=j$q4_u-b0C(RTrAF_YWiJ_StNvEUkF)tF#blE zpRg6POuH8sdFO&}HPt26^_IOi1*6aj>bAWy%!P$!~`6qoPj++qO%h97xp(0tyUpmn1&U$@ZLBd5($ Date: Fri, 13 Jun 2025 17:14:11 +0800 Subject: [PATCH 41/63] test(no-array-fill-with-reference-type): Class should be class to avoid syntax error --- test/no-array-fill-with-reference-type.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 7ffa364f03..5789c33691 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -152,8 +152,8 @@ test.snapshot({ }], }, - 'new Array(3).fill(new Class {});', + 'new Array(3).fill(new class {});', 'new Array(3).fill(new A.B());', - 'const cls = new Class {}; new Array(3).fill(cls);', + 'const cls = new class {}; new Array(3).fill(cls);', ], }); From acaf4e7de6a4f3299cfd28fe4a9b21eda7d5eae1 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 13 Jun 2025 17:29:11 +0800 Subject: [PATCH 42/63] feat(no-array-fill-with-reference-type): only check const --- rules/no-array-fill-with-reference-type.js | 51 ++++++++++++++-------- test/no-array-fill-with-reference-type.js | 15 ++++--- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index e01740196f..c30ea086bd 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -154,24 +154,7 @@ function isReferenceType(node, context) { // For variable identifiers (recursively check its declaration). if (node.type === 'Identifier') { - const {variables} = context.sourceCode.getScope(node); - const variable = variables.find(v => v.name === node.name); - const definitionNode = variable?.defs[0].node; - - log('variables:', variables); - log('variable:', variable); - log('variable.defs[0].node:', definitionNode); - - if (!variable || !definitionNode) { - return false; - } - - // Check `const foo = []; Array(3).fill(foo);` - if (definitionNode.type === 'VariableDeclarator') { - return isReferenceType(definitionNode.init, context); - } - - return isReferenceType(definitionNode, context); + return isIdentifierReferenceType(node, context); } // Symbol (such as `Symbol('name')`) @@ -198,6 +181,38 @@ function isReferenceType(node, context) { return true; } +/** + + @param {*} node + @param {import('eslint').Rule.RuleContext} context + @returns {boolean} + */ +function isIdentifierReferenceType(node, context) { + const {variables} = context.sourceCode.getScope(node); + const variable = variables.find(v => v.name === node.name); + const definitionNode = variable?.defs[0].node; + + log('variables:', variables); + log('variable:', variable); + log('variable.defs[0].node:', definitionNode); + + if (!variable || !definitionNode) { + return false; + } + + // Check `const foo = []; Array(3).fill(foo);` + if (definitionNode.type === 'VariableDeclarator') { + // Not check `let` + if (definitionNode.parent.kind === 'let') { + return false; + } + + return isReferenceType(definitionNode.init, context); + } + + return isReferenceType(definitionNode, context); +} + const schema = [ { type: 'object', diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 5789c33691..bb02dfaba8 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -32,6 +32,12 @@ test.snapshot({ // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable. // It cannot be exhaustively checked, we only check `Array.fill`. 'const map = new Map(); Array.from({ length: 3 }, () => map);', + + ` + const object = {} + Array.from({length: 3}, () => object) + `, + ` const map = new Map(); const list = []; @@ -69,6 +75,10 @@ test.snapshot({ 'new Array(3).fill(new RegExp("pattern"));', 'const p = /pattern/; new Array(3).fill(p);', 'const p = new RegExp("pattern"); new Array(3).fill(p);', + + `let a = [] + a = 2 + new Array(3).fill(a)`, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -121,11 +131,6 @@ test.snapshot({ 'Array.from({length: 3}).fill(createError(\'no\', \'yes\')[0])', 'const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)', - // ` - // const object = {} - // Array.from({length: 3}, () => object) - // `, - // Should not fill with function { code: 'new Array(3).fill(() => 1);', From a7b36db93b1a3d91b2c09fa9ca7cf132be8f2bee Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 18 Jun 2025 11:14:54 +0800 Subject: [PATCH 43/63] feat(no-array-fill-with-reference-type): report Array.from(arrayLike, () => sharedMap) --- rules/no-array-fill-with-reference-type.js | 96 +++++++++++++-- test/no-array-fill-with-reference-type.js | 56 +++++++-- .../no-array-fill-with-reference-type.js.md | 111 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 1701 -> 2110 bytes 4 files changed, 243 insertions(+), 20 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index c30ea086bd..7a6a7d63b4 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,5 +1,10 @@ +// @ts-check import {isFunction, isRegexLiteral} from './ast/index.js'; +/** + @typedef {any} Node + */ + // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { @@ -19,18 +24,22 @@ const log = (...arguments_) => debugging && console.log(...arguments_); /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { + // Array.fill or Array.from().fill const isArrayFill = node.callee.type === 'MemberExpression' && ((node.callee.object.callee?.name === 'Array') || (context.sourceCode.getText(node.callee.object.callee) === 'Array.from')) && node.callee.property.name === 'fill' && node.arguments.length > 0; - log('isArrayFill:', isArrayFill); + // Array.from().map Array.from(arrayLike, mapper) + const isArrayFrom = node.callee.type === 'MemberExpression' && node.callee.object?.name === 'Array' && node.callee.property.name === 'from'; + log('isArrayFill:', {isArrayFill, isArrayFrom}); - if (!isArrayFill) { + if (!isArrayFill && !isArrayFrom) { return; } - const fillArgument = node.arguments[0]; + const fillArgument = isArrayFill ? node.arguments[0] : getArrayFromReturnNode(node); + log('fillArgument:', fillArgument); if (!isReferenceType(fillArgument, context)) { @@ -51,6 +60,57 @@ const create = context => ({ }, }); +function getArrayFromReturnNode(node) { + const secondArgument = node.arguments[1]; + log('secondArgument:', secondArgument); + + // Array.from({ length: 10 }, () => { return sharedObject; }); + let result; + if (secondArgument && isFunction(secondArgument)) { + result = getReturnIdentifier(secondArgument); + } else if (node.parent.type === 'MemberExpression' && node.parent.property.name === 'map') { + // Array.from({ length: 10 }).map(() => { return sharedObject; }); + result = getReturnIdentifier(node.parent.parent.arguments[0]); + } + + // Should not check reference type if the identifier is declared in the current function + if (result?.declaredInCurrentFunction) { + return; + } + + const fillArgument = result?.returnNode; + + return fillArgument; +} + +/** + + @param {Node} node + @returns {{ returnNode: Node, declaredInCurrentFunction: boolean }} + */ +function getReturnIdentifier(node) { + if (node.body.type === 'Identifier') { + return {returnNode: node.body, declaredInCurrentFunction: false}; + } + + // Array.from({ length: 3 }, () => (new Map)) + // Array.from({ length: 3 }, () => ({})) + // Array.from({ length: 3 }, () => {}) + if (!node.body.body) { + return {returnNode: node.body, declaredInCurrentFunction: true}; + } + + const returnStatement = node.body.body.find(node => node.type === 'ReturnStatement'); + const name = returnStatement?.argument?.name; + if (!name) { + return {returnNode: returnStatement?.argument, declaredInCurrentFunction: true}; + } + + const declaredInCurrentFunction = node.body.body.some(node => node.type === 'VariableDeclaration' && node.declarations.some(declaration => declaration.id.name === name)); + + return {returnNode: returnStatement?.argument, declaredInCurrentFunction}; +} + /** @param {*} fillArgument @@ -181,6 +241,27 @@ function isReferenceType(node, context) { return true; } +/** + Variable can be declared in its parent or grandparent scope so we need to check all the scopes up to the global scope. + @param {{variableName: string; node: any; context: import('eslint').Rule.RuleContext}} params + @returns + */ +function findVariableDefinition({variableName, node, context}) { + if (!node) { + return; + } + + const scope = context.sourceCode.getScope(node); + const {variables} = scope; + const variable = variables.find(v => v.name === variableName); + + if (variable) { + return variable; + } + + return findVariableDefinition({variableName, node: node.parent, context}); +} + /** @param {*} node @@ -188,13 +269,10 @@ function isReferenceType(node, context) { @returns {boolean} */ function isIdentifierReferenceType(node, context) { - const {variables} = context.sourceCode.getScope(node); - const variable = variables.find(v => v.name === node.name); - const definitionNode = variable?.defs[0].node; + const variable = findVariableDefinition({variableName: node.name, node, context}); + const definitionNode = variable?.defs[0]?.node; - log('variables:', variables); - log('variable:', variable); - log('variable.defs[0].node:', definitionNode); + log({definitionNode}); if (!variable || !definitionNode) { return false; diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index bb02dfaba8..4175e6079a 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -22,22 +22,15 @@ test.snapshot({ 'Array.from({ length: 3 }, () => { return {} }); // ✓ Safe alternative', 'Array.from({ length: 3 }, () => (new Map)); // ✓ Safe alternative', 'Array.from({ length: 3 }, () => { return new Map }); // ✓ Safe alternative', - 'Array.from({ length: 3 }, () => { return new Map() }); // ✓ Safe alternative', + 'Array.from({ length: 33 }, () => { return new Map() }); // ✓ Safe alternative', 'Array(3).fill(0); // ✓ number (primitive)', 'new Foo(3).fill({}); // ✓ Not Array', 'Foo(3).fill({}); // ✓ Not Array', - // Below are the cases though have the same reference problem but are not covered by the rule. - // Due to the rule name it will not check other than `Array.fill`, even if `Array.from` also fills in reference variable. - // It cannot be exhaustively checked, we only check `Array.fill`. - 'const map = new Map(); Array.from({ length: 3 }, () => map);', - - ` - const object = {} - Array.from({length: 3}, () => object) - `, - + // Should be invalid but will pass. + // Due to the rule name it will not check other than `Array.fill` or `Array.from`. + // Too hard to implement exhaustive check. ` const map = new Map(); const list = []; @@ -76,9 +69,30 @@ test.snapshot({ 'const p = /pattern/; new Array(3).fill(p);', 'const p = new RegExp("pattern"); new Array(3).fill(p);', + // [undefined, undefined, undefined] + 'Array.from({ length: 3 }, () => {});', + `let a = [] a = 2 new Array(3).fill(a)`, + + // Valid because it returns a new map every time + ` + const map = new Map(); + const list = Array.from({ length: 3 }, () => { + const map = new Map(); + return map + }); + `, + + // It should be invalid because it return reference to the same map `outerMap`, but we cannot check every corner case + ` + const outerMap = new Map(); + const list = Array.from({ length: 3 }, () => { + const map = outerMap; + return map + }); + `, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -160,5 +174,25 @@ test.snapshot({ 'new Array(3).fill(new class {});', 'new Array(3).fill(new A.B());', 'const cls = new class {}; new Array(3).fill(cls);', + + 'const obj = {}; Array.from({ length: 3 }).fill(obj);', + + // Variable declared in parent scope + 'const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map);', + + // Variable declared in its grand parent scope + 'const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }', + 'function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }', + + // `initialArray` is filled with no reference type (literal string) but will be treated as such because it is a function calling + // we will not dive deep into the function body to check if it returns a reference type + 'function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }', + + ` + const object = {} + Array.from({length: 3}, () => object) + `, + + 'const object = {}; Array.from({length: 31}).map(() => object);', ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index fe20ec9f5f..d239c8ba74 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -503,3 +503,114 @@ Generated by [AVA](https://avajs.dev). > 1 | const cls = new class {}; new Array(3).fill(cls);␊ | ^^^ Avoid using \`Array.fill()\` with reference type (variable (cls)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` + +## invalid(29): const obj = {}; Array.from({ length: 3 }).fill(obj); + +> Input + + `␊ + 1 | const obj = {}; Array.from({ length: 3 }).fill(obj);␊ + ` + +> Error 1/1 + + `␊ + > 1 | const obj = {}; Array.from({ length: 3 }).fill(obj);␊ + | ^^^ Avoid using \`Array.from().fill()\` with reference type (variable (obj)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(30): const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map); + +> Input + + `␊ + 1 | const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map);␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map);␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(31): const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } + +> Input + + `␊ + 1 | const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + ` + +> Error 1/1 + + `␊ + > 1 | const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(32): function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } + +> Input + + `␊ + 1 | function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + ` + +> Error 1/1 + + `␊ + > 1 | function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(33): function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } + +> Input + + `␊ + 1 | function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + ` + +> Error 1/1 + + `␊ + > 1 | function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(34): const object = {} Array.from({length: 3}, () => object) + +> Input + + `␊ + 1 |␊ + 2 | const object = {}␊ + 3 | Array.from({length: 3}, () => object)␊ + 4 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | const object = {}␊ + > 3 | Array.from({length: 3}, () => object)␊ + | ^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (object)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 4 | ␊ + ` + +## invalid(35): const object = {}; Array.from({length: 31}).map(() => object); + +> Input + + `␊ + 1 | const object = {}; Array.from({length: 31}).map(() => object);␊ + ` + +> Error 1/1 + + `␊ + > 1 | const object = {}; Array.from({length: 31}).map(() => object);␊ + | ^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (object)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 3689e95a18804d3e7380f875877621a11d3132a7..fb996f626019854c6c7bb6719cbab3f0e35dab5f 100644 GIT binary patch literal 2110 zcmV-E2*LM3RzVFRTcK3rUFYKKsBtRMu8;|@e`~zq_@qh*h2_$|=On~gzH$L&b{+Xuk z@LLo6oRjX?bMd&=W(}mD@k`T<(=TKpAdxp3W0R+8_!!t2Vby z=lO@;=ZC);%FhKE006iR{_E;hn7^*cHP|*}wE^q)qn+o(b+{p$o1l|A(TQ3mVBTsH z5bRsT61-y&dcUr12`wmHNhJH zAJOp+UYNHJO?A6yo+MIMcY6LlZAi z+I8Gzh~ZH#!zE&R87>h<;>BU;+Cw9~M9lOIxt4c^VaMI>Gd$)pJjP@=+LTO_=;~;f z;bqb|bJLTGcN~oK2xEndk!zAQeNH2zBl*=lK+8r_s7mUhtSDDxbMrE3kekiIG}I-< zAbEgxe$BDgxY#shO*LFi>_?jTgRcpGnEe+-$8ZMJaLQG~ac)L;VigL`@D#*wWn4fI zUk^<1Q1b&($pNI2=W~HGM|j8)>aUcQm=i-5W|Y&ehNi@6sA{TVLK9|z=F<#g7@OfD zdJ8c=>4+$){eh_HAX3o_u8I=J%##uGim#*Vk}gXd3IU;+1sz?Yy@oL)BxcGb6xDkO z`I|mbCHFNDfz2X;mHYxr5q~VPJyyb_6Ihwu<+95+QytHY`ZG{rjQSW=)gs*In)$=F5or zIrqg9(+6V1hd+bhkI>gZdT%ja0*NKjo&9Mn84$-Z6~{zWaaf-0(d92~xk~~G( zyEI9xkNp~YA8F_kDr6)3^5Vk|nc6vlv~vVkpZ#zeLo<$UQcOOU#|((&2o;OfRE@uj zF^7aO<_ICp4#uAd^Fy~|mTLE6FYjE?t)}uZmyjEXLez%2ISmzPd&b2NX$nC)?1dC; zikXLb1n6%BD8yW(4CBDE42ye&*&)h|-`G4YnM4p7b87|BIv7~LJ4RS}^ax@4Ie0h1 zwZj9H^8M(T-+eH2`=LA)o=kz1P9jR<(Q+yn*-GwZ#O&EzwA6|MFb>TKnU*Q2i}bw8 zSPxV>R_;($bt0L>wjdN$tvCY3Tf``et7B^n#_W}JVh2p*C4~G{7V>ybA}D~l50FL> zyRU((R0CyN^vbGi%93J71+%ca#;OXvH?itp$^IhpDyrX(nVLbX{o%8?67Hw-NV5q~ zSt*KR6kY~q7=fyb-KFbwgre^WGE4<&=J*T=Vw4JkeI~H(glfgZPW|Hu z-65_PdMyn|2K$f}B}0?={XpOjvcA(X5urQG`nfT%>pHq(5Zsu@wbU zqSdg>sxO zw5p2XG~cTM`!`j^V1arAfto@KsThWtsZ~VuUc?KfIL3KI`B%CHkmWT4u;(f4?%_IZ z;~LD`gB8-2(l)NKc%MVOPaxj$Y%`HhAmj%z@|gDHQx5Z58orGb ov)J1(NaTg75A=`W!;`+&K{8K}VqV&VV(Hb$f8kl@&DBQ$0HFyA;{X5v literal 1701 zcmV;W23q++RzV}PJ00000000Bsnp?{pmdi-*l7amf0}>7i$a+^ckE=*7|-Wq>+7kUU+cI@zW=y!z2kkLqzO(3sA2C} z6pT*5o4rFU+N}EjUAt~s9SiEUIve#08}%{asP{gpqM@&&p+74fdTv5A{y(Gf|6V@+ zeJgSZ-j$NX;0at{1jdB~`gepBCJ}{-lmap%AhA&zLMVQdqrj$OaAZIN$iv_PjWR$J zLO=&ybrxzh_~DzcV0HU5+Hk^@mJp>0DJ9QV??M&(f0LwfmHm` z$GC_vj!Q90O^T+^8Dw;%yjcb~@Q@5Qh_S5c`p25HbBng=J#%;lT12;L8K7I<@~yR3 zO-Jh(Hq*ozq=`S}nvjQi^n&OaE`S=YGBsS5W^^xBW!N8{VKrVED+uD-kqI7a{#aCU z7OCW=Qsm4LA98~FD`zF<$54bBq_v^oQgj$u1s!W{5?niUMA884y_5aR`3L|N@0 zi;B)66}`+ExXfKc^sh&kxrfa6u8g|Y+hOpl2>fCscw{;R!*d{n{wjk0 zTr~6~PLcu7MB8;=1k^V;YPYM`aQ`+e5zG7kaL^S^lkDq0cM0=##Qa_MVoB)(v5~`{ zMes-XYaqY36fc3ylIYL=JeC58W1Wj*BB?msJM1UHrbq7?7F<{>ZKRcrG+GI{3^U}8 zh0=KsN#{x`>7;U=K}k8Lm_S&Amr}owo#ch=E@9=F*US?Q?=A@xWgqb*ac_q;^eNKN zO;pGx_7%j39SXH`1!?CZu0D^#X$sBwy2&y5xE>22mWy00Zc{b=F2+0(!l*BVJUbYF zAJke|-Q&x`R7=>4W8Ajpi z5_jo(Vbp`Q7i;+^Jrc)Fh~DLB=~JpoI{C|cM#JsbC+Ov`|A8d*qr5uk#}!i>q{hv{ zEdXDY^A#Vs^TX(h0FNOyZ^ZzXRMk&`uw)$-8CVSB6U~^P9vTy$**g@*K^KI$(H>Z- z7Ka;~I~MXArRNd)e`3)e3NlUwdFJ>638KaYAwCn>@AnK`6dt3OLE|dEaYHeweV~H={)@l_`WviCm=j?c_gX9k7)IQl{0q=c53Oco$_% zd|1%CQ(Y1tf=|;$@r{Vm@-c$*Q_Kl?-%c! Date: Wed, 18 Jun 2025 13:41:29 +0800 Subject: [PATCH 44/63] chore(no-array-fill-with-reference-type): fix npm run lint error --- test/no-array-fill-with-reference-type.js | 9 +++++++++ test/prefer-negative-index.js | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 4175e6079a..8b232c2180 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -93,6 +93,15 @@ test.snapshot({ return map }); `, + + ` + const error = { + messageId: 'prefer-negative-index', + }; + Array.from({length: 4}, () => { + return { ...error } + }); + `, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array diff --git a/test/prefer-negative-index.js b/test/prefer-negative-index.js index 205d5e9507..19727c63d0 100644 --- a/test/prefer-negative-index.js +++ b/test/prefer-negative-index.js @@ -166,6 +166,8 @@ test({ [NOT_EMPTY].slice.call(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); [NOT_EMPTY].splice.call(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); `, + // It's safe due to no mutation to `errors` + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 4}, () => error), output: outdent` [].slice.call(foo, - 1, - 2, foo.length - 3); @@ -190,6 +192,7 @@ test({ 'NOT_EMPTY'.slice.apply(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); 'NOT_EMPTY'.splice.apply(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); `, + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 2}, () => error), output: outdent` ''.slice.call(foo, - 1, - 2, foo.length - 3); @@ -239,6 +242,7 @@ test({ NOT_SUPPORTED.prototype.slice.call(foo, foo.length - 1, foo.length - 2, foo.length - 3); NOT_SUPPORTED.prototype.splice.call(foo, foo.length - 1, foo.length - 2, foo.length - 3); `, + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 16}, () => error), output: outdent` Array.prototype.slice.call(foo, - 1, - 2, foo.length - 3); @@ -312,6 +316,7 @@ test({ NOT_SUPPORTED.prototype.slice.apply(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); NOT_SUPPORTED.prototype.splice.apply(foo, [foo.length - 1, foo.length - 2, foo.length - 3]); `, + // eslint-disable-next-line unicorn/no-array-fill-with-reference-type errors: Array.from({length: 16}, () => error), output: outdent` Array.prototype.slice.apply(foo, [- 1, - 2, foo.length - 3]); From bc9f7f58b05cfb8edc55b46c1b40966df9478e14 Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 30 Jun 2025 10:30:39 +0800 Subject: [PATCH 45/63] refactor(no-array-fill-with-reference-type): rename options --- .../no-array-fill-with-reference-type.md | 12 +++++------ rules/no-array-fill-with-reference-type.js | 14 ++++++------ test/no-array-fill-with-reference-type.js | 20 +++++++++--------- .../no-array-fill-with-reference-type.js.md | 16 +++++++------- .../no-array-fill-with-reference-type.js.snap | Bin 2110 -> 2111 bytes 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index 5aa274f7de..a4b2e977cb 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -104,7 +104,7 @@ Array.from({ length: 3 }, () => []); ## Options -### canFillWithFunction +### allowFunctions Type: `boolean`\ Default: `true` @@ -121,18 +121,18 @@ new Array(3).fill(function () {}) "unicorn/catch-error-name": [ "error", { - "canFillWithFunction": false + "allowFunctions": false } ] ``` -with `canFillWithFunction: false`, this would fail: +with `allowFunctions: false`, this would fail: ```js new Array(3).fill(function () {}) ``` -### canFillWithRegexp +### allowRegularExpressions Type: `boolean`\ Default: `true` @@ -149,12 +149,12 @@ new Array(3).fill(/pattern/) "unicorn/catch-error-name": [ "error", { - "canFillWithRegexp": false + "allowRegularExpressions": false } ] ``` -with `canFillWithRegexp: false`, this would fail: +with `allowRegularExpressions: false`, this would fail: ```js new Array(3).fill(/pattern/) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 7a6a7d63b4..7163cd55b1 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -13,9 +13,9 @@ const messages = { const DEFAULTS = { // Not check for function expressions by default because it is rare to fill an array with a function and add properties to it. - canFillWithFunction: true, + allowFunctions: true, // The same reason as above. - canFillWithRegexp: true, + allowRegularExpressions: true, }; const debugging = false; @@ -200,7 +200,7 @@ function isReferenceType(node, context) { // For null, number, string, boolean. if (node.type === 'Literal') { // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). - if (!options.canFillWithRegexp && isRegexLiteral(node)) { + if (!options.allowRegularExpressions && isRegexLiteral(node)) { return true; } @@ -228,12 +228,12 @@ function isReferenceType(node, context) { } } - if (options.canFillWithFunction && isFunction(node)) { + if (options.allowFunctions && isFunction(node)) { return false; } const isNewRegexp = node.type === 'NewExpression' && node.callee.name === 'RegExp'; - if (options.canFillWithRegexp && isNewRegexp) { + if (options.allowRegularExpressions && isNewRegexp) { return false; } @@ -296,10 +296,10 @@ const schema = [ type: 'object', additionalProperties: false, properties: { - canFillWithFunction: { + allowFunctions: { type: 'boolean', }, - canFillWithRegexp: { + allowRegularExpressions: { type: 'boolean', }, }, diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 8b232c2180..49cd0da98e 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -50,11 +50,11 @@ test.snapshot({ });`, 'new Array(4).fill(function () {});', - // Set canFillWithFunction explicitly to true + // Set allowFunctions explicitly to true { code: 'new Array(41).fill(function () {});', options: [{ - canFillWithFunction: true, + allowFunctions: true, }], }, @@ -114,25 +114,25 @@ test.snapshot({ { code: 'new Array(3).fill(/pattern/); // ✗ RegExp', options: [{ - canFillWithRegexp: false, + allowRegularExpressions: false, }], }, { code: 'new Array(3).fill(new RegExp("pattern")); // ✗ RegExp', options: [{ - canFillWithRegexp: false, + allowRegularExpressions: false, }], }, { code: 'const p = /pattern/; new Array(3).fill(p); // ✗ RegExp', options: [{ - canFillWithRegexp: false, + allowRegularExpressions: false, }], }, { code: 'const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp', options: [{ - canFillWithRegexp: false, + allowRegularExpressions: false, }], }, @@ -158,25 +158,25 @@ test.snapshot({ { code: 'new Array(3).fill(() => 1);', options: [{ - canFillWithFunction: false, + allowFunctions: false, }], }, { code: 'new Array(3).fill(() => {});', options: [{ - canFillWithFunction: false, + allowFunctions: false, }], }, { code: 'new Array(3).fill(() => { return {} });', options: [{ - canFillWithFunction: false, + allowFunctions: false, }], }, { code: 'new Array(3).fill(function () {});', options: [{ - canFillWithFunction: false, + allowFunctions: false, }], }, diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index d239c8ba74..79135da6f9 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -107,7 +107,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithRegexp": false␊ + "allowRegularExpressions": false␊ }␊ ]␊ ` @@ -132,7 +132,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithRegexp": false␊ + "allowRegularExpressions": false␊ }␊ ]␊ ` @@ -157,7 +157,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithRegexp": false␊ + "allowRegularExpressions": false␊ }␊ ]␊ ` @@ -182,7 +182,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithRegexp": false␊ + "allowRegularExpressions": false␊ }␊ ]␊ ` @@ -372,7 +372,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithFunction": false␊ + "allowFunctions": false␊ }␊ ]␊ ` @@ -397,7 +397,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithFunction": false␊ + "allowFunctions": false␊ }␊ ]␊ ` @@ -422,7 +422,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithFunction": false␊ + "allowFunctions": false␊ }␊ ]␊ ` @@ -447,7 +447,7 @@ Generated by [AVA](https://avajs.dev). `␊ [␊ {␊ - "canFillWithFunction": false␊ + "allowFunctions": false␊ }␊ ]␊ ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index fb996f626019854c6c7bb6719cbab3f0e35dab5f..e15145ad1f901a118c536f4defd728a70ed34a27 100644 GIT binary patch literal 2111 zcmV-F2*CG2RzVOf44V%U7E;YhgdrZBuHT@f4lwrc1f-LF-Td zfr535P=vR2Lhskqok9zW#Uiwapdi4^EVMu)MpIKjQmUjulqyjSkQChzO;c@Q)B1ym zRWMW_ir&-+D5}ewzAb8`TC{(=w4iCK2BqPWGwOL~)JK`4-uX*l4Sfj>{Za1FQxmN5 z{}GM<1OE7Tt?(gOS40x~PvC?@pv)xD{e($j98t(~DIhZp5^I?OgyL5|3T!F>M+_u@ zJnTQ95eLv16Hu!yOvCUne0TR#Sl+ruDu$QRJfbwlrDWOaT*x8-D|!A!#D3uu^D*1U zDXn8O1;EA}VB_43S`r(kdY$1|5*uD<=Ml71zNzKdLxa2|Hkg_AB;xkSKhwCD0~0S+ z+I8Heh~X(N!xdt<8LkjU;zeQT*h3?|LX6}Lxt4c_VaMJ6Gn{Z3PB0k`H$=lAnljvF zc!ks#Zn{$Oj*W2+VJveoa!s!3cI0c$G=V;YzE1!=#^Q5UlB=ikCpuBWL9E#zpS#(&?Kc^$k%GMyld|7e&sEH zSC9r4{L9}S^PS7%gjo%9=ALAZLch)870I0_(g6P~h0kunnV&4GDwF&qS8|FpL`u)&qv!+Ss>n?W= z^Hs$BqVsx*=mW9g!=Fa*hv;h{xwi-}f!LDh&i*u(6o_M$ieoISILuF+Tinf%&NEJM zUai!TR@S0u#pBY;kUC~c=Ms|6nMl%!;%i6Qyo!PeB>lu5s}~nnaLJ zxFPwQV&-8M0s0#O3NRNc!#J=^!@>b!cAPTfw>r;@1}O-PxwVXF9rLZ<6_`v2Em4{bP9|SUy)BkdIpvRRE%Op$_Dm*RYJ~w9g=UCMOBK{b zdX8nJ2Pz#aXQ(O~5e;HlDC8A2KLq((M9&NBBO46H?3HwE2TbHeg!~m2@@P&%D1f;q zkVFvsuYs#n10`DYN{VDiqHIM4GqAqFstVmVvFcyZ`Xclys^5;8nnA1m!3($&?x*um zvk6aG35sJBUJ7QI0#z5gOVqpz+ePM5F8z zd_7^b+Q1}@cD^#hL8P&{-G;uFc^XmwCy;tid_e+8GO4FX3&T_k?8AXIJ5)0scEX=V z)Q)py&}(V;6>tbC;5WVkJfVeye~`J;9@i-UKw-shJhR#-rx2-v?}EH*C;35Zm#r|6 zVy(&2ow^VB5FNBGf75>o_`gg47iomE zZP3v(n}_i{GPSaXv~tmJ_b{f{SPI&W2_+?4 ziyu-!mBI>2szJffnnZvWyPFk?1hl=HyMr{>jH0=I1;v!*7f6;LN0MdV0_&r4{~yx6 zN2P7{1L=~gP7LexK{o&{yEa1XJh+<~@D)I40A_~5vwbr8=JB$$^Dpjdh}@*h6V0eaa-005>2^8Ek+ literal 2110 zcmV-E2*LM3RzVFRTcK3rUFYKKsBtRMu8;|@e`~zq_@qh*h2_$|=On~gzH$L&b{+Xuk z@LLo6oRjX?bMd&=W(}mD@k`T<(=TKpAdxp3W0R+8_!!t2Vby z=lO@;=ZC);%FhKE006iR{_E;hn7^*cHP|*}wE^q)qn+o(b+{p$o1l|A(TQ3mVBTsH z5bRsT61-y&dcUr12`wmHNhJH zAJOp+UYNHJO?A6yo+MIMcY6LlZAi z+I8Gzh~ZH#!zE&R87>h<;>BU;+Cw9~M9lOIxt4c^VaMI>Gd$)pJjP@=+LTO_=;~;f z;bqb|bJLTGcN~oK2xEndk!zAQeNH2zBl*=lK+8r_s7mUhtSDDxbMrE3kekiIG}I-< zAbEgxe$BDgxY#shO*LFi>_?jTgRcpGnEe+-$8ZMJaLQG~ac)L;VigL`@D#*wWn4fI zUk^<1Q1b&($pNI2=W~HGM|j8)>aUcQm=i-5W|Y&ehNi@6sA{TVLK9|z=F<#g7@OfD zdJ8c=>4+$){eh_HAX3o_u8I=J%##uGim#*Vk}gXd3IU;+1sz?Yy@oL)BxcGb6xDkO z`I|mbCHFNDfz2X;mHYxr5q~VPJyyb_6Ihwu<+95+QytHY`ZG{rjQSW=)gs*In)$=F5or zIrqg9(+6V1hd+bhkI>gZdT%ja0*NKjo&9Mn84$-Z6~{zWaaf-0(d92~xk~~G( zyEI9xkNp~YA8F_kDr6)3^5Vk|nc6vlv~vVkpZ#zeLo<$UQcOOU#|((&2o;OfRE@uj zF^7aO<_ICp4#uAd^Fy~|mTLE6FYjE?t)}uZmyjEXLez%2ISmzPd&b2NX$nC)?1dC; zikXLb1n6%BD8yW(4CBDE42ye&*&)h|-`G4YnM4p7b87|BIv7~LJ4RS}^ax@4Ie0h1 zwZj9H^8M(T-+eH2`=LA)o=kz1P9jR<(Q+yn*-GwZ#O&EzwA6|MFb>TKnU*Q2i}bw8 zSPxV>R_;($bt0L>wjdN$tvCY3Tf``et7B^n#_W}JVh2p*C4~G{7V>ybA}D~l50FL> zyRU((R0CyN^vbGi%93J71+%ca#;OXvH?itp$^IhpDyrX(nVLbX{o%8?67Hw-NV5q~ zSt*KR6kY~q7=fyb-KFbwgre^WGE4<&=J*T=Vw4JkeI~H(glfgZPW|Hu z-65_PdMyn|2K$f}B}0?={XpOjvcA(X5urQG`nfT%>pHq(5Zsu@wbU zqSdg>sxO zw5p2XG~cTM`!`j^V1arAfto@KsThWtsZ~VuUc?KfIL3KI`B%CHkmWT4u;(f4?%_IZ z;~LD`gB8-2(l)NKc%MVOPaxj$Y%`HhAmj%z@|gDHQx5Z58orGb ov)J1(NaTg75A=`W!;`+&K{8K}VqV&VV(Hb$f8kl@&DBQ$0HFyA;{X5v From b87ec58984654370a3182938f5d245677df53c23 Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 30 Jun 2025 11:39:55 +0800 Subject: [PATCH 46/63] refactor(no-array-fill-with-reference-type): use existing util isMemberExpression --- rules/no-array-fill-with-reference-type.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 7163cd55b1..d386b40c01 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,5 +1,5 @@ // @ts-check -import {isFunction, isRegexLiteral} from './ast/index.js'; +import {isFunction, isMemberExpression, isRegexLiteral} from './ast/index.js'; /** @typedef {any} Node @@ -24,14 +24,14 @@ const log = (...arguments_) => debugging && console.log(...arguments_); /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { - // Array.fill or Array.from().fill - const isArrayFill = node.callee.type === 'MemberExpression' + // `arr.fill` or `new Array().fill` or `Array.from().fill` + const isArrayFill = isMemberExpression(node.callee) && ((node.callee.object.callee?.name === 'Array') || (context.sourceCode.getText(node.callee.object.callee) === 'Array.from')) && node.callee.property.name === 'fill' && node.arguments.length > 0; - // Array.from().map Array.from(arrayLike, mapper) - const isArrayFrom = node.callee.type === 'MemberExpression' && node.callee.object?.name === 'Array' && node.callee.property.name === 'from'; + // `Array.from().map` or `Array.from(arrayLike, mapper)` + const isArrayFrom = isMemberExpression(node.callee) && node.callee.object?.name === 'Array' && node.callee.property.name === 'from'; log('isArrayFill:', {isArrayFill, isArrayFrom}); if (!isArrayFill && !isArrayFrom) { From 05893d17f38157e9820c78c7a114148eb15fd879 Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 30 Jun 2025 17:02:57 +0800 Subject: [PATCH 47/63] fix(no-array-fill-with-reference-type): fix integration failed when callback is a function variable --- rules/no-array-fill-with-reference-type.js | 34 ++++++++-- test/no-array-fill-with-reference-type.js | 63 ++++++++++++++++++ .../no-array-fill-with-reference-type.js.md | 43 ++++++++++++ .../no-array-fill-with-reference-type.js.snap | Bin 2111 -> 2362 bytes 4 files changed, 134 insertions(+), 6 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index d386b40c01..68bd03772f 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,4 +1,5 @@ // @ts-check +import {findVariable} from '@eslint-community/eslint-utils'; import {isFunction, isMemberExpression, isRegexLiteral} from './ast/index.js'; /** @@ -38,7 +39,7 @@ const create = context => ({ return; } - const fillArgument = isArrayFill ? node.arguments[0] : getArrayFromReturnNode(node); + const fillArgument = isArrayFill ? node.arguments[0] : getArrayFromReturnNode(node, context); log('fillArgument:', fillArgument); @@ -60,17 +61,17 @@ const create = context => ({ }, }); -function getArrayFromReturnNode(node) { +function getArrayFromReturnNode(node, context) { const secondArgument = node.arguments[1]; log('secondArgument:', secondArgument); // Array.from({ length: 10 }, () => { return sharedObject; }); let result; if (secondArgument && isFunction(secondArgument)) { - result = getReturnIdentifier(secondArgument); + result = getReturnIdentifier(secondArgument, context); } else if (node.parent.type === 'MemberExpression' && node.parent.property.name === 'map') { // Array.from({ length: 10 }).map(() => { return sharedObject; }); - result = getReturnIdentifier(node.parent.parent.arguments[0]); + result = getReturnIdentifier(node.parent.parent.arguments[0], context); } // Should not check reference type if the identifier is declared in the current function @@ -85,10 +86,31 @@ function getArrayFromReturnNode(node) { /** - @param {Node} node + @param {Node} node - callback for map @returns {{ returnNode: Node, declaredInCurrentFunction: boolean }} */ -function getReturnIdentifier(node) { +function getReturnIdentifier(node, context) { + if (node.type === 'Identifier') { + const scope = context.sourceCode.getScope(node); + + const variable = findVariable(scope, node); + + if (!variable) { + // Not check if the identifier is not declared + return {returnNode: node, declaredInCurrentFunction: true}; + } + + // Must be ArrowFunctionExpression or FunctionExpression + const {init} = variable.defs[0].node; + + if (!isFunction(init)) { + // Not check if the identifier is not a function + return {returnNode: node, declaredInCurrentFunction: true}; + } + + return getReturnIdentifier(init, context); + } + if (node.body.type === 'Identifier') { return {returnNode: node.body, declaredInCurrentFunction: false}; } diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 49cd0da98e..c7ec6476a8 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -102,6 +102,51 @@ test.snapshot({ return { ...error } }); `, + + // Case from integration failed test + // https://github.com/sindresorhus/eslint-plugin-unicorn/actions/runs/15963375449/job/45019476320?pr=2661#step:5:139 + ` + import { ref } from 'vue' + + let id = 0 + + const dataGenerator = () => ({ + id: \`random-id-$\{++id}\`, + name: 'Tom', + date: '2020-10-1', + }) + + const data = ref(Array.from({ length: 200 }).map(dataGenerator)) + `, + + // Not crash for variable `dataGenerator404` not found + (` + import { ref } from 'vue' + + let id = 0 + + const dataGenerator = () => ({ + id: \`random-id-$\{++id}\`, + name: 'Tom', + date: '2020-10-1', + }) + + const data = ref(Array.from({ length: 200 }).map(dataGenerator404)) + `), + + (` + import { ref } from 'vue' + + let id = 0 + + const dataGenerator = { + id: \`random-id-$\{++id}\`, + name: 'Tom', + date: '2020-10-1', + } + + const data = ref(Array.from({ length: 200 }).map(dataGenerator)) + `), ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -203,5 +248,23 @@ test.snapshot({ `, 'const object = {}; Array.from({length: 31}).map(() => object);', + + // Case from integration failed test + // https://github.com/sindresorhus/eslint-plugin-unicorn/actions/runs/15963375449/job/45019476320?pr=2661#step:5:139 + ` + import { ref } from 'vue' + + let id = 0 + + const sharedObj = { + id: \`random-id-$\{++id}\`, + name: 'Tom', + date: '2020-10-1', + } + + const dataGenerator = () => (sharedObj) + + const data = ref(Array.from({ length: 200 }).map(dataGenerator)) + `, ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 79135da6f9..80cd8d9ada 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -614,3 +614,46 @@ Generated by [AVA](https://avajs.dev). > 1 | const object = {}; Array.from({length: 31}).map(() => object);␊ | ^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (object)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` + +## invalid(36): import { ref } from 'vue' let id = 0 const sharedObj = { id: `random-id-${++id}`, name: 'Tom', date: '2020-10-1', } const dataGenerator = () => (sharedObj) const data = ref(Array.from({ length: 200 }).map(dataGenerator)) + +> Input + + `␊ + 1 |␊ + 2 | import { ref } from 'vue'␊ + 3 |␊ + 4 | let id = 0␊ + 5 |␊ + 6 | const sharedObj = {␊ + 7 | id: \`random-id-${++id}\`,␊ + 8 | name: 'Tom',␊ + 9 | date: '2020-10-1',␊ + 10 | }␊ + 11 |␊ + 12 | const dataGenerator = () => (sharedObj)␊ + 13 |␊ + 14 | const data = ref(Array.from({ length: 200 }).map(dataGenerator))␊ + 15 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | import { ref } from 'vue'␊ + 3 |␊ + 4 | let id = 0␊ + 5 |␊ + 6 | const sharedObj = {␊ + 7 | id: \`random-id-${++id}\`,␊ + 8 | name: 'Tom',␊ + 9 | date: '2020-10-1',␊ + 10 | }␊ + 11 |␊ + > 12 | const dataGenerator = () => (sharedObj)␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (sharedObj)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 13 |␊ + 14 | const data = ref(Array.from({ length: 200 }).map(dataGenerator))␊ + 15 | ␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index e15145ad1f901a118c536f4defd728a70ed34a27..23a2316146eb9bddf456bd2d496020c214d0b806 100644 GIT binary patch literal 2362 zcmV-A3B~q7RzVxEk00000000B!o8NES))mJs7ex{62QXkL3Jlv0)C3|MTNWidj_ufs(9mJ1R9b zl6Tx6MD2oO0x|4?MZhpa-t4=oMY;|D-L*@WWm=#tC_&ciLDpN`tb4y?Ug{N;`WJ<% zXC`?0{~OBxr{esNt%xDGM@AAyPvCSwpv@&PKEtK3gecU76p$GXiS5b^Lh+3l1vZs{ zBL@;d9*!PRGXS*61vDJVYp}2YpMUs1T;IJ%I!=_*1w?64NXfP39mpa8uXz58h0zi8-}NzWB8+VzMxjYw^LZW_ZB=ho0fsJ;nyTyOgBxUTpsUuUhkc9K zwq_c3Z54W|Zj&m&sCwJCxp%$q(2IdGo<+*|hgccnV5ct&&u|Ge@p7Pvv%YB0{>b>TKRn)qRiHj%ol{ln_N02R*QfO&cw{;P!*#%g{xbyqhw;$UI7tUQ7j5dk45+U#)O5D5Lth&%sFwTwFdXrk z$>8#syMXx?VtzIFykzu&*ofh;A^3CbGf>=HhL1pQNsL>67E1}lvBku(m{uJ0OmIth zGQ@i(2rjCXJ*1WGELw@Uj51`7xzc$RN#|T9>11-ALrDdim{3?pFQsvJc8PUo_tl_# z=1%hQ(z~yQI%U6MMM6(UHS`YB&>N^bo7z_xA9l#q&N-x=dEEP)hSLn1@pV(6@u40| zAeMP17CPCQeRX3438Co=p~%X{KN039!5mtlRgL4kqQRD+l;wa>5Qt8UJ?HK!v|$v= zOBB)yf^<3zDc%&f4yy>zzY(AWbEzs!0E-%yj|sDv7&Gxy=S9^alFVsa+lbbw*#5h3 zgjYx3BTQe#uTlhdM1Tr@AAR#j4~8vEC@aau6iaDxiX~M|#UtCU{2Vd+aV1@8r2&|Q zW{OHH71YaYA4_urD$7-ns*XiehqxA`x?$Gmp#F&1b@^8FHit2PB%Rv<7kL9A|0NH3 zHYX_*z+Dq4B8a2cz#XOmg>`y0Lvu7$ccX%JxOJP?D-7Sn>;J0mh18>{X*=d>295S- zui&2WG@YkvO+?Bn&^boom7s-@n7a70bY2)rxbGEA{HNV2$4v0P<;%#39GTC*JTN*= z%4z(q?~r=F5O)m5AtiJRGLsJCEdg4Yq2=$v^TQbN*tQUslL>4E9qQ@A6^x!@V@jZV ztnsqFL@oXfzKJk~BjA!oD_@m`B+}U2K||lJ{0LG1Pa^e+_>u%rq){)C78aNm_?rWJ zeyB7ae!-tb)Ls(GVA9gTE8rQVfN#YLh=i67{&D8c=D1qo4TT+l;+Z#nat4u-Vh7}7 zJHG$QjM;;Kd*J?PYzF?*1DseIWW|HvI_M# z&HefubXAA`Xf<2Sd8Ik8)aTguhoXLk7{pQ?(}H#X^(E#-4&4XqG(L&@1!^^$-~&e{ zIs3x4D+W^5JGABTn;yUI5$1#5()RB3ig27CdTz!3K48% gN08=|HI2Of44V%U7E;YhgdrZBuHT@f4lwrc1f-LF-Td zfr535P=vR2Lhskqok9zW#Uiwapdi4^EVMu)MpIKjQmUjulqyjSkQChzO;c@Q)B1ym zRWMW_ir&-+D5}ewzAb8`TC{(=w4iCK2BqPWGwOL~)JK`4-uX*l4Sfj>{Za1FQxmN5 z{}GM<1OE7Tt?(gOS40x~PvC?@pv)xD{e($j98t(~DIhZp5^I?OgyL5|3T!F>M+_u@ zJnTQ95eLv16Hu!yOvCUne0TR#Sl+ruDu$QRJfbwlrDWOaT*x8-D|!A!#D3uu^D*1U zDXn8O1;EA}VB_43S`r(kdY$1|5*uD<=Ml71zNzKdLxa2|Hkg_AB;xkSKhwCD0~0S+ z+I8Heh~X(N!xdt<8LkjU;zeQT*h3?|LX6}Lxt4c_VaMJ6Gn{Z3PB0k`H$=lAnljvF zc!ks#Zn{$Oj*W2+VJveoa!s!3cI0c$G=V;YzE1!=#^Q5UlB=ikCpuBWL9E#zpS#(&?Kc^$k%GMyld|7e&sEH zSC9r4{L9}S^PS7%gjo%9=ALAZLch)870I0_(g6P~h0kunnV&4GDwF&qS8|FpL`u)&qv!+Ss>n?W= z^Hs$BqVsx*=mW9g!=Fa*hv;h{xwi-}f!LDh&i*u(6o_M$ieoISILuF+Tinf%&NEJM zUai!TR@S0u#pBY;kUC~c=Ms|6nMl%!;%i6Qyo!PeB>lu5s}~nnaLJ zxFPwQV&-8M0s0#O3NRNc!#J=^!@>b!cAPTfw>r;@1}O-PxwVXF9rLZ<6_`v2Em4{bP9|SUy)BkdIpvRRE%Op$_Dm*RYJ~w9g=UCMOBK{b zdX8nJ2Pz#aXQ(O~5e;HlDC8A2KLq((M9&NBBO46H?3HwE2TbHeg!~m2@@P&%D1f;q zkVFvsuYs#n10`DYN{VDiqHIM4GqAqFstVmVvFcyZ`Xclys^5;8nnA1m!3($&?x*um zvk6aG35sJBUJ7QI0#z5gOVqpz+ePM5F8z zd_7^b+Q1}@cD^#hL8P&{-G;uFc^XmwCy;tid_e+8GO4FX3&T_k?8AXIJ5)0scEX=V z)Q)py&}(V;6>tbC;5WVkJfVeye~`J;9@i-UKw-shJhR#-rx2-v?}EH*C;35Zm#r|6 zVy(&2ow^VB5FNBGf75>o_`gg47iomE zZP3v(n}_i{GPSaXv~tmJ_b{f{SPI&W2_+?4 ziyu-!mBI>2szJffnnZvWyPFk?1hl=HyMr{>jH0=I1;v!*7f6;LN0MdV0_&r4{~yx6 zN2P7{1L=~gP7LexK{o&{yEa1XJh+<~@D)I40A_~5vwbr8=JB$$^Dpjdh}@*h6V0eaa-005>2^8Ek+ From 88b4528baacb4178e568c8b7af7b449331dcfc81 Mon Sep 17 00:00:00 2001 From: legend80s Date: Tue, 1 Jul 2025 10:59:04 +0800 Subject: [PATCH 48/63] test(no-array-fill-with-reference-type): fix integration test failed on global functions as map callback --- rules/no-array-fill-with-reference-type.js | 7 +-- test/no-array-fill-with-reference-type.js | 63 ++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 68bd03772f..d078cbf9fa 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -101,9 +101,10 @@ function getReturnIdentifier(node, context) { } // Must be ArrowFunctionExpression or FunctionExpression - const {init} = variable.defs[0].node; + const init = variable.defs[0]?.node?.init; - if (!isFunction(init)) { + // `init` will be undefined if the identifier is builtin globals like String + if (!init || !isFunction(init)) { // Not check if the identifier is not a function return {returnNode: node, declaredInCurrentFunction: true}; } @@ -302,7 +303,7 @@ function isIdentifierReferenceType(node, context) { // Check `const foo = []; Array(3).fill(foo);` if (definitionNode.type === 'VariableDeclarator') { - // Not check `let` + // Not check `let` `let foo = []; Array(3).fill(foo);` if (definitionNode.parent.kind === 'let') { return false; } diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index c7ec6476a8..7267028f54 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -76,6 +76,9 @@ test.snapshot({ a = 2 new Array(3).fill(a)`, + // Not check `let` variables even if it is reference value but it can be reassigned + 'let foo = []; Array(3).fill(foo);', + // Valid because it returns a new map every time ` const map = new Map(); @@ -147,6 +150,66 @@ test.snapshot({ const data = ref(Array.from({ length: 200 }).map(dataGenerator)) `), + + // https://github.com/vercel/next.js/blob/canary/packages/next/src/build/turborepo-access-trace/result.ts#L33C11-L33C47 + 'Array.from(this.fsPaths).map(String)', + // https://github.com/angular/angular/blob/main/devtools/projects/ng-devtools-backend/src/lib/component-tree/component-tree.ts#L553 + ` + import { + buildDirectiveTree, + getLViewFromDirectiveOrElementInstance, + } from '../directive-forest/index'; + + export const buildDirectiveForest = () => { + const roots = getRoots(); + return Array.prototype.concat.apply([], Array.from(roots).map(buildDirectiveTree)); + };`, + + // https://github.com/microsoft/vscode/blob/main/src/vs/base/test/common/map.test.ts#L527 + 'assert.deepStrictEqual(Array.from(map.keys()).map(String), [fileA].map(String));', + + // Will not check this even if sharedObj is a reference type + ` + const foo = 1, sharedObj = { + name: 'Tom', + date: '2020-10-1', + }; + + let dataGenerator = () => 1; // because findVariable only find the first variable + + dataGenerator = () => (sharedObj); + + const data = Array.from({ length: 200 }).map(dataGenerator) + `, + + // This is valid since sharedObj is overwritten to a primitive value. + ` + let sharedObj = { + name: 'Tom', + date: '2020-10-1', + }; + + sharedObj = 1; + + let dataGenerator = () => sharedObj; + + const data = Array.from({ length: 200 }).map(dataGenerator) + `, + + // This should be invalid since sharedObj is overwritten to a reference value. + // but we will not check this corner case. + ` + let sharedObj = 1; + + sharedObj = { + name: 'Tom', + date: '2020-10-1', + }; + + // let dataGenerator = () => sharedObj; + + const data = Array.from({ length: 200 }).map(() => sharedObj); + `, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array From ed1f6ae115b43c9a0f32f05d88e853932e6fef2c Mon Sep 17 00:00:00 2001 From: legend80s Date: Tue, 1 Jul 2025 11:22:37 +0800 Subject: [PATCH 49/63] test(no-array-fill-with-reference-type): fix integration test failed. No check member expression as callback. --- rules/no-array-fill-with-reference-type.js | 7 +++++++ test/no-array-fill-with-reference-type.js | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index d078cbf9fa..a7791e26a3 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -112,6 +112,13 @@ function getReturnIdentifier(node, context) { return getReturnIdentifier(init, context); } + // Console.log('node:', node); + + // No check member expression as callback `Array.from(element.querySelectorAll('ng2 li')).map(angular.element);` + if (!node.body) { + return {returnNode: node, declaredInCurrentFunction: true}; + } + if (node.body.type === 'Identifier') { return {returnNode: node.body, declaredInCurrentFunction: false}; } diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 7267028f54..23868442f4 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -210,6 +210,12 @@ test.snapshot({ const data = Array.from({ length: 200 }).map(() => sharedObj); `, + + // https://github.com/angular/angular/blob/main/packages/upgrade/src/dynamic/test/upgrade_spec.ts#L800 + ` + const ng2Descendants = Array.from(element.querySelectorAll('ng2 li')).map( + angular.element, + );`, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array From 5e9494e75bc3d39ac6d59d41c9c9c6a975024142 Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 16 Jul 2025 16:23:29 +0800 Subject: [PATCH 50/63] fix: correct return type for isMemberExpression function & add type predicat to it --- rules/ast/is-member-expression.d.ts | 16 ++++++++++++++++ rules/ast/is-member-expression.js | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 rules/ast/is-member-expression.d.ts diff --git a/rules/ast/is-member-expression.d.ts b/rules/ast/is-member-expression.d.ts new file mode 100644 index 0000000000..69994ea620 --- /dev/null +++ b/rules/ast/is-member-expression.d.ts @@ -0,0 +1,16 @@ +import type { Node, MemberExpression } from "estree"; + +export default function isMemberExpression( + node: Node, + options?: + | { + property?: string; + properties?: string[]; + object?: string; + objects?: string[]; + optional?: boolean; + computed?: boolean; + } + | string + | string[] +): node is MemberExpression; diff --git a/rules/ast/is-member-expression.js b/rules/ast/is-member-expression.js index 9507cfd13a..453ef7580a 100644 --- a/rules/ast/is-member-expression.js +++ b/rules/ast/is-member-expression.js @@ -1,5 +1,7 @@ +// @ts-check /* eslint-disable complexity */ /** +@param {ESTreeNode} node @param { { property?: string, @@ -10,7 +12,7 @@ computed?: boolean } | string | string[] } [options] -@returns {string} +@returns {boolean} */ export default function isMemberExpression(node, options) { if (node?.type !== 'MemberExpression') { @@ -96,3 +98,5 @@ export default function isMemberExpression(node, options) { return true; } + +/** @typedef {import('estree').Node} ESTreeNode */ From 4bddea97daf364db5342b13749688c5abd9cbb4e Mon Sep 17 00:00:00 2001 From: legend80s Date: Wed, 16 Jul 2025 16:58:06 +0800 Subject: [PATCH 51/63] feat(no-array-fill-with-reference-type): check is member expression is reference type & not check symbol & show precise type in tips --- rules/no-array-fill-with-reference-type.js | 293 ++++++++++++++---- test/no-array-fill-with-reference-type.js | 76 ++++- .../no-array-fill-with-reference-type.js.md | 238 +++++++++++--- .../no-array-fill-with-reference-type.js.snap | Bin 2362 -> 2755 bytes test/string-content.js | 2 - 5 files changed, 494 insertions(+), 115 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index a7791e26a3..a52e5ce575 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -1,10 +1,11 @@ // @ts-check import {findVariable} from '@eslint-community/eslint-utils'; -import {isFunction, isMemberExpression, isRegexLiteral} from './ast/index.js'; +import { + isCallExpression, + isFunction, isMemberExpression, isMethodCall, isNewExpression, isRegexLiteral, +} from './ast/index.js'; -/** - @typedef {any} Node - */ +const debugging = false; // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; @@ -19,20 +20,20 @@ const DEFAULTS = { allowRegularExpressions: true, }; -const debugging = false; const log = (...arguments_) => debugging && console.log(...arguments_); +const RECURSION_LIMIT = 5; + /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ CallExpression(node) { - // `arr.fill` or `new Array().fill` or `Array.from().fill` - const isArrayFill = isMemberExpression(node.callee) - && ((node.callee.object.callee?.name === 'Array') || (context.sourceCode.getText(node.callee.object.callee) === 'Array.from')) - && node.callee.property.name === 'fill' - && node.arguments.length > 0; + // Check all `fill` method call even if the object is not Array because we don't know if its runtime type is array + // `arr.fill()` or `new Array().fill()` or `Array.from().fill()` + const isArrayFill = isMethodCall(node, {method: 'fill', argumentsLength: 1}); // `Array.from().map` or `Array.from(arrayLike, mapper)` - const isArrayFrom = isMemberExpression(node.callee) && node.callee.object?.name === 'Array' && node.callee.property.name === 'from'; + const isArrayFrom = isMethodCall(node, {object: 'Array', method: 'from'}); + log('isArrayFill:', {isArrayFill, isArrayFrom}); if (!isArrayFill && !isArrayFrom) { @@ -43,12 +44,14 @@ const create = context => ({ log('fillArgument:', fillArgument); - if (!isReferenceType(fillArgument, context)) { + const [is, resolvedNode] = isReferenceType(fillArgument, context); + + if (!is) { return; } - const actual = context.sourceCode.getText(node.callee.object.callee) === 'Array.from' ? 'Array.from().fill()' : 'Array.fill()'; - const type = getType(fillArgument, context); + const actual = isMethodCall(node.callee.object, {object: 'Array', method: 'from'}) ? 'Array.from().fill()' : 'Array.fill()'; + const type = getType(resolvedNode, context); return { node: fillArgument, @@ -61,6 +64,12 @@ const create = context => ({ }, }); +/** + + @param {import('estree').CallExpression} node + @param {RuleContext} context + @returns + */ function getArrayFromReturnNode(node, context) { const secondArgument = node.arguments[1]; log('secondArgument:', secondArgument); @@ -69,8 +78,10 @@ function getArrayFromReturnNode(node, context) { let result; if (secondArgument && isFunction(secondArgument)) { result = getReturnIdentifier(secondArgument, context); - } else if (node.parent.type === 'MemberExpression' && node.parent.property.name === 'map') { + // @ts-expect-error node always has a parent + } else if (isMemberExpression(node.parent, 'map')) { // Array.from({ length: 10 }).map(() => { return sharedObject; }); + // @ts-expect-error node always has a parent result = getReturnIdentifier(node.parent.parent.arguments[0], context); } @@ -86,7 +97,7 @@ function getArrayFromReturnNode(node, context) { /** - @param {Node} node - callback for map + @param {import('estree').FunctionExpression | Node} node - callback for map @returns {{ returnNode: Node, declaredInCurrentFunction: boolean }} */ function getReturnIdentifier(node, context) { @@ -114,75 +125,72 @@ function getReturnIdentifier(node, context) { // Console.log('node:', node); + // @ts-expect-error node is FunctionExpression + const {body: nodeBody} = node; + // No check member expression as callback `Array.from(element.querySelectorAll('ng2 li')).map(angular.element);` - if (!node.body) { + if (!nodeBody) { return {returnNode: node, declaredInCurrentFunction: true}; } - if (node.body.type === 'Identifier') { - return {returnNode: node.body, declaredInCurrentFunction: false}; + if (nodeBody.type === 'Identifier') { + return {returnNode: nodeBody, declaredInCurrentFunction: false}; } // Array.from({ length: 3 }, () => (new Map)) // Array.from({ length: 3 }, () => ({})) // Array.from({ length: 3 }, () => {}) - if (!node.body.body) { - return {returnNode: node.body, declaredInCurrentFunction: true}; + if (!nodeBody.body) { + return {returnNode: nodeBody, declaredInCurrentFunction: true}; } - const returnStatement = node.body.body.find(node => node.type === 'ReturnStatement'); + const returnStatement = nodeBody.body.find(node => node.type === 'ReturnStatement'); const name = returnStatement?.argument?.name; if (!name) { return {returnNode: returnStatement?.argument, declaredInCurrentFunction: true}; } - const declaredInCurrentFunction = node.body.body.some(node => node.type === 'VariableDeclaration' && node.declarations.some(declaration => declaration.id.name === name)); + const declaredInCurrentFunction = nodeBody.body.some(node => node.type === 'VariableDeclaration' && node.declarations.some(declaration => declaration.id.name === name)); return {returnNode: returnStatement?.argument, declaredInCurrentFunction}; } /** - @param {*} fillArgument @param {import('eslint').Rule.RuleContext} context @returns {string} */ function getType(fillArgument, context) { - let type = ''; - switch (fillArgument.type) { case 'ObjectExpression': { - type = 'Object'; - break; + return 'Object'; } case 'ArrayExpression': { - type = 'Array'; - break; + return 'Array'; } case 'NewExpression': { - type = getNewExpressionType(fillArgument, context); - - break; + return getNewExpressionType(fillArgument, context); } case 'FunctionExpression': case 'ArrowFunctionExpression': { - type = 'Function'; - break; + return 'Function'; } default: { if (fillArgument.type === 'Literal' && fillArgument.regex) { - type = 'RegExp'; - } else if (fillArgument.type === 'Identifier') { - type = `variable (${fillArgument.name})`; + return 'RegExp'; + } + + if (fillArgument.type === 'Identifier') { + return `variable (${fillArgument.name})`; } } } - return type; + return ''; } /** @@ -210,18 +218,17 @@ function getNewExpressionType(fillArgument, context) { } /** - @param {*} node + @param {Node} node @param {import('eslint').Rule.RuleContext} context - @returns + @returns {[is: false] | [is: true, node: Node]} */ function isReferenceType(node, context) { + log('[isReferenceType]: ', node); if (!node) { - return false; + return [false]; } - /** - @type {typeof DEFAULTS} - */ + /** @type {typeof DEFAULTS} */ const options = { ...DEFAULTS, ...context.options[0], @@ -231,15 +238,15 @@ function isReferenceType(node, context) { if (node.type === 'Literal') { // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). if (!options.allowRegularExpressions && isRegexLiteral(node)) { - return true; + return [true, node]; } - return false; + return [false]; } // For template literals. if (node.type === 'TemplateLiteral') { - return false; + return [false]; } // For variable identifiers (recursively check its declaration). @@ -247,28 +254,161 @@ function isReferenceType(node, context) { return isIdentifierReferenceType(node, context); } - // Symbol (such as `Symbol('name')`) - if (node.type === 'CallExpression' && node.callee.name === 'Symbol') { - const {variables} = context.sourceCode.getScope(node); - - log('variables 2:', variables); - if (!variables || variables.length === 0) { - // Variable declaration not found; it might be a global variable. - return false; - } + if (isSymbol(node)) { + return [false]; } if (options.allowFunctions && isFunction(node)) { - return false; + return [false]; } - const isNewRegexp = node.type === 'NewExpression' && node.callee.name === 'RegExp'; - if (options.allowRegularExpressions && isNewRegexp) { - return false; + if (options.allowRegularExpressions && isNewExpression(node, 'RegExp')) { + return [false]; + } + + if (isMemberExpression(node)) { + const propertyNode = getMemberExpressionLeafNode(node, context); + if (!propertyNode) { + return [false]; + } + + return isReferenceType(propertyNode, context); } // Other cases: objects, arrays, new expressions, regular expressions, etc. - return true; + return [true, node]; +} + +/** + Get member expression leaf node + like get nested object property in plain object but in ESLint AST Node + @param {MemberExpression} node - The whole member expression node + @param {RuleContext} context - ESLint rule context + @returns {undefined | ESTreeNode} - The leaf node + @example + // pseudo code + const obj = { a: { b: { c: { list: [] } } } }; + obj.a.b.c.list // => [] + */ +function getMemberExpressionLeafNode(node, context) { + const chain = getPropertyAccessChain(node); + + if (!chain || chain.length === 0) { + return; + } + + // The chain names: [ 'obj', 'a', 'b', 'c', 'list' ] + // if the MemberExpression is `obj.a.b.c.list` + // @ts-ignore + log('chain names:', chain.map(node => node.name ?? node.property?.name)); + + // @ts-expect-error `chain[0].name` cannot be undefined because the previous check ensures + const variable = findVariableDefinition({node, variableName: chain[0].name, context}); + if (!variable || !variable.defs[0]?.node) { + return; + } + + /** @type {ESTreeNode | undefined} */ + let currentObject = variable.defs[0].node.init; + + for (let index = 1; index < chain.length; index++) { + const currentPropertyInChain = chain[index].property; + // .log(`#${index}`, 'currentPropertyInChain:', currentPropertyInChain?.type, currentPropertyInChain); + // .log(`#${index}`, 'currentObject:', currentObject); + if (!currentObject || currentObject.type !== 'ObjectExpression') { + return; + } + + const property = currentObject.properties.find( + // @ts-expect-error + p => p.key.type === 'Identifier' + // @ts-expect-error + && p.key.name === (currentPropertyInChain.type === 'Identifier' ? currentPropertyInChain.name : currentPropertyInChain.value), + ); + // .log(`#${index}`, 'property:', property); + + if (!property) { + return; + } + + // @ts-expect-error + currentObject = property.value; + } + + return currentObject; +} + +/** + Extracts the property access chain from a MemberExpression + @param {MemberExpression | Identifier} node - The node to analyze + @returns {PropertyAccessNode[] | undefined} - Array of access nodes or undefined if invalid + @example + return [ Node('obj'), Property('a'), Property('b'), Property('c'), Property('list') ] if node is MemberExpress `obj.a.b.c.list` + */ +function getPropertyAccessChain(node) { + /** @type {PropertyAccessNode[]} */ + const chain = []; + /** @type {MemberExpression | Identifier | null} */ + let current = node; + let times = 0; + + // We use `unshift` because `obj.a.b.c.list` loop order is `list` -> `c` -> `b` -> `a` -> `obj` + while (current) { + times += 1; + if (times > RECURSION_LIMIT) { + log('Skip deep-nested member checks for performance and to prevent potential infinite loops.'); + return; + } + + if (current.type === 'Identifier') { + chain.unshift({name: current.name}); + // `break` at end of chain. + break; + } + + if (current.type === 'MemberExpression') { + if (current.property.type === 'Identifier') { + chain.unshift({property: current.property}); + } else if (current.property.type === 'Literal') { + chain.unshift({property: current.property}); + } else { + // Unsupported property type + return; + } + + // @ts-expect-error + current = current.object; + } else { + // Unsupported node type + return; + } + } + + return chain.length > 0 ? chain : undefined; +} + +/** + @param {any} node + @returns {boolean} + */ +function isSymbol(node) { + const SYMBOL = 'Symbol'; + // Symbol (such as `Symbol('description')`) will not check + if (node.type === 'CallExpression' && node.callee.name === SYMBOL) { + return true; + } + + // Symbol (such as `Symbol.for('description')`) will not check + if (isCallExpression(node) && node.callee.object?.name === SYMBOL) { + return true; + } + + // Symbol (such as `Symbol.iterator`) will not check + if (isMemberExpression(node, {object: SYMBOL})) { + return true; + } + + return false; } /** @@ -283,6 +423,7 @@ function findVariableDefinition({variableName, node, context}) { const scope = context.sourceCode.getScope(node); const {variables} = scope; + log('[findVariableDefinition] variables', variables); const variable = variables.find(v => v.name === variableName); if (variable) { @@ -296,7 +437,7 @@ function findVariableDefinition({variableName, node, context}) { @param {*} node @param {import('eslint').Rule.RuleContext} context - @returns {boolean} + @returns {[is: false] | [is: true, node: Node]} */ function isIdentifierReferenceType(node, context) { const variable = findVariableDefinition({variableName: node.name, node, context}); @@ -305,14 +446,14 @@ function isIdentifierReferenceType(node, context) { log({definitionNode}); if (!variable || !definitionNode) { - return false; + return [false]; } // Check `const foo = []; Array(3).fill(foo);` if (definitionNode.type === 'VariableDeclarator') { // Not check `let` `let foo = []; Array(3).fill(foo);` if (definitionNode.parent.kind === 'let') { - return false; + return [false]; } return isReferenceType(definitionNode.init, context); @@ -352,3 +493,25 @@ const config = { }; export default config; + +/** + @typedef {ESTreeNode} Node + */ + +/** + @typedef {Object} PropertyAccessNode + @property {string} [name] - For identifiers (root object) + @property {import('estree').Identifier | import('estree').Literal} [property] - For property access + */ + +/** + @typedef {import('eslint').Rule.RuleContext} RuleContext + @typedef {import('estree').Node} ESTreeNode + @typedef {import('estree').MemberExpression} MemberExpression + @typedef {import('estree').Identifier} Identifier + @typedef {import('estree').Literal} Literal + @typedef {import('estree').VariableDeclarator} VariableDeclarator + @typedef {import('estree').ObjectExpression} ObjectExpression + @typedef {import('estree').Property} Property + @typedef {import('eslint-scope').Variable} ESLintVariable + */ diff --git a/test/no-array-fill-with-reference-type.js b/test/no-array-fill-with-reference-type.js index 23868442f4..92f9f8f1d0 100644 --- a/test/no-array-fill-with-reference-type.js +++ b/test/no-array-fill-with-reference-type.js @@ -25,8 +25,6 @@ test.snapshot({ 'Array.from({ length: 33 }, () => { return new Map() }); // ✓ Safe alternative', 'Array(3).fill(0); // ✓ number (primitive)', - 'new Foo(3).fill({}); // ✓ Not Array', - 'Foo(3).fill({}); // ✓ Not Array', // Should be invalid but will pass. // Due to the rule name it will not check other than `Array.fill` or `Array.from`. @@ -216,6 +214,52 @@ test.snapshot({ const ng2Descendants = Array.from(element.querySelectorAll('ng2 li')).map( angular.element, );`, + + 'const arr = new Array(3); arr.fill(1)', + 'const arr = new Array(3).fill(Symbol.for("description"))', + 'const arr = new Array(3).fill(Symbol.iterator)', + + 'const obj = { primitive: 1 }; const arr = new Array(3).fill(obj.primitive)', + 'const obj = { a: { b: { c: { primitive: 1 } } } }; const arr = new Array(3).fill(obj.a.b.c.primitive)', + // `undefined` is not a reference type + 'const obj = { primitive: 1 }; const arr = new Array(3).fill(obj.list)', + // `undefined` is not a reference type + 'const obj = { a: { b: { c: { } } } }; const arr = new Array(3).fill(obj.a.b.c.list)', + // `undefined` is not a reference type + 'const obj = {}; const arr = new Array(3).fill(obj.a.b.c.list)', + // Will not check too deep (> 5) even if `list` is a reference type. + 'const obj = { a: { b: { c: { d: { list: [] } } } } }; const arr = new Array(3).fill(obj.a.b.c.d.list)', + 'const obj = { a: { b: { c: { d: { e: { list: [] } } } } } }; const arr = new Array(3).fill(obj.a.b.c.d.e.list)', + + ` + const obj2 = { a: { b: { c: { list: [] } } } }; + const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: 0 }, c: { list1: [], list: [] } } } }; + + const arr = new Array(3).fill(obj.a.b.c1.list); + `, + ` + const obj2 = { a: { b: { c: { list: 0 } } } }; + const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: 0 }, c: { list1: [], list: [] } } } }; + + const arr = new Array(3).fill(obj2.a.b.c.list); + `, + + // Not check computed property for simplicity. + 'const prop = "list"; const obj = { list: [] }; const arr = new Array(3).fill(obj[prop])', + + // Will not check too deep even if its return value is a reference type. + ` + const createError = (match, suggest) => [ + { + message: 'temp', + suggestions: undefined, + }, + ]; + + const obj = { + errors: Array.from({length: 3}).fill(createError("no", "yes")[0]), + }; + `, ], invalid: [ 'new Array(3).fill([]);', // ✗ Array @@ -265,7 +309,6 @@ test.snapshot({ 'new Array(3).fill(new Date())', 'Array.from({ length: 3 }).fill(new Date())', - 'Array.from({length: 3}).fill(createError(\'no\', \'yes\')[0])', 'const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)', // Should not fill with function @@ -305,6 +348,7 @@ test.snapshot({ // Variable declared in its grand parent scope 'const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }', + 'function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }', // `initialArray` is filled with no reference type (literal string) but will be treated as such because it is a function calling @@ -335,5 +379,31 @@ test.snapshot({ const data = ref(Array.from({ length: 200 }).map(dataGenerator)) `, + + 'const arr = new Array(3); arr.fill([])', + 'new Foo(3).fill({});', // Check all fill method call even if the object is not Array + 'Foo(3).fill({});', // Check all fill method call even if the object is not Array + + 'const obj = { arr: [] }; const arr = new Array(3).fill(obj.arr)', + ` + const obj = { a: { b: { c: { list: [] } } } }; + const arr = new Array(3).fill(obj.a.b.c.list); + `, + ` + const obj2 = { a: { b: { c: { list: [] } } } }; + const obj = { a: { b: { c: { list: [] } } } }; + const arr = new Array(3).fill(obj.a.b.c.list); + `, + ` + const obj2 = { a: { b: { c: { list: [] } } } }; + const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: [] }, c: { list1: [], list: [] } } } }; + const arr = new Array(3).fill(obj.a.b.c.list); + `, + + 'const obj = { list: [] }; const arr = new Array(3).fill(obj["list"])', + ` + const obj = { a: { b: { c: { list: [] } } } }; + const arr = new Array(3).fill(obj['a']['b']['c']['list']); + `, ], }); diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 80cd8d9ada..09ec6a07bf 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -166,7 +166,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const p = /pattern/; new Array(3).fill(p); // ✗ RegExp␊ - | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^ Avoid using \`Array.fill()\` with reference type (RegExp). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(10): const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp @@ -191,7 +191,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const p = new RegExp("pattern"); new Array(3).fill(p); // ✗ RegExp␊ - | ^ Avoid using \`Array.fill()\` with reference type (variable (p)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^ Avoid using \`Array.fill()\` with reference type (new RegExp()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(11): new Array(3).fill(new String('fff')); // ✗ new String @@ -236,7 +236,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | class BarClass {}; new Array(3).fill(BarClass); // ✗ Class␊ - | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (BarClass)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(14): class BarClass {}; new Array(3).fill(new BarClass()); // ✗ Class instance @@ -266,7 +266,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map(); new Array(3).fill(map); // ✗ Variable (map)␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(16): Array(3).fill({}); // ✗ Object @@ -329,22 +329,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(20): Array.from({length: 3}).fill(createError('no', 'yes')[0]) - -> Input - - `␊ - 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - ` - -> Error 1/1 - - `␊ - > 1 | Array.from({length: 3}).fill(createError('no', 'yes')[0])␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ - ` - -## invalid(21): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) +## invalid(20): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) > Input @@ -356,10 +341,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array)␊ - | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (initialArray)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(22): new Array(3).fill(() => 1); +## invalid(21): new Array(3).fill(() => 1); > Input @@ -384,7 +369,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(23): new Array(3).fill(() => {}); +## invalid(22): new Array(3).fill(() => {}); > Input @@ -409,7 +394,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(24): new Array(3).fill(() => { return {} }); +## invalid(23): new Array(3).fill(() => { return {} }); > Input @@ -434,7 +419,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(25): new Array(3).fill(function () {}); +## invalid(24): new Array(3).fill(function () {}); > Input @@ -459,7 +444,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Function). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(26): new Array(3).fill(new class {}); +## invalid(25): new Array(3).fill(new class {}); > Input @@ -474,7 +459,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new class). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(27): new Array(3).fill(new A.B()); +## invalid(26): new Array(3).fill(new A.B()); > Input @@ -489,7 +474,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (new A.B). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(28): const cls = new class {}; new Array(3).fill(cls); +## invalid(27): const cls = new class {}; new Array(3).fill(cls); > Input @@ -501,10 +486,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const cls = new class {}; new Array(3).fill(cls);␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (cls)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (new class). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(29): const obj = {}; Array.from({ length: 3 }).fill(obj); +## invalid(28): const obj = {}; Array.from({ length: 3 }).fill(obj); > Input @@ -516,10 +501,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const obj = {}; Array.from({ length: 3 }).fill(obj);␊ - | ^^^ Avoid using \`Array.from().fill()\` with reference type (variable (obj)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(30): const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map); +## invalid(29): const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map); > Input @@ -531,10 +516,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map);␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(31): const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } +## invalid(30): const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } > Input @@ -546,10 +531,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const map = new Map({ foo: "bar" }); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type (new Map()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(32): function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } +## invalid(31): function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } > Input @@ -561,10 +546,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function getMap() { return new Map({ foo: "bar" }); } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(33): function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } +## invalid(32): function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); } > Input @@ -576,10 +561,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function getMap() { return "literal string" } const map = getMap(); if (true) { const initialArray = Array.from({ length: 3 }, () => map); }␊ - | ^^^ Avoid using \`Array.fill()\` with reference type (variable (map)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.fill()\` with reference type. Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(34): const object = {} Array.from({length: 3}, () => object) +## invalid(33): const object = {} Array.from({length: 3}, () => object) > Input @@ -596,11 +581,11 @@ Generated by [AVA](https://avajs.dev). 1 |␊ 2 | const object = {}␊ > 3 | Array.from({length: 3}, () => object)␊ - | ^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (object)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ 4 | ␊ ` -## invalid(35): const object = {}; Array.from({length: 31}).map(() => object); +## invalid(34): const object = {}; Array.from({length: 31}).map(() => object); > Input @@ -612,10 +597,10 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const object = {}; Array.from({length: 31}).map(() => object);␊ - | ^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (object)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` -## invalid(36): import { ref } from 'vue' let id = 0 const sharedObj = { id: `random-id-${++id}`, name: 'Tom', date: '2020-10-1', } const dataGenerator = () => (sharedObj) const data = ref(Array.from({ length: 200 }).map(dataGenerator)) +## invalid(35): import { ref } from 'vue' let id = 0 const sharedObj = { id: `random-id-${++id}`, name: 'Tom', date: '2020-10-1', } const dataGenerator = () => (sharedObj) const data = ref(Array.from({ length: 200 }).map(dataGenerator)) > Input @@ -652,8 +637,171 @@ Generated by [AVA](https://avajs.dev). 10 | }␊ 11 |␊ > 12 | const dataGenerator = () => (sharedObj)␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (variable (sharedObj)). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ 13 |␊ 14 | const data = ref(Array.from({ length: 200 }).map(dataGenerator))␊ 15 | ␊ ` + +## invalid(36): const arr = new Array(3); arr.fill([]) + +> Input + + `␊ + 1 | const arr = new Array(3); arr.fill([])␊ + ` + +> Error 1/1 + + `␊ + > 1 | const arr = new Array(3); arr.fill([])␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(37): new Foo(3).fill({}); + +> Input + + `␊ + 1 | new Foo(3).fill({});␊ + ` + +> Error 1/1 + + `␊ + > 1 | new Foo(3).fill({});␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(38): Foo(3).fill({}); + +> Input + + `␊ + 1 | Foo(3).fill({});␊ + ` + +> Error 1/1 + + `␊ + > 1 | Foo(3).fill({});␊ + | ^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(39): const obj = { arr: [] }; const arr = new Array(3).fill(obj.arr) + +> Input + + `␊ + 1 | const obj = { arr: [] }; const arr = new Array(3).fill(obj.arr)␊ + ` + +> Error 1/1 + + `␊ + > 1 | const obj = { arr: [] }; const arr = new Array(3).fill(obj.arr)␊ + | ^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(40): const obj = { a: { b: { c: { list: [] } } } }; const arr = new Array(3).fill(obj.a.b.c.list); + +> Input + + `␊ + 1 |␊ + 2 | const obj = { a: { b: { c: { list: [] } } } };␊ + 3 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + 4 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | const obj = { a: { b: { c: { list: [] } } } };␊ + > 3 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 4 | ␊ + ` + +## invalid(41): const obj2 = { a: { b: { c: { list: [] } } } }; const obj = { a: { b: { c: { list: [] } } } }; const arr = new Array(3).fill(obj.a.b.c.list); + +> Input + + `␊ + 1 |␊ + 2 | const obj2 = { a: { b: { c: { list: [] } } } };␊ + 3 | const obj = { a: { b: { c: { list: [] } } } };␊ + 4 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + 5 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | const obj2 = { a: { b: { c: { list: [] } } } };␊ + 3 | const obj = { a: { b: { c: { list: [] } } } };␊ + > 4 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 5 | ␊ + ` + +## invalid(42): const obj2 = { a: { b: { c: { list: [] } } } }; const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: [] }, c: { list1: [], list: [] } } } }; const arr = new Array(3).fill(obj.a.b.c.list); + +> Input + + `␊ + 1 |␊ + 2 | const obj2 = { a: { b: { c: { list: [] } } } };␊ + 3 | const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: [] }, c: { list1: [], list: [] } } } };␊ + 4 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + 5 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | const obj2 = { a: { b: { c: { list: [] } } } };␊ + 3 | const obj = { a: { b1: { c: { list: [] } } , b: { c1: { list: [] }, c: { list1: [], list: [] } } } };␊ + > 4 | const arr = new Array(3).fill(obj.a.b.c.list);␊ + | ^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 5 | ␊ + ` + +## invalid(43): const obj = { list: [] }; const arr = new Array(3).fill(obj["list"]) + +> Input + + `␊ + 1 | const obj = { list: [] }; const arr = new Array(3).fill(obj["list"])␊ + ` + +> Error 1/1 + + `␊ + > 1 | const obj = { list: [] }; const arr = new Array(3).fill(obj["list"])␊ + | ^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + ` + +## invalid(44): const obj = { a: { b: { c: { list: [] } } } }; const arr = new Array(3).fill(obj['a']['b']['c']['list']); + +> Input + + `␊ + 1 |␊ + 2 | const obj = { a: { b: { c: { list: [] } } } };␊ + 3 | const arr = new Array(3).fill(obj['a']['b']['c']['list']);␊ + 4 | ␊ + ` + +> Error 1/1 + + `␊ + 1 |␊ + 2 | const obj = { a: { b: { c: { list: [] } } } };␊ + > 3 | const arr = new Array(3).fill(obj['a']['b']['c']['list']);␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Array). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + 4 | ␊ + ` diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 23a2316146eb9bddf456bd2d496020c214d0b806..98468a25b5530686260ea0c938b8628652306eb9 100644 GIT binary patch literal 2755 zcmV;!3Ow~eRzVbGP4WH&ng(lKEQcZDJ{wO77+q?Y68ct%6is z0gc>&4a1OMF4T(UwxX(q-M!+fVrp{7ys2B}x8H8HWJ}&IJuvf$8G2+MocUblD_H;u z?g^gG5>;*xl{~3+jx6{25B$&1{$?h-9%cXl;2s2z8#iF%wyw0`$W*ig*tZ{bo-6Ld z9mTo{25A$6XiWmv%N+s*`<7xEUN8x}-_Q>WT_~5!&?`Zq2y5%m1%p^eh6ak(A|0Z& zh-QJJnU+jV^@{uUKSXYUr32B-BZGjZ`${u!$_8nb-FH_u4MR6TnwPw&=e?*`xlwoi zEAm1wq0m1p3_UZ!i~k={{C_8of8UB2f_)?;aq3-m9buK`*qi`hbr0BrFr%)@9jab099QK|5ZWaKZ80>pJbNg}SLF^j z(>{r~eH5N)Ld%hfmn!X?;wFgUqLAShvHT3T2q*E9F!b!9NN*8qc!omD<6-C&ck&FE zJcdhLhVvcSvWTJ0_ZeO%2b*_&sragkaRXtj2{8&y@~Y1Z$Y?dYn+53FNOH2O>UXY_ zgCkWoHt%)}Vw#GsnYk5c%c@DT0KM#w#LkXh7LMTw(8Lp- zCe8`-+VQoJbHkG>M(g7$Liu=Tnn#*HMy))IwDM3Uv=)hWJVsw^$X=Q2!z9!$mpmmc z7gwOEYo-MqSOb<-tDG=)qNVgKB7MP?Qd;}RsHLwWEq&J0QfkjdV&WcCTq8Zl<{c_X zNZgc5DXMQGJa9*oG6{q*h}Rf8NXP&{>9}9Tf8Ic02E@ z_4}8C9p5dafz9xa?|^yd2o%EY2S18L@rCdfEN(%u+p%=rW5$o1uUPsKH z$m50gQ1*4dzAhVz+)xSFr-K@L5ozc-)NzenmLDH3kgJ^~q@4opXO5!K1e$SmGu2b6 zb4(|6E;ae$#X8bJ#nr$t3m5-Hgg@}6$c9?9nC1lww!$PWd4xPiRH7YNH&>trJzrdc zkd_govwle7rno7XMS%W;07aOKm0SW?)NpZ1n4MwF#50+fWQ!DvoNBd(XgwO*Nq3F# z^5`Rk=}+N{5S|?opdp(^*Zj$YVXF?(a&$6%Y?miRMnjvJD{mG$OvfdIHf$7=HM_SX0IV-#Ucchg+h?{`E zOA!q~Vy>RQ6M(kJ(DLWgTsL|=wpE1XkqEYeuG47Y3i`>RK1DU}(~OsG3aRq<$_=>D z?E#lGTFA)EN0G+n#tnTZ^Jzr=<4EcQ{zVC3m@0gNv@p-Kz~7eFc3q|Z@Du(VqIO0o zgF#E>_WVyog8@LWf>`JHzjo_1TI8Db*Ov zE@J{1v9WPgynAn>e38GSImy`AHNwlte<3&@Mr>zx?L?AEx0ShkaRQ*MGbl@J2-Q?g zcQ&;dG9lkoO&+K#2-GqfA|)`)O|2ZF_jx=7N@83@RD4W(@@+8A=NM?1W?4_OpSS0Yy<&m)a&hOG*vEH#yKMq7tW%97D5>^n)7xLQ)$P_T?6 zQiLvlrYaT$=mq8WDw5k#61k1aDXt=4LyG)PB1MkOu@Q>)zE|~IOx1MakByxUh-G`& zcR+}(hv<3_j#KWESx!|f zV#q3(_KwWl38dGLkUW17BfXB@X>MA*gZ%z!jI=s_zhQFHX&TdrZ49r~{Np&f1BMQV z5C%qpx#!%;S=el&-qf}u_$)vb?!l>3fnu@%HTz1e;<5mB`);mi(RbBnAIn6Ry`Hda zuWB8gg z-vUZ&1@;YDYw3q`N^9ln9^acdc2Jm@Vo z=T0Z{`thOX7Mx3qzN!kvi(Xu^FP;)bj^1+4xy2ttdV1M89gHSTyo!C1R>hL@Dw4m# zj0`h5MVuhm$+w#XVh z*)ZH`7H{%@m7Zh2*%WNp&ZCB{j2gBmYupCx6q5VDXHWwcX)$&~HN_jQzQ(|LKLkO) zl;z*&9mI47VfwOf6>#ub-s0cy5tDcQi+_Q~`2?mR2SxEd&Eid0fTCml7>e~5-B`zo z^Lr@Hzx3i9BgWGl-)C5Smj_qaXmYQ>?jH13g*5zhj z5xx?4-7Q5?vFo&uHgIYyyIbtn!YV;=tUwnU^rJ~XRK>KM&^mvy0$gsCn`QbWFO$EI zr1LG&06Ug5Y~-KJsqiU)22$LXa0(!vhwEuQj6YE@HM^Z7=L_Co!j$~NtR_+Bu?hL- zNGCs;5$PnJ_XAQ+kOB2{`VxRZO8r|UdZsjng!>rD^3UT;xbT-3y?yBGk0n!ojY9IXac1f`Lh}CxEk00000000B!o8NES))mJs7ex{62QXkL3Jlv0)C3|MTNWidj_ufs(9mJ1R9b zl6Tx6MD2oO0x|4?MZhpa-t4=oMY;|D-L*@WWm=#tC_&ciLDpN`tb4y?Ug{N;`WJ<% zXC`?0{~OBxr{esNt%xDGM@AAyPvCSwpv@&PKEtK3gecU76p$GXiS5b^Lh+3l1vZs{ zBL@;d9*!PRGXS*61vDJVYp}2YpMUs1T;IJ%I!=_*1w?64NXfP39mpa8uXz58h0zi8-}NzWB8+VzMxjYw^LZW_ZB=ho0fsJ;nyTyOgBxUTpsUuUhkc9K zwq_c3Z54W|Zj&m&sCwJCxp%$q(2IdGo<+*|hgccnV5ct&&u|Ge@p7Pvv%YB0{>b>TKRn)qRiHj%ol{ln_N02R*QfO&cw{;P!*#%g{xbyqhw;$UI7tUQ7j5dk45+U#)O5D5Lth&%sFwTwFdXrk z$>8#syMXx?VtzIFykzu&*ofh;A^3CbGf>=HhL1pQNsL>67E1}lvBku(m{uJ0OmIth zGQ@i(2rjCXJ*1WGELw@Uj51`7xzc$RN#|T9>11-ALrDdim{3?pFQsvJc8PUo_tl_# z=1%hQ(z~yQI%U6MMM6(UHS`YB&>N^bo7z_xA9l#q&N-x=dEEP)hSLn1@pV(6@u40| zAeMP17CPCQeRX3438Co=p~%X{KN039!5mtlRgL4kqQRD+l;wa>5Qt8UJ?HK!v|$v= zOBB)yf^<3zDc%&f4yy>zzY(AWbEzs!0E-%yj|sDv7&Gxy=S9^alFVsa+lbbw*#5h3 zgjYx3BTQe#uTlhdM1Tr@AAR#j4~8vEC@aau6iaDxiX~M|#UtCU{2Vd+aV1@8r2&|Q zW{OHH71YaYA4_urD$7-ns*XiehqxA`x?$Gmp#F&1b@^8FHit2PB%Rv<7kL9A|0NH3 zHYX_*z+Dq4B8a2cz#XOmg>`y0Lvu7$ccX%JxOJP?D-7Sn>;J0mh18>{X*=d>295S- zui&2WG@YkvO+?Bn&^boom7s-@n7a70bY2)rxbGEA{HNV2$4v0P<;%#39GTC*JTN*= z%4z(q?~r=F5O)m5AtiJRGLsJCEdg4Yq2=$v^TQbN*tQUslL>4E9qQ@A6^x!@V@jZV ztnsqFL@oXfzKJk~BjA!oD_@m`B+}U2K||lJ{0LG1Pa^e+_>u%rq){)C78aNm_?rWJ zeyB7ae!-tb)Ls(GVA9gTE8rQVfN#YLh=i67{&D8c=D1qo4TT+l;+Z#nat4u-Vh7}7 zJHG$QjM;;Kd*J?PYzF?*1DseIWW|HvI_M# z&HefubXAA`Xf<2Sd8Ik8)aTguhoXLk7{pQ?(}H#X^(E#-4&4XqG(L&@1!^^$-~&e{ zIs3x4D+W^5JGABTn;yUI5$1#5()RB3ig27CdTz!3K48% gN08=|HI2 Date: Mon, 13 Oct 2025 17:55:14 +0800 Subject: [PATCH 52/63] docs: readme --- readme.md | 274 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 141 insertions(+), 133 deletions(-) diff --git a/readme.md b/readme.md index 73b83ae09e..5a93abbe85 100644 --- a/readme.md +++ b/readme.md @@ -51,142 +51,150 @@ export default [ 💼 [Configurations](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) enabled in.\ ✅ Set in the `recommended` [configuration](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config).\ +☑️ Set in the `unopinionated` [configuration](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config).\ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -| Name                                    | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | -| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | -| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ | 🔧 | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | -| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | -| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ | 🔧 | | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ | 🔧 | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | 💡 | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | | -| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ | | | -| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | -| [no-array-fill-with-reference-type](docs/rules/no-array-fill-with-reference-type.md) | Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements. | ✅ | | | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | -| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | | -| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ | 🔧 | 💡 | -| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | | -| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | | -| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ | 🔧 | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | | -| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | | -| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ | 🔧 | 💡 | -| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ | 🔧 | | -| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ | 🔧 | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ | 🔧 | | -| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ | | | -| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ | 🔧 | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ | 🔧 | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ | 🔧 | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ | 🔧 | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ | 🔧 | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ | 🔧 | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ | | 💡 | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ | 🔧 | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ | 🔧 | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ | 🔧 | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ | 🔧 | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ | 🔧 | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ | 🔧 | 💡 | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 | -| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ | 🔧 | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ | | 💡 | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ | 🔧 | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ | 🔧 | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ | 🔧 | 💡 | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | -| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ | 🔧 | | -| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 | -| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ | 🔧 | | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ | 🔧 | 💡 | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ | 🔧 | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ | 🔧 | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ | 🔧 | 💡 | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ | 🔧 | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ | 🔧 | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ | 🔧 | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ | 🔧 | 💡 | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ | 🔧 | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ | 🔧 | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ | 🔧 | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | 💡 | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | -| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ | 🔧 | 💡 | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | -| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | | -| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | | +| Name | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | +| [consistent-assert](docs/rules/consistent-assert.md) | Enforce consistent assertion style with `node:assert`. | ✅ | 🔧 | | +| [consistent-date-clone](docs/rules/consistent-date-clone.md) | Prefer passing `Date` directly to the constructor when cloning. | ✅ ☑️ | 🔧 | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | | 💡 | +| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | | +| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ ☑️ | 🔧 | | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | ✅ ☑️ | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase or lowercase values. | ✅ ☑️ | 🔧 | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | ✅ ☑️ | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | ✅ | 🔧 | 💡 | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | ✅ | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ ☑️ | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ ☑️ | 🔧 | 💡 | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ ☑️ | | | +| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. | ✅ ☑️ | | | +| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ ☑️ | | 💡 | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ ☑️ | 🔧 | 💡 | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ ☑️ | 🔧 | 💡 | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | | +| [no-array-reverse](docs/rules/no-array-reverse.md) | Prefer `Array#toReversed()` over `Array#reverse()`. | ✅ ☑️ | | 💡 | +| [no-array-sort](docs/rules/no-array-sort.md) | Prefer `Array#toSorted()` over `Array#sort()`. | ✅ ☑️ | | 💡 | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | | +| [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ ☑️ | | 💡 | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ ☑️ | 🔧 | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ ☑️ | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ ☑️ | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ ☑️ | 🔧 | | +| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ ☑️ | 🔧 | 💡 | +| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ ☑️ | | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ ☑️ | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ ☑️ | 🔧 | | +| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ ☑️ | | | +| [no-named-default](docs/rules/no-named-default.md) | Disallow named usage of default import and export. | ✅ ☑️ | 🔧 | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ ☑️ | 🔧 | | +| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ ☑️ | | 💡 | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ ☑️ | 🔧 | 💡 | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ ☑️ | 🔧 | 💡 | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ ☑️ | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ ☑️ | | | +| [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ ☑️ | 🔧 | 💡 | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ ☑️ | 🔧 | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ ☑️ | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ ☑️ | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | ✅ ☑️ | 🔧 | 💡 | +| [no-unnecessary-array-flat-depth](docs/rules/no-unnecessary-array-flat-depth.md) | Disallow using `1` as the `depth` argument of `Array#flat()`. | ✅ ☑️ | 🔧 | | +| [no-unnecessary-array-splice-count](docs/rules/no-unnecessary-array-splice-count.md) | Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`. | ✅ ☑️ | 🔧 | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | ✅ ☑️ | 🔧 | | +| [no-unnecessary-polyfills](docs/rules/no-unnecessary-polyfills.md) | Enforce the use of built-in methods instead of unnecessary polyfills. | ✅ ☑️ | | | +| [no-unnecessary-slice-end](docs/rules/no-unnecessary-slice-end.md) | Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`. | ✅ ☑️ | 🔧 | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ ☑️ | 🔧 | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ ☑️ | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-error-capture-stack-trace](docs/rules/no-useless-error-capture-stack-trace.md) | Disallow unnecessary `Error.captureStackTrace(…)`. | ✅ ☑️ | 🔧 | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ ☑️ | 🔧 | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ ☑️ | 🔧 | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | ✅ ☑️ | 🔧 | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | ✅ ☑️ | 🔧 | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | ✅ ☑️ | | 💡 | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | ✅ ☑️ | 🔧 | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | ✅ ☑️ | 🔧 | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | ✅ ☑️ | 🔧 | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | ✅ ☑️ | 🔧 | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | ✅ ☑️ | 🔧 | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ ☑️ | 🔧 | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ ☑️ | 🔧 | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-bigint-literals](docs/rules/prefer-bigint-literals.md) | Prefer `BigInt` literals over the constructor. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ ☑️ | | | +| [prefer-class-fields](docs/rules/prefer-class-fields.md) | Prefer class field declarations over `this` assignments in constructors. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-classlist-toggle](docs/rules/prefer-classlist-toggle.md) | Prefer using `Element#classList.toggle()` to toggle class names. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ ☑️ | | 💡 | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | ✅ ☑️ | 🔧 | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | ✅ ☑️ | | 💡 | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | ✅ ☑️ | 🔧 | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | ✅ ☑️ | 🔧 | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ ☑️ | | 💡 | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ ☑️ | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 | +| [prefer-global-this](docs/rules/prefer-global-this.md) | Prefer `globalThis` over `window`, `self`, and `global`. | ✅ ☑️ | 🔧 | | +| [prefer-import-meta-properties](docs/rules/prefer-import-meta-properties.md) | Prefer `import.meta.{dirname,filename}` over legacy techniques for getting file paths. | | 🔧 | | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ ☑️ | 🔧 | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ ☑️ | | 💡 | +| [prefer-math-min-max](docs/rules/prefer-math-min-max.md) | Prefer `Math.min()` and `Math.max()` over ternaries for simple comparisons. | ✅ ☑️ | 🔧 | | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | ✅ ☑️ | 🔧 | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | ✅ ☑️ | 🔧 | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | ✅ ☑️ | 🔧 | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` when possible. | ✅ ☑️ | 🔧 | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | ✅ ☑️ | 🔧 | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | ✅ ☑️ | 🔧 | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | ✅ ☑️ | 🔧 | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | ✅ ☑️ | 🔧 | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ ☑️ | 🔧 | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ ☑️ | 🔧 | | +| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 | +| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ ☑️ | 🔧 | | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ ☑️ | 🔧 | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ ☑️ | 🔧 | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ ☑️ | 🔧 | 💡 | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ ☑️ | 🔧 | | +| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ ☑️ | | 💡 | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ ☑️ | 🔧 | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ ☑️ | 🔧 | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ ☑️ | | 💡 | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ ☑️ | 🔧 | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ ☑️ | 🔧 | 💡 | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ ☑️ | 🔧 | | +| [require-module-attributes](docs/rules/require-module-attributes.md) | Require non-empty module attributes for imports and exports | ✅ ☑️ | 🔧 | | +| [require-module-specifiers](docs/rules/require-module-specifiers.md) | Require non-empty specifier list in import and export statements. | ✅ ☑️ | 🔧 | 💡 | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ ☑️ | 🔧 | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ ☑️ | 🔧 | 💡 | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ ☑️ | 🔧 | | From 6bf07d36c120edaa4a3e276e8902336cab1bede7 Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 13 Oct 2025 17:57:27 +0800 Subject: [PATCH 53/63] chore(merge): merge remote main and resolve conflicts in readme use remote --- readme.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/readme.md b/readme.md index 563a9a9bd5..eaf3113b9c 100644 --- a/readme.md +++ b/readme.md @@ -55,12 +55,7 @@ export default [ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). -<<<<<<< HEAD -| Name | Description | 💼 | 🔧 | 💡 | -======= - | Name                                    | Description | 💼 | 🔧 | 💡 | ->>>>>>> fc803fcd31ee865853532eaf27c42b8ebffa485e | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--- | :- | :- | | [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | | 🔧 | | | [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | | From f15bb3201f4e65b490916e56ff07358b3802fc41 Mon Sep 17 00:00:00 2001 From: legend80s Date: Tue, 21 Oct 2025 08:54:59 +0800 Subject: [PATCH 54/63] style: format importings and remove useless debugging code --- rules/no-array-fill-with-reference-type.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index a52e5ce575..12400a1a8a 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -2,11 +2,13 @@ import {findVariable} from '@eslint-community/eslint-utils'; import { isCallExpression, - isFunction, isMemberExpression, isMethodCall, isNewExpression, isRegexLiteral, + isFunction, + isMemberExpression, + isMethodCall, + isNewExpression, + isRegexLiteral, } from './ast/index.js'; -const debugging = false; - // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { @@ -20,8 +22,6 @@ const DEFAULTS = { allowRegularExpressions: true, }; -const log = (...arguments_) => debugging && console.log(...arguments_); - const RECURSION_LIMIT = 5; /** @param {import('eslint').Rule.RuleContext} context */ From bb92e959b016b68e6aed97e9f907fffab6d31869 Mon Sep 17 00:00:00 2001 From: legend80s Date: Tue, 21 Oct 2025 17:39:16 +0800 Subject: [PATCH 55/63] refactor: remove useless logs --- rules/no-array-fill-with-reference-type.js | 44 +++++++++++----------- test/string-content.js | 1 - 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 12400a1a8a..48836b023f 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -26,6 +26,9 @@ const RECURSION_LIMIT = 5; /** @param {import('eslint').Rule.RuleContext} context */ const create = context => ({ + /** + @param {import('estree').CallExpression} node + */ CallExpression(node) { // Check all `fill` method call even if the object is not Array because we don't know if its runtime type is array // `arr.fill()` or `new Array().fill()` or `Array.from().fill()` @@ -34,23 +37,26 @@ const create = context => ({ // `Array.from().map` or `Array.from(arrayLike, mapper)` const isArrayFrom = isMethodCall(node, {object: 'Array', method: 'from'}); - log('isArrayFill:', {isArrayFill, isArrayFrom}); - if (!isArrayFill && !isArrayFrom) { return; } const fillArgument = isArrayFill ? node.arguments[0] : getArrayFromReturnNode(node, context); - log('fillArgument:', fillArgument); - const [is, resolvedNode] = isReferenceType(fillArgument, context); if (!is) { return; } - const actual = isMethodCall(node.callee.object, {object: 'Array', method: 'from'}) ? 'Array.from().fill()' : 'Array.fill()'; + const actual = isMethodCall( + // @ts-expect-error + node.callee.object, + {object: 'Array', method: 'from'}, + ) + ? 'Array.from().fill()' + : 'Array.fill()'; + const type = getType(resolvedNode, context); return { @@ -72,7 +78,6 @@ const create = context => ({ */ function getArrayFromReturnNode(node, context) { const secondArgument = node.arguments[1]; - log('secondArgument:', secondArgument); // Array.from({ length: 10 }, () => { return sharedObject; }); let result; @@ -98,6 +103,7 @@ function getArrayFromReturnNode(node, context) { /** @param {import('estree').FunctionExpression | Node} node - callback for map + @param {RuleContext} context @returns {{ returnNode: Node, declaredInCurrentFunction: boolean }} */ function getReturnIdentifier(node, context) { @@ -123,8 +129,6 @@ function getReturnIdentifier(node, context) { return getReturnIdentifier(init, context); } - // Console.log('node:', node); - // @ts-expect-error node is FunctionExpression const {body: nodeBody} = node; @@ -144,13 +148,19 @@ function getReturnIdentifier(node, context) { return {returnNode: nodeBody, declaredInCurrentFunction: true}; } + // @ts-expect-error const returnStatement = nodeBody.body.find(node => node.type === 'ReturnStatement'); const name = returnStatement?.argument?.name; if (!name) { return {returnNode: returnStatement?.argument, declaredInCurrentFunction: true}; } - const declaredInCurrentFunction = nodeBody.body.some(node => node.type === 'VariableDeclaration' && node.declarations.some(declaration => declaration.id.name === name)); + const declaredInCurrentFunction = nodeBody.body.some( + // @ts-expect-error + node => node.type === 'VariableDeclaration' + // @ts-expect-error + && node.declarations.some(declaration => declaration.id.name === name), + ); return {returnNode: returnStatement?.argument, declaredInCurrentFunction}; } @@ -218,12 +228,11 @@ function getNewExpressionType(fillArgument, context) { } /** - @param {Node} node + @param {undefined | Node} node @param {import('eslint').Rule.RuleContext} context @returns {[is: false] | [is: true, node: Node]} */ function isReferenceType(node, context) { - log('[isReferenceType]: ', node); if (!node) { return [false]; } @@ -299,8 +308,6 @@ function getMemberExpressionLeafNode(node, context) { // The chain names: [ 'obj', 'a', 'b', 'c', 'list' ] // if the MemberExpression is `obj.a.b.c.list` - // @ts-ignore - log('chain names:', chain.map(node => node.name ?? node.property?.name)); // @ts-expect-error `chain[0].name` cannot be undefined because the previous check ensures const variable = findVariableDefinition({node, variableName: chain[0].name, context}); @@ -313,19 +320,16 @@ function getMemberExpressionLeafNode(node, context) { for (let index = 1; index < chain.length; index++) { const currentPropertyInChain = chain[index].property; - // .log(`#${index}`, 'currentPropertyInChain:', currentPropertyInChain?.type, currentPropertyInChain); - // .log(`#${index}`, 'currentObject:', currentObject); if (!currentObject || currentObject.type !== 'ObjectExpression') { return; } const property = currentObject.properties.find( // @ts-expect-error - p => p.key.type === 'Identifier' + property_ => property_.key.type === 'Identifier' // @ts-expect-error - && p.key.name === (currentPropertyInChain.type === 'Identifier' ? currentPropertyInChain.name : currentPropertyInChain.value), + && property_.key.name === (currentPropertyInChain.type === 'Identifier' ? currentPropertyInChain.name : currentPropertyInChain.value), ); - // .log(`#${index}`, 'property:', property); if (!property) { return; @@ -356,7 +360,6 @@ function getPropertyAccessChain(node) { while (current) { times += 1; if (times > RECURSION_LIMIT) { - log('Skip deep-nested member checks for performance and to prevent potential infinite loops.'); return; } @@ -423,7 +426,6 @@ function findVariableDefinition({variableName, node, context}) { const scope = context.sourceCode.getScope(node); const {variables} = scope; - log('[findVariableDefinition] variables', variables); const variable = variables.find(v => v.name === variableName); if (variable) { @@ -443,8 +445,6 @@ function isIdentifierReferenceType(node, context) { const variable = findVariableDefinition({variableName: node.name, node, context}); const definitionNode = variable?.defs[0]?.node; - log({definitionNode}); - if (!variable || !definitionNode) { return [false]; } diff --git a/test/string-content.js b/test/string-content.js index 8b409e9dff..d36a06da66 100644 --- a/test/string-content.js +++ b/test/string-content.js @@ -223,7 +223,6 @@ test({ 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')[0]), }, // Escape From 2063c399b43a6bcdcaa4264111ccb70b1840fefe Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 24 Oct 2025 13:55:24 +0800 Subject: [PATCH 56/63] refactor: rename function name to clear ambiguousness and remove similar case in readme --- .vscode/settings.json | 7 ++++ .../no-array-fill-with-reference-type.md | 11 ------ rules/no-array-fill-with-reference-type.js | 39 +++++++++++++------ 3 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..d5ead6460c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "[javascript]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + // "editor.defaultFormatter": "biomejs.biome" + } +} diff --git a/docs/rules/no-array-fill-with-reference-type.md b/docs/rules/no-array-fill-with-reference-type.md index a4b2e977cb..ef4ce51063 100644 --- a/docs/rules/no-array-fill-with-reference-type.md +++ b/docs/rules/no-array-fill-with-reference-type.md @@ -59,17 +59,6 @@ Array.from({ length: 3 }).fill(new Date()); Array.from({ length: 3 }, () => new Date()); ``` -```js -// ❌ Class -class BarClass {}; -new Array(3).fill(new BarClass()); -Array(3).fill(new BarClass()); -Array.from({ length: 3 }).fill(new BarClass()); - -// ✅ -Array.from({ length: 3 }, () => new BarClass()); -``` - ```js // ❌ Function new Array(3).fill(function () {}) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 48836b023f..f8efb26fe5 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -12,7 +12,8 @@ import { // @ts-check const MESSAGE_ID_ERROR = 'no-array-fill-with-reference-type/error'; const messages = { - [MESSAGE_ID_ERROR]: 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { return independent instance })` instead to ensure no reference shared.', + [MESSAGE_ID_ERROR]: + 'Avoid using `{{actual}}` with reference type{{type}}. Use `Array.from({ ... }, () => { return independent instance })` instead to ensure no reference shared.', }; const DEFAULTS = { @@ -41,7 +42,9 @@ const create = context => ({ return; } - const fillArgument = isArrayFill ? node.arguments[0] : getArrayFromReturnNode(node, context); + const fillArgument = isArrayFill + ? node.arguments[0] + : getReturnNodeOfArrayDotFrom(node, context); const [is, resolvedNode] = isReferenceType(fillArgument, context); @@ -72,22 +75,22 @@ const create = context => ({ /** - @param {import('estree').CallExpression} node + @param {import('estree').CallExpression} functionNode @param {RuleContext} context @returns */ -function getArrayFromReturnNode(node, context) { - const secondArgument = node.arguments[1]; +function getReturnNodeOfArrayDotFrom(functionNode, context) { + const secondArgument = functionNode.arguments[1]; // Array.from({ length: 10 }, () => { return sharedObject; }); let result; if (secondArgument && isFunction(secondArgument)) { result = getReturnIdentifier(secondArgument, context); // @ts-expect-error node always has a parent - } else if (isMemberExpression(node.parent, 'map')) { + } else if (isMemberExpression(functionNode.parent, 'map')) { // Array.from({ length: 10 }).map(() => { return sharedObject; }); // @ts-expect-error node always has a parent - result = getReturnIdentifier(node.parent.parent.arguments[0], context); + result = getReturnIdentifier(functionNode.parent.parent.arguments[0], context); } // Should not check reference type if the identifier is declared in the current function @@ -152,12 +155,16 @@ function getReturnIdentifier(node, context) { const returnStatement = nodeBody.body.find(node => node.type === 'ReturnStatement'); const name = returnStatement?.argument?.name; if (!name) { - return {returnNode: returnStatement?.argument, declaredInCurrentFunction: true}; + return { + returnNode: returnStatement?.argument, + declaredInCurrentFunction: true, + }; } const declaredInCurrentFunction = nodeBody.body.some( // @ts-expect-error - node => node.type === 'VariableDeclaration' + node => + node.type === 'VariableDeclaration' // @ts-expect-error && node.declarations.some(declaration => declaration.id.name === name), ); @@ -217,7 +224,10 @@ function getNewExpressionType(fillArgument, context) { // NewExpression.callee not always have a name. // new A.B() and new class {} // Try the best to get the type from source code - const matches = context.sourceCode.getText(fillArgument.callee).split('\n')[0].match(/\S+/); + const matches = context.sourceCode + .getText(fillArgument.callee) + .split('\n')[0] + .match(/\S+/); if (matches) { // Limit the length to avoid too long tips @@ -442,7 +452,11 @@ function findVariableDefinition({variableName, node, context}) { @returns {[is: false] | [is: true, node: Node]} */ function isIdentifierReferenceType(node, context) { - const variable = findVariableDefinition({variableName: node.name, node, context}); + const variable = findVariableDefinition({ + variableName: node.name, + node, + context, + }); const definitionNode = variable?.defs[0]?.node; if (!variable || !definitionNode) { @@ -483,7 +497,8 @@ const config = { meta: { type: 'problem', docs: { - description: 'Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements.', + description: + 'Disallows using `Array.fill()` or `Array.from().fill()` with **reference types** to prevent unintended shared references across array elements.', recommended: true, }, schema, From 4990e6ba7c3dcf2ae1eade225792d4272bb0e399 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 24 Oct 2025 16:58:53 +0800 Subject: [PATCH 57/63] refactor: make code intent more obvious --- rules/no-array-fill-with-reference-type.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index f8efb26fe5..3044cb6669 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -153,8 +153,11 @@ function getReturnIdentifier(node, context) { // @ts-expect-error const returnStatement = nodeBody.body.find(node => node.type === 'ReturnStatement'); - const name = returnStatement?.argument?.name; - if (!name) { + + // const list = Array.from({ length: 3 }, () => { + // return {} // <= the returnStatement has no name or type !== 'Identifier' we can return here + // }); + if (returnStatement?.argument?.type !== 'Identifier') { return { returnNode: returnStatement?.argument, declaredInCurrentFunction: true, @@ -166,7 +169,7 @@ function getReturnIdentifier(node, context) { node => node.type === 'VariableDeclaration' // @ts-expect-error - && node.declarations.some(declaration => declaration.id.name === name), + && node.declarations.some(declaration => declaration.id.name === returnStatement?.argument?.name), ); return {returnNode: returnStatement?.argument, declaredInCurrentFunction}; From 8dd83fa9d49031d46b0acd120e376285a26d2a69 Mon Sep 17 00:00:00 2001 From: legend80s Date: Fri, 24 Oct 2025 17:26:19 +0800 Subject: [PATCH 58/63] refactor: make declaredInCurrentFunction more readable --- rules/no-array-fill-with-reference-type.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 3044cb6669..c39e0e7e0e 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -94,7 +94,8 @@ function getReturnNodeOfArrayDotFrom(functionNode, context) { } // Should not check reference type if the identifier is declared in the current function - if (result?.declaredInCurrentFunction) { + // or is global + if (result?.declaredInCurrentFunction || result?.isGlobal) { return; } @@ -107,7 +108,7 @@ function getReturnNodeOfArrayDotFrom(functionNode, context) { @param {import('estree').FunctionExpression | Node} node - callback for map @param {RuleContext} context - @returns {{ returnNode: Node, declaredInCurrentFunction: boolean }} + @returns {{ returnNode: Node, declaredInCurrentFunction: boolean, isGlobal?: boolean }} */ function getReturnIdentifier(node, context) { if (node.type === 'Identifier') { @@ -117,7 +118,7 @@ function getReturnIdentifier(node, context) { if (!variable) { // Not check if the identifier is not declared - return {returnNode: node, declaredInCurrentFunction: true}; + return {returnNode: node, declaredInCurrentFunction: false, isGlobal: true}; } // Must be ArrowFunctionExpression or FunctionExpression From f5348dfc65c33bcc46525231bca2c8d4c228795c Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 27 Oct 2025 08:58:29 +0800 Subject: [PATCH 59/63] refactor: simplify return value of isReferenceType and rename it to make the function intent more clearer --- rules/no-array-fill-with-reference-type.js | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index c39e0e7e0e..46ff697901 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -46,9 +46,9 @@ const create = context => ({ ? node.arguments[0] : getReturnNodeOfArrayDotFrom(node, context); - const [is, resolvedNode] = isReferenceType(fillArgument, context); + const referenceNode = getReference(fillArgument, context); - if (!is) { + if (referenceNode === undefined) { return; } @@ -60,7 +60,7 @@ const create = context => ({ ? 'Array.from().fill()' : 'Array.fill()'; - const type = getType(resolvedNode, context); + const type = getType(referenceNode, context); return { node: fillArgument, @@ -244,11 +244,11 @@ function getNewExpressionType(fillArgument, context) { /** @param {undefined | Node} node @param {import('eslint').Rule.RuleContext} context - @returns {[is: false] | [is: true, node: Node]} + @returns {undefined | Node} return undefined if node is not a reference type */ -function isReferenceType(node, context) { +function getReference(node, context) { if (!node) { - return [false]; + return undefined; } /** @type {typeof DEFAULTS} */ @@ -261,45 +261,45 @@ function isReferenceType(node, context) { if (node.type === 'Literal') { // Exclude regular expression literals (e.g., `/pattern/`, which are objects despite being literals). if (!options.allowRegularExpressions && isRegexLiteral(node)) { - return [true, node]; + return node; } - return [false]; + return undefined; } // For template literals. if (node.type === 'TemplateLiteral') { - return [false]; + return undefined; } // For variable identifiers (recursively check its declaration). if (node.type === 'Identifier') { - return isIdentifierReferenceType(node, context); + return getIdentifierReference(node, context); } if (isSymbol(node)) { - return [false]; + return undefined; } if (options.allowFunctions && isFunction(node)) { - return [false]; + return undefined; } if (options.allowRegularExpressions && isNewExpression(node, 'RegExp')) { - return [false]; + return undefined; } if (isMemberExpression(node)) { const propertyNode = getMemberExpressionLeafNode(node, context); if (!propertyNode) { - return [false]; + return undefined; } - return isReferenceType(propertyNode, context); + return getReference(propertyNode, context); } // Other cases: objects, arrays, new expressions, regular expressions, etc. - return [true, node]; + return node; } /** @@ -453,9 +453,9 @@ function findVariableDefinition({variableName, node, context}) { @param {*} node @param {import('eslint').Rule.RuleContext} context - @returns {[is: false] | [is: true, node: Node]} + @returns {undefined | Node} return undefined if it's not a reference type */ -function isIdentifierReferenceType(node, context) { +function getIdentifierReference(node, context) { const variable = findVariableDefinition({ variableName: node.name, node, @@ -464,20 +464,20 @@ function isIdentifierReferenceType(node, context) { const definitionNode = variable?.defs[0]?.node; if (!variable || !definitionNode) { - return [false]; + return undefined; } // Check `const foo = []; Array(3).fill(foo);` if (definitionNode.type === 'VariableDeclarator') { // Not check `let` `let foo = []; Array(3).fill(foo);` if (definitionNode.parent.kind === 'let') { - return [false]; + return undefined; } - return isReferenceType(definitionNode.init, context); + return getReference(definitionNode.init, context); } - return isReferenceType(definitionNode, context); + return getReference(definitionNode, context); } const schema = [ From 8c950170c0012899b48aa11579897763eb00189d Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 27 Oct 2025 09:05:18 +0800 Subject: [PATCH 60/63] refactor: rename function and argument name --- rules/no-array-fill-with-reference-type.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 46ff697901..c526f7296f 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -60,7 +60,7 @@ const create = context => ({ ? 'Array.from().fill()' : 'Array.fill()'; - const type = getType(referenceNode, context); + const type = getDescription(referenceNode, context); return { node: fillArgument, @@ -177,12 +177,12 @@ function getReturnIdentifier(node, context) { } /** - @param {*} fillArgument + @param {Node} node @param {import('eslint').Rule.RuleContext} context @returns {string} */ -function getType(fillArgument, context) { - switch (fillArgument.type) { +function getDescription(node, context) { + switch (node.type) { case 'ObjectExpression': { return 'Object'; } @@ -192,7 +192,7 @@ function getType(fillArgument, context) { } case 'NewExpression': { - return getNewExpressionType(fillArgument, context); + return getNewExpressionType(node, context); } case 'FunctionExpression': @@ -201,12 +201,16 @@ function getType(fillArgument, context) { } default: { - if (fillArgument.type === 'Literal' && fillArgument.regex) { + if ( + node.type === 'Literal' + // @ts-expect-error + && node.regex + ) { return 'RegExp'; } - if (fillArgument.type === 'Identifier') { - return `variable (${fillArgument.name})`; + if (node.type === 'Identifier') { + return `variable (${node.name})`; } } } From 16b9e9ab57282284facea5817b4bb2036a56c239 Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 27 Oct 2025 09:23:12 +0800 Subject: [PATCH 61/63] refactor: clarify comment --- rules/no-array-fill-with-reference-type.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index c526f7296f..9cba7a00c3 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -82,8 +82,8 @@ const create = context => ({ function getReturnNodeOfArrayDotFrom(functionNode, context) { const secondArgument = functionNode.arguments[1]; - // Array.from({ length: 10 }, () => { return sharedObject; }); let result; + // Array.from({ length: 10 }, () => { return sharedObject; }); if (secondArgument && isFunction(secondArgument)) { result = getReturnIdentifier(secondArgument, context); // @ts-expect-error node always has a parent @@ -93,8 +93,9 @@ function getReturnNodeOfArrayDotFrom(functionNode, context) { result = getReturnIdentifier(functionNode.parent.parent.arguments[0], context); } - // Should not check reference type if the identifier is declared in the current function - // or is global + // Should not check reference type: + // 1. if the identifier is declared in the current function(so the reference type is created at every callback therefor not a **shared** reference.) + // 2. or is global (we cannot know if it is a reference type or not.) if (result?.declaredInCurrentFunction || result?.isGlobal) { return; } @@ -117,7 +118,7 @@ function getReturnIdentifier(node, context) { const variable = findVariable(scope, node); if (!variable) { - // Not check if the identifier is not declared + // Not check if the identifier is not declared, most likely it is a builtin global return {returnNode: node, declaredInCurrentFunction: false, isGlobal: true}; } From 9e2b96e28d64fd473a26f8e2136a36beffe2c2be Mon Sep 17 00:00:00 2001 From: legend80s Date: Mon, 27 Oct 2025 10:04:53 +0800 Subject: [PATCH 62/63] refactor: split Array.from(arrayLike, mapper1) and Array.from().map(mapper2) apart so the code paths are easier to follow --- rules/no-array-fill-with-reference-type.js | 30 +++++++----------- .../no-array-fill-with-reference-type.js.md | 10 +++--- .../no-array-fill-with-reference-type.js.snap | Bin 2755 -> 2746 bytes 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 9cba7a00c3..681deaada7 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -35,8 +35,13 @@ const create = context => ({ // `arr.fill()` or `new Array().fill()` or `Array.from().fill()` const isArrayFill = isMethodCall(node, {method: 'fill', argumentsLength: 1}); - // `Array.from().map` or `Array.from(arrayLike, mapper)` - const isArrayFrom = isMethodCall(node, {object: 'Array', method: 'from'}); + // 1. `Array.from(arrayLike, mapper1)` + const isArrayFromMap = isMethodCall(node, {object: 'Array', method: 'from', argumentsLength: 2}); + // 2. or `Array.from().map(mapper2)` + // @ts-expect-error + const isArrayFromDotMap = isMethodCall(node.callee.object, {object: 'Array', method: 'from', argumentsLength: 1}) + && isMemberExpression(node.callee, 'map'); + const isArrayFrom = isArrayFromMap || isArrayFromDotMap; if (!isArrayFill && !isArrayFrom) { return; @@ -44,7 +49,7 @@ const create = context => ({ const fillArgument = isArrayFill ? node.arguments[0] - : getReturnNodeOfArrayDotFrom(node, context); + : getCallbackReturnNode(isArrayFromMap ? node.arguments[1] : node.arguments[0], context); const referenceNode = getReference(fillArgument, context); @@ -57,7 +62,7 @@ const create = context => ({ node.callee.object, {object: 'Array', method: 'from'}, ) - ? 'Array.from().fill()' + ? 'Array.from()' : 'Array.fill()'; const type = getDescription(referenceNode, context); @@ -75,23 +80,12 @@ const create = context => ({ /** - @param {import('estree').CallExpression} functionNode + @param {import('estree').Expression | import('estree').SpreadElement} callbackExpression @param {RuleContext} context @returns */ -function getReturnNodeOfArrayDotFrom(functionNode, context) { - const secondArgument = functionNode.arguments[1]; - - let result; - // Array.from({ length: 10 }, () => { return sharedObject; }); - if (secondArgument && isFunction(secondArgument)) { - result = getReturnIdentifier(secondArgument, context); - // @ts-expect-error node always has a parent - } else if (isMemberExpression(functionNode.parent, 'map')) { - // Array.from({ length: 10 }).map(() => { return sharedObject; }); - // @ts-expect-error node always has a parent - result = getReturnIdentifier(functionNode.parent.parent.arguments[0], context); - } +function getCallbackReturnNode(callbackExpression, context) { + const result = getReturnIdentifier(callbackExpression, context); // Should not check reference type: // 1. if the identifier is declared in the current function(so the reference type is created at every callback therefor not a **shared** reference.) diff --git a/test/snapshots/no-array-fill-with-reference-type.js.md b/test/snapshots/no-array-fill-with-reference-type.js.md index 09ec6a07bf..3d2b1668fb 100644 --- a/test/snapshots/no-array-fill-with-reference-type.js.md +++ b/test/snapshots/no-array-fill-with-reference-type.js.md @@ -296,7 +296,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill({});␊ - | ^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^ Avoid using \`Array.from()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(18): new Array(3).fill(new Date()) @@ -326,7 +326,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | Array.from({ length: 3 }).fill(new Date())␊ - | ^^^^^^^^^^ Avoid using \`Array.from().fill()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^^^^^ Avoid using \`Array.from()\` with reference type (new Date()). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(20): const initialArray = []; new Array(3).fill(initialArray); // ✗ Variable (array) @@ -501,7 +501,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const obj = {}; Array.from({ length: 3 }).fill(obj);␊ - | ^^^ Avoid using \`Array.from().fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^ Avoid using \`Array.from()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(29): const map = new Map({ foo: "bar" }); Array.from({ length: 3 }, () => map); @@ -597,7 +597,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const object = {}; Array.from({length: 31}).map(() => object);␊ - | ^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^ Avoid using \`Array.from()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ ` ## invalid(35): import { ref } from 'vue' let id = 0 const sharedObj = { id: `random-id-${++id}`, name: 'Tom', date: '2020-10-1', } const dataGenerator = () => (sharedObj) const data = ref(Array.from({ length: 200 }).map(dataGenerator)) @@ -637,7 +637,7 @@ Generated by [AVA](https://avajs.dev). 10 | }␊ 11 |␊ > 12 | const dataGenerator = () => (sharedObj)␊ - | ^^^^^^^^^ Avoid using \`Array.fill()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ + | ^^^^^^^^^ Avoid using \`Array.from()\` with reference type (Object). Use \`Array.from({ ... }, () => { return independent instance })\` instead to ensure no reference shared.␊ 13 |␊ 14 | const data = ref(Array.from({ length: 200 }).map(dataGenerator))␊ 15 | ␊ diff --git a/test/snapshots/no-array-fill-with-reference-type.js.snap b/test/snapshots/no-array-fill-with-reference-type.js.snap index 98468a25b5530686260ea0c938b8628652306eb9..1867d7aecd06d49d5cfac96038be86f7422e2830 100644 GIT binary patch literal 2746 zcmV;r3PtrnRzVCGcpsz8P3T?41xv71r%p zK_am1SRacB00000000B+oLg)oXBEfeR8_SGBoL@V;&yN^ws#%JV>`*l*`%B8W>>u| zt8Q9Ih_cPt{+yldWX77A>~8Bd5A=!4BNA=Zm$r|*^TI2zO&{%=!J#cTe8wG*!Lziup$AU1BMgO77(p?T)M}?SfQn zfJW}ZreVmh7HY+EM^V+n-hOdSF*Uhs-qJ1eoA0*UvL)}79-4b(j(#!^&wVQM#VmjX z_XSU9i7GdVN}kcW$Cms2`~K(We?6Do2r~cxa36x7n>S(ej;^%f*i^JbIItgeo+}=} zUB$Wu2I&xkXe|QPt6c&G`<7xEUNQ;0-_VZ=Jt&vU&@Vxu2(3V3>%d>})d`<3h zEA3;5+lS$mCbS$`c&Wh-oUiX672ukyVpq0s7f}*XH5%u0=0;%6J$lh=U!!EF8mApoynF zO`I3jwG(S0=cXrDjMm3Bgz~A-GLJNWf?9bDY2`DS&{iZm@EBvU5l3Zi4AaoMT=tZ- zT5Lc|*Gvn#unw%M);MYGMoZ}{i1bBQN@?w%pq9RbwDd_&OQ|CliHZA};TGuyw(d|t zLgJQON>P0sA%8v~s`S22P+;pwVCA5|MtF-vVjE3()7p$l{Bc38-FI-R_) z)gN364t%$f2DZWnzC-4nPrwOx9Q*_l#iQXpSX@W3`>}MxV<(DffPay}=P$p}Z?5P% zm;BSJY??vv*Ae*5Q1Hlf0EX>=3;lBl`p3he$8i!5cq-b|{WPF{hM}hGd@cIga7i}o z_lI7e*Gzhs2iyhBcM$Vuz3wHU55z_cUr_O5@RpzxNGXZam%$E`K|QVv=r`Ui{sj-` z885h?Dh`n9EZ~cnsIeA(@Uuf zOeb_LHTmYn2GT&q)xanl7ym+p-}jctM%uKP72FE2qz zs|eCLKcsL|+!A~U0s1=v6k#q_aS32i!&49IEQ2Lp!n`b7q)_Cvr!|D>iO|uxYlK%o zA0j?~4&Qz7?1;#W*eAN?Pah21Zje@^t01=4#^#(#8rN@{H4YED7=D zG{c9S3QSAo zrO7KmFyV?3T0Ho(%$==YRK@4{TJCxxZ)&`ZNEJfoTmw6!pON+1iUTRtc5^)Kvs(6-|*680MB%4$=EGo&qH?E+Q)a%zE){GS252XT5nF*6ln+EHLQJ+dS0I zBGeZU>SVSPZ6cvI6yME z5wic2&LdYGFCuYlg>3+(^qNXC<83^qWq0T`_UlKLxLQ&=P_T?+QiL9Vi7FNZ=m+KY zI+ELQ61j~lD6S&kK#KfUB1MiZurZ4EfmiiAOx1M7k4>5miDgGP2tbIfkLY?2PE!0o zKq7m4&Q$-=O$^<`v0Q#($Ev6!SBSrgtANd+k6UXhe{|b4>D}5(|_ztV6}kwqy9Zv(N%cy8#D=thM!{ z1*N_4c<oBfOYrv z3(QN=cOR_N_zK*vrCOk(>BI!WZYIpm=AhO&AHR5yg`2GcT3Kt zWnWW;@hUz~g)ZvoJ&y<@*aP-*oFII@eF4Tz}Thb(}o^4(0jhUY=v* zc$V|~Jj?Iu@YWhF?gs4bLw`-!0~<~6EX4l1*@Fum?}r&-(PYKN%%@>aH~YW zDNUf@K0>nm%Ondf{N+V&ANu+esnlPhl>B&-l{$%({J+E#lsNmf`FbrdY8#|BMw#v9 z=~!g^EVOZZwnjlF^~C$5r&WdUqjKpa#G{}uxOJvcQe-X3FZa=1I$!J$ZcN$0Q}rm AmjD0& literal 2755 zcmV;!3Ow~eRzVbGP4WH&ng(lKEQcZDJ{wO77+q?Y68ct%6is z0gc>&4a1OMF4T(UwxX(q-M!+fVrp{7ys2B}x8H8HWJ}&IJuvf$8G2+MocUblD_H;u z?g^gG5>;*xl{~3+jx6{25B$&1{$?h-9%cXl;2s2z8#iF%wyw0`$W*ig*tZ{bo-6Ld z9mTo{25A$6XiWmv%N+s*`<7xEUN8x}-_Q>WT_~5!&?`Zq2y5%m1%p^eh6ak(A|0Z& zh-QJJnU+jV^@{uUKSXYUr32B-BZGjZ`${u!$_8nb-FH_u4MR6TnwPw&=e?*`xlwoi zEAm1wq0m1p3_UZ!i~k={{C_8of8UB2f_)?;aq3-m9buK`*qi`hbr0BrFr%)@9jab099QK|5ZWaKZ80>pJbNg}SLF^j z(>{r~eH5N)Ld%hfmn!X?;wFgUqLAShvHT3T2q*E9F!b!9NN*8qc!omD<6-C&ck&FE zJcdhLhVvcSvWTJ0_ZeO%2b*_&sragkaRXtj2{8&y@~Y1Z$Y?dYn+53FNOH2O>UXY_ zgCkWoHt%)}Vw#GsnYk5c%c@DT0KM#w#LkXh7LMTw(8Lp- zCe8`-+VQoJbHkG>M(g7$Liu=Tnn#*HMy))IwDM3Uv=)hWJVsw^$X=Q2!z9!$mpmmc z7gwOEYo-MqSOb<-tDG=)qNVgKB7MP?Qd;}RsHLwWEq&J0QfkjdV&WcCTq8Zl<{c_X zNZgc5DXMQGJa9*oG6{q*h}Rf8NXP&{>9}9Tf8Ic02E@ z_4}8C9p5dafz9xa?|^yd2o%EY2S18L@rCdfEN(%u+p%=rW5$o1uUPsKH z$m50gQ1*4dzAhVz+)xSFr-K@L5ozc-)NzenmLDH3kgJ^~q@4opXO5!K1e$SmGu2b6 zb4(|6E;ae$#X8bJ#nr$t3m5-Hgg@}6$c9?9nC1lww!$PWd4xPiRH7YNH&>trJzrdc zkd_govwle7rno7XMS%W;07aOKm0SW?)NpZ1n4MwF#50+fWQ!DvoNBd(XgwO*Nq3F# z^5`Rk=}+N{5S|?opdp(^*Zj$YVXF?(a&$6%Y?miRMnjvJD{mG$OvfdIHf$7=HM_SX0IV-#Ucchg+h?{`E zOA!q~Vy>RQ6M(kJ(DLWgTsL|=wpE1XkqEYeuG47Y3i`>RK1DU}(~OsG3aRq<$_=>D z?E#lGTFA)EN0G+n#tnTZ^Jzr=<4EcQ{zVC3m@0gNv@p-Kz~7eFc3q|Z@Du(VqIO0o zgF#E>_WVyog8@LWf>`JHzjo_1TI8Db*Ov zE@J{1v9WPgynAn>e38GSImy`AHNwlte<3&@Mr>zx?L?AEx0ShkaRQ*MGbl@J2-Q?g zcQ&;dG9lkoO&+K#2-GqfA|)`)O|2ZF_jx=7N@83@RD4W(@@+8A=NM?1W?4_OpSS0Yy<&m)a&hOG*vEH#yKMq7tW%97D5>^n)7xLQ)$P_T?6 zQiLvlrYaT$=mq8WDw5k#61k1aDXt=4LyG)PB1MkOu@Q>)zE|~IOx1MakByxUh-G`& zcR+}(hv<3_j#KWESx!|f zV#q3(_KwWl38dGLkUW17BfXB@X>MA*gZ%z!jI=s_zhQFHX&TdrZ49r~{Np&f1BMQV z5C%qpx#!%;S=el&-qf}u_$)vb?!l>3fnu@%HTz1e;<5mB`);mi(RbBnAIn6Ry`Hda zuWB8gg z-vUZ&1@;YDYw3q`N^9ln9^acdc2Jm@Vo z=T0Z{`thOX7Mx3qzN!kvi(Xu^FP;)bj^1+4xy2ttdV1M89gHSTyo!C1R>hL@Dw4m# zj0`h5MVuhm$+w#XVh z*)ZH`7H{%@m7Zh2*%WNp&ZCB{j2gBmYupCx6q5VDXHWwcX)$&~HN_jQzQ(|LKLkO) zl;z*&9mI47VfwOf6>#ub-s0cy5tDcQi+_Q~`2?mR2SxEd&Eid0fTCml7>e~5-B`zo z^Lr@Hzx3i9BgWGl-)C5Smj_qaXmYQ>?jH13g*5zhj z5xx?4-7Q5?vFo&uHgIYyyIbtn!YV;=tUwnU^rJ~XRK>KM&^mvy0$gsCn`QbWFO$EI zr1LG&06Ug5Y~-KJsqiU)22$LXa0(!vhwEuQj6YE@HM^Z7=L_Co!j$~NtR_+Bu?hL- zNGCs;5$PnJ_XAQ+kOB2{`VxRZO8r|UdZsjng!>rD^3UT;xbT-3y?yBGk0n!ojY9IXac1f`Lh}C Date: Mon, 27 Oct 2025 10:34:26 +0800 Subject: [PATCH 63/63] fix: fix eslint errors --- rules/no-array-fill-with-reference-type.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rules/no-array-fill-with-reference-type.js b/rules/no-array-fill-with-reference-type.js index 681deaada7..e4c10feaa0 100644 --- a/rules/no-array-fill-with-reference-type.js +++ b/rules/no-array-fill-with-reference-type.js @@ -150,8 +150,8 @@ function getReturnIdentifier(node, context) { // @ts-expect-error const returnStatement = nodeBody.body.find(node => node.type === 'ReturnStatement'); - // const list = Array.from({ length: 3 }, () => { - // return {} // <= the returnStatement has no name or type !== 'Identifier' we can return here + // For case: const list = Array.from({ length: 3 }, () => { + // return {} // <= the returnStatement has no name or type !== 'Identifier' we can return here // }); if (returnStatement?.argument?.type !== 'Identifier') { return { @@ -247,7 +247,7 @@ function getNewExpressionType(fillArgument, context) { */ function getReference(node, context) { if (!node) { - return undefined; + return; } /** @type {typeof DEFAULTS} */ @@ -263,12 +263,12 @@ function getReference(node, context) { return node; } - return undefined; + return; } // For template literals. if (node.type === 'TemplateLiteral') { - return undefined; + return; } // For variable identifiers (recursively check its declaration). @@ -277,21 +277,21 @@ function getReference(node, context) { } if (isSymbol(node)) { - return undefined; + return; } if (options.allowFunctions && isFunction(node)) { - return undefined; + return; } if (options.allowRegularExpressions && isNewExpression(node, 'RegExp')) { - return undefined; + return; } if (isMemberExpression(node)) { const propertyNode = getMemberExpressionLeafNode(node, context); if (!propertyNode) { - return undefined; + return; } return getReference(propertyNode, context); @@ -463,14 +463,14 @@ function getIdentifierReference(node, context) { const definitionNode = variable?.defs[0]?.node; if (!variable || !definitionNode) { - return undefined; + return; } // Check `const foo = []; Array(3).fill(foo);` if (definitionNode.type === 'VariableDeclarator') { // Not check `let` `let foo = []; Array(3).fill(foo);` if (definitionNode.parent.kind === 'let') { - return undefined; + return; } return getReference(definitionNode.init, context);