ericsssan/ez-checker

GitHub: ericsssan/ez-checker

ez-checker 是一个用 Zig 编写的独立 TypeScript 类型检查引擎,提供表达式推断、类型解析、控制流窄化和跨文件解析能力,可供 linter、编译器或语言服务器等工具嵌入使用。

Stars: 1 | Forks: 0

# ez-checker [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/ericsssan/ez-checker/actions/workflows/ci.yml) [![TypeScript 语料库](https://img.shields.io/badge/TypeScript_corpus-84.3%25-brightgreen)](#conformance) [![原始类型](https://img.shields.io/badge/primitive_types-90.9%25-brightgreen)](#conformance) TypeScript 类型检查器的重新实现。仅包含类型系统:推断任何表达式的类型,解析声明,通过控制流进行类型窄化。无代码生成,无诊断信息,无 `tsconfig.json`。 最初提取自 [Ez](https://github.com/ericsssan/Ez) linter,但其类型推断引擎是通用的——可供 linter、编译器、语言服务器或任何需要对 TypeScript 类型进行推理的工具使用。 基于 [es-parser](https://github.com/ericsssan/es-parser) 构建。使用 Zig 编写。 ## 已实现的功能 **表达式推断** 字面量、模板字面量、数组、对象、函数、类、二元/一元运算符、三元运算符、赋值、await、逗号表达式、类型断言(`as`、`satisfies`、`!`)。 **类型解析** 原始类型、数组、元组、联合类型、交叉类型、对象类型、函数类型、`typeof`、`keyof`、索引访问(`T[K]`)、映射类型、条件类型(包含 `infer`)、模板字面量类型、泛型类型引用、递归类型别名。 **实用工具类型** `Partial`、`Required`、`Readonly`、`Pick`、`Omit`、`Exclude`、`Extract`、`NonNullable`、`Record`、`ReturnType`、`Parameters`、`Awaited`。 **控制流类型窄化** Null/undefined 检查、`typeof` 守卫、`instanceof`、类型谓词(`x is T`)、断言函数(`asserts x`)、可辨识联合、真值判断、赋值类型窄化、提前返回类型窄化。 **声明** 变量、函数(包含重载)、类(实例 + 静态,继承)、接口(extends、调用/构造签名、索引签名、声明合并)、类型别名、枚举(数字、字符串、混合)、命名空间(声明合并)、导入。 **跨文件解析** 可选。实现 `ModuleResolver` 并设置 `Checker.module_resolver`,以按需解析来自导入模块的类型。 ## 一致性 以 TypeScript 编译器本身为基准进行衡量:对于 [microsoft/TypeScript](https://github.com/microsoft/TypeScript) 测试语料库中的每一个表达式,ez-checker 会推断出一种类型,并将其与 `tsc` 为同一表达式生成的 `.types` 基准进行逐字符串比较。 | 指标 | 正确数 | 总数 | 比率 | | --- | --- | --- | --- | | 所有表达式类型 | 554,130 | 657,474 | **84.3%** | | 原始类型(子指标) | 338,560 | 372,262 | **90.9%** | 棘轮机制(`oracle/baseline.lock`)记录了这些下限;如果任何指标出现倒退,`zig build test-oracle` 将会失败,并且 CI 会在每次推送和拉取请求时强制执行此检查。使用 `zig build run-oracle` 扫描语料库;在取得实质性改进后,使用 `zig build save-baseline` 提升下限。 ## 已知缺失 完整跟踪列表请参阅[待解决问题](https://github.com/ericsssan/ez-checker/issues/9)。简要说明如下: - 尚未实现 `ConstructorParameters` 和 `InstanceType` - 对象字面量上的 `as const`(数组支持;对象不支持) - 可选链(`?.`)不会为结果类型添加 `| undefined` - `==`/`!=`(宽松相等)不进行类型窄化 - `throw` 不会对后续代码进行类型窄化 - 不支持类 + 接口声明合并 - 不支持 `declare module` / `declare global` 扩展 - 重载决议会选择第一个匹配的签名,而不是最佳签名 - 全局内置类型(约 30 个手动整理的条目;没有完整的 lib.dom 或 lib.es*) ## 用法 `build.zig.zon`: ``` .dependencies = .{ .ez_checker = .{ .path = "../ez-checker" }, .es_parser = .{ .path = "../es-parser" }, }, ``` `build.zig`: ``` const ez_checker_mod = b.dependency("ez_checker", .{ .target = target, .optimize = .ReleaseFast, }).module("ez-checker"); your_module.addImport("ez_checker", ez_checker_mod); ``` ## API ``` const ez = @import("ez_checker"); const Checker = ez.Checker; const types = ez.types; // Init from an already-parsed file. var checker = try Checker.init(allocator, &ast, &semantic_result); defer checker.deinit(); // Optional: wire cross-file resolution. checker.file_path = "/abs/path/to/file.ts"; checker.module_resolver = my_module_cache.resolver(); // Query the type of any expression node. const ty: types.TypeId = checker.typeOf(node_index); // Classify the result. if (types.isAny(&checker.store, ty)) { /* any */ } if (types.containsAny(&checker.store, ty)) { /* any somewhere inside */ } if (types.isAssignableTo(&checker.store, src, dst)) { /* assignable */ } ``` ### `ModuleResolver` 实现此接口以启用跨文件类型解析: ``` fn resolveImpl( ctx: *anyopaque, from_dir: []const u8, module_spec: []const u8, export_name: []const u8, local_store: *types.TypeStore, gpa: std.mem.Allocator, ) ?types.TypeId { const cache: *MyCache = @ptrCast(@alignCast(ctx)); return cache.resolve(from_dir, module_spec, export_name, local_store, gpa); } checker.module_resolver = .{ .ctx = @ptrCast(my_cache), .resolve_fn = &resolveImpl, }; ``` ## 许可证 MIT
标签:SOC Prime, TypeScript, Zig, 云安全监控, 安全插件, 开发工具, 类型检查器, 编译器组件, 静态分析