开源项目caniuse如何保证554个feature数据的准确性:validate-jsons.js校验机制代码实现深度剖析
【免费下载链接】caniuseRaw browser/feature support data from caniuse.com项目地址: https://gitcode.com/gh_mirrors/ca/caniuse
caniuse 仓库(npm 包名 caniuse-db)是著名浏览器兼容表网站背后的原始数据仓库:features-json/目录下存放着 570 余个浏览器功能特性(feature)的 JSON 数据文件,region-usage-json/目录下还有 240 个地区的浏览器使用率文件。如此庞大的浏览器兼容数据,准确性是如何保证的?答案就藏在validator/validate-jsons.js这个校验脚本里——一条命令、约 370 行代码,就能让每个数据文件都通过多层严格检查。本文带你完整读懂这套数据校验机制。
🎯 为什么兼容数据仓库需要一个"质检员"
caniuse 的数据是"双向流动"的:网站数据库定期导出为 GitHub 上的 JSON 文件,任何人提交的数据修改经审核后又会写回数据库(详见 CONTRIBUTING.md 中描述的机制)。同时,大量前端工程直接通过 npm 消费这份数据来做兼容性决策。
这意味着:一个字段写错,影响的不是一个人,而是整个下游生态。所以项目为每一类数据都设置了机器可执行的"验收标准",核心就是validator/validate-jsons.js:
| 目录/文件 | 内容 | 校验类型 |
|---|---|---|
features-json/ | 571 个 feature 数据文件(如fetch.json、wasm.json) | feature |
region-usage-json/ | 240 个国家/地区的浏览器使用率(如US.json) | usage |
sample-data.json | feature 文件的"标准模板",校验时的比对基准 | 基准 |
data.json/fulldata-json/ | 全量合并数据,供外部项目消费 | 产物 |
🚀 一步跑通:如何执行数据校验
想亲眼看看校验过程,只需两步:
git clone https://gitcode.com/gh_mirrors/ca/caniuse cd caniuse && npm run validatenpm run validate实际执行的就是package.json中定义的node validator/validate-jsons.js。全部通过时脚本静默结束;一旦发现违规,它会立刻抛出错误,并且错误信息精确到"哪个特性、哪个浏览器、哪个版本",例如:
[fetch:firefox:34] No support token found这种"精确定位"是新手阅读源码前最值得记住的一点——它决定了校验脚本能真正大规模使用,而不是报错后让人大海捞针。
🗺️ 校验架构鸟瞰:一个脚本的两类检查
整个校验器由一个Validator构造函数驱动,入口逻辑(validate-jsons.js305-312 行)按类型分派:
- feature 类型:对
features-json/里每个文件调用validateFeature(),逐字段检查; - usage 类型:对
region-usage-json/里每个文件调用validateUsage(),检查使用率统计。
此外脚本顶部定义了一组"白名单常量"和通用校验函数(8-12 行的validationFn对象),后面所有检查都复用它们:
w3cStatusArr = ['rec', 'pr', 'cr', 'wd']:W3C 规范状态白名单;statusArr:再叠加ls(WHATWG 活标)、other、unoff;categoryArr:12 个合法分类,如CSS、JS API、HTML5;supportValues = ['y', 'a', 'n', 'u', 'p']:支持状态的核心 token。
🔍 机制一:字段白名单校验——缺字段、多字段都不行
validateFeature()(245-274 行)像一个"字段清单",逐一核对每个 feature 文件:title、description必须是字符串,spec必须是字符串且是合法 URL(isURL是一个完整的 URL 正则,还会排除内网 IP 段),status必须在白名单内,links是"每个元素都含合法 url 和 title 的数组",usage_perc_y必须是数字,shown、ucprefix必须是布尔……
更严格的是配套的validateKeys()(209-215 行):它做反向检查——文件里出现的每一个键都必须在模板中存在,否则抛出"Extra key found"。这相当于"缺项扣分、超纲也扣分",彻底杜绝字段名拼写错误悄悄混入。
🔍 机制二:支持状态的"token 语法"——y/a/n/u/p 各来一个
caniuse 表格里的每个格子其实是一串紧凑 token,比如features-json/fetch.json中 Firefox 34 的值是"n d #1 #4":n表示不支持、d表示"部分/有差异"、#1 #4表示引用第 1、4 条备注。
validateSupportValue()(147-174 行)把每个值按空格拆成 token,然后执行三条铁律:
- 每个 token 必须合法:
validateToken()(140-145 行)用正则^(y|a|n|u|p|x|d|(\#\d+))$限定形态,y(支持)、a(部分支持)、n(不支持)、u(未知)、p(需前缀)、x/d(扩展标记)、#数字(备注引用)之外一律拒绝; - 核心 token 不能重复:同一个 token 出现两次、或出现两个支持状态(如
y n),直接报错; - 必须恰好有一个支持 token:全是备注号没有
y/n/u的值会被No support token found拦下。
这套"微型语法"保证了人类阅读、程序解析都不会歧义。
🔍 机制三:跨字段一致性——备注不能"悬空"
单字段合法还不够,字段之间也要自洽,这是最能体现数据工程功力的部分:
- 备注一致性
validateNoteCoherence()(185-207 行):用正则从stats里所有版本值中抓出#数字引用集合,与notes_by_num的键集合做双向核对——备注写了却从未被任何版本引用(页面不会展示它,属于脏数据),或版本引用了不存在的备注,都会报错。这正是"悬空引用"检查; - 规范与状态的搭配
validateStatusOfSpec()(176-182 行):如果spec指向 WHATWG(spec.whatwg.org 域名),status就不允许填 W3C 状态(rec/pr/cr/wd),因为活标不属于 W3C 流程——这是典型的业务规则校验; - 浏览器/版本矩阵完整性
validateSupportData()(217-243 行):以sample-data.json为基准,要求每个浏览器、每个版本都有对应值,缺一个浏览器或一个版本立即报错(Browser version missing),并再次用validateKeys挡住"多出来的浏览器"。
🔍 机制四:地区使用率校验——错误与警告的分寸感
validateUsage()(276-303 行)检查region-usage-json/里的文件:month必须符合YYYY-MM(如2026-06)、access_date必须符合YYYY-MM-DD、total必须是数字。
有意思的是它对total的处理是警告而非报错(293-302 行):总体覆盖率低于 80 会提示"Expected total usage to be > 80",美国数据低于 95 单独警告。使用率偏低可能是真实的采集问题,也可能是统计正常波动——这类"大概率有问题"的场景用warn人工复核,而格式、字段这类"确定是错的"才用throw,轻重分明。
错误定位方面,throwError()(88-98 行)会自动把上下文拼进错误前缀:[featureId]、[featureId:browser]、[featureId:browser:version],校验到哪个层级就标注哪个层级。
💡 这套校验机制的 5 个设计亮点
- 失败快速(fail-fast):任何违规立即抛错终止,不带病继续;
- 白名单优先:状态、分类、token 全部用枚举白名单,未列举即非法;
- 模板驱动:
sample-data.json既是新特性文件的"填写样板",也是校验时的比对基准,一份数据两用; - 错误与警告分离:硬错误抛异常,软问题打警告,避免告警疲劳;
- 错误可定位:错误信息自带"特性:浏览器:版本"坐标,配合 571 个文件也能量级化排错。
📝 小结
caniuse 用validator/validate-jsons.js一个轻量脚本,就把"字段白名单、token 语法、跨字段一致性、统计合理性"四层规则落在了每一条浏览器兼容数据上。对新手而言,这是学习数据校验设计非常好的范本:规则集中在常量区、校验逻辑函数化、报错信息带上下文——小脚本,大工程。
【免费下载链接】caniuseRaw browser/feature support data from caniuse.com项目地址: https://gitcode.com/gh_mirrors/ca/caniuse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考