@zhangyu1818/oxlint-config 1.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 +125 -0
- package/dist/index.d.ts +169 -0
- package/dist/index.js +989 -0
- package/dist/react-agent-rules.d.ts +44 -0
- package/dist/react-agent-rules.js +94 -0
- package/package.json +59 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
interface CallExpressionNode {
|
|
2
|
+
arguments: unknown[];
|
|
3
|
+
callee: unknown;
|
|
4
|
+
type: 'CallExpression';
|
|
5
|
+
}
|
|
6
|
+
interface RuleContext {
|
|
7
|
+
report(descriptor: {
|
|
8
|
+
message: string;
|
|
9
|
+
node: unknown;
|
|
10
|
+
}): void;
|
|
11
|
+
}
|
|
12
|
+
declare const plugin: {
|
|
13
|
+
meta: {
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
rules: {
|
|
17
|
+
'effect-empty-deps-only': {
|
|
18
|
+
meta: {
|
|
19
|
+
schema: never[];
|
|
20
|
+
};
|
|
21
|
+
create(context: RuleContext): {
|
|
22
|
+
CallExpression(node: CallExpressionNode): void;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
'no-forward-ref': {
|
|
26
|
+
meta: {
|
|
27
|
+
schema: never[];
|
|
28
|
+
};
|
|
29
|
+
create(context: RuleContext): {
|
|
30
|
+
CallExpression(node: CallExpressionNode): void;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
'no-manual-memoization': {
|
|
34
|
+
meta: {
|
|
35
|
+
schema: never[];
|
|
36
|
+
};
|
|
37
|
+
create(context: RuleContext): {
|
|
38
|
+
CallExpression(node: CallExpressionNode): void;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { plugin as default };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/react-agent-rules.ts
|
|
2
|
+
var NO_MANUAL_MEMOIZATION_MESSAGE = "React Compiler automatically optimizes components and values, so manual memoization is not needed.";
|
|
3
|
+
var NO_FORWARD_REF_MESSAGE = "Starting in React 19, ref is a prop, so forwardRef is no longer needed.";
|
|
4
|
+
var EFFECT_EMPTY_DEPS_ONLY_MESSAGE = "Effects here must use an empty dependency array. Use them only for mount and unmount logic. For event-driven logic, use useEffectEvent inside the effect. Do not use effects as a watch mechanism.";
|
|
5
|
+
var manualMemoizationNames = /* @__PURE__ */ new Set(["memo", "useMemo", "useCallback"]);
|
|
6
|
+
var effectNames = /* @__PURE__ */ new Set(["useEffect", "useLayoutEffect"]);
|
|
7
|
+
var forwardRefNames = /* @__PURE__ */ new Set(["forwardRef"]);
|
|
8
|
+
function isRecord(node) {
|
|
9
|
+
return typeof node === "object" && node !== null;
|
|
10
|
+
}
|
|
11
|
+
function isIdentifier(node, name) {
|
|
12
|
+
return isRecord(node) && node.type === "Identifier" && node.name === name;
|
|
13
|
+
}
|
|
14
|
+
function isNamedIdentifier(node, names) {
|
|
15
|
+
return isRecord(node) && node.type === "Identifier" && typeof node.name === "string" && names.has(node.name);
|
|
16
|
+
}
|
|
17
|
+
function isMemberExpression(node) {
|
|
18
|
+
return isRecord(node) && node.type === "MemberExpression" && typeof node.computed === "boolean" && "object" in node && "property" in node;
|
|
19
|
+
}
|
|
20
|
+
function isReactMember(node, names) {
|
|
21
|
+
return isMemberExpression(node) && !node.computed && isIdentifier(node.object, "React") && isNamedIdentifier(node.property, names);
|
|
22
|
+
}
|
|
23
|
+
function isEmptyDependencyArray(node) {
|
|
24
|
+
return isRecord(node) && node.type === "ArrayExpression" && Array.isArray(node.elements) && node.elements.length === 0;
|
|
25
|
+
}
|
|
26
|
+
var noManualMemoizationRule = {
|
|
27
|
+
meta: {
|
|
28
|
+
schema: []
|
|
29
|
+
},
|
|
30
|
+
create(context) {
|
|
31
|
+
return {
|
|
32
|
+
CallExpression(node) {
|
|
33
|
+
if (isNamedIdentifier(node.callee, manualMemoizationNames) || isReactMember(node.callee, manualMemoizationNames)) {
|
|
34
|
+
context.report({
|
|
35
|
+
message: NO_MANUAL_MEMOIZATION_MESSAGE,
|
|
36
|
+
node
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var noForwardRefRule = {
|
|
44
|
+
meta: {
|
|
45
|
+
schema: []
|
|
46
|
+
},
|
|
47
|
+
create(context) {
|
|
48
|
+
return {
|
|
49
|
+
CallExpression(node) {
|
|
50
|
+
if (isNamedIdentifier(node.callee, forwardRefNames) || isReactMember(node.callee, forwardRefNames)) {
|
|
51
|
+
context.report({
|
|
52
|
+
message: NO_FORWARD_REF_MESSAGE,
|
|
53
|
+
node
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var effectEmptyDepsOnlyRule = {
|
|
61
|
+
meta: {
|
|
62
|
+
schema: []
|
|
63
|
+
},
|
|
64
|
+
create(context) {
|
|
65
|
+
return {
|
|
66
|
+
CallExpression(node) {
|
|
67
|
+
if (!isNamedIdentifier(node.callee, effectNames) && !isReactMember(node.callee, effectNames)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const dependencyArray = node.arguments[1];
|
|
71
|
+
if (!isEmptyDependencyArray(dependencyArray)) {
|
|
72
|
+
context.report({
|
|
73
|
+
message: EFFECT_EMPTY_DEPS_ONLY_MESSAGE,
|
|
74
|
+
node
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var plugin = {
|
|
82
|
+
meta: {
|
|
83
|
+
name: "react-agent-rules"
|
|
84
|
+
},
|
|
85
|
+
rules: {
|
|
86
|
+
"effect-empty-deps-only": effectEmptyDepsOnlyRule,
|
|
87
|
+
"no-forward-ref": noForwardRefRule,
|
|
88
|
+
"no-manual-memoization": noManualMemoizationRule
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var react_agent_rules_default = plugin;
|
|
92
|
+
export {
|
|
93
|
+
react_agent_rules_default as default
|
|
94
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zhangyu1818/oxlint-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Native Oxlint and Oxfmt config preset package",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"oxc",
|
|
7
|
+
"oxfmt-config",
|
|
8
|
+
"oxlint-config"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/zhangyu1818/oxlint-config",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/zhangyu1818/oxlint-config.git"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"format": "oxfmt -c oxfmt.config.ts .",
|
|
31
|
+
"format:check": "oxfmt --check -c oxfmt.config.ts .",
|
|
32
|
+
"lint": "oxlint",
|
|
33
|
+
"lint:fix": "oxlint --fix",
|
|
34
|
+
"test": "vitest --run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"tsc:check": "tsc"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"local-pkg": "^1.1.2"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^25.5.0",
|
|
43
|
+
"oxfmt": "^0.45.0",
|
|
44
|
+
"oxlint": "^1.60.0",
|
|
45
|
+
"oxlint-tsgolint": "^0.21.1",
|
|
46
|
+
"tsup": "^8.5.1",
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"vitest": "^4.1.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"oxfmt": "^0.45.0",
|
|
52
|
+
"oxlint": "^1.60.0",
|
|
53
|
+
"oxlint-tsgolint": "^0.21.1"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
57
|
+
},
|
|
58
|
+
"packageManager": "pnpm@10.32.1"
|
|
59
|
+
}
|