frontend-guardian-core 2.6.0

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 (152) hide show
  1. package/LICENSE +21 -0
  2. package/bin/fg-core.js +1238 -0
  3. package/bin/watch-mode.js +123 -0
  4. package/dist/engine/cache.d.ts +68 -0
  5. package/dist/engine/cache.d.ts.map +1 -0
  6. package/dist/engine/cache.js +164 -0
  7. package/dist/engine/cache.js.map +1 -0
  8. package/dist/engine/rule-engine.d.ts +135 -0
  9. package/dist/engine/rule-engine.d.ts.map +1 -0
  10. package/dist/engine/rule-engine.js +716 -0
  11. package/dist/engine/rule-engine.js.map +1 -0
  12. package/dist/formatters/github-annotation.d.ts +36 -0
  13. package/dist/formatters/github-annotation.d.ts.map +1 -0
  14. package/dist/formatters/github-annotation.js +122 -0
  15. package/dist/formatters/github-annotation.js.map +1 -0
  16. package/dist/formatters/pr-comment.d.ts +43 -0
  17. package/dist/formatters/pr-comment.d.ts.map +1 -0
  18. package/dist/formatters/pr-comment.js +171 -0
  19. package/dist/formatters/pr-comment.js.map +1 -0
  20. package/dist/formatters/sarif.d.ts +104 -0
  21. package/dist/formatters/sarif.d.ts.map +1 -0
  22. package/dist/formatters/sarif.js +130 -0
  23. package/dist/formatters/sarif.js.map +1 -0
  24. package/dist/index.d.ts +46 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +108 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/integrations/base.d.ts +44 -0
  29. package/dist/integrations/base.d.ts.map +1 -0
  30. package/dist/integrations/base.js +104 -0
  31. package/dist/integrations/base.js.map +1 -0
  32. package/dist/integrations/eslint.d.ts +8 -0
  33. package/dist/integrations/eslint.d.ts.map +1 -0
  34. package/dist/integrations/eslint.js +67 -0
  35. package/dist/integrations/eslint.js.map +1 -0
  36. package/dist/integrations/formatter.d.ts +35 -0
  37. package/dist/integrations/formatter.d.ts.map +1 -0
  38. package/dist/integrations/formatter.js +182 -0
  39. package/dist/integrations/formatter.js.map +1 -0
  40. package/dist/integrations/index.d.ts +17 -0
  41. package/dist/integrations/index.d.ts.map +1 -0
  42. package/dist/integrations/index.js +25 -0
  43. package/dist/integrations/index.js.map +1 -0
  44. package/dist/integrations/stylelint.d.ts +8 -0
  45. package/dist/integrations/stylelint.d.ts.map +1 -0
  46. package/dist/integrations/stylelint.js +59 -0
  47. package/dist/integrations/stylelint.js.map +1 -0
  48. package/dist/integrations/typescript.d.ts +8 -0
  49. package/dist/integrations/typescript.d.ts.map +1 -0
  50. package/dist/integrations/typescript.js +92 -0
  51. package/dist/integrations/typescript.js.map +1 -0
  52. package/dist/rules/registry.d.ts +83 -0
  53. package/dist/rules/registry.d.ts.map +1 -0
  54. package/dist/rules/registry.js +205 -0
  55. package/dist/rules/registry.js.map +1 -0
  56. package/dist/scanners/a11y-scanner.d.ts +14 -0
  57. package/dist/scanners/a11y-scanner.d.ts.map +1 -0
  58. package/dist/scanners/a11y-scanner.js +781 -0
  59. package/dist/scanners/a11y-scanner.js.map +1 -0
  60. package/dist/scanners/component-scanner.d.ts +12 -0
  61. package/dist/scanners/component-scanner.d.ts.map +1 -0
  62. package/dist/scanners/component-scanner.js +304 -0
  63. package/dist/scanners/component-scanner.js.map +1 -0
  64. package/dist/scanners/cross-file-scanner.d.ts +18 -0
  65. package/dist/scanners/cross-file-scanner.d.ts.map +1 -0
  66. package/dist/scanners/cross-file-scanner.js +684 -0
  67. package/dist/scanners/cross-file-scanner.js.map +1 -0
  68. package/dist/scanners/hooks-scanner.d.ts +15 -0
  69. package/dist/scanners/hooks-scanner.d.ts.map +1 -0
  70. package/dist/scanners/hooks-scanner.js +670 -0
  71. package/dist/scanners/hooks-scanner.js.map +1 -0
  72. package/dist/scanners/i18n-scanner.d.ts +13 -0
  73. package/dist/scanners/i18n-scanner.d.ts.map +1 -0
  74. package/dist/scanners/i18n-scanner.js +535 -0
  75. package/dist/scanners/i18n-scanner.js.map +1 -0
  76. package/dist/scanners/naming-scanner.d.ts +19 -0
  77. package/dist/scanners/naming-scanner.d.ts.map +1 -0
  78. package/dist/scanners/naming-scanner.js +746 -0
  79. package/dist/scanners/naming-scanner.js.map +1 -0
  80. package/dist/scanners/performance-scanner.d.ts +7 -0
  81. package/dist/scanners/performance-scanner.d.ts.map +1 -0
  82. package/dist/scanners/performance-scanner.js +402 -0
  83. package/dist/scanners/performance-scanner.js.map +1 -0
  84. package/dist/scanners/platform-scanner.d.ts +15 -0
  85. package/dist/scanners/platform-scanner.d.ts.map +1 -0
  86. package/dist/scanners/platform-scanner.js +320 -0
  87. package/dist/scanners/platform-scanner.js.map +1 -0
  88. package/dist/scanners/security-scanner.d.ts +7 -0
  89. package/dist/scanners/security-scanner.d.ts.map +1 -0
  90. package/dist/scanners/security-scanner.js +349 -0
  91. package/dist/scanners/security-scanner.js.map +1 -0
  92. package/dist/scanners/svelte-scanner.d.ts +14 -0
  93. package/dist/scanners/svelte-scanner.d.ts.map +1 -0
  94. package/dist/scanners/svelte-scanner.js +228 -0
  95. package/dist/scanners/svelte-scanner.js.map +1 -0
  96. package/dist/types.d.ts +343 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +6 -0
  99. package/dist/types.js.map +1 -0
  100. package/dist/utils/ast-parser.d.ts +21 -0
  101. package/dist/utils/ast-parser.d.ts.map +1 -0
  102. package/dist/utils/ast-parser.js +119 -0
  103. package/dist/utils/ast-parser.js.map +1 -0
  104. package/dist/utils/baseline.d.ts +89 -0
  105. package/dist/utils/baseline.d.ts.map +1 -0
  106. package/dist/utils/baseline.js +156 -0
  107. package/dist/utils/baseline.js.map +1 -0
  108. package/dist/utils/ci-generator.d.ts +34 -0
  109. package/dist/utils/ci-generator.d.ts.map +1 -0
  110. package/dist/utils/ci-generator.js +194 -0
  111. package/dist/utils/ci-generator.js.map +1 -0
  112. package/dist/utils/common.d.ts +8 -0
  113. package/dist/utils/common.d.ts.map +1 -0
  114. package/dist/utils/common.js +38 -0
  115. package/dist/utils/common.js.map +1 -0
  116. package/dist/utils/concurrent.d.ts +16 -0
  117. package/dist/utils/concurrent.d.ts.map +1 -0
  118. package/dist/utils/concurrent.js +49 -0
  119. package/dist/utils/concurrent.js.map +1 -0
  120. package/dist/utils/config-loader.d.ts +8 -0
  121. package/dist/utils/config-loader.d.ts.map +1 -0
  122. package/dist/utils/config-loader.js +154 -0
  123. package/dist/utils/config-loader.js.map +1 -0
  124. package/dist/utils/fix-bot.d.ts +36 -0
  125. package/dist/utils/fix-bot.d.ts.map +1 -0
  126. package/dist/utils/fix-bot.js +274 -0
  127. package/dist/utils/fix-bot.js.map +1 -0
  128. package/dist/utils/git-hooks.d.ts +55 -0
  129. package/dist/utils/git-hooks.d.ts.map +1 -0
  130. package/dist/utils/git-hooks.js +318 -0
  131. package/dist/utils/git-hooks.js.map +1 -0
  132. package/dist/utils/history-report.d.ts +72 -0
  133. package/dist/utils/history-report.d.ts.map +1 -0
  134. package/dist/utils/history-report.js +144 -0
  135. package/dist/utils/history-report.js.map +1 -0
  136. package/dist/utils/init-config.d.ts +23 -0
  137. package/dist/utils/init-config.d.ts.map +1 -0
  138. package/dist/utils/init-config.js +146 -0
  139. package/dist/utils/init-config.js.map +1 -0
  140. package/dist/utils/pr-publisher.d.ts +64 -0
  141. package/dist/utils/pr-publisher.d.ts.map +1 -0
  142. package/dist/utils/pr-publisher.js +265 -0
  143. package/dist/utils/pr-publisher.js.map +1 -0
  144. package/dist/utils/project-detector.d.ts +20 -0
  145. package/dist/utils/project-detector.d.ts.map +1 -0
  146. package/dist/utils/project-detector.js +342 -0
  147. package/dist/utils/project-detector.js.map +1 -0
  148. package/dist/utils/report-uploader.d.ts +35 -0
  149. package/dist/utils/report-uploader.d.ts.map +1 -0
  150. package/dist/utils/report-uploader.js +106 -0
  151. package/dist/utils/report-uploader.js.map +1 -0
  152. package/package.json +78 -0
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Watch Mode — 文件变更自动增量扫描
4
+ *
5
+ * Usage: fg-core <project-dir> --watch [--module <name>]
6
+ */
7
+
8
+ import { watch } from "node:fs";
9
+ import { statSync, existsSync } from "node:fs";
10
+ import { resolve, relative } from "node:path";
11
+ import pc from "picocolors";
12
+
13
+ /**
14
+ * 启动 watch 模式
15
+ * @param {Object} options - CLI 选项
16
+ * @param {Function} scanFn - 扫描函数 (options, cacheInstance) => Promise<void>
17
+ * @param {Object} cacheInstance - SmartCache 实例(可选,用于复用缓存)
18
+ */
19
+ export async function runWatchMode(options, scanFn, cacheInstance) {
20
+ const projectDir = options.projectDir;
21
+ const includeExts = new Set([".js", ".ts", ".jsx", ".tsx", ".vue", ".svelte", ".css", ".scss", ".less"]);
22
+
23
+ console.log(pc.cyan("👀 Watch 模式已启动"));
24
+ console.log(pc.gray(` 项目: ${projectDir}`));
25
+ console.log(pc.gray(` 模块: ${options.module}`));
26
+ if (cacheInstance && options.cache !== false) {
27
+ console.log(pc.gray(" 缓存: 已启用(Watch 模式复用)"));
28
+ }
29
+ console.log(pc.gray(" 按 Ctrl+C 退出\n"));
30
+
31
+ // 防抖:200ms 内多次变更只扫描一次
32
+ let debounceTimer = null;
33
+ const changedFiles = new Set();
34
+
35
+ // 首次扫描(复用 cacheInstance)
36
+ await scanFn({ ...options, watch: false }, cacheInstance);
37
+ console.log(pc.gray("\n⏳ 等待文件变更...\n"));
38
+
39
+ function handleChange(filePath) {
40
+ const ext = filePath.slice(filePath.lastIndexOf("."));
41
+ if (!includeExts.has(ext)) return;
42
+ if (filePath.includes("node_modules")) return;
43
+ if (filePath.includes(".git")) return;
44
+
45
+ changedFiles.add(filePath);
46
+
47
+ if (debounceTimer) {
48
+ clearTimeout(debounceTimer);
49
+ }
50
+
51
+ debounceTimer = setTimeout(async () => {
52
+ const files = Array.from(changedFiles);
53
+ changedFiles.clear();
54
+
55
+ console.clear();
56
+ console.log(pc.cyan(`📝 检测到 ${files.length} 个文件变更`));
57
+ for (const f of files) {
58
+ console.log(pc.gray(` - ${relative(projectDir, f)}`));
59
+ }
60
+ console.log("");
61
+
62
+ const watchOptions = {
63
+ ...options,
64
+ files,
65
+ watch: false,
66
+ };
67
+
68
+ try {
69
+ await scanFn(watchOptions, cacheInstance);
70
+ } catch (err) {
71
+ console.error(pc.red("扫描失败:"), err.message || err);
72
+ }
73
+
74
+ console.log(pc.gray("\n⏳ 等待文件变更...\n"));
75
+ }, 300);
76
+ }
77
+
78
+ // 递归监听 src 目录和配置文件
79
+ const watchDirs = [resolve(projectDir, "src")];
80
+ if (!existsSync(watchDirs[0])) {
81
+ watchDirs[0] = projectDir;
82
+ }
83
+
84
+ const watchers = [];
85
+
86
+ function addWatcher(dir) {
87
+ try {
88
+ const watcher = watch(dir, { recursive: true }, (eventType, filename) => {
89
+ if (!filename) return;
90
+ const fullPath = resolve(dir, filename);
91
+ if (!existsSync(fullPath)) return;
92
+ try {
93
+ const stat = statSync(fullPath);
94
+ if (stat.isDirectory()) return;
95
+ } catch {
96
+ return;
97
+ }
98
+ handleChange(fullPath);
99
+ });
100
+ watchers.push(watcher);
101
+ } catch {
102
+ // 某些环境不支持递归 watch
103
+ }
104
+ }
105
+
106
+ for (const dir of watchDirs) {
107
+ if (existsSync(dir)) {
108
+ addWatcher(dir);
109
+ }
110
+ }
111
+
112
+ // 保持进程运行
113
+ process.on("SIGINT", () => {
114
+ console.log(pc.gray("\n👋 Watch 模式已停止"));
115
+ for (const w of watchers) {
116
+ w.close();
117
+ }
118
+ process.exit(0);
119
+ });
120
+
121
+ // 永不 resolve,保持运行
122
+ return new Promise(() => {});
123
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * SmartCache — 智能增量扫描缓存引擎
3
+ *
4
+ * 设计目标:
5
+ * 1. 基于文件内容 SHA-256 哈希,只扫描变更文件
6
+ * 2. 缓存持久化到 .frontend-guardian/cache.json
7
+ * 3. 自动过期策略(默认 7 天)
8
+ * 4. 兼容 --staged / --diff 增量模式
9
+ */
10
+ import type { Issue } from "../types.js";
11
+ export interface CacheEntry {
12
+ /** 文件内容 SHA-256 */
13
+ hash: string;
14
+ /** 扫描结果 */
15
+ issues: Issue[];
16
+ /** 缓存时间戳 */
17
+ timestamp: number;
18
+ /** 规则版本(规则变更时缓存失效) */
19
+ ruleVersion: string;
20
+ }
21
+ export interface CacheManifest {
22
+ /** 引擎版本 */
23
+ version: string;
24
+ /** 项目目录 */
25
+ projectDir: string;
26
+ /** 文件到缓存条目的映射 */
27
+ entries: Record<string, CacheEntry>;
28
+ /** 上次全量扫描时间 */
29
+ lastFullScan: number;
30
+ }
31
+ export declare class SmartCache {
32
+ private manifest;
33
+ private cacheDir;
34
+ private cacheFile;
35
+ private ttl;
36
+ /** v2.1.0: 内存级 AST 缓存(无需持久化,进程内复用) */
37
+ private astCache;
38
+ constructor(projectDir: string, ttl?: number);
39
+ /** 计算文件内容哈希 */
40
+ static computeHash(content: string): string;
41
+ /** 检查文件是否已缓存且未过期 */
42
+ isCached(filePath: string, content: string): boolean;
43
+ /** 从缓存获取文件扫描结果 */
44
+ get(filePath: string): Issue[] | undefined;
45
+ /** 缓存文件扫描结果 */
46
+ set(filePath: string, content: string, issues: Issue[]): void;
47
+ /** 删除缓存条目 */
48
+ invalidate(filePath: string): void;
49
+ /** 批量使缓存失效(glob 模式) */
50
+ invalidatePattern(pattern: string): void;
51
+ /** 保存缓存到磁盘 */
52
+ save(): void;
53
+ /** 获取缓存统计 */
54
+ getStats(): {
55
+ total: number;
56
+ valid: number;
57
+ expired: number;
58
+ };
59
+ /** 获取缓存的 AST(内存级,不持久化) */
60
+ getAst(filePath: string, content: string): unknown | undefined;
61
+ /** 缓存 AST 解析结果 */
62
+ setAst(filePath: string, content: string, ast: unknown): void;
63
+ /** 清理过期缓存 */
64
+ gc(): number;
65
+ /** 加载缓存 manifest */
66
+ private loadManifest;
67
+ }
68
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/engine/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,UAAU;IACvB,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,YAAY;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC1B,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACpC,eAAe;IACf,YAAY,EAAE,MAAM,CAAC;CACxB;AAOD,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,GAAG,CAAS;IACpB,sCAAsC;IACtC,OAAO,CAAC,QAAQ,CAAqD;gBAEzD,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAoB;IAOzD,eAAe;IACf,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI3C,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAkBpD,kBAAkB;IAClB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,SAAS;IAK1C,eAAe;IACf,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAS7D,aAAa;IACb,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIlC,uBAAuB;IACvB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IASxC,cAAc;IACd,IAAI,IAAI,IAAI;IAWZ,aAAa;IACb,QAAQ,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAkB7D,0BAA0B;IAC1B,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAW9D,kBAAkB;IAClB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI;IAO7D,aAAa;IACb,EAAE,IAAI,MAAM;IAcZ,oBAAoB;IACpB,OAAO,CAAC,YAAY;CAoBvB"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * SmartCache — 智能增量扫描缓存引擎
4
+ *
5
+ * 设计目标:
6
+ * 1. 基于文件内容 SHA-256 哈希,只扫描变更文件
7
+ * 2. 缓存持久化到 .frontend-guardian/cache.json
8
+ * 3. 自动过期策略(默认 7 天)
9
+ * 4. 兼容 --staged / --diff 增量模式
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SmartCache = void 0;
13
+ const node_crypto_1 = require("node:crypto");
14
+ const node_fs_1 = require("node:fs");
15
+ const node_path_1 = require("node:path");
16
+ /** 缓存默认存活时间(7 天) */
17
+ const DEFAULT_TTL = 7 * 24 * 60 * 60 * 1000;
18
+ /** 引擎版本,规则变更时递增使缓存失效 */
19
+ const ENGINE_VERSION = "2.0.0";
20
+ class SmartCache {
21
+ manifest;
22
+ cacheDir;
23
+ cacheFile;
24
+ ttl;
25
+ /** v2.1.0: 内存级 AST 缓存(无需持久化,进程内复用) */
26
+ astCache = new Map();
27
+ constructor(projectDir, ttl = DEFAULT_TTL) {
28
+ this.cacheDir = (0, node_path_1.resolve)(projectDir, ".frontend-guardian");
29
+ this.cacheFile = (0, node_path_1.resolve)(this.cacheDir, "cache.json");
30
+ this.ttl = ttl;
31
+ this.manifest = this.loadManifest();
32
+ }
33
+ /** 计算文件内容哈希 */
34
+ static computeHash(content) {
35
+ return (0, node_crypto_1.createHash)("sha256").update(content).digest("hex").slice(0, 16);
36
+ }
37
+ /** 检查文件是否已缓存且未过期 */
38
+ isCached(filePath, content) {
39
+ const entry = this.manifest.entries[filePath];
40
+ if (!entry)
41
+ return false;
42
+ // 内容变更
43
+ const hash = SmartCache.computeHash(content);
44
+ if (entry.hash !== hash)
45
+ return false;
46
+ // 规则版本变更
47
+ if (entry.ruleVersion !== ENGINE_VERSION)
48
+ return false;
49
+ // 缓存过期
50
+ const now = Date.now();
51
+ if (now - entry.timestamp > this.ttl)
52
+ return false;
53
+ return true;
54
+ }
55
+ /** 从缓存获取文件扫描结果 */
56
+ get(filePath) {
57
+ const entry = this.manifest.entries[filePath];
58
+ return entry?.issues;
59
+ }
60
+ /** 缓存文件扫描结果 */
61
+ set(filePath, content, issues) {
62
+ this.manifest.entries[filePath] = {
63
+ hash: SmartCache.computeHash(content),
64
+ issues,
65
+ timestamp: Date.now(),
66
+ ruleVersion: ENGINE_VERSION,
67
+ };
68
+ }
69
+ /** 删除缓存条目 */
70
+ invalidate(filePath) {
71
+ delete this.manifest.entries[filePath];
72
+ }
73
+ /** 批量使缓存失效(glob 模式) */
74
+ invalidatePattern(pattern) {
75
+ const regex = new RegExp(pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"));
76
+ for (const key of Object.keys(this.manifest.entries)) {
77
+ if (regex.test(key)) {
78
+ delete this.manifest.entries[key];
79
+ }
80
+ }
81
+ }
82
+ /** 保存缓存到磁盘 */
83
+ save() {
84
+ try {
85
+ if (!(0, node_fs_1.existsSync)(this.cacheDir)) {
86
+ (0, node_fs_1.mkdirSync)(this.cacheDir, { recursive: true });
87
+ }
88
+ (0, node_fs_1.writeFileSync)(this.cacheFile, JSON.stringify(this.manifest, null, 2), "utf-8");
89
+ }
90
+ catch {
91
+ // 缓存写入失败静默处理
92
+ }
93
+ }
94
+ /** 获取缓存统计 */
95
+ getStats() {
96
+ const now = Date.now();
97
+ let valid = 0;
98
+ let expired = 0;
99
+ for (const entry of Object.values(this.manifest.entries)) {
100
+ if (now - entry.timestamp > this.ttl || entry.ruleVersion !== ENGINE_VERSION) {
101
+ expired++;
102
+ }
103
+ else {
104
+ valid++;
105
+ }
106
+ }
107
+ return { total: Object.keys(this.manifest.entries).length, valid, expired };
108
+ }
109
+ // ── v2.1.0: AST 内存缓存 ──────────────────────────────────────────────
110
+ /** 获取缓存的 AST(内存级,不持久化) */
111
+ getAst(filePath, content) {
112
+ const cached = this.astCache.get(filePath);
113
+ if (!cached)
114
+ return undefined;
115
+ const hash = SmartCache.computeHash(content);
116
+ if (cached.hash !== hash) {
117
+ this.astCache.delete(filePath);
118
+ return undefined;
119
+ }
120
+ return cached.ast;
121
+ }
122
+ /** 缓存 AST 解析结果 */
123
+ setAst(filePath, content, ast) {
124
+ this.astCache.set(filePath, {
125
+ hash: SmartCache.computeHash(content),
126
+ ast,
127
+ });
128
+ }
129
+ /** 清理过期缓存 */
130
+ gc() {
131
+ const now = Date.now();
132
+ let removed = 0;
133
+ for (const [key, entry] of Object.entries(this.manifest.entries)) {
134
+ if (now - entry.timestamp > this.ttl || entry.ruleVersion !== ENGINE_VERSION) {
135
+ delete this.manifest.entries[key];
136
+ removed++;
137
+ }
138
+ }
139
+ return removed;
140
+ }
141
+ /** 加载缓存 manifest */
142
+ loadManifest() {
143
+ try {
144
+ if ((0, node_fs_1.existsSync)(this.cacheFile)) {
145
+ const raw = (0, node_fs_1.readFileSync)(this.cacheFile, "utf-8");
146
+ const manifest = JSON.parse(raw);
147
+ if (manifest.version === ENGINE_VERSION && manifest.projectDir === this.cacheDir) {
148
+ return manifest;
149
+ }
150
+ }
151
+ }
152
+ catch {
153
+ // 缓存读取失败,返回空 manifest
154
+ }
155
+ return {
156
+ version: ENGINE_VERSION,
157
+ projectDir: this.cacheDir,
158
+ entries: {},
159
+ lastFullScan: 0,
160
+ };
161
+ }
162
+ }
163
+ exports.SmartCache = SmartCache;
164
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/engine/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * RuleEngine — 可插拔规则引擎核心
3
+ *
4
+ * 设计目标:
5
+ * 1. 支持注册/注销规则(插件化)
6
+ * 2. 按 severity 过滤
7
+ * 3. 按 framework/platform/componentLib 条件执行
8
+ * 4. 并行扫描多文件
9
+ * 5. 支持增量扫描(git diff)
10
+ */
11
+ import type { Rule, Issue, Severity, ScanResult, FixPreview } from "../types.js";
12
+ import type { ExternalTool, ExternalToolResult } from "../integrations/index.js";
13
+ import { SmartCache } from "./cache.js";
14
+ export interface EngineOptions {
15
+ /** 项目根目录 */
16
+ projectDir: string;
17
+ /** 最低 severity */
18
+ minSeverity?: Severity;
19
+ /** 仅检查这些文件 */
20
+ files?: string[];
21
+ /** 排除模式 */
22
+ exclude?: string[];
23
+ /** 并行度 */
24
+ concurrency?: number;
25
+ /** 配置文件路径 */
26
+ configFile?: string;
27
+ /** 仅扫描 git staged 文件 */
28
+ staged?: boolean;
29
+ /** git diff 范围,如 main...feature */
30
+ diffRange?: string;
31
+ /** 智能扫描范围:自动检测未提交/最近修改的文件 */
32
+ autoScope?: boolean;
33
+ /** 是否运行外部工具集成(ESLint / TypeScript / Stylelint) */
34
+ external?: boolean;
35
+ /** 是否启用智能缓存 */
36
+ cache?: boolean;
37
+ /** 缓存 TTL(毫秒,默认 7 天) */
38
+ cacheTtl?: number;
39
+ /** 修复预览模式(只展示不写入) */
40
+ dryRun?: boolean;
41
+ /** 交互式修复模式(逐条确认) */
42
+ interactive?: boolean;
43
+ /** 大文件跳过阈值(字节,默认 500KB = 512000) */
44
+ skipLargeFilesThreshold?: number;
45
+ /** v2.6.0: 外部传入的 SmartCache 实例(用于 Watch 模式复用缓存) */
46
+ cacheInstance?: SmartCache;
47
+ }
48
+ export declare class RuleEngine {
49
+ private registry;
50
+ private config;
51
+ private projectMeta;
52
+ private options;
53
+ private cache?;
54
+ private history;
55
+ constructor(options: EngineOptions);
56
+ /** ── Phase 3: 配置驱动规则加载 ── */
57
+ private loadConfigRules;
58
+ /** 注册规则 */
59
+ register(rule: Rule): this;
60
+ /** 批量注册 */
61
+ registerAll(rules: Rule[]): this;
62
+ /** 注销规则 */
63
+ unregister(ruleId: string): this;
64
+ /** 获取所有已注册规则(应用配置覆盖后) */
65
+ getRules(): Rule[];
66
+ /** 根据条件过滤规则 */
67
+ filterRules(options?: {
68
+ category?: string;
69
+ framework?: string;
70
+ platform?: string;
71
+ componentLib?: string;
72
+ }): Rule[];
73
+ /** 模块名到规则 category 的映射 */
74
+ private moduleToCategory;
75
+ /** 执行扫描 */
76
+ scan(module: string): Promise<ScanResult>;
77
+ /** 扫描单个文件(带智能缓存 + 大文件跳过) */
78
+ private scanFile;
79
+ /** 获取扫描文件列表 */
80
+ private getScanFiles;
81
+ /** 通过 git 获取变更文件列表 */
82
+ private getDiffFiles;
83
+ /** 智能推断扫描范围:未提交修改 → 最近 5 次提交 → 全量 */
84
+ private getAutoScopeFiles;
85
+ /** 创建 RuleUtils */
86
+ private createUtils;
87
+ /** 计算每行起始偏移 */
88
+ private computeLineOffsets;
89
+ /**
90
+ * 应用所有可修复的问题
91
+ * @param issues 包含 fix 字段的 Issue 列表
92
+ * @returns 修复统计(dryRun 模式下 filesModified 为空,fixedCount 为预览数量)
93
+ */
94
+ applyFixes(issues: Issue[]): {
95
+ fixedCount: number;
96
+ filesModified: string[];
97
+ errors: string[];
98
+ previews?: FixPreview[];
99
+ skippedByUser?: number;
100
+ };
101
+ /**
102
+ * v2.4.0: 交互式修复 — 向用户展示 diff 并询问是否应用
103
+ * 同步阻塞式输入(基于 readline),适用于 CLI 场景
104
+ */
105
+ private promptForFix;
106
+ /** 同步读取一行输入 */
107
+ private readSyncLine;
108
+ /** 对单文件应用单个修复 */
109
+ private applySingleFix;
110
+ /** 生成 diff 预览(dry-run 模式) */
111
+ private makeDiffPreview;
112
+ /** 清理过期缓存 */
113
+ gcCache(): number;
114
+ /**
115
+ * 格式化被扫描项目的代码
116
+ * 自动检测 Biome / Prettier,使用项目已有配置或生成默认配置
117
+ * @param files 指定文件列表(undefined 则格式化全部)
118
+ */
119
+ format(files?: string[]): import("../integrations/formatter.js").FormatResult;
120
+ /**
121
+ * 将相似 Issue 聚类为聚合 Issue
122
+ * 按 (file, ruleId) 分组,同一文件同一规则的多个 Issue 合并为一个
123
+ */
124
+ clusterIssues(issues: Issue[]): Issue[];
125
+ /**
126
+ * 运行外部工具集成检查
127
+ * 自动检测项目中可用的工具(ESLint / TypeScript / Stylelint)并执行
128
+ */
129
+ runExternal(tools?: ExternalTool[]): ExternalToolResult[];
130
+ /** 获取默认的外部工具列表 */
131
+ private getDefaultExternalTools;
132
+ }
133
+ /** 创建默认引擎实例 */
134
+ export declare function createEngine(options: EngineOptions): RuleEngine;
135
+ //# sourceMappingURL=rule-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-engine.d.ts","sourceRoot":"","sources":["../../src/engine/rule-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EACR,IAAI,EAEJ,KAAK,EACL,QAAQ,EACR,UAAU,EAMV,UAAU,EACb,MAAM,YAAY,CAAC;AASpB,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEhF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKxC,MAAM,WAAW,aAAa;IAC1B,YAAY;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,cAAc;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW;IACX,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oCAAoC;IACpC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,mDAAmD;IACnD,aAAa,CAAC,EAAE,UAAU,CAAC;CAC9B;AAED,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,KAAK,CAAC,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAgB;gBAEnB,OAAO,EAAE,aAAa;IAkBlC,8BAA8B;IAC9B,OAAO,CAAC,eAAe;IAmBvB,WAAW;IACX,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAK1B,WAAW;IACX,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;IAKhC,WAAW;IACX,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAKhC,yBAAyB;IACzB,QAAQ,IAAI,IAAI,EAAE;IAIlB,eAAe;IACf,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,EAAE;IAIlH,0BAA0B;IAC1B,OAAO,CAAC,gBAAgB;IASxB,WAAW;IACL,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAiG/C,4BAA4B;YACd,QAAQ;IAkEtB,eAAe;YACD,YAAY;IA6C1B,sBAAsB;IACtB,OAAO,CAAC,YAAY;IA2BpB,qCAAqC;IACrC,OAAO,CAAC,iBAAiB;IAiDzB,mBAAmB;IACnB,OAAO,CAAC,WAAW;IAwCnB,eAAe;IACf,OAAO,CAAC,kBAAkB;IAc1B;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;IA8F/I;;;OAGG;IACH,OAAO,CAAC,YAAY;IAmCpB,eAAe;IACf,OAAO,CAAC,YAAY;IAqBpB,iBAAiB;IACjB,OAAO,CAAC,cAAc;IAkCtB,6BAA6B;IAC7B,OAAO,CAAC,eAAe;IA+BvB,aAAa;IACb,OAAO,IAAI,MAAM;IAQjB;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,8BAA8B,EAAE,YAAY;IAQ7E;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;IA0CvC;;;OAGG;IACH,WAAW,CAAC,KAAK,CAAC,EAAE,YAAY,EAAE,GAAG,kBAAkB,EAAE;IAczD,kBAAkB;IAClB,OAAO,CAAC,uBAAuB;CAKlC;AAED,eAAe;AACf,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CAE/D"}