@pobammer-ts/eslint-cease-nonsense-rules 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/rules/ban-react-fc.d.ts +7 -0
- package/dist/rules/ban-react-fc.js +78 -0
- package/dist/rules/ban-react-fc.js.map +1 -0
- package/dist/rules/prefer-sequence-overloads.d.ts +7 -0
- package/dist/rules/prefer-sequence-overloads.js +106 -0
- package/dist/rules/prefer-sequence-overloads.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,11 +24,13 @@ export default [
|
|
|
24
24
|
},
|
|
25
25
|
rules: {
|
|
26
26
|
// Enable all rules (recommended)
|
|
27
|
+
"cease-nonsense/ban-react-fc": "error",
|
|
27
28
|
"cease-nonsense/enforce-ianitor-check-type": "error",
|
|
28
29
|
"cease-nonsense/no-color3-constructor": "error",
|
|
29
30
|
"cease-nonsense/no-print": "error",
|
|
30
31
|
"cease-nonsense/no-shorthand-names": "error",
|
|
31
32
|
"cease-nonsense/no-warn": "error",
|
|
33
|
+
"cease-nonsense/prefer-sequence-overloads": "error",
|
|
32
34
|
"cease-nonsense/prefer-udim2-shorthand": "error",
|
|
33
35
|
"cease-nonsense/require-named-effect-functions": "error",
|
|
34
36
|
"cease-nonsense/require-react-component-keys": "error",
|
|
@@ -103,6 +105,46 @@ const config = userConfigValidator.check(getUserConfig());
|
|
|
103
105
|
|
|
104
106
|
### React
|
|
105
107
|
|
|
108
|
+
#### `ban-react-fc`
|
|
109
|
+
|
|
110
|
+
Bans React.FC and similar component type annotations. Use explicit function declarations instead.
|
|
111
|
+
|
|
112
|
+
React.FC (Function Component) and related types break debug information in React DevTools, making profiling exponentially harder. They also encourage poor patterns and add unnecessary complexity.
|
|
113
|
+
|
|
114
|
+
**❌ Bad:**
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
export const MyComponent: React.FC<Props> = ({ children }) => {
|
|
118
|
+
return <div>{children}</div>;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const Button: FC<ButtonProps> = ({ label }) => <button>{label}</button>;
|
|
122
|
+
|
|
123
|
+
const Modal: React.FunctionComponent = () => <div>Modal</div>;
|
|
124
|
+
|
|
125
|
+
const Input: VFC = () => <input />;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**✅ Good:**
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
export function MyComponent({ children }: Props) {
|
|
132
|
+
return <div>{children}</div>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function Button({ label }: ButtonProps) {
|
|
136
|
+
return <button>{label}</button>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function Modal() {
|
|
140
|
+
return <div>Modal</div>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function Input() {
|
|
144
|
+
return <input />;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
106
148
|
#### `require-react-component-keys`
|
|
107
149
|
|
|
108
150
|
Enforces key props on all React elements except top-level returns from components.
|
|
@@ -348,6 +390,38 @@ UDim2.fromOffset(100, 50);
|
|
|
348
390
|
new UDim2(0, 0, 0, 0); // Allowed
|
|
349
391
|
```
|
|
350
392
|
|
|
393
|
+
#### `prefer-sequence-overloads`
|
|
394
|
+
|
|
395
|
+
Prefer the optimized `ColorSequence` and `NumberSequence` constructor overloads instead of building an array of `*SequenceKeypoint`s for the 0/1 endpoints. Includes auto-fix.
|
|
396
|
+
|
|
397
|
+
**❌ Bad:**
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
new ColorSequence([
|
|
401
|
+
new ColorSequenceKeypoint(0, Color3.fromRGB(100, 200, 255)),
|
|
402
|
+
new ColorSequenceKeypoint(1, Color3.fromRGB(255, 100, 200)),
|
|
403
|
+
]);
|
|
404
|
+
|
|
405
|
+
new NumberSequence([
|
|
406
|
+
new NumberSequenceKeypoint(0, 0),
|
|
407
|
+
new NumberSequenceKeypoint(1, 100),
|
|
408
|
+
]);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**✅ Good:**
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
new ColorSequence(Color3.fromRGB(100, 200, 255), Color3.fromRGB(255, 100, 200));
|
|
415
|
+
|
|
416
|
+
new ColorSequence(Color3.fromRGB(255, 255, 255));
|
|
417
|
+
|
|
418
|
+
new NumberSequence(0, 100);
|
|
419
|
+
|
|
420
|
+
new NumberSequence(42);
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Automatically collapses identical 0/1 endpoints to the single-argument overload.
|
|
424
|
+
|
|
351
425
|
#### `no-shorthand-names`
|
|
352
426
|
|
|
353
427
|
Bans shorthand variable names in favor of descriptive full names.
|
package/dist/index.d.ts
CHANGED
|
@@ -24,11 +24,13 @@ declare const recommended: {
|
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
readonly rules: {
|
|
27
|
+
readonly "cease-nonsense/ban-react-fc": "error";
|
|
27
28
|
readonly "cease-nonsense/enforce-ianitor-check-type": "error";
|
|
28
29
|
readonly "cease-nonsense/no-color3-constructor": "error";
|
|
29
30
|
readonly "cease-nonsense/no-print": "error";
|
|
30
31
|
readonly "cease-nonsense/no-shorthand-names": "error";
|
|
31
32
|
readonly "cease-nonsense/no-warn": "error";
|
|
33
|
+
readonly "cease-nonsense/prefer-sequence-overloads": "error";
|
|
32
34
|
readonly "cease-nonsense/prefer-udim2-shorthand": "error";
|
|
33
35
|
readonly "cease-nonsense/require-named-effect-functions": "error";
|
|
34
36
|
readonly "cease-nonsense/require-react-component-keys": "error";
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import banReactFC from "./rules/ban-react-fc";
|
|
1
2
|
import enforceIanitorCheckType from "./rules/enforce-ianitor-check-type";
|
|
2
3
|
import noColor3Constructor from "./rules/no-color3-constructor";
|
|
3
4
|
import noPrint from "./rules/no-print";
|
|
4
5
|
import noShorthandNames from "./rules/no-shorthand-names";
|
|
5
6
|
import noWarn from "./rules/no-warn";
|
|
6
7
|
import preferUDim2Shorthand from "./rules/prefer-udim2-shorthand";
|
|
8
|
+
import preferSequenceOverloads from "./rules/prefer-sequence-overloads";
|
|
7
9
|
import requireNamedEffectFunctions from "./rules/require-named-effect-functions";
|
|
8
10
|
import requireReactComponentKeys from "./rules/require-react-component-keys";
|
|
9
11
|
import useExhaustiveDependencies from "./rules/use-exhaustive-dependencies";
|
|
@@ -14,11 +16,13 @@ import useHookAtTopLevel from "./rules/use-hook-at-top-level";
|
|
|
14
16
|
* Exposes rule implementations and configuration presets for ESLint flat config.
|
|
15
17
|
*/
|
|
16
18
|
const rules = {
|
|
19
|
+
"ban-react-fc": banReactFC,
|
|
17
20
|
"enforce-ianitor-check-type": enforceIanitorCheckType,
|
|
18
21
|
"no-color3-constructor": noColor3Constructor,
|
|
19
22
|
"no-print": noPrint,
|
|
20
23
|
"no-shorthand-names": noShorthandNames,
|
|
21
24
|
"no-warn": noWarn,
|
|
25
|
+
"prefer-sequence-overloads": preferSequenceOverloads,
|
|
22
26
|
"prefer-udim2-shorthand": preferUDim2Shorthand,
|
|
23
27
|
"require-named-effect-functions": requireNamedEffectFunctions,
|
|
24
28
|
"require-react-component-keys": requireReactComponentKeys,
|
|
@@ -48,11 +52,13 @@ const recommended = {
|
|
|
48
52
|
},
|
|
49
53
|
},
|
|
50
54
|
rules: {
|
|
55
|
+
"cease-nonsense/ban-react-fc": "error",
|
|
51
56
|
"cease-nonsense/enforce-ianitor-check-type": "error",
|
|
52
57
|
"cease-nonsense/no-color3-constructor": "error",
|
|
53
58
|
"cease-nonsense/no-print": "error",
|
|
54
59
|
"cease-nonsense/no-shorthand-names": "error",
|
|
55
60
|
"cease-nonsense/no-warn": "error",
|
|
61
|
+
"cease-nonsense/prefer-sequence-overloads": "error",
|
|
56
62
|
"cease-nonsense/prefer-udim2-shorthand": "error",
|
|
57
63
|
"cease-nonsense/require-named-effect-functions": "error",
|
|
58
64
|
"cease-nonsense/require-react-component-keys": "error",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,uBAAuB,MAAM,oCAAoC,CAAC;AACzE,OAAO,mBAAmB,MAAM,+BAA+B,CAAC;AAChE,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,gBAAgB,MAAM,4BAA4B,CAAC;AAC1D,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,oBAAoB,MAAM,gCAAgC,CAAC;AAClE,OAAO,2BAA2B,MAAM,wCAAwC,CAAC;AACjF,OAAO,yBAAyB,MAAM,sCAAsC,CAAC;AAC7E,OAAO,yBAAyB,MAAM,qCAAqC,CAAC;AAC5E,OAAO,iBAAiB,MAAM,+BAA+B,CAAC;AAI9D;;;;GAIG;AACH,MAAM,KAAK,GAA4C;IACtD,4BAA4B,EAAE,uBAAuB;IACrD,uBAAuB,EAAE,mBAAmB;IAC5C,UAAU,EAAE,OAAO;IACnB,oBAAoB,EAAE,gBAAgB;IACtC,SAAS,EAAE,MAAM;IACjB,wBAAwB,EAAE,oBAAoB;IAC9C,gCAAgC,EAAE,2BAA2B;IAC7D,8BAA8B,EAAE,yBAAyB;IACzD,6BAA6B,EAAE,yBAAyB;IACxD,uBAAuB,EAAE,iBAAiB;CACjC,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,GAAG;IACnB,OAAO,EAAE;QACR,gBAAgB,EAAE;YACjB,KAAK;SACL;KACD;IACD,KAAK,EAAE;QACN,2CAA2C,EAAE,OAAO;QACpD,sCAAsC,EAAE,OAAO;QAC/C,yBAAyB,EAAE,OAAO;QAClC,mCAAmC,EAAE,OAAO;QAC5C,wBAAwB,EAAE,OAAO;QACjC,uCAAuC,EAAE,OAAO;QAChD,+CAA+C,EAAE,OAAO;QACxD,6CAA6C,EAAE,OAAO;QACtD,4CAA4C,EAAE,OAAO;QACrD,sCAAsC,EAAE,OAAO;KAC/C;CACQ,CAAC;AAWX,MAAM,MAAM,GAAW;IACtB,OAAO,EAAE,EAAE,WAAW,EAAE;IACxB,KAAK;CACI,CAAC;AAEX,eAAe,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,UAAU,MAAM,sBAAsB,CAAC;AAC9C,OAAO,uBAAuB,MAAM,oCAAoC,CAAC;AACzE,OAAO,mBAAmB,MAAM,+BAA+B,CAAC;AAChE,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,gBAAgB,MAAM,4BAA4B,CAAC;AAC1D,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,oBAAoB,MAAM,gCAAgC,CAAC;AAClE,OAAO,uBAAuB,MAAM,mCAAmC,CAAC;AACxE,OAAO,2BAA2B,MAAM,wCAAwC,CAAC;AACjF,OAAO,yBAAyB,MAAM,sCAAsC,CAAC;AAC7E,OAAO,yBAAyB,MAAM,qCAAqC,CAAC;AAC5E,OAAO,iBAAiB,MAAM,+BAA+B,CAAC;AAI9D;;;;GAIG;AACH,MAAM,KAAK,GAA4C;IACtD,cAAc,EAAE,UAAU;IAC1B,4BAA4B,EAAE,uBAAuB;IACrD,uBAAuB,EAAE,mBAAmB;IAC5C,UAAU,EAAE,OAAO;IACnB,oBAAoB,EAAE,gBAAgB;IACtC,SAAS,EAAE,MAAM;IACjB,2BAA2B,EAAE,uBAAuB;IACpD,wBAAwB,EAAE,oBAAoB;IAC9C,gCAAgC,EAAE,2BAA2B;IAC7D,8BAA8B,EAAE,yBAAyB;IACzD,6BAA6B,EAAE,yBAAyB;IACxD,uBAAuB,EAAE,iBAAiB;CACjC,CAAC;AAEX;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,GAAG;IACnB,OAAO,EAAE;QACR,gBAAgB,EAAE;YACjB,KAAK;SACL;KACD;IACD,KAAK,EAAE;QACN,6BAA6B,EAAE,OAAO;QACtC,2CAA2C,EAAE,OAAO;QACpD,sCAAsC,EAAE,OAAO;QAC/C,yBAAyB,EAAE,OAAO;QAClC,mCAAmC,EAAE,OAAO;QAC5C,wBAAwB,EAAE,OAAO;QACjC,0CAA0C,EAAE,OAAO;QACnD,uCAAuC,EAAE,OAAO;QAChD,+CAA+C,EAAE,OAAO;QACxD,6CAA6C,EAAE,OAAO;QACtD,4CAA4C,EAAE,OAAO;QACrD,sCAAsC,EAAE,OAAO;KAC/C;CACQ,CAAC;AAWX,MAAM,MAAM,GAAW;IACtB,OAAO,EAAE,EAAE,WAAW,EAAE;IACxB,KAAK;CACI,CAAC;AAEX,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TSESLint } from "@typescript-eslint/utils";
|
|
2
|
+
type MessageIds = "banReactFC";
|
|
3
|
+
interface RuleDocsWithRecommended extends TSESLint.RuleMetaDataDocs {
|
|
4
|
+
recommended?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const banReactFC: TSESLint.RuleModuleWithMetaDocs<MessageIds, [], RuleDocsWithRecommended>;
|
|
7
|
+
export default banReactFC;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bans React.FC and similar component type annotations.
|
|
3
|
+
*
|
|
4
|
+
* React.FC (Function Component) and related types like FunctionComponent, VFC, and VoidFunctionComponent
|
|
5
|
+
* have several drawbacks:
|
|
6
|
+
* - They break debug information in React DevTools, making profiling harder
|
|
7
|
+
* - They add unnecessary complexity compared to simple function declarations
|
|
8
|
+
* - They encourage poor patterns like implicit children handling
|
|
9
|
+
*
|
|
10
|
+
* Instead, use explicit function declarations with proper parameter typing.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // ❌ Reports
|
|
14
|
+
* export const MyComponent: React.FC<Props> = ({ children }) => {
|
|
15
|
+
* return <div>{children}</div>;
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // ✅ OK
|
|
19
|
+
* export function MyComponent({ children }: Props) {
|
|
20
|
+
* return <div>{children}</div>;
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
const BANNED_FC_NAMES = new Set(["FC", "FunctionComponent", "VFC", "VoidFunctionComponent"]);
|
|
24
|
+
const banReactFC = {
|
|
25
|
+
/**
|
|
26
|
+
* Creates the ESLint rule visitor.
|
|
27
|
+
*
|
|
28
|
+
* @param context - The ESLint rule context.
|
|
29
|
+
* @returns The visitor object with AST node handlers.
|
|
30
|
+
*/
|
|
31
|
+
create(context) {
|
|
32
|
+
return {
|
|
33
|
+
VariableDeclarator(node) {
|
|
34
|
+
const typeAnnotation = node.id.typeAnnotation;
|
|
35
|
+
if (!typeAnnotation)
|
|
36
|
+
return;
|
|
37
|
+
const inner = typeAnnotation.typeAnnotation;
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
39
|
+
if (inner.type !== "TSTypeReference")
|
|
40
|
+
return;
|
|
41
|
+
const typeName = inner.typeName;
|
|
42
|
+
let isBannedFC = false;
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
44
|
+
if (typeName.type === "Identifier") {
|
|
45
|
+
isBannedFC = BANNED_FC_NAMES.has(typeName.name);
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
47
|
+
}
|
|
48
|
+
else if (typeName.type === "TSQualifiedName") {
|
|
49
|
+
isBannedFC = BANNED_FC_NAMES.has(typeName.right.name);
|
|
50
|
+
}
|
|
51
|
+
if (!isBannedFC)
|
|
52
|
+
return;
|
|
53
|
+
const initType = node.init?.type;
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
55
|
+
if (initType !== "ArrowFunctionExpression")
|
|
56
|
+
return;
|
|
57
|
+
context.report({
|
|
58
|
+
messageId: "banReactFC",
|
|
59
|
+
node,
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
defaultOptions: [],
|
|
65
|
+
meta: {
|
|
66
|
+
docs: {
|
|
67
|
+
description: "Ban React.FC and similar component type annotations. Use explicit function declarations instead.",
|
|
68
|
+
recommended: true,
|
|
69
|
+
},
|
|
70
|
+
messages: {
|
|
71
|
+
banReactFC: "Avoid React.FC/FunctionComponent/VFC/VoidFunctionComponent types. They break debug information and profiling. Use explicit function declarations instead: `function Component(props: Props) { ... }`",
|
|
72
|
+
},
|
|
73
|
+
schema: [],
|
|
74
|
+
type: "problem",
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
export default banReactFC;
|
|
78
|
+
//# sourceMappingURL=ban-react-fc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ban-react-fc.js","sourceRoot":"","sources":["../../src/rules/ban-react-fc.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC;AAE7F,MAAM,UAAU,GAA6E;IAC5F;;;;;OAKG;IACH,MAAM,CAAC,OAAO;QACb,OAAO;YACN,kBAAkB,CAAC,IAAiC;gBACnD,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC;gBAC9C,IAAI,CAAC,cAAc;oBAAE,OAAO;gBAE5B,MAAM,KAAK,GAAG,cAAc,CAAC,cAAc,CAAC;gBAC5C,wEAAwE;gBACxE,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB;oBAAE,OAAO;gBAE7C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;gBAEhC,IAAI,UAAU,GAAG,KAAK,CAAC;gBACvB,wEAAwE;gBACxE,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACpC,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAChD,wEAAwE;gBACzE,CAAC;qBAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBAChD,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvD,CAAC;gBAED,IAAI,CAAC,UAAU;oBAAE,OAAO;gBAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;gBACjC,wEAAwE;gBACxE,IAAI,QAAQ,KAAK,yBAAyB;oBAAE,OAAO;gBAEnD,OAAO,CAAC,MAAM,CAAC;oBACd,SAAS,EAAE,YAAY;oBACvB,IAAI;iBACJ,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;IACD,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACL,IAAI,EAAE;YACL,WAAW,EACV,kGAAkG;YACnG,WAAW,EAAE,IAAI;SACjB;QACD,QAAQ,EAAE;YACT,UAAU,EACT,sMAAsM;SACvM;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KACf;CACD,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TSESLint } from "@typescript-eslint/utils";
|
|
2
|
+
interface RuleDocsWithRecommended extends TSESLint.RuleMetaDataDocs {
|
|
3
|
+
recommended?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare const preferSequenceOverloads: TSESLint.RuleModuleWithMetaDocs<"preferSingleOverload" | "preferTwoPointOverload", [
|
|
6
|
+
], RuleDocsWithRecommended>;
|
|
7
|
+
export default preferSequenceOverloads;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
2
|
+
const sequenceDescriptors = [
|
|
3
|
+
{ keypointName: "ColorSequenceKeypoint", sequenceName: "ColorSequence" },
|
|
4
|
+
{ keypointName: "NumberSequenceKeypoint", sequenceName: "NumberSequence" },
|
|
5
|
+
];
|
|
6
|
+
function isSequenceIdentifier(node) {
|
|
7
|
+
return (node.type === AST_NODE_TYPES.Identifier &&
|
|
8
|
+
sequenceDescriptors.some((descriptor) => descriptor.sequenceName === node.name));
|
|
9
|
+
}
|
|
10
|
+
function findDescriptor(sequenceName) {
|
|
11
|
+
return sequenceDescriptors.find((descriptor) => descriptor.sequenceName === sequenceName);
|
|
12
|
+
}
|
|
13
|
+
function isNumericLiteral(argument) {
|
|
14
|
+
return argument !== undefined && argument.type === AST_NODE_TYPES.Literal && typeof argument.value === "number";
|
|
15
|
+
}
|
|
16
|
+
function isExpressionArgument(argument) {
|
|
17
|
+
return argument !== undefined && argument.type !== AST_NODE_TYPES.SpreadElement;
|
|
18
|
+
}
|
|
19
|
+
function extractKeypoint(element, descriptor) {
|
|
20
|
+
if (element === null || element.type !== AST_NODE_TYPES.NewExpression)
|
|
21
|
+
return undefined;
|
|
22
|
+
if (element.callee.type !== AST_NODE_TYPES.Identifier || element.callee.name !== descriptor.keypointName) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
if (element.arguments.length !== 2)
|
|
26
|
+
return undefined;
|
|
27
|
+
const [timeArgument, valueArgument] = element.arguments;
|
|
28
|
+
if (!isNumericLiteral(timeArgument))
|
|
29
|
+
return undefined;
|
|
30
|
+
if (!isExpressionArgument(valueArgument))
|
|
31
|
+
return undefined;
|
|
32
|
+
return {
|
|
33
|
+
time: timeArgument.value,
|
|
34
|
+
value: valueArgument,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const docs = {
|
|
38
|
+
description: "Prefer the optimized ColorSequence and NumberSequence constructor overloads over passing ColorSequenceKeypoint or NumberSequenceKeypoint arrays when only using endpoints 0 and 1.",
|
|
39
|
+
recommended: true,
|
|
40
|
+
};
|
|
41
|
+
const preferSequenceOverloads = {
|
|
42
|
+
create(context) {
|
|
43
|
+
const sourceCode = context.getSourceCode();
|
|
44
|
+
return {
|
|
45
|
+
NewExpression(node) {
|
|
46
|
+
const callee = node.callee;
|
|
47
|
+
if (!isSequenceIdentifier(callee))
|
|
48
|
+
return;
|
|
49
|
+
const descriptor = findDescriptor(callee.name);
|
|
50
|
+
if (descriptor === undefined)
|
|
51
|
+
return;
|
|
52
|
+
if (node.arguments.length !== 1)
|
|
53
|
+
return;
|
|
54
|
+
const [argument] = node.arguments;
|
|
55
|
+
if (argument === undefined || argument.type !== AST_NODE_TYPES.ArrayExpression)
|
|
56
|
+
return;
|
|
57
|
+
if (argument.elements.length !== 2)
|
|
58
|
+
return;
|
|
59
|
+
const firstElement = argument.elements[0] ?? null;
|
|
60
|
+
const secondElement = argument.elements[1] ?? null;
|
|
61
|
+
const firstKeypoint = extractKeypoint(firstElement, descriptor);
|
|
62
|
+
const secondKeypoint = extractKeypoint(secondElement, descriptor);
|
|
63
|
+
if (firstKeypoint === undefined || secondKeypoint === undefined)
|
|
64
|
+
return;
|
|
65
|
+
if (firstKeypoint.time !== 0 || secondKeypoint.time !== 1)
|
|
66
|
+
return;
|
|
67
|
+
const firstValueText = sourceCode.getText(firstKeypoint.value);
|
|
68
|
+
const secondValueText = sourceCode.getText(secondKeypoint.value);
|
|
69
|
+
const normalizedFirstValue = firstValueText.trim();
|
|
70
|
+
const normalizedSecondValue = secondValueText.trim();
|
|
71
|
+
if (normalizedFirstValue === normalizedSecondValue) {
|
|
72
|
+
context.report({
|
|
73
|
+
data: {
|
|
74
|
+
sequenceName: descriptor.sequenceName,
|
|
75
|
+
},
|
|
76
|
+
fix: (fixer) => fixer.replaceText(node, `new ${descriptor.sequenceName}(${firstValueText})`),
|
|
77
|
+
messageId: "preferSingleOverload",
|
|
78
|
+
node,
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
context.report({
|
|
83
|
+
data: {
|
|
84
|
+
sequenceName: descriptor.sequenceName,
|
|
85
|
+
},
|
|
86
|
+
fix: (fixer) => fixer.replaceText(node, `new ${descriptor.sequenceName}(${firstValueText}, ${secondValueText})`),
|
|
87
|
+
messageId: "preferTwoPointOverload",
|
|
88
|
+
node,
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
defaultOptions: [],
|
|
94
|
+
meta: {
|
|
95
|
+
docs,
|
|
96
|
+
fixable: "code",
|
|
97
|
+
messages: {
|
|
98
|
+
preferSingleOverload: "Use the single-argument {{sequenceName}} constructor overload instead of redundant keypoints when both endpoints share the same value.",
|
|
99
|
+
preferTwoPointOverload: "Use the two-argument {{sequenceName}} constructor overload instead of allocating an array of keypoints for endpoints 0 and 1.",
|
|
100
|
+
},
|
|
101
|
+
schema: [],
|
|
102
|
+
type: "problem",
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
export default preferSequenceOverloads;
|
|
106
|
+
//# sourceMappingURL=prefer-sequence-overloads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-sequence-overloads.js","sourceRoot":"","sources":["../../src/rules/prefer-sequence-overloads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAiB1D,MAAM,mBAAmB,GAAsC;IAC9D,EAAE,YAAY,EAAE,uBAAuB,EAAE,YAAY,EAAE,eAAe,EAAE;IACxE,EAAE,YAAY,EAAE,wBAAwB,EAAE,YAAY,EAAE,gBAAgB,EAAE;CAC1E,CAAC;AAEF,SAAS,oBAAoB,CAC5B,IAA0C;IAE1C,OAAO,CACN,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;QACvC,mBAAmB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,CAC/E,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,YAAgD;IACvE,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,KAAK,YAAY,CAAC,CAAC;AAC3F,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAqD;IAG9E,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,IAAI,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC;AACjH,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAqD;IAClF,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,aAAa,CAAC;AACjF,CAAC;AAED,SAAS,eAAe,CACvB,OAA4D,EAC5D,UAA8B;IAE9B,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IACxF,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,YAAY,EAAE,CAAC;QAC1G,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAErD,MAAM,CAAC,YAAY,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IACxD,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC;QAAE,OAAO,SAAS,CAAC;IAE3D,OAAO;QACN,IAAI,EAAE,YAAY,CAAC,KAAK;QACxB,KAAK,EAAE,aAAa;KACpB,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAA4B;IACrC,WAAW,EACV,oLAAoL;IACrL,WAAW,EAAE,IAAI;CACjB,CAAC;AAEF,MAAM,uBAAuB,GAIzB;IACH,MAAM,CAAC,OAAO;QACb,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;QAE3C,OAAO;YACN,aAAa,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC;oBAAE,OAAO;gBAE1C,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,UAAU,KAAK,SAAS;oBAAE,OAAO;gBAErC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBAExC,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;gBAClC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe;oBAAE,OAAO;gBACvF,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBAE3C,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAClD,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAEnD,MAAM,aAAa,GAAG,eAAe,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;gBAChE,MAAM,cAAc,GAAG,eAAe,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;gBAClE,IAAI,aAAa,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS;oBAAE,OAAO;gBAExE,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,KAAK,CAAC;oBAAE,OAAO;gBAElE,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBAC/D,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;gBACjE,MAAM,oBAAoB,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;gBACnD,MAAM,qBAAqB,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;gBAErD,IAAI,oBAAoB,KAAK,qBAAqB,EAAE,CAAC;oBACpD,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE;4BACL,YAAY,EAAE,UAAU,CAAC,YAAY;yBACrC;wBACD,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,UAAU,CAAC,YAAY,IAAI,cAAc,GAAG,CAAC;wBAC5F,SAAS,EAAE,sBAAsB;wBACjC,IAAI;qBACJ,CAAC,CAAC;oBACH,OAAO;gBACR,CAAC;gBAED,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI,EAAE;wBACL,YAAY,EAAE,UAAU,CAAC,YAAY;qBACrC;oBACD,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CACd,KAAK,CAAC,WAAW,CAChB,IAAI,EACJ,OAAO,UAAU,CAAC,YAAY,IAAI,cAAc,KAAK,eAAe,GAAG,CACvE;oBACF,SAAS,EAAE,wBAAwB;oBACnC,IAAI;iBACJ,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;IACD,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACL,IAAI;QACJ,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE;YACT,oBAAoB,EACnB,wIAAwI;YACzI,sBAAsB,EACrB,+HAA+H;SAChI;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KACf;CACD,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
package/package.json
CHANGED