eslint-plugin-react-hooks-extra 2.0.0-next.61 → 2.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/README.md +20 -16
- package/dist/index.d.ts +0 -4
- package/dist/index.js +86 -471
- package/package.json +16 -24
package/README.md
CHANGED
|
@@ -17,26 +17,30 @@ npm install --save-dev eslint-plugin-react-hooks-extra
|
|
|
17
17
|
// @ts-check
|
|
18
18
|
import js from "@eslint/js";
|
|
19
19
|
import reactHooksExtra from "eslint-plugin-react-hooks-extra";
|
|
20
|
+
import { defineConfig } from "eslint/config";
|
|
20
21
|
import tseslint from "typescript-eslint";
|
|
21
22
|
|
|
22
|
-
export default
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
export default defineConfig([
|
|
24
|
+
{
|
|
25
|
+
files: ["**/*.ts", "**/*.tsx"],
|
|
26
|
+
extends: [
|
|
27
|
+
js.configs.recommended,
|
|
28
|
+
tseslint.configs.recommended,
|
|
29
|
+
reactHooksExtra.configs.recommended,
|
|
30
|
+
],
|
|
31
|
+
languageOptions: {
|
|
32
|
+
parser: tseslint.parser,
|
|
33
|
+
parserOptions: {
|
|
34
|
+
projectService: true,
|
|
35
|
+
tsconfigRootDir: import.meta.dirname,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
// Put rules you want to override here
|
|
40
|
+
"react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
|
|
34
41
|
},
|
|
35
42
|
},
|
|
36
|
-
|
|
37
|
-
// Put rules you want to override here
|
|
38
|
-
},
|
|
39
|
-
});
|
|
43
|
+
]);
|
|
40
44
|
```
|
|
41
45
|
|
|
42
46
|
## Rules
|
package/dist/index.d.ts
CHANGED
|
@@ -9,10 +9,6 @@ declare const _default: {
|
|
|
9
9
|
rules?: Record<string, _eslint_react_kit0.RuleConfig>;
|
|
10
10
|
settings?: _eslint_react_kit0.SettingsConfig;
|
|
11
11
|
};
|
|
12
|
-
"recommended-legacy": {
|
|
13
|
-
plugins: string[];
|
|
14
|
-
rules: Record<string, _eslint_react_kit0.RuleConfig<unknown[]>> | undefined;
|
|
15
|
-
};
|
|
16
12
|
};
|
|
17
13
|
meta: {
|
|
18
14
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import { getConfigAdapters, getDocsUrl
|
|
1
|
+
import { getConfigAdapters, getDocsUrl } from "@eslint-react/shared";
|
|
2
2
|
import * as AST from "@eslint-react/ast";
|
|
3
3
|
import * as ER from "@eslint-react/core";
|
|
4
|
-
import { constVoid, getOrElseUpdate,
|
|
4
|
+
import { constVoid, getOrElseUpdate, not } from "@eslint-react/eff";
|
|
5
5
|
import * as VAR from "@eslint-react/var";
|
|
6
6
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
7
|
+
import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
7
8
|
import { match } from "ts-pattern";
|
|
8
9
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
9
10
|
|
|
10
11
|
//#region rolldown:runtime
|
|
11
12
|
var __defProp = Object.defineProperty;
|
|
12
|
-
var __export = (
|
|
13
|
+
var __export = (all) => {
|
|
14
|
+
let target = {};
|
|
13
15
|
for (var name$2 in all) __defProp(target, name$2, {
|
|
14
16
|
get: all[name$2],
|
|
15
17
|
enumerable: true
|
|
16
18
|
});
|
|
19
|
+
return target;
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
//#endregion
|
|
20
23
|
//#region src/configs/recommended.ts
|
|
21
|
-
var recommended_exports = {
|
|
22
|
-
__export(recommended_exports, {
|
|
24
|
+
var recommended_exports = /* @__PURE__ */ __export({
|
|
23
25
|
name: () => name$1,
|
|
24
26
|
rules: () => rules
|
|
25
27
|
});
|
|
@@ -29,19 +31,48 @@ const rules = { "react-hooks-extra/no-direct-set-state-in-use-effect": "warn" };
|
|
|
29
31
|
//#endregion
|
|
30
32
|
//#region package.json
|
|
31
33
|
var name = "eslint-plugin-react-hooks-extra";
|
|
32
|
-
var version = "2.0.0
|
|
34
|
+
var version = "2.0.0";
|
|
33
35
|
|
|
34
36
|
//#endregion
|
|
35
|
-
//#region src/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
//#region src/utils/create-rule.ts
|
|
38
|
+
const createRule = ESLintUtils.RuleCreator(getDocsUrl("hooks-extra"));
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/utils/is-variable-declarator-from-hook-call.ts
|
|
42
|
+
function isInitFromHookCall(init) {
|
|
43
|
+
if (init?.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
44
|
+
switch (init.callee.type) {
|
|
45
|
+
case AST_NODE_TYPES.Identifier: return ER.isReactHookName(init.callee.name);
|
|
46
|
+
case AST_NODE_TYPES.MemberExpression: return init.callee.property.type === AST_NODE_TYPES.Identifier && ER.isReactHookName(init.callee.property.name);
|
|
47
|
+
default: return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isVariableDeclaratorFromHookCall(node) {
|
|
51
|
+
if (node.type !== AST_NODE_TYPES.VariableDeclarator) return false;
|
|
52
|
+
if (node.id.type !== AST_NODE_TYPES.Identifier) return false;
|
|
53
|
+
return isInitFromHookCall(node.init);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/rules/no-direct-set-state-in-use-effect.ts
|
|
58
|
+
const RULE_NAME = "no-direct-set-state-in-use-effect";
|
|
59
|
+
const RULE_FEATURES = ["EXP"];
|
|
60
|
+
var no_direct_set_state_in_use_effect_default = createRule({
|
|
61
|
+
meta: {
|
|
62
|
+
type: "problem",
|
|
63
|
+
docs: {
|
|
64
|
+
description: "Disallow direct calls to the `set` function of `useState` in `useEffect`.",
|
|
65
|
+
[Symbol.for("rule_features")]: RULE_FEATURES
|
|
66
|
+
},
|
|
67
|
+
messages: { noDirectSetStateInUseEffect: "Do not call the 'set' function '{{name}}' of 'useState' directly in 'useEffect'." },
|
|
68
|
+
schema: []
|
|
69
|
+
},
|
|
70
|
+
name: RULE_NAME,
|
|
71
|
+
create,
|
|
72
|
+
defaultOptions: []
|
|
73
|
+
});
|
|
74
|
+
function create(context) {
|
|
75
|
+
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
45
76
|
const functionEntries = [];
|
|
46
77
|
const setupFnRef = { current: null };
|
|
47
78
|
const setupFnIds = [];
|
|
@@ -50,6 +81,7 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
50
81
|
const setStateInEffectArg = /* @__PURE__ */ new WeakMap();
|
|
51
82
|
const setStateInEffectSetup = /* @__PURE__ */ new Map();
|
|
52
83
|
const setStateInHookCallbacks = /* @__PURE__ */ new WeakMap();
|
|
84
|
+
const getText = (n) => context.sourceCode.getText(n);
|
|
53
85
|
const onSetupFunctionEnter = (node) => {
|
|
54
86
|
setupFnRef.current = node;
|
|
55
87
|
};
|
|
@@ -57,14 +89,14 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
57
89
|
if (setupFnRef.current === node) setupFnRef.current = null;
|
|
58
90
|
};
|
|
59
91
|
function isFunctionOfUseEffectSetup(node) {
|
|
60
|
-
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectLikeCall(node.parent);
|
|
92
|
+
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && ER.isUseEffectLikeCall(node.parent);
|
|
61
93
|
}
|
|
62
94
|
function getCallName(node) {
|
|
63
95
|
if (node.type === AST_NODE_TYPES.CallExpression) return AST.toStringFormat(node.callee, getText);
|
|
64
96
|
return AST.toStringFormat(node, getText);
|
|
65
97
|
}
|
|
66
98
|
function getCallKind(node) {
|
|
67
|
-
return match(node).when(isUseStateCall, () => "useState").when(isUseEffectLikeCall, () =>
|
|
99
|
+
return match(node).when(ER.isUseStateCall, () => "useState").when(ER.isUseEffectLikeCall, () => "useEffect").when(isSetStateCall, () => "setState").when(AST.isThenCall, () => "then").otherwise(() => "other");
|
|
68
100
|
}
|
|
69
101
|
function getFunctionKind(node) {
|
|
70
102
|
const parent = AST.findParentNode(node, not(AST.isTypeExpression)) ?? node.parent;
|
|
@@ -81,7 +113,7 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
81
113
|
const variableNode = VAR.getVariableDefinitionNode(variable, 0);
|
|
82
114
|
if (variableNode == null) return false;
|
|
83
115
|
if (variableNode.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
84
|
-
if (!ER.
|
|
116
|
+
if (!ER.isUseStateCall(variableNode)) return false;
|
|
85
117
|
const variableNodeParent = variableNode.parent;
|
|
86
118
|
if (!("id" in variableNodeParent) || variableNodeParent.id?.type !== AST_NODE_TYPES.ArrayPattern) return true;
|
|
87
119
|
return variableNodeParent.id.elements.findIndex((e) => e?.type === AST_NODE_TYPES.Identifier && e.name === topLevelId.name) === at;
|
|
@@ -96,24 +128,14 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
96
128
|
const [index] = node.callee.arguments;
|
|
97
129
|
if (!isAt || index == null) return false;
|
|
98
130
|
const indexScope = context.sourceCode.getScope(node);
|
|
99
|
-
|
|
100
|
-
kind: "lazy",
|
|
101
|
-
node: index,
|
|
102
|
-
initialScope: indexScope
|
|
103
|
-
}).value;
|
|
104
|
-
return indexValue === 1 && isIdFromUseStateCall(callee.object);
|
|
131
|
+
return getStaticValue(index, indexScope)?.value === 1 && isIdFromUseStateCall(callee.object);
|
|
105
132
|
}
|
|
106
133
|
case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(node.callee, 1);
|
|
107
134
|
case AST_NODE_TYPES.MemberExpression: {
|
|
108
135
|
if (!("name" in node.callee.object)) return false;
|
|
109
136
|
const property = node.callee.property;
|
|
110
137
|
const propertyScope = context.sourceCode.getScope(node);
|
|
111
|
-
|
|
112
|
-
kind: "lazy",
|
|
113
|
-
node: property,
|
|
114
|
-
initialScope: propertyScope
|
|
115
|
-
}).value;
|
|
116
|
-
return propertyValue === 1 && isIdFromUseStateCall(node.callee.object, 1);
|
|
138
|
+
return getStaticValue(property, propertyScope)?.value === 1 && isIdFromUseStateCall(node.callee.object, 1);
|
|
117
139
|
}
|
|
118
140
|
default: return false;
|
|
119
141
|
}
|
|
@@ -142,15 +164,19 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
142
164
|
case pEntry.node.async: break;
|
|
143
165
|
case pEntry.node === setupFunction:
|
|
144
166
|
case pEntry.kind === "immediate" && AST.findParentNode(pEntry.node, AST.isFunction) === setupFunction:
|
|
145
|
-
|
|
167
|
+
context.report({
|
|
168
|
+
messageId: "noDirectSetStateInUseEffect",
|
|
169
|
+
node,
|
|
170
|
+
data: { name: context.sourceCode.getText(node.callee) }
|
|
171
|
+
});
|
|
146
172
|
return;
|
|
147
173
|
default: {
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
else getOrElseUpdate(setStateInHookCallbacks,
|
|
174
|
+
const init = AST.findParentNode(node, isVariableDeclaratorFromHookCall)?.init;
|
|
175
|
+
if (init == null) getOrElseUpdate(setStateCallsByFn, pEntry.node, () => []).push(node);
|
|
176
|
+
else getOrElseUpdate(setStateInHookCallbacks, init, () => []).push(node);
|
|
151
177
|
}
|
|
152
178
|
}
|
|
153
|
-
}).with(
|
|
179
|
+
}).with("useEffect", () => {
|
|
154
180
|
if (AST.isFunction(node.arguments.at(0))) return;
|
|
155
181
|
setupFnIds.push(...AST.getNestedIdentifiers(node));
|
|
156
182
|
}).with("other", () => {
|
|
@@ -165,19 +191,19 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
165
191
|
case AST_NODE_TYPES.ArrowFunctionExpression: {
|
|
166
192
|
const parent = node.parent.parent;
|
|
167
193
|
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
|
|
168
|
-
if (!isUseMemoCall(parent)) break;
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
194
|
+
if (!ER.isUseMemoCall(parent)) break;
|
|
195
|
+
const init = AST.findParentNode(parent, isVariableDeclaratorFromHookCall)?.init;
|
|
196
|
+
if (init != null) getOrElseUpdate(setStateInEffectArg, init, () => []).push(node);
|
|
171
197
|
break;
|
|
172
198
|
}
|
|
173
199
|
case AST_NODE_TYPES.CallExpression:
|
|
174
200
|
if (node !== node.parent.arguments.at(0)) break;
|
|
175
|
-
if (isUseCallbackCall(node.parent)) {
|
|
176
|
-
const
|
|
177
|
-
if (
|
|
201
|
+
if (ER.isUseCallbackCall(node.parent)) {
|
|
202
|
+
const init = AST.findParentNode(node.parent, isVariableDeclaratorFromHookCall)?.init;
|
|
203
|
+
if (init != null) getOrElseUpdate(setStateInEffectArg, init, () => []).push(node);
|
|
178
204
|
break;
|
|
179
205
|
}
|
|
180
|
-
if (isUseEffectLikeCall(node.parent)) getOrElseUpdate(setStateInEffectSetup, node.parent, () => []).push(node);
|
|
206
|
+
if (ER.isUseEffectLikeCall(node.parent)) getOrElseUpdate(setStateInEffectSetup, node.parent, () => []).push(node);
|
|
181
207
|
}
|
|
182
208
|
},
|
|
183
209
|
"Program:exit"() {
|
|
@@ -191,433 +217,32 @@ function useNoDirectSetStateInUseEffect(context, options) {
|
|
|
191
217
|
}
|
|
192
218
|
return [];
|
|
193
219
|
};
|
|
194
|
-
for (const [, calls] of setStateInEffectSetup) for (const call of calls)
|
|
220
|
+
for (const [, calls] of setStateInEffectSetup) for (const call of calls) context.report({
|
|
221
|
+
messageId: "noDirectSetStateInUseEffect",
|
|
222
|
+
node: call,
|
|
223
|
+
data: { name: call.name }
|
|
224
|
+
});
|
|
195
225
|
for (const { callee } of trackedFnCalls) {
|
|
196
226
|
if (!("name" in callee)) continue;
|
|
197
227
|
const { name: name$2 } = callee;
|
|
198
228
|
const setStateCalls = getSetStateCalls(name$2, context.sourceCode.getScope(callee));
|
|
199
|
-
for (const setStateCall of setStateCalls)
|
|
229
|
+
for (const setStateCall of setStateCalls) context.report({
|
|
230
|
+
messageId: "noDirectSetStateInUseEffect",
|
|
231
|
+
node: setStateCall,
|
|
232
|
+
data: { name: getCallName(setStateCall) }
|
|
233
|
+
});
|
|
200
234
|
}
|
|
201
235
|
for (const id of setupFnIds) {
|
|
202
236
|
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
203
|
-
for (const setStateCall of setStateCalls)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
function isInitFromHookCall(init) {
|
|
209
|
-
if (init?.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
210
|
-
switch (init.callee.type) {
|
|
211
|
-
case AST_NODE_TYPES.Identifier: return ER.isReactHookName(init.callee.name);
|
|
212
|
-
case AST_NODE_TYPES.MemberExpression: return init.callee.property.type === AST_NODE_TYPES.Identifier && ER.isReactHookName(init.callee.property.name);
|
|
213
|
-
default: return false;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function isVariableDeclaratorFromHookCall(node) {
|
|
217
|
-
if (node.type !== AST_NODE_TYPES.VariableDeclarator) return false;
|
|
218
|
-
if (node.id.type !== AST_NODE_TYPES.Identifier) return false;
|
|
219
|
-
return isInitFromHookCall(node.init);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
//#endregion
|
|
223
|
-
//#region src/utils/create-rule.ts
|
|
224
|
-
const createRule = ESLintUtils.RuleCreator(getDocsUrl("hooks-extra"));
|
|
225
|
-
|
|
226
|
-
//#endregion
|
|
227
|
-
//#region src/rules/no-direct-set-state-in-use-effect.ts
|
|
228
|
-
const RULE_NAME$5 = "no-direct-set-state-in-use-effect";
|
|
229
|
-
const RULE_FEATURES$5 = ["EXP"];
|
|
230
|
-
var no_direct_set_state_in_use_effect_default = createRule({
|
|
231
|
-
meta: {
|
|
232
|
-
type: "problem",
|
|
233
|
-
docs: {
|
|
234
|
-
description: "Disallow direct calls to the `set` function of `useState` in `useEffect`.",
|
|
235
|
-
[Symbol.for("rule_features")]: RULE_FEATURES$5
|
|
236
|
-
},
|
|
237
|
-
messages: { noDirectSetStateInUseEffect: "Do not call the 'set' function '{{name}}' of 'useState' directly in 'useEffect'." },
|
|
238
|
-
schema: []
|
|
239
|
-
},
|
|
240
|
-
name: RULE_NAME$5,
|
|
241
|
-
create: create$5,
|
|
242
|
-
defaultOptions: []
|
|
243
|
-
});
|
|
244
|
-
function create$5(context) {
|
|
245
|
-
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
246
|
-
return useNoDirectSetStateInUseEffect(context, {
|
|
247
|
-
onViolation(ctx, node, data) {
|
|
248
|
-
ctx.report({
|
|
249
|
-
messageId: "noDirectSetStateInUseEffect",
|
|
250
|
-
node,
|
|
251
|
-
data
|
|
252
|
-
});
|
|
253
|
-
},
|
|
254
|
-
useEffectKind: "useEffect"
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
//#endregion
|
|
259
|
-
//#region src/rules/no-direct-set-state-in-use-layout-effect.ts
|
|
260
|
-
const RULE_NAME$4 = "no-direct-set-state-in-use-layout-effect";
|
|
261
|
-
const RULE_FEATURES$4 = ["EXP"];
|
|
262
|
-
var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
263
|
-
meta: {
|
|
264
|
-
type: "problem",
|
|
265
|
-
docs: {
|
|
266
|
-
description: "Disallow direct calls to the `set` function of `useState` in `useLayoutEffect`.",
|
|
267
|
-
[Symbol.for("rule_features")]: RULE_FEATURES$4
|
|
268
|
-
},
|
|
269
|
-
messages: { noDirectSetStateInUseLayoutEffect: "Do not call the 'set' function '{{name}}' of 'useState' directly in 'useLayoutEffect'." },
|
|
270
|
-
schema: []
|
|
271
|
-
},
|
|
272
|
-
name: RULE_NAME$4,
|
|
273
|
-
create: create$4,
|
|
274
|
-
defaultOptions: []
|
|
275
|
-
});
|
|
276
|
-
function create$4(context) {
|
|
277
|
-
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
278
|
-
return useNoDirectSetStateInUseEffect(context, {
|
|
279
|
-
onViolation(ctx, node, data) {
|
|
280
|
-
ctx.report({
|
|
281
|
-
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
282
|
-
node,
|
|
283
|
-
data
|
|
284
|
-
});
|
|
285
|
-
},
|
|
286
|
-
useEffectKind: "useLayoutEffect"
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
//#endregion
|
|
291
|
-
//#region src/rules-removed/no-unnecessary-use-callback.ts
|
|
292
|
-
const RULE_NAME$3 = "no-unnecessary-use-callback";
|
|
293
|
-
const RULE_FEATURES$3 = ["EXP"];
|
|
294
|
-
var no_unnecessary_use_callback_default = createRule({
|
|
295
|
-
meta: {
|
|
296
|
-
type: "problem",
|
|
297
|
-
deprecated: {
|
|
298
|
-
deprecatedSince: "2.0.0",
|
|
299
|
-
replacedBy: [{
|
|
300
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
301
|
-
plugin: {
|
|
302
|
-
name: "eslint-plugin-react-x",
|
|
303
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x"
|
|
304
|
-
},
|
|
305
|
-
rule: {
|
|
306
|
-
name: "no-unnecessary-use-callback",
|
|
307
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-callback"
|
|
308
|
-
}
|
|
309
|
-
}, {
|
|
310
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
311
|
-
plugin: {
|
|
312
|
-
name: "@eslint-react/eslint-plugin",
|
|
313
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin"
|
|
314
|
-
},
|
|
315
|
-
rule: {
|
|
316
|
-
name: "no-unnecessary-use-callback",
|
|
317
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-callback"
|
|
318
|
-
}
|
|
319
|
-
}]
|
|
320
|
-
},
|
|
321
|
-
docs: {
|
|
322
|
-
description: "Disallow unnecessary usage of `useCallback`.",
|
|
323
|
-
[Symbol.for("rule_features")]: RULE_FEATURES$3
|
|
324
|
-
},
|
|
325
|
-
messages: { noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary." },
|
|
326
|
-
schema: []
|
|
327
|
-
},
|
|
328
|
-
name: RULE_NAME$3,
|
|
329
|
-
create: create$3,
|
|
330
|
-
defaultOptions: []
|
|
331
|
-
});
|
|
332
|
-
function create$3(context) {
|
|
333
|
-
if (!context.sourceCode.text.includes("use")) return {};
|
|
334
|
-
const alias = getSettingsFromContext(context).additionalHooks.useCallback ?? [];
|
|
335
|
-
const isUseCallbackCall = ER.isReactHookCallWithNameAlias(context, "useCallback", alias);
|
|
336
|
-
return { CallExpression(node) {
|
|
337
|
-
if (!ER.isReactHookCall(node)) return;
|
|
338
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
339
|
-
if (!isUseCallbackCall(node)) return;
|
|
340
|
-
const scope = context.sourceCode.getScope(node);
|
|
341
|
-
const component = scope.block;
|
|
342
|
-
if (!AST.isFunction(component)) return;
|
|
343
|
-
const [arg0, arg1] = node.arguments;
|
|
344
|
-
if (arg0 == null || arg1 == null) return;
|
|
345
|
-
const hasEmptyDeps = match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
346
|
-
const variable = VAR.findVariable(n.name, initialScope);
|
|
347
|
-
const variableNode = VAR.getVariableDefinitionNode(variable, 0);
|
|
348
|
-
if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
|
|
349
|
-
return variableNode.elements.length === 0;
|
|
350
|
-
}).otherwise(() => false);
|
|
351
|
-
if (!hasEmptyDeps) return;
|
|
352
|
-
const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
|
|
353
|
-
if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
|
|
354
|
-
return n;
|
|
355
|
-
}).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
356
|
-
const variable = VAR.findVariable(n.name, initialScope);
|
|
357
|
-
const variableNode = VAR.getVariableDefinitionNode(variable, 0);
|
|
358
|
-
if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) return null;
|
|
359
|
-
return variableNode;
|
|
360
|
-
}).otherwise(() => null);
|
|
361
|
-
if (arg0Node == null) return;
|
|
362
|
-
const arg0NodeScope = context.sourceCode.getScope(arg0Node);
|
|
363
|
-
const arg0NodeReferences = VAR.getChildScopes(arg0NodeScope).flatMap((x) => x.references);
|
|
364
|
-
const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
|
|
365
|
-
if (!isReferencedToComponentScope) context.report({
|
|
366
|
-
messageId: "noUnnecessaryUseCallback",
|
|
367
|
-
node
|
|
368
|
-
});
|
|
369
|
-
} };
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
//#endregion
|
|
373
|
-
//#region src/rules-removed/no-unnecessary-use-memo.ts
|
|
374
|
-
const RULE_NAME$2 = "no-unnecessary-use-memo";
|
|
375
|
-
const RULE_FEATURES$2 = ["EXP"];
|
|
376
|
-
var no_unnecessary_use_memo_default = createRule({
|
|
377
|
-
meta: {
|
|
378
|
-
type: "problem",
|
|
379
|
-
deprecated: {
|
|
380
|
-
deprecatedSince: "2.0.0",
|
|
381
|
-
replacedBy: [{
|
|
382
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
383
|
-
plugin: {
|
|
384
|
-
name: "eslint-plugin-react-x",
|
|
385
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x"
|
|
386
|
-
},
|
|
387
|
-
rule: {
|
|
388
|
-
name: "no-unnecessary-use-memo",
|
|
389
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-memo"
|
|
390
|
-
}
|
|
391
|
-
}, {
|
|
392
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
393
|
-
plugin: {
|
|
394
|
-
name: "@eslint-react/eslint-plugin",
|
|
395
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin"
|
|
396
|
-
},
|
|
397
|
-
rule: {
|
|
398
|
-
name: "no-unnecessary-use-memo",
|
|
399
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-memo"
|
|
400
|
-
}
|
|
401
|
-
}]
|
|
402
|
-
},
|
|
403
|
-
docs: {
|
|
404
|
-
description: "Disallow unnecessary usage of `useMemo`.",
|
|
405
|
-
[Symbol.for("rule_features")]: RULE_FEATURES$2
|
|
406
|
-
},
|
|
407
|
-
messages: { noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary." },
|
|
408
|
-
schema: []
|
|
409
|
-
},
|
|
410
|
-
name: RULE_NAME$2,
|
|
411
|
-
create: create$2,
|
|
412
|
-
defaultOptions: []
|
|
413
|
-
});
|
|
414
|
-
function create$2(context) {
|
|
415
|
-
if (!context.sourceCode.text.includes("use")) return {};
|
|
416
|
-
const alias = getSettingsFromContext(context).additionalHooks.useMemo ?? [];
|
|
417
|
-
const isUseMemoCall = ER.isReactHookCallWithNameAlias(context, "useMemo", alias);
|
|
418
|
-
return { CallExpression(node) {
|
|
419
|
-
if (!ER.isReactHookCall(node)) return;
|
|
420
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
421
|
-
if (!isUseMemoCall(node)) return;
|
|
422
|
-
const scope = context.sourceCode.getScope(node);
|
|
423
|
-
const component = scope.block;
|
|
424
|
-
if (!AST.isFunction(component)) return;
|
|
425
|
-
const [arg0, arg1] = node.arguments;
|
|
426
|
-
if (arg0 == null || arg1 == null) return;
|
|
427
|
-
const hasCallInArg0 = AST.isFunction(arg0) && [...AST.getNestedCallExpressions(arg0.body), ...AST.getNestedNewExpressions(arg0.body)].length > 0;
|
|
428
|
-
if (hasCallInArg0) return;
|
|
429
|
-
const hasEmptyDeps = match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
430
|
-
const variable = VAR.findVariable(n.name, initialScope);
|
|
431
|
-
const variableNode = VAR.getVariableDefinitionNode(variable, 0);
|
|
432
|
-
if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) return false;
|
|
433
|
-
return variableNode.elements.length === 0;
|
|
434
|
-
}).otherwise(() => false);
|
|
435
|
-
if (!hasEmptyDeps) return;
|
|
436
|
-
const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
|
|
437
|
-
if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) return n.body;
|
|
438
|
-
return n;
|
|
439
|
-
}).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
440
|
-
const variable = VAR.findVariable(n.name, initialScope);
|
|
441
|
-
const variableNode = VAR.getVariableDefinitionNode(variable, 0);
|
|
442
|
-
if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) return null;
|
|
443
|
-
return variableNode;
|
|
444
|
-
}).otherwise(() => null);
|
|
445
|
-
if (arg0Node == null) return;
|
|
446
|
-
const arg0NodeScope = context.sourceCode.getScope(arg0Node);
|
|
447
|
-
const arg0NodeReferences = VAR.getChildScopes(arg0NodeScope).flatMap((x) => x.references);
|
|
448
|
-
const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
|
|
449
|
-
if (!isReferencedToComponentScope) context.report({
|
|
450
|
-
messageId: "noUnnecessaryUseMemo",
|
|
451
|
-
node
|
|
452
|
-
});
|
|
453
|
-
} };
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
//#endregion
|
|
457
|
-
//#region src/rules-removed/no-unnecessary-use-prefix.ts
|
|
458
|
-
const RULE_NAME$1 = "no-unnecessary-use-prefix";
|
|
459
|
-
const RULE_FEATURES$1 = [];
|
|
460
|
-
const WELL_KNOWN_HOOKS = ["useMDXComponents"];
|
|
461
|
-
function containsUseComments(context, node) {
|
|
462
|
-
return context.sourceCode.getCommentsInside(node).some(({ value }) => /use\([\s\S]*?\)/u.test(value) || /use[A-Z0-9]\w*\([\s\S]*?\)/u.test(value));
|
|
463
|
-
}
|
|
464
|
-
var no_unnecessary_use_prefix_default = createRule({
|
|
465
|
-
meta: {
|
|
466
|
-
type: "problem",
|
|
467
|
-
deprecated: {
|
|
468
|
-
deprecatedSince: "2.0.0",
|
|
469
|
-
replacedBy: [{
|
|
470
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
471
|
-
plugin: {
|
|
472
|
-
name: "eslint-plugin-react-x",
|
|
473
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x"
|
|
474
|
-
},
|
|
475
|
-
rule: {
|
|
476
|
-
name: "no-unnecessary-use-prefix",
|
|
477
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-prefix"
|
|
478
|
-
}
|
|
479
|
-
}, {
|
|
480
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
481
|
-
plugin: {
|
|
482
|
-
name: "@eslint-react/eslint-plugin",
|
|
483
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin"
|
|
484
|
-
},
|
|
485
|
-
rule: {
|
|
486
|
-
name: "no-unnecessary-use-prefix",
|
|
487
|
-
url: "https://eslint-react.xyz/docs/rules/no-unnecessary-use-prefix"
|
|
488
|
-
}
|
|
489
|
-
}]
|
|
490
|
-
},
|
|
491
|
-
docs: {
|
|
492
|
-
description: "Enforces that a function with the `use` prefix should use at least one Hook inside of it.",
|
|
493
|
-
[Symbol.for("rule_features")]: RULE_FEATURES$1
|
|
494
|
-
},
|
|
495
|
-
messages: { noUnnecessaryUsePrefix: "If your function doesn't call any Hooks, avoid the 'use' prefix. Instead, write it as a regular function without the 'use' prefix." },
|
|
496
|
-
schema: []
|
|
497
|
-
},
|
|
498
|
-
name: RULE_NAME$1,
|
|
499
|
-
create: create$1,
|
|
500
|
-
defaultOptions: []
|
|
501
|
-
});
|
|
502
|
-
function create$1(context) {
|
|
503
|
-
const { ctx, listeners } = ER.useHookCollector();
|
|
504
|
-
return {
|
|
505
|
-
...listeners,
|
|
506
|
-
"Program:exit"(program) {
|
|
507
|
-
const allHooks = ctx.getAllHooks(program);
|
|
508
|
-
for (const { id, name: name$2, node, hookCalls } of allHooks.values()) {
|
|
509
|
-
if (WELL_KNOWN_HOOKS.includes(name$2)) continue;
|
|
510
|
-
if (AST.isFunctionEmpty(node)) continue;
|
|
511
|
-
if (hookCalls.length > 0) continue;
|
|
512
|
-
if (containsUseComments(context, node)) continue;
|
|
513
|
-
if (id != null) {
|
|
514
|
-
context.report({
|
|
515
|
-
messageId: "noUnnecessaryUsePrefix",
|
|
516
|
-
data: { name: name$2 },
|
|
517
|
-
loc: getPreferredLoc(context, id)
|
|
518
|
-
});
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
context.report({
|
|
522
|
-
messageId: "noUnnecessaryUsePrefix",
|
|
523
|
-
node,
|
|
524
|
-
data: { name: name$2 }
|
|
237
|
+
for (const setStateCall of setStateCalls) context.report({
|
|
238
|
+
messageId: "noDirectSetStateInUseEffect",
|
|
239
|
+
node: setStateCall,
|
|
240
|
+
data: { name: getCallName(setStateCall) }
|
|
525
241
|
});
|
|
526
242
|
}
|
|
527
243
|
}
|
|
528
244
|
};
|
|
529
245
|
}
|
|
530
|
-
function getPreferredLoc(context, id) {
|
|
531
|
-
if (AST.isMultiLine(id)) return id.loc;
|
|
532
|
-
if (!context.sourceCode.getText(id).startsWith("use")) return id.loc;
|
|
533
|
-
return {
|
|
534
|
-
end: {
|
|
535
|
-
column: id.loc.start.column + 3,
|
|
536
|
-
line: id.loc.start.line
|
|
537
|
-
},
|
|
538
|
-
start: {
|
|
539
|
-
column: id.loc.start.column,
|
|
540
|
-
line: id.loc.start.line
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
//#endregion
|
|
546
|
-
//#region src/rules-removed/prefer-use-state-lazy-initialization.ts
|
|
547
|
-
const RULE_NAME = "prefer-use-state-lazy-initialization";
|
|
548
|
-
const RULE_FEATURES = ["EXP"];
|
|
549
|
-
const ALLOW_LIST = [
|
|
550
|
-
"Boolean",
|
|
551
|
-
"String",
|
|
552
|
-
"Number"
|
|
553
|
-
];
|
|
554
|
-
var prefer_use_state_lazy_initialization_default = createRule({
|
|
555
|
-
meta: {
|
|
556
|
-
type: "problem",
|
|
557
|
-
deprecated: {
|
|
558
|
-
deprecatedSince: "2.0.0",
|
|
559
|
-
replacedBy: [{
|
|
560
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
561
|
-
plugin: {
|
|
562
|
-
name: "eslint-plugin-react-x",
|
|
563
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x"
|
|
564
|
-
},
|
|
565
|
-
rule: {
|
|
566
|
-
name: "prefer-use-state-lazy-initialization",
|
|
567
|
-
url: "https://eslint-react.xyz/docs/rules/prefer-use-state-lazy-initialization"
|
|
568
|
-
}
|
|
569
|
-
}, {
|
|
570
|
-
message: "Use the same rule from `eslint-plugin-react-x` or `@eslint-react/eslint-plugin` instead.",
|
|
571
|
-
plugin: {
|
|
572
|
-
name: "@eslint-react/eslint-plugin",
|
|
573
|
-
url: "https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin"
|
|
574
|
-
},
|
|
575
|
-
rule: {
|
|
576
|
-
name: "prefer-use-state-lazy-initialization",
|
|
577
|
-
url: "https://eslint-react.xyz/docs/rules/prefer-use-state-lazy-initialization"
|
|
578
|
-
}
|
|
579
|
-
}]
|
|
580
|
-
},
|
|
581
|
-
docs: {
|
|
582
|
-
description: "Enforces function calls made inside `useState` to be wrapped in an `initializer function`.",
|
|
583
|
-
[Symbol.for("rule_features")]: RULE_FEATURES
|
|
584
|
-
},
|
|
585
|
-
messages: { preferUseStateLazyInitialization: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'." },
|
|
586
|
-
schema: []
|
|
587
|
-
},
|
|
588
|
-
name: RULE_NAME,
|
|
589
|
-
create,
|
|
590
|
-
defaultOptions: []
|
|
591
|
-
});
|
|
592
|
-
function create(context) {
|
|
593
|
-
const alias = getSettingsFromContext(context).additionalHooks.useState ?? [];
|
|
594
|
-
const isUseStateCall = ER.isReactHookCallWithNameAlias(context, "useState", alias);
|
|
595
|
-
return { CallExpression(node) {
|
|
596
|
-
if (!ER.isReactHookCall(node)) return;
|
|
597
|
-
if (!isUseStateCall(node)) return;
|
|
598
|
-
const [useStateInput] = node.arguments;
|
|
599
|
-
if (useStateInput == null) return;
|
|
600
|
-
for (const expr of AST.getNestedNewExpressions(useStateInput)) {
|
|
601
|
-
if (!("name" in expr.callee)) continue;
|
|
602
|
-
if (ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
603
|
-
if (AST.findParentNode(expr, (n) => ER.isUseCall(context, n)) != null) continue;
|
|
604
|
-
context.report({
|
|
605
|
-
messageId: "preferUseStateLazyInitialization",
|
|
606
|
-
node: expr
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
for (const expr of AST.getNestedCallExpressions(useStateInput)) {
|
|
610
|
-
if (!("name" in expr.callee)) continue;
|
|
611
|
-
if (ER.isReactHookName(expr.callee.name)) continue;
|
|
612
|
-
if (ALLOW_LIST.includes(expr.callee.name)) continue;
|
|
613
|
-
if (AST.findParentNode(expr, (n) => ER.isUseCall(context, n)) != null) continue;
|
|
614
|
-
context.report({
|
|
615
|
-
messageId: "preferUseStateLazyInitialization",
|
|
616
|
-
node: expr
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
} };
|
|
620
|
-
}
|
|
621
246
|
|
|
622
247
|
//#endregion
|
|
623
248
|
//#region src/plugin.ts
|
|
@@ -626,25 +251,15 @@ const plugin = {
|
|
|
626
251
|
name,
|
|
627
252
|
version
|
|
628
253
|
},
|
|
629
|
-
rules: {
|
|
630
|
-
"no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
|
|
631
|
-
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_layout_effect_default,
|
|
632
|
-
"no-unnecessary-use-callback": no_unnecessary_use_callback_default,
|
|
633
|
-
"no-unnecessary-use-memo": no_unnecessary_use_memo_default,
|
|
634
|
-
"no-unnecessary-use-prefix": no_unnecessary_use_prefix_default,
|
|
635
|
-
"prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default
|
|
636
|
-
}
|
|
254
|
+
rules: { "no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default }
|
|
637
255
|
};
|
|
638
256
|
|
|
639
257
|
//#endregion
|
|
640
258
|
//#region src/index.ts
|
|
641
|
-
const { toFlatConfig
|
|
259
|
+
const { toFlatConfig } = getConfigAdapters("react-hooks-extra", plugin);
|
|
642
260
|
var src_default = {
|
|
643
261
|
...plugin,
|
|
644
|
-
configs: {
|
|
645
|
-
["recommended"]: toFlatConfig(recommended_exports),
|
|
646
|
-
["recommended-legacy"]: toLegacyConfig(recommended_exports)
|
|
647
|
-
}
|
|
262
|
+
configs: { ["recommended"]: toFlatConfig(recommended_exports) }
|
|
648
263
|
};
|
|
649
264
|
|
|
650
265
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks-extra",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for React Hooks related rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -36,39 +36,31 @@
|
|
|
36
36
|
"./package.json"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
40
|
-
"@typescript-eslint/type-utils": "^8.
|
|
41
|
-
"@typescript-eslint/types": "^8.
|
|
42
|
-
"@typescript-eslint/utils": "^8.
|
|
39
|
+
"@typescript-eslint/scope-manager": "^8.44.1",
|
|
40
|
+
"@typescript-eslint/type-utils": "^8.44.1",
|
|
41
|
+
"@typescript-eslint/types": "^8.44.1",
|
|
42
|
+
"@typescript-eslint/utils": "^8.44.1",
|
|
43
43
|
"string-ts": "^2.2.1",
|
|
44
44
|
"ts-pattern": "^5.8.0",
|
|
45
|
-
"@eslint-react/ast": "2.0.0
|
|
46
|
-
"@eslint-react/core": "2.0.0
|
|
47
|
-
"@eslint-react/kit": "2.0.0
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
50
|
-
"@eslint-react/var": "2.0.0
|
|
45
|
+
"@eslint-react/ast": "2.0.0",
|
|
46
|
+
"@eslint-react/core": "2.0.0",
|
|
47
|
+
"@eslint-react/kit": "2.0.0",
|
|
48
|
+
"@eslint-react/shared": "2.0.0",
|
|
49
|
+
"@eslint-react/eff": "2.0.0",
|
|
50
|
+
"@eslint-react/var": "2.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/react": "^19.1.
|
|
53
|
+
"@types/react": "^19.1.13",
|
|
54
54
|
"@types/react-dom": "^19.1.9",
|
|
55
|
-
"tsdown": "^0.
|
|
55
|
+
"tsdown": "^0.15.4",
|
|
56
56
|
"@local/configs": "0.0.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"eslint": "^
|
|
60
|
-
"typescript": "^
|
|
61
|
-
},
|
|
62
|
-
"peerDependenciesMeta": {
|
|
63
|
-
"eslint": {
|
|
64
|
-
"optional": false
|
|
65
|
-
},
|
|
66
|
-
"typescript": {
|
|
67
|
-
"optional": true
|
|
68
|
-
}
|
|
59
|
+
"eslint": "^9.36.0",
|
|
60
|
+
"typescript": "^5.9.2"
|
|
69
61
|
},
|
|
70
62
|
"engines": {
|
|
71
|
-
"node": ">=
|
|
63
|
+
"node": ">=20.0.0"
|
|
72
64
|
},
|
|
73
65
|
"publishConfig": {
|
|
74
66
|
"access": "public"
|