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