@linkdesk/plugin-sdk 0.1.0 → 0.1.1
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/dist/bin.js +12 -0
- package/dist/bin.js.map +1 -1
- package/dist/eslint/checks/css-hardcode.d.ts +14 -0
- package/dist/eslint/checks/css-hardcode.d.ts.map +1 -0
- package/dist/eslint/checks/css-hardcode.js +87 -0
- package/dist/eslint/checks/css-hardcode.js.map +1 -0
- package/dist/eslint/checks/disable.d.ts +29 -0
- package/dist/eslint/checks/disable.d.ts.map +1 -0
- package/dist/eslint/checks/disable.js +151 -0
- package/dist/eslint/checks/disable.js.map +1 -0
- package/dist/eslint/checks/font-scale.d.ts +19 -0
- package/dist/eslint/checks/font-scale.d.ts.map +1 -0
- package/dist/eslint/checks/font-scale.js +127 -0
- package/dist/eslint/checks/font-scale.js.map +1 -0
- package/dist/eslint/checks/scan.d.ts +20 -0
- package/dist/eslint/checks/scan.d.ts.map +1 -0
- package/dist/eslint/checks/scan.js +63 -0
- package/dist/eslint/checks/scan.js.map +1 -0
- package/dist/eslint/checks/spacing-grid.d.ts +14 -0
- package/dist/eslint/checks/spacing-grid.d.ts.map +1 -0
- package/dist/eslint/checks/spacing-grid.js +54 -0
- package/dist/eslint/checks/spacing-grid.js.map +1 -0
- package/dist/eslint/index.d.ts +15 -0
- package/dist/eslint/index.d.ts.map +1 -0
- package/dist/eslint/index.js +13 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/lint.d.ts +26 -0
- package/dist/eslint/lint.d.ts.map +1 -0
- package/dist/eslint/lint.js +112 -0
- package/dist/eslint/lint.js.map +1 -0
- package/dist/eslint/preset.d.ts +11 -0
- package/dist/eslint/preset.d.ts.map +1 -0
- package/dist/eslint/preset.js +88 -0
- package/dist/eslint/preset.js.map +1 -0
- package/dist/eslint/rules.d.ts +28 -0
- package/dist/eslint/rules.d.ts.map +1 -0
- package/dist/eslint/rules.js +441 -0
- package/dist/eslint/rules.js.map +1 -0
- package/dist/vite-config.d.ts +29 -8
- package/dist/vite-config.d.ts.map +1 -1
- package/dist/vite-config.js +377 -67
- package/dist/vite-config.js.map +1 -1
- package/package.json +20 -3
- package/schemas/plugin.schema.json +696 -687
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════
|
|
2
|
+
// 1. async 初始化函数 _initialized guard 必须配 _loadingPromise
|
|
3
|
+
// (壳 #59c 教训:StrictMode 双重 effect 竞态)
|
|
4
|
+
// ═══════════════════════════════════════════════════════════
|
|
5
|
+
export const noAsyncInitGuardOnly = {
|
|
6
|
+
meta: {
|
|
7
|
+
type: "problem",
|
|
8
|
+
docs: {
|
|
9
|
+
description: "async 初始化函数只设 _initialized guard 不够——必须配 _loadingPromise 防 StrictMode 双重 effect 竞态(第二次调用须返回进行中的 Promise)",
|
|
10
|
+
recommended: true,
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
noLoadingPromise: "async init 函数 {{name}} 在 await 前设 _initialized=true,未返回 _loadingPromise。" +
|
|
14
|
+
" StrictMode 双重 effect 第二次调用会跳过加载,但后续初始化操作可能尚未就绪(隐形竞态)。" +
|
|
15
|
+
" 修复:if (_initialized) return _loadingPromise ?? Promise.resolve(); return (_loadingPromise = (async () => { ... })());",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
let initializedSet = false;
|
|
20
|
+
let hasAwaitAfter = false;
|
|
21
|
+
let hasLoadingPromise = false;
|
|
22
|
+
let functionName = "";
|
|
23
|
+
return {
|
|
24
|
+
":matches(FunctionDeclaration, FunctionExpression, ArrowFunctionExpression)[async=true]"(node) {
|
|
25
|
+
initializedSet = false;
|
|
26
|
+
hasAwaitAfter = false;
|
|
27
|
+
hasLoadingPromise = false;
|
|
28
|
+
functionName = (node.id && node.id.name) || "";
|
|
29
|
+
},
|
|
30
|
+
"AssignmentExpression[left.type='Identifier'][left.name='_initialized']"(node) {
|
|
31
|
+
if (node.right && node.right.value === true) {
|
|
32
|
+
initializedSet = true;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"Identifier[name='_loadingPromise']"() {
|
|
36
|
+
hasLoadingPromise = true;
|
|
37
|
+
},
|
|
38
|
+
AwaitExpression() {
|
|
39
|
+
if (initializedSet) {
|
|
40
|
+
hasAwaitAfter = true;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
":matches(FunctionDeclaration, FunctionExpression, ArrowFunctionExpression)[async=true]:exit"(node) {
|
|
44
|
+
if (initializedSet && hasAwaitAfter && !hasLoadingPromise) {
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: "noLoadingPromise",
|
|
48
|
+
data: { name: functionName || "(anonymous)" },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
initializedSet = false;
|
|
52
|
+
hasAwaitAfter = false;
|
|
53
|
+
hasLoadingPromise = false;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
// ═══════════════════════════════════════════════════════════
|
|
59
|
+
// 2. useEffect 依赖回调 prop 但缺活跃守卫(壳 #59c 教训)
|
|
60
|
+
// 组件 return null 不代表 effect 不跑——React effect 只看挂载不看 DOM。
|
|
61
|
+
// ═══════════════════════════════════════════════════════════
|
|
62
|
+
export const noEffectCallbackWithoutActiveGuard = {
|
|
63
|
+
meta: {
|
|
64
|
+
type: "problem",
|
|
65
|
+
docs: {
|
|
66
|
+
description: "useEffect 依赖回调 prop(onChange/onHighlight/onSelect/onApply)但缺 if (!open)/if (!isActive) 活跃守卫——组件 return null 时 effect 照跑",
|
|
67
|
+
recommended: true,
|
|
68
|
+
},
|
|
69
|
+
messages: {
|
|
70
|
+
missingGuard: "useEffect 依赖了回调 prop (onChange/onHighlight/onSelect/onApply),但没有 if (!open) 或 if (!isActive) 活跃守卫。" +
|
|
71
|
+
" 组件 return null 时 React effect 照跑——回调可能意外触发全局副作用。" +
|
|
72
|
+
" 修复:effect 顶部加 if (!open) return; 并把 open/isActive 纳入依赖数组。",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
create(context) {
|
|
76
|
+
const CALLBACK_PROP_PATTERN = /^on(Change|Highlight|Select|Apply|Close|Toggle|Submit)$/;
|
|
77
|
+
return {
|
|
78
|
+
CallExpression(node) {
|
|
79
|
+
if (node.callee?.type !== "Identifier" || node.callee.name !== "useEffect")
|
|
80
|
+
return;
|
|
81
|
+
const args = node.arguments;
|
|
82
|
+
if (args.length < 2)
|
|
83
|
+
return;
|
|
84
|
+
const depsArg = args[1];
|
|
85
|
+
if (!depsArg || depsArg.type !== "ArrayExpression")
|
|
86
|
+
return;
|
|
87
|
+
const body = args[0];
|
|
88
|
+
if (!body || (body.type !== "ArrowFunctionExpression" && body.type !== "FunctionExpression"))
|
|
89
|
+
return;
|
|
90
|
+
const callbackDeps = depsArg.elements.filter((el) => {
|
|
91
|
+
if (!el || el.type !== "Identifier")
|
|
92
|
+
return false;
|
|
93
|
+
return CALLBACK_PROP_PATTERN.test(el.name);
|
|
94
|
+
});
|
|
95
|
+
if (callbackDeps.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
const bodyText = context.getSourceCode().getText(body);
|
|
98
|
+
const hasActiveGuard = /\bif\s*\(\s*!\s*(?:open|isActive|active|visible|enabled)\s*\)/.test(bodyText);
|
|
99
|
+
if (hasActiveGuard)
|
|
100
|
+
return;
|
|
101
|
+
context.report({ node, messageId: "missingGuard" });
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
// ═══════════════════════════════════════════════════════════
|
|
107
|
+
// 3. useEffect/useCallback cleanup 禁止动态 import()(壳 #36k2 教训)
|
|
108
|
+
// import() 异步在 StrictMode 重挂载后 resolve → 误删新注册数据
|
|
109
|
+
// ═══════════════════════════════════════════════════════════
|
|
110
|
+
const AST_CHILD_KEYS = new Set([
|
|
111
|
+
"body", "expression", "argument", "callee", "alternate", "consequent",
|
|
112
|
+
"test", "init", "left", "right", "object", "property", "elements",
|
|
113
|
+
"declarations", "params", "id", "handler", "finalizer",
|
|
114
|
+
]);
|
|
115
|
+
function hasDynamicImport(node, context, depth = 0) {
|
|
116
|
+
if (!node || depth > 20)
|
|
117
|
+
return false;
|
|
118
|
+
if (node.type === "CallExpression" && node.callee?.type === "Import") {
|
|
119
|
+
context.report({ node, messageId: "dynamicImport" });
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
for (const key of AST_CHILD_KEYS) {
|
|
123
|
+
const child = node[key];
|
|
124
|
+
if (!child)
|
|
125
|
+
continue;
|
|
126
|
+
if (Array.isArray(child)) {
|
|
127
|
+
for (const item of child) {
|
|
128
|
+
if (item && typeof item.type === "string" && hasDynamicImport(item, context, depth + 1))
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (typeof child.type === "string" && hasDynamicImport(child, context, depth + 1)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
export const noDynamicImportInEffectCleanup = {
|
|
139
|
+
meta: {
|
|
140
|
+
type: "problem",
|
|
141
|
+
docs: {
|
|
142
|
+
description: "useEffect/useCallback cleanup 禁止动态 import()——异步执行在 StrictMode 重挂载后误删新数据",
|
|
143
|
+
recommended: true,
|
|
144
|
+
},
|
|
145
|
+
messages: {
|
|
146
|
+
dynamicImport: "useEffect/useCallback cleanup 中禁止动态 import()。" +
|
|
147
|
+
" import() 异步执行——React StrictMode 会先 unmount(触发此 cleanup)再 mount(重新注册)," +
|
|
148
|
+
" 异步 import 在 mount 之后才 resolve → 把新注册的数据也删了。" +
|
|
149
|
+
" 修复:改成文件顶部静态 import。",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
create(context) {
|
|
153
|
+
return {
|
|
154
|
+
CallExpression(node) {
|
|
155
|
+
if (node.callee?.type !== "Identifier")
|
|
156
|
+
return;
|
|
157
|
+
if (node.callee.name !== "useEffect" && node.callee.name !== "useCallback")
|
|
158
|
+
return;
|
|
159
|
+
const args = node.arguments;
|
|
160
|
+
if (args.length === 0)
|
|
161
|
+
return;
|
|
162
|
+
const body = args[0];
|
|
163
|
+
if (!body || (body.type !== "ArrowFunctionExpression" && body.type !== "FunctionExpression"))
|
|
164
|
+
return;
|
|
165
|
+
const bodyNode = body.body;
|
|
166
|
+
if (!bodyNode)
|
|
167
|
+
return;
|
|
168
|
+
if (bodyNode.type === "CallExpression") {
|
|
169
|
+
if (bodyNode.callee?.type === "Import")
|
|
170
|
+
context.report({ node: bodyNode, messageId: "dynamicImport" });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (bodyNode.type !== "BlockStatement")
|
|
174
|
+
return;
|
|
175
|
+
for (const stmt of bodyNode.body) {
|
|
176
|
+
if (stmt.type !== "ReturnStatement" || !stmt.argument)
|
|
177
|
+
continue;
|
|
178
|
+
hasDynamicImport(stmt.argument, context);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
// ═══════════════════════════════════════════════════════════
|
|
185
|
+
// 4. JSX 中禁止 ref.current 参与渲染(壳 #58e 教训)
|
|
186
|
+
// ref 更新不触发重渲染 → UI 与实际状态脱节。渲染决策走 useState。
|
|
187
|
+
// ═══════════════════════════════════════════════════════════
|
|
188
|
+
export const noRefCurrentInJsx = {
|
|
189
|
+
meta: {
|
|
190
|
+
type: "problem",
|
|
191
|
+
docs: {
|
|
192
|
+
description: "JSX 中禁止 ref.current 直接参与渲染——ref 更新不触发 React 重渲染",
|
|
193
|
+
recommended: true,
|
|
194
|
+
},
|
|
195
|
+
messages: {
|
|
196
|
+
noRefCurrent: "JSX 中禁止 {{name}}.current——ref 更新不触发 React 重渲染。" +
|
|
197
|
+
" 异步拿到数据 → ref 更新 → 组件不知道 → 下次任何事件触发重渲染时突然切状态 → UI 跳变/空白。" +
|
|
198
|
+
" 修复:改用 useState。ref 仅用于 DOM 引用/前值对比/generation counter。",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
create(context) {
|
|
202
|
+
return {
|
|
203
|
+
"JSXExpressionContainer > MemberExpression[property.name='current']"(node) {
|
|
204
|
+
const objectName = node.object?.type === "Identifier" ? node.object.name : "?";
|
|
205
|
+
context.report({ node, messageId: "noRefCurrent", data: { name: objectName } });
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
// ═══════════════════════════════════════════════════════════
|
|
211
|
+
// 5. JSX/UI 中文字面量必须走 t()(壳 no-hardcoded-chinese 同逻辑;门禁名 = no-hardcoded-zh)
|
|
212
|
+
// UI 文案硬编码中文 → i18n 遗漏。注释/console/测试文件不拦。
|
|
213
|
+
// ═══════════════════════════════════════════════════════════
|
|
214
|
+
const CHINESE_RE = /[㐀-鿿]/;
|
|
215
|
+
function hasChinese(text) {
|
|
216
|
+
return CHINESE_RE.test(text);
|
|
217
|
+
}
|
|
218
|
+
function isInsideTranslationCall(node) {
|
|
219
|
+
let cur = node.parent;
|
|
220
|
+
while (cur) {
|
|
221
|
+
if (cur.type === "CallExpression") {
|
|
222
|
+
const callee = cur.callee;
|
|
223
|
+
if (callee.type === "Identifier" && (callee.name === "t" || callee.name === "i18n"))
|
|
224
|
+
return true;
|
|
225
|
+
if (callee.type === "MemberExpression" &&
|
|
226
|
+
callee.object?.type === "Identifier" &&
|
|
227
|
+
callee.object.name === "i18n" &&
|
|
228
|
+
callee.property?.type === "Identifier" &&
|
|
229
|
+
callee.property.name === "t")
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (cur.type === "JSXExpressionContainer" || cur.type === "JSXAttribute")
|
|
233
|
+
break;
|
|
234
|
+
cur = cur.parent;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
/** 字面量是否落在 JSX 表达式上下文——向上穿透三元/逻辑链(盲区:placeholder={cond ? "中文" : "…"}) */
|
|
239
|
+
function isInJsxContext(node) {
|
|
240
|
+
let cur = node.parent;
|
|
241
|
+
while (cur) {
|
|
242
|
+
if (cur.type === "JSXExpressionContainer" || cur.type === "JSXAttribute")
|
|
243
|
+
return true;
|
|
244
|
+
if (cur.type === "ConditionalExpression" || cur.type === "LogicalExpression") {
|
|
245
|
+
cur = cur.parent;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
export const noHardcodedZh = {
|
|
253
|
+
meta: {
|
|
254
|
+
type: "suggestion",
|
|
255
|
+
docs: {
|
|
256
|
+
description: "JSX/UI 中的中文字面量必须走 t() 包裹——防 i18n 遗漏(UI 文字全走 t() 硬约束)",
|
|
257
|
+
recommended: true,
|
|
258
|
+
},
|
|
259
|
+
messages: {
|
|
260
|
+
noZh: "UI 文案中文字面量 \"{{text}}\" 未用 t() 包裹。" +
|
|
261
|
+
" 修复:<span>{t(\"中文\")}</span> 或 placeholder={t(\"中文\")},文案进 i18n 资源。" +
|
|
262
|
+
" 注释/console/测试文件可忽略。",
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
create(context) {
|
|
266
|
+
return {
|
|
267
|
+
JSXText(node) {
|
|
268
|
+
const text = node.value.trim();
|
|
269
|
+
if (!text || !hasChinese(text))
|
|
270
|
+
return;
|
|
271
|
+
context.report({ node, messageId: "noZh", data: { text: text.slice(0, 20) } });
|
|
272
|
+
},
|
|
273
|
+
Literal(node) {
|
|
274
|
+
if (typeof node.value !== "string" || !hasChinese(node.value))
|
|
275
|
+
return;
|
|
276
|
+
if (isInsideTranslationCall(node))
|
|
277
|
+
return;
|
|
278
|
+
if (isInJsxContext(node)) {
|
|
279
|
+
context.report({ node, messageId: "noZh", data: { text: node.value.slice(0, 20) } });
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
TemplateLiteral(node) {
|
|
283
|
+
if (node.quasis.length === 1 && hasChinese(node.quasis[0].value.raw)) {
|
|
284
|
+
if (isInsideTranslationCall(node))
|
|
285
|
+
return;
|
|
286
|
+
if (isInJsxContext(node)) {
|
|
287
|
+
context.report({ node, messageId: "noZh", data: { text: node.quasis[0].value.raw.slice(0, 20) } });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
// ═══════════════════════════════════════════════════════════
|
|
295
|
+
// 6. 颜色禁止硬编码 hex——走 CSS 变量 var(--xxx)(壳 no-hardcoded-hex 同逻辑)
|
|
296
|
+
// var(--x, #hex) 回退值合规;取色器色板/canvas/测试/i18n 数据豁免;
|
|
297
|
+
// 内容画布(游戏/数据可视化主区)走文件级 /* eslint-disable linkdesk/no-hardcoded-hex -- 内容画布 */
|
|
298
|
+
// ——标准注释即批量知情绕行(07 §七·2)。
|
|
299
|
+
// ═══════════════════════════════════════════════════════════
|
|
300
|
+
const HEX_RE = /#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b/;
|
|
301
|
+
const CSS_VAR_FALLBACK_RE = /var\(/;
|
|
302
|
+
export const noHardcodedHex = {
|
|
303
|
+
meta: {
|
|
304
|
+
type: "problem",
|
|
305
|
+
docs: {
|
|
306
|
+
description: "颜色禁止硬编码 hex——走 CSS 变量 var(--xxx)(var(--*)/t() 零警告,主题/玻璃自动跟随)",
|
|
307
|
+
recommended: true,
|
|
308
|
+
},
|
|
309
|
+
messages: {
|
|
310
|
+
noHex: "颜色硬编码 hex \"{{text}}\" 未走 CSS 变量。" +
|
|
311
|
+
" 修复:color/background 用 var(--text-*/--bg-*/--accent-*/--surface-*) → 自动跟随主题+玻璃。" +
|
|
312
|
+
" 若是默认色数据/取色器色板/canvas 绘图,加 `// eslint-disable-next-line linkdesk/no-hardcoded-hex -- 理由` 并注明豁免类别。" +
|
|
313
|
+
" 内容画布(游戏/数据可视化主区)用文件级 `/* eslint-disable linkdesk/no-hardcoded-hex -- 内容画布 */`。",
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
create(context) {
|
|
317
|
+
const filename = (context.getFilename?.() ?? "").replace(/\\/g, "/");
|
|
318
|
+
const isExemptFile = /\.(test|spec)\.(ts|tsx)$/.test(filename) ||
|
|
319
|
+
/mock/i.test(filename) ||
|
|
320
|
+
/\/themes?\//.test(filename) ||
|
|
321
|
+
/\/i18n\//.test(filename) ||
|
|
322
|
+
/\/color-picker\//.test(filename) ||
|
|
323
|
+
/canvas/i.test(filename);
|
|
324
|
+
return {
|
|
325
|
+
Literal(node) {
|
|
326
|
+
if (typeof node.value !== "string")
|
|
327
|
+
return;
|
|
328
|
+
if (isExemptFile)
|
|
329
|
+
return;
|
|
330
|
+
if (!HEX_RE.test(node.value))
|
|
331
|
+
return;
|
|
332
|
+
if (CSS_VAR_FALLBACK_RE.test(node.value))
|
|
333
|
+
return;
|
|
334
|
+
context.report({ node, messageId: "noHex", data: { text: node.value.slice(0, 20) } });
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
// ═══════════════════════════════════════════════════════════
|
|
340
|
+
// 7. 禁止裸 px 圆角(新写)——border-radius 走 var(--radius-*) / var(--surface-radius)
|
|
341
|
+
// React style={{ borderRadius: 8 }}(数字=px)或 borderRadius: "8px" → 用 var() 字符串。
|
|
342
|
+
// 内容画布豁免同上(文件级 disable)。CSS 文件里的 border-radius 由 token 契约文档引导
|
|
343
|
+
// (eslint 不扫 .css——契约域,07 §六「不设门禁的域」同精神)。
|
|
344
|
+
// ═══════════════════════════════════════════════════════════
|
|
345
|
+
const PX_STRING_RE = /^(\d+(?:\.\d+)?)px$/;
|
|
346
|
+
export const noHardcodedRadius = {
|
|
347
|
+
meta: {
|
|
348
|
+
type: "problem",
|
|
349
|
+
docs: {
|
|
350
|
+
description: "禁止裸 px 圆角——border-radius 走 var(--radius-*) / var(--surface-radius) 跟随圆角滑杆",
|
|
351
|
+
recommended: true,
|
|
352
|
+
},
|
|
353
|
+
messages: {
|
|
354
|
+
noRadius: "borderRadius 硬编码 {{value}} 未走 CSS 变量。" +
|
|
355
|
+
" 修复:border-radius: var(--radius-md) 或 var(--surface-radius) → 自动跟随全局圆角滑杆。" +
|
|
356
|
+
" 内容画布(游戏/数据可视化)用文件级 `/* eslint-disable linkdesk/no-hardcoded-radius -- 内容画布 */`。",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
create(context) {
|
|
360
|
+
const filename = (context.getFilename?.() ?? "").replace(/\\/g, "/");
|
|
361
|
+
const isExemptFile = /\.(test|spec)\.(ts|tsx)$/.test(filename) || /canvas/i.test(filename);
|
|
362
|
+
return {
|
|
363
|
+
JSXAttribute(node) {
|
|
364
|
+
if (isExemptFile)
|
|
365
|
+
return;
|
|
366
|
+
// 只查 style={{ ... }} 的 JSX 表达式对象
|
|
367
|
+
if (node.name?.type !== "JSXIdentifier" || node.name.name !== "style")
|
|
368
|
+
return;
|
|
369
|
+
const val = node.value;
|
|
370
|
+
if (!val || val.type !== "JSXExpressionContainer" || !val.expression)
|
|
371
|
+
return;
|
|
372
|
+
const expr = val.expression;
|
|
373
|
+
if (expr.type !== "ObjectExpression")
|
|
374
|
+
return;
|
|
375
|
+
for (const prop of expr.properties) {
|
|
376
|
+
if (prop.type !== "Property")
|
|
377
|
+
continue;
|
|
378
|
+
const key = prop.key;
|
|
379
|
+
if (!key || (key.type !== "Identifier" && key.type !== "Literal"))
|
|
380
|
+
continue;
|
|
381
|
+
const keyName = key.type === "Identifier" ? key.name : String(key.value);
|
|
382
|
+
if (keyName !== "borderRadius")
|
|
383
|
+
continue;
|
|
384
|
+
const v = prop.value;
|
|
385
|
+
if (v && v.type === "Literal") {
|
|
386
|
+
if (typeof v.value === "number" || (typeof v.value === "string" && PX_STRING_RE.test(v.value))) {
|
|
387
|
+
context.report({ node: v, messageId: "noRadius", data: { value: String(v.value) } });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
// ═══════════════════════════════════════════════════════════
|
|
396
|
+
// 8. QuickPick 禁止 renderItem(壳同规则)——@linkdesk/ui 控件用 slot props 保视觉统一
|
|
397
|
+
// ═══════════════════════════════════════════════════════════
|
|
398
|
+
export const noQuickpickRenderItem = {
|
|
399
|
+
meta: {
|
|
400
|
+
type: "problem",
|
|
401
|
+
docs: {
|
|
402
|
+
description: "QuickPick 禁止 renderItem——用 structured slot props 保面板视觉统一",
|
|
403
|
+
recommended: true,
|
|
404
|
+
},
|
|
405
|
+
messages: {
|
|
406
|
+
noRenderItem: "QuickPick renderItem 已废弃——自由度过高导致面板视觉不统一。" +
|
|
407
|
+
" 改用 slot props:renderLabel / renderCategory / renderDetail / renderDetailRight。",
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
create(context) {
|
|
411
|
+
return {
|
|
412
|
+
JSXElement(node) {
|
|
413
|
+
const tagName = node.openingElement?.name;
|
|
414
|
+
if (!tagName || tagName.type !== "Identifier" || tagName.name !== "QuickPick")
|
|
415
|
+
return;
|
|
416
|
+
for (const attr of node.openingElement.attributes || []) {
|
|
417
|
+
if (attr.type === "JSXAttribute" && attr.name?.type === "JSXIdentifier" && attr.name.name === "renderItem") {
|
|
418
|
+
context.report({ node: attr, messageId: "noRenderItem" });
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
// ═══════════════════════════════════════════════════════════
|
|
427
|
+
// 注册映射——kebab 键 = 配置规则 id 的 ruleName 部分。
|
|
428
|
+
// eslint 按原样名查 plugin.rules(config.js parseRuleId 后直查,无 camel 转换),
|
|
429
|
+
// 故键必须与 preset 里 `linkdesk/<rule>` 的破折号名一致(壳 export default 同款)。
|
|
430
|
+
// ═══════════════════════════════════════════════════════════
|
|
431
|
+
export const linkdeskRuleMap = {
|
|
432
|
+
"no-async-init-guard-only": noAsyncInitGuardOnly,
|
|
433
|
+
"no-effect-callback-without-active-guard": noEffectCallbackWithoutActiveGuard,
|
|
434
|
+
"no-dynamic-import-in-effect-cleanup": noDynamicImportInEffectCleanup,
|
|
435
|
+
"no-ref-current-in-jsx": noRefCurrentInJsx,
|
|
436
|
+
"no-hardcoded-zh": noHardcodedZh,
|
|
437
|
+
"no-hardcoded-hex": noHardcodedHex,
|
|
438
|
+
"no-hardcoded-radius": noHardcodedRadius,
|
|
439
|
+
"no-quickpick-render-item": noQuickpickRenderItem,
|
|
440
|
+
};
|
|
441
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/eslint/rules.ts"],"names":[],"mappings":"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"}
|
package/dist/vite-config.d.ts
CHANGED
|
@@ -10,19 +10,40 @@
|
|
|
10
10
|
* 构建裁决:
|
|
11
11
|
* - React/react-dom/react-i18next/**i18next** external(壳提供——插件自打 i18next 实例 → 翻译全空,
|
|
12
12
|
* B3 教训);其他依赖 inline 完全自包含。
|
|
13
|
-
* -
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* - 🔥 E6#15(多表面打包):一个插件 = 主入口 + 每 contributes.views[].render 一个编译表面。
|
|
14
|
+
* **每个表面一次独立 vite lib build**(closeBundle 编排 N 次内层 `build()`)→ 每表面单文件自包含。
|
|
15
|
+
* 不赌 vite 单 build 多 JS 入口(实测 entry facade 空 chunk——rollup 把共享图并进首个入口却丢
|
|
16
|
+
* 其余入口 default 导出;E6#15 实证)。各表面共享模块在表面间重复打包(react 等 external 除外,
|
|
17
|
+
* css 内联进各表面再合并去重)——zip 大一点,换来入口导出零失真 + 逐表面失败隔离。
|
|
18
|
+
* zip 内布局:
|
|
19
|
+
* index.bundle.js 主入口(entry default 组件 + 模块级贡献副作用)
|
|
20
|
+
* views/<View>.bundle.js 每 contributes.views[].render 的独立表面(独立 lib build 产物)
|
|
21
|
+
* index.bundle.css 全插件聚合 css(有则 loader <link> 注入,与 js 并列)
|
|
22
|
+
* dist/ 内 plugin.json 的 render 字段改写指向 `views/<View>.bundle.js`(编译产物路径)——
|
|
23
|
+
* 源码 plugin.json 保持作者视角 `src/views/X.tsx`;壳 loader 读 dist manifest 后
|
|
24
|
+
* dynamic-import `${root}/views/X.bundle.js`(既有 glob 外回退分支,E5.7#98)即命中。
|
|
25
|
+
* - CSS:每表面 lib build cssCodeSplit 强制 false → 各产单 css → packager 合并为 `index.bundle.css`
|
|
26
|
+
* (各表面 css 规则全局性,合并 = 源码模式壳 build 全插件 css 合一语义)。壳 loader 激活 bundle
|
|
27
|
+
* 插件时 `<link rel=stylesheet>` 注入、卸载移除(对标 VS Code extension css 由宿主 link 的架构模型;
|
|
28
|
+
* 入口同步 css 不会被 vite style-inject,entry css 期待 html <link>,插件 chunk 无 html 消费方)。
|
|
29
|
+
* - Worker(monaco 等):`worker.format:"es"`——lib 模式 worker 默认 iife 撞 code-split 报错
|
|
30
|
+
* (Invalid value "iife" for worker.format),es 允许 worker 内动态 import。
|
|
31
|
+
* - 打包 = 内嵌私有插件 `linkdesk-plugin-packager` 的 Vite hook 序列。外层 build 只做哑入口
|
|
32
|
+
* (虚拟模块)承载 closeBundle——真实工作全在 closeBundle:逐表面 lib build → 汇总 pkgDir →
|
|
33
|
+
* 静态清单 + jszip。归属唯一(packager),bin 只编排不重复 zip。
|
|
17
34
|
* - 静态清单从**源码 pluginRoot** 拷贝(非 outDir——outDir 每次 emptyOutDir 清空),含 plugin.json/
|
|
18
|
-
* icon/README.md/CHANGELOG.md(K2 缝隙)/ i18n
|
|
19
|
-
* outDir 深拷贝进 pkgDir。
|
|
35
|
+
* icon/README.md/CHANGELOG.md(K2 缝隙)/ i18n 声明文件。
|
|
20
36
|
* - zip 条目相对 pkgDir、正斜杠、无外层目录(loader 解压期待 plugin.json 在顶,E6#7 契约)。
|
|
21
37
|
* - dev/serve 不触发 build 系 hook → packager 天然只在 build 跑。
|
|
22
38
|
*/
|
|
23
|
-
import type
|
|
39
|
+
import { type UserConfig } from "vite";
|
|
40
|
+
/** 壳提供、插件不得重复打包的依赖——i18next 必须 external(B3:自打实例 → 翻译全空)。
|
|
41
|
+
* E6#15d 消费切换实证:`react-dom/client` 必须同列 external——池 import-map 已提供 clean 副本,
|
|
42
|
+
* 否则作者 import react-dom/client 时其 dev wrapper(createRoot 解析读 `process.env.NODE_ENV`,
|
|
43
|
+
* 顶层执行)被内联进 bundle → 池运行态 ReferenceError: process is not defined → 视图全崩。 */
|
|
44
|
+
export declare const DEFAULT_EXTERNAL: string[];
|
|
24
45
|
export interface LinkdeskPluginOptions {
|
|
25
|
-
/** 入口文件,默认 plugin.json 的 entry,再缺省 "src/index.tsx" */
|
|
46
|
+
/** 入口文件,默认 plugin.json 的 entry,再缺省 "src/index.tsx"。无 entry(纯 contributes 插件)→ 仅 views 表面 */
|
|
26
47
|
entry?: string;
|
|
27
48
|
/** 输出目录,默认 "dist" */
|
|
28
49
|
outDir?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-config.d.ts","sourceRoot":"","sources":["../src/vite-config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vite-config.d.ts","sourceRoot":"","sources":["../src/vite-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAWxE;;;6EAG6E;AAC7E,eAAO,MAAM,gBAAgB,UAA8F,CAAC;AAM5H,MAAM,WAAW,qBAAqB;IACpC,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAuOD,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU,CAkN1F"}
|