@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
package/dist/bin.js
CHANGED
|
@@ -13,6 +13,7 @@ import { join } from "node:path";
|
|
|
13
13
|
import { build } from "vite";
|
|
14
14
|
import { validatePluginJson } from "./validate.js";
|
|
15
15
|
import { defineLinkdeskPluginConfig } from "./vite-config.js";
|
|
16
|
+
import { runPluginLint, renderPluginLintReport } from "./eslint/lint.js";
|
|
16
17
|
const VITE_CONFIG_FILES = [
|
|
17
18
|
"vite.config.ts",
|
|
18
19
|
"vite.config.mts",
|
|
@@ -26,7 +27,15 @@ const USAGE = `linkdesk-plugin-sdk <command>
|
|
|
26
27
|
命令:
|
|
27
28
|
build 在插件工程根构建 .linkdesk-plugin(读 plugin.json → Vite build → zip)
|
|
28
29
|
validate 校验 plugin.json(参数 = 路径,默认 ./plugin.json)
|
|
30
|
+
lint E6#54d 门禁(eslint 12 规则 + 三 check 双轨,全 WARN 永不 fail;知情绕行 =
|
|
31
|
+
eslint-disable 注释)。参数 = 工程根,默认 process.cwd()
|
|
29
32
|
`;
|
|
33
|
+
async function cmdLint(root) {
|
|
34
|
+
const report = await runPluginLint(root);
|
|
35
|
+
// WARN 永不 fail(门禁哲学)——退出码只反映真 error(语法致命 / 作者自配 error 规则)
|
|
36
|
+
process.stdout.write(renderPluginLintReport(report) + "\n");
|
|
37
|
+
return report.eslintRows.some((r) => r.severity === 2) ? 1 : 0;
|
|
38
|
+
}
|
|
30
39
|
async function cmdBuild() {
|
|
31
40
|
const root = process.cwd();
|
|
32
41
|
const hasConfig = VITE_CONFIG_FILES.some((f) => existsSync(join(root, f)));
|
|
@@ -59,6 +68,9 @@ async function main() {
|
|
|
59
68
|
case "validate":
|
|
60
69
|
code = cmdValidate(arg ?? "plugin.json");
|
|
61
70
|
break;
|
|
71
|
+
case "lint":
|
|
72
|
+
code = await cmdLint(arg ?? process.cwd());
|
|
73
|
+
break;
|
|
62
74
|
default:
|
|
63
75
|
console.error(USAGE);
|
|
64
76
|
code = command ? 1 : 0;
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-css-hardcode.mjs 移植(E6#54d)——非 token 颜色字面量门禁。
|
|
3
|
+
*
|
|
4
|
+
* 与壳版本差异(07 §六·规则载体双轨 + 面向第三方工程):
|
|
5
|
+
* - root 相对扫描(任意插件工程),不写死壳目录;
|
|
6
|
+
* - 豁免只留通用类别:token 定义行(--name: 字面量)/ 测试 mock / i18n·主题·取色器数据目录
|
|
7
|
+
* / 内容画布文件级 eslint-disable(07 §七·2 视图级豁免);
|
|
8
|
+
* - ts/tsx 只扫 rgb()/hsl()(hex 由 eslint linkdesk/no-hardcoded-hex 规则拦——避免同 hex
|
|
9
|
+
* 双报噪音);.css 全扫(hex + rgb/hsl——eslint 到不了 .css)。
|
|
10
|
+
* - 纯函数返回违规数组(不 process.exit)——知情绕行由 buildDisableIndex 裁决。
|
|
11
|
+
*/
|
|
12
|
+
import { type CheckViolation } from "./scan.js";
|
|
13
|
+
export declare function runCssHardcodeCheck(root: string): CheckViolation[];
|
|
14
|
+
//# sourceMappingURL=css-hardcode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-hardcode.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/css-hardcode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAwF,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAoBtI,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CA6DlE"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-css-hardcode.mjs 移植(E6#54d)——非 token 颜色字面量门禁。
|
|
3
|
+
*
|
|
4
|
+
* 与壳版本差异(07 §六·规则载体双轨 + 面向第三方工程):
|
|
5
|
+
* - root 相对扫描(任意插件工程),不写死壳目录;
|
|
6
|
+
* - 豁免只留通用类别:token 定义行(--name: 字面量)/ 测试 mock / i18n·主题·取色器数据目录
|
|
7
|
+
* / 内容画布文件级 eslint-disable(07 §七·2 视图级豁免);
|
|
8
|
+
* - ts/tsx 只扫 rgb()/hsl()(hex 由 eslint linkdesk/no-hardcoded-hex 规则拦——避免同 hex
|
|
9
|
+
* 双报噪音);.css 全扫(hex + rgb/hsl——eslint 到不了 .css)。
|
|
10
|
+
* - 纯函数返回违规数组(不 process.exit)——知情绕行由 buildDisableIndex 裁决。
|
|
11
|
+
*/
|
|
12
|
+
import { collectFiles, relPath, readSource, stripComments, stripLineComments, isTestOrMockRel } from "./scan.js";
|
|
13
|
+
import { buildDisableIndex, isDisabled, CHECK_IDS } from "./disable.js";
|
|
14
|
+
const DATA_DIR_RE = /(^|\/)(i18n|themes?|color-picker)\//;
|
|
15
|
+
const EXT_CSS = [".css"];
|
|
16
|
+
const EXT_CODE = [".ts", ".tsx"];
|
|
17
|
+
const HEX_RE = /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b/g;
|
|
18
|
+
const RGB_RE = /rgba?\(|hsla?\(/g;
|
|
19
|
+
/** 定义上下文:本行属 `--name: <字面量>` 自定义属性(token 单一权威,非消费) */
|
|
20
|
+
const DEF_RE = /--[\w-]+\s*:\s*(?!var\()/;
|
|
21
|
+
/** rgb()/hsl() 参数含动态模板(${/var(/calc(/color-mix(/#hex)→ 非硬编码字面量 */
|
|
22
|
+
function isDynamicFunc(line, index) {
|
|
23
|
+
const open = line.lastIndexOf("(", index);
|
|
24
|
+
const close = line.indexOf(")", index);
|
|
25
|
+
const body = line.slice(open + 1, close < 0 ? undefined : close);
|
|
26
|
+
return /(\$\{|\bvar\(|calc\(|\bcolor-mix\(|#[0-9a-fA-F]{3,})/.test(body);
|
|
27
|
+
}
|
|
28
|
+
export function runCssHardcodeCheck(root) {
|
|
29
|
+
const violations = [];
|
|
30
|
+
const push = (rel, line, message, disabled) => {
|
|
31
|
+
// 知情绕行 = 静默豁免(对齐 eslint 原生 suppress 语义——disable 声明后不亮灯;内容画布
|
|
32
|
+
// 文件级一次声明即整体安静)。disable 注释本身 = 市场偏离收集器的机器可读标记,无需 echo。
|
|
33
|
+
if (isDisabled(disabled, line, CHECK_IDS.cssHardcode))
|
|
34
|
+
return;
|
|
35
|
+
violations.push({ file: rel, line, message });
|
|
36
|
+
};
|
|
37
|
+
for (const css of collectFiles(root, EXT_CSS)) {
|
|
38
|
+
const rel = relPath(root, css);
|
|
39
|
+
if (isTestOrMockRel(rel))
|
|
40
|
+
continue;
|
|
41
|
+
if (DATA_DIR_RE.test(rel))
|
|
42
|
+
continue;
|
|
43
|
+
const src = readSource(css);
|
|
44
|
+
const disabled = buildDisableIndex(src, [CHECK_IDS.cssHardcode]);
|
|
45
|
+
// 去块注释再行注释(保行号);行注释靠 (^|[^:]) 守卫防 https:// 误伤
|
|
46
|
+
const cleaned = stripLineComments(stripComments(src));
|
|
47
|
+
cleaned.split("\n").forEach((line, i) => {
|
|
48
|
+
if (!line.trim())
|
|
49
|
+
return;
|
|
50
|
+
if (DEF_RE.test(line))
|
|
51
|
+
return; // token 定义行豁免
|
|
52
|
+
const hits = [];
|
|
53
|
+
for (const m of line.matchAll(HEX_RE))
|
|
54
|
+
hits.push({ color: m[0], index: m.index });
|
|
55
|
+
for (const m of line.matchAll(RGB_RE)) {
|
|
56
|
+
if (!isDynamicFunc(line, m.index)) {
|
|
57
|
+
hits.push({ color: m[0] === "rgb(" || m[0] === "rgba(" ? "rgb()" : "hsl()", index: m.index });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const h of hits) {
|
|
61
|
+
push(rel, i + 1, `${line.trim().slice(0, 100)} ← 硬编码 ${h.color}(应走 CSS 变量 var(--text-*/--bg-*/--accent-*/--surface-*))`, disabled);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
for (const code of collectFiles(root, EXT_CODE)) {
|
|
66
|
+
const rel = relPath(root, code);
|
|
67
|
+
if (isTestOrMockRel(rel))
|
|
68
|
+
continue;
|
|
69
|
+
if (DATA_DIR_RE.test(rel))
|
|
70
|
+
continue;
|
|
71
|
+
const src = readSource(code);
|
|
72
|
+
const disabled = buildDisableIndex(src, [CHECK_IDS.cssHardcode]);
|
|
73
|
+
// ts/tsx:hex 由 eslint linkdesk/no-hardcoded-hex 规则拦,这里只补 rgb()/hsl()——强化版 hex 门禁
|
|
74
|
+
const cleaned = stripLineComments(stripComments(src));
|
|
75
|
+
cleaned.split("\n").forEach((line, i) => {
|
|
76
|
+
if (!line.trim())
|
|
77
|
+
return;
|
|
78
|
+
for (const m of line.matchAll(RGB_RE)) {
|
|
79
|
+
if (isDynamicFunc(line, m.index))
|
|
80
|
+
continue;
|
|
81
|
+
push(rel, i + 1, `${line.trim().slice(0, 100)} ← 硬编码 ${m[0] === "rgb(" || m[0] === "rgba(" ? "rgb()" : "hsl()"}(应走 CSS 变量)`, disabled);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return violations;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=css-hardcode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-hardcode.js","sourceRoot":"","sources":["../../../src/eslint/checks/css-hardcode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 知情绕行注释解析器(E6#54d)——供 SDK 三个 check 脚本(css-hardcode / font-scale / spacing-grid)
|
|
3
|
+
* 识别标准 eslint-disable 注释:命中豁免的违规行**整体静默**(对齐 eslint 原生 suppress 语义——
|
|
4
|
+
* disable 声明后不亮灯,内容画布文件级一次声明即整体安静;disable 注释本身即市场偏离收集器的
|
|
5
|
+
* 机器可读标记,check 不需 echo)。未豁免的违规 = 未处理偏离,正常上报。
|
|
6
|
+
*
|
|
7
|
+
* 与壳 no-hardcoded-hex 现有格式一致(非发明新语法,07 设计 §六·知情绕行):
|
|
8
|
+
* - 行级:`// eslint-disable-next-line <id> -- 理由`(其下一行豁免)
|
|
9
|
+
* `// eslint-disable-line <id> -- 理由`(本行豁免,行内尾注释)
|
|
10
|
+
* - 文件级:`/* eslint-disable <id> -- 理由`(块注释收尾 + 理由)——内容画布视图级豁免,
|
|
11
|
+
* 从该行到文件尾;`eslint-enable <id>` 可提前结束(缺省无 ids = 结束全部)
|
|
12
|
+
*
|
|
13
|
+
* eslint 本体不认这些伪规则 id(linkdesk/no-hardcoded-hex 等是 check 脚本 id,非 eslint rule),
|
|
14
|
+
* 因此 SDK lint 跑 eslint 时关掉 reportUnusedDisableDirectives——脚本自己认这些注释。
|
|
15
|
+
*/
|
|
16
|
+
export declare const CHECK_IDS: {
|
|
17
|
+
readonly cssHardcode: "linkdesk/no-hardcoded-hex";
|
|
18
|
+
readonly fontScale: "linkdesk/no-hardcoded-font-size";
|
|
19
|
+
readonly spacingGrid: "linkdesk/no-nonstandard-spacing";
|
|
20
|
+
};
|
|
21
|
+
export interface DisableIndex {
|
|
22
|
+
/** 1-based 行 → 该行豁免的 id 集合(行级 next-line/line + 文件级 disable 区间) */
|
|
23
|
+
active: Map<number, Set<string>>;
|
|
24
|
+
}
|
|
25
|
+
/** 建豁免索引。wantedIds = 本 check 认的 id(如 ["linkdesk/no-hardcoded-hex"])。 */
|
|
26
|
+
export declare function buildDisableIndex(source: string, wantedIds: string[]): DisableIndex;
|
|
27
|
+
/** 某文件某行(1-based)是否对该 check 知情豁免 */
|
|
28
|
+
export declare function isDisabled(index: DisableIndex, line: number, id: string): boolean;
|
|
29
|
+
//# sourceMappingURL=disable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disable.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/disable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAoFX,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CAClC;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,YAAY,CAmDnF;AAED,oCAAoC;AACpC,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAGjF"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 知情绕行注释解析器(E6#54d)——供 SDK 三个 check 脚本(css-hardcode / font-scale / spacing-grid)
|
|
3
|
+
* 识别标准 eslint-disable 注释:命中豁免的违规行**整体静默**(对齐 eslint 原生 suppress 语义——
|
|
4
|
+
* disable 声明后不亮灯,内容画布文件级一次声明即整体安静;disable 注释本身即市场偏离收集器的
|
|
5
|
+
* 机器可读标记,check 不需 echo)。未豁免的违规 = 未处理偏离,正常上报。
|
|
6
|
+
*
|
|
7
|
+
* 与壳 no-hardcoded-hex 现有格式一致(非发明新语法,07 设计 §六·知情绕行):
|
|
8
|
+
* - 行级:`// eslint-disable-next-line <id> -- 理由`(其下一行豁免)
|
|
9
|
+
* `// eslint-disable-line <id> -- 理由`(本行豁免,行内尾注释)
|
|
10
|
+
* - 文件级:`/* eslint-disable <id> -- 理由`(块注释收尾 + 理由)——内容画布视图级豁免,
|
|
11
|
+
* 从该行到文件尾;`eslint-enable <id>` 可提前结束(缺省无 ids = 结束全部)
|
|
12
|
+
*
|
|
13
|
+
* eslint 本体不认这些伪规则 id(linkdesk/no-hardcoded-hex 等是 check 脚本 id,非 eslint rule),
|
|
14
|
+
* 因此 SDK lint 跑 eslint 时关掉 reportUnusedDisableDirectives——脚本自己认这些注释。
|
|
15
|
+
*/
|
|
16
|
+
export const CHECK_IDS = {
|
|
17
|
+
cssHardcode: "linkdesk/no-hardcoded-hex",
|
|
18
|
+
fontScale: "linkdesk/no-hardcoded-font-size",
|
|
19
|
+
spacingGrid: "linkdesk/no-nonstandard-spacing",
|
|
20
|
+
};
|
|
21
|
+
/** 单遍注释 tokenizer:产出全部 // 行注释与 /* 块注释(块注释可跨行)。 */
|
|
22
|
+
function tokenizeComments(source) {
|
|
23
|
+
const out = [];
|
|
24
|
+
let i = 0;
|
|
25
|
+
let line = 1;
|
|
26
|
+
const n = source.length;
|
|
27
|
+
while (i < n) {
|
|
28
|
+
const ch = source[i];
|
|
29
|
+
if (ch === "\n") {
|
|
30
|
+
line++;
|
|
31
|
+
i++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (ch !== "/" || i + 1 >= n) {
|
|
35
|
+
i++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const next = source[i + 1];
|
|
39
|
+
if (next === "/") {
|
|
40
|
+
// 行注释到行尾
|
|
41
|
+
let j = i + 2;
|
|
42
|
+
while (j < n && source[j] !== "\n")
|
|
43
|
+
j++;
|
|
44
|
+
out.push({ text: source.slice(i + 2, j), startLine: line });
|
|
45
|
+
i = j;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (next === "*") {
|
|
49
|
+
// 块注释到 */
|
|
50
|
+
let j = i + 2;
|
|
51
|
+
let l = line;
|
|
52
|
+
while (j < n && !(source[j] === "*" && source[j + 1] === "/")) {
|
|
53
|
+
if (source[j] === "\n")
|
|
54
|
+
l++;
|
|
55
|
+
j++;
|
|
56
|
+
}
|
|
57
|
+
const end = j + 2 <= n ? j + 2 : j;
|
|
58
|
+
out.push({ text: source.slice(i + 2, j), startLine: line });
|
|
59
|
+
line = l + (end > j ? 0 : 0); // 闭合后若跨行已计过
|
|
60
|
+
// 推进:更新 line 计数越过内容
|
|
61
|
+
for (let k = i; k < end; k++)
|
|
62
|
+
if (source[k] === "\n")
|
|
63
|
+
line++;
|
|
64
|
+
i = end;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
i++;
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
const REASON_SEP = /\s+--\s+/;
|
|
72
|
+
function parseComment(comment) {
|
|
73
|
+
// 取首个非空行(块注释常以 " * " 前缀逐行;正文里先搜 eslint-disable 词)
|
|
74
|
+
const m = comment.text.match(/\beslint-(disable-next-line|disable-line|disable|enable)\b/);
|
|
75
|
+
if (!m)
|
|
76
|
+
return null;
|
|
77
|
+
const full = m[0];
|
|
78
|
+
const kind = full === "eslint-disable-next-line"
|
|
79
|
+
? "next-line"
|
|
80
|
+
: full === "eslint-disable-line"
|
|
81
|
+
? "line"
|
|
82
|
+
: full === "eslint-disable"
|
|
83
|
+
? "disable"
|
|
84
|
+
: "enable";
|
|
85
|
+
// ids = 关键字之后、可选 " -- reason" 之前的逗号/空白分隔 token
|
|
86
|
+
const after = comment.text.slice(m.index + full.length);
|
|
87
|
+
const [idPart, reason] = after.split(REASON_SEP, 2);
|
|
88
|
+
const ids = (idPart ?? "").split(/[\s,]+/).map((s) => s.trim()).filter(Boolean);
|
|
89
|
+
return { line: comment.startLine, kind, ids, reason: reason?.trim() };
|
|
90
|
+
}
|
|
91
|
+
/** 建豁免索引。wantedIds = 本 check 认的 id(如 ["linkdesk/no-hardcoded-hex"])。 */
|
|
92
|
+
export function buildDisableIndex(source, wantedIds) {
|
|
93
|
+
const active = new Map();
|
|
94
|
+
const wanted = new Set(wantedIds);
|
|
95
|
+
const mark = (l, id) => {
|
|
96
|
+
let s = active.get(l);
|
|
97
|
+
if (!s) {
|
|
98
|
+
s = new Set();
|
|
99
|
+
active.set(l, s);
|
|
100
|
+
}
|
|
101
|
+
s.add(id);
|
|
102
|
+
};
|
|
103
|
+
const comments = tokenizeComments(source);
|
|
104
|
+
const directives = comments.map(parseComment).filter((d) => d !== null);
|
|
105
|
+
// 1) 文件级 disable…enable 区间(每 id 单独算)
|
|
106
|
+
const opens = new Map(); // id -> start line
|
|
107
|
+
// bare disable(ids 空)视为作用于全部 wanted
|
|
108
|
+
const resolve = (ids) => (ids.length === 0 ? [...wanted] : ids.filter((x) => wanted.has(x)));
|
|
109
|
+
const totalLines = source.split("\n").length;
|
|
110
|
+
const applyRange = (id, from, toExclusive) => {
|
|
111
|
+
for (let l = from; l < toExclusive; l++)
|
|
112
|
+
mark(l, id);
|
|
113
|
+
};
|
|
114
|
+
for (const d of directives) {
|
|
115
|
+
if (d.kind === "disable") {
|
|
116
|
+
for (const id of resolve(d.ids)) {
|
|
117
|
+
if (!opens.has(id))
|
|
118
|
+
opens.set(id, d.line);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (d.kind === "enable") {
|
|
122
|
+
for (const id of resolve(d.ids)) {
|
|
123
|
+
const from = opens.get(id);
|
|
124
|
+
if (from !== undefined) {
|
|
125
|
+
applyRange(id, from, d.line); // 到 enable 所在行为止(不含)
|
|
126
|
+
opens.delete(id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const [id, from] of opens)
|
|
132
|
+
applyRange(id, from, totalLines + 1);
|
|
133
|
+
// 2) 行级 next-line / line
|
|
134
|
+
for (const d of directives) {
|
|
135
|
+
if (d.kind === "next-line") {
|
|
136
|
+
for (const id of resolve(d.ids))
|
|
137
|
+
mark(d.line + 1, id);
|
|
138
|
+
}
|
|
139
|
+
else if (d.kind === "line") {
|
|
140
|
+
for (const id of resolve(d.ids))
|
|
141
|
+
mark(d.line, id);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { active };
|
|
145
|
+
}
|
|
146
|
+
/** 某文件某行(1-based)是否对该 check 知情豁免 */
|
|
147
|
+
export function isDisabled(index, line, id) {
|
|
148
|
+
const s = index.active.get(line);
|
|
149
|
+
return !!s && s.has(id);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=disable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../src/eslint/checks/disable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-font-scale-audit.mjs 移植(E6#54d)——字号度量防回潮(面向第三方插件工程)。
|
|
3
|
+
*
|
|
4
|
+
* 壳版本差异(07 §六·规则载体双轨 + 第三方无壳 DOM 概念):
|
|
5
|
+
* - root 相对扫描(任意插件工程);含 .tsx/.jsx 行内 `style={{ fontSize: NN }}`;
|
|
6
|
+
* - 壳「独立显示图标 WHITELIST 注册表」**不移植**——那是壳专属 CSS 选择器清单,对第三方
|
|
7
|
+
* 工程是死代码。图标等确有意的裸 px 字号 → 该行 eslint-disable linkdesk/no-hardcoded-font-size
|
|
8
|
+
* -- 理由(07 §七·2 知情绕行),不再发明第二套白名单语法;
|
|
9
|
+
* - 豁免只留通用类别:token 定义不适用(font-size 无定义/消费分界,见下)/ 测试 mock /
|
|
10
|
+
* i18n·主题·取色器数据目录 / 内容画布文件级 disable。
|
|
11
|
+
* - 纯函数返回违规数组(不 process.exit)——知情绕行由 buildDisableIndex 裁决。
|
|
12
|
+
*
|
|
13
|
+
* 语义(档案 §七):`font-size: NNpx` / `line-height: NNpx` 裸 px 一律拦(须走插件的
|
|
14
|
+
* 字号 token / --ui-scale 生态);unitless / calc / var() / % 放行。1-6px 微调豁免不适用
|
|
15
|
+
* 字号(字号无微调豁免——壳原版也无,字号哪怕 12px 也须 token)。
|
|
16
|
+
*/
|
|
17
|
+
import { type CheckViolation } from "./scan.js";
|
|
18
|
+
export declare function runFontScaleCheck(root: string): CheckViolation[];
|
|
19
|
+
//# sourceMappingURL=font-scale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-scale.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/font-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAuG,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AA6FrJ,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAehE"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-font-scale-audit.mjs 移植(E6#54d)——字号度量防回潮(面向第三方插件工程)。
|
|
3
|
+
*
|
|
4
|
+
* 壳版本差异(07 §六·规则载体双轨 + 第三方无壳 DOM 概念):
|
|
5
|
+
* - root 相对扫描(任意插件工程);含 .tsx/.jsx 行内 `style={{ fontSize: NN }}`;
|
|
6
|
+
* - 壳「独立显示图标 WHITELIST 注册表」**不移植**——那是壳专属 CSS 选择器清单,对第三方
|
|
7
|
+
* 工程是死代码。图标等确有意的裸 px 字号 → 该行 eslint-disable linkdesk/no-hardcoded-font-size
|
|
8
|
+
* -- 理由(07 §七·2 知情绕行),不再发明第二套白名单语法;
|
|
9
|
+
* - 豁免只留通用类别:token 定义不适用(font-size 无定义/消费分界,见下)/ 测试 mock /
|
|
10
|
+
* i18n·主题·取色器数据目录 / 内容画布文件级 disable。
|
|
11
|
+
* - 纯函数返回违规数组(不 process.exit)——知情绕行由 buildDisableIndex 裁决。
|
|
12
|
+
*
|
|
13
|
+
* 语义(档案 §七):`font-size: NNpx` / `line-height: NNpx` 裸 px 一律拦(须走插件的
|
|
14
|
+
* 字号 token / --ui-scale 生态);unitless / calc / var() / % 放行。1-6px 微调豁免不适用
|
|
15
|
+
* 字号(字号无微调豁免——壳原版也无,字号哪怕 12px 也须 token)。
|
|
16
|
+
*/
|
|
17
|
+
import { collectFiles, relPath, readSource, stripComments, stripLineComments, countNewlines, isTestOrMockRel } from "./scan.js";
|
|
18
|
+
import { buildDisableIndex, isDisabled, CHECK_IDS } from "./disable.js";
|
|
19
|
+
const DATA_DIR_RE = /(^|\/)(i18n|themes?|color-picker)\//;
|
|
20
|
+
const EXT_CSS = [".css"];
|
|
21
|
+
const EXT_JSX = [".tsx", ".jsx"];
|
|
22
|
+
const PX_ONLY_RE = /^\d+(\.\d+)?px$/;
|
|
23
|
+
/** tsx 行内 `style={{ fontSize: NN }}`(px 数字字面量)——多行 style 对象亦覆盖 */
|
|
24
|
+
const INLINE_FONT_SIZE_RE = /style\s*[:=]\s*\{[\s\S]*?fontSize\s*:\s*(\d+(?:\.\d+)?)/g;
|
|
25
|
+
/** 递归收集 CSS 规则块(含 @media 等内层嵌套块);从去注释文本解析 → 行号不漂移 */
|
|
26
|
+
function collectBlocks(text, baseLine, out) {
|
|
27
|
+
let i = 0;
|
|
28
|
+
const n = text.length;
|
|
29
|
+
while (i < n) {
|
|
30
|
+
const open = text.indexOf("{", i);
|
|
31
|
+
if (open === -1)
|
|
32
|
+
break;
|
|
33
|
+
const prevSemi = text.lastIndexOf(";", open);
|
|
34
|
+
const prevClose = text.lastIndexOf("}", open);
|
|
35
|
+
const selStart = Math.max(prevSemi, prevClose) + 1;
|
|
36
|
+
const selector = text.slice(selStart, open).trim();
|
|
37
|
+
let depth = 1;
|
|
38
|
+
let j = open + 1;
|
|
39
|
+
while (j < n && depth > 0) {
|
|
40
|
+
if (text[j] === "{")
|
|
41
|
+
depth++;
|
|
42
|
+
else if (text[j] === "}")
|
|
43
|
+
depth--;
|
|
44
|
+
j++;
|
|
45
|
+
}
|
|
46
|
+
const inner = text.slice(open + 1, j - 1);
|
|
47
|
+
const line = baseLine + countNewlines(text.slice(0, open));
|
|
48
|
+
if (selector)
|
|
49
|
+
out.push({ selector, inner, line });
|
|
50
|
+
collectBlocks(inner, line, out);
|
|
51
|
+
i = j;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const HINT = "字号必须 var(--font-size-*) / 行高 unitless 或 calc(*var(--ui-scale))(LinkDesk 度量体系门禁);" +
|
|
55
|
+
"确属独立显示图标 → eslint-disable-next-line linkdesk/no-hardcoded-font-size -- 理由";
|
|
56
|
+
function auditCssFile(abs, rel, violations, disabled) {
|
|
57
|
+
const src = readSource(abs);
|
|
58
|
+
const cleaned = stripComments(src);
|
|
59
|
+
const rules = [];
|
|
60
|
+
collectBlocks(cleaned, 0, rules);
|
|
61
|
+
for (const rule of rules) {
|
|
62
|
+
// 只扫本层声明(首个 `{` 之前)——嵌套块由递归单独处理,避免双报
|
|
63
|
+
const nested = rule.inner.indexOf("{");
|
|
64
|
+
const declText = nested === -1 ? rule.inner : rule.inner.slice(0, nested);
|
|
65
|
+
for (const part of declText.split(";")) {
|
|
66
|
+
const decl = part.trim();
|
|
67
|
+
if (!decl)
|
|
68
|
+
continue;
|
|
69
|
+
const colon = decl.indexOf(":");
|
|
70
|
+
if (colon === -1)
|
|
71
|
+
continue;
|
|
72
|
+
const property = decl.slice(0, colon).trim().toLowerCase();
|
|
73
|
+
if (property !== "font-size" && property !== "line-height")
|
|
74
|
+
continue;
|
|
75
|
+
const value = decl.slice(colon + 1).trim().replace(/!important\s*$/, "").trim();
|
|
76
|
+
if (!PX_ONLY_RE.test(value))
|
|
77
|
+
continue; // 非裸 px(token/calc/unitless)放行
|
|
78
|
+
const declIdx = declText.indexOf(decl);
|
|
79
|
+
const line1 = rule.line + countNewlines(declText.slice(0, declIdx)) + 1;
|
|
80
|
+
// 知情绕行 = 静默豁免(对齐 eslint suppress 语义,disable 声明后不亮灯)
|
|
81
|
+
if (isDisabled(disabled, line1, CHECK_IDS.fontScale))
|
|
82
|
+
return;
|
|
83
|
+
violations.push({
|
|
84
|
+
file: rel,
|
|
85
|
+
line: line1,
|
|
86
|
+
message: `${value}(selector: ${rule.selector})← 裸 px 字号/行高——${HINT}`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function auditJsxFile(abs, rel, violations, disabled) {
|
|
92
|
+
const src = readSource(abs);
|
|
93
|
+
const cleaned = stripLineComments(stripComments(src)); // 注释伪报排除(行号不漂移)
|
|
94
|
+
let m;
|
|
95
|
+
INLINE_FONT_SIZE_RE.lastIndex = 0;
|
|
96
|
+
while ((m = INLINE_FONT_SIZE_RE.exec(cleaned)) !== null) {
|
|
97
|
+
const line1 = countNewlines(cleaned.slice(0, m.index)) + 1;
|
|
98
|
+
if (isDisabled(disabled, line1, CHECK_IDS.fontScale))
|
|
99
|
+
continue; // 知情绕行 = 静默豁免
|
|
100
|
+
violations.push({
|
|
101
|
+
file: rel,
|
|
102
|
+
line: line1,
|
|
103
|
+
message: `行内 style fontSize = ${m[1]}px ← 裸 px 字号——${HINT}`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function runFontScaleCheck(root) {
|
|
108
|
+
const violations = [];
|
|
109
|
+
for (const css of collectFiles(root, EXT_CSS)) {
|
|
110
|
+
const rel = relPath(root, css);
|
|
111
|
+
if (isTestOrMockRel(rel))
|
|
112
|
+
continue;
|
|
113
|
+
if (DATA_DIR_RE.test(rel))
|
|
114
|
+
continue;
|
|
115
|
+
auditCssFile(css, rel, violations, buildDisableIndex(readSource(css), [CHECK_IDS.fontScale]));
|
|
116
|
+
}
|
|
117
|
+
for (const jsx of collectFiles(root, EXT_JSX)) {
|
|
118
|
+
const rel = relPath(root, jsx);
|
|
119
|
+
if (isTestOrMockRel(rel))
|
|
120
|
+
continue;
|
|
121
|
+
if (DATA_DIR_RE.test(rel))
|
|
122
|
+
continue;
|
|
123
|
+
auditJsxFile(jsx, rel, violations, buildDisableIndex(readSource(jsx), [CHECK_IDS.fontScale]));
|
|
124
|
+
}
|
|
125
|
+
return violations;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=font-scale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-scale.js","sourceRoot":"","sources":["../../../src/eslint/checks/font-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAuB,MAAM,WAAW,CAAC;AACrJ,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAExE,MAAM,WAAW,GAAG,qCAAqC,CAAC;AAC1D,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;AACzB,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACjC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,kEAAkE;AAClE,MAAM,mBAAmB,GAAG,0DAA0D,CAAC;AAQvF,qDAAqD;AACrD,SAAS,aAAa,CAAC,IAAY,EAAE,QAAgB,EAAE,GAAc;IACnE,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAClC,IAAI,IAAI,KAAK,CAAC,CAAC;YAAE,MAAM;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;gBAAE,KAAK,EAAE,CAAC;iBACxB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;gBAAE,KAAK,EAAE,CAAC;YAClC,CAAC,EAAE,CAAC;QACN,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3D,IAAI,QAAQ;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC,GAAG,CAAC,CAAC;IACR,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GACR,kFAAkF;IAClF,2EAA2E,CAAC;AAE9E,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW,EAAE,UAA4B,EAAE,QAA8C;IAC1H,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,aAAa,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,qCAAqC;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1E,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,SAAS;YAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3D,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,aAAa;gBAAE,SAAS;YACrE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAChF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,SAAS,CAAC,+BAA+B;YACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;YACxE,oDAAoD;YACpD,IAAI,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC;gBAAE,OAAO;YAC7D,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,GAAG;gBACT,IAAI,EAAE,KAAK;gBACX,OAAO,EAAE,GAAG,KAAK,cAAc,IAAI,CAAC,QAAQ,kBAAkB,IAAI,EAAE;aACrE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW,EAAE,UAA4B,EAAE,QAA8C;IAC1H,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,iBAAiB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB;IACvE,IAAI,CAAyB,CAAC;IAC9B,mBAAmB,CAAC,SAAS,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3D,IAAI,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC;YAAE,SAAS,CAAC,cAAc;QAC9E,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC,iBAAiB,IAAI,EAAE;SAC5D,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,eAAe,CAAC,GAAG,CAAC;YAAE,SAAS;QACnC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,eAAe,CAAC,GAAG,CAAC;YAAE,SAAS;QACnC,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const SKIP_DIRS: Set<string>;
|
|
2
|
+
/** 收集 dir 下指定扩展名文件(跳过 SKIP_DIRS)。返回绝对路径数组。 */
|
|
3
|
+
export declare function collectFiles(dir: string, exts: string[]): string[];
|
|
4
|
+
/** 工程相对路径(正斜杠) */
|
|
5
|
+
export declare function relPath(root: string, abs: string): string;
|
|
6
|
+
/** 把 /* *\/ 注释替换为等长空格(保留换行 → 行号不漂移;注释内 { ; 不干扰解析) */
|
|
7
|
+
export declare function stripComments(text: string): string;
|
|
8
|
+
/** 去掉 // 行注释(保留 : 前缀防 https:// 误伤) */
|
|
9
|
+
export declare function stripLineComments(text: string): string;
|
|
10
|
+
export declare function countNewlines(s: string): number;
|
|
11
|
+
export declare function isTestOrMockRel(rel: string): boolean;
|
|
12
|
+
export declare function readSource(abs: string): string;
|
|
13
|
+
export interface CheckViolation {
|
|
14
|
+
file: string;
|
|
15
|
+
line: number;
|
|
16
|
+
message: string;
|
|
17
|
+
/** eslint-disable 知情绕行的理由(若该行被豁免注释标记);未豁免 = undefined */
|
|
18
|
+
bypassReason?: string;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,SAAS,aAAyF,CAAC;AAEhH,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAoBlE;AAED,kBAAkB;AAClB,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 三个 check 脚本(css-hardcode / font-scale / spacing-grid)共享的工程扫描工具(E6#54d 移植)。
|
|
3
|
+
*
|
|
4
|
+
* 与壳 check-*.mjs 的关系:壳版本写死壳目录(src/plugins/…)+ 壳文档化豁免白名单;本版本
|
|
5
|
+
* 面向**任意第三方插件工程**——以传入 root 为相对基准扫描,豁免只留通用类别(token 定义 / 测试 /
|
|
6
|
+
* i18n·主题·取色器数据 / canvas / 内容画布文件级 disable),不携带壳专属路径(07 §六·三档)。
|
|
7
|
+
* 机制(去注释 / 行号不漂移 / 纯函数收违规不 process.exit)与壳同源。
|
|
8
|
+
*/
|
|
9
|
+
import { readdirSync, readFileSync, existsSync } from "node:fs";
|
|
10
|
+
import { join, relative, sep } from "node:path";
|
|
11
|
+
export const SKIP_DIRS = new Set(["node_modules", "dist", "dist-electron", ".git", ".vite", "coverage", "out"]);
|
|
12
|
+
/** 收集 dir 下指定扩展名文件(跳过 SKIP_DIRS)。返回绝对路径数组。 */
|
|
13
|
+
export function collectFiles(dir, exts) {
|
|
14
|
+
const out = [];
|
|
15
|
+
const walk = (cur) => {
|
|
16
|
+
let entries;
|
|
17
|
+
try {
|
|
18
|
+
entries = readdirSync(cur, { withFileTypes: true });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return; // 不可读目录(权限等)跳过
|
|
22
|
+
}
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
if (SKIP_DIRS.has(entry.name))
|
|
26
|
+
continue;
|
|
27
|
+
walk(join(cur, entry.name));
|
|
28
|
+
}
|
|
29
|
+
else if (entry.isFile() && exts.some((e) => entry.name.endsWith(e))) {
|
|
30
|
+
out.push(join(cur, entry.name));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
if (existsSync(dir))
|
|
35
|
+
walk(dir);
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** 工程相对路径(正斜杠) */
|
|
39
|
+
export function relPath(root, abs) {
|
|
40
|
+
return relative(root, abs).split(sep).join("/");
|
|
41
|
+
}
|
|
42
|
+
/** 把 /* *\/ 注释替换为等长空格(保留换行 → 行号不漂移;注释内 { ; 不干扰解析) */
|
|
43
|
+
export function stripComments(text) {
|
|
44
|
+
return text.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
|
|
45
|
+
}
|
|
46
|
+
/** 去掉 // 行注释(保留 : 前缀防 https:// 误伤) */
|
|
47
|
+
export function stripLineComments(text) {
|
|
48
|
+
return text.replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
49
|
+
}
|
|
50
|
+
export function countNewlines(s) {
|
|
51
|
+
let c = 0;
|
|
52
|
+
for (const ch of s)
|
|
53
|
+
if (ch === "\n")
|
|
54
|
+
c++;
|
|
55
|
+
return c;
|
|
56
|
+
}
|
|
57
|
+
export function isTestOrMockRel(rel) {
|
|
58
|
+
return /\.(test|spec)\.(tsx?|jsx?)$/.test(rel) || /\.(fixture|mock)\.(tsx?|jsx?)$/.test(rel);
|
|
59
|
+
}
|
|
60
|
+
export function readSource(abs) {
|
|
61
|
+
return readFileSync(abs, "utf8");
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/eslint/checks/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;AAEhH,8CAA8C;AAC9C,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,IAAc;IACtD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,GAAW,EAAQ,EAAE;QACjC,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,eAAe;QACzB,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACxC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9B,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kBAAkB;AAClB,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAW;IAC/C,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,EAAE,IAAI,CAAC;QAAE,IAAI,EAAE,KAAK,IAAI;YAAE,CAAC,EAAE,CAAC;IACzC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-spacing-grid.mjs 移植(E6#54d)——间距 4px 节奏刻度门禁(面向第三方插件工程)。
|
|
3
|
+
*
|
|
4
|
+
* 壳版本差异(07 §六·规则载体双轨):root 相对扫描(任意插件工程);豁免只留通用类别
|
|
5
|
+
* (测试 mock / i18n·主题·取色器数据目录 / eslint-disable 知情绕行)。token 定义行天然豁免:
|
|
6
|
+
* `--space-*: NNpx` 的属性名不是 padding/margin/gap,属性前缀正则不会命中(与壳同源语义)。
|
|
7
|
+
*
|
|
8
|
+
* 语义(档案):CSS 声明行的 padding/margin/gap 值在 4px 节奏刻度上;1-6px = 微调值
|
|
9
|
+
* (图标间距/紧凑内边距有意的精细控制)豁免;>6px 非 4 倍数 = 违规模板。
|
|
10
|
+
* 纯函数返回违规数组(不 process.exit)——知情绕行由 buildDisableIndex 裁决。
|
|
11
|
+
*/
|
|
12
|
+
import { type CheckViolation } from "./scan.js";
|
|
13
|
+
export declare function runSpacingGridCheck(root: string): CheckViolation[];
|
|
14
|
+
//# sourceMappingURL=spacing-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing-grid.d.ts","sourceRoot":"","sources":["../../../src/eslint/checks/spacing-grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAwF,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAStI,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CA4BlE"}
|