@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
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// src/rules/render-method-required.ts
|
|
2
|
+
var renderMethodRequired = {
|
|
3
|
+
meta: {
|
|
4
|
+
type: "problem",
|
|
5
|
+
docs: {
|
|
6
|
+
description: "require WSX components to implement render method",
|
|
7
|
+
category: "Possible Errors",
|
|
8
|
+
recommended: true
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
missingRenderMethod: "WSX component '{{componentName}}' must implement a render() method"
|
|
12
|
+
},
|
|
13
|
+
schema: []
|
|
14
|
+
// 无配置选项
|
|
15
|
+
},
|
|
16
|
+
create(context) {
|
|
17
|
+
return {
|
|
18
|
+
ClassDeclaration(node) {
|
|
19
|
+
const isWebComponent = node.superClass && node.superClass.type === "Identifier" && node.superClass.name === "WebComponent";
|
|
20
|
+
if (!isWebComponent) return;
|
|
21
|
+
const componentName = node.id?.name || "Unknown";
|
|
22
|
+
const hasRenderMethod = node.body.body.some(
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
(member) => member.type === "MethodDefinition" && member.key.type === "Identifier" && member.key.name === "render" && member.value.body !== null
|
|
25
|
+
);
|
|
26
|
+
if (!hasRenderMethod) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId: "missingRenderMethod",
|
|
30
|
+
data: { componentName }
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// src/rules/no-react-imports.ts
|
|
39
|
+
var noReactImports = {
|
|
40
|
+
meta: {
|
|
41
|
+
type: "problem",
|
|
42
|
+
docs: {
|
|
43
|
+
description: "disallow React imports in WSX files",
|
|
44
|
+
category: "Best Practices",
|
|
45
|
+
recommended: true
|
|
46
|
+
},
|
|
47
|
+
fixable: "code",
|
|
48
|
+
messages: {
|
|
49
|
+
noReactImport: "Do not import React in WSX files. Use 'h' function instead"
|
|
50
|
+
},
|
|
51
|
+
schema: []
|
|
52
|
+
// 无配置选项
|
|
53
|
+
},
|
|
54
|
+
create(context) {
|
|
55
|
+
const reactModules = [
|
|
56
|
+
"react",
|
|
57
|
+
"react-dom",
|
|
58
|
+
"react-dom/client",
|
|
59
|
+
"react-hooks",
|
|
60
|
+
"@types/react",
|
|
61
|
+
"@types/react-dom"
|
|
62
|
+
];
|
|
63
|
+
return {
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
ImportDeclaration(node) {
|
|
66
|
+
const source = node.source.value;
|
|
67
|
+
if (typeof source === "string" && reactModules.some(
|
|
68
|
+
(module) => source === module || source.startsWith(module + "/")
|
|
69
|
+
)) {
|
|
70
|
+
context.report({
|
|
71
|
+
node,
|
|
72
|
+
messageId: "noReactImport",
|
|
73
|
+
fix(fixer) {
|
|
74
|
+
return fixer.remove(node);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// src/rules/web-component-naming.ts
|
|
84
|
+
var webComponentNaming = {
|
|
85
|
+
meta: {
|
|
86
|
+
type: "suggestion",
|
|
87
|
+
docs: {
|
|
88
|
+
description: "enforce Web Component naming conventions",
|
|
89
|
+
category: "Stylistic Issues",
|
|
90
|
+
recommended: true
|
|
91
|
+
},
|
|
92
|
+
messages: {
|
|
93
|
+
tagNameNeedsHyphen: "Web Component tag name '{{tagName}}' must contain at least one hyphen",
|
|
94
|
+
tagNameReserved: "Tag name '{{tagName}}' conflicts with HTML standard elements"
|
|
95
|
+
},
|
|
96
|
+
schema: []
|
|
97
|
+
// 无配置选项
|
|
98
|
+
},
|
|
99
|
+
create(context) {
|
|
100
|
+
const htmlElements = /* @__PURE__ */ new Set([
|
|
101
|
+
"div",
|
|
102
|
+
"span",
|
|
103
|
+
"p",
|
|
104
|
+
"a",
|
|
105
|
+
"button",
|
|
106
|
+
"input",
|
|
107
|
+
"form",
|
|
108
|
+
"img",
|
|
109
|
+
"h1",
|
|
110
|
+
"h2",
|
|
111
|
+
"h3",
|
|
112
|
+
"ul",
|
|
113
|
+
"li",
|
|
114
|
+
"table",
|
|
115
|
+
"tr",
|
|
116
|
+
"td",
|
|
117
|
+
"th",
|
|
118
|
+
"section",
|
|
119
|
+
"article",
|
|
120
|
+
"header",
|
|
121
|
+
"footer"
|
|
122
|
+
]);
|
|
123
|
+
return {
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
125
|
+
Decorator(node) {
|
|
126
|
+
if (node.expression.type === "CallExpression" && node.expression.callee.type === "Identifier" && node.expression.callee.name === "autoRegister") {
|
|
127
|
+
const args = node.expression.arguments;
|
|
128
|
+
if (args.length > 0 && args[0].type === "ObjectExpression") {
|
|
129
|
+
const tagNameProp = args[0].properties.find(
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
|
+
(prop) => prop.type === "Property" && prop.key && prop.key.type === "Identifier" && prop.key.name === "tagName"
|
|
132
|
+
);
|
|
133
|
+
if (tagNameProp && tagNameProp.type === "Property" && tagNameProp.value.type === "Literal") {
|
|
134
|
+
const tagName = tagNameProp.value.value;
|
|
135
|
+
if (typeof tagName === "string") {
|
|
136
|
+
if (htmlElements.has(tagName)) {
|
|
137
|
+
context.report({
|
|
138
|
+
node: tagNameProp.value,
|
|
139
|
+
messageId: "tagNameReserved",
|
|
140
|
+
data: { tagName }
|
|
141
|
+
});
|
|
142
|
+
} else if (!tagName.includes("-")) {
|
|
143
|
+
context.report({
|
|
144
|
+
node: tagNameProp.value,
|
|
145
|
+
messageId: "tagNameNeedsHyphen",
|
|
146
|
+
data: { tagName }
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// src/configs/recommended.ts
|
|
159
|
+
var recommendedConfig = {
|
|
160
|
+
parser: "@typescript-eslint/parser",
|
|
161
|
+
parserOptions: {
|
|
162
|
+
ecmaVersion: "latest",
|
|
163
|
+
sourceType: "module",
|
|
164
|
+
ecmaFeatures: {
|
|
165
|
+
jsx: true
|
|
166
|
+
},
|
|
167
|
+
jsxPragma: "h",
|
|
168
|
+
jsxFragmentName: "Fragment"
|
|
169
|
+
},
|
|
170
|
+
plugins: ["wsx"],
|
|
171
|
+
rules: {
|
|
172
|
+
// WSX 特定规则(移除 valid-jsx-pragma,由 Vite 处理)
|
|
173
|
+
"wsx/render-method-required": "error",
|
|
174
|
+
"wsx/no-react-imports": "error",
|
|
175
|
+
"wsx/web-component-naming": "warn",
|
|
176
|
+
// TypeScript 规则(推荐)
|
|
177
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
178
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
179
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
180
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
181
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
182
|
+
// 通用规则
|
|
183
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
184
|
+
"no-debugger": "error",
|
|
185
|
+
"no-unused-vars": "off",
|
|
186
|
+
// 使用 TypeScript 版本
|
|
187
|
+
"no-undef": "off",
|
|
188
|
+
// TypeScript 处理
|
|
189
|
+
"prefer-const": "error",
|
|
190
|
+
"no-var": "error",
|
|
191
|
+
"no-duplicate-imports": "error",
|
|
192
|
+
"no-trailing-spaces": "error",
|
|
193
|
+
"eol-last": "error",
|
|
194
|
+
"comma-dangle": ["error", "always-multiline"],
|
|
195
|
+
semi: ["error", "always"],
|
|
196
|
+
quotes: ["error", "double", { avoidEscape: true, allowTemplateLiterals: true }],
|
|
197
|
+
// 禁用 React 相关规则
|
|
198
|
+
"react/react-in-jsx-scope": "off",
|
|
199
|
+
"react/prop-types": "off",
|
|
200
|
+
"react/jsx-uses-react": "off",
|
|
201
|
+
"react/jsx-uses-vars": "off",
|
|
202
|
+
"react/jsx-key": "off",
|
|
203
|
+
"react/jsx-no-duplicate-props": "off",
|
|
204
|
+
"react/jsx-no-undef": "off",
|
|
205
|
+
"react/no-array-index-key": "off",
|
|
206
|
+
"react/no-unescaped-entities": "off"
|
|
207
|
+
},
|
|
208
|
+
globals: {
|
|
209
|
+
// 浏览器环境
|
|
210
|
+
window: "readonly",
|
|
211
|
+
document: "readonly",
|
|
212
|
+
console: "readonly",
|
|
213
|
+
// Node.js 环境
|
|
214
|
+
process: "readonly",
|
|
215
|
+
Buffer: "readonly",
|
|
216
|
+
__dirname: "readonly",
|
|
217
|
+
__filename: "readonly",
|
|
218
|
+
global: "readonly",
|
|
219
|
+
module: "readonly",
|
|
220
|
+
require: "readonly",
|
|
221
|
+
exports: "readonly",
|
|
222
|
+
// Web Components API
|
|
223
|
+
HTMLElement: "readonly",
|
|
224
|
+
customElements: "readonly",
|
|
225
|
+
CustomEvent: "readonly",
|
|
226
|
+
ShadowRoot: "readonly",
|
|
227
|
+
HTMLSlotElement: "readonly",
|
|
228
|
+
CSSStyleSheet: "readonly",
|
|
229
|
+
// WSX 特定
|
|
230
|
+
h: "readonly",
|
|
231
|
+
Fragment: "readonly"
|
|
232
|
+
},
|
|
233
|
+
settings: {
|
|
234
|
+
// 不需要 React 设置
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/configs/flat.ts
|
|
239
|
+
var flatConfig = {
|
|
240
|
+
name: "wsx/recommended",
|
|
241
|
+
files: ["**/*.wsx"],
|
|
242
|
+
languageOptions: {
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
+
parser: "@typescript-eslint/parser",
|
|
245
|
+
ecmaVersion: "latest",
|
|
246
|
+
sourceType: "module",
|
|
247
|
+
parserOptions: {
|
|
248
|
+
ecmaFeatures: {
|
|
249
|
+
jsx: true
|
|
250
|
+
},
|
|
251
|
+
jsxPragma: "h",
|
|
252
|
+
jsxFragmentName: "Fragment"
|
|
253
|
+
},
|
|
254
|
+
globals: {
|
|
255
|
+
// Browser environment
|
|
256
|
+
window: "readonly",
|
|
257
|
+
document: "readonly",
|
|
258
|
+
console: "readonly",
|
|
259
|
+
// Node.js environment
|
|
260
|
+
process: "readonly",
|
|
261
|
+
Buffer: "readonly",
|
|
262
|
+
__dirname: "readonly",
|
|
263
|
+
__filename: "readonly",
|
|
264
|
+
global: "readonly",
|
|
265
|
+
module: "readonly",
|
|
266
|
+
require: "readonly",
|
|
267
|
+
exports: "readonly",
|
|
268
|
+
// Web Components API
|
|
269
|
+
HTMLElement: "readonly",
|
|
270
|
+
customElements: "readonly",
|
|
271
|
+
CustomEvent: "readonly",
|
|
272
|
+
ShadowRoot: "readonly",
|
|
273
|
+
HTMLSlotElement: "readonly",
|
|
274
|
+
CSSStyleSheet: "readonly",
|
|
275
|
+
// WSX specific
|
|
276
|
+
h: "readonly",
|
|
277
|
+
Fragment: "readonly"
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
plugins: {
|
|
281
|
+
wsx: {
|
|
282
|
+
rules: {
|
|
283
|
+
"render-method-required": renderMethodRequired,
|
|
284
|
+
"no-react-imports": noReactImports,
|
|
285
|
+
"web-component-naming": webComponentNaming
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
rules: {
|
|
290
|
+
// WSX specific rules
|
|
291
|
+
"wsx/render-method-required": "error",
|
|
292
|
+
"wsx/no-react-imports": "error",
|
|
293
|
+
"wsx/web-component-naming": "warn",
|
|
294
|
+
// TypeScript rules (recommended)
|
|
295
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
296
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
297
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
298
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
299
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
300
|
+
// General rules
|
|
301
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
302
|
+
"no-debugger": "error",
|
|
303
|
+
"no-unused-vars": "off",
|
|
304
|
+
// Use TypeScript version
|
|
305
|
+
"no-undef": "off",
|
|
306
|
+
// TypeScript handles this
|
|
307
|
+
"prefer-const": "error",
|
|
308
|
+
"no-var": "error",
|
|
309
|
+
"no-duplicate-imports": "error",
|
|
310
|
+
"no-trailing-spaces": "error",
|
|
311
|
+
"eol-last": "error",
|
|
312
|
+
"comma-dangle": ["error", "always-multiline"],
|
|
313
|
+
semi: ["error", "always"],
|
|
314
|
+
quotes: ["error", "double", { avoidEscape: true, allowTemplateLiterals: true }]
|
|
315
|
+
},
|
|
316
|
+
settings: {
|
|
317
|
+
// No React settings needed
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
function createFlatConfig(plugin2) {
|
|
321
|
+
return {
|
|
322
|
+
...flatConfig,
|
|
323
|
+
plugins: {
|
|
324
|
+
wsx: plugin2
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/index.ts
|
|
330
|
+
var plugin = {
|
|
331
|
+
// 插件元信息
|
|
332
|
+
meta: {
|
|
333
|
+
name: "@wsxjs/eslint-plugin-wsx",
|
|
334
|
+
version: "0.0.2"
|
|
335
|
+
},
|
|
336
|
+
// 核心规则(移除 valid-jsx-pragma)
|
|
337
|
+
rules: {
|
|
338
|
+
"render-method-required": renderMethodRequired,
|
|
339
|
+
"no-react-imports": noReactImports,
|
|
340
|
+
"web-component-naming": webComponentNaming
|
|
341
|
+
},
|
|
342
|
+
// 配置预设
|
|
343
|
+
configs: {
|
|
344
|
+
recommended: recommendedConfig
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
var flat = {
|
|
348
|
+
recommended: createFlatConfig(plugin)
|
|
349
|
+
};
|
|
350
|
+
var rules = plugin.rules;
|
|
351
|
+
var configs = plugin.configs;
|
|
352
|
+
var index_default = plugin;
|
|
353
|
+
export {
|
|
354
|
+
configs,
|
|
355
|
+
index_default as default,
|
|
356
|
+
flat,
|
|
357
|
+
rules
|
|
358
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wsxjs/eslint-plugin-wsx",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "ESLint plugin for WSX Framework",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"!**/__tests__",
|
|
19
|
+
"!**/test"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"eslint",
|
|
23
|
+
"plugin",
|
|
24
|
+
"wsx",
|
|
25
|
+
"web-components"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@wsxjs/wsx-core": "0.0.5"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"tsup": "^8.0.0",
|
|
32
|
+
"typescript": "^5.0.0",
|
|
33
|
+
"jest": "^29.0.0",
|
|
34
|
+
"@types/jest": "^29.0.0",
|
|
35
|
+
"ts-jest": "^29.0.0",
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"@types/estree": "^1.0.0",
|
|
38
|
+
"@typescript-eslint/utils": "^6.0.0",
|
|
39
|
+
"@typescript-eslint/rule-tester": "^6.0.0",
|
|
40
|
+
"@types/eslint": "^8.0.0",
|
|
41
|
+
"eslint": "^8.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"eslint": ">=8.0.0 || ^9.0.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --cjs-interop",
|
|
48
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
49
|
+
"test": "jest",
|
|
50
|
+
"test:watch": "jest --watch",
|
|
51
|
+
"test:coverage": "jest --coverage",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"clean": "rm -rf dist coverage"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Plugin WSX - Flat Config for ESLint 9+
|
|
3
|
+
*
|
|
4
|
+
* Modern flat config format for WSX framework
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Linter } from "eslint";
|
|
8
|
+
import { renderMethodRequired } from "../rules/render-method-required";
|
|
9
|
+
import { noReactImports } from "../rules/no-react-imports";
|
|
10
|
+
import { webComponentNaming } from "../rules/web-component-naming";
|
|
11
|
+
|
|
12
|
+
export const flatConfig: Linter.FlatConfig = {
|
|
13
|
+
name: "wsx/recommended",
|
|
14
|
+
files: ["**/*.wsx"],
|
|
15
|
+
languageOptions: {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
parser: "@typescript-eslint/parser" as any,
|
|
18
|
+
ecmaVersion: "latest",
|
|
19
|
+
sourceType: "module",
|
|
20
|
+
parserOptions: {
|
|
21
|
+
ecmaFeatures: {
|
|
22
|
+
jsx: true,
|
|
23
|
+
},
|
|
24
|
+
jsxPragma: "h",
|
|
25
|
+
jsxFragmentName: "Fragment",
|
|
26
|
+
},
|
|
27
|
+
globals: {
|
|
28
|
+
// Browser environment
|
|
29
|
+
window: "readonly",
|
|
30
|
+
document: "readonly",
|
|
31
|
+
console: "readonly",
|
|
32
|
+
|
|
33
|
+
// Node.js environment
|
|
34
|
+
process: "readonly",
|
|
35
|
+
Buffer: "readonly",
|
|
36
|
+
__dirname: "readonly",
|
|
37
|
+
__filename: "readonly",
|
|
38
|
+
global: "readonly",
|
|
39
|
+
module: "readonly",
|
|
40
|
+
require: "readonly",
|
|
41
|
+
exports: "readonly",
|
|
42
|
+
|
|
43
|
+
// Web Components API
|
|
44
|
+
HTMLElement: "readonly",
|
|
45
|
+
customElements: "readonly",
|
|
46
|
+
CustomEvent: "readonly",
|
|
47
|
+
ShadowRoot: "readonly",
|
|
48
|
+
HTMLSlotElement: "readonly",
|
|
49
|
+
CSSStyleSheet: "readonly",
|
|
50
|
+
|
|
51
|
+
// WSX specific
|
|
52
|
+
h: "readonly",
|
|
53
|
+
Fragment: "readonly",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
plugins: {
|
|
57
|
+
wsx: {
|
|
58
|
+
rules: {
|
|
59
|
+
"render-method-required": renderMethodRequired,
|
|
60
|
+
"no-react-imports": noReactImports,
|
|
61
|
+
"web-component-naming": webComponentNaming,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
rules: {
|
|
66
|
+
// WSX specific rules
|
|
67
|
+
"wsx/render-method-required": "error",
|
|
68
|
+
"wsx/no-react-imports": "error",
|
|
69
|
+
"wsx/web-component-naming": "warn",
|
|
70
|
+
|
|
71
|
+
// TypeScript rules (recommended)
|
|
72
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
73
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
74
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
75
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
76
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
77
|
+
|
|
78
|
+
// General rules
|
|
79
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
80
|
+
"no-debugger": "error",
|
|
81
|
+
"no-unused-vars": "off", // Use TypeScript version
|
|
82
|
+
"no-undef": "off", // TypeScript handles this
|
|
83
|
+
"prefer-const": "error",
|
|
84
|
+
"no-var": "error",
|
|
85
|
+
"no-duplicate-imports": "error",
|
|
86
|
+
"no-trailing-spaces": "error",
|
|
87
|
+
"eol-last": "error",
|
|
88
|
+
"comma-dangle": ["error", "always-multiline"],
|
|
89
|
+
semi: ["error", "always"],
|
|
90
|
+
quotes: ["error", "double", { avoidEscape: true, allowTemplateLiterals: true }],
|
|
91
|
+
},
|
|
92
|
+
settings: {
|
|
93
|
+
// No React settings needed
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Helper function to create a flat config with the plugin
|
|
98
|
+
export function createFlatConfig(plugin: Record<string, unknown>): Linter.FlatConfig {
|
|
99
|
+
return {
|
|
100
|
+
...flatConfig,
|
|
101
|
+
plugins: {
|
|
102
|
+
wsx: plugin,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Plugin WSX - 推荐配置
|
|
3
|
+
*
|
|
4
|
+
* 为 WSX 文件提供推荐的 ESLint 配置
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { WSXConfig } from "../types";
|
|
8
|
+
|
|
9
|
+
export const recommendedConfig: WSXConfig = {
|
|
10
|
+
parser: "@typescript-eslint/parser",
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaVersion: "latest",
|
|
13
|
+
sourceType: "module",
|
|
14
|
+
ecmaFeatures: {
|
|
15
|
+
jsx: true,
|
|
16
|
+
},
|
|
17
|
+
jsxPragma: "h",
|
|
18
|
+
jsxFragmentName: "Fragment",
|
|
19
|
+
},
|
|
20
|
+
plugins: ["wsx"],
|
|
21
|
+
rules: {
|
|
22
|
+
// WSX 特定规则(移除 valid-jsx-pragma,由 Vite 处理)
|
|
23
|
+
"wsx/render-method-required": "error",
|
|
24
|
+
"wsx/no-react-imports": "error",
|
|
25
|
+
"wsx/web-component-naming": "warn",
|
|
26
|
+
|
|
27
|
+
// TypeScript 规则(推荐)
|
|
28
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
29
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
30
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
31
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
32
|
+
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
33
|
+
|
|
34
|
+
// 通用规则
|
|
35
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
36
|
+
"no-debugger": "error",
|
|
37
|
+
"no-unused-vars": "off", // 使用 TypeScript 版本
|
|
38
|
+
"no-undef": "off", // TypeScript 处理
|
|
39
|
+
"prefer-const": "error",
|
|
40
|
+
"no-var": "error",
|
|
41
|
+
"no-duplicate-imports": "error",
|
|
42
|
+
"no-trailing-spaces": "error",
|
|
43
|
+
"eol-last": "error",
|
|
44
|
+
"comma-dangle": ["error", "always-multiline"],
|
|
45
|
+
semi: ["error", "always"],
|
|
46
|
+
quotes: ["error", "double", { avoidEscape: true, allowTemplateLiterals: true }],
|
|
47
|
+
|
|
48
|
+
// 禁用 React 相关规则
|
|
49
|
+
"react/react-in-jsx-scope": "off",
|
|
50
|
+
"react/prop-types": "off",
|
|
51
|
+
"react/jsx-uses-react": "off",
|
|
52
|
+
"react/jsx-uses-vars": "off",
|
|
53
|
+
"react/jsx-key": "off",
|
|
54
|
+
"react/jsx-no-duplicate-props": "off",
|
|
55
|
+
"react/jsx-no-undef": "off",
|
|
56
|
+
"react/no-array-index-key": "off",
|
|
57
|
+
"react/no-unescaped-entities": "off",
|
|
58
|
+
},
|
|
59
|
+
globals: {
|
|
60
|
+
// 浏览器环境
|
|
61
|
+
window: "readonly",
|
|
62
|
+
document: "readonly",
|
|
63
|
+
console: "readonly",
|
|
64
|
+
|
|
65
|
+
// Node.js 环境
|
|
66
|
+
process: "readonly",
|
|
67
|
+
Buffer: "readonly",
|
|
68
|
+
__dirname: "readonly",
|
|
69
|
+
__filename: "readonly",
|
|
70
|
+
global: "readonly",
|
|
71
|
+
module: "readonly",
|
|
72
|
+
require: "readonly",
|
|
73
|
+
exports: "readonly",
|
|
74
|
+
|
|
75
|
+
// Web Components API
|
|
76
|
+
HTMLElement: "readonly",
|
|
77
|
+
customElements: "readonly",
|
|
78
|
+
CustomEvent: "readonly",
|
|
79
|
+
ShadowRoot: "readonly",
|
|
80
|
+
HTMLSlotElement: "readonly",
|
|
81
|
+
CSSStyleSheet: "readonly",
|
|
82
|
+
|
|
83
|
+
// WSX 特定
|
|
84
|
+
h: "readonly",
|
|
85
|
+
Fragment: "readonly",
|
|
86
|
+
},
|
|
87
|
+
settings: {
|
|
88
|
+
// 不需要 React 设置
|
|
89
|
+
},
|
|
90
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Plugin for WSX (Web Components JSX) - TypeScript 版本
|
|
3
|
+
*
|
|
4
|
+
* 提供针对 WSX 框架的专用 ESLint 规则和配置
|
|
5
|
+
* 注意:不包含 valid-jsx-pragma 规则,因为 Vite 插件已处理 JSX pragma
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { renderMethodRequired } from "./rules/render-method-required";
|
|
9
|
+
import { noReactImports } from "./rules/no-react-imports";
|
|
10
|
+
import { webComponentNaming } from "./rules/web-component-naming";
|
|
11
|
+
import { recommendedConfig } from "./configs/recommended";
|
|
12
|
+
import { createFlatConfig } from "./configs/flat";
|
|
13
|
+
import { WSXPlugin } from "./types";
|
|
14
|
+
|
|
15
|
+
const plugin: WSXPlugin = {
|
|
16
|
+
// 插件元信息
|
|
17
|
+
meta: {
|
|
18
|
+
name: "@wsxjs/eslint-plugin-wsx",
|
|
19
|
+
version: "0.0.2",
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// 核心规则(移除 valid-jsx-pragma)
|
|
23
|
+
rules: {
|
|
24
|
+
"render-method-required": renderMethodRequired,
|
|
25
|
+
"no-react-imports": noReactImports,
|
|
26
|
+
"web-component-naming": webComponentNaming,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
// 配置预设
|
|
30
|
+
configs: {
|
|
31
|
+
recommended: recommendedConfig,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Export for ESLint 9 flat config
|
|
36
|
+
export const flat = {
|
|
37
|
+
recommended: createFlatConfig(plugin),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Export individual rules for manual configuration
|
|
41
|
+
export const rules = plugin.rules;
|
|
42
|
+
|
|
43
|
+
// Export configs
|
|
44
|
+
export const configs = plugin.configs;
|
|
45
|
+
|
|
46
|
+
export default plugin;
|