@wsxjs/eslint-plugin-wsx 0.0.5
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/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/chunk-MR6HKTAK.mjs +105 -0
- package/dist/configs/flat.js +130 -0
- package/dist/configs/flat.mjs +8 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +387 -0
- package/dist/index.mjs +358 -0
- package/package.json +55 -0
- package/src/configs/flat.ts +105 -0
- package/src/configs/recommended.ts +90 -0
- package/src/index.ts +46 -0
- package/src/rules/no-react-imports.ts +55 -0
- package/src/rules/render-method-required.ts +55 -0
- package/src/rules/web-component-naming.ts +97 -0
- package/src/types.ts +44 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint 规则:no-react-imports
|
|
3
|
+
*
|
|
4
|
+
* 禁止在 WSX 文件中导入 React 相关模块
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Rule } from "eslint";
|
|
8
|
+
import { WSXRuleModule } from "../types";
|
|
9
|
+
|
|
10
|
+
export const noReactImports: WSXRuleModule = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "problem",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "disallow React imports in WSX files",
|
|
15
|
+
category: "Best Practices",
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
fixable: "code",
|
|
19
|
+
messages: {
|
|
20
|
+
noReactImport: "Do not import React in WSX files. Use 'h' function instead",
|
|
21
|
+
},
|
|
22
|
+
schema: [], // 无配置选项
|
|
23
|
+
},
|
|
24
|
+
create(context: Rule.RuleContext) {
|
|
25
|
+
const reactModules = [
|
|
26
|
+
"react",
|
|
27
|
+
"react-dom",
|
|
28
|
+
"react-dom/client",
|
|
29
|
+
"react-hooks",
|
|
30
|
+
"@types/react",
|
|
31
|
+
"@types/react-dom",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
ImportDeclaration(node: any) {
|
|
37
|
+
const source = node.source.value;
|
|
38
|
+
if (
|
|
39
|
+
typeof source === "string" &&
|
|
40
|
+
reactModules.some(
|
|
41
|
+
(module) => source === module || source.startsWith(module + "/")
|
|
42
|
+
)
|
|
43
|
+
) {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: "noReactImport",
|
|
47
|
+
fix(fixer) {
|
|
48
|
+
return fixer.remove(node);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint 规则:render-method-required
|
|
3
|
+
*
|
|
4
|
+
* 确保继承 WebComponent 的类实现 render() 方法
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Rule } from "eslint";
|
|
8
|
+
import { WSXRuleModule } from "../types";
|
|
9
|
+
|
|
10
|
+
export const renderMethodRequired: WSXRuleModule = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "problem",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "require WSX components to implement render method",
|
|
15
|
+
category: "Possible Errors",
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
messages: {
|
|
19
|
+
missingRenderMethod:
|
|
20
|
+
"WSX component '{{componentName}}' must implement a render() method",
|
|
21
|
+
},
|
|
22
|
+
schema: [], // 无配置选项
|
|
23
|
+
},
|
|
24
|
+
create(context: Rule.RuleContext) {
|
|
25
|
+
return {
|
|
26
|
+
ClassDeclaration(node: import("estree").ClassDeclaration) {
|
|
27
|
+
// 检查是否继承自 WebComponent
|
|
28
|
+
const isWebComponent =
|
|
29
|
+
node.superClass &&
|
|
30
|
+
node.superClass.type === "Identifier" &&
|
|
31
|
+
node.superClass.name === "WebComponent";
|
|
32
|
+
|
|
33
|
+
if (!isWebComponent) return;
|
|
34
|
+
|
|
35
|
+
const componentName = node.id?.name || "Unknown";
|
|
36
|
+
const hasRenderMethod = node.body.body.some(
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
(member: any) =>
|
|
39
|
+
member.type === "MethodDefinition" &&
|
|
40
|
+
member.key.type === "Identifier" &&
|
|
41
|
+
member.key.name === "render" &&
|
|
42
|
+
member.value.body !== null
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (!hasRenderMethod) {
|
|
46
|
+
context.report({
|
|
47
|
+
node,
|
|
48
|
+
messageId: "missingRenderMethod",
|
|
49
|
+
data: { componentName },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint 规则:web-component-naming
|
|
3
|
+
*
|
|
4
|
+
* 强制 Web Component 命名规范(必须包含连字符)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Rule } from "eslint";
|
|
8
|
+
import { WSXRuleModule } from "../types";
|
|
9
|
+
|
|
10
|
+
export const webComponentNaming: WSXRuleModule = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "enforce Web Component naming conventions",
|
|
15
|
+
category: "Stylistic Issues",
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
messages: {
|
|
19
|
+
tagNameNeedsHyphen:
|
|
20
|
+
"Web Component tag name '{{tagName}}' must contain at least one hyphen",
|
|
21
|
+
tagNameReserved: "Tag name '{{tagName}}' conflicts with HTML standard elements",
|
|
22
|
+
},
|
|
23
|
+
schema: [], // 无配置选项
|
|
24
|
+
},
|
|
25
|
+
create(context: Rule.RuleContext) {
|
|
26
|
+
const htmlElements = new Set([
|
|
27
|
+
"div",
|
|
28
|
+
"span",
|
|
29
|
+
"p",
|
|
30
|
+
"a",
|
|
31
|
+
"button",
|
|
32
|
+
"input",
|
|
33
|
+
"form",
|
|
34
|
+
"img",
|
|
35
|
+
"h1",
|
|
36
|
+
"h2",
|
|
37
|
+
"h3",
|
|
38
|
+
"ul",
|
|
39
|
+
"li",
|
|
40
|
+
"table",
|
|
41
|
+
"tr",
|
|
42
|
+
"td",
|
|
43
|
+
"th",
|
|
44
|
+
"section",
|
|
45
|
+
"article",
|
|
46
|
+
"header",
|
|
47
|
+
"footer",
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
Decorator(node: any) {
|
|
53
|
+
if (
|
|
54
|
+
node.expression.type === "CallExpression" &&
|
|
55
|
+
node.expression.callee.type === "Identifier" &&
|
|
56
|
+
node.expression.callee.name === "autoRegister"
|
|
57
|
+
) {
|
|
58
|
+
const args = node.expression.arguments;
|
|
59
|
+
if (args.length > 0 && args[0].type === "ObjectExpression") {
|
|
60
|
+
const tagNameProp = args[0].properties.find(
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
(prop: any) =>
|
|
63
|
+
prop.type === "Property" &&
|
|
64
|
+
prop.key &&
|
|
65
|
+
prop.key.type === "Identifier" &&
|
|
66
|
+
prop.key.name === "tagName"
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
tagNameProp &&
|
|
71
|
+
tagNameProp.type === "Property" &&
|
|
72
|
+
tagNameProp.value.type === "Literal"
|
|
73
|
+
) {
|
|
74
|
+
const tagName = tagNameProp.value.value;
|
|
75
|
+
|
|
76
|
+
if (typeof tagName === "string") {
|
|
77
|
+
if (htmlElements.has(tagName)) {
|
|
78
|
+
context.report({
|
|
79
|
+
node: tagNameProp.value,
|
|
80
|
+
messageId: "tagNameReserved",
|
|
81
|
+
data: { tagName },
|
|
82
|
+
});
|
|
83
|
+
} else if (!tagName.includes("-")) {
|
|
84
|
+
context.report({
|
|
85
|
+
node: tagNameProp.value,
|
|
86
|
+
messageId: "tagNameNeedsHyphen",
|
|
87
|
+
data: { tagName },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript 类型定义 - WSX ESLint 插件
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Rule } from "eslint";
|
|
6
|
+
|
|
7
|
+
export interface WSXRuleContext extends Rule.RuleContext {
|
|
8
|
+
// WSX 特定的上下文扩展
|
|
9
|
+
report: (descriptor: Rule.ReportDescriptor) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface WSXRuleModule extends Rule.RuleModule {
|
|
13
|
+
// WSX 特定的规则模块扩展
|
|
14
|
+
create: (context: WSXRuleContext) => Rule.RuleListener;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface WSXConfig {
|
|
18
|
+
parser?: string;
|
|
19
|
+
parserOptions?: {
|
|
20
|
+
ecmaVersion?: string | number;
|
|
21
|
+
sourceType?: "script" | "module";
|
|
22
|
+
ecmaFeatures?: {
|
|
23
|
+
jsx?: boolean;
|
|
24
|
+
};
|
|
25
|
+
jsxPragma?: string;
|
|
26
|
+
jsxFragmentName?: string;
|
|
27
|
+
};
|
|
28
|
+
plugins?: string[];
|
|
29
|
+
rules?: Record<string, unknown>;
|
|
30
|
+
globals?: Record<string, "readonly" | "writable">;
|
|
31
|
+
settings?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface WSXPluginMeta {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface WSXPlugin {
|
|
40
|
+
meta: WSXPluginMeta;
|
|
41
|
+
rules: Record<string, WSXRuleModule>;
|
|
42
|
+
configs: Record<string, WSXConfig>;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
}
|