@nudojs/parser
parser 包负责源代码解析和指令提取。产出 Babel 兼容的 AST 以及供求值器使用的结构化指令数据。
parse
parse(source: string, opts?: { errorRecovery?: boolean }): File
将 JavaScript/TypeScript 源码解析为 Babel File AST,再对其执行 stripTypes——返回的 AST 不含任何 TS 专有节点,因此 .ts 输入在所有下游消费方(求值器、analyzer、LSP)零接线即可工作。
固定 Babel 选项:sourceType: "module"、plugins: ["typescript", "jsx"]、attachComment: true(指令提取需要)。
opts.errorRecovery 启用 Babel 错误恢复模式,供尽力而为的解析使用(例如对老 CJS 使用现场文件的 collectCallRecords);默认 false,语法错误快速失败。
返回: Babel File 节点(根 AST),TS 专有语法已原地剥除。
stripTypes
stripTypes<T extends Node>(ast: T): T
从 Babel AST 中原地剥除 TS 专有语法并返回同一棵树——不重写任何 loc/start/end,兄弟节点顺序保持不变(@nudo:case 注释按 comment loc 对齐)。parse() 已无条件执行此 pass,只有当你自己用 @babel/parser 解析时才需要直接调用。
剥除/解包内容:类型断言(as、satisfies、<T>x、x!)解包为内层表达式;interface、类型别名、declare 语句、TS enum、type-only import/export 删除;参数/返回类型注解与类型参数列表丢弃。enum 成员引用会退化为 unknown-global 诊断——求值器没有 enum 求值语义。非 declare 的 namespace 和 import x = require(...) 保留原样,求值为 unknown。
指令类型
指令从注释中提取,使用 @nudo: 命名空间。函数级指令来自顶层语句的前导块注释;文件级与行内指令来自行注释(见 extractFileDirectives / extractInlineDirectives)。
Directive 联合类型涵盖五种函数级指令:
type Directive =
| CaseDirective
| MockDirective
| PureDirective
| SkipDirective
| SampleDirective;
CaseDirective
type CaseDirective = {
kind: "case";
name: string;
argsAbs: Abs[];
expected?: Abs;
commentLine?: number;
}
调试见证用例,带输入参数(约束构建器 + 具体字面量)。可选 expected 用于 nudo test 返回类型断言。
MockDirective
type MockDirective = {
kind: "mock";
name: string;
expression?: string; // 行内表达式(原始文本)
fromPath?: string; // mock 模块路径
arrowFn?: { params: string[]; body: Node; paramPatterns: Node[] }; // 解析后的行内箭头函数
sinonExpr?: SinonExpression; // stub()/spy()/mock() 表达式
nudoMock?: MockHelper; // 解析后的 mock-helper 形态(来自 @nudojs/core)
}
将某绑定替换为感知 Abs 的 mock 实现。行内箭头函数(@nudo:mock fetch = (url) => ({ ok: true }))解析进 arrowFn;sinon 风格与 stub() 风格表达式统一归一化为 nudoMock(@nudojs/core 的 MockHelper)。
SinonExpression
type SinonExpression = {
type: "stub" | "spy" | "mock";
returnValue?: Abs;
resolvedValue?: Abs;
rejectedValue?: Abs;
}
@nudo:mock 的 sinon 风格形态(@nudo:mock fetch = sinon.stub().resolves({...})),从 stub()/spy()/mock() 前缀归一化而来。
PureDirective
type PureDirective = { kind: "pure" }
标记函数为纯函数,启用记忆化。
SkipDirective
type SkipDirective = {
kind: "skip";
returns?: Abs;
}
跳过求值;使用 returns 或已有类型注解。
SampleDirective
type SampleDirective = {
kind: "sample";
count: number;
}
请求的循环迭代次数。仅为源码兼容而解析,analyzer 不消费——循环求值走有界展开,此指令对输出无效果。
FileDirective
文件顶部(任何语句之前)的行注释,对文件内所有函数生效:
type FileDirective = EnvDirective | MockModuleDirective;
type EnvDirective = {
kind: "env";
envs: string[]; // 具名或基于路径的 env,逗号分隔
}
type MockModuleDirective = {
kind: "mock-module";
source: string; // 要替换的 import 说明符
fromPath: string; // 提供 mock 模块的文件
names?: string[]; // 部分形态:只 mock 这些导出
}
InlineDirective
附着在内部语句或表达式上的行注释:
type InlineDirective = AsDirective | ReplaceDirective;
type AsDirective = {
kind: "as";
typeAbs: Abs; // 假设类型:// @nudo:as string
}
type ReplaceDirective = {
kind: "replace";
targetSource: string; // 要覆盖的表达式文本
typeAbs: Abs; // 替换类型
}
FunctionWithDirectives
type FunctionWithDirectives = {
node: Node; // Babel AST node (function declaration/expression)
name: string; // function name
directives: Directive[];
}
顶层函数及其关联指令。
extractDirectives
extractDirectives(ast: Node): FunctionWithDirectives[]
从顶层语句的前导块注释中提取 @nudo:* 指令。仅包含至少有一条指令的语句。支持:
FunctionDeclarationExportDefaultDeclaration(内含 FunctionDeclaration)VariableDeclaration(第一个声明)
返回: 函数及其指令的数组,每个带标注的语句对应一项。
extractFileDirectives
extractFileDirectives(ast: Node): FileDirective[]
从 AST 的顶层行注释提取文件级指令:/// @nudo:env(一个或多个逗号分隔的 env)与 /// @nudo:mock-module "source" from "path"(部分 mock 可带 { a, b } 名单)。非 File 节点返回空数组。
示例:
/// @nudo:env node, ./nudo-harvest-node.ts
extractInlineDirectives
extractInlineDirectives(node: Node): InlineDirective[]
从附着在单个节点上的行注释提取 @nudo:as 与 @nudo:replace 指令——agent 侧类型假设(nudo.whatIf 注入 // @nudo:as <type> 行)背后的机制。注释必须独占一行、位于语句上方(同一行的行尾注释不算该节点的前导注释);其余注释类型被忽略。
示例:
// @nudo:as string()
const y = f(x);
parseCaseArgExpr
parseCaseArgExpr(expr: string): Abs
把指令类型表达式解析为 Abs——产品文法是约束构建器 + 具体字面量 + 结构字面量。用于 @nudo:case 实参、@nudo:as/@nudo:replace、mock 返回值与 @nudo:skip 返回表达式。
支持形式(按优先级):
- 约束表达式(主文法):
number()、number().gt(0)、lit(...)、union(…)、shape({…})、array(…)、fn({…}, …)、and、partial/pick/omit/record/required/readonly/nonNullable - 裸字面量:
true、false、null、undefined、数字、带引号字符串 - 函数:箭头表达式(
(x) => x + 1)与function(x) { ... }——解析为真实的函数 Abs - JSON 风格:
{ "key": value }、[a, b, c]
返回: 解析得到的 Abs,无法识别的表达式返回 unknown。