@didnhdj/fnmap 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # fnmap
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@didnhdj/fnmap.svg)](https://www.npmjs.com/package/@didnhdj/fnmap)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@didnhdj/fnmap.svg)](https://www.npmjs.com/package/@didnhdj/fnmap)
5
+
3
6
  > AI code indexing tool for analyzing JS/TS code structure and generating structured code maps
4
7
 
5
8
  [中文文档](./README_CN.md)
@@ -9,7 +12,6 @@
9
12
  - 🚀 **Fast Analysis**: Quickly analyze JavaScript/TypeScript code structure using AST
10
13
  - 📊 **Structured Output**: Generate `.fnmap` index files with imports, functions, classes, and constants
11
14
  - 🔗 **Call Graph**: Track function call relationships and dependencies
12
- - 📈 **Mermaid Diagrams**: Generate visual call graphs in Mermaid format
13
15
  - 🎯 **Git Integration**: Process only changed files for efficient workflows
14
16
  - ⚙️ **Flexible Configuration**: Support for multiple configuration methods
15
17
  - 🔌 **Pre-commit Hook**: Integrate seamlessly with git hooks
@@ -37,7 +39,20 @@ npm install --save-dev @didnhdj/fnmap
37
39
  fnmap --init
38
40
  ```
39
41
 
40
- This creates a `.fnmaprc` configuration file in your project root and automatically appends fnmap documentation to `CLAUDE.md` or `AGENTS.md` if they exist (useful for AI assistants).
42
+ This interactive command will:
43
+ 1. Create a `.fnmaprc` configuration file in your project root
44
+ 2. Add fnmap-generated files to `.gitignore` (optional)
45
+ 3. Automatically append fnmap format documentation to:
46
+ - `CLAUDE.md` (project-level instructions for Claude AI)
47
+ - `~/.claude/CLAUDE.md` (user-level global instructions)
48
+ - `AGENTS.md` (project-level agent instructions)
49
+ - Or any custom file path you specify
50
+
51
+ The appended documentation helps AI assistants (like Claude) understand the `.fnmap` format, enabling them to:
52
+ - Quickly navigate your codebase using the index
53
+ - Locate functions and classes by line number
54
+ - Understand code structure and call graphs
55
+ - Make more informed code suggestions
41
56
 
42
57
  ### Basic Usage
43
58
 
@@ -55,17 +70,13 @@ fnmap --files index.js,utils.js
55
70
  fnmap --changed
56
71
 
57
72
  # Process git staged files (for pre-commit hook)
58
- fnmap --staged -q
59
- ```
60
-
61
- ### Generate Call Graphs
73
+ fnmap --staged
62
74
 
63
- ```bash
64
- # Generate file-level Mermaid diagrams
65
- fnmap --mermaid file --dir src
75
+ # Show detailed processing logs
76
+ fnmap --log --dir src
66
77
 
67
- # Generate project-level Mermaid diagram
68
- fnmap --mermaid project
78
+ # Clear generated files
79
+ fnmap --clear
69
80
  ```
70
81
 
71
82
  ## Configuration
@@ -131,26 +142,8 @@ The `.fnmap` file contains structured information about your code:
131
142
  - `ClassName:SuperClass startLine-endLine` - Class information
132
143
  - ` .methodName(params) line description →calls` - Instance method
133
144
  - ` +methodName(params) line description →calls` - Static method
134
- - `CONSTANT_NAME line description` - Constant definition
135
-
136
- ### Mermaid Call Graph
137
-
138
- When using `--mermaid` option, generates visual call graphs:
139
-
140
- **File-level** (`filename.mermaid`):
141
- ```mermaid
142
- flowchart TD
143
- subgraph utils["utils"]
144
- readConfig["readConfig"]
145
- parseData["parseData"]
146
- saveFile["saveFile"]
147
- end
148
- readConfig --> parseData
149
- saveFile --> parseData
150
- ```
151
-
152
- **Project-level** (`.fnmap.mermaid`):
153
- Shows call relationships across all files in the project.
145
+ - `$constName line description` - Constant definition (`$` prefix)
146
+ - `>export1,export2,default` - Exports (`>` prefix, supports `default`, `type:Name`)
154
147
 
155
148
  ## CLI Options
156
149
 
@@ -159,14 +152,15 @@ Usage: fnmap [options] [files...]
159
152
 
160
153
  Options:
161
154
  -v, --version Show version number
162
- -f, --files <files> Process specific files (comma-separated, generates separate .fnmap for each)
155
+ -f, --files <files> Process specified files (comma-separated)
163
156
  -d, --dir <dir> Process all code files in directory
164
157
  -p, --project <dir> Specify project root directory (default: current directory)
165
- -c, --changed Process git changed files (staged + modified + untracked)
166
- -s, --staged Process git staged files (for pre-commit hook)
158
+ -c, --changed Process only git changed files (staged + modified + untracked)
159
+ -s, --staged Process only git staged files (for pre-commit hook)
167
160
  -m, --mermaid [mode] Generate Mermaid call graph (file=file-level, project=project-level)
168
- -q, --quiet Quiet mode (suppress output)
169
- --init Create default configuration file and append docs to CLAUDE.md/AGENTS.md
161
+ -l, --log Show detailed processing logs
162
+ --init Create default config file and setup project (interactive)
163
+ --clear Clear generated files (.fnmap, *.fnmap, *.mermaid)
170
164
  -h, --help Display help information
171
165
  ```
172
166
 
@@ -239,19 +233,43 @@ interface FileInfo {
239
233
 
240
234
  ## Use Cases
241
235
 
242
- ### 1. Pre-commit Hook
236
+ ### 1. AI Assistant Integration
237
+
238
+ fnmap is designed to help AI coding assistants understand your codebase better:
239
+
240
+ ```bash
241
+ # Initialize and setup AI documentation
242
+ fnmap --init
243
+
244
+ # Generate code index for your project
245
+ fnmap --dir src
246
+ ```
247
+
248
+ The `.fnmap` files help AI assistants:
249
+ - Navigate large codebases efficiently
250
+ - Find specific functions/classes by name and line number
251
+ - Understand module dependencies and call graphs
252
+ - Provide context-aware code suggestions
253
+
254
+ **Recommended workflow with Claude Code or similar AI tools:**
255
+ 1. Run `fnmap --init` to add format documentation to `CLAUDE.md`
256
+ 2. Generate index files with `fnmap --dir src`
257
+ 3. AI assistants will automatically read `.fnmap` files for context
258
+ 4. Update index when code changes with `fnmap --changed`
259
+
260
+ ### 2. Pre-commit Hook
243
261
 
244
262
  Add to `.husky/pre-commit` or `.git/hooks/pre-commit`:
245
263
 
246
264
  ```bash
247
265
  #!/bin/sh
248
- fnmap --staged -q
266
+ fnmap --staged
249
267
  git add .fnmap
250
268
  ```
251
269
 
252
270
  This automatically updates the `.fnmap` index when committing code.
253
271
 
254
- ### 2. CI/CD Integration
272
+ ### 3. CI/CD Integration
255
273
 
256
274
  ```yaml
257
275
  # .github/workflows/ci.yml
@@ -262,23 +280,14 @@ This automatically updates the `.fnmap` index when committing code.
262
280
  git diff --exit-code .fnmap || echo "Code index updated"
263
281
  ```
264
282
 
265
- ### 3. Code Review
283
+ ### 4. Code Review
266
284
 
267
285
  ```bash
268
286
  # Generate index for changed files
269
287
  fnmap --changed
270
288
 
271
- # Generate call graph for review
272
- fnmap --mermaid file --changed
273
- ```
274
-
275
- ### 4. Documentation Generation
276
-
277
- ```bash
278
- # Generate project-level call graph
279
- fnmap --mermaid project
280
-
281
- # Use the .fnmap.mermaid file in your documentation
289
+ # Show detailed logs during analysis
290
+ fnmap --log --changed
282
291
  ```
283
292
 
284
293
  ## Supported File Types
@@ -305,7 +314,6 @@ To ensure performance and safety, fnmap has the following default limits:
305
314
  2. **Structure Analysis**: Traverses AST to extract imports, functions, classes, constants
306
315
  3. **Call Graph**: Tracks function call relationships and dependencies
307
316
  4. **Index Generation**: Generates compact `.fnmap` files with structured information
308
- 5. **Visualization**: Optionally generates Mermaid diagrams for visual representation
309
317
 
310
318
  ## Examples
311
319
 
@@ -332,17 +340,14 @@ Complete! Analyzed: 1, Failed: 0
332
340
  ==================================================
333
341
  ```
334
342
 
335
- ### Example 2: Analyze Directory with Call Graph
343
+ ### Example 2: Analyze Directory
336
344
 
337
345
  ```bash
338
- fnmap --dir src --mermaid file
346
+ fnmap --dir src
339
347
  ```
340
348
 
341
349
  Generates:
342
- - `src/.fnmap` - Code index
343
- - `src/utils.mermaid` - Call graph for utils.js
344
- - `src/parser.mermaid` - Call graph for parser.js
345
- - etc.
350
+ - `src/.fnmap` - Code index for all files in src directory
346
351
 
347
352
  ### Example 3: Git Workflow
348
353
 
@@ -351,7 +356,7 @@ Generates:
351
356
  git add .
352
357
 
353
358
  # Generate index for staged files
354
- fnmap --staged -q
359
+ fnmap --staged
355
360
 
356
361
  # Add updated index
357
362
  git add .fnmap
package/README_CN.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # fnmap
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@didnhdj/fnmap.svg)](https://www.npmjs.com/package/@didnhdj/fnmap)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@didnhdj/fnmap.svg)](https://www.npmjs.com/package/@didnhdj/fnmap)
5
+
3
6
  > AI 代码索引生成工具,分析 JS/TS 代码结构,生成结构化代码映射
4
7
 
5
8
  [English Documentation](./README.md)
@@ -9,7 +12,6 @@
9
12
  - 🚀 **快速分析**:使用 AST 快速分析 JavaScript/TypeScript 代码结构
10
13
  - 📊 **结构化输出**:生成包含导入、函数、类、常量的 `.fnmap` 索引文件
11
14
  - 🔗 **调用图谱**:追踪函数调用关系和依赖
12
- - 📈 **Mermaid 图表**:生成 Mermaid 格式的可视化调用图
13
15
  - 🎯 **Git 集成**:只处理改动的文件,提高工作效率
14
16
  - ⚙️ **灵活配置**:支持多种配置方式
15
17
  - 🔌 **Pre-commit Hook**:无缝集成 git hooks
@@ -37,7 +39,20 @@ npm install --save-dev @didnhdj/fnmap
37
39
  fnmap --init
38
40
  ```
39
41
 
40
- 这会在项目根目录创建 `.fnmaprc` 配置文件,并自动追加 fnmap 文档到 `CLAUDE.md` 或 `AGENTS.md`(如果存在,方便 AI 助手理解)。
42
+ 这个交互式命令会:
43
+ 1. 在项目根目录创建 `.fnmaprc` 配置文件
44
+ 2. 添加 fnmap 生成的文件到 `.gitignore`(可选)
45
+ 3. 自动追加 fnmap 格式文档到:
46
+ - `CLAUDE.md`(项目级 Claude AI 指令)
47
+ - `~/.claude/CLAUDE.md`(用户级全局指令)
48
+ - `AGENTS.md`(项目级 Agent 指令)
49
+ - 或任何你指定的自定义文件路径
50
+
51
+ 追加的文档帮助 AI 助手(如 Claude)理解 `.fnmap` 格式,使其能够:
52
+ - 使用索引快速导航代码库
53
+ - 通过行号定位函数和类
54
+ - 理解代码结构和调用图
55
+ - 提供更准确的代码建议
41
56
 
42
57
  ### 基本用法
43
58
 
@@ -55,17 +70,13 @@ fnmap --files index.js,utils.js
55
70
  fnmap --changed
56
71
 
57
72
  # 处理 git staged 文件(用于 pre-commit hook)
58
- fnmap --staged -q
59
- ```
60
-
61
- ### 生成调用图
73
+ fnmap --staged
62
74
 
63
- ```bash
64
- # 生成文件级 Mermaid 图表
65
- fnmap --mermaid file --dir src
75
+ # 显示详细处理日志
76
+ fnmap --log --dir src
66
77
 
67
- # 生成项目级 Mermaid 图表
68
- fnmap --mermaid project
78
+ # 清理生成的文件
79
+ fnmap --clear
69
80
  ```
70
81
 
71
82
  ## 配置
@@ -131,26 +142,8 @@ fnmap 支持多种配置方式(按优先级排序):
131
142
  - `ClassName:SuperClass startLine-endLine` - 类信息
132
143
  - ` .methodName(params) line description →calls` - 实例方法
133
144
  - ` +methodName(params) line description →calls` - 静态方法
134
- - `CONSTANT_NAME line description` - 常量定义
135
-
136
- ### Mermaid 调用图
137
-
138
- 使用 `--mermaid` 选项时,生成可视化调用图:
139
-
140
- **文件级** (`filename.mermaid`):
141
- ```mermaid
142
- flowchart TD
143
- subgraph utils["utils"]
144
- readConfig["readConfig"]
145
- parseData["parseData"]
146
- saveFile["saveFile"]
147
- end
148
- readConfig --> parseData
149
- saveFile --> parseData
150
- ```
151
-
152
- **项目级** (`.fnmap.mermaid`):
153
- 显示项目中所有文件的调用关系。
145
+ - `$constName line description` - 常量定义(`$` 前缀)
146
+ - `>export1,export2,default` - 导出(`>` 前缀,支持 `default`、`type:Name`)
154
147
 
155
148
  ## CLI 选项
156
149
 
@@ -159,14 +152,15 @@ flowchart TD
159
152
 
160
153
  选项:
161
154
  -v, --version 显示版本号
162
- -f, --files <files> 处理指定文件(逗号分隔,为每个文件生成单独的 .fnmap)
155
+ -f, --files <files> 处理指定文件(逗号分隔)
163
156
  -d, --dir <dir> 处理目录下所有代码文件
164
157
  -p, --project <dir> 指定项目根目录(默认:当前目录)
165
158
  -c, --changed 处理 git 改动的文件(staged + modified + untracked)
166
159
  -s, --staged 处理 git staged 文件(用于 pre-commit hook)
167
160
  -m, --mermaid [mode] 生成 Mermaid 调用图(file=文件级,project=项目级)
168
- -q, --quiet 静默模式(不输出信息)
169
- --init 创建默认配置文件并追加文档到 CLAUDE.md/AGENTS.md
161
+ -l, --log 显示详细处理日志
162
+ --init 创建默认配置文件并设置项目(交互式)
163
+ --clear 清理生成的文件(.fnmap、*.fnmap、*.mermaid)
170
164
  -h, --help 显示帮助信息
171
165
  ```
172
166
 
@@ -239,19 +233,43 @@ interface FileInfo {
239
233
 
240
234
  ## 使用场景
241
235
 
242
- ### 1. Pre-commit Hook
236
+ ### 1. AI 助手集成
237
+
238
+ fnmap 专为帮助 AI 编程助手更好地理解代码库而设计:
239
+
240
+ ```bash
241
+ # 初始化并设置 AI 文档
242
+ fnmap --init
243
+
244
+ # 为项目生成代码索引
245
+ fnmap --dir src
246
+ ```
247
+
248
+ `.fnmap` 文件帮助 AI 助手:
249
+ - 高效导航大型代码库
250
+ - 按名称和行号查找特定函数/类
251
+ - 理解模块依赖和调用图
252
+ - 提供上下文感知的代码建议
253
+
254
+ **与 Claude Code 或类似 AI 工具的推荐工作流:**
255
+ 1. 运行 `fnmap --init` 将格式文档添加到 `CLAUDE.md`
256
+ 2. 使用 `fnmap --dir src` 生成索引文件
257
+ 3. AI 助手将自动读取 `.fnmap` 文件以获取上下文
258
+ 4. 代码变更时使用 `fnmap --changed` 更新索引
259
+
260
+ ### 2. Pre-commit Hook
243
261
 
244
262
  添加到 `.husky/pre-commit` 或 `.git/hooks/pre-commit`:
245
263
 
246
264
  ```bash
247
265
  #!/bin/sh
248
- fnmap --staged -q
266
+ fnmap --staged
249
267
  git add .fnmap
250
268
  ```
251
269
 
252
270
  这样在提交代码时会自动更新 `.fnmap` 索引。
253
271
 
254
- ### 2. CI/CD 集成
272
+ ### 3. CI/CD 集成
255
273
 
256
274
  ```yaml
257
275
  # .github/workflows/ci.yml
@@ -262,23 +280,14 @@ git add .fnmap
262
280
  git diff --exit-code .fnmap || echo "Code index updated"
263
281
  ```
264
282
 
265
- ### 3. 代码审查
283
+ ### 4. 代码审查
266
284
 
267
285
  ```bash
268
286
  # 为改动的文件生成索引
269
287
  fnmap --changed
270
288
 
271
- # 生成调用图用于审查
272
- fnmap --mermaid file --changed
273
- ```
274
-
275
- ### 4. 文档生成
276
-
277
- ```bash
278
- # 生成项目级调用图
279
- fnmap --mermaid project
280
-
281
- # 在文档中使用 .fnmap.mermaid 文件
289
+ # 分析时显示详细日志
290
+ fnmap --log --changed
282
291
  ```
283
292
 
284
293
  ## 支持的文件类型
@@ -305,7 +314,6 @@ fnmap --mermaid project
305
314
  2. **结构分析**:遍历 AST 提取导入、函数、类、常量
306
315
  3. **调用图谱**:追踪函数调用关系和依赖
307
316
  4. **索引生成**:生成紧凑的 `.fnmap` 文件,包含结构化信息
308
- 5. **可视化**:可选生成 Mermaid 图表进行可视化展示
309
317
 
310
318
  ## 示例
311
319
 
@@ -332,17 +340,14 @@ Complete! Analyzed: 1, Failed: 0
332
340
  ==================================================
333
341
  ```
334
342
 
335
- ### 示例 2:分析目录并生成调用图
343
+ ### 示例 2:分析目录
336
344
 
337
345
  ```bash
338
- fnmap --dir src --mermaid file
346
+ fnmap --dir src
339
347
  ```
340
348
 
341
349
  生成:
342
- - `src/.fnmap` - 代码索引
343
- - `src/utils.mermaid` - utils.js 的调用图
344
- - `src/parser.mermaid` - parser.js 的调用图
345
- - 等等
350
+ - `src/.fnmap` - src 目录下所有文件的代码索引
346
351
 
347
352
  ### 示例 3:Git 工作流
348
353
 
@@ -351,7 +356,7 @@ fnmap --dir src --mermaid file
351
356
  git add .
352
357
 
353
358
  # 为 staged 文件生成索引
354
- fnmap --staged -q
359
+ fnmap --staged
355
360
 
356
361
  # 添加更新的索引
357
362
  git add .fnmap
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,aAAa,EAMd,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,uBAAuB,EAAqB,MAAM,SAAS,CAAC;AAKrE;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CA40BjF;AAoFD,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,aAAa,EAOd,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,uBAAuB,EAAqB,MAAM,SAAS,CAAC;AAKrE;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,CAk7BjF;AAoFD,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,MAAM;iBACJ,MAAM,KAAG,IAAI;mBAGX,MAAM,KAAG,IAAI;gBAGhB,MAAM,KAAG,IAAI;gBAGb,MAAM,KAAG,IAAI;iBAGZ,MAAM,KAAG,IAAI;iBAIb,MAAM,KAAG,IAAI;CAG3B,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEjD;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAqDlC;AAGD,wBAAgB,UAAU,IAAI,OAAO,CAKpC;AAGD,eAAO,MAAM,OAAO;;;;CAUnB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,MAAM;iBACJ,MAAM,KAAG,IAAI;mBAGX,MAAM,KAAG,IAAI;gBAGhB,MAAM,KAAG,IAAI;gBAGb,MAAM,KAAG,IAAI;iBAGZ,MAAM,KAAG,IAAI;iBAIb,MAAM,KAAG,IAAI;CAG3B,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEjD;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAenC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAqDlC;AAGD,wBAAgB,UAAU,IAAI,OAAO,CAKpC;AAGD,eAAO,MAAM,OAAO;;;;CAUnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fnmap.d.ts","sourceRoot":"","sources":["../../src/generator/fnmap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CA2DjF"}
1
+ {"version":3,"file":"fnmap.d.ts","sourceRoot":"","sources":["../../src/generator/fnmap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CA0EjF"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("fs"),g=require("path"),nn=require("commander"),Ie=require("child_process"),tn=require("@babel/parser"),Re=require("@babel/traverse"),W={FILE_NOT_FOUND:"FILE_NOT_FOUND",FILE_READ_ERROR:"FILE_READ_ERROR",PARSE_ERROR:"PARSE_ERROR",CONFIG_ERROR:"CONFIG_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",PERMISSION_ERROR:"PERMISSION_ERROR",FILE_TOO_LARGE:"FILE_TOO_LARGE"};function Te(e){return"parseError"in e}function rn(e){return e.success===!0}function sn(e){return e.success===!1}function on(e){return e.valid===!0}function an(e){return e.valid===!1}const S={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",gray:"\x1B[90m",bold:"\x1B[1m"},Le=10*1024*1024,je=50,Fe=[".js",".ts",".jsx",".tsx",".mjs"],Oe=["node_modules",".git","dist","build",".next","coverage","__pycache__",".cache"],Ne={enable:!0,include:["**/*.js","**/*.ts","**/*.jsx","**/*.tsx","**/*.mjs"],exclude:[]};function $e(e){if(!e)return e;const r=e.replace(/\\/g,"/");return g.normalize(r)}function cn(e){return e.map($e)}function ze(e){if(!e||typeof e!="string")return{valid:!1,error:"File path is required and must be a string / 文件路径必须是字符串",errorType:W.VALIDATION_ERROR};if(!F.existsSync(e))return{valid:!1,error:`File not found: ${e} / 文件不存在: ${e}`,errorType:W.FILE_NOT_FOUND};try{const r=F.statSync(e);if(!r.isFile())return{valid:!1,error:`Path is not a file: ${e} / 路径不是文件: ${e}`,errorType:W.VALIDATION_ERROR};if(r.size>Le)return{valid:!1,error:`File too large (${(r.size/1024/1024).toFixed(2)}MB > ${Le/1024/1024}MB): ${e} / 文件过大`,errorType:W.FILE_TOO_LARGE}}catch(r){return{valid:!1,error:`Cannot access file: ${e}. Reason: ${r.message} / 无法访问文件`,errorType:W.PERMISSION_ERROR}}return{valid:!0}}function De(e){if(!e||typeof e!="object")return{valid:!1,error:"Config must be an object / 配置必须是对象"};const r=e;return r.enable!==void 0&&typeof r.enable!="boolean"?{valid:!1,error:"Config.enable must be a boolean / enable 字段必须是布尔值"}:r.include!==void 0&&!Array.isArray(r.include)?{valid:!1,error:"Config.include must be an array / include 字段必须是数组"}:r.exclude!==void 0&&!Array.isArray(r.exclude)?{valid:!1,error:"Config.exclude must be an array / exclude 字段必须是数组"}:{valid:!0}}function Se(e,r,t={}){const s=[r];return t.file&&s.push(`File: ${t.file}`),t.line!==void 0&&t.column!==void 0&&s.push(`Location: Line ${t.line}, Column ${t.column}`),t.suggestion&&s.push(`Suggestion: ${t.suggestion}`),s.join(`
3
- `)}let ye=!0,be=null;const E={error:e=>{ye||console.error(`${S.red}✗${S.reset} ${e}`)},success:e=>{ye||console.log(`${S.green}✓${S.reset} ${e}`)},info:e=>{ye||console.log(e)},warn:e=>{ye||console.warn(`${S.yellow}!${S.reset} ${e}`)},title:e=>{ye||console.log(`${S.bold}${e}${S.reset}`)},stats:e=>{console.log(e)}};function he(e){ye=e}function _e(){return ye}function Be(){try{return require("../../package.json").version}catch{return"0.1.0"}}function Me(){return be=new nn.Command,be.name("fnmap").description("AI code indexing tool - Analyzes JS/TS code structure and generates structured code maps").version(Be(),"-v, --version","Show version number").option("-f, --files <files>","Process specified files (comma-separated)",e=>e.split(",").map(r=>$e(r.trim())).filter(Boolean)).option("-d, --dir <dir>","Process all code files in directory",e=>$e(e)).option("-p, --project <dir>","Specify project root directory (default: current directory)",e=>$e(e),process.env.CLAUDE_PROJECT_DIR??process.cwd()).option("-c, --changed","Process only git changed files (staged + modified + untracked)").option("-s, --staged","Process only git staged files (for pre-commit hook)").option("-m, --mermaid [mode]","Generate Mermaid call graph (file=file-level, project=project-level)").option("-l, --log","Show detailed processing logs").option("--init","Create default config file and setup project (interactive)").option("--clear","Clear generated files (.fnmap, *.fnmap, *.mermaid)").argument("[files...]","Directly specify file paths").allowUnknownOption(!1).addHelpText("after",`
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("fs"),g=require("path"),nt=require("commander"),Se=require("child_process"),rt=require("@babel/parser"),je=require("@babel/traverse"),st=require("os"),it=require("node:readline");function ot(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,s.get?s:{enumerable:!0,get:()=>e[n]})}}return r.default=e,Object.freeze(r)}const at=ot(it),U={FILE_NOT_FOUND:"FILE_NOT_FOUND",FILE_READ_ERROR:"FILE_READ_ERROR",PARSE_ERROR:"PARSE_ERROR",CONFIG_ERROR:"CONFIG_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",PERMISSION_ERROR:"PERMISSION_ERROR",FILE_TOO_LARGE:"FILE_TOO_LARGE"};function Me(e){return"parseError"in e}function ct(e){return e.success===!0}function lt(e){return e.success===!1}function ft(e){return e.valid===!0}function dt(e){return e.valid===!1}const F={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",gray:"\x1B[90m",bold:"\x1B[1m"},Le=10*1024*1024,Ne=50,we=[".js",".ts",".jsx",".tsx",".mjs"],Pe=["node_modules",".git","dist","build",".next","coverage","__pycache__",".cache"],ke={enable:!0,include:["**/*.js","**/*.ts","**/*.jsx","**/*.tsx","**/*.mjs"],exclude:[]};function Ee(e){if(!e)return e;const r=e.replace(/\\/g,"/");return g.normalize(r)}function pt(e){return e.map(Ee)}function Be(e){if(!e||typeof e!="string")return{valid:!1,error:"File path is required and must be a string / 文件路径必须是字符串",errorType:U.VALIDATION_ERROR};if(!v.existsSync(e))return{valid:!1,error:`File not found: ${e} / 文件不存在: ${e}`,errorType:U.FILE_NOT_FOUND};try{const r=v.statSync(e);if(!r.isFile())return{valid:!1,error:`Path is not a file: ${e} / 路径不是文件: ${e}`,errorType:U.VALIDATION_ERROR};if(r.size>Le)return{valid:!1,error:`File too large (${(r.size/1024/1024).toFixed(2)}MB > ${Le/1024/1024}MB): ${e} / 文件过大`,errorType:U.FILE_TOO_LARGE}}catch(r){return{valid:!1,error:`Cannot access file: ${e}. Reason: ${r.message} / 无法访问文件`,errorType:U.PERMISSION_ERROR}}return{valid:!0}}function _e(e){if(!e||typeof e!="object")return{valid:!1,error:"Config must be an object / 配置必须是对象"};const r=e;return r.enable!==void 0&&typeof r.enable!="boolean"?{valid:!1,error:"Config.enable must be a boolean / enable 字段必须是布尔值"}:r.include!==void 0&&!Array.isArray(r.include)?{valid:!1,error:"Config.include must be an array / include 字段必须是数组"}:r.exclude!==void 0&&!Array.isArray(r.exclude)?{valid:!1,error:"Config.exclude must be an array / exclude 字段必须是数组"}:{valid:!0}}function Ae(e,r,n={}){const s=[r];return n.file&&s.push(`File: ${n.file}`),n.line!==void 0&&n.column!==void 0&&s.push(`Location: Line ${n.line}, Column ${n.column}`),n.suggestion&&s.push(`Suggestion: ${n.suggestion}`),s.join(`
3
+ `)}let he=!0,Ce=null;const b={error:e=>{he||console.error(`${F.red}✗${F.reset} ${e}`)},success:e=>{he||console.log(`${F.green}✓${F.reset} ${e}`)},info:e=>{he||console.log(e)},warn:e=>{he||console.warn(`${F.yellow}!${F.reset} ${e}`)},title:e=>{he||console.log(`${F.bold}${e}${F.reset}`)},stats:e=>{console.log(e)}};function xe(e){he=e}function Te(){return he}function Je(){try{let e;try{e=require("../../package.json")}catch{e=require("../package.json")}return e.version}catch{return"0.1.0"}}function Ge(){return Ce=new nt.Command,Ce.name("fnmap").description("AI code indexing tool - Analyzes JS/TS code structure and generates structured code maps").version(Je(),"-v, --version","Show version number").option("-f, --files <files>","Process specified files (comma-separated)",e=>e.split(",").map(r=>Ee(r.trim())).filter(Boolean)).option("-d, --dir <dir>","Process all code files in directory",e=>Ee(e)).option("-p, --project <dir>","Specify project root directory (default: current directory)",e=>Ee(e),process.env.CLAUDE_PROJECT_DIR??process.cwd()).option("-c, --changed","Process only git changed files (staged + modified + untracked)").option("-s, --staged","Process only git staged files (for pre-commit hook)").option("-m, --mermaid [mode]","Generate Mermaid call graph (file=file-level, project=project-level)").option("-l, --log","Show detailed processing logs").option("--init","Create default config file and setup project (interactive)").option("--clear","Clear generated files (.fnmap, *.fnmap, *.mermaid)").argument("[files...]","Directly specify file paths").allowUnknownOption(!1).addHelpText("after",`
4
4
  Configuration files (by priority):
5
5
  .fnmaprc JSON config file
6
6
  .fnmaprc.json JSON config file
@@ -23,58 +23,33 @@ Examples:
23
23
  $ fnmap --init Interactive project setup
24
24
  $ fnmap --clear Clear all generated files
25
25
  $ fnmap --clear --dir src Clear generated files in src directory
26
- `),be}function xe(){return be||Me()}const ln={get opts(){return xe().opts.bind(xe())},get args(){return xe().args},get parse(){return xe().parse.bind(xe())}};function Je(e){const r=[".fnmaprc",".fnmaprc.json"];for(const s of r){const c=g.join(e,s);if(F.existsSync(c))try{const f=F.readFileSync(c,"utf-8");if(!f.trim()){E.warn(`Config file is empty: ${s}. Using default config / 配置文件为空,使用默认配置`);continue}let $;try{$=JSON.parse(f)}catch(p){const h=p,o=Se(W.CONFIG_ERROR,`Failed to parse config file: ${s} / 配置文件解析失败`,{file:c,line:h.lineNumber,column:h.columnNumber,suggestion:"Check JSON syntax, ensure proper quotes and commas / 检查 JSON 语法,确保引号和逗号正确"});E.warn(o);continue}const u=De($);if(!u.valid){E.warn(`Invalid config in ${s}: ${u.error}`);continue}return{config:$,source:s}}catch(f){const $=f,u=Se(W.FILE_READ_ERROR,`Failed to read config file: ${s} / 配置文件读取失败`,{file:c,suggestion:$.message});E.warn(u)}}const t=g.join(e,"package.json");if(F.existsSync(t))try{const s=JSON.parse(F.readFileSync(t,"utf-8"));if(s.fnmap){const c=De(s.fnmap);if(!c.valid)E.warn(`Invalid fnmap config in package.json: ${c.error}`);else return{config:s.fnmap,source:"package.json#fnmap"}}}catch{}return{config:null,source:null}}function Ke(e){return e?{...Ne,...e,exclude:[...e.exclude??[]]}:Ne}function Pe(e){return e.endsWith(".d.ts")||e.endsWith(".d.tsx")||e.endsWith(".d.mts")}function fn(e){try{return Ie.execSync("git rev-parse --show-toplevel",{cwd:e,encoding:"utf-8"}).trim()}catch{return null}}function Xe(e,r=!1){const t=[];try{const s=fn(e);if(!s)return[];let c;if(r)c=Ie.execSync("git diff --cached --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"});else{const u=Ie.execSync("git diff --cached --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"}),p=Ie.execSync("git diff --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"}),h=Ie.execSync("git ls-files --others --exclude-standard",{cwd:e,encoding:"utf-8"});c=`${u}
27
- ${p}
28
- ${h}`}const f=c.split(`
29
- `).map(u=>u.trim()).filter(Boolean).filter(u=>{const p=g.extname(u);return Fe.includes(p)&&!Pe(u)}),$=[...new Set(f)];for(const u of $){const p=g.resolve(s,u);F.existsSync(p)&&p.startsWith(g.resolve(e))&&t.push(p)}}catch{return[]}return t}function dn(e){const r=[];if(!F.existsSync(e))return r;try{const t=F.readdirSync(e,{withFileTypes:!0});for(const s of t)if(s.isFile()){const c=g.extname(s.name);Fe.includes(c)&&!Pe(s.name)&&r.push(g.join(e,s.name))}}catch{return r}return r}function Ae(e,r=e,t=Oe,s=0,c=new Set){const f=[];if(!F.existsSync(e))return E.warn(`Directory does not exist: ${e} / 目录不存在`),f;if(s>je)return E.warn(`Max directory depth (${je}) exceeded: ${e} / 超过最大目录深度`),f;let $;try{$=F.realpathSync(e)}catch(p){const h=p;return E.warn(`Cannot resolve real path: ${e}. Reason: ${h.message} / 无法解析真实路径`),f}if(c.has($))return E.warn(`Circular reference detected, skipping: ${e} / 检测到循环引用`),f;c.add($);let u;try{u=F.readdirSync(e,{withFileTypes:!0})}catch(p){const h=p;return h.code==="EACCES"||h.code==="EPERM"?E.warn(`Permission denied: ${e} / 权限不足`):E.warn(`Failed to read directory: ${e}. Reason: ${h.message} / 读取目录失败`),f}for(const p of u)try{const h=g.join(e,p.name);if(p.isDirectory())t.includes(p.name)||f.push(...Ae(h,r,t,s+1,c));else if(p.isFile()){const o=g.extname(p.name);Fe.includes(o)&&!Pe(p.name)&&f.push(g.relative(r,h))}}catch(h){const o=h;E.warn(`Error processing entry: ${p.name}. Reason: ${o.message} / 处理条目出错`)}return f}function Y(e){if(!e)return"";const t=e.value.split(`
30
- `).map(s=>s.replace(/^\s*\*\s?/,"").trim());for(const s of t)if(s.startsWith("@description "))return s.slice(13).trim().slice(0,60);for(const s of t)if(s&&!s.startsWith("@")&&!s.startsWith("/"))return s.slice(0,60);return""}function ge(e,r){if(e.leadingComments&&e.leadingComments.length>0)return e.leadingComments[e.leadingComments.length-1]??null;if(r&&(r.type==="ExportNamedDeclaration"||r.type==="ExportDefaultDeclaration")){const t=r;if(t.leadingComments&&t.leadingComments.length>0)return t.leadingComments[t.leadingComments.length-1]??null}return null}const ve=typeof Re=="function"?Re:Re.default;function Ge(e,r){var I,v;if(e==null)return{parseError:"Code content is null or undefined / 代码内容为空",errorType:W.VALIDATION_ERROR};if(typeof e!="string")return{parseError:"Code must be a string / 代码必须是字符串类型",errorType:W.VALIDATION_ERROR};if(!e.trim())return{description:"",imports:[],functions:[],classes:[],constants:[],callGraph:{}};const t={description:"",imports:[],functions:[],classes:[],constants:[],callGraph:{}},s=e.match(/^\/\*\*[\s\S]*?\*\//);if(s){const n=s[0].split(`
31
- `).map(i=>i.replace(/^\s*\*\s?/,"").trim()).filter(i=>i&&!i.startsWith("/")&&!i.startsWith("@ai"));for(const i of n)if(i.startsWith("@description ")){t.description=i.slice(13).trim();break}if(!t.description&&n.length>0){const i=n.find(m=>!m.startsWith("@"));i&&(t.description=i)}}let c;try{const a=r&&(r.endsWith(".ts")||r.endsWith(".tsx"));c=tn.parse(e,{sourceType:"unambiguous",plugins:["jsx","classPrivateProperties","classPrivateMethods",...a?["typescript"]:[]]})}catch(a){const n=a;return{parseError:Se(W.PARSE_ERROR,`Syntax error: ${n.message} / 语法错误`,{file:r??void 0,line:(I=n.loc)==null?void 0:I.line,column:(v=n.loc)==null?void 0:v.column,suggestion:"Check syntax errors in the file / 检查文件中的语法错误"}),loc:n.loc,errorType:W.PARSE_ERROR}}const f=new Map,$=new Map,u=new Map;function p(a){if(!a)return null;if(a.type==="Identifier")return a.name;if(a.type==="MemberExpression"){const n=a.object,i=a.property;if(n.type==="Identifier"&&i.type==="Identifier")return n.name}return null}function h(a){var i,m,b;let n=a;for(;n;){if(n.node.type==="FunctionDeclaration"){const x=n.node;if(x.id)return x.id.name}if(n.node.type==="ClassMethod"){const x=n.node,R=(i=n.parentPath)==null?void 0:i.parentPath,C=R==null?void 0:R.node,j=((m=C==null?void 0:C.id)==null?void 0:m.name)??"",O=((b=x.key)==null?void 0:b.name)??"";return j?`${j}.${O}`:O}if(n.node.type==="ArrowFunctionExpression"||n.node.type==="FunctionExpression"){const x=n.parent;if((x==null?void 0:x.type)==="VariableDeclarator"){const C=x.id;if(C!=null&&C.name)return C.name}}n=n.parentPath}return null}ve(c,{VariableDeclarator(a){var i,m,b,x;const n=a.node;if(((i=n.init)==null?void 0:i.type)==="CallExpression"&&((m=n.init.callee)==null?void 0:m.type)==="Identifier"&&n.init.callee.name==="require"&&((x=(b=n.init.arguments)==null?void 0:b[0])==null?void 0:x.type)==="StringLiteral"){const R=n.init.arguments[0].value;if(f.has(R)||f.set(R,new Set),n.id.type==="Identifier"){const C=n.id.name;f.get(R).add(C),$.set(C,R),u.set(C,new Set)}else if(n.id.type==="ObjectPattern"){for(const C of n.id.properties)if(C.type==="ObjectProperty"&&C.key.type==="Identifier"){const j=C.value.type==="Identifier"?C.value.name:C.key.name;f.get(R).add(C.key.name),$.set(j,R),u.set(j,new Set)}}}},CallExpression(a){var i,m,b,x,R,C;const n=a.node;if(((i=n.callee)==null?void 0:i.type)==="Identifier"&&n.callee.name==="require"&&((b=(m=n.arguments)==null?void 0:m[0])==null?void 0:b.type)==="StringLiteral"){const j=a.parent;if((j==null?void 0:j.type)==="MemberExpression"&&((x=j.property)==null?void 0:x.type)==="Identifier"){const O=n.arguments[0].value;f.has(O)||f.set(O,new Set),f.get(O).add(j.property.name);const U=(R=a.parentPath)==null?void 0:R.parent;if((U==null?void 0:U.type)==="VariableDeclarator"){const V=U;((C=V.id)==null?void 0:C.type)==="Identifier"&&($.set(V.id.name,O),u.set(V.id.name,new Set))}}}},ImportDeclaration(a){const n=a.node,i=n.source.value;f.has(i)||f.set(i,new Set);for(const m of n.specifiers){let b,x;if(m.type==="ImportDefaultSpecifier")b="default",x=m.local.name;else if(m.type==="ImportNamespaceSpecifier")b="*",x=m.local.name;else if(m.type==="ImportSpecifier"){const R=m.imported;b=R.type==="Identifier"?R.name:R.value,x=m.local.name}b&&x&&(f.get(i).add(b),$.set(x,i),u.set(x,new Set))}}}),ve(c,{Identifier(a){const n=a.node.name;if(u.has(n)){const i=a.parent;if((i==null?void 0:i.type)==="VariableDeclarator"&&i.id===a.node||(i==null?void 0:i.type)==="ImportSpecifier"||(i==null?void 0:i.type)==="ImportDefaultSpecifier")return;const m=h(a);m&&u.get(n).add(m)}},FunctionDeclaration(a){var C,j,O,U,V;if(a.parent.type==="ExportDefaultDeclaration")return;const n=a.node,i=((C=n.id)==null?void 0:C.name)??"[anonymous]",m=n.params.map(G=>{var K,X;return G.type==="Identifier"?G.name:G.type==="AssignmentPattern"&&((K=G.left)==null?void 0:K.type)==="Identifier"?G.left.name+"?":G.type==="RestElement"&&((X=G.argument)==null?void 0:X.type)==="Identifier"?"..."+G.argument.name:"?"}),b=((O=(j=n.loc)==null?void 0:j.start)==null?void 0:O.line)??0,x=((V=(U=n.loc)==null?void 0:U.end)==null?void 0:V.line)??0,R=Y(ge(n,a.parent));t.functions.push({name:i,params:m.join(","),startLine:b,endLine:x,description:R})},ClassDeclaration(a){var j,O,U,V,G,K,X,ee,ne;if(a.parent.type==="ExportDefaultDeclaration")return;const n=a.node,i=((j=n.id)==null?void 0:j.name)??"[anonymous]",m=((U=(O=n.loc)==null?void 0:O.start)==null?void 0:U.line)??0,b=((G=(V=n.loc)==null?void 0:V.end)==null?void 0:G.line)??0,x=p(n.superClass),R=Y(ge(n,a.parent)),C=[];if((K=n.body)!=null&&K.body){for(const z of n.body.body)if(z.type==="ClassMethod"){const se=((X=z.key)==null?void 0:X.type)==="Identifier"?z.key.name:"[computed]",ie=z.params.map(H=>{var re;return H.type==="Identifier"?H.name:H.type==="AssignmentPattern"&&((re=H.left)==null?void 0:re.type)==="Identifier"?H.left.name+"?":"?"}),oe=((ne=(ee=z.loc)==null?void 0:ee.start)==null?void 0:ne.line)??0;let te="";const Z=z.leadingComments;Z&&Z.length>0&&(te=Y(Z[Z.length-1])),C.push({name:se,params:ie.join(","),line:oe,static:z.static,kind:z.kind,description:te})}}t.classes.push({name:i,superClass:x,startLine:m,endLine:b,methods:C,description:R})},VariableDeclaration(a){var b,x,R,C,j,O,U,V,G,K,X,ee,ne,z,se,ie,oe,te,Z,H,re,ce,le,fe,de,me,pe,ae,B,L,J;const n=a.parent.type;if(n!=="Program"&&n!=="ExportNamedDeclaration")return;const i=a.node,m=Y(ge(i,a.parent));for(const k of i.declarations){const _=((b=k.id)==null?void 0:b.type)==="Identifier"?k.id.name:void 0;if(_){if(((x=k.init)==null?void 0:x.type)==="ArrowFunctionExpression"||((R=k.init)==null?void 0:R.type)==="FunctionExpression"){const d=k.init.params.map(P=>{var N,q;return P.type==="Identifier"?P.name:P.type==="AssignmentPattern"&&((N=P.left)==null?void 0:N.type)==="Identifier"?P.left.name+"?":P.type==="RestElement"&&((q=P.argument)==null?void 0:q.type)==="Identifier"?"..."+P.argument.name:"?"}),A=((j=(C=i.loc)==null?void 0:C.start)==null?void 0:j.line)??0,M=((U=(O=i.loc)==null?void 0:O.end)==null?void 0:U.line)??0;t.functions.push({name:_,params:d.join(","),startLine:A,endLine:M,description:m});continue}if(((V=k.init)==null?void 0:V.type)==="ClassExpression"){const w=k.init,d=((K=(G=i.loc)==null?void 0:G.start)==null?void 0:K.line)??0,A=((ee=(X=i.loc)==null?void 0:X.end)==null?void 0:ee.line)??0,M=p(w.superClass),P=[];if((ne=w.body)!=null&&ne.body){for(const N of w.body.body)if(N.type==="ClassMethod"){const q=((z=N.key)==null?void 0:z.type)==="Identifier"?N.key.name:"[computed]",T=N.params.map(Ee=>{var Ue;return Ee.type==="Identifier"?Ee.name:Ee.type==="AssignmentPattern"&&((Ue=Ee.left)==null?void 0:Ue.type)==="Identifier"?Ee.left.name+"?":"?"}),D=((ie=(se=N.loc)==null?void 0:se.start)==null?void 0:ie.line)??0;let Q="";const ue=N.leadingComments;ue&&ue.length>0&&(Q=Y(ue[ue.length-1])),P.push({name:q,params:T.join(","),line:D,static:N.static,kind:N.kind,description:Q})}}t.classes.push({name:_,superClass:M,startLine:d,endLine:A,methods:P,description:m});continue}if(((oe=k.init)==null?void 0:oe.type)==="ObjectExpression"){const w=k.init;for(const d of w.properties)if(d.type==="ObjectMethod"){const A=((te=d.key)==null?void 0:te.type)==="Identifier"?`${_}.${d.key.name}`:`${_}.[computed]`,M=d.params.map(T=>{var D,Q;return T.type==="Identifier"?T.name:T.type==="AssignmentPattern"&&((D=T.left)==null?void 0:D.type)==="Identifier"?T.left.name+"?":T.type==="RestElement"&&((Q=T.argument)==null?void 0:Q.type)==="Identifier"?"..."+T.argument.name:"?"}),P=((H=(Z=d.loc)==null?void 0:Z.start)==null?void 0:H.line)??0,N=((ce=(re=d.loc)==null?void 0:re.end)==null?void 0:ce.line)??0;let q="";d.leadingComments&&d.leadingComments.length>0&&(q=Y(d.leadingComments[d.leadingComments.length-1])),t.functions.push({name:A,params:M.join(","),startLine:P,endLine:N,description:q})}else if(d.type==="ObjectProperty"&&((le=d.key)==null?void 0:le.type)==="Identifier"&&(((fe=d.value)==null?void 0:fe.type)==="ArrowFunctionExpression"||((de=d.value)==null?void 0:de.type)==="FunctionExpression")){const A=d.value,M=`${_}.${d.key.name}`,P=A.params.map(D=>{var Q,ue;return D.type==="Identifier"?D.name:D.type==="AssignmentPattern"&&((Q=D.left)==null?void 0:Q.type)==="Identifier"?D.left.name+"?":D.type==="RestElement"&&((ue=D.argument)==null?void 0:ue.type)==="Identifier"?"..."+D.argument.name:"?"}),N=((pe=(me=d.loc)==null?void 0:me.start)==null?void 0:pe.line)??0,q=((B=(ae=d.loc)==null?void 0:ae.end)==null?void 0:B.line)??0;let T="";d.leadingComments&&d.leadingComments.length>0&&(T=Y(d.leadingComments[d.leadingComments.length-1])),t.functions.push({name:M,params:P.join(","),startLine:N,endLine:q,description:T})}}if(i.kind==="const"&&_===_.toUpperCase()&&_.length>2){const w=((J=(L=i.loc)==null?void 0:L.start)==null?void 0:J.line)??0;t.constants.push({name:_,line:w,description:m})}}}},ExportDefaultDeclaration(a){var b,x,R,C,j,O,U,V,G,K,X,ee,ne,z,se,ie,oe,te,Z,H,re,ce,le,fe,de,me,pe,ae,B;const n=a.node,i=n.declaration,m=Y(ge(n,a.parent));if(i.type==="FunctionDeclaration"){const L=i,J=((b=L.id)==null?void 0:b.name)??"[default]",k=L.params.map(d=>{var A,M;return d.type==="Identifier"?d.name:d.type==="AssignmentPattern"&&((A=d.left)==null?void 0:A.type)==="Identifier"?d.left.name+"?":d.type==="RestElement"&&((M=d.argument)==null?void 0:M.type)==="Identifier"?"..."+d.argument.name:"?"}),_=((R=(x=n.loc)==null?void 0:x.start)==null?void 0:R.line)??0,w=((j=(C=n.loc)==null?void 0:C.end)==null?void 0:j.line)??0;t.functions.push({name:J,params:k.join(","),startLine:_,endLine:w,description:m});return}if(i.type==="ClassDeclaration"){const L=i,J=((O=L.id)==null?void 0:O.name)??"[default]",k=((V=(U=n.loc)==null?void 0:U.start)==null?void 0:V.line)??0,_=((K=(G=n.loc)==null?void 0:G.end)==null?void 0:K.line)??0,w=p(L.superClass),d=[];if((X=L.body)!=null&&X.body){for(const A of L.body.body)if(A.type==="ClassMethod"){const M=((ee=A.key)==null?void 0:ee.type)==="Identifier"?A.key.name:"[computed]",P=A.params.map(D=>{var Q;return D.type==="Identifier"?D.name:D.type==="AssignmentPattern"&&((Q=D.left)==null?void 0:Q.type)==="Identifier"?D.left.name+"?":"?"}),N=((z=(ne=A.loc)==null?void 0:ne.start)==null?void 0:z.line)??0;let q="";const T=A.leadingComments;T&&T.length>0&&(q=Y(T[T.length-1])),d.push({name:M,params:P.join(","),line:N,static:A.static,kind:A.kind,description:q})}}t.classes.push({name:J,superClass:w,startLine:k,endLine:_,methods:d,description:m});return}if(i.type==="ArrowFunctionExpression"||i.type==="FunctionExpression"){const L=i,J=L.type==="FunctionExpression"&&((se=L.id)!=null&&se.name)?L.id.name:"[default]",k=L.params.map(d=>{var A,M;return d.type==="Identifier"?d.name:d.type==="AssignmentPattern"&&((A=d.left)==null?void 0:A.type)==="Identifier"?d.left.name+"?":d.type==="RestElement"&&((M=d.argument)==null?void 0:M.type)==="Identifier"?"..."+d.argument.name:"?"}),_=((oe=(ie=n.loc)==null?void 0:ie.start)==null?void 0:oe.line)??0,w=((Z=(te=n.loc)==null?void 0:te.end)==null?void 0:Z.line)??0;t.functions.push({name:J,params:k.join(","),startLine:_,endLine:w,description:m});return}if(i.type==="ClassExpression"){const L=i,J=((H=L.id)==null?void 0:H.name)??"[default]",k=((ce=(re=n.loc)==null?void 0:re.start)==null?void 0:ce.line)??0,_=((fe=(le=n.loc)==null?void 0:le.end)==null?void 0:fe.line)??0,w=((de=L.superClass)==null?void 0:de.type)==="Identifier"?L.superClass.name:null,d=[];if((me=L.body)!=null&&me.body){for(const A of L.body.body)if(A.type==="ClassMethod"){const M=((pe=A.key)==null?void 0:pe.type)==="Identifier"?A.key.name:"[computed]",P=A.params.map(D=>{var Q;return D.type==="Identifier"?D.name:D.type==="AssignmentPattern"&&((Q=D.left)==null?void 0:Q.type)==="Identifier"?D.left.name+"?":"?"}),N=((B=(ae=A.loc)==null?void 0:ae.start)==null?void 0:B.line)??0;let q="";const T=A.leadingComments;T&&T.length>0&&(q=Y(T[T.length-1])),d.push({name:M,params:P.join(","),line:N,static:A.static,kind:A.kind,description:q})}}t.classes.push({name:J,superClass:w,startLine:k,endLine:_,methods:d,description:m})}},AssignmentExpression(a){var x,R,C,j,O,U,V,G,K,X,ee,ne,z,se,ie,oe,te,Z,H,re,ce,le,fe,de,me,pe;const n=a.node;if(a.parent.type!=="ExpressionStatement")return;const i=(x=a.parentPath)==null?void 0:x.parent;if((i==null?void 0:i.type)!=="Program")return;const m=n.left,b=n.right;if(m.type==="MemberExpression"&&((R=m.object)==null?void 0:R.type)==="Identifier"&&m.object.name==="module"&&((C=m.property)==null?void 0:C.type)==="Identifier"&&m.property.name==="exports"){const ae=Y(ge(a.parent,i));if(b.type==="FunctionExpression"||b.type==="ArrowFunctionExpression"){const B=b,L=b.type==="FunctionExpression"&&((j=b.id)!=null&&j.name)?b.id.name:"[exports]",J=B.params.map(w=>{var d,A;return w.type==="Identifier"?w.name:w.type==="AssignmentPattern"&&((d=w.left)==null?void 0:d.type)==="Identifier"?w.left.name+"?":w.type==="RestElement"&&((A=w.argument)==null?void 0:A.type)==="Identifier"?"..."+w.argument.name:"?"}),k=((U=(O=n.loc)==null?void 0:O.start)==null?void 0:U.line)??0,_=((G=(V=n.loc)==null?void 0:V.end)==null?void 0:G.line)??0;t.functions.push({name:L,params:J.join(","),startLine:k,endLine:_,description:ae});return}if(b.type==="ClassExpression"){const B=b,L=((K=B.id)==null?void 0:K.name)??"[exports]",J=((ee=(X=n.loc)==null?void 0:X.start)==null?void 0:ee.line)??0,k=((z=(ne=n.loc)==null?void 0:ne.end)==null?void 0:z.line)??0,_=p(B.superClass),w=[];if((se=B.body)!=null&&se.body){for(const d of B.body.body)if(d.type==="ClassMethod"){const A=((ie=d.key)==null?void 0:ie.type)==="Identifier"?d.key.name:"[computed]",M=d.params.map(N=>{var q;return N.type==="Identifier"?N.name:N.type==="AssignmentPattern"&&((q=N.left)==null?void 0:q.type)==="Identifier"?N.left.name+"?":"?"}),P=((te=(oe=d.loc)==null?void 0:oe.start)==null?void 0:te.line)??0;w.push({name:A,params:M.join(","),line:P,static:d.static,kind:d.kind,description:""})}}t.classes.push({name:L,superClass:_,startLine:J,endLine:k,methods:w,description:ae});return}}if(m.type==="MemberExpression"&&((Z=m.property)==null?void 0:Z.type)==="Identifier"){const ae=m.property.name;let B=!1;if(((H=m.object)==null?void 0:H.type)==="Identifier"&&m.object.name==="exports"&&(B=!0),((re=m.object)==null?void 0:re.type)==="MemberExpression"&&((ce=m.object.object)==null?void 0:ce.type)==="Identifier"&&m.object.object.name==="module"&&((le=m.object.property)==null?void 0:le.type)==="Identifier"&&m.object.property.name==="exports"&&(B=!0),B){const L=Y(ge(a.parent,i));if(b.type==="FunctionExpression"||b.type==="ArrowFunctionExpression"){const k=b.params.map(d=>{var A,M;return d.type==="Identifier"?d.name:d.type==="AssignmentPattern"&&((A=d.left)==null?void 0:A.type)==="Identifier"?d.left.name+"?":d.type==="RestElement"&&((M=d.argument)==null?void 0:M.type)==="Identifier"?"..."+d.argument.name:"?"}),_=((de=(fe=n.loc)==null?void 0:fe.start)==null?void 0:de.line)??0,w=((pe=(me=n.loc)==null?void 0:me.end)==null?void 0:pe.line)??0;t.functions.push({name:ae,params:k.join(","),startLine:_,endLine:w,description:L})}}}}});for(const[a,n]of f){const i=new Set;for(const m of $.keys())if($.get(m)===a&&u.has(m))for(const b of u.get(m))i.add(b);t.imports.push({module:a,members:Array.from(n),usedIn:Array.from(i)})}const o=new Set;for(const a of t.functions)o.add(a.name);for(const a of t.classes)for(const n of a.methods)o.add(n.name),o.add(`${a.name}.${n.name}`);const y=new Set($.keys()),l=new Map;ve(c,{CallExpression(a){var m,b;const n=a.node;let i=null;if(n.callee.type==="Identifier")i=n.callee.name;else if(n.callee.type==="MemberExpression"&&((m=n.callee.property)==null?void 0:m.type)==="Identifier"){const x=((b=n.callee.object)==null?void 0:b.type)==="Identifier"?n.callee.object.name:void 0,R=n.callee.property.name;x&&y.has(x)?i=`${x}.${R}`:i=R}if(i){const x=h(a);if(x&&x!==i){const R=o.has(i),C=y.has(i)||i.includes(".")&&y.has(i.split(".")[0]);(R||C)&&(l.has(x)||l.set(x,new Set),l.get(x).add(i))}}}}),t.callGraph={};for(const[a,n]of l)t.callGraph[a]=Array.from(n);return t.isPureType=mn(c),t}function mn(e){let r=!1;for(const t of e.program.body){switch(t.type){case"TSTypeAliasDeclaration":case"TSInterfaceDeclaration":case"TSEnumDeclaration":break;case"ImportDeclaration":t.importKind!=="type"&&t.specifiers.some(c=>c.type==="ImportSpecifier"?c.importKind!=="type":!0)&&t.specifiers.length>0&&(r=!0);break;case"ExportNamedDeclaration":if(t.exportKind==="type")break;if(t.declaration){const s=t.declaration.type;s!=="TSTypeAliasDeclaration"&&s!=="TSInterfaceDeclaration"&&(r=!0)}else t.specifiers&&t.specifiers.length>0&&t.specifiers.some(c=>c.type==="ExportSpecifier"?c.exportKind!=="type":!0)&&(r=!0);break;case"ExportDefaultDeclaration":r=!0;break;case"ExportAllDeclaration":t.exportKind!=="type"&&(r=!0);break;default:r=!0;break}if(r)break}return!r}function pn(e,r){const t=[];let s=`/*@AI ${r}`;e.description&&(s+=` - ${e.description.slice(0,50)}`),t.push(s);for(const c of e.imports){const f=Array.isArray(c.members)?c.members.join(","):"";let $=`<${c.module}:${f}`;Array.isArray(c.usedIn)&&c.usedIn.length>0&&($+=` ->${c.usedIn.join(",")}`),t.push($)}for(const c of e.classes){let f=c.name;c.superClass&&(f+=`:${c.superClass}`),f+=` ${c.startLine}-${c.endLine}`,c.description&&(f+=` ${c.description}`),t.push(f);for(const $ of c.methods){const u=$.static?" +":" .",p=$.kind==="get"?"get:":$.kind==="set"?"set:":"";let h=`${u}${p}${$.name}(${$.params}) ${$.line}`;$.description&&(h+=` ${$.description}`),t.push(h)}}for(const c of e.functions){let f=`${c.name}(${c.params}) ${c.startLine}-${c.endLine}`;c.description&&(f+=` ${c.description}`),t.push(f)}for(const c of e.constants){let f=`${c.name} ${c.line}`;c.description&&(f+=` ${c.description}`),t.push(f)}return t.push("@AI*/"),t.join(`
32
- `)}function un(e){let r=e;return r=r.replace(/\/\*@AI[\s\S]*?@AI\*\/\s*/g,""),r=r.replace(/\/\*\*[\s\S]*?@ai-context-end[\s\S]*?\*\/\s*/g,""),r=r.replace(/^\/\*\*[\s\S]*?\*\/\s*\n?/,""),r}function ke(e,r){var s,c,f;const t=[`@FNMAP ${g.basename(e)}/`];for(const{relativePath:$,info:u}of r){let h=`#${g.basename($)}`;u.description&&(h+=` ${u.description.slice(0,50)}`),t.push(h);for(const o of u.imports){const y=Array.isArray(o.members)?o.members.join(","):"";t.push(` <${o.module}:${y}`)}for(const o of u.classes){let y=` ${o.name}`;o.superClass&&(y+=`:${o.superClass}`),y+=` ${o.startLine}-${o.endLine}`,o.description&&(y+=` ${o.description}`),t.push(y);for(const l of o.methods){const I=l.static?" +":" .",v=l.kind==="get"?"get:":l.kind==="set"?"set:":"";let a=`${I}${v}${l.name}(${l.params}) ${l.line}`;l.description&&(a+=` ${l.description}`);const n=`${o.name}.${l.name}`,i=((s=u.callGraph)==null?void 0:s[n])??((c=u.callGraph)==null?void 0:c[l.name]);Array.isArray(i)&&i.length>0&&(a+=` →${i.join(",")}`),t.push(a)}}for(const o of u.functions){let y=` ${o.name}(${o.params}) ${o.startLine}-${o.endLine}`;o.description&&(y+=` ${o.description}`);const l=(f=u.callGraph)==null?void 0:f[o.name];Array.isArray(l)&&l.length>0&&(y+=` →${l.join(",")}`),t.push(y)}for(const o of u.constants){let y=` ${o.name} ${o.line}`;o.description&&(y+=` ${o.description}`),t.push(y)}}return t.push("@FNMAP"),t.join(`
33
- `)}function He(e,r){const t=["flowchart TD"],s=o=>"id_"+o.replace(/[^a-zA-Z0-9]/g,y=>`_${y.charCodeAt(0)}_`),c=o=>o.replace(/"/g,"#quot;"),f=r.functions.map(o=>o.name),$=[];for(const o of r.classes)for(const y of o.methods)$.push(`${o.name}.${y.name}`);const u=[...f,...$];if(u.length===0)return null;const p=g.basename(e,g.extname(e));t.push(` subgraph ${s(p)}["${p}"]`);for(const o of u)t.push(` ${s(o)}["${c(o)}"]`);t.push(" end");const h=r.callGraph??{};for(const[o,y]of Object.entries(h))if(Array.isArray(y)){for(const l of y)if(u.includes(l)||l.includes(".")){const I=u.includes(l)?l:l.split(".").pop();(u.includes(l)||u.some(v=>v.endsWith(I)))&&t.push(` ${s(o)} --> ${s(l)}`)}}return t.join(`
34
- `)}function Qe(e,r){const t=["flowchart TD"],s=p=>"id_"+p.replace(/[^a-zA-Z0-9]/g,h=>`_${h.charCodeAt(0)}_`),c=p=>p.replace(/"/g,"#quot;"),f=new Map,$=[];for(const{relativePath:p,info:h}of r){const o=g.basename(p,g.extname(p)),y=h.functions.map(a=>a.name),l=[];for(const a of h.classes)for(const n of a.methods)l.push(`${a.name}.${n.name}`);const I=[...y,...l];f.set(p,{fileName:o,functions:I});const v=h.callGraph??{};for(const[a,n]of Object.entries(v))if(Array.isArray(n))for(const i of n)$.push({file:p,fileName:o,caller:a,callee:i})}for(const[,{fileName:p,functions:h}]of f)if(h.length!==0){t.push(` subgraph ${s(p)}["${c(p)}"]`);for(const o of h)t.push(` ${s(p)}_${s(o)}["${c(o)}"]`);t.push(" end")}const u=new Set;for(const{fileName:p,caller:h,callee:o}of $){const y=`${s(p)}_${s(h)}`;let l=null;for(const[,{fileName:I,functions:v}]of f)if(v.includes(o)){l=`${s(I)}_${s(o)}`;break}if(!l){const I=[...f.keys()].find(v=>{var a;return((a=f.get(v))==null?void 0:a.fileName)===p});if(I){const v=f.get(I);v!=null&&v.functions.includes(o)&&(l=`${s(p)}_${s(o)}`)}}if(l){const I=`${y}-->${l}`;u.has(I)||(t.push(` ${y} --> ${l}`),u.add(I))}}return t.join(`
35
- `)}function yn(e,r){const t=(r==null?void 0:r.filePath)??null;try{const s=Ge(e,t);return s?Te(s)?{success:!1,error:s.parseError,errorType:s.errorType,loc:s.loc}:{success:!0,info:s}:{success:!1,error:"Analysis returned null / 分析返回空值",errorType:W.PARSE_ERROR}}catch(s){return{success:!1,error:`Failed to process code / 处理代码失败: ${s.message}`,errorType:W.PARSE_ERROR}}}function Ze(e){const r=ze(e);if(!r.valid)return{success:!1,error:r.error,errorType:r.errorType??W.VALIDATION_ERROR};try{const t=F.readFileSync(e,"utf-8"),s=Ge(t,e);return s?Te(s)?{success:!1,error:s.parseError,errorType:s.errorType,loc:s.loc}:{success:!0,info:s}:{success:!1,error:"Analysis returned null / 分析返回空值",errorType:W.PARSE_ERROR}}catch(t){const s=t;return{success:!1,error:Se(W.FILE_READ_ERROR,"Failed to read or process file / 读取或处理文件失败",{file:e,suggestion:s.message}),errorType:W.FILE_READ_ERROR}}}const Ve={},qe=`
36
-
37
- ## .fnmap Code Index Format
38
-
39
- The \`.fnmap\` file provides a structured code index for quick navigation. Read it before exploring code to locate target files and function line numbers.
40
-
41
- **Format Reference:**
42
-
43
- - \`#filename.js\` - Filename followed by file description
44
- - \`<module:members\` - Imported module and its members
45
- - \`funcName(params) 10-20 description →callee1,callee2\` - Function signature, line range, description, call graph
46
- - \`ClassName:SuperClass 30-100\` - Class definition with inheritance
47
- - \` .method(params) 35 →callee\` - Instance method (\`.\` prefix)
48
- - \` +staticMethod(params) 40\` - Static method (\`+\` prefix)
49
- - \`CONST_NAME 5\` - Constant definition with line number
50
-
51
- **Call Graph:** The \`→\` at the end of function/method lines indicates which functions are called (both local and imported), helping you understand code execution flow.
52
-
53
- **Note:** \`.fnmap\` files are auto-maintained by scripts and should not be manually updated.
54
-
55
- ## Code Comment Guidelines
56
-
57
- 1. Every global variable, function, class, and file module must have a **concise comment describing its purpose or functionality** - avoid describing anything else
58
- 2. When updating code, always update related comments to reflect the changes
59
- 3. Prefer encapsulating logic in functions rather than writing flat, sequential code
60
- `,We=`
26
+ `),Ce}function be(){return Ce||Ge()}const mt={get opts(){return be().opts.bind(be())},get args(){return be().args},get parse(){return be().parse.bind(be())}};function Ke(e){const r=[".fnmaprc",".fnmaprc.json"];for(const s of r){const c=g.join(e,s);if(v.existsSync(c))try{const d=v.readFileSync(c,"utf-8");if(!d.trim()){b.warn(`Config file is empty: ${s}. Using default config / 配置文件为空,使用默认配置`);continue}let E;try{E=JSON.parse(d)}catch(y){const h=y,o=Ae(U.CONFIG_ERROR,`Failed to parse config file: ${s} / 配置文件解析失败`,{file:c,line:h.lineNumber,column:h.columnNumber,suggestion:"Check JSON syntax, ensure proper quotes and commas / 检查 JSON 语法,确保引号和逗号正确"});b.warn(o);continue}const m=_e(E);if(!m.valid){b.warn(`Invalid config in ${s}: ${m.error}`);continue}return{config:E,source:s}}catch(d){const E=d,m=Ae(U.FILE_READ_ERROR,`Failed to read config file: ${s} / 配置文件读取失败`,{file:c,suggestion:E.message});b.warn(m)}}const n=g.join(e,"package.json");if(v.existsSync(n))try{const s=JSON.parse(v.readFileSync(n,"utf-8"));if(s.fnmap){const c=_e(s.fnmap);if(!c.valid)b.warn(`Invalid fnmap config in package.json: ${c.error}`);else return{config:s.fnmap,source:"package.json#fnmap"}}}catch{}return{config:null,source:null}}function Xe(e){return e?{...ke,...e,exclude:[...e.exclude??[]]}:ke}function Ue(e){return e.endsWith(".d.ts")||e.endsWith(".d.tsx")||e.endsWith(".d.mts")}function ut(e){try{return Se.execSync("git rev-parse --show-toplevel",{cwd:e,encoding:"utf-8"}).trim()}catch{return null}}function He(e,r=!1){const n=[];try{const s=ut(e);if(!s)return[];let c;if(r)c=Se.execSync("git diff --cached --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"});else{const m=Se.execSync("git diff --cached --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"}),y=Se.execSync("git diff --name-only --diff-filter=ACMR",{cwd:e,encoding:"utf-8"}),h=Se.execSync("git ls-files --others --exclude-standard",{cwd:e,encoding:"utf-8"});c=`${m}
27
+ ${y}
28
+ ${h}`}const d=c.split(`
29
+ `).map(m=>m.trim()).filter(Boolean).filter(m=>{const y=g.extname(m);return we.includes(y)&&!Ue(m)}),E=[...new Set(d)];for(const m of E){const y=g.resolve(s,m);v.existsSync(y)&&y.startsWith(g.resolve(e))&&n.push(y)}}catch{return[]}return n}function yt(e){const r=[];if(!v.existsSync(e))return r;try{const n=v.readdirSync(e,{withFileTypes:!0});for(const s of n)if(s.isFile()){const c=g.extname(s.name);we.includes(c)&&!Ue(s.name)&&r.push(g.join(e,s.name))}}catch{return r}return r}function ve(e,r=e,n=Pe,s=0,c=new Set){const d=[];if(!v.existsSync(e))return b.warn(`Directory does not exist: ${e} / 目录不存在`),d;if(s>Ne)return b.warn(`Max directory depth (${Ne}) exceeded: ${e} / 超过最大目录深度`),d;let E;try{E=v.realpathSync(e)}catch(y){const h=y;return b.warn(`Cannot resolve real path: ${e}. Reason: ${h.message} / 无法解析真实路径`),d}if(c.has(E))return b.warn(`Circular reference detected, skipping: ${e} / 检测到循环引用`),d;c.add(E);let m;try{m=v.readdirSync(e,{withFileTypes:!0})}catch(y){const h=y;return h.code==="EACCES"||h.code==="EPERM"?b.warn(`Permission denied: ${e} / 权限不足`):b.warn(`Failed to read directory: ${e}. Reason: ${h.message} / 读取目录失败`),d}for(const y of m)try{const h=g.join(e,y.name);if(y.isDirectory())n.includes(y.name)||d.push(...ve(h,r,n,s+1,c));else if(y.isFile()){const o=g.extname(y.name);we.includes(o)&&!Ue(y.name)&&d.push(g.relative(r,h))}}catch(h){const o=h;b.warn(`Error processing entry: ${y.name}. Reason: ${o.message} / 处理条目出错`)}return d}function ee(e){if(!e)return"";const n=e.value.split(`
30
+ `).map(s=>s.replace(/^\s*\*\s?/,"").trim());for(const s of n)if(s.startsWith("@description "))return s.slice(13).trim().slice(0,60);for(const s of n)if(s&&!s.startsWith("@")&&!s.startsWith("/"))return s.slice(0,60);return""}function $e(e,r){if(e.leadingComments&&e.leadingComments.length>0)return e.leadingComments[e.leadingComments.length-1]??null;if(r&&(r.type==="ExportNamedDeclaration"||r.type==="ExportDefaultDeclaration")){const n=r;if(n.leadingComments&&n.leadingComments.length>0)return n.leadingComments[n.leadingComments.length-1]??null}return null}const Fe=typeof je=="function"?je:je.default;function qe(e,r){var S,j;if(e==null)return{parseError:"Code content is null or undefined / 代码内容为空",errorType:U.VALIDATION_ERROR};if(typeof e!="string")return{parseError:"Code must be a string / 代码必须是字符串类型",errorType:U.VALIDATION_ERROR};if(!e.trim())return{description:"",imports:[],functions:[],classes:[],constants:[],exports:[],callGraph:{}};const n={description:"",imports:[],functions:[],classes:[],constants:[],exports:[],callGraph:{}},s=e.match(/^\/\*\*[\s\S]*?\*\//);if(s){const t=s[0].split(`
31
+ `).map(i=>i.replace(/^\s*\*\s?/,"").trim()).filter(i=>i&&!i.startsWith("/")&&!i.startsWith("@ai"));for(const i of t)if(i.startsWith("@description ")){n.description=i.slice(13).trim();break}if(!n.description&&t.length>0){const i=t.find(f=>!f.startsWith("@"));i&&(n.description=i)}}let c;try{const a=r&&(r.endsWith(".ts")||r.endsWith(".tsx"));c=rt.parse(e,{sourceType:"unambiguous",plugins:["jsx","classPrivateProperties","classPrivateMethods",...a?["typescript"]:[]]})}catch(a){const t=a;return{parseError:Ae(U.PARSE_ERROR,`Syntax error: ${t.message} / 语法错误`,{file:r??void 0,line:(S=t.loc)==null?void 0:S.line,column:(j=t.loc)==null?void 0:j.column,suggestion:"Check syntax errors in the file / 检查文件中的语法错误"}),loc:t.loc,errorType:U.PARSE_ERROR}}const d=new Map,E=new Map,m=new Map;function y(a){if(!a)return null;if(a.type==="Identifier")return a.name;if(a.type==="MemberExpression"){const t=a.object,i=a.property;if(t.type==="Identifier"&&i.type==="Identifier")return t.name}return null}function h(a){var i,f,I;let t=a;for(;t;){if(t.node.type==="FunctionDeclaration"){const $=t.node;if($.id)return $.id.name}if(t.node.type==="ClassMethod"){const $=t.node,u=(i=t.parentPath)==null?void 0:i.parentPath,C=u==null?void 0:u.node,D=((f=C==null?void 0:C.id)==null?void 0:f.name)??"",k=((I=$.key)==null?void 0:I.name)??"";return D?`${D}.${k}`:k}if(t.node.type==="ArrowFunctionExpression"||t.node.type==="FunctionExpression"){const $=t.parent;if(($==null?void 0:$.type)==="VariableDeclarator"){const C=$.id;if(C!=null&&C.name)return C.name}}t=t.parentPath}return null}Fe(c,{VariableDeclarator(a){var i,f,I,$;const t=a.node;if(((i=t.init)==null?void 0:i.type)==="CallExpression"&&((f=t.init.callee)==null?void 0:f.type)==="Identifier"&&t.init.callee.name==="require"&&(($=(I=t.init.arguments)==null?void 0:I[0])==null?void 0:$.type)==="StringLiteral"){const u=t.init.arguments[0].value;if(d.has(u)||d.set(u,new Set),t.id.type==="Identifier"){const C=t.id.name;d.get(u).add(C),E.set(C,u),m.set(C,new Set)}else if(t.id.type==="ObjectPattern"){for(const C of t.id.properties)if(C.type==="ObjectProperty"&&C.key.type==="Identifier"){const D=C.value.type==="Identifier"?C.value.name:C.key.name;d.get(u).add(C.key.name),E.set(D,u),m.set(D,new Set)}}}},CallExpression(a){var i,f,I,$,u,C;const t=a.node;if(((i=t.callee)==null?void 0:i.type)==="Identifier"&&t.callee.name==="require"&&((I=(f=t.arguments)==null?void 0:f[0])==null?void 0:I.type)==="StringLiteral"){const D=a.parent;if((D==null?void 0:D.type)==="MemberExpression"&&(($=D.property)==null?void 0:$.type)==="Identifier"){const k=t.arguments[0].value;d.has(k)||d.set(k,new Set),d.get(k).add(D.property.name);const M=(u=a.parentPath)==null?void 0:u.parent;if((M==null?void 0:M.type)==="VariableDeclarator"){const G=M;((C=G.id)==null?void 0:C.type)==="Identifier"&&(E.set(G.id.name,k),m.set(G.id.name,new Set))}}}},ImportDeclaration(a){const t=a.node,i=t.source.value;d.has(i)||d.set(i,new Set);for(const f of t.specifiers){let I,$;if(f.type==="ImportDefaultSpecifier")I="default",$=f.local.name;else if(f.type==="ImportNamespaceSpecifier")I="*",$=f.local.name;else if(f.type==="ImportSpecifier"){const u=f.imported;I=u.type==="Identifier"?u.name:u.value,$=f.local.name}I&&$&&(d.get(i).add(I),E.set($,i),m.set($,new Set))}}}),Fe(c,{Identifier(a){const t=a.node.name;if(m.has(t)){const i=a.parent;if((i==null?void 0:i.type)==="VariableDeclarator"&&i.id===a.node||(i==null?void 0:i.type)==="ImportSpecifier"||(i==null?void 0:i.type)==="ImportDefaultSpecifier")return;const f=h(a);f&&m.get(t).add(f)}},FunctionDeclaration(a){var C,D,k,M,G;if(a.parent.type==="ExportDefaultDeclaration")return;const t=a.node,i=((C=t.id)==null?void 0:C.name)??"[anonymous]",f=t.params.map(O=>{var K,X;return O.type==="Identifier"?O.name:O.type==="AssignmentPattern"&&((K=O.left)==null?void 0:K.type)==="Identifier"?O.left.name+"?":O.type==="RestElement"&&((X=O.argument)==null?void 0:X.type)==="Identifier"?"..."+O.argument.name:"?"}),I=((k=(D=t.loc)==null?void 0:D.start)==null?void 0:k.line)??0,$=((G=(M=t.loc)==null?void 0:M.end)==null?void 0:G.line)??0,u=ee($e(t,a.parent));n.functions.push({name:i,params:f.join(","),startLine:I,endLine:$,description:u})},ClassDeclaration(a){var D,k,M,G,O,K,X,te,ne;if(a.parent.type==="ExportDefaultDeclaration")return;const t=a.node,i=((D=t.id)==null?void 0:D.name)??"[anonymous]",f=((M=(k=t.loc)==null?void 0:k.start)==null?void 0:M.line)??0,I=((O=(G=t.loc)==null?void 0:G.end)==null?void 0:O.line)??0,$=y(t.superClass),u=ee($e(t,a.parent)),C=[];if((K=t.body)!=null&&K.body){for(const q of t.body.body)if(q.type==="ClassMethod"){const ie=((X=q.key)==null?void 0:X.type)==="Identifier"?q.key.name:"[computed]",oe=q.params.map(H=>{var se;return H.type==="Identifier"?H.name:H.type==="AssignmentPattern"&&((se=H.left)==null?void 0:se.type)==="Identifier"?H.left.name+"?":"?"}),ae=((ne=(te=q.loc)==null?void 0:te.start)==null?void 0:ne.line)??0;let re="";const Q=q.leadingComments;Q&&Q.length>0&&(re=ee(Q[Q.length-1])),C.push({name:ie,params:oe.join(","),line:ae,static:q.static,kind:q.kind,description:re})}}n.classes.push({name:i,superClass:$,startLine:f,endLine:I,methods:C,description:u})},VariableDeclaration(a){var I,$,u,C,D,k,M,G,O,K,X,te,ne,q,ie,oe,ae,re,Q,H,se,le,fe,de,pe,me,ue,ce,z,L,J,W,B;const t=a.parent.type;if(t!=="Program"&&t!=="ExportNamedDeclaration")return;const i=a.node,f=ee($e(i,a.parent));for(const w of i.declarations){const x=((I=w.id)==null?void 0:I.type)==="Identifier"?w.id.name:void 0;if(x){if((($=w.init)==null?void 0:$.type)==="ArrowFunctionExpression"||((u=w.init)==null?void 0:u.type)==="FunctionExpression"){const A=w.init.params.map(_=>{var N,T;return _.type==="Identifier"?_.name:_.type==="AssignmentPattern"&&((N=_.left)==null?void 0:N.type)==="Identifier"?_.left.name+"?":_.type==="RestElement"&&((T=_.argument)==null?void 0:T.type)==="Identifier"?"..."+_.argument.name:"?"}),Z=((D=(C=i.loc)==null?void 0:C.start)==null?void 0:D.line)??0,V=((M=(k=i.loc)==null?void 0:k.end)==null?void 0:M.line)??0;n.functions.push({name:x,params:A.join(","),startLine:Z,endLine:V,description:f});continue}if(((G=w.init)==null?void 0:G.type)==="ClassExpression"){const R=w.init,A=((K=(O=i.loc)==null?void 0:O.start)==null?void 0:K.line)??0,Z=((te=(X=i.loc)==null?void 0:X.end)==null?void 0:te.line)??0,V=y(R.superClass),_=[];if((ne=R.body)!=null&&ne.body){for(const N of R.body.body)if(N.type==="ClassMethod"){const T=((q=N.key)==null?void 0:q.type)==="Identifier"?N.key.name:"[computed]",P=N.params.map(Ie=>{var Ve;return Ie.type==="Identifier"?Ie.name:Ie.type==="AssignmentPattern"&&((Ve=Ie.left)==null?void 0:Ve.type)==="Identifier"?Ie.left.name+"?":"?"}),Y=((oe=(ie=N.loc)==null?void 0:ie.start)==null?void 0:oe.line)??0;let ye="";const ge=N.leadingComments;ge&&ge.length>0&&(ye=ee(ge[ge.length-1])),_.push({name:T,params:P.join(","),line:Y,static:N.static,kind:N.kind,description:ye})}}n.classes.push({name:x,superClass:V,startLine:A,endLine:Z,methods:_,description:f});continue}if(((ae=w.init)==null?void 0:ae.type)==="ObjectExpression"){const R=w.init;for(const A of R.properties)if(A.type==="ObjectMethod"){const Z=((re=A.key)==null?void 0:re.type)==="Identifier"?`${x}.${A.key.name}`:`${x}.[computed]`,V=A.params.map(P=>{var Y,ye;return P.type==="Identifier"?P.name:P.type==="AssignmentPattern"&&((Y=P.left)==null?void 0:Y.type)==="Identifier"?P.left.name+"?":P.type==="RestElement"&&((ye=P.argument)==null?void 0:ye.type)==="Identifier"?"..."+P.argument.name:"?"}),_=((H=(Q=A.loc)==null?void 0:Q.start)==null?void 0:H.line)??0,N=((le=(se=A.loc)==null?void 0:se.end)==null?void 0:le.line)??0;let T="";A.leadingComments&&A.leadingComments.length>0&&(T=ee(A.leadingComments[A.leadingComments.length-1])),n.functions.push({name:Z,params:V.join(","),startLine:_,endLine:N,description:T})}else if(A.type==="ObjectProperty"&&((fe=A.key)==null?void 0:fe.type)==="Identifier"&&(((de=A.value)==null?void 0:de.type)==="ArrowFunctionExpression"||((pe=A.value)==null?void 0:pe.type)==="FunctionExpression")){const Z=A.value,V=`${x}.${A.key.name}`,_=Z.params.map(Y=>{var ye,ge;return Y.type==="Identifier"?Y.name:Y.type==="AssignmentPattern"&&((ye=Y.left)==null?void 0:ye.type)==="Identifier"?Y.left.name+"?":Y.type==="RestElement"&&((ge=Y.argument)==null?void 0:ge.type)==="Identifier"?"..."+Y.argument.name:"?"}),N=((ue=(me=A.loc)==null?void 0:me.start)==null?void 0:ue.line)??0,T=((z=(ce=A.loc)==null?void 0:ce.end)==null?void 0:z.line)??0;let P="";A.leadingComments&&A.leadingComments.length>0&&(P=ee(A.leadingComments[A.leadingComments.length-1])),n.functions.push({name:V,params:_.join(","),startLine:N,endLine:T,description:P})}}if(i.kind==="const"&&!(((L=w.init)==null?void 0:L.type)==="CallExpression"&&((J=w.init.callee)==null?void 0:J.type)==="Identifier"&&w.init.callee.name==="require")){const A=((B=(W=i.loc)==null?void 0:W.start)==null?void 0:B.line)??0;n.constants.push({name:x,line:A,description:f})}}}},ExportDefaultDeclaration(a){var I,$,u,C,D,k,M,G,O,K,X,te,ne,q,ie,oe,ae,re,Q,H,se,le,fe,de,pe,me,ue,ce,z;const t=a.node,i=t.declaration,f=ee($e(t,a.parent));if(i.type==="FunctionDeclaration"){const L=i,J=((I=L.id)==null?void 0:I.name)??"[default]",W=L.params.map(x=>{var R,A;return x.type==="Identifier"?x.name:x.type==="AssignmentPattern"&&((R=x.left)==null?void 0:R.type)==="Identifier"?x.left.name+"?":x.type==="RestElement"&&((A=x.argument)==null?void 0:A.type)==="Identifier"?"..."+x.argument.name:"?"}),B=((u=($=t.loc)==null?void 0:$.start)==null?void 0:u.line)??0,w=((D=(C=t.loc)==null?void 0:C.end)==null?void 0:D.line)??0;n.functions.push({name:J,params:W.join(","),startLine:B,endLine:w,description:f});return}if(i.type==="ClassDeclaration"){const L=i,J=((k=L.id)==null?void 0:k.name)??"[default]",W=((G=(M=t.loc)==null?void 0:M.start)==null?void 0:G.line)??0,B=((K=(O=t.loc)==null?void 0:O.end)==null?void 0:K.line)??0,w=y(L.superClass),x=[];if((X=L.body)!=null&&X.body){for(const R of L.body.body)if(R.type==="ClassMethod"){const A=((te=R.key)==null?void 0:te.type)==="Identifier"?R.key.name:"[computed]",Z=R.params.map(T=>{var P;return T.type==="Identifier"?T.name:T.type==="AssignmentPattern"&&((P=T.left)==null?void 0:P.type)==="Identifier"?T.left.name+"?":"?"}),V=((q=(ne=R.loc)==null?void 0:ne.start)==null?void 0:q.line)??0;let _="";const N=R.leadingComments;N&&N.length>0&&(_=ee(N[N.length-1])),x.push({name:A,params:Z.join(","),line:V,static:R.static,kind:R.kind,description:_})}}n.classes.push({name:J,superClass:w,startLine:W,endLine:B,methods:x,description:f});return}if(i.type==="ArrowFunctionExpression"||i.type==="FunctionExpression"){const L=i,J=L.type==="FunctionExpression"&&((ie=L.id)!=null&&ie.name)?L.id.name:"[default]",W=L.params.map(x=>{var R,A;return x.type==="Identifier"?x.name:x.type==="AssignmentPattern"&&((R=x.left)==null?void 0:R.type)==="Identifier"?x.left.name+"?":x.type==="RestElement"&&((A=x.argument)==null?void 0:A.type)==="Identifier"?"..."+x.argument.name:"?"}),B=((ae=(oe=t.loc)==null?void 0:oe.start)==null?void 0:ae.line)??0,w=((Q=(re=t.loc)==null?void 0:re.end)==null?void 0:Q.line)??0;n.functions.push({name:J,params:W.join(","),startLine:B,endLine:w,description:f});return}if(i.type==="ClassExpression"){const L=i,J=((H=L.id)==null?void 0:H.name)??"[default]",W=((le=(se=t.loc)==null?void 0:se.start)==null?void 0:le.line)??0,B=((de=(fe=t.loc)==null?void 0:fe.end)==null?void 0:de.line)??0,w=((pe=L.superClass)==null?void 0:pe.type)==="Identifier"?L.superClass.name:null,x=[];if((me=L.body)!=null&&me.body){for(const R of L.body.body)if(R.type==="ClassMethod"){const A=((ue=R.key)==null?void 0:ue.type)==="Identifier"?R.key.name:"[computed]",Z=R.params.map(T=>{var P;return T.type==="Identifier"?T.name:T.type==="AssignmentPattern"&&((P=T.left)==null?void 0:P.type)==="Identifier"?T.left.name+"?":"?"}),V=((z=(ce=R.loc)==null?void 0:ce.start)==null?void 0:z.line)??0;let _="";const N=R.leadingComments;N&&N.length>0&&(_=ee(N[N.length-1])),x.push({name:A,params:Z.join(","),line:V,static:R.static,kind:R.kind,description:_})}}n.classes.push({name:J,superClass:w,startLine:W,endLine:B,methods:x,description:f})}},AssignmentExpression(a){var $,u,C,D,k,M,G,O,K,X,te,ne,q,ie,oe,ae,re,Q,H,se,le,fe,de,pe,me,ue;const t=a.node;if(a.parent.type!=="ExpressionStatement")return;const i=($=a.parentPath)==null?void 0:$.parent;if((i==null?void 0:i.type)!=="Program")return;const f=t.left,I=t.right;if(f.type==="MemberExpression"&&((u=f.object)==null?void 0:u.type)==="Identifier"&&f.object.name==="module"&&((C=f.property)==null?void 0:C.type)==="Identifier"&&f.property.name==="exports"){const ce=ee($e(a.parent,i));if(I.type==="FunctionExpression"||I.type==="ArrowFunctionExpression"){const z=I,L=I.type==="FunctionExpression"&&((D=I.id)!=null&&D.name)?I.id.name:"[exports]",J=z.params.map(w=>{var x,R;return w.type==="Identifier"?w.name:w.type==="AssignmentPattern"&&((x=w.left)==null?void 0:x.type)==="Identifier"?w.left.name+"?":w.type==="RestElement"&&((R=w.argument)==null?void 0:R.type)==="Identifier"?"..."+w.argument.name:"?"}),W=((M=(k=t.loc)==null?void 0:k.start)==null?void 0:M.line)??0,B=((O=(G=t.loc)==null?void 0:G.end)==null?void 0:O.line)??0;n.functions.push({name:L,params:J.join(","),startLine:W,endLine:B,description:ce});return}if(I.type==="ClassExpression"){const z=I,L=((K=z.id)==null?void 0:K.name)??"[exports]",J=((te=(X=t.loc)==null?void 0:X.start)==null?void 0:te.line)??0,W=((q=(ne=t.loc)==null?void 0:ne.end)==null?void 0:q.line)??0,B=y(z.superClass),w=[];if((ie=z.body)!=null&&ie.body){for(const x of z.body.body)if(x.type==="ClassMethod"){const R=((oe=x.key)==null?void 0:oe.type)==="Identifier"?x.key.name:"[computed]",A=x.params.map(V=>{var _;return V.type==="Identifier"?V.name:V.type==="AssignmentPattern"&&((_=V.left)==null?void 0:_.type)==="Identifier"?V.left.name+"?":"?"}),Z=((re=(ae=x.loc)==null?void 0:ae.start)==null?void 0:re.line)??0;w.push({name:R,params:A.join(","),line:Z,static:x.static,kind:x.kind,description:""})}}n.classes.push({name:L,superClass:B,startLine:J,endLine:W,methods:w,description:ce});return}}if(f.type==="MemberExpression"&&((Q=f.property)==null?void 0:Q.type)==="Identifier"){const ce=f.property.name;let z=!1;if(((H=f.object)==null?void 0:H.type)==="Identifier"&&f.object.name==="exports"&&(z=!0),((se=f.object)==null?void 0:se.type)==="MemberExpression"&&((le=f.object.object)==null?void 0:le.type)==="Identifier"&&f.object.object.name==="module"&&((fe=f.object.property)==null?void 0:fe.type)==="Identifier"&&f.object.property.name==="exports"&&(z=!0),z){const L=ee($e(a.parent,i));if(I.type==="FunctionExpression"||I.type==="ArrowFunctionExpression"){const W=I.params.map(x=>{var R,A;return x.type==="Identifier"?x.name:x.type==="AssignmentPattern"&&((R=x.left)==null?void 0:R.type)==="Identifier"?x.left.name+"?":x.type==="RestElement"&&((A=x.argument)==null?void 0:A.type)==="Identifier"?"..."+x.argument.name:"?"}),B=((pe=(de=t.loc)==null?void 0:de.start)==null?void 0:pe.line)??0,w=((ue=(me=t.loc)==null?void 0:me.end)==null?void 0:ue.line)??0;n.functions.push({name:ce,params:W.join(","),startLine:B,endLine:w,description:L})}}}}});for(const[a,t]of d){const i=new Set;for(const f of E.keys())if(E.get(f)===a&&m.has(f))for(const I of m.get(f))i.add(I);n.imports.push({module:a,members:Array.from(t),usedIn:Array.from(i)})}const o=new Set;for(const a of n.functions)o.add(a.name);for(const a of n.classes)for(const t of a.methods)o.add(t.name),o.add(`${a.name}.${t.name}`);const p=new Set(E.keys()),l=new Map;Fe(c,{CallExpression(a){var f,I;const t=a.node;let i=null;if(t.callee.type==="Identifier")i=t.callee.name;else if(t.callee.type==="MemberExpression"&&((f=t.callee.property)==null?void 0:f.type)==="Identifier"){const $=((I=t.callee.object)==null?void 0:I.type)==="Identifier"?t.callee.object.name:void 0,u=t.callee.property.name;$&&p.has($)?i=`${$}.${u}`:i=u}if(i){const $=h(a);if($&&$!==i){const u=o.has(i),C=p.has(i)||i.includes(".")&&p.has(i.split(".")[0]);(u||C)&&(l.has($)||l.set($,new Set),l.get($).add(i))}}}}),n.callGraph={};for(const[a,t]of l)n.callGraph[a]=Array.from(t);return Fe(c,{ExportNamedDeclaration(a){var I,$;const t=a.node,i=(($=(I=t.loc)==null?void 0:I.start)==null?void 0:$.line)??0,f=t.exportKind==="type";if(t.specifiers&&t.specifiers.length>0){for(const u of t.specifiers)if(u.type==="ExportSpecifier"){const C=u.exported.type==="Identifier"?u.exported.name:u.exported.value,D=u.local.name,k=f||u.exportKind==="type";n.exports.push({name:C,localName:D!==C?D:void 0,line:i,kind:k?"type":"value"})}return}if(t.declaration){const u=t.declaration;if(u.type==="FunctionDeclaration"&&u.id)n.exports.push({name:u.id.name,line:i,kind:"value"});else if(u.type==="ClassDeclaration"&&u.id)n.exports.push({name:u.id.name,line:i,kind:"value"});else if(u.type==="VariableDeclaration")for(const C of u.declarations)C.id.type==="Identifier"&&n.exports.push({name:C.id.name,line:i,kind:"value"});else(u.type==="TSTypeAliasDeclaration"||u.type==="TSInterfaceDeclaration")&&u.id&&n.exports.push({name:u.id.name,line:i,kind:"type"})}},ExportDefaultDeclaration(a){var $,u;const t=a.node,i=((u=($=t.loc)==null?void 0:$.start)==null?void 0:u.line)??0,f=t.declaration;let I;f.type==="FunctionDeclaration"&&f.id||f.type==="ClassDeclaration"&&f.id?I=f.id.name:f.type==="Identifier"&&(I=f.name),n.exports.push({name:"default",localName:I,line:i,kind:"default"})}}),n.isPureType=gt(c),n}function gt(e){let r=!1;for(const n of e.program.body){switch(n.type){case"TSTypeAliasDeclaration":case"TSInterfaceDeclaration":case"TSEnumDeclaration":break;case"ImportDeclaration":n.importKind!=="type"&&n.specifiers.some(c=>c.type==="ImportSpecifier"?c.importKind!=="type":!0)&&n.specifiers.length>0&&(r=!0);break;case"ExportNamedDeclaration":if(n.exportKind==="type")break;if(n.declaration){const s=n.declaration.type;s!=="TSTypeAliasDeclaration"&&s!=="TSInterfaceDeclaration"&&(r=!0)}else n.specifiers&&n.specifiers.length>0&&n.specifiers.some(c=>c.type==="ExportSpecifier"?c.exportKind!=="type":!0)&&(r=!0);break;case"ExportDefaultDeclaration":r=!0;break;case"ExportAllDeclaration":n.exportKind!=="type"&&(r=!0);break;default:r=!0;break}if(r)break}return!r}function ht(e,r){const n=[];let s=`/*@AI ${r}`;e.description&&(s+=` - ${e.description.slice(0,50)}`),n.push(s);for(const c of e.imports){const d=Array.isArray(c.members)?c.members.join(","):"";let E=`<${c.module}:${d}`;Array.isArray(c.usedIn)&&c.usedIn.length>0&&(E+=` ->${c.usedIn.join(",")}`),n.push(E)}for(const c of e.classes){let d=c.name;c.superClass&&(d+=`:${c.superClass}`),d+=` ${c.startLine}-${c.endLine}`,c.description&&(d+=` ${c.description}`),n.push(d);for(const E of c.methods){const m=E.static?" +":" .",y=E.kind==="get"?"get:":E.kind==="set"?"set:":"";let h=`${m}${y}${E.name}(${E.params}) ${E.line}`;E.description&&(h+=` ${E.description}`),n.push(h)}}for(const c of e.functions){let d=`${c.name}(${c.params}) ${c.startLine}-${c.endLine}`;c.description&&(d+=` ${c.description}`),n.push(d)}for(const c of e.constants){let d=`${c.name} ${c.line}`;c.description&&(d+=` ${c.description}`),n.push(d)}return n.push("@AI*/"),n.join(`
32
+ `)}function $t(e){let r=e;return r=r.replace(/\/\*@AI[\s\S]*?@AI\*\/\s*/g,""),r=r.replace(/\/\*\*[\s\S]*?@ai-context-end[\s\S]*?\*\/\s*/g,""),r=r.replace(/^\/\*\*[\s\S]*?\*\/\s*\n?/,""),r}function Oe(e,r){var s,c,d;const n=[`@FNMAP ${g.basename(e)}/`];for(const{relativePath:E,info:m}of r){let h=`#${g.basename(E)}`;m.description&&(h+=` ${m.description.slice(0,50)}`),n.push(h);for(const o of m.imports){const p=Array.isArray(o.members)?o.members.join(","):"";n.push(` <${o.module}:${p}`)}for(const o of m.classes){let p=` ${o.name}`;o.superClass&&(p+=`:${o.superClass}`),p+=` ${o.startLine}-${o.endLine}`,o.description&&(p+=` ${o.description}`),n.push(p);for(const l of o.methods){const S=l.static?" +":" .",j=l.kind==="get"?"get:":l.kind==="set"?"set:":"";let a=`${S}${j}${l.name}(${l.params}) ${l.line}`;l.description&&(a+=` ${l.description}`);const t=`${o.name}.${l.name}`,i=((s=m.callGraph)==null?void 0:s[t])??((c=m.callGraph)==null?void 0:c[l.name]);Array.isArray(i)&&i.length>0&&(a+=` →${i.join(",")}`),n.push(a)}}for(const o of m.functions){let p=` ${o.name}(${o.params}) ${o.startLine}-${o.endLine}`;o.description&&(p+=` ${o.description}`);const l=(d=m.callGraph)==null?void 0:d[o.name];Array.isArray(l)&&l.length>0&&(p+=` →${l.join(",")}`),n.push(p)}for(const o of m.constants){let p=` $${o.name} ${o.line}`;o.description&&(p+=` ${o.description}`),n.push(p)}if(m.exports&&m.exports.length>0){const o=[];for(const p of m.exports)p.kind==="default"?o.push(p.localName?`default:${p.localName}`:"default"):p.kind==="type"?o.push(`type:${p.name}`):o.push(p.name);n.push(` >${o.join(",")}`)}}return n.push("@FNMAP"),n.join(`
33
+ `)}function Qe(e,r){const n=["flowchart TD"],s=o=>"id_"+o.replace(/[^a-zA-Z0-9]/g,p=>`_${p.charCodeAt(0)}_`),c=o=>o.replace(/"/g,"#quot;"),d=r.functions.map(o=>o.name),E=[];for(const o of r.classes)for(const p of o.methods)E.push(`${o.name}.${p.name}`);const m=[...d,...E];if(m.length===0)return null;const y=g.basename(e,g.extname(e));n.push(` subgraph ${s(y)}["${y}"]`);for(const o of m)n.push(` ${s(o)}["${c(o)}"]`);n.push(" end");const h=r.callGraph??{};for(const[o,p]of Object.entries(h))if(Array.isArray(p)){for(const l of p)if(m.includes(l)||l.includes(".")){const S=m.includes(l)?l:l.split(".").pop();(m.includes(l)||m.some(j=>j.endsWith(S)))&&n.push(` ${s(o)} --> ${s(l)}`)}}return n.join(`
34
+ `)}function Ze(e,r){const n=["flowchart TD"],s=y=>"id_"+y.replace(/[^a-zA-Z0-9]/g,h=>`_${h.charCodeAt(0)}_`),c=y=>y.replace(/"/g,"#quot;"),d=new Map,E=[];for(const{relativePath:y,info:h}of r){const o=g.basename(y,g.extname(y)),p=h.functions.map(a=>a.name),l=[];for(const a of h.classes)for(const t of a.methods)l.push(`${a.name}.${t.name}`);const S=[...p,...l];d.set(y,{fileName:o,functions:S});const j=h.callGraph??{};for(const[a,t]of Object.entries(j))if(Array.isArray(t))for(const i of t)E.push({file:y,fileName:o,caller:a,callee:i})}for(const[,{fileName:y,functions:h}]of d)if(h.length!==0){n.push(` subgraph ${s(y)}["${c(y)}"]`);for(const o of h)n.push(` ${s(y)}_${s(o)}["${c(o)}"]`);n.push(" end")}const m=new Set;for(const{fileName:y,caller:h,callee:o}of E){const p=`${s(y)}_${s(h)}`;let l=null;for(const[,{fileName:S,functions:j}]of d)if(j.includes(o)){l=`${s(S)}_${s(o)}`;break}if(!l){const S=[...d.keys()].find(j=>{var a;return((a=d.get(j))==null?void 0:a.fileName)===y});if(S){const j=d.get(S);j!=null&&j.functions.includes(o)&&(l=`${s(y)}_${s(o)}`)}}if(l){const S=`${p}-->${l}`;m.has(S)||(n.push(` ${p} --> ${l}`),m.add(S))}}return n.join(`
35
+ `)}function xt(e,r){const n=(r==null?void 0:r.filePath)??null;try{const s=qe(e,n);return s?Me(s)?{success:!1,error:s.parseError,errorType:s.errorType,loc:s.loc}:{success:!0,info:s}:{success:!1,error:"Analysis returned null / 分析返回空值",errorType:U.PARSE_ERROR}}catch(s){return{success:!1,error:`Failed to process code / 处理代码失败: ${s.message}`,errorType:U.PARSE_ERROR}}}function Ye(e){const r=Be(e);if(!r.valid)return{success:!1,error:r.error,errorType:r.errorType??U.VALIDATION_ERROR};try{const n=v.readFileSync(e,"utf-8"),s=qe(n,e);return s?Me(s)?{success:!1,error:s.parseError,errorType:s.errorType,loc:s.loc}:{success:!0,info:s}:{success:!1,error:"Analysis returned null / 分析返回空值",errorType:U.PARSE_ERROR}}catch(n){const s=n;return{success:!1,error:Ae(U.FILE_READ_ERROR,"Failed to read or process file / 读取或处理文件失败",{file:e,suggestion:s.message}),errorType:U.FILE_READ_ERROR}}}const ze="\n\n## .fnmap Code Index Format\n\nThe `.fnmap` file provides a structured code index for quick navigation. Read it before exploring code to locate target files and function line numbers.\n\n**Format Reference:**\n\n- `#filename.js` - Filename followed by file description\n- `<module:members` - Imported module and its members\n- `funcName(params) 10-20 description →callee1,callee2` - Function signature, line range, description, call graph\n- `ClassName:SuperClass 30-100` - Class definition with inheritance\n- ` .method(params) 35 →callee` - Instance method (`.` prefix)\n- ` +staticMethod(params) 40` - Static method (`+` prefix)\n- `$constName 5` - Constant definition (`$` prefix)\n- `>export1,export2,default` - Exports (`>` prefix, supports `default`, `type:Name`)\n\n**Call Graph:** The `→` at the end of function/method lines indicates which functions are called (both local and imported), helping you understand code execution flow.\n\n**Note:** `.fnmap` files are auto-maintained by scripts and should not be manually updated.\n\n## Code Comment Guidelines\n\n1. Every global variable, function, class, and file module must have a **concise comment describing its purpose or functionality** - avoid describing anything else\n2. When updating code, always update related comments to reflect the changes\n3. Prefer encapsulating logic in functions rather than writing flat, sequential code\n",We=`
61
36
  # fnmap generated files
62
37
  .fnmap
63
38
  *.fnmap
64
39
  *.mermaid
65
40
  .fnmap.mermaid
66
- `;function Ce(e,r){return new Promise(t=>{e.question(r,s=>{t(s.trim())})})}function Ye(e,r){let t=0;const s=["node_modules",".git","dist","build",".next","coverage"];if(!F.existsSync(e))return E.warn(`Directory does not exist: ${e}`),0;const c=F.readdirSync(e,{withFileTypes:!0});for(const f of c){const $=g.join(e,f.name);if(f.isDirectory()){if(s.includes(f.name))continue;t+=Ye($,r)}else if(f.isFile()){const u=f.name;if(u===".fnmap"||u.endsWith(".fnmap")||u.endsWith(".mermaid"))try{F.unlinkSync($),E.success(`Deleted: ${g.relative(r,$)}`),t++}catch(p){const h=p;E.error(`Failed to delete ${g.relative(r,$)}: ${h.message}`)}}}return t}function gn(e,r){E.title("fnmap - Clear Generated Files"),E.info("=".repeat(50));const t=r?g.resolve(e,r):e,s=Ye(t,e);E.info("=".repeat(50)),s>0?E.success(`Cleared ${s} generated file(s)`):E.info("No generated files found")}function hn(e){const r=g.join(e,".gitignore");if(F.existsSync(r)){const t=F.readFileSync(r,"utf-8");if(t.includes("fnmap generated files")||t.includes("*.fnmap")){console.log(`${S.yellow}!${S.reset} .gitignore already contains fnmap rules`);return}F.appendFileSync(r,We)}else F.writeFileSync(r,We.trim()+`
67
- `);console.log(`${S.green}✓${S.reset} Added fnmap rules to .gitignore`)}function we(e,r){const t=g.dirname(e);if(F.existsSync(t)||F.mkdirSync(t,{recursive:!0}),F.existsSync(e)){if(F.readFileSync(e,"utf-8").includes(".fnmap Code Index Format")){console.log(`${S.yellow}!${S.reset} ${r} already contains fnmap documentation`);return}F.appendFileSync(e,qe)}else F.writeFileSync(e,qe.trim()+`
68
- `);console.log(`${S.green}✓${S.reset} Added fnmap documentation to ${r}`)}async function $n(e){const r=Ve.createInterface({input:process.stdin,output:process.stdout});console.log(`
69
- ${S.bold}fnmap - Interactive Setup${S.reset}`),console.log("=".repeat(50));try{const t=g.join(e,".fnmaprc");if(F.existsSync(t))console.log(`${S.yellow}!${S.reset} Config file already exists: .fnmaprc`);else{const y={enable:!0,include:["src/**/*.js","src/**/*.ts","src/**/*.jsx","src/**/*.tsx"],exclude:["node_modules","dist","build",".next","coverage","__pycache__",".cache"]};F.writeFileSync(t,JSON.stringify(y,null,2)),console.log(`${S.green}✓${S.reset} Created config file: .fnmaprc`)}(await Ce(r,`
70
- Add fnmap rules to .gitignore? (Y/n): `)).toLowerCase()!=="n"&&hn(e);const c=g.join(e,"CLAUDE.md"),f=g.join(e,"AGENTS.md"),$=g.join(Ve.homedir(),".claude","CLAUDE.md"),u=F.existsSync(c),p=F.existsSync(f),h=F.existsSync($);if(!(u||p))console.log(`
71
- ${S.yellow}!${S.reset} No CLAUDE.md or AGENTS.md found in project.`),(await Ce(r,"Create CLAUDE.md with fnmap documentation? (Y/n): ")).toLowerCase()!=="n"&&we(c,"CLAUDE.md");else{console.log(`
72
- ${S.bold}Select files to add fnmap documentation:${S.reset}`),console.log(`(Enter numbers separated by comma, e.g., 1,2)
73
- `);const y=[];let l=1;u&&y.push({key:String(l++),label:"Project CLAUDE.md",path:c,exists:!0}),y.push({key:String(l++),label:"User CLAUDE.md (~/.claude/CLAUDE.md)",path:$,exists:h}),p&&y.push({key:String(l++),label:"AGENTS.md",path:f,exists:!0});const I=String(l);for(const n of y){const i=n.exists?`${S.green}[exists]${S.reset}`:`${S.gray}[new]${S.reset}`;console.log(` ${n.key}. ${n.label} ${i}`)}console.log(` ${I}. Custom file path`),console.log(` 0. Skip
74
- `);const a=(await Ce(r,"Your choice: ")).split(",").map(n=>n.trim()).filter(Boolean);if(a.includes("0")||a.length===0)console.log("Skipped adding documentation to files.");else for(const n of a)if(n===I){const i=await Ce(r,"Enter custom file path: ");if(i){const m=g.isAbsolute(i)?i:g.resolve(e,i);we(m,i)}}else{const i=y.find(m=>m.key===n);i&&we(i.path,i.label)}}console.log(`
75
- `+"=".repeat(50)),console.log(`${S.green}✓${S.reset} Setup complete!`),console.log(`
76
- Run ${S.bold}fnmap${S.reset} or ${S.bold}fnmap --dir src${S.reset} to generate code index.`)}finally{r.close()}}async function en(){const e=Me();e.parse(process.argv);const r=e.opts(),t=e.args;r.log&&he(!1);const s=g.resolve(r.project);if(r.clear){const o=_e();he(!1),gn(s,r.dir),he(o);return}if(r.init){const o=_e();he(!1),await $n(s),he(o);return}const c=[...r.files??[],...t.map($e)].filter(o=>F.existsSync(o));let f=[],$=!1;if(r.changed||r.staged){const o=Xe(s,r.staged);if(o.length===0){E.info("No git changed code files detected");return}const y=new Set;for(const l of o)y.add(g.dirname(l));for(const l of y){const I=dn(l);f.push(...I)}}else if(c.length>0)$=!0,f=c.map(o=>g.isAbsolute(o)?o:g.resolve(s,o));else if(r.dir){const o=g.resolve(s,r.dir);f=Ae(o,s).map(l=>g.join(s,l))}else{const{config:o,source:y}=Je(s);if(o){if(E.info(`Using config: ${y}`),o.enable===!1){E.info("Config file has enable set to false, skipping processing");return}const l=Ke(o),I=[...Oe,...l.exclude];if(l.include&&l.include.length>0){const v=new Set;for(const a of l.include){const n=a.replace(/\/\*\*\/.*$/,"").replace(/\*\*\/.*$/,"").replace(/\/\*\..*$/,"").replace(/\*\..*$/,"");n&&v.add(n)}for(const a of v){const n=g.resolve(s,a);if(F.existsSync(n)){const i=Ae(n,s,I);f.push(...i.map(m=>g.join(s,m)))}}}}else{E.warn("No config file found. Use fnmap init to create config, or use --dir/--files to specify scope"),E.info(""),E.info("Supported config files: .fnmaprc, .fnmaprc.json, package.json#fnmap");return}}if(f.length===0){E.info("No files found to process");return}f=[...new Set(f)],E.info("=".repeat(50)),E.title("fnmap - AI Code Indexing Tool"),E.info("=".repeat(50));let u=0,p=0;const h=new Map;for(const o of f){const y=g.relative(s,o);E.info(`
77
- Analyzing: ${y}`);const l=Ze(o);if(l.success){u++;const I=l.info;if(I.isPureType){E.info("Skipped (pure type file) / 跳过纯类型文件");continue}E.success(`Imports: ${I.imports.length}, Functions: ${I.functions.length}, Classes: ${I.classes.length}, Constants: ${I.constants.length}`);const v=g.dirname(o);h.has(v)||h.set(v,[]),h.get(v).push({relativePath:y,info:I})}else p++,E.error(l.error)}if(h.size>0)if(E.info(`
78
- Generating .fnmap index...`),$)for(const[o,y]of h)for(const{relativePath:l,info:I}of y)try{const v=ke(o,[{relativePath:l,info:I}]),a=g.basename(l,g.extname(l)),n=g.join(o,`${a}.fnmap`);F.writeFileSync(n,v),E.success(g.relative(s,n))}catch(v){const a=v;E.error(`Failed to generate .fnmap for ${l}: ${a.message}`)}else for(const[o,y]of h)try{const l=ke(o,y),I=g.join(o,".fnmap");F.writeFileSync(I,l),E.success(g.relative(s,I))}catch(l){const I=l;E.error(`Failed to generate .fnmap for ${g.relative(s,o)}: ${I.message}`)}if(r.mermaid&&h.size>0){if(E.info(`
79
- Generating Mermaid call graphs...`),r.mermaid==="file"||r.mermaid===!0)for(const[o,y]of h)for(const{relativePath:l,info:I}of y)try{const v=He(l,I);if(v){const a=g.basename(l,g.extname(l)),n=g.join(o,`${a}.mermaid`);F.writeFileSync(n,v),E.success(g.relative(s,n))}}catch(v){const a=v;E.error(`Failed to generate mermaid for ${l}: ${a.message}`)}else if(r.mermaid==="project")try{const o=[];for(const[,I]of h)o.push(...I);const y=Qe(s,o),l=g.join(s,".fnmap.mermaid");F.writeFileSync(l,y),E.success(g.relative(s,l))}catch(o){const y=o;E.error(`Failed to generate project mermaid: ${y.message}`)}}E.info(`
80
- `+"=".repeat(50)),E.stats(`Complete! Analyzed: ${S.green}${u}${S.reset}, Failed: ${p>0?S.red:""}${p}${S.reset}`),E.info("=".repeat(50))}require.main===module&&en().catch(e=>{console.error(e),process.exit(1)});exports.COLORS=S;exports.DEFAULT_CONFIG=Ne;exports.DEFAULT_EXCLUDES=Oe;exports.ErrorTypes=W;exports.MAX_DIR_DEPTH=je;exports.MAX_FILE_SIZE=Le;exports.SUPPORTED_EXTENSIONS=Fe;exports.analyzeFile=Ge;exports.extractJSDocDescription=Y;exports.formatError=Se;exports.generateAiMap=ke;exports.generateFileMermaid=He;exports.generateHeader=pn;exports.generateProjectMermaid=Qe;exports.getGitChangedFiles=Xe;exports.getVersion=Be;exports.isParseError=Te;exports.isProcessFailure=sn;exports.isProcessSuccess=rn;exports.isQuietMode=_e;exports.isValidationFailure=an;exports.isValidationSuccess=on;exports.loadConfig=Je;exports.logger=E;exports.main=en;exports.mergeConfig=Ke;exports.normalizePath=$e;exports.normalizePaths=cn;exports.processCode=yn;exports.processFile=Ze;exports.program=ln;exports.removeExistingHeaders=un;exports.scanDirectory=Ae;exports.setQuietMode=he;exports.setupCLI=Me;exports.validateConfig=De;exports.validateFilePath=ze;
41
+ `;function Re(e,r){return new Promise(n=>{e.question(r,s=>{n(s.trim())})})}function et(e,r){let n=0;const s=["node_modules",".git","dist","build",".next","coverage"];if(!v.existsSync(e))return b.warn(`Directory does not exist: ${e}`),0;const c=v.readdirSync(e,{withFileTypes:!0});for(const d of c){const E=g.join(e,d.name);if(d.isDirectory()){if(s.includes(d.name))continue;n+=et(E,r)}else if(d.isFile()){const m=d.name;if(m===".fnmap"||m.endsWith(".fnmap")||m.endsWith(".mermaid"))try{v.unlinkSync(E),b.success(`Deleted: ${g.relative(r,E)}`),n++}catch(y){const h=y;b.error(`Failed to delete ${g.relative(r,E)}: ${h.message}`)}}}return n}function Et(e,r){b.title("fnmap - Clear Generated Files"),b.info("=".repeat(50));const n=r?g.resolve(e,r):e,s=et(n,e);b.info("=".repeat(50)),s>0?b.success(`Cleared ${s} generated file(s)`):b.info("No generated files found")}function It(e){const r=g.join(e,".gitignore");if(v.existsSync(r)){const n=v.readFileSync(r,"utf-8");if(n.includes("fnmap generated files")||n.includes("*.fnmap")){console.log(`${F.yellow}!${F.reset} .gitignore already contains fnmap rules`);return}v.appendFileSync(r,We)}else v.writeFileSync(r,We.trim()+`
42
+ `);console.log(`${F.green}✓${F.reset} Added fnmap rules to .gitignore`)}function De(e,r){const n=g.dirname(e);if(v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),v.existsSync(e)){if(v.readFileSync(e,"utf-8").includes(".fnmap Code Index Format")){console.log(`${F.yellow}!${F.reset} ${r} already contains fnmap documentation`);return}v.appendFileSync(e,ze)}else v.writeFileSync(e,ze.trim()+`
43
+ `);console.log(`${F.green}✓${F.reset} Added fnmap documentation to ${r}`)}async function bt(e){const r=at.createInterface({input:process.stdin,output:process.stdout});console.log(`
44
+ ${F.bold}fnmap - Interactive Setup${F.reset}`),console.log("=".repeat(50));try{const n=g.join(e,".fnmaprc");if(v.existsSync(n))console.log(`${F.yellow}!${F.reset} Config file already exists: .fnmaprc`);else{const p={enable:!0,include:["src/**/*.js","src/**/*.ts","src/**/*.jsx","src/**/*.tsx"],exclude:["node_modules","dist","build",".next","coverage","__pycache__",".cache"]};v.writeFileSync(n,JSON.stringify(p,null,2)),console.log(`${F.green}✓${F.reset} Created config file: .fnmaprc`)}(await Re(r,`
45
+ Add fnmap rules to .gitignore? (Y/n): `)).toLowerCase()!=="n"&&It(e);const c=g.join(e,"CLAUDE.md"),d=g.join(e,"AGENTS.md"),E=g.join(st.homedir(),".claude","CLAUDE.md"),m=v.existsSync(c),y=v.existsSync(d),h=v.existsSync(E);if(!(m||y))console.log(`
46
+ ${F.yellow}!${F.reset} No CLAUDE.md or AGENTS.md found in project.`),(await Re(r,"Create CLAUDE.md with fnmap documentation? (Y/n): ")).toLowerCase()!=="n"&&De(c,"CLAUDE.md");else{console.log(`
47
+ ${F.bold}Select files to add fnmap documentation:${F.reset}`),console.log(`(Enter numbers separated by comma, e.g., 1,2)
48
+ `);const p=[];let l=1;m&&p.push({key:String(l++),label:"Project CLAUDE.md",path:c,exists:!0}),p.push({key:String(l++),label:"User CLAUDE.md (~/.claude/CLAUDE.md)",path:E,exists:h}),y&&p.push({key:String(l++),label:"AGENTS.md",path:d,exists:!0});const S=String(l);for(const t of p){const i=t.exists?`${F.green}[exists]${F.reset}`:`${F.gray}[new]${F.reset}`;console.log(` ${t.key}. ${t.label} ${i}`)}console.log(` ${S}. Custom file path`),console.log(` 0. Skip
49
+ `);const a=(await Re(r,"Your choice: ")).split(",").map(t=>t.trim()).filter(Boolean);if(a.includes("0")||a.length===0)console.log("Skipped adding documentation to files.");else for(const t of a)if(t===S){const i=await Re(r,"Enter custom file path: ");if(i){const f=g.isAbsolute(i)?i:g.resolve(e,i);De(f,i)}}else{const i=p.find(f=>f.key===t);i&&De(i.path,i.label)}}console.log(`
50
+ `+"=".repeat(50)),console.log(`${F.green}✓${F.reset} Setup complete!`),console.log(`
51
+ Run ${F.bold}fnmap${F.reset} or ${F.bold}fnmap --dir src${F.reset} to generate code index.`)}finally{r.close()}}async function tt(){const e=Ge();e.parse(process.argv);const r=e.opts(),n=e.args;r.log&&xe(!1);const s=g.resolve(r.project);if(r.clear){const o=Te();xe(!1),Et(s,r.dir),xe(o);return}if(r.init){const o=Te();xe(!1),await bt(s),xe(o);return}const c=[...r.files??[],...n.map(Ee)].filter(o=>v.existsSync(o));let d=[],E=!1;if(r.changed||r.staged){const o=He(s,r.staged);if(o.length===0){b.info("No git changed code files detected");return}const p=new Set;for(const l of o)p.add(g.dirname(l));for(const l of p){const S=yt(l);d.push(...S)}}else if(c.length>0)E=!0,d=c.map(o=>g.isAbsolute(o)?o:g.resolve(s,o));else if(r.dir){const o=g.resolve(s,r.dir);d=ve(o,s).map(l=>g.join(s,l))}else{const{config:o,source:p}=Ke(s);if(o){if(b.info(`Using config: ${p}`),o.enable===!1){b.info("Config file has enable set to false, skipping processing");return}const l=Xe(o),S=[...Pe,...l.exclude];if(l.include&&l.include.length>0){const j=new Set;for(const a of l.include){const t=a.replace(/\/\*\*\/.*$/,"").replace(/\*\*\/.*$/,"").replace(/\/\*\..*$/,"").replace(/\*\..*$/,"");t&&j.add(t)}for(const a of j){const t=g.resolve(s,a);if(v.existsSync(t)){const i=ve(t,s,S);d.push(...i.map(f=>g.join(s,f)))}}}}else{b.warn("No config file found. Use fnmap init to create config, or use --dir/--files to specify scope"),b.info(""),b.info("Supported config files: .fnmaprc, .fnmaprc.json, package.json#fnmap");return}}if(d.length===0){b.info("No files found to process");return}d=[...new Set(d)],b.info("=".repeat(50)),b.title("fnmap - AI Code Indexing Tool"),b.info("=".repeat(50));let m=0,y=0;const h=new Map;for(const o of d){const p=g.relative(s,o);b.info(`
52
+ Analyzing: ${p}`);const l=Ye(o);if(l.success){m++;const S=l.info;if(S.isPureType){b.info("Skipped (pure type file) / 跳过纯类型文件");continue}if(!(S.functions.length>0||S.classes.length>0||S.constants.length>0||S.exports&&S.exports.length>0)){b.info("Skipped (empty file) / 跳过空文件");continue}b.success(`Imports: ${S.imports.length}, Functions: ${S.functions.length}, Classes: ${S.classes.length}, Constants: ${S.constants.length}`);const a=g.dirname(o);h.has(a)||h.set(a,[]),h.get(a).push({relativePath:p,info:S})}else y++,b.error(l.error)}if(h.size>0)if(b.info(`
53
+ Generating .fnmap index...`),E)for(const[o,p]of h)for(const{relativePath:l,info:S}of p)try{const j=Oe(o,[{relativePath:l,info:S}]),a=g.basename(l,g.extname(l)),t=g.join(o,`${a}.fnmap`);v.writeFileSync(t,j),b.success(g.relative(s,t))}catch(j){const a=j;b.error(`Failed to generate .fnmap for ${l}: ${a.message}`)}else for(const[o,p]of h)try{const l=Oe(o,p),S=g.join(o,".fnmap");v.writeFileSync(S,l),b.success(g.relative(s,S))}catch(l){const S=l;b.error(`Failed to generate .fnmap for ${g.relative(s,o)}: ${S.message}`)}if(r.mermaid&&h.size>0){if(b.info(`
54
+ Generating Mermaid call graphs...`),r.mermaid==="file"||r.mermaid===!0)for(const[o,p]of h)for(const{relativePath:l,info:S}of p)try{const j=Qe(l,S);if(j){const a=g.basename(l,g.extname(l)),t=g.join(o,`${a}.mermaid`);v.writeFileSync(t,j),b.success(g.relative(s,t))}}catch(j){const a=j;b.error(`Failed to generate mermaid for ${l}: ${a.message}`)}else if(r.mermaid==="project")try{const o=[];for(const[,S]of h)o.push(...S);const p=Ze(s,o),l=g.join(s,".fnmap.mermaid");v.writeFileSync(l,p),b.success(g.relative(s,l))}catch(o){const p=o;b.error(`Failed to generate project mermaid: ${p.message}`)}}b.info(`
55
+ `+"=".repeat(50)),b.stats(`Complete! Analyzed: ${F.green}${m}${F.reset}, Failed: ${y>0?F.red:""}${y}${F.reset}`),b.info("=".repeat(50))}require.main===module&&tt().catch(e=>{console.error(e),process.exit(1)});exports.COLORS=F;exports.DEFAULT_CONFIG=ke;exports.DEFAULT_EXCLUDES=Pe;exports.ErrorTypes=U;exports.MAX_DIR_DEPTH=Ne;exports.MAX_FILE_SIZE=Le;exports.SUPPORTED_EXTENSIONS=we;exports.analyzeFile=qe;exports.extractJSDocDescription=ee;exports.formatError=Ae;exports.generateAiMap=Oe;exports.generateFileMermaid=Qe;exports.generateHeader=ht;exports.generateProjectMermaid=Ze;exports.getGitChangedFiles=He;exports.getVersion=Je;exports.isParseError=Me;exports.isProcessFailure=lt;exports.isProcessSuccess=ct;exports.isQuietMode=Te;exports.isValidationFailure=dt;exports.isValidationSuccess=ft;exports.loadConfig=Ke;exports.logger=b;exports.main=tt;exports.mergeConfig=Xe;exports.normalizePath=Ee;exports.normalizePaths=pt;exports.processCode=xt;exports.processFile=Ye;exports.program=mt;exports.removeExistingHeaders=$t;exports.scanDirectory=ve;exports.setQuietMode=xe;exports.setupCLI=Ge;exports.validateConfig=_e;exports.validateFilePath=Be;
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAmRA;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmP1C"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAoRA;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA6P1C"}
@@ -59,6 +59,12 @@ export interface ConstantInfo {
59
59
  line: number;
60
60
  description: string;
61
61
  }
62
+ export interface ExportInfo {
63
+ name: string;
64
+ localName?: string;
65
+ line: number;
66
+ kind: 'value' | 'type' | 'default';
67
+ }
62
68
  export type CallGraph = Record<string, string[]>;
63
69
  export interface FileInfo {
64
70
  description: string;
@@ -66,6 +72,7 @@ export interface FileInfo {
66
72
  functions: FunctionInfo[];
67
73
  classes: ClassInfo[];
68
74
  constants: ConstantInfo[];
75
+ exports: ExportInfo[];
69
76
  callGraph: CallGraph;
70
77
  isPureType?: boolean;
71
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU;;;;;;;;CAQb,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAIrE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,IAAI,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAIrE,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAID,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,aAAa,CAAC;IAC/C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAEjD,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,gBAAgB,CAAC;AAIxD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,cAAc,CAAC;AAI5D,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACvC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAGD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,WAAW,EAAE,OAAO,CAAC;CACtB;AAID,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;CAChB;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,gBAAgB,CAE9E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,cAAc,CAEhF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,cAAc,CAEhF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,IAAI,iBAAiB,CAEzF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,IAAI,iBAAiB,CAEzF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@didnhdj/fnmap",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "AI code indexing tool for analyzing JS/TS code structure and generating structured code maps to help AI understand code quickly",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",