ata-validator 0.12.5 → 0.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +6 -2
- package/index.js +39 -12
- package/lib/js-compiler.js +23 -4
- package/package.json +1 -1
- package/prebuilds/ata-darwin-arm64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-arm64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-arm64-musl/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-x64/node-napi-v10.node +0 -0
- package/prebuilds/ata-linux-x64-musl/node-napi-v10.node +0 -0
- package/prebuilds/ata-win32-x64/node-napi-v10.node +0 -0
- package/prebuilds/darwin-arm64/ata-validator.node +0 -0
package/index.d.ts
CHANGED
|
@@ -140,8 +140,12 @@ export class Validator {
|
|
|
140
140
|
*/
|
|
141
141
|
static bundleStandalone(schemas: object[], options?: BundleStandaloneOptions): string;
|
|
142
142
|
|
|
143
|
-
/**
|
|
144
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Bundle multiple schemas with deduplicated shared templates. Smaller output
|
|
145
|
+
* than bundle(). Accepts the same options as bundleStandalone, including
|
|
146
|
+
* `format: 'esm' | 'cjs'` and cross-schema `$ref` resolution.
|
|
147
|
+
*/
|
|
148
|
+
static bundleCompact(schemas: object[], options?: BundleStandaloneOptions): string;
|
|
145
149
|
|
|
146
150
|
/** Load a bundle created by Validator.bundle(). Returns array of Validator instances. */
|
|
147
151
|
static loadBundle(mods: object[], schemas: object[], options?: ValidatorOptions): Validator[];
|
package/index.js
CHANGED
|
@@ -1187,10 +1187,12 @@ Validator.bundle = function (schemas, opts) {
|
|
|
1187
1187
|
|
|
1188
1188
|
// Zero-dependency self-contained bundle — no require('ata-validator') needed at runtime.
|
|
1189
1189
|
// opts.format: 'cjs' (default) or 'esm'.
|
|
1190
|
+
// opts.formats: { name: fn } — embedded in the output via Function#toString.
|
|
1190
1191
|
Validator.bundleStandalone = function (schemas, opts) {
|
|
1191
|
-
// Cross-schema $ref resolution:
|
|
1192
|
-
//
|
|
1193
|
-
const
|
|
1192
|
+
// Cross-schema $ref resolution: only meaningful when at least one schema has
|
|
1193
|
+
// an $id. Skip the schemas-as-map plumbing when none of them do.
|
|
1194
|
+
const haveIds = schemas.some((s) => s && typeof s === 'object' && s.$id);
|
|
1195
|
+
const bundleOpts = haveIds ? { ...(opts || {}), schemas } : (opts || {});
|
|
1194
1196
|
const format = (opts && opts.format) || 'cjs';
|
|
1195
1197
|
const R = "Object.freeze({valid:true,errors:Object.freeze([])})";
|
|
1196
1198
|
const fns = schemas.map((schema) => {
|
|
@@ -1201,12 +1203,25 @@ Validator.bundleStandalone = function (schemas, opts) {
|
|
|
1201
1203
|
const jsErrFn = compileToJSCodegenWithErrors(
|
|
1202
1204
|
typeof schema === "string" ? JSON.parse(schema) : schema,
|
|
1203
1205
|
v._schemaMap,
|
|
1206
|
+
v._userFormats,
|
|
1204
1207
|
);
|
|
1205
1208
|
const errBody =
|
|
1206
1209
|
jsErrFn && jsErrFn._errSource
|
|
1207
1210
|
? jsErrFn._errSource
|
|
1208
1211
|
: "return{valid:false,errors:[{code:'error',path:'',message:'validation failed'}]}";
|
|
1209
|
-
|
|
1212
|
+
// Serialize custom format closures so the bundle has no runtime dep on ata.
|
|
1213
|
+
let preamble = '';
|
|
1214
|
+
if (jsFn._formatClosures) {
|
|
1215
|
+
preamble = jsFn._formatClosures
|
|
1216
|
+
.map(({ name, fn }) => `var ${name}=${fn.toString()};`)
|
|
1217
|
+
.join('\n');
|
|
1218
|
+
}
|
|
1219
|
+
if (opts && opts.verbose) {
|
|
1220
|
+
// Embed the schema and a small resolver so errors carry parentSchema.
|
|
1221
|
+
const schemaLit = JSON.stringify(typeof schema === 'string' ? JSON.parse(schema) : schema);
|
|
1222
|
+
return `(function(R){${preamble}var _S=${schemaLit};function _PS(p){if(!p||p[0]!=='#')return undefined;var s=p.slice(1);if(!s)return _S;var ps=s.split('/').filter(Boolean).map(function(x){return x.replace(/~1/g,'/').replace(/~0/g,'~')});var t=_S;for(var i=0;i<ps.length-1;i++){if(t==null||typeof t!=='object')return undefined;t=t[ps[i]]}return t}var E=function(d){var _all=true;${errBody}};var _v=function(d){${jsFn._hybridSource}};return function(d){var r=_v(d);if(r&&r.valid===false&&r.errors){var es=[];for(var i=0;i<r.errors.length;i++){var e=r.errors[i];es.push(Object.assign({},e,{parentSchema:_PS(e.schemaPath)}))}return{valid:false,errors:es}}return r}})(R)`;
|
|
1223
|
+
}
|
|
1224
|
+
return `(function(R){${preamble}var E=function(d){var _all=true;${errBody}};return function(d){${jsFn._hybridSource}}})(R)`;
|
|
1210
1225
|
});
|
|
1211
1226
|
const arr = `[${fns.join(",")}]`;
|
|
1212
1227
|
if (format === 'esm') {
|
|
@@ -1217,15 +1232,20 @@ Validator.bundleStandalone = function (schemas, opts) {
|
|
|
1217
1232
|
|
|
1218
1233
|
// Compact bundle: deduplicated code. Shared template functions + per-schema params.
|
|
1219
1234
|
// Much smaller file → faster V8 parse → faster startup.
|
|
1235
|
+
// opts.format: 'cjs' (default) or 'esm'.
|
|
1220
1236
|
Validator.bundleCompact = function (schemas, opts) {
|
|
1237
|
+
const haveIds = schemas.some((s) => s && typeof s === 'object' && s.$id);
|
|
1238
|
+
const bundleOpts = haveIds ? { ...(opts || {}), schemas } : (opts || {});
|
|
1239
|
+
const format = (opts && opts.format) || 'cjs';
|
|
1221
1240
|
// Analyze schemas and group by structure
|
|
1222
1241
|
const entries = schemas.map((schema) => {
|
|
1223
|
-
const v = new Validator(schema,
|
|
1242
|
+
const v = new Validator(schema, bundleOpts);
|
|
1224
1243
|
v._ensureCompiled();
|
|
1225
1244
|
const jsFn = v._jsFn;
|
|
1226
1245
|
if (!jsFn || !jsFn._hybridSource) return null;
|
|
1227
1246
|
const jsErrFn = compileToJSCodegenWithErrors(
|
|
1228
1247
|
typeof schema === "string" ? JSON.parse(schema) : schema,
|
|
1248
|
+
v._schemaMap,
|
|
1229
1249
|
);
|
|
1230
1250
|
return {
|
|
1231
1251
|
hybrid: jsFn._hybridSource,
|
|
@@ -1260,31 +1280,38 @@ Validator.bundleCompact = function (schemas, opts) {
|
|
|
1260
1280
|
});
|
|
1261
1281
|
|
|
1262
1282
|
// Generate compact bundle
|
|
1263
|
-
|
|
1264
|
-
out
|
|
1283
|
+
const isEsm = format === 'esm';
|
|
1284
|
+
let out = isEsm
|
|
1285
|
+
? "// Auto-generated by ata-validator — do not edit\n"
|
|
1286
|
+
: "'use strict';\n";
|
|
1287
|
+
const declKW = isEsm ? "const" : "var";
|
|
1288
|
+
out += `${declKW} R=Object.freeze({valid:true,errors:Object.freeze([])});\n`;
|
|
1265
1289
|
|
|
1266
1290
|
// Shared hybrid factories
|
|
1267
|
-
out +=
|
|
1291
|
+
out += `${declKW} H=[\n`;
|
|
1268
1292
|
out += bodies
|
|
1269
1293
|
.map((b) => `function(R,E){return function(d){${b}}}`)
|
|
1270
1294
|
.join(",\n");
|
|
1271
1295
|
out += "\n];\n";
|
|
1272
1296
|
|
|
1273
1297
|
// Shared error functions
|
|
1274
|
-
out +=
|
|
1298
|
+
out += `${declKW} EF=[\n`;
|
|
1275
1299
|
out += errBodies.map((b) => `function(d){var _all=true;${b}}`).join(",\n");
|
|
1276
1300
|
out += "\n];\n";
|
|
1277
1301
|
|
|
1278
1302
|
// Build validators from shared templates
|
|
1279
|
-
|
|
1280
|
-
out += indices
|
|
1303
|
+
const arrBody = indices
|
|
1281
1304
|
.map(([hi, ei]) => {
|
|
1282
1305
|
if (hi < 0) return "null";
|
|
1283
1306
|
if (ei >= 0) return `H[${hi}](R,EF[${ei}])`;
|
|
1284
1307
|
return `H[${hi}](R,function(){return{valid:false,errors:[]}})`;
|
|
1285
1308
|
})
|
|
1286
1309
|
.join(",");
|
|
1287
|
-
|
|
1310
|
+
if (isEsm) {
|
|
1311
|
+
out += `const validators=[${arrBody}];\nexport default validators;\nexport { validators };\n`;
|
|
1312
|
+
} else {
|
|
1313
|
+
out += `module.exports=[${arrBody}];\n`;
|
|
1314
|
+
}
|
|
1288
1315
|
|
|
1289
1316
|
return out;
|
|
1290
1317
|
};
|
package/lib/js-compiler.js
CHANGED
|
@@ -946,6 +946,17 @@ function compileToJSCodegen(schema, schemaMap, userFormats) {
|
|
|
946
946
|
boolFn._source = helperStr + body
|
|
947
947
|
boolFn._preambleSource = preambleStr
|
|
948
948
|
boolFn._hybridSource = helperStr + hybridBody
|
|
949
|
+
// Custom-format closure entries that the bundle output needs to recreate.
|
|
950
|
+
// Stored as { name, fn } so consumers can serialize via Function#toString.
|
|
951
|
+
if (ctx.userFormats) {
|
|
952
|
+
const fmtEntries = []
|
|
953
|
+
for (let i = 0; i < closureNames.length; i++) {
|
|
954
|
+
if (closureNames[i].startsWith('_uf_')) {
|
|
955
|
+
fmtEntries.push({ name: closureNames[i], fn: closureValues[i] })
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (fmtEntries.length) boolFn._formatClosures = fmtEntries
|
|
959
|
+
}
|
|
949
960
|
|
|
950
961
|
return boolFn
|
|
951
962
|
} catch {
|
|
@@ -2448,7 +2459,7 @@ function genCharCodeSwitch(keys, v) {
|
|
|
2448
2459
|
// --- Error-collecting codegen: same checks, but pushes errors instead of returning false ---
|
|
2449
2460
|
// Returns a function: (data, allErrors) => { valid, errors }
|
|
2450
2461
|
// Valid path is still fast — only error path does extra work.
|
|
2451
|
-
function compileToJSCodegenWithErrors(schema, schemaMap) {
|
|
2462
|
+
function compileToJSCodegenWithErrors(schema, schemaMap, userFormats) {
|
|
2452
2463
|
// Bail on unevaluated keywords — error codegen doesn't support them yet
|
|
2453
2464
|
if (typeof schema === 'object' && schema !== null) {
|
|
2454
2465
|
const s = JSON.stringify(schema)
|
|
@@ -2509,7 +2520,7 @@ function compileToJSCodegenWithErrors(schema, schemaMap) {
|
|
|
2509
2520
|
}
|
|
2510
2521
|
}
|
|
2511
2522
|
|
|
2512
|
-
const ctx = { varCounter: 0, helperCode: [], rootDefs: eRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: eAnchors, rootSchema: schema }
|
|
2523
|
+
const ctx = { varCounter: 0, helperCode: [], rootDefs: eRootDefs, refStack: new Set(), schemaMap: schemaMap || null, anchors: eAnchors, rootSchema: schema, userFormats: userFormats || null }
|
|
2513
2524
|
ctx.helperCode.push('const _cpLen=s=>{let n=0;for(const _ of s)n++;return n}')
|
|
2514
2525
|
const lines = []
|
|
2515
2526
|
genCodeE(schema, 'd', '', lines, ctx, '#')
|
|
@@ -2733,15 +2744,23 @@ function genCodeE(schema, v, pathExpr, lines, ctx, schemaPrefix) {
|
|
|
2733
2744
|
}
|
|
2734
2745
|
if (schema.format) {
|
|
2735
2746
|
const fc = FORMAT_CODEGEN[schema.format]
|
|
2747
|
+
const failPush = `_e.push({keyword:'format',instancePath:${pathExpr||'""'},schemaPath:'${schemaPrefix}/format',params:{format:'${esc(schema.format)}'},message:'must match format "${esc(schema.format)}"'});if(!_all)return{valid:false,errors:_e}`
|
|
2736
2748
|
// Format errors use the boolean codegen — just wrap with error push
|
|
2737
2749
|
if (fc) {
|
|
2738
2750
|
const ri = ctx.varCounter++
|
|
2739
2751
|
const boolLines = []
|
|
2740
2752
|
boolLines.push(fc(v, isStr))
|
|
2741
2753
|
// Replace `return false` with error push in the format check
|
|
2742
|
-
const fmtCode = boolLines.join(';').replace(/return false/g,
|
|
2743
|
-
`{_e.push({keyword:'format',instancePath:${pathExpr||'""'},schemaPath:'${schemaPrefix}/format',params:{format:'${esc(schema.format)}'},message:'must match format "${esc(schema.format)}"'});if(!_all)return{valid:false,errors:_e}}`)
|
|
2754
|
+
const fmtCode = boolLines.join(';').replace(/return false/g, `{${failPush}}`)
|
|
2744
2755
|
lines.push(fmtCode)
|
|
2756
|
+
} else if (ctx.userFormats && typeof ctx.userFormats[schema.format] === 'function') {
|
|
2757
|
+
// User-supplied format checker on the error path. Same closure plumbing
|
|
2758
|
+
// as the boolean codegen — but error codegen has no closure factory, so
|
|
2759
|
+
// bundle output serializes the function via Function#toString separately.
|
|
2760
|
+
const safeName = schema.format.replace(/[^a-zA-Z0-9_]/g, '_')
|
|
2761
|
+
const closureName = `_uf_${safeName}`
|
|
2762
|
+
const guard = isStr ? '' : `typeof ${v}==='string'&&`
|
|
2763
|
+
lines.push(`if(${guard}!${closureName}(${v})){${failPush}}`)
|
|
2745
2764
|
}
|
|
2746
2765
|
}
|
|
2747
2766
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.6",
|
|
4
4
|
"description": "Ultra-fast JSON Schema validator. 5x faster validation, 159,000x faster compilation. Works without native addon. Cross-schema $ref, Draft 2020-12 + Draft 7, V8-optimized JS codegen, simdjson, RE2, multi-core. Standard Schema V1 compatible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|