@nighttrax/eslint-config-tsx 12.5.0 → 13.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nighttrax/eslint-config-tsx",
3
- "version": "12.5.0",
3
+ "version": "13.1.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-jsx-a11y": "~6.10.2",
26
- "eslint-plugin-react": "~7.37.5",
27
- "eslint-plugin-react-hooks": "~7.1.0",
28
- "eslint-plugin-react-you-might-not-need-an-effect": "~0.10.0",
29
- "@nighttrax/eslint-config-ts": "12.3.0"
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.1.0"
30
31
  },
31
32
  "peerDependencies": {
32
- "eslint": "^9.0.0",
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-react";
2
- import jsxA11y from "eslint-plugin-jsx-a11y";
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.flat.recommended,
23
- react.configs.flat["jsx-runtime"],
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
- // This usually warns for memoized or forwardRef-ed components, which is fine.
36
- "react/display-name": "off",
37
- "react/function-component-definition": [
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
- // Produces some false positives, plus it seems to be covered by react-hooks/set-state-in-effect.
52
- "react-you-might-not-need-an-effect/no-derived-state": "off",
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
+ }