@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.
Files changed (44) hide show
  1. package/dist/bin.js +12 -0
  2. package/dist/bin.js.map +1 -1
  3. package/dist/eslint/checks/css-hardcode.d.ts +14 -0
  4. package/dist/eslint/checks/css-hardcode.d.ts.map +1 -0
  5. package/dist/eslint/checks/css-hardcode.js +87 -0
  6. package/dist/eslint/checks/css-hardcode.js.map +1 -0
  7. package/dist/eslint/checks/disable.d.ts +29 -0
  8. package/dist/eslint/checks/disable.d.ts.map +1 -0
  9. package/dist/eslint/checks/disable.js +151 -0
  10. package/dist/eslint/checks/disable.js.map +1 -0
  11. package/dist/eslint/checks/font-scale.d.ts +19 -0
  12. package/dist/eslint/checks/font-scale.d.ts.map +1 -0
  13. package/dist/eslint/checks/font-scale.js +127 -0
  14. package/dist/eslint/checks/font-scale.js.map +1 -0
  15. package/dist/eslint/checks/scan.d.ts +20 -0
  16. package/dist/eslint/checks/scan.d.ts.map +1 -0
  17. package/dist/eslint/checks/scan.js +63 -0
  18. package/dist/eslint/checks/scan.js.map +1 -0
  19. package/dist/eslint/checks/spacing-grid.d.ts +14 -0
  20. package/dist/eslint/checks/spacing-grid.d.ts.map +1 -0
  21. package/dist/eslint/checks/spacing-grid.js +54 -0
  22. package/dist/eslint/checks/spacing-grid.js.map +1 -0
  23. package/dist/eslint/index.d.ts +15 -0
  24. package/dist/eslint/index.d.ts.map +1 -0
  25. package/dist/eslint/index.js +13 -0
  26. package/dist/eslint/index.js.map +1 -0
  27. package/dist/eslint/lint.d.ts +26 -0
  28. package/dist/eslint/lint.d.ts.map +1 -0
  29. package/dist/eslint/lint.js +112 -0
  30. package/dist/eslint/lint.js.map +1 -0
  31. package/dist/eslint/preset.d.ts +11 -0
  32. package/dist/eslint/preset.d.ts.map +1 -0
  33. package/dist/eslint/preset.js +88 -0
  34. package/dist/eslint/preset.js.map +1 -0
  35. package/dist/eslint/rules.d.ts +28 -0
  36. package/dist/eslint/rules.d.ts.map +1 -0
  37. package/dist/eslint/rules.js +441 -0
  38. package/dist/eslint/rules.js.map +1 -0
  39. package/dist/vite-config.d.ts +29 -8
  40. package/dist/vite-config.d.ts.map +1 -1
  41. package/dist/vite-config.js +377 -67
  42. package/dist/vite-config.js.map +1 -1
  43. package/package.json +20 -3
  44. package/schemas/plugin.schema.json +696 -687
@@ -0,0 +1,54 @@
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 { 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
+ /** 声明行命中:本行含 padding/margin/gap(含 padding-inline 等逻辑属——前缀 \b 后须紧跟 :,逻辑属被天然排除,与壳同源) */
17
+ const DECL_LINE_RE = /\b(padding|margin|gap)\s*:/;
18
+ const PX_RE = /\b(\d+)px\b/g;
19
+ export function runSpacingGridCheck(root) {
20
+ const violations = [];
21
+ for (const css of collectFiles(root, EXT_CSS)) {
22
+ const rel = relPath(root, css);
23
+ if (isTestOrMockRel(rel))
24
+ continue;
25
+ if (DATA_DIR_RE.test(rel))
26
+ continue;
27
+ const src = readSource(css);
28
+ const disabled = buildDisableIndex(src, [CHECK_IDS.spacingGrid]);
29
+ const cleaned = stripLineComments(stripComments(src));
30
+ cleaned.split("\n").forEach((line, i) => {
31
+ if (!DECL_LINE_RE.test(line))
32
+ return;
33
+ const line1 = i + 1;
34
+ for (const m of line.matchAll(PX_RE)) {
35
+ const value = parseInt(m[1], 10);
36
+ if (value <= 6)
37
+ continue; // 微调值(图标间距/紧凑内边距有意的精细控制)
38
+ if (value % 4 === 0)
39
+ continue; // 4px 节奏合规
40
+ // 知情绕行 = 静默豁免(对齐 eslint suppress 语义,disable 声明后不亮灯)
41
+ if (isDisabled(disabled, line1, CHECK_IDS.spacingGrid))
42
+ continue;
43
+ violations.push({
44
+ file: rel,
45
+ line: line1,
46
+ message: `${line.trim().slice(0, 100)} ← ${value}px 不在 4px 节奏刻度上(padding/margin/gap)——` +
47
+ "归到最近 4px 倍数,或 eslint-disable-next-line linkdesk/no-nonstandard-spacing -- 理由",
48
+ });
49
+ }
50
+ });
51
+ }
52
+ return violations;
53
+ }
54
+ //# sourceMappingURL=spacing-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spacing-grid.js","sourceRoot":"","sources":["../../../src/eslint/checks/spacing-grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAuB,MAAM,WAAW,CAAC;AACtI,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,sFAAsF;AACtF,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAClD,MAAM,KAAK,GAAG,cAAc,CAAC;AAE7B,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,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,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,iBAAiB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACtC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;YACrC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YACpB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACjC,IAAI,KAAK,IAAI,CAAC;oBAAE,SAAS,CAAC,yBAAyB;gBACnD,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS,CAAC,WAAW;gBAC1C,oDAAoD;gBACpD,IAAI,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC;oBAAE,SAAS;gBACjE,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,GAAG;oBACT,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,KAAK,uCAAuC;wBACtF,8EAA8E;iBACjF,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @linkdesk/plugin-sdk/eslint 子路径出口(E6#54d)——作者零配置门禁。
3
+ *
4
+ * 用法(脚手架模板):
5
+ * "lint": "linkdesk-plugin-sdk lint" // 两条腿全跑 + 打印报告(bin)
6
+ * // 或编程:linkdeskPluginLintConfig() 展开进作者自配 eslint.config.js
7
+ *
8
+ * 全量门禁 = eslint 规则腿 + 三 check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
+ * 见 src/eslint/rules.ts 头注(双源注记)。这里不暴露内部 check 函数——bin lint 已聚合。
10
+ */
11
+ export { linkdeskPluginLintConfig } from "./preset.js";
12
+ export type { PluginLintOptions } from "./preset.js";
13
+ export { runPluginLint, renderPluginLintReport } from "./lint.js";
14
+ export type { PluginLintReport, LintLeg } from "./lint.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @linkdesk/plugin-sdk/eslint 子路径出口(E6#54d)——作者零配置门禁。
3
+ *
4
+ * 用法(脚手架模板):
5
+ * "lint": "linkdesk-plugin-sdk lint" // 两条腿全跑 + 打印报告(bin)
6
+ * // 或编程:linkdeskPluginLintConfig() 展开进作者自配 eslint.config.js
7
+ *
8
+ * 全量门禁 = eslint 规则腿 + 三 check 扫描腿(lint.ts 编排)。规则 id 与 disable 注释格式
9
+ * 见 src/eslint/rules.ts 头注(双源注记)。这里不暴露内部 check 函数——bin lint 已聚合。
10
+ */
11
+ export { linkdeskPluginLintConfig } from "./preset.js";
12
+ export { runPluginLint, renderPluginLintReport } from "./lint.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type PluginLintOptions } from "./preset.js";
2
+ import { type CheckViolation } from "./checks/scan.js";
3
+ export interface LintLeg {
4
+ id: string;
5
+ label: string;
6
+ violations: CheckViolation[];
7
+ }
8
+ export interface EslintRow {
9
+ file: string;
10
+ line: number;
11
+ column: number;
12
+ ruleId: string | null;
13
+ message: string;
14
+ severity: 1 | 2;
15
+ }
16
+ export interface PluginLintReport {
17
+ files: number;
18
+ eslintRows: EslintRow[];
19
+ legs: LintLeg[];
20
+ totalCheckViolations: number;
21
+ tsconfigUsed: string | null;
22
+ }
23
+ export declare function runPluginLint(root: string, options?: PluginLintOptions): Promise<PluginLintReport>;
24
+ /** 打印报告(人机双通道的即时反馈环);返回进程退出码(真 error 才 1,WARN 永不 fail)。 */
25
+ export declare function renderPluginLintReport(report: PluginLintReport): string;
26
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"AAcA,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAI/E,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2D5G;AAED,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAkCvE"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `runPluginLint()`——`npm run lint` 门禁编排(E6#54d):eslint 规则腿 + 三 check 扫描腿双轨。
3
+ *
4
+ * 对标壳 check 同款双轨(07 §六·载体双轨):eslint(12 项注册规则,全 WARN)管 ts/tsx;
5
+ * css-hardcode / font-scale / spacing-grid 三移植脚本管整工程(eslint 到不了 .css,
6
+ * ts/tsx 的 rgb()/hsl() 也归 css-hardcode 补)。jscpd = 项目级可选(文档引导,不进编排)。
7
+ *
8
+ * 门禁哲学(07 §六·三档):违规全 WARN **永不 fail build**——本编排按违规数统计并打印
9
+ * 「未处理偏离」行;退出码只反映真 error(语法致命错 / 作者自配 error 规则),WARN 不拦。
10
+ * 知情绕行 = 标准 eslint-disable 注释(disable.ts 语义:命中豁免行整体静默不亮灯)。
11
+ */
12
+ import { ESLint } from "eslint";
13
+ import { existsSync } from "node:fs";
14
+ import { resolve } from "node:path";
15
+ import { linkdeskPluginLintConfig } from "./preset.js";
16
+ import { runCssHardcodeCheck } from "./checks/css-hardcode.js";
17
+ import { runFontScaleCheck } from "./checks/font-scale.js";
18
+ import { runSpacingGridCheck } from "./checks/spacing-grid.js";
19
+ import {} from "./checks/scan.js";
20
+ /** 示例用的门禁 id(打印知情绕行格式);伪 id 与 check 脚本 CHECK_IDS 同源 */
21
+ const LEG_HINT_ID = "linkdesk/no-hardcoded-hex";
22
+ export async function runPluginLint(root, options = {}) {
23
+ const absRoot = resolve(root);
24
+ const defaultTsconfig = resolve(absRoot, "tsconfig.json");
25
+ const tsconfig = options.tsconfig
26
+ ? resolve(absRoot, options.tsconfig)
27
+ : existsSync(defaultTsconfig)
28
+ ? defaultTsconfig
29
+ : null;
30
+ const preset = linkdeskPluginLintConfig({
31
+ files: options.files,
32
+ ignore: options.ignore,
33
+ tsconfig: tsconfig ?? undefined, // 无 tsconfig → 剥 settings(import-x 直解 node_modules)
34
+ });
35
+ if (!tsconfig) {
36
+ // 剥掉 import-x/typescript resolver——工程没有 tsconfig 时它无事可做
37
+ for (const block of preset) {
38
+ if (block.settings)
39
+ delete block.settings;
40
+ }
41
+ }
42
+ const eslint = new ESLint({
43
+ cwd: absRoot,
44
+ overrideConfigFile: true, // 只用 SDK 预设——零配置确定性强,不吞作者自配 eslint.config.js
45
+ overrideConfig: preset,
46
+ });
47
+ const results = await eslint.lintFiles(["**/*.{ts,tsx,js,jsx}"]);
48
+ const eslintRows = [];
49
+ for (const res of results) {
50
+ for (const m of res.messages) {
51
+ eslintRows.push({
52
+ file: res.filePath.slice(absRoot.length + 1).split("\\").join("/"),
53
+ line: m.line ?? 0,
54
+ column: m.column ?? 0,
55
+ ruleId: m.ruleId,
56
+ message: m.message,
57
+ severity: m.fatal || m.severity === 2 ? 2 : 1,
58
+ });
59
+ }
60
+ }
61
+ const css = runCssHardcodeCheck(absRoot);
62
+ const font = runFontScaleCheck(absRoot);
63
+ const spacing = runSpacingGridCheck(absRoot);
64
+ const legs = [
65
+ { id: "linkdesk/no-hardcoded-hex(css + rgb/hsl 腿)", label: "check-css-hardcode", violations: css },
66
+ { id: "linkdesk/no-hardcoded-font-size", label: "check-font-scale", violations: font },
67
+ { id: "linkdesk/no-nonstandard-spacing", label: "check-spacing-grid", violations: spacing },
68
+ ];
69
+ const totalCheckViolations = css.length + font.length + spacing.length;
70
+ return {
71
+ files: results.length,
72
+ eslintRows,
73
+ legs,
74
+ totalCheckViolations,
75
+ tsconfigUsed: tsconfig ? tsconfig : null,
76
+ };
77
+ }
78
+ /** 打印报告(人机双通道的即时反馈环);返回进程退出码(真 error 才 1,WARN 永不 fail)。 */
79
+ export function renderPluginLintReport(report) {
80
+ const lines = [];
81
+ const errors = report.eslintRows.filter((r) => r.severity === 2);
82
+ const warnings = report.eslintRows.filter((r) => r.severity === 1);
83
+ if (errors.length > 0) {
84
+ lines.push(`❌ eslint ${errors.length} 处 error(语法致命错 / 作者自配 error 规则)——`);
85
+ for (const r of errors)
86
+ lines.push(` ${r.file}:${r.line}:${r.column} [${r.ruleId ?? "fatal"}] ${r.message}`);
87
+ }
88
+ if (warnings.length > 0) {
89
+ lines.push(`⚠ eslint 规则腿:${warnings.length} 处未处理偏离(${report.files} 文件)——均为 WARN,永不 fail build。`);
90
+ for (const r of warnings)
91
+ lines.push(` ${r.file}:${r.line}:${r.column} [${r.ruleId}] ${r.message}`);
92
+ }
93
+ else if (errors.length === 0) {
94
+ lines.push(`✅ eslint 规则腿:${report.files} 文件零偏离。`);
95
+ }
96
+ for (const leg of report.legs) {
97
+ if (leg.violations.length === 0) {
98
+ lines.push(`✅ ${leg.label}:零偏离。`);
99
+ continue;
100
+ }
101
+ lines.push(`⚠ ${leg.label}:${leg.violations.length} 处未处理偏离——`);
102
+ for (const v of leg.violations) {
103
+ lines.push(` ${v.file}:${v.line} ${v.message}`);
104
+ }
105
+ }
106
+ lines.push(`\n门禁 = 警告不是封锁(07 §六·三档):未处理偏离可修可绕——知情绕行写标准注释\n` +
107
+ ` // eslint-disable-next-line ${LEG_HINT_ID} -- 理由 (行级)\n` +
108
+ ` /* eslint-disable ${LEG_HINT_ID} -- 内容画布 */ (文件级:内容/画布整文件豁免)\n` +
109
+ `WARN 永不 fail build/上传;偏离标签随包可见(市场层读取 disable 注释)。`);
110
+ return lines.join("\n");
111
+ }
112
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/eslint/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Linter } from "eslint";
2
+ export interface PluginLintOptions {
3
+ /** 参与 lint 的 glob(默认:ts/tsx/js/jsx) */
4
+ files?: string[];
5
+ /** 追加忽略 glob(叠在默认忽略集之上) */
6
+ ignore?: string[];
7
+ /** import-x/no-unresolved 解析用 tsconfig 路径(相对工程根;默认 ./tsconfig.json) */
8
+ tsconfig?: string;
9
+ }
10
+ export declare function linkdeskPluginLintConfig(options?: PluginLintOptions): Linter.Config[];
11
+ //# sourceMappingURL=preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/eslint/preset.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAK7C,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAgBD,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,CAkDzF"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `linkdeskPluginLintConfig()`——第三方插件工程的 eslint 门禁预设(E6#54d)。
3
+ *
4
+ * 07 设计 §六「三档梯度」:全部规则 **WARN 级,永不 fail build/上传**——lint 是建议不是封锁。
5
+ * 知情绕行 = 标准 eslint-disable 注释(行级 eslint-disable-next-line/eslint-disable-line,
6
+ * 或文件级 eslint-disable 批量声明——注释里带理由 `-- 内容画布` 等),本预设把
7
+ * reportUnusedDisableDirectives 留给调用方关闭(见 lint.ts——脚本伪 id 如
8
+ * linkdesk/no-hardcoded-font-size 非 eslint rule,eslint 不认,靠 check 脚本自己认)。
9
+ *
10
+ * 15 项门禁载体双轨(07 §六·审计对齐):
11
+ * - 本预设 = eslint 规则腿(rules 映射 12 项注册);
12
+ * - 整工程扫描腿 = css-hardcode / font-scale / spacing-grid 三 check(lint.ts 调 run*Check)——
13
+ * css 与 rgb()/hsl() 的 hex 强拦、字号 token、间距 4px 节奏(eslint 到不了 .css);
14
+ * - jscpd(克隆检测)= 项目级可选,不进预设(文档引导)。
15
+ * `npm run lint`(bin lint)两条腿都走,对标壳 check 同款双轨。
16
+ *
17
+ * 脚手架模板默认启用本预设(07 §八);作者可自定义 eslint.config 后自管。
18
+ */
19
+ import tseslint from "@typescript-eslint/eslint-plugin";
20
+ import tsparser from "@typescript-eslint/parser";
21
+ import reactHooks from "eslint-plugin-react-hooks";
22
+ import importX from "eslint-plugin-import-x";
23
+ import { linkdeskRuleMap } from "./rules.js";
24
+ /** 默认忽略 = 构建产物 / 依赖 / 版本控制 / vite 缓存 / 声明文件 / 测试与 mock(对齐 scan.ts SKIP_DIRS 语义) */
25
+ const BASE_IGNORES = [
26
+ "**/node_modules/**",
27
+ "**/dist/**",
28
+ "**/dist-electron/**",
29
+ "**/out/**",
30
+ "**/coverage/**",
31
+ "**/.git/**",
32
+ "**/.vite/**",
33
+ "**/*.d.ts",
34
+ "**/*.{test,spec}.{ts,tsx,js,jsx}",
35
+ "**/*.{fixture,mock}.{ts,tsx,js,jsx}",
36
+ ];
37
+ export function linkdeskPluginLintConfig(options = {}) {
38
+ const files = options.files ?? ["**/*.{ts,tsx,js,jsx}"];
39
+ const tsconfig = options.tsconfig ?? "./tsconfig.json";
40
+ return [
41
+ { ignores: [...BASE_IGNORES, ...(options.ignore ?? [])] },
42
+ {
43
+ files,
44
+ languageOptions: {
45
+ parser: tsparser,
46
+ parserOptions: {
47
+ ecmaVersion: "latest",
48
+ sourceType: "module",
49
+ ecmaFeatures: { jsx: true },
50
+ },
51
+ },
52
+ // 脚本伪 id(linkdesk/no-hardcoded-font-size / no-nonstandard-spacing)不是 eslint rule——
53
+ // 关掉 unused-disable 报告,eslint 不报"未找到规则",靠 check 脚本自己认这些注释
54
+ linterOptions: { reportUnusedDisableDirectives: "off" },
55
+ // 各插件包的 configs 类型与 eslint 9 的 Plugin.configs 联合类型跨包漂移(tseslint 8 / react-hooks 7 /
56
+ // import-x 4 各自定义 configs),运行时语义兼容——统一按 eslint Plugin 收窄(eslint-config-* 生态同法)
57
+ plugins: {
58
+ "@typescript-eslint": tseslint,
59
+ linkdesk: { rules: linkdeskRuleMap }, // kebab 键 = eslint 按原样查(无 camel 转换)
60
+ "react-hooks": reactHooks,
61
+ "import-x": importX,
62
+ },
63
+ settings: {
64
+ "import-x/resolver": {
65
+ typescript: { alwaysTryTypes: true, project: tsconfig },
66
+ },
67
+ },
68
+ rules: {
69
+ // ═══ 07 §六 · React 通用陷阱 6 条(react-hooks 官方 2 + 移植 4)═══
70
+ "react-hooks/rules-of-hooks": "warn",
71
+ "react-hooks/exhaustive-deps": "warn",
72
+ "linkdesk/no-async-init-guard-only": "warn",
73
+ "linkdesk/no-effect-callback-without-active-guard": "warn",
74
+ "linkdesk/no-dynamic-import-in-effect-cleanup": "warn",
75
+ "linkdesk/no-ref-current-in-jsx": "warn",
76
+ // ═══ 07 §六 · 视觉统一 5 条(eslint 腿;css + rgb/hsl 腿 = lint.ts 三 check)═══
77
+ "linkdesk/no-hardcoded-zh": "warn", // ts/tsx UI 文案中文字面量——推荐 t()
78
+ "linkdesk/no-hardcoded-hex": "warn", // ts/tsx hex(同 disable id = 强化版 css 腿,见 css-hardcode.ts)
79
+ "linkdesk/no-hardcoded-radius": "warn", // border-radius 裸 px——推荐 var(--radius-*)/var(--surface-radius)
80
+ "import-x/no-unresolved": "warn", // 模块路径拼错
81
+ // ═══ 07 §六 · 审美 4 条(eslint 腿;spacing 腿在 lint.ts;jscpd 文档引导可选)═══
82
+ "linkdesk/no-quickpick-render-item": "warn",
83
+ "@typescript-eslint/no-explicit-any": "warn",
84
+ },
85
+ },
86
+ ];
87
+ }
88
+ //# sourceMappingURL=preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.js","sourceRoot":"","sources":["../../src/eslint/preset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,QAAQ,MAAM,kCAAkC,CAAC;AACxD,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,UAAU,MAAM,2BAA2B,CAAC;AACnD,OAAO,OAAO,MAAM,wBAAwB,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAa7C,mFAAmF;AACnF,MAAM,YAAY,GAAG;IACnB,oBAAoB;IACpB,YAAY;IACZ,qBAAqB;IACrB,WAAW;IACX,gBAAgB;IAChB,YAAY;IACZ,aAAa;IACb,WAAW;IACX,kCAAkC;IAClC,qCAAqC;CACtC,CAAC;AAEF,MAAM,UAAU,wBAAwB,CAAC,UAA6B,EAAE;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,OAAO;QACL,EAAE,OAAO,EAAE,CAAC,GAAG,YAAY,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,EAAE;QACzD;YACE,KAAK;YACL,eAAe,EAAE;gBACf,MAAM,EAAE,QAAQ;gBAChB,aAAa,EAAE;oBACb,WAAW,EAAE,QAAQ;oBACrB,UAAU,EAAE,QAAQ;oBACpB,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE;iBAC5B;aACF;YACD,mFAAmF;YACnF,0DAA0D;YAC1D,aAAa,EAAE,EAAE,6BAA6B,EAAE,KAAK,EAAE;YACvD,oFAAoF;YACpF,+EAA+E;YAC/E,OAAO,EAAE;gBACP,oBAAoB,EAAE,QAAkC;gBACxD,QAAQ,EAAE,EAAE,KAAK,EAAE,eAAe,EAA4B,EAAE,oCAAoC;gBACpG,aAAa,EAAE,UAAoC;gBACnD,UAAU,EAAE,OAAiC;aAC9C;YACD,QAAQ,EAAE;gBACR,mBAAmB,EAAE;oBACnB,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE;iBACxD;aACF;YACD,KAAK,EAAE;gBACL,yDAAyD;gBACzD,4BAA4B,EAAE,MAAM;gBACpC,6BAA6B,EAAE,MAAM;gBACrC,mCAAmC,EAAE,MAAM;gBAC3C,kDAAkD,EAAE,MAAM;gBAC1D,8CAA8C,EAAE,MAAM;gBACtD,gCAAgC,EAAE,MAAM;gBACxC,sEAAsE;gBACtE,0BAA0B,EAAE,MAAM,EAAE,4BAA4B;gBAChE,2BAA2B,EAAE,MAAM,EAAE,yDAAyD;gBAC9F,8BAA8B,EAAE,MAAM,EAAE,+DAA+D;gBACvG,wBAAwB,EAAE,MAAM,EAAE,SAAS;gBAC3C,kEAAkE;gBAClE,mCAAmC,EAAE,MAAM;gBAC3C,oCAAoC,EAAE,MAAM;aAC7C;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @linkdesk/plugin-sdk 门禁自定义规则(E6#54d)——从壳 eslint-local-rules.js 移植的作者面向子集。
3
+ *
4
+ * 🔴 双源注记(与壳 eslint-local-rules.js 同 id / 同语义,防作者文档与壳文档二义):
5
+ * 壳规则管壳代码(src/ + 仓库内 plugins/),本文件规则管第三方插件工程(仓库外)——两个
6
+ * 工程物理隔离,发布态 plugin-sdk 不能 import 仓库源码,故是"移植副本"而非"共享单源"。
7
+ * 与壳语义同名的规则沿用 `linkdesk/` 命名空间 + 同名(no-hardcoded-hex / no-async-init-guard-only /
8
+ * no-effect-callback-without-active-guard / no-dynamic-import-in-effect-cleanup / no-ref-current-in-jsx /
9
+ * no-quickpick-render-item)——disable 注释格式两套配置一致;zh 规则例外:SDK 用设计文档 07 §六
10
+ * id `linkdesk/no-hardcoded-zh`(壳遗留名 no-hardcoded-chinese,第三方作者不写壳代码故不冲突),
11
+ * no-hardcoded-radius 为 SDK 新写(壳无对应)。改消息文本 / 规则 id 时同步核对壳 eslint-local-rules.js。
12
+ *
13
+ * 三档梯度定位(07 设计 §六):这些规则全部 WARN 级(永不 fail build/上传),报错自解释
14
+ * (错在哪 + 换成什么 + 为什么),知情绕行 = 标准 eslint-disable 注释(非发明新语法)。
15
+ *
16
+ * 规则命名空间 = `linkdesk`(与壳一致),由 src/eslint/preset.ts 注册进 flat config。
17
+ */
18
+ import type { Rule } from "eslint";
19
+ export declare const noAsyncInitGuardOnly: Rule.RuleModule;
20
+ export declare const noEffectCallbackWithoutActiveGuard: Rule.RuleModule;
21
+ export declare const noDynamicImportInEffectCleanup: Rule.RuleModule;
22
+ export declare const noRefCurrentInJsx: Rule.RuleModule;
23
+ export declare const noHardcodedZh: Rule.RuleModule;
24
+ export declare const noHardcodedHex: Rule.RuleModule;
25
+ export declare const noHardcodedRadius: Rule.RuleModule;
26
+ export declare const noQuickpickRenderItem: Rule.RuleModule;
27
+ export declare const linkdeskRuleMap: Record<string, Rule.RuleModule>;
28
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/eslint/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAMnC,eAAO,MAAM,oBAAoB,EAAE,IAAI,CAAC,UAuDvC,CAAC;AAMF,eAAO,MAAM,kCAAkC,EAAE,IAAI,CAAC,UA0CrD,CAAC;AAgCF,eAAO,MAAM,8BAA8B,EAAE,IAAI,CAAC,UAuCjD,CAAC;AAMF,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,UAsBpC,CAAC;AA4CF,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,UAsChC,CAAC;AAWF,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,UAmCjC,CAAC;AAUF,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,UA4CpC,CAAC;AAKF,eAAO,MAAM,qBAAqB,EAAE,IAAI,CAAC,UA2BxC,CAAC;AAOF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAS3D,CAAC"}