Skip to content

Commit c406efa

Browse files
committed
refactor: refactor array methods utility functions
1 parent aea0f52 commit c406efa

File tree

13 files changed

+277
-46
lines changed

13 files changed

+277
-46
lines changed

packages/plugins/eslint-plugin-react-dom/src/rules/no-unsafe-iframe-sandbox.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ react-dom/no-unsafe-iframe-sandbox
2525

2626
Enforces `sandbox` attribute for `iframe` elements is not set to unsafe combinations.
2727

28-
If `sandbox` attribute is not set, the iframe content can have abilities that are not intended to be allowed.
28+
This rule reports cases where attribute contains `allow-scripts` and `allow-same-origin` at the same time as this combination allows the embedded document to remove the sandbox attribute and bypass the restrictions.
2929

3030
## Examples
3131

32-
This rule reports cases where attribute contains `allow-scripts` and `allow-same-origin` at the same time as this combination allows the embedded document to remove the sandbox attribute and bypass the restrictions.
33-
3432
### Failing
3533

3634
```tsx

packages/plugins/eslint-plugin-react-x/src/rules/no-array-index-key.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function getMapIndexParamName(context: RuleContext, node: TSESTree.CallExpressio
5151
return _;
5252
}
5353
const { name } = callee.property;
54-
const indexPosition = AST.getArrayMethodIndexParamPosition(name);
54+
const indexPosition = AST.getArrayMethodCallbackIndexParamPosition(name);
5555
if (indexPosition === -1) {
5656
return _;
5757
}

packages/plugins/eslint-plugin-react-x/src/rules/no-implicit-key.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ And it's also be proposed to be deprecated is this RFC: [Deprecate spreading key
3535

3636
## Examples
3737

38-
This rule aims to prevent spreading key from objects.
39-
4038
### Failing
4139

4240
```tsx

packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
116116
return;
117117
}
118118
const isMapCall = AST.isArrayMapCall(node);
119-
if (!isMapCall && !isArrayFromCall(node)) {
119+
if (!isMapCall && !AST.isArrayFromCall(node)) {
120120
return;
121121
}
122122
const fn = node.arguments[isMapCall ? 0 : 1];
@@ -148,10 +148,3 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
148148
},
149149
};
150150
}
151-
152-
function isArrayFromCall(node: TSESTree.Node): node is TSESTree.CallExpression {
153-
return node.type === T.CallExpression
154-
&& node.callee.type === T.MemberExpression
155-
&& node.callee.property.type === T.Identifier
156-
&& node.callee.property.name === "from";
157-
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: no-unnecessary-key
3+
---
4+
5+
**Full Name in `eslint-plugin-react-x`**
6+
7+
```plain copy
8+
react-x/no-unnecessary-key
9+
```
10+
11+
**Full Name in `@eslint-react/eslint-plugin`**
12+
13+
```plain copy
14+
@eslint-react/no-unnecessary-key
15+
```
16+
17+
**Features**
18+
19+
`🧪`
20+
21+
## Description
22+
23+
## Examples
24+
25+
### Failing
26+
27+
### Passing
28+
29+
## Implementation
30+
31+
- [Rule source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x/src/rules/no-unnecessary-key.ts)
32+
- [Test source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x/src/rules/no-unnecessary-key.spec.ts)
33+
34+
---
35+
36+
## See Also
37+
38+
- [`no-missing-key`](./no-missing-key)\
39+
Prevents missing `key` on items in list rendering.
40+
- [`no-duplicate-key`](./no-duplicate-key)\
41+
Prevents duplicate `key` on elements in the same array or a list of `children`.
42+
- [`no-implicit-key`](./no-implicit-key)\
43+
Prevents `key` from not being explicitly specified (e.g. spreading `key` from objects).
44+
- [`no-array-index-key`](./no-array-index-key)\
45+
Warns when an array `index` is used as a `key` prop.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import tsx from "dedent";
2+
3+
import { allValid, ruleTester } from "../../../../../test";
4+
import rule, { RULE_NAME } from "./no-implicit-key";
5+
6+
ruleTester.run(RULE_NAME, rule, {
7+
invalid: [
8+
{
9+
code: tsx`
10+
const props = { key: "1" };
11+
12+
const App = () => {
13+
return [
14+
<div {...props}>1</div>,
15+
<div {...props}>2</div>,
16+
<div {...props}>3</div>,
17+
]
18+
};
19+
`,
20+
errors: [
21+
{ messageId: "noImplicitKey" },
22+
{ messageId: "noImplicitKey" },
23+
{ messageId: "noImplicitKey" },
24+
],
25+
},
26+
{
27+
code: tsx`
28+
29+
const App = () => {
30+
const props = { key: "1" };
31+
32+
return [
33+
<div {...props}>1</div>,
34+
<div {...props}>2</div>,
35+
<div {...props}>3</div>,
36+
]
37+
};
38+
`,
39+
errors: [
40+
{ messageId: "noImplicitKey" },
41+
{ messageId: "noImplicitKey" },
42+
{ messageId: "noImplicitKey" },
43+
],
44+
},
45+
{
46+
code: tsx`
47+
const App = () => {
48+
return [
49+
<div {...{ key: "1" }}>1</div>,
50+
<div {...{ key: "2" }}>2</div>,
51+
<div {...{ key: "3" }}>3</div>,
52+
]
53+
};
54+
`,
55+
errors: [
56+
{ messageId: "noImplicitKey" },
57+
{ messageId: "noImplicitKey" },
58+
{ messageId: "noImplicitKey" },
59+
],
60+
},
61+
{
62+
code: tsx`
63+
const App = () => {
64+
return [
65+
<div {...{...{ key: "1" }}}>1</div>,
66+
<div {...{...{ key: "2" }}}>2</div>,
67+
<div {...{...{ key: "3" }}}>3</div>,
68+
]
69+
};
70+
`,
71+
errors: [
72+
{ messageId: "noImplicitKey" },
73+
{ messageId: "noImplicitKey" },
74+
{ messageId: "noImplicitKey" },
75+
],
76+
},
77+
{
78+
code: tsx`
79+
const props1 = { key: "1" };
80+
const App = () => {
81+
const props2 = { key: "1" };
82+
83+
return [
84+
<div key="0">0</div>,
85+
<div {...props1}>1</div>,
86+
<div {...props2}>2</div>,
87+
<div {...{...{...{ key: "3" }}}}>3</div>,
88+
]
89+
};
90+
`,
91+
errors: [
92+
{ messageId: "noImplicitKey" },
93+
{ messageId: "noImplicitKey" },
94+
{ messageId: "noImplicitKey" },
95+
],
96+
},
97+
{
98+
code: tsx`
99+
const props1 = { key: "1" };
100+
const props4 = { key: "4" };
101+
const App = () => {
102+
const props2 = { key: "1" };
103+
104+
return [
105+
<div key="0">0</div>,
106+
<div {...props1}>1</div>,
107+
<div {...props2}>2</div>,
108+
<div {...{...{...{ key: "3" }}}}>3</div>,
109+
<div {...{...{...props4}}}>4</div>,
110+
]
111+
};
112+
`,
113+
errors: [
114+
{ messageId: "noImplicitKey" },
115+
{ messageId: "noImplicitKey" },
116+
{ messageId: "noImplicitKey" },
117+
{ messageId: "noImplicitKey" },
118+
],
119+
},
120+
],
121+
valid: [
122+
...allValid,
123+
tsx`
124+
const App = () => {
125+
return [<div key="1">1</div>]
126+
};
127+
`,
128+
tsx`
129+
const App = () => {
130+
return [
131+
<div key="1">1</div>,
132+
<div key="2">2</div>,
133+
<div key="3">3</div>,
134+
]
135+
};
136+
`,
137+
tsx`
138+
const App = () => {
139+
return [1, 2, 3].map((item) => <div key={Math.random()}>{item}</div>)
140+
};
141+
`,
142+
],
143+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { RuleContext, RuleFeature } from "@eslint-react/kit";
2+
import type { TSESTree } from "@typescript-eslint/types";
3+
import type { RuleListener } from "@typescript-eslint/utils/ts-eslint";
4+
import type { CamelCase } from "string-ts";
5+
import * as JSX from "@eslint-react/jsx";
6+
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
7+
8+
import { createRule } from "../utils";
9+
10+
export const RULE_NAME = "no-implicit-key";
11+
12+
export const RULE_FEATURES = [
13+
"EXP",
14+
] as const satisfies RuleFeature[];
15+
16+
export type MessageID = CamelCase<typeof RULE_NAME>;
17+
18+
export default createRule<[], MessageID>({
19+
meta: {
20+
type: "problem",
21+
docs: {
22+
description: "Prevents `key` from not being explicitly specified (e.g. spreading `key` from objects).",
23+
[Symbol.for("rule_features")]: RULE_FEATURES,
24+
},
25+
messages: {
26+
noImplicitKey: "Do not use implicit 'key' props.",
27+
},
28+
schema: [],
29+
},
30+
name: RULE_NAME,
31+
create,
32+
defaultOptions: [],
33+
});
34+
35+
export function create(context: RuleContext<MessageID, []>): RuleListener {
36+
return {
37+
JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
38+
const initialScope = context.sourceCode.getScope(node);
39+
const keyProp = JSX.getAttribute("key", node.attributes, initialScope);
40+
},
41+
};
42+
}
43+
44+
function isInListRendering(node: TSESTree.JSXOpeningElement) {
45+
}

packages/plugins/eslint-plugin-react-x/src/rules/prefer-destructuring-assignment.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ Enforces destructuring assignment for component props and context.
2020

2121
## Examples
2222

23-
This rule aims to enforce the use of destructuring assignment over property assignment.
24-
2523
### Failing
2624

2725
```tsx

packages/utilities/ast/src/array-methods.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const indexParamPosition = new Map<string, number>([
2+
["every", 1],
3+
["filter", 1],
4+
["find", 1],
5+
["findIndex", 1],
6+
["findLast", 1],
7+
["findLastIndex", 1],
8+
["flatMap", 1],
9+
["forEach", 1],
10+
["map", 1],
11+
["reduce", 2],
12+
["reduceRight", 2],
13+
["some", 1],
14+
]);
15+
16+
export function getArrayMethodCallbackIndexParamPosition(methodName: string) {
17+
return indexParamPosition.get(methodName) ?? -1;
18+
}

0 commit comments

Comments
 (0)