从零实现 JSON Schema 验证器 - 第三周
Source: Dev.to
每周更新 – 基础与架构
这周我相当忙,没太多时间做事,但我做出了一些基础性的决定,并遇到了一些小问题。
TypeScript 学习曲线
这是我第一次使用 TypeScript。我原以为它只是“带有静态类型的 JavaScript”,但很快发现我还需要 预先确定对象的静态结构。编写项目的基础部分变得很繁琐,因为每个变量在我定义类型之前都会出现红色波浪线。
虽然这种前期工作让人感到烦恼,但我现在看到它会在后期提升开发体验。
早期挑战
启动一个新项目总是很困难:
- 没有现有代码可以依附或扩展。
- 系统的宏观愿景可能让人望而生畏。
- 你不断在高层架构视角和低层实现视角之间切换。
- 早期决策会产生长期影响,使后续修改变得困难。
在有点迷茫之后,我通过进一步研究(见下一节)找到了思路。
架构决策
在阅读 JSON Schema 规范之前,维护者建议我 先关注系统的架构,这样以后添加对新 JSON Schema 草案的支持会更直接。
关键字处理对象
我决定创建 关键字处理对象,将关键字名称映射到实现这些关键字的函数。每个支持的草案都有自己的处理对象。
在实现 draft 2020‑12 处理器时,我遇到了阻碍:我不确定处理函数应如何与系统的其余部分集成。研究后发现两种常见的验证器架构:
- 递归架构
- 访问者架构
访问者架构为我的方法提供了缺失的环节,于是我采用了它。
基于访问者的验证器架构
两种架构都是递归的,但递归的应用方式不同。
-
公共入口点 –
validate
向用户公开的函数。 -
模式遍历 –
validateSchema
控制流程,决定遍历模式的哪一部分,并从关键字处理对象中获取相应的处理器。 -
处理器签名
(schema: any, instance: any, context: ValidationContext) => voidschema– 当前子模式。instance– 正在验证的数据。context– 跟踪错误、实例和模式位置、已评估的项/属性,并可能提供实用函数。
-
递归委托
处理器完成工作后,会在任何子模式上调用validateSchema,将控制权交回遍历逻辑。 -
完成
步骤 2‑4 循环执行,直至验证结束。随后validate函数使用累积的ValidationContext生成最终的验证结果。
这种设计将 流程控制 与 关键字实现 明确分离,便于添加、更新或移除关键字。
实现说明
- 我一直在使用大语言模型(LLM)协助实现,但仓库中的每一段代码要么由我亲自编写,要么经过彻底审查。
- 源代码已在 GitHub 上公开:(replace with the actual URL)。
第 3 周更新结束。