ata-validator 1.60.0 → 1.61.1
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/README.md +134 -6
- package/bin/ata.js +84 -0
- package/build.d.ts +29 -0
- package/build.mjs +2 -0
- package/compiled-bare-rich.d.ts +6 -0
- package/compiled-bare.d.ts +7 -0
- package/compiled-bare.js +5 -0
- package/compiled-bare.mjs +35 -0
- package/compiled-object.d.ts +11 -0
- package/compiled-object.js +6 -0
- package/compiled-object.mjs +3 -0
- package/compiled-plain.d.ts +16 -0
- package/compiled-plain.js +5 -0
- package/compiled-plain.mjs +3 -0
- package/compiled.d.ts +3 -1
- package/index.browser.mjs +2 -2
- package/index.bundle.mjs +2 -2
- package/index.d.ts +9 -0
- package/index.edge.mjs +2 -2
- package/index.js +48 -0
- package/index.mjs +1 -1
- package/index.node.mjs +1 -1
- package/lib/aot-build.js +81 -6
- package/lib/aot-impl.js +24 -21
- package/lib/bun-target.js +612 -0
- package/lib/codegen-engine.js +9 -3
- package/lib/combined-runtime.js +1 -1
- package/lib/compiled-bare-rich.js +54 -0
- package/lib/compiled-bare.js +44 -0
- package/lib/compiled-common.js +17 -2
- package/lib/compiled-defaults.browser.js +9 -0
- package/lib/compiled-defaults.js +8 -0
- package/lib/compiled-object.js +123 -0
- package/lib/compiled-plain.js +57 -0
- package/lib/compiled.js +2 -1
- package/lib/email-literal.js +29 -0
- package/lib/enrich-error.js +5 -1
- package/lib/error-codes.js +6 -76
- package/lib/formats-source.js +20 -3
- package/lib/formats.js +1 -1
- package/lib/js-compiler-errors.js +49 -10
- package/lib/js-compiler.js +92 -13
- package/lib/json-rejections.js +159 -0
- package/lib/native-codes.js +67 -0
- package/lib/native-message.js +8 -0
- package/lib/native.browser.js +11 -0
- package/lib/public-api.js +1 -0
- package/lib/rejections.js +13 -152
- package/lib/standard-schema.js +1 -1
- package/lib/tier0.js +1 -1
- package/lib/validator-core.js +46 -4
- package/lib/verify.js +386 -0
- package/lib/version.js +1 -1
- package/lite.js +1 -0
- package/lite.mjs +1 -1
- package/package.json +44 -9
package/lib/aot-build.js
CHANGED
|
@@ -202,7 +202,29 @@ function pruneRegistry(roots, byId) {
|
|
|
202
202
|
return out;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
function bunTargetPath (output) {
|
|
206
|
+
const ext = path.extname(output);
|
|
207
|
+
return output.slice(0, output.length - ext.length) + '.bun.ts';
|
|
208
|
+
}
|
|
209
|
+
|
|
205
210
|
async function build(opts) {
|
|
211
|
+
// `--target bun`: every module written for JavaScriptCore, the plain ones
|
|
212
|
+
// included, since the executable the target is for runs on it.
|
|
213
|
+
const { setTargetEngine } = require('./js-compiler');
|
|
214
|
+
const prevEngine = setTargetEngine(opts.target === 'bun' ? 'jsc-aot' : null);
|
|
215
|
+
// An executable compiled ahead of time pays no bundle size and answers
|
|
216
|
+
// rejections: the one-pass error function (3.6x cheaper on a rejection, 20%
|
|
217
|
+
// larger gzipped) is the default there, and schema-source frames, which it
|
|
218
|
+
// does not carry, are off unless asked for.
|
|
219
|
+
if (opts.target === 'bun') opts = { ...opts, onePass: opts.onePass === undefined ? true : opts.onePass, source: opts.source === true ? true : false };
|
|
220
|
+
try {
|
|
221
|
+
return await buildWith(opts);
|
|
222
|
+
} finally {
|
|
223
|
+
setTargetEngine(prevEngine);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function buildWith(opts) {
|
|
206
228
|
const globs = opts.globs || [];
|
|
207
229
|
if (globs.length === 0) throw new Error('build: at least one glob required');
|
|
208
230
|
const format = opts.format || 'esm';
|
|
@@ -226,6 +248,10 @@ async function build(opts) {
|
|
|
226
248
|
|
|
227
249
|
const compiled = [];
|
|
228
250
|
const cached = [];
|
|
251
|
+
// --target bun: the .bun.ts written beside a module, and the schemas whose
|
|
252
|
+
// rules a type cannot carry.
|
|
253
|
+
const bunTargets = [];
|
|
254
|
+
const bunDeclined = [];
|
|
229
255
|
const skipped = [];
|
|
230
256
|
const failed = [];
|
|
231
257
|
const warnings = [];
|
|
@@ -345,7 +371,10 @@ async function build(opts) {
|
|
|
345
371
|
// the registry is put together from such modules: always rebuilt.
|
|
346
372
|
!cacheEntry.usesSiblings &&
|
|
347
373
|
fs.existsSync(output) &&
|
|
348
|
-
cacheEntry.outputHash === hashContent(fs.readFileSync(output))
|
|
374
|
+
cacheEntry.outputHash === hashContent(fs.readFileSync(output)) &&
|
|
375
|
+
// The Bun target is written beside the module; when it is asked for
|
|
376
|
+
// and missing, the module is rebuilt so that it gets written.
|
|
377
|
+
(opts.target !== 'bun' || fs.existsSync(bunTargetPath(output)))
|
|
349
378
|
);
|
|
350
379
|
if (opts.check) {
|
|
351
380
|
if (fresh) cached.push({ input, output });
|
|
@@ -460,12 +489,25 @@ async function build(opts) {
|
|
|
460
489
|
continue;
|
|
461
490
|
}
|
|
462
491
|
compiled.push({ input, output, bytes: outBytes, gzipBytes: gzBytes, errors: e.mode });
|
|
492
|
+
const stem = path.basename(input, path.extname(input)).replace(/\.schema$/, '');
|
|
493
|
+
const typeName = stem
|
|
494
|
+
.replace(/[^A-Za-z0-9_]/g, '_')
|
|
495
|
+
.replace(/^([a-z])/, (m) => m.toUpperCase()) || 'Data';
|
|
496
|
+
if (opts.target === 'bun') {
|
|
497
|
+
const { writeBunTarget, Declined } = require('./bun-target');
|
|
498
|
+
try {
|
|
499
|
+
const w = writeBunTarget({ schema: e.schema, input, output, typeName });
|
|
500
|
+
bunTargets.push({ input, output: w.bunPath, definitions: w.definitions });
|
|
501
|
+
} catch (err) {
|
|
502
|
+
if (!(err instanceof Declined)) throw err;
|
|
503
|
+
// No type can be written; the plain module stands alone.
|
|
504
|
+
const reason = `--target bun: ${err.message}; the plain module stands alone`;
|
|
505
|
+
if (opts.strict) { failed.push({ input, error: reason }); continue; }
|
|
506
|
+
bunDeclined.push({ input, reason });
|
|
507
|
+
}
|
|
508
|
+
}
|
|
463
509
|
if (opts.types !== false) {
|
|
464
510
|
const { toTypeScript } = require('./ts-gen');
|
|
465
|
-
const stem = path.basename(input, path.extname(input)).replace(/\.schema$/, '');
|
|
466
|
-
const typeName = stem
|
|
467
|
-
.replace(/[^A-Za-z0-9_]/g, '_')
|
|
468
|
-
.replace(/^([a-z])/, (m) => m.toUpperCase()) || 'Data';
|
|
469
511
|
const dts = toTypeScript(e.schema, { name: typeName, applyDefaults: /\nfunction applyDefaults\(/.test(src) });
|
|
470
512
|
const ext = path.extname(output);
|
|
471
513
|
const dtsExt = ext === '.mjs' ? '.d.mts'
|
|
@@ -514,7 +556,7 @@ async function build(opts) {
|
|
|
514
556
|
// module, whose errors come from the runtime. Only the written one counts.
|
|
515
557
|
const fromRuntime = new Set(entries.filter((e) => e.mode !== 'inline').map((e) => e.input));
|
|
516
558
|
const kept = warnings.filter((w) => !(w.kind === 'error-detail' && fromRuntime.has(w.input)));
|
|
517
|
-
return { compiled, cached, skipped, failed, warnings: kept, runtime: runtimeReport };
|
|
559
|
+
return { compiled, cached, skipped, failed, warnings: kept, runtime: runtimeReport, bunTargets, bunDeclined };
|
|
518
560
|
}
|
|
519
561
|
|
|
520
562
|
async function watch(opts, onReport) {
|
|
@@ -647,6 +689,18 @@ function compiledModuleFor(schema, opts) {
|
|
|
647
689
|
try {
|
|
648
690
|
src = aot.toStandaloneModule(validatorFor(schema), {
|
|
649
691
|
format: (opts && opts.format) || 'esm',
|
|
692
|
+
// The one-pass error function where the caller asks (a plugin writing
|
|
693
|
+
// for a Bun executable): 3.6x cheaper on a rejection, 20% larger gzipped.
|
|
694
|
+
onePass: opts && opts.onePass === true ? true : undefined,
|
|
695
|
+
source: opts && (opts.onePass === true || opts.plainErrors === true) ? false : undefined,
|
|
696
|
+
// Errors in the runtime's `richErrors: false` shape, for
|
|
697
|
+
// ata-validator/compiled-plain, which hands them out as they are.
|
|
698
|
+
plainErrors: !!(opts && opts.plainErrors === true),
|
|
699
|
+
// `verdictOnly`: the module for a reader that only ever calls isValid
|
|
700
|
+
// (a bundler plugin's verdict wrappers). Its validate() hands out the
|
|
701
|
+
// abort-early stub, so the error collector, never called there, is not
|
|
702
|
+
// written: 954 to 539 bytes gzipped on a one-field object.
|
|
703
|
+
abortEarly: !!(opts && opts.verdictOnly === true),
|
|
650
704
|
// Errors in the runtime's order, for a reader that does not sort them
|
|
651
705
|
// itself (a form resolver); fromCompiled sorts, so a plugin putting
|
|
652
706
|
// that wrapper around the module leaves it off.
|
|
@@ -664,7 +718,28 @@ function compiledModuleFor(schema, opts) {
|
|
|
664
718
|
// not export this, and a plugin should then replace only calls without options.
|
|
665
719
|
const { COMPILED_OPTIONS: compiledOptions } = require('./compiled');
|
|
666
720
|
|
|
721
|
+
// For a build plugin: the Bun target (lib/bun-target.js) and the verification
|
|
722
|
+
// (lib/verify.js), loaded on first use.
|
|
723
|
+
const bunTarget = {
|
|
724
|
+
get schemaToBunType () { return require('./bun-target').schemaToBunType },
|
|
725
|
+
get toBunModule () { return require('./bun-target').toBunModule },
|
|
726
|
+
get writeBunTarget () { return require('./bun-target').writeBunTarget },
|
|
727
|
+
get Declined () { return require('./bun-target').Declined },
|
|
728
|
+
// The generated code's target engine (lib/js-compiler): a plugin that
|
|
729
|
+
// writes for a Bun executable compiled ahead of time sets 'jsc-aot'.
|
|
730
|
+
setTargetEngine (engine) { return require('./js-compiler').setTargetEngine(engine) },
|
|
731
|
+
}
|
|
732
|
+
const verify = {
|
|
733
|
+
get verifyOne () { return require('./verify').verifyOne },
|
|
734
|
+
get verifySource () { return require('./verify').verifySource },
|
|
735
|
+
get generate () { return require('./verify').generate },
|
|
736
|
+
get renderReport () { return require('./verify').renderReport },
|
|
737
|
+
get ok () { return require('./verify').ok },
|
|
738
|
+
}
|
|
739
|
+
|
|
667
740
|
module.exports = {
|
|
741
|
+
bunTarget,
|
|
742
|
+
verify,
|
|
668
743
|
compiledOptions,
|
|
669
744
|
compiledEligible,
|
|
670
745
|
compiledSchemaFor,
|
package/lib/aot-impl.js
CHANGED
|
@@ -367,7 +367,7 @@ function defaultsDecl(validator) {
|
|
|
367
367
|
if (defaults.buildDefaultsApplier(schema) === null) return '';
|
|
368
368
|
const embedded = require('./schema-strip').stripAnnotationsKeepingDefaults(schema);
|
|
369
369
|
const text = JSON.stringify(JSON.stringify(embedded)).replace(/</g, '\\u003c');
|
|
370
|
-
return `const _ataDefaults = (function () {\nconst MAX_DEPTH = ${defaults.MAX_DEPTH};\n${
|
|
370
|
+
return `const _ataDefaults = (function () {\nconst MAX_DEPTH = ${defaults.MAX_DEPTH};\n${loadAotOrder().take('defaults.js', defaults.EMBED)}\nreturn buildDefaultsApplier;\n})();\n` +
|
|
371
371
|
`let _ataFill;\nfunction applyDefaults(d) { (_ataFill || (_ataFill = _ataDefaults(JSON.parse(${text}))))(d); }\n`;
|
|
372
372
|
}
|
|
373
373
|
|
|
@@ -430,7 +430,12 @@ function toStandaloneModule(validator, opts) {
|
|
|
430
430
|
// documents against large schemas asks for it.
|
|
431
431
|
let onePass = null;
|
|
432
432
|
let ordered = false;
|
|
433
|
-
|
|
433
|
+
// `plainErrors`: the errors in the runtime's `richErrors: false` shape, as
|
|
434
|
+
// the one-pass program writes them before codes and links are stamped on.
|
|
435
|
+
// A wrapper that hands them out as they are (ata-validator/compiled-plain)
|
|
436
|
+
// then carries no error pipeline of its own.
|
|
437
|
+
const plainErrors = !!(opts && opts.plainErrors === true);
|
|
438
|
+
const wantOnePass = plainErrors || (opts && opts.onePass === true) ? 'always' : (opts && (opts.onePass === false || opts.noOnePass)) ? 'never' : 'auto';
|
|
434
439
|
// Asked for explicitly, the one-pass function wins over schema-source
|
|
435
440
|
// frames, which `ata compile` writes by default outside production; the
|
|
436
441
|
// caller is told, since it asked for both.
|
|
@@ -445,7 +450,10 @@ function toStandaloneModule(validator, opts) {
|
|
|
445
450
|
}
|
|
446
451
|
if (wantOnePass === 'always' || errLen === 0) onePass = onePassCore(validator, opts);
|
|
447
452
|
}
|
|
448
|
-
if (onePass !== null) {
|
|
453
|
+
if (onePass !== null && plainErrors) {
|
|
454
|
+
errCore = `const _ER = function(e) { this.valid = false; this.errors = e; };\n` +
|
|
455
|
+
`const _vC = (function() {\n${onePass.core}\n})();\n`;
|
|
456
|
+
} else if (onePass !== null) {
|
|
449
457
|
errCore = `function _ataStamp(e) { for (let i = 0; i < e.length; i++) { const x = e[i]; if (x.code === undefined) { const c = x.keyword === 'required' && typeof x.schemaPath === 'string' && x.schemaPath.endsWith('/dependentRequired') ? 'ATA7005' : _ataCode(x.keyword, x.params && x.params.format); if (c !== null) { x.code = c; x.docUrl = 'https://ata-validator.com/e/' + c; } } else if (x.docUrl === undefined) x.docUrl = 'https://ata-validator.com/e/' + x.code; if (x.branchErrors !== undefined) _ataStamp(x.branchErrors); } }\n` +
|
|
450
458
|
`const _ER = function(e) { _ataStamp(e); this.valid = false; this.errors = e; };\n` +
|
|
451
459
|
`${codeTableSource(onePass.keywords, onePass.formats)}const _vC = (function() {\n${onePass.core}\n})();\n`;
|
|
@@ -458,7 +466,7 @@ function toStandaloneModule(validator, opts) {
|
|
|
458
466
|
// sorts by each error site's ordinal, the collector writes it (`_o`).
|
|
459
467
|
const schemaForErrors = typeof validator._schemaObj === 'object' ? validator._schemaObj : {};
|
|
460
468
|
ordered = !!(opts && opts.order === true);
|
|
461
|
-
const noOrdinal = !ordered || !
|
|
469
|
+
const noOrdinal = !ordered || !loadAotOrder().wantsOrdinals(schemaForErrors);
|
|
462
470
|
jsErrFn = compileToJSCodegenWithErrors(
|
|
463
471
|
schemaForErrors,
|
|
464
472
|
null,
|
|
@@ -600,7 +608,7 @@ function toStandaloneModule(validator, opts) {
|
|
|
600
608
|
compactCore = `let _ataErrs = null;\nfunction _ataErrors(d) { if (_ataErrs === null) _ataErrs = _ataCreateErrors(JSON.parse(${text})${rtOpts ? ', { ' + rtOpts + ' }' : ''}); return _ataErrs(d); }\n`;
|
|
601
609
|
}
|
|
602
610
|
const orderDecl = errCore && ordered && errorRuntime === null && onePass === null
|
|
603
|
-
?
|
|
611
|
+
? loadAotOrder().orderDecl(validator._schemaObj)
|
|
604
612
|
: '';
|
|
605
613
|
// Asked for and not given: stub errors, the one-pass function, or no error
|
|
606
614
|
// code generated. The caller is told rather than handed the collector's
|
|
@@ -736,20 +744,15 @@ function validate(data) { ${pre.call}${validBody}; }
|
|
|
736
744
|
${parseCore}${positionsCore}${fillDecl}${hashDecl}${exports}`;
|
|
737
745
|
}
|
|
738
746
|
|
|
739
|
-
//
|
|
740
|
-
//
|
|
741
|
-
//
|
|
742
|
-
//
|
|
743
|
-
//
|
|
744
|
-
//
|
|
745
|
-
//
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
// that.
|
|
749
|
-
const ERROR_RUNTIME_MODULE = './error-runtime';
|
|
750
|
-
// Reads the library's files too, at build time (see lib/aot-order.js).
|
|
751
|
-
const AOT_ORDER_MODULE = './aot-order';
|
|
752
|
-
function loadErrorRuntime() { return require(ERROR_RUNTIME_MODULE); }
|
|
747
|
+
// The error runtime and the order helpers are required by their literal
|
|
748
|
+
// names: an executable compiled ahead of time (Bun) loads a module from a
|
|
749
|
+
// computed path by throwing, and warns about every such require at build
|
|
750
|
+
// time. Both modules read the library's own files with fs at build time;
|
|
751
|
+
// a bundle for a runtime without fs is kept away from lib/aot-order.js by
|
|
752
|
+
// the package's `browser` field, and lib/error-runtime.js loads fs only in
|
|
753
|
+
// the functions that read files.
|
|
754
|
+
function loadErrorRuntime() { return require('./error-runtime'); }
|
|
755
|
+
function loadAotOrder() { return require('./aot-order'); }
|
|
753
756
|
|
|
754
757
|
// The schema hash a module stamps, once per validator: a plugin writes both
|
|
755
758
|
// modules of a schema (self-contained and compact) from one validator, and
|
|
@@ -973,7 +976,7 @@ function bundleStandalone(Validator, schemas, opts) {
|
|
|
973
976
|
v._ensureCompiled();
|
|
974
977
|
const jsFn = v._jsFn;
|
|
975
978
|
if (!jsFn || !jsFn._hybridSource) return null;
|
|
976
|
-
const noOrdinal = !ordered || !
|
|
979
|
+
const noOrdinal = !ordered || !loadAotOrder().wantsOrdinals(v._schemaObj);
|
|
977
980
|
// The schema the validator compiled, not the one the caller passed. They
|
|
978
981
|
// differ whenever anything prepared the schema: draft-07 normalization,
|
|
979
982
|
// `format` removed under assertFormat: false, keywords outside the
|
|
@@ -1040,7 +1043,7 @@ function bundleStandalone(Validator, schemas, opts) {
|
|
|
1040
1043
|
// In order: the collector's errors sorted as the runtime sorts them.
|
|
1041
1044
|
const hasErr = !!(jsErrFn && jsErrFn._errSource);
|
|
1042
1045
|
const errDecl = ordered && hasErr
|
|
1043
|
-
? `${
|
|
1046
|
+
? `${loadAotOrder().orderDecl(v._schemaObj)}var E=function(d){var r=(function(d){var _all=true;${errBody}})(d);return r&&r.errors?{valid:false,errors:_ataOrder(r.errors)}:r};`
|
|
1044
1047
|
: `var E=function(d){var _all=true;${errBody}};`;
|
|
1045
1048
|
if (opts && opts.verbose) {
|
|
1046
1049
|
// Embed the schema and a small resolver so errors carry parentSchema.
|