autosnippet 3.2.6 → 3.2.8

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 (65) hide show
  1. package/README.md +16 -1
  2. package/bin/cli.js +7 -0
  3. package/dashboard/dist/assets/index-D5jiDBQG.css +1 -0
  4. package/dashboard/dist/assets/{index-DfHY_3ln.js → index-e5OKj-Ni.js} +38 -38
  5. package/dashboard/dist/index.html +2 -2
  6. package/lib/cli/AiScanService.js +3 -3
  7. package/lib/core/AstAnalyzer.js +26 -4
  8. package/lib/core/analysis/CallEdgeResolver.js +402 -0
  9. package/lib/core/analysis/CallGraphAnalyzer.js +367 -0
  10. package/lib/core/analysis/CallSiteExtractor.js +629 -0
  11. package/lib/core/analysis/DataFlowInferrer.js +57 -0
  12. package/lib/core/analysis/ImportPathResolver.js +189 -0
  13. package/lib/core/analysis/ImportRecord.js +105 -0
  14. package/lib/core/analysis/SymbolTableBuilder.js +211 -0
  15. package/lib/core/ast/ProjectGraph.js +8 -0
  16. package/lib/core/ast/lang-dart.js +352 -5
  17. package/lib/core/ast/lang-go.js +212 -10
  18. package/lib/core/ast/lang-java.js +205 -1
  19. package/lib/core/ast/lang-kotlin.js +330 -1
  20. package/lib/core/ast/lang-python.js +31 -2
  21. package/lib/core/ast/lang-rust.js +284 -3
  22. package/lib/core/ast/lang-swift.js +180 -1
  23. package/lib/core/ast/lang-typescript.js +290 -1
  24. package/lib/external/mcp/McpServer.js +1 -0
  25. package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +21 -0
  26. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +5 -4
  27. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +2 -1
  28. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +70 -4
  29. package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +95 -1
  30. package/lib/external/mcp/handlers/bootstrap-external.js +9 -2
  31. package/lib/external/mcp/handlers/bootstrap-internal.js +17 -6
  32. package/lib/external/mcp/handlers/consolidated.js +9 -0
  33. package/lib/external/mcp/handlers/guard.js +3 -3
  34. package/lib/external/mcp/handlers/structure.js +62 -0
  35. package/lib/external/mcp/handlers/task.js +182 -10
  36. package/lib/external/mcp/handlers/wiki-external.js +66 -3
  37. package/lib/external/mcp/tools.js +36 -1
  38. package/lib/http/HttpServer.js +4 -0
  39. package/lib/http/routes/remote.js +1138 -0
  40. package/lib/http/routes/task.js +1 -0
  41. package/lib/infrastructure/database/migrations/003_add_remote_commands.js +27 -0
  42. package/lib/injection/ServiceContainer.js +6 -11
  43. package/lib/platform/ios/index.js +2 -2
  44. package/lib/platform/ios/spm/PackageSwiftParser.js +14 -3
  45. package/lib/platform/ios/spm/SpmDiscoverer.js +123 -17
  46. package/lib/platform/ios/spm/{SpmService.js → SpmHelper.js} +43 -675
  47. package/lib/platform/ios/xcode/XcodeWriteUtils.js +1 -1
  48. package/lib/service/chat/ChatAgent.js +1 -1
  49. package/lib/service/chat/ChatAgentPrompts.js +13 -1
  50. package/lib/service/chat/ExplorationTracker.js +52 -8
  51. package/lib/service/chat/HandoffProtocol.js +19 -1
  52. package/lib/service/chat/WorkingMemory.js +3 -1
  53. package/lib/service/chat/memory/ActiveContext.js +3 -1
  54. package/lib/service/chat/memory/SessionStore.js +4 -3
  55. package/lib/service/chat/tools/ast-graph.js +229 -32
  56. package/lib/service/chat/tools/index.js +6 -1
  57. package/lib/service/chat/tools/infrastructure.js +5 -0
  58. package/lib/service/cursor/CursorDeliveryPipeline.js +167 -1
  59. package/lib/service/knowledge/CodeEntityGraph.js +327 -2
  60. package/lib/service/knowledge/KnowledgeService.js +5 -1
  61. package/lib/service/module/ModuleService.js +9 -0
  62. package/lib/service/wiki/WikiGenerator.js +1 -1
  63. package/lib/shared/PathGuard.js +1 -1
  64. package/package.json +12 -1
  65. package/dashboard/dist/assets/index-BaGY7kJI.css +0 -1
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @module ImportPathResolver
3
+ * @description Phase 5: 将 import 路径解析为项目内文件路径
4
+ *
5
+ * 负责:
6
+ * - 相对路径 (./ ../) 解析
7
+ * - 文件扩展名补全 (.ts, .js, .py, ...)
8
+ * - index 文件约定 (./dir → ./dir/index.ts)
9
+ * - 外部依赖识别与过滤
10
+ * - tsconfig paths alias 支持 (@/xxx → src/xxx)
11
+ *
12
+ * 不负责:
13
+ * - webpack resolve alias (需额外配置)
14
+ * - Node.js exports map (需解析 package.json)
15
+ */
16
+
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+
20
+ export class ImportPathResolver {
21
+ /**
22
+ * @param {string} projectRoot — 项目根目录
23
+ * @param {string[]} allFiles — 项目内所有文件的相对路径
24
+ */
25
+ constructor(projectRoot, allFiles) {
26
+ this.projectRoot = projectRoot;
27
+ /** @type {Map<string, string>} normalizedPath → actualFilePath */
28
+ this.fileIndex = new Map();
29
+ /** @type {Array<{prefix: string, targets: string[]}>} tsconfig paths 映射 */
30
+ this.pathAliases = [];
31
+
32
+ // 构建文件索引
33
+ for (const f of allFiles) {
34
+ // 完整路径
35
+ this.fileIndex.set(f, f);
36
+
37
+ // 去扩展名 → 完整路径
38
+ const base = f.replace(/\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|m|dart)$/, '');
39
+ if (!this.fileIndex.has(base)) {
40
+ this.fileIndex.set(base, f);
41
+ }
42
+
43
+ // index 文件约定: src/utils/ → src/utils/index.ts
44
+ if (/\/index\.(ts|tsx|js|jsx|mjs|cjs)$/.test(f)) {
45
+ const dir = f.replace(/\/index\.(ts|tsx|js|jsx|mjs|cjs)$/, '');
46
+ if (!this.fileIndex.has(dir)) {
47
+ this.fileIndex.set(dir, f);
48
+ }
49
+ }
50
+
51
+ // Python __init__.py 约定: pkg/ → pkg/__init__.py
52
+ if (f.endsWith('/__init__.py')) {
53
+ const dir = f.replace(/\/__init__\.py$/, '');
54
+ if (!this.fileIndex.has(dir)) {
55
+ this.fileIndex.set(dir, f);
56
+ }
57
+ }
58
+ }
59
+
60
+ // 自动加载 tsconfig paths
61
+ this._loadTsconfigPaths(projectRoot);
62
+ }
63
+
64
+ /**
65
+ * 从 tsconfig.json 加载 paths alias 配置
66
+ * @param {string} projectRoot
67
+ * @private
68
+ */
69
+ _loadTsconfigPaths(projectRoot) {
70
+ const candidates = ['tsconfig.json', 'tsconfig.app.json', 'jsconfig.json'];
71
+ for (const name of candidates) {
72
+ try {
73
+ const configPath = path.join(projectRoot, name);
74
+ if (!fs.existsSync(configPath)) continue;
75
+ const raw = fs.readFileSync(configPath, 'utf-8');
76
+ // 简单的 JSON 解析 (去除注释)
77
+ const cleaned = raw.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
78
+ const config = JSON.parse(cleaned);
79
+ const compilerOptions = config.compilerOptions || {};
80
+ const baseUrl = compilerOptions.baseUrl || '.';
81
+ const paths = compilerOptions.paths;
82
+ if (!paths) continue;
83
+
84
+ for (const [aliasPattern, targetPatterns] of Object.entries(paths)) {
85
+ // "@/*" → ["src/*"]
86
+ // "~/*" → ["src/*"]
87
+ // "@components/*" → ["src/components/*"]
88
+ const prefix = aliasPattern.replace(/\/?\*$/, '');
89
+ const targets = (Array.isArray(targetPatterns) ? targetPatterns : [targetPatterns])
90
+ .map((t) => {
91
+ const target = String(t).replace(/\/?\*$/, '');
92
+ // 相对于 baseUrl 解析
93
+ return path.normalize(path.join(baseUrl, target));
94
+ });
95
+ if (prefix) {
96
+ this.pathAliases.push({ prefix, targets });
97
+ }
98
+ }
99
+
100
+ // 只加载第一个找到的配置文件
101
+ break;
102
+ } catch (_e) {
103
+ // 配置解析失败,静默跳过
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * 解析 import 路径到项目文件
110
+ *
111
+ * @param {string} importPath — 如 "./UserRepo" 或 "../shared/utils"
112
+ * @param {string} importerFile — 当前文件路径 (相对路径)
113
+ * @returns {string|null} — 解析后的文件路径 (相对) 或 null (外部依赖)
114
+ */
115
+ resolve(importPath, importerFile) {
116
+ const pathStr = String(importPath);
117
+
118
+ // 1. 跳过外部依赖 (先检查 alias,再判断外部)
119
+ // 相对路径始终尝试解析
120
+ if (pathStr.startsWith('.')) {
121
+ const importerDir = path.dirname(importerFile);
122
+ const resolved = path.normalize(path.join(importerDir, pathStr));
123
+ if (this.fileIndex.has(resolved)) return this.fileIndex.get(resolved);
124
+ return this.fileIndex.get(resolved) || null;
125
+ }
126
+
127
+ // 2. tsconfig paths alias 解析
128
+ const aliasResolved = this._resolveAlias(pathStr);
129
+ if (aliasResolved) return aliasResolved;
130
+
131
+ // 3. 如果不是 alias 且是外部依赖 → null
132
+ if (this._isExternal(pathStr)) return null;
133
+
134
+ // 4. Python 模块路径 (点分隔 → 斜线)
135
+ if (pathStr.includes('.') && !pathStr.includes('/')) {
136
+ const slashed = pathStr.replace(/\./g, '/');
137
+ if (this.fileIndex.has(slashed)) return this.fileIndex.get(slashed);
138
+ }
139
+
140
+ // 5. 直接匹配(Go 包路径、Rust crate path 等)
141
+ return this.fileIndex.get(pathStr) || null;
142
+ }
143
+
144
+ /**
145
+ * 尝试通过 tsconfig paths alias 解析
146
+ * @param {string} importPath
147
+ * @returns {string|null}
148
+ * @private
149
+ */
150
+ _resolveAlias(importPath) {
151
+ for (const { prefix, targets } of this.pathAliases) {
152
+ if (importPath === prefix || importPath.startsWith(prefix + '/')) {
153
+ const remainder = importPath === prefix ? '' : importPath.slice(prefix.length + 1);
154
+ for (const target of targets) {
155
+ const resolved = remainder ? path.normalize(path.join(target, remainder)) : target;
156
+ if (this.fileIndex.has(resolved)) return this.fileIndex.get(resolved);
157
+ }
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+
163
+ /**
164
+ * 判断是否为外部依赖
165
+ * @param {string} importPath
166
+ * @returns {boolean}
167
+ */
168
+ _isExternal(importPath) {
169
+ // 相对路径不是外部
170
+ if (importPath.startsWith('.') || importPath.startsWith('/')) {
171
+ return false;
172
+ }
173
+
174
+ // scoped npm packages: @scope/pkg
175
+ // bare specifier: lodash, express 等
176
+ // 如果在文件索引中有匹配,说明是项目内的
177
+ if (this.fileIndex.has(importPath)) return false;
178
+
179
+ // Python 点分路径的特殊处理
180
+ if (importPath.includes('.') && !importPath.includes('/')) {
181
+ const slashed = importPath.replace(/\./g, '/');
182
+ if (this.fileIndex.has(slashed)) return false;
183
+ }
184
+
185
+ return true;
186
+ }
187
+ }
188
+
189
+ export default ImportPathResolver;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @module ImportRecord
3
+ * @description 增强的 Import 记录 — 对外表现类似 string,内部携带结构化元信息。
4
+ *
5
+ * Phase 5: 跨文件调用链分析的基础数据结构。
6
+ *
7
+ * 兼容性保证:
8
+ * - imp.includes('express') ✅ (includes 方法代理到 path)
9
+ * - `${imp}` ✅ (toString 返回 path)
10
+ * - imp.startsWith('./') ✅ (同上代理)
11
+ * - JSON.stringify(imp) ✅ (toJSON 返回 path)
12
+ * - typeof imp === 'object' ⚠️ 不再是 'string'
13
+ *
14
+ * @example
15
+ * const rec = new ImportRecord('./UserRepo', { symbols: ['UserRepo'], kind: 'named' });
16
+ * rec.includes('User'); // true
17
+ * `${rec}`; // './UserRepo'
18
+ * rec.symbols; // ['UserRepo']
19
+ */
20
+
21
+ export class ImportRecord {
22
+ /**
23
+ * @param {string} path — 导入路径原始字符串
24
+ * @param {object} [meta]
25
+ * @param {string[]} [meta.symbols] — 导入的符号名 e.g. ['UserRepo', 'findById'] 或 ['*']
26
+ * @param {string|null} [meta.alias] — 导入别名 e.g. import { UserRepo as Repo }
27
+ * @param {'named'|'default'|'namespace'|'side-effect'} [meta.kind] — 导入方式
28
+ * @param {boolean} [meta.isTypeOnly] — 是否为类型导入 (TypeScript)
29
+ */
30
+ constructor(path, meta = {}) {
31
+ this.path = String(path);
32
+ this.symbols = meta.symbols || [];
33
+ this.alias = meta.alias || null;
34
+ this.kind = meta.kind || 'side-effect';
35
+ this.isTypeOnly = meta.isTypeOnly || false;
36
+ }
37
+
38
+ // ── String 兼容性方法 ──
39
+
40
+ toString() {
41
+ return this.path;
42
+ }
43
+
44
+ includes(s) {
45
+ return this.path.includes(s);
46
+ }
47
+
48
+ startsWith(s) {
49
+ return this.path.startsWith(s);
50
+ }
51
+
52
+ endsWith(s) {
53
+ return this.path.endsWith(s);
54
+ }
55
+
56
+ indexOf(s) {
57
+ return this.path.indexOf(s);
58
+ }
59
+
60
+ replace(a, b) {
61
+ return this.path.replace(a, b);
62
+ }
63
+
64
+ match(re) {
65
+ return this.path.match(re);
66
+ }
67
+
68
+ split(sep) {
69
+ return this.path.split(sep);
70
+ }
71
+
72
+ trim() {
73
+ return this.path.trim();
74
+ }
75
+
76
+ toJSON() {
77
+ return this.path;
78
+ }
79
+
80
+ get length() {
81
+ return this.path.length;
82
+ }
83
+
84
+ valueOf() {
85
+ return this.path;
86
+ }
87
+
88
+ // ── Phase 5 结构化访问 ──
89
+
90
+ /** 是否具有结构化符号信息 */
91
+ get isStructured() {
92
+ return this.symbols.length > 0;
93
+ }
94
+
95
+ /**
96
+ * 检查是否导入了指定符号名
97
+ * @param {string} symbolName
98
+ * @returns {boolean}
99
+ */
100
+ hasSymbol(symbolName) {
101
+ return this.symbols.includes(symbolName) || this.symbols.includes('*');
102
+ }
103
+ }
104
+
105
+ export default ImportRecord;
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @module SymbolTableBuilder
3
+ * @description Phase 5: 从 analyzeProject 结果构建全局符号表
4
+ *
5
+ * 符号表是调用图解析的核心数据结构,将 AST 提取的声明信息组织为可查询的全局表。
6
+ *
7
+ * 数据流:
8
+ * ProjectAstSummary → SymbolTableBuilder.build() → SymbolTable {
9
+ * declarations: Map<FQN, SymbolDeclaration>
10
+ * fileExports: Map<FilePath, string[]>
11
+ * fileImports: Map<FilePath, ImportRecord[]>
12
+ * }
13
+ */
14
+
15
+ import { ImportRecord } from './ImportRecord.js';
16
+
17
+ /**
18
+ * @typedef {object} SymbolDeclaration
19
+ * @property {string} fqn — Fully Qualified Name e.g. "src/service/UserService.ts::UserService.getUser"
20
+ * @property {string} name — 短名 e.g. "getUser"
21
+ * @property {string|null} className — 所属类
22
+ * @property {string} file — 声明文件 (相对路径)
23
+ * @property {number} line — 行号
24
+ * @property {'class'|'function'|'method'|'variable'|'interface'|'type'} kind
25
+ * @property {boolean} isExported — 是否导出
26
+ */
27
+
28
+ /**
29
+ * @typedef {object} SymbolTable
30
+ * @property {Map<string, SymbolDeclaration>} declarations — 符号 FQN → 声明
31
+ * @property {Map<string, string[]>} fileExports — 文件 → 导出符号名列表
32
+ * @property {Map<string, ImportRecord[]>} fileImports — 文件 → ImportRecord 列表
33
+ * @property {Set<string>} instantiatedClasses — Phase 5.3 RTA: 程序中实际实例化的类名集合
34
+ * @property {Map<string, Map<string, string>>} propertyTypes — Phase 5.3 DI: className → (fieldName → typeName)
35
+ */
36
+
37
+ export class SymbolTableBuilder {
38
+ /**
39
+ * 从 analyzeProject 结果构建全局符号表
40
+ *
41
+ * @param {object} projectSummary — analyzeProject() 返回的 ProjectAstSummary
42
+ * @returns {SymbolTable}
43
+ */
44
+ static build(projectSummary) {
45
+ /** @type {SymbolTable} */
46
+ const table = {
47
+ declarations: new Map(),
48
+ fileExports: new Map(),
49
+ fileImports: new Map(),
50
+ // Phase 5.3: RTA — track classes that are actually instantiated in the program
51
+ instantiatedClasses: new Set(),
52
+ // Phase 5.3: DI — property type annotations: className → (fieldName → typeName)
53
+ propertyTypes: new Map(),
54
+ };
55
+
56
+ if (!projectSummary?.fileSummaries) return table;
57
+
58
+ for (const fileSummary of projectSummary.fileSummaries) {
59
+ const filePath = fileSummary.file;
60
+
61
+ // 1. 提取导出名列表 (用于后续 import resolution)
62
+ const exportNames = _extractExportNames(fileSummary.exports || []);
63
+
64
+ // 2. 注册类声明
65
+ for (const cls of fileSummary.classes || []) {
66
+ if (!cls.name || cls.name === 'Unknown') continue;
67
+ const fqn = `${filePath}::${cls.name}`;
68
+ table.declarations.set(fqn, {
69
+ fqn,
70
+ name: cls.name,
71
+ className: null,
72
+ file: filePath,
73
+ line: cls.line || 0,
74
+ kind: cls.kind === 'enum' ? 'type' : cls.kind === 'type' ? 'type' : 'class',
75
+ isExported: _isExported(cls.name, exportNames),
76
+ });
77
+ }
78
+
79
+ // 3. 注册接口/协议声明
80
+ for (const proto of fileSummary.protocols || []) {
81
+ if (!proto.name || proto.name === 'Unknown') continue;
82
+ const fqn = `${filePath}::${proto.name}`;
83
+ table.declarations.set(fqn, {
84
+ fqn,
85
+ name: proto.name,
86
+ className: null,
87
+ file: filePath,
88
+ line: proto.line || 0,
89
+ kind: 'interface',
90
+ isExported: _isExported(proto.name, exportNames),
91
+ });
92
+ }
93
+
94
+ // 4. 注册方法/函数声明
95
+ for (const method of fileSummary.methods || []) {
96
+ if (!method.name || method.name === 'unknown') continue;
97
+ const scope = method.className || '';
98
+ const fqn = `${filePath}::${scope ? `${scope}.` : ''}${method.name}`;
99
+ table.declarations.set(fqn, {
100
+ fqn,
101
+ name: method.name,
102
+ className: method.className || null,
103
+ file: filePath,
104
+ line: method.line || 0,
105
+ kind: method.className ? 'method' : 'function',
106
+ isExported: !method.className && _isExported(method.name, exportNames),
107
+ });
108
+ }
109
+
110
+ // 5. 注册导出
111
+ table.fileExports.set(filePath, exportNames);
112
+
113
+ // 6. 注册导入 (兼容 string 和 ImportRecord)
114
+ const imports = (fileSummary.imports || []).map((imp) =>
115
+ imp instanceof ImportRecord ? imp : new ImportRecord(String(imp))
116
+ );
117
+ table.fileImports.set(filePath, imports);
118
+
119
+ // 7. Phase 5.3 RTA: Collect instantiated classes from callSites
120
+ // new ClassName() → callType='constructor', receiverType=ClassName
121
+ // <Component /> → callType='constructor', receiverType=Component (JSX)
122
+ for (const cs of fileSummary.callSites || []) {
123
+ if (cs.callType === 'constructor' && cs.receiverType) {
124
+ table.instantiatedClasses.add(cs.receiverType);
125
+ }
126
+ }
127
+
128
+ // 8. Phase 5.3 DI: Collect property type annotations
129
+ // property { name, className, typeAnnotation } → propertyTypes[className][name] = type
130
+ for (const prop of fileSummary.properties || []) {
131
+ if (prop.typeAnnotation && prop.className) {
132
+ if (!table.propertyTypes.has(prop.className)) {
133
+ table.propertyTypes.set(prop.className, new Map());
134
+ }
135
+ table.propertyTypes.get(prop.className).set(prop.name, prop.typeAnnotation);
136
+ }
137
+ }
138
+ }
139
+
140
+ return table;
141
+ }
142
+ }
143
+
144
+ // ── 内部工具函数 ───────────────────────────────────────────
145
+
146
+ /**
147
+ * 从 exports 数组中提取导出名
148
+ * exports 格式可能是:
149
+ * - string[]
150
+ * - { line, text }[] (TypeScript walker 的格式)
151
+ * - { name, ... }[]
152
+ *
153
+ * @param {Array} exports
154
+ * @returns {string[]}
155
+ */
156
+ function _extractExportNames(exports) {
157
+ const names = [];
158
+
159
+ for (const exp of exports) {
160
+ if (typeof exp === 'string') {
161
+ names.push(exp);
162
+ continue;
163
+ }
164
+
165
+ if (exp?.name) {
166
+ names.push(exp.name);
167
+ continue;
168
+ }
169
+
170
+ if (exp?.text) {
171
+ // 从 export 文本中尝试提取名称
172
+ // e.g. "export class UserService" → "UserService"
173
+ // e.g. "export function getUser" → "getUser"
174
+ // e.g. "export const config" → "config"
175
+ // e.g. "export default class" → "default"
176
+ const text = exp.text;
177
+ const match = text.match(
178
+ /export\s+(?:default\s+)?(?:class|function|const|let|var|interface|type|enum|abstract\s+class)\s+(\w+)/
179
+ );
180
+ if (match) {
181
+ names.push(match[1]);
182
+ } else if (text.includes('export default')) {
183
+ names.push('default');
184
+ }
185
+ // export { A, B, C }
186
+ const namedMatch = text.match(/export\s*\{([^}]+)\}/);
187
+ if (namedMatch) {
188
+ const items = namedMatch[1].split(',').map((s) => {
189
+ // 处理 "A as B" 的情况
190
+ const parts = s.trim().split(/\s+as\s+/);
191
+ return parts[parts.length - 1].trim();
192
+ });
193
+ names.push(...items.filter(Boolean));
194
+ }
195
+ }
196
+ }
197
+
198
+ return names;
199
+ }
200
+
201
+ /**
202
+ * 检查符号是否被导出
203
+ * @param {string} name
204
+ * @param {string[]} exportNames
205
+ * @returns {boolean}
206
+ */
207
+ function _isExported(name, exportNames) {
208
+ return exportNames.includes(name) || exportNames.includes('default');
209
+ }
210
+
211
+ export default SymbolTableBuilder;
@@ -292,6 +292,14 @@ export default class ProjectGraph {
292
292
  return this.#files.get(relativePath) || null;
293
293
  }
294
294
 
295
+ /**
296
+ * 获取所有已解析的文件路径
297
+ * @returns {string[]} 相对路径列表
298
+ */
299
+ getAllFilePaths() {
300
+ return [...this.#files.keys()];
301
+ }
302
+
295
303
  /**
296
304
  * 搜索类名 (模糊匹配)
297
305
  * @param {string} query