Skip to content

feat: add new rule no-array-fill-with-reference-type without fix solution #2661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
87f000c
docs: add tips of how to install for new developers
May 29, 2025
a8f6d3f
fix: error when npm run create-rule > Cannot find package 'lodash-es'…
May 29, 2025
ea97dd1
feat: add new rule no-array-fill-with-reference-type without fix solu…
May 29, 2025
35057ee
feat(no-array-fill-with-reference-type): only check fill on builtin A…
May 29, 2025
aded9b0
test(no-array-fill-with-reference-type): add more valid cases
May 29, 2025
57f4d74
docs(no-array-fill-with-reference-type): remove comments
May 29, 2025
85bb03a
docs(no-array-fill-with-reference-type): gen code by npm run fix:esli…
May 29, 2025
3977224
docs(no-array-fill-with-reference-type): brief the desc and recover r…
May 29, 2025
8243f14
docs: no file configs/recommended.js
May 29, 2025
3635dd3
docs(no-array-fill-with-reference-type): gen code by npm run fix:esli…
May 29, 2025
fcd690e
docs: add tips of how to install for new developers
legend80s May 29, 2025
51af337
fix: error when npm run create-rule > Cannot find package 'lodash-es'…
legend80s May 29, 2025
09ca3b5
feat: add new rule no-array-fill-with-reference-type without fix solu…
legend80s May 29, 2025
b20ddf2
feat(no-array-fill-with-reference-type): only check fill on builtin A…
legend80s May 29, 2025
c70d17f
test(no-array-fill-with-reference-type): add more valid cases
legend80s May 29, 2025
7c7fa38
docs(no-array-fill-with-reference-type): remove comments
legend80s May 29, 2025
d3a4179
docs(no-array-fill-with-reference-type): gen code by npm run fix:esli…
legend80s May 29, 2025
681827d
docs(no-array-fill-with-reference-type): brief the desc and recover r…
legend80s May 29, 2025
a6ca789
docs: no file configs/recommended.js
legend80s May 29, 2025
2091479
docs(no-array-fill-with-reference-type): gen code by npm run fix:esli…
legend80s May 29, 2025
d80842c
Merge branch 'main' of github.com:legend80s/eslint-plugin-unicorn
legend80s May 29, 2025
90b768b
feat(no-array-fill-with-reference-type): no fixable
legend80s May 29, 2025
a0841ad
docs(no-array-fill-with-reference-type): no fixable
legend80s May 29, 2025
ab37dcb
feat(no-array-fill-with-reference-type): check Array.from().fill
legend80s May 29, 2025
6b14629
docs(no-array-fill-with-reference-type): correct docs
legend80s May 29, 2025
b6bf56c
docs(no-array-fill-with-reference-type): correct docs by npm run fix:…
legend80s May 29, 2025
928e51a
test: disable no-array-fill-with-reference-type because it is safe du…
legend80s May 30, 2025
36b04e3
feat: hide unknown type in error message
legend80s May 30, 2025
4f4cf65
test: hide unknown type in error message
legend80s May 30, 2025
3813e76
test: add a case of hiding unknown type in error message
legend80s May 30, 2025
2a7ffee
feat: report precisely on node.arguments[0] only.
legend80s Jun 4, 2025
d5f2398
feat(no-array-fill-with-reference-type): report precisely on node.arg…
legend80s Jun 4, 2025
0d5c73c
chore(no-array-fill-with-reference-type): merge with remote
legend80s Jun 4, 2025
639c593
test(no-array-fill-with-reference-type): add more case to improve cov…
legend80s Jun 4, 2025
9ab3fb0
test(no-array-fill-with-reference-type): fix ci failed. code gen by -u
legend80s Jun 4, 2025
4f3849f
feat: add option to not check for function expressions by default bec…
legend80s Jun 5, 2025
ef37d48
docs: add option to not check for function
legend80s Jun 5, 2025
2d499c0
Merge branch 'main' into main
legend80s Jun 10, 2025
bac577b
style: add new line to fix lint errors
legend80s Jun 10, 2025
59b4ae8
feat(no-array-fill-with-reference-type): ignore regexp literal and ne…
legend80s Jun 13, 2025
04a2a55
docs(no-array-fill-with-reference-type): ignore regexp literal and ne…
legend80s Jun 13, 2025
9b80603
docs(no-array-fill-with-reference-type): more precise suggestion tips
legend80s Jun 13, 2025
00eb9a3
feat(no-array-fill-with-reference-type): try the best to retrie type …
legend80s Jun 13, 2025
b64f7cf
test(no-array-fill-with-reference-type): Class should be class to avo…
legend80s Jun 13, 2025
acaf4e7
feat(no-array-fill-with-reference-type): only check const
legend80s Jun 13, 2025
a7b36db
feat(no-array-fill-with-reference-type): report Array.from(arrayLike,…
legend80s Jun 18, 2025
2bc40f8
chore(no-array-fill-with-reference-type): fix npm run lint error
legend80s Jun 18, 2025
bc9f7f5
refactor(no-array-fill-with-reference-type): rename options
legend80s Jun 30, 2025
b87ec58
refactor(no-array-fill-with-reference-type): use existing util isMemb…
legend80s Jun 30, 2025
05893d1
fix(no-array-fill-with-reference-type): fix integration failed when c…
legend80s Jun 30, 2025
88b4528
test(no-array-fill-with-reference-type): fix integration test failed …
legend80s Jul 1, 2025
ed1f6ae
test(no-array-fill-with-reference-type): fix integration test failed.…
legend80s Jul 1, 2025
5e9494e
fix: correct return type for isMemberExpression function & add type p…
legend80s Jul 16, 2025
4bddea9
feat(no-array-fill-with-reference-type): check is member expression i…
legend80s Jul 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/new-rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -17,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 ``.
Expand Down
161 changes: 161 additions & 0 deletions docs/rules/no-array-fill-with-reference-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# 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).

<!-- end auto-generated rule header -->
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` -->

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
// ❌ 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());

// ✅
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 () {})
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 = []

// ❌ Shared reference
new Array(3).fill(box);
Array(3).fill(box);
Array.from({ length: 3 }).fill(box);

// ✅
Array.from({ length: 3 }, () => []);
```

## Options

### allowFunctions

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",
{
"allowFunctions": false
}
]
```

with `allowFunctions: false`, this would fail:

```js
new Array(3).fill(function () {})
```

### allowRegularExpressions

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",
{
"allowRegularExpressions": false
}
]
```

with `allowRegularExpressions: false`, this would fail:

```js
new Array(3).fill(/pattern/)
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"eslint-remote-tester-repositories": "^2.0.1",
"espree": "^10.4.0",
"listr2": "^8.3.3",
"lodash-es": "^4.17.21",
"markdownlint-cli": "^0.45.0",
"memoize": "^10.1.0",
"nano-spawn": "^1.0.2",
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +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()` 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()`. | ✅ | | |
Expand Down
16 changes: 16 additions & 0 deletions rules/ast/is-member-expression.d.ts
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 5 additions & 1 deletion rules/ast/is-member-expression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// @ts-check
/* eslint-disable complexity */
/**
@param {ESTreeNode} node
@param {
{
property?: string,
Expand All @@ -10,7 +12,7 @@
computed?: boolean
} | string | string[]
} [options]
@returns {string}
@returns {boolean}
*/
export default function isMemberExpression(node, options) {
if (node?.type !== 'MemberExpression') {
Expand Down Expand Up @@ -96,3 +98,5 @@ export default function isMemberExpression(node, options) {

return true;
}

/** @typedef {import('estree').Node} ESTreeNode */
1 change: 1 addition & 0 deletions rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export {default as 'no-abusive-eslint-disable'} from './no-abusive-eslint-disabl
export {default as 'no-accessor-recursion'} from './no-accessor-recursion.js';
export {default as 'no-anonymous-default-export'} from './no-anonymous-default-export.js';
export {default as 'no-array-callback-reference'} from './no-array-callback-reference.js';
export {default as 'no-array-fill-with-reference-type'} from './no-array-fill-with-reference-type.js';
export {default as 'no-array-for-each'} from './no-array-for-each.js';
export {default as 'no-array-method-this-argument'} from './no-array-method-this-argument.js';
export {default as 'no-array-reduce'} from './no-array-reduce.js';
Expand Down
Loading
Loading