@nighttrax/eslint-config-tsx 12.4.0 → 13.0.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/package.json +8 -7
- package/src/react.mjs +15 -27
- package/src/rules/function-component-definition.mts +89 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nighttrax/eslint-config-tsx",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -22,14 +22,15 @@
|
|
|
22
22
|
"url": "git+https://github.com/NiGhTTraX/eslint-config.git"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"eslint-plugin
|
|
26
|
-
"eslint-
|
|
27
|
-
"eslint
|
|
28
|
-
"eslint-plugin-react-you-might-not-need-an-effect": "~0.
|
|
29
|
-
"
|
|
25
|
+
"@eslint-react/eslint-plugin": "~5.8.12",
|
|
26
|
+
"@eslint-react/kit": "~5.8.12",
|
|
27
|
+
"@typescript-eslint/utils": "~8.60.1",
|
|
28
|
+
"eslint-plugin-react-you-might-not-need-an-effect": "~1.0.0",
|
|
29
|
+
"typescript-eslint": "~8.60.1",
|
|
30
|
+
"@nighttrax/eslint-config-ts": "13.0.0"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
32
|
-
"eslint": "^
|
|
33
|
+
"eslint": "^10.0.0",
|
|
33
34
|
"prettier": "^3.0.0",
|
|
34
35
|
"typescript": "^5.0.0 || ^6.0.0"
|
|
35
36
|
},
|
package/src/react.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import react from "eslint-plugin
|
|
2
|
-
import
|
|
3
|
-
import reactHooks from "eslint-plugin-react-hooks";
|
|
4
|
-
import reactYouMightNotNeedAnEffect from "eslint-plugin-react-you-might-not-need-an-effect";
|
|
1
|
+
import react from "@eslint-react/eslint-plugin";
|
|
2
|
+
import eslintReactKit from "@eslint-react/kit";
|
|
5
3
|
import { EXTENSIONS, nighttraxTS } from "@nighttrax/eslint-config-ts";
|
|
4
|
+
import reactYouMightNotNeedAnEffect from "eslint-plugin-react-you-might-not-need-an-effect";
|
|
5
|
+
import { functionComponentDefinition } from "./rules/function-component-definition.mts";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @param {import('typescript-eslint').InfiniteDepthConfigWithExtends[]} [configs]
|
|
@@ -19,37 +19,25 @@ export const nighttraxReact = (
|
|
|
19
19
|
) =>
|
|
20
20
|
nighttraxTS(
|
|
21
21
|
[
|
|
22
|
-
react.configs
|
|
23
|
-
|
|
24
|
-
reactHooks.configs.flat["recommended-latest"],
|
|
25
|
-
jsxA11y["flatConfigs"].recommended,
|
|
26
|
-
reactYouMightNotNeedAnEffect.configs.recommended,
|
|
22
|
+
react.configs["strict-type-checked"],
|
|
23
|
+
eslintReactKit().use(functionComponentDefinition).getConfig(),
|
|
27
24
|
|
|
28
25
|
{
|
|
26
|
+
plugins: {
|
|
27
|
+
"@no-effect": reactYouMightNotNeedAnEffect,
|
|
28
|
+
},
|
|
29
29
|
settings: {
|
|
30
|
-
react: {
|
|
30
|
+
"react-x": {
|
|
31
31
|
version,
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
rules: {
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"error",
|
|
39
|
-
{
|
|
40
|
-
namedComponents: "arrow-function",
|
|
41
|
-
unnamedComponents: "arrow-function",
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
"react/jsx-no-leaked-render": "error",
|
|
45
|
-
"react/jsx-boolean-value": ["error", "never"],
|
|
46
|
-
"react/forward-ref-uses-ref": "error",
|
|
47
|
-
"react/jsx-no-useless-fragment": "error",
|
|
48
|
-
"react/jsx-fragments": "error",
|
|
49
|
-
"react/jsx-curly-brace-presence": "error",
|
|
35
|
+
"@stylistic/jsx-curly-brace-presence": "error",
|
|
36
|
+
"@stylistic/jsx-shorthand-boolean": "error",
|
|
37
|
+
"@stylistic/jsx-shorthand-fragment": "error",
|
|
50
38
|
|
|
51
|
-
|
|
52
|
-
"
|
|
39
|
+
"@no-effect/no-pass-live-state-to-parent": "error",
|
|
40
|
+
"@no-effect/no-event-handler": "error",
|
|
53
41
|
},
|
|
54
42
|
},
|
|
55
43
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { RuleFunction } from "@eslint-react/kit";
|
|
2
|
+
import { merge } from "@eslint-react/kit";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
|
|
5
|
+
/** Enforce arrow function definitions for function components. */
|
|
6
|
+
export function functionComponentDefinition(): RuleFunction {
|
|
7
|
+
return (context, { collect, hint }) => {
|
|
8
|
+
const { query, visitor } = collect.components(context, {
|
|
9
|
+
hint:
|
|
10
|
+
hint.component.Default &
|
|
11
|
+
~hint.component.DoNotIncludeFunctionDefinedAsObjectMethod,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
return merge(visitor, {
|
|
15
|
+
"Program:exit"(program) {
|
|
16
|
+
// ─── Iterate all components ────────────────────
|
|
17
|
+
for (const { node } of query.all(program)) {
|
|
18
|
+
// › Guard: must not already be arrow function
|
|
19
|
+
if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
message:
|
|
26
|
+
"Function components must be defined with arrow functions.",
|
|
27
|
+
suggest: [
|
|
28
|
+
{
|
|
29
|
+
desc: "Convert to arrow function.",
|
|
30
|
+
fix(fixer) {
|
|
31
|
+
const src = context.sourceCode;
|
|
32
|
+
|
|
33
|
+
if (node.generator) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const prefix = node.async ? "async " : "";
|
|
38
|
+
const typeParams = node.typeParameters
|
|
39
|
+
? src.getText(node.typeParameters)
|
|
40
|
+
: "";
|
|
41
|
+
const params = `(${node.params.map((p) => src.getText(p)).join(", ")})`;
|
|
42
|
+
const returnType = node.returnType
|
|
43
|
+
? src.getText(node.returnType)
|
|
44
|
+
: "";
|
|
45
|
+
const body = src.getText(node.body);
|
|
46
|
+
|
|
47
|
+
// ─── Case: function declaration ──────────────
|
|
48
|
+
if (
|
|
49
|
+
node.type === AST_NODE_TYPES.FunctionDeclaration &&
|
|
50
|
+
node.id
|
|
51
|
+
) {
|
|
52
|
+
return fixer.replaceText(
|
|
53
|
+
node,
|
|
54
|
+
`const ${node.id.name} = ${prefix}${typeParams}${params}${returnType} => ${body};`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── Case: function expression in variable ───
|
|
59
|
+
if (
|
|
60
|
+
node.type === AST_NODE_TYPES.FunctionExpression &&
|
|
61
|
+
node.parent.type === AST_NODE_TYPES.VariableDeclarator
|
|
62
|
+
) {
|
|
63
|
+
return fixer.replaceText(
|
|
64
|
+
node,
|
|
65
|
+
`${prefix}${typeParams}${params}${returnType} => ${body}`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ─── Case: object method shorthand ───────────
|
|
70
|
+
if (
|
|
71
|
+
node.type === AST_NODE_TYPES.FunctionExpression &&
|
|
72
|
+
node.parent.type === AST_NODE_TYPES.Property
|
|
73
|
+
) {
|
|
74
|
+
return fixer.replaceText(
|
|
75
|
+
node.parent,
|
|
76
|
+
`${src.getText(node.parent.key)}: ${prefix}${typeParams}${params}${returnType} => ${body}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return null;
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
}
|