如何获取ajv.compile()的JSON模式编译错误行号与列号信息
如何获取ajv.compile()的JSON模式编译错误行号与列号信息
嘿,我来帮你搞定这个问题!你想要的是在使用ajv.compile()编译JSON Schema时,拿到Schema本身的编译错误对应的行号和列号,不是验证数据时的错误,这点我完全get到了。
其实你已经找对了方向——用json-source-map来做源映射就是核心解法!下面我给你梳理完整的实现思路和代码:
完整实现代码
validateSchema.ts
const fsExtra = require('fs-extra'); const jsonSourceMap = require('json-source-map'); const Ajv = require('ajv'); // 读取Schema文件内容并生成源映射 const schemaContent = fsExtra.readFileSync(`${__dirname}/../my.schema.json`).toString(); const { data: schema, pointers } = jsonSourceMap.parse(schemaContent); // 初始化AJV实例,开启严格模式和全错误捕获 const ajv = new Ajv({ strict: true, allErrors: true, verbose: true }); try { ajv.compile(schema); console.log('Schema编译成功!'); } catch (error) { // 处理单个编译错误的情况 if (error instanceof Error && 'instancePath' in error) { const errorPointer = error.instancePath; // 通过源映射找到错误对应的行列位置 const position = pointers[errorPointer]; if (position) { console.error(`Schema编译错误:${error.message}`); // 注意源映射的行列是从0开始计数,要+1转成日常使用的编号 console.error(`位置:行 ${position.key.line + 1},列 ${position.key.column + 1}`); } else { console.error(`Schema编译错误:${error.message}`); console.error('无法匹配到对应的行列位置'); } } // 处理多个错误的情况(因为开启了allErrors) else if (error.errors && Array.isArray(error.errors)) { error.errors.forEach(err => { const errorPointer = err.instancePath; const position = pointers[errorPointer]; if (position) { console.error(`错误:${err.message}`); console.error(`位置:行 ${position.key.line + 1},列 ${position.key.column + 1}\n`); } else { console.error(`错误:${err.message}`); console.error('无法匹配到对应的行列位置\n'); } }); } // 兜底处理其他异常 else { console.error('Schema编译出错:', error); } }
示例错误的my.schema.json
比如你提供的这个有语法问题的Schema:
{ "title": "JSON schema for names", "$schema": "http://json-schema.org/draft-07/schema#", "type": ... }
原理说明
json-source-map工具在解析JSON时,会生成每个节点对应的源位置映射(也就是代码里的pointers对象),它的键是JSON指针路径,值包含了该节点在原始文件中的行号、列号信息。- AJV编译Schema出错时,抛出的错误对象(或错误数组里的元素)会带有
instancePath字段,这个路径正好能和pointers的键对应上,从而把错误定位到原始文件的具体行列。
注意事项
- 记得先安装依赖:
npm install ajv json-source-map fs-extra - 一定要开启AJV的
allErrors: true,这样才能捕获所有编译错误,而不是只返回第一个错误。
备注:内容来源于stack exchange,提问作者TwitchBronBron
相关产品推荐
相关产品推荐

