语言支持与 API 保真度
codeknit 提取语法时无需运行编译器、评估宏或加载项目依赖。下表描述的是已测试的构造,而非完整的语言符合性或跨文件名称解析的保证。
每种语言在 internal/plugin/api_fidelity_test.go 中都有一个精确的基本参数/返回签名断言。声明覆盖率也在 internal/plugin/coverage_test.go 和各语言测试包中进行检查。
| 语言 | 扩展名 | 签名基准 | 声明和容器覆盖率 |
|---|---|---|---|
| C | .c, .h |
定义和原型中的命名参数和返回类型 | 结构体、联合体、枚举、类型定义、宏;头文件保护内的声明 |
| C++ | .cpp, .cc, .cxx, .hpp, .hxx, .h |
函数、原型和方法声明中的命名参数和返回类型 | 类、结构体、方法、命名空间、模板;头文件保护和 extern "C" 包装 |
| C# | .cs |
命名类型参数和显式返回类型 | 类、结构体、接口、方法、字段、委托、命名空间 |
| Go | .go |
分组、未命名、可变、函数类型和泛型参数;命名/多返回值;泛型接收者 | 带有类型和标签的结构体字段、嵌入字段、接口方法签名、类型参数、包 |
| Java | .java |
命名类型参数和显式返回类型 | 类、接口、构造函数、方法、字段、嵌套类、包 |
| JavaScript | .js, .jsx, .mjs, .cjs |
命名参数;无推断返回类型 | 函数、箭头函数、类、字段、方法、包含 JSX 的声明 |
| PHP | .php |
命名类型参数和显式返回类型 | 类、接口、特征、枚举、方法、属性、命名空间 |
| Python | .py, .pyi |
注解、默认值、*args、**kwargs、位置/关键字分隔符、返回注解 |
函数、类、嵌套类、装饰方法;常规绑定接收者被省略 |
| Ruby | .rb |
命名参数;无推断返回类型 | 类、模块、实例/单例方法、常量 |
| Rust | .rs |
类型模式、self/&self/&mut self、可变绑定、显式返回类型 |
内联和嵌套模块、命名结构体字段、特征方法和实现方法 |
| Scala | .scala, .sc |
命名类型参数和显式返回类型 | 类、特征、对象、方法、枚举、包 |
| TypeScript | .ts, .tsx, .mts, .cts |
命名类型参数和显式返回注解 | 函数、箭头函数、接口、类、字段、命名空间;TSX 使用其自身的语法 |
头文件语言选择
Section titled “头文件语言选择”所有处理源代码的 CLI 命令均接受 --header-language c|cpp 参数。该选择仅适用于 .h 文件。其他扩展名保留其通常的解析器。
codeknit parse ./src --header-language cppcodeknit fingerprint ./src --header-language ccodeknit graph analyze ./src --header-language cpp默认值为 c,以保留 C 宏、类型定义和联合体的提取。对于命名为 .h 的 C++ 头文件,请使用 cpp;命名为 .hpp 和 .hxx 的文件已默认使用 C++。该选择是显式的,因为两种语法都可以接受对方语言的部分语法,而无需提取其完整结构。
头文件保护和条件分支在不评估其条件的情况下被遍历。因此,结果可能包含来自互斥分支的声明。宏展开、包含解析和构建标志不适用。TUI 对 .h 文件使用默认的 C 选择。
保持 API 形状
Section titled “保持 API 形状”例如,Go:
func Pair(a, b int, rest ...string) (string, error)生成:
Pair(a: int, b: int, rest: ...string) -> (string, error)Go 接口方法和 Go/Rust 命名字段在正常和 fingerprint 模式下均显示为符号。方法和字段保留其所属类型。嵌套的 Rust 模块保留限定名称,如 service.storage.read,即使另一个模块声明了同名函数。
Rust 允许字段和方法同名。字段作用域名称在内部带有 #field 后缀,以便其 ID 和包含边保持不同;显示名称和签名保留原始字段名称。
Python 签名保留注解、默认值、可变参数和调用约定分隔符。常规的第一个 self 或 cls 参数在绑定方法中被省略,但在自由函数或静态方法中保留。
多行签名在 JSON 中保留源代码换行符。SKT 将换行符转义为 \n 和 \r,以便每个符号保持在一行物理输出行中。
关系保留接收者限定和词法所有权。相对导入和重命名的 JavaScript/TypeScript 及 Python 导入提供目标上下文。Go 和 Java 包声明可以在同一目录下的文件之间解析。未匹配的导入不会回退到无关声明,竞争候选项仍然保持模糊。
本地接收者绑定优先于命名空间导入,包括当参数遮蔽导入的命名空间时。Python 包导入考虑包的 __init__ 模块中的声明,而非任意后代模块。无法从该模块确定的重新导出仍然未解析。
Java、C++、C#、Scala 和 TypeScript 可调用提取保留声明字节范围,以便重载体可以有不同的调用者和别名作用域,包括同一行上的声明。选择重载目标仍然保守。Java、C++、C#、Scala 和 TypeScript 中的显式覆盖关系查找最近的继承声明;缺少基类、循环或竞争候选项保留不确定性,而非产生自链接。
这是基于语法的分析,而非编译器或运行时调用图。裸 JavaScript 包说明符、包重新导出、构建配置、复杂接收者类型和动态调度可能仍然未解析。存储库中其他位置的唯一名称不足以证明依赖关系。
JSON 保留不确定的边,标记为 resolution: "unresolved" 或 "ambiguous",并在可用时包含候选 ID。这些边没有目标 ShortID。
SKT 对所有关系使用相同的边表示法,并带有可选的解析标记:
S8 --references--> S5S10 --references[unresolved]--> string, boolS11 --calls[ambiguous]--> Helper [candidates=S12, S15]已知端点和候选项使用 ShortID,包括未解析关系的端点。没有符号的裸不确定目标是相对于源文件的名称。看起来像 ShortID 的字面名称和其他复杂标识使用带引号的完整 ID 以避免歧义。具有相同源、类型、解析和候选集的边共享一个目标列表。SKT 阅读器保留解析和候选项,包括对后续输出块中符号的引用。精简输出对关系类型进行编码,同时保持解析标记的可读性。
C/C++ 包含具有显式的 meta/file 和 meta/include 符号。头文件拼写在符号列表中仅出现一次;边使用其 ShortID:
[symbols]## src/main.cS1 meta/file L1-L4 main.cS2 meta/include L1-L1 "config.h" {resolution=unresolved}S3 meta/include L2-L2 "utils.h" {resolution=unresolved}S4 meta/include L3-L3 <stdio.h> {resolution=unresolved}
[edges]S1 --references[unresolved]--> S2, S3, S4包含符号描述的是书写的指令,而非已解析的头文件声明。同一文件内的重复包含共享一个端点。文件/包含元数据被排除在依赖排名和死代码发现之外;添加 ID 并不意味着通过编译器的包含搜索配置找到了头文件。
依赖度量和 HTML 图链接仅使用已解析的边。报告显示排除的关系计数,HTML 图显示不确定性计数。扇入和扇出计算不同的邻居数量。继承分析考虑所有基类和接口;循环继承没有报告深度。可达性从命名的 main、Main 或 init 可调用开始,并沿依赖边传递。到达成员使其容器相关,而不使每个兄弟成员可达。如果没有识别的入口点,则省略可达性发现。
回调参数和返回的可调用对象是引用,而非调用证明。别名解析保留文件、函数和对象标识;冲突的赋值保持不确定。图发现是审查候选项:外部调用者和动态行为可能改变结果。基于目录的层规则和变更传播权重是启发式的,而非测量概率。
- 复杂的 C/C++ 指针、引用、数组和函数指针声明器可能仍然具有不完整的签名。宏生成的声明不会被展开。
- TypeScript/JavaScript 构造函数处理和某些可选、剩余或解构参数形式不完整。
- 超出测试用例的高级泛型约束和类型形式因语言而异。不会推断返回类型。
- Rust 宏不会被展开。记录外联模块声明;必须在扫描中包含其文件。元组字段、枚举变体详情和关联项具有部分覆盖率。
- 语法提取无法以编译器的精度解析动态调度、重载、导入依赖或构建配置语义。
- 部分语法错误可能仍然会遗漏声明。在应用重构之前,请检查报告的警告并验证源代码。
更完整的提取会改变符号计数和 ShortID。升级时请重新生成现有的 skeleton 输出,而不要与旧输出混合。