Skip to content

castFromAst / castAllFromAst ​

把 TypeScript 源码静态解析成 IR 节点,不执行用户代码。

类型签名 ​

typescript
interface AstCastOptions {
  fileName?: string;
  onUnknown?: "raw" | "fallback" | "throw"; // 默认 'raw'
  resolver?: AstResolver; // 跨文件解析器
  sourceFile?: ts.SourceFile; // 内部复用
  zodRoots?: string[]; // 默认 ['z']
}

function castFromAst(
  source: string,
  exportName: string,
  opts?: AstCastOptions,
): IRNode;

function castAllFromAst(
  source: string,
  opts?: AstCastOptions,
): Array<{ name: string; ir: IRNode }>;

行为 ​

入口识别 ​

  • export const X = ... ✅
  • export let X = ... ✅
  • export { X } ✅(若 X 在文件内定义)
  • export type X、export interface X、export function X ❌(跳过)

支持的 schema 形态 ​

  • 13 种原语:z.string/number/bigint/boolean/date/symbol/undefined/null/void/any/unknown/never/nan
  • 9 种集合:z.array/set/object/tuple/record/map
  • 字面量与枚举:z.literal/enum/nativeEnum
  • 联合与交集:z.union/discriminatedUnion/intersection
  • 高级:z.lazy/promise/function/pipe
  • 修饰符链:optional/nullable/nullish/default/catch/brand/readonly/prefault
  • 约束链:min/max/length/regex/email/url/int/positive/...
  • z.coerce.* 5 种
  • 跨文件 import + spread .shape
  • 包装函数内联(单层)

onUnknown 处理 ​

取值行为
'raw' (默认)返回 RawNode,带 reason 字段说明原因
'fallback'返回 FallbackNode
'throw'抛出错误

AstResolver 接口 ​

AstResolver 是 ModuleResolver 的视图接口:

typescript
interface AstResolver {
  resolveSchema(
    specifier: string,
    exportName: string,
    fromFile: string,
    opts?: AstCastOptions,
  ): IRNode | { kind: "circular" } | undefined;

  resolveSpreadShape(
    baseExpr: ts.Expression,
    fromFile: string,
    opts?: AstCastOptions,
  ): ObjectField[] | undefined;

  resolveIdentifier(
    name: string,
    fromFile: string,
    fromSource: ts.SourceFile,
    opts?: AstCastOptions,
  ): IRNode | undefined;
}

用 makeAstResolver(moduleResolver) 构造实例。

示例 ​

单 export ​

typescript
const ir = castFromAst(
  `export const User = z.object({ id: z.number() });`,
  "User",
);
// ir.kind === 'object'

全部 export ​

typescript
const src = `
  export const A = z.string();
  export const B = z.number().int();
  const _internal = z.any();
  export type T = typeof A;
`;
const results = castAllFromAst(src);
// [{ name: 'A', ir: ... }, { name: 'B', ir: ... }]
// _internal 和 T 不在结果里

跨文件 + 自定义 onUnknown ​

typescript
import {
  ModuleResolver,
  makeAstResolver,
  castFromAst,
} from "@zod-codepen/core";

const resolver = new ModuleResolver(process.cwd());
const ir = castFromAst(source, "User", {
  resolver: makeAstResolver(resolver),
  onUnknown: "throw",
});

与 castFromZod 的差异 ​

维度castFromZodcastFromAst
输入运行时 Zod 对象TS 源码字符串
需要 import 用户代码是否
支持重运行时依赖否(导入会失败)是
版本中立通过 adapter完全中立
性能直接读对象,快编译 AST,约 50ms 启动
不识别的 schema返回 z.unknown() 字符串RawNode 或抛错

两条路径都产出相同的 IRNode 结构,可互换地喂给 codegen。

错误恢复 ​

castFromAst 不会因为单个 schema 解析失败而中止。在 castAllFromAst 中,失败的 schema 会以 RawNode 或 FallbackNode 出现在结果里 —— 调用方可以决定跳过、警告、或抛错。

typescript
const results = castAllFromAst(src);
const valid = results.filter(
  ({ ir }) => ir.kind !== "raw" && ir.kind !== "fallback",
);

相关 API ​

Released under the MPL 2.0 License.