ata-validator 1.61.3 → 1.62.0
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 +67 -10
- package/bin/ata.js +3 -2
- package/compat.js +15 -2
- package/index.d.ts +7 -0
- package/index.js +10 -0
- package/lib/aot-build.js +27 -1
- package/lib/aot-impl.js +108 -17
- package/lib/buffer-gate.js +25 -14
- package/lib/bun-target.js +21 -5
- package/lib/clone-emit.js +115 -10
- package/lib/codegen-engine.js +94 -18
- package/lib/compiled-common.js +11 -4
- package/lib/compiled-verdict.js +2 -2
- package/lib/compiled.js +1 -1
- package/lib/data-positions.js +18 -0
- package/lib/defaults.js +101 -23
- package/lib/describe-schema.js +38 -5
- package/lib/diagnose.js +51 -29
- package/lib/enrich-error.js +23 -1
- package/lib/error-sort-rank.js +12 -0
- package/lib/formats-source.js +12 -1
- package/lib/formats.js +19 -19
- package/lib/interpreter-core.js +23 -4
- package/lib/js-compiler-errors.js +70 -72
- package/lib/js-compiler.js +212 -72
- package/lib/json-rejections.js +1 -1
- package/lib/migrate.js +24 -5
- package/lib/native-attach.browser.js +7 -0
- package/lib/native-attach.js +76 -0
- package/lib/native-positions.js +7 -0
- package/lib/plan-compiler.js +7 -1
- package/lib/regex-linear.js +88 -0
- package/lib/rejections.js +13 -3
- package/lib/render-compact.js +5 -5
- package/lib/render-pretty.js +23 -10
- package/lib/safe-regex.js +29 -4
- package/lib/scan-compiler.js +16 -4
- package/lib/stream.js +293 -0
- package/lib/tier0.js +6 -2
- package/lib/ts-gen.js +25 -12
- package/lib/unique-items.js +11 -3
- package/lib/validator-core.js +61 -66
- package/lib/verify.js +25 -6
- package/lib/version.js +1 -1
- package/package.json +17 -8
- package/stream.d.ts +51 -0
- package/stream.js +3 -0
- package/stream.mjs +3 -0
package/lib/verify.js
CHANGED
|
@@ -20,7 +20,8 @@ const { pathToFileURL } = require('url')
|
|
|
20
20
|
function rng (seed) {
|
|
21
21
|
let x = (seed >>> 0) || 0x9e3779b9
|
|
22
22
|
const next = () => { x ^= x << 13; x ^= x >>> 17; x ^= x << 5; return (x >>> 0) / 4294967296 }
|
|
23
|
-
|
|
23
|
+
// `nodes` counts the values of the document being made (makeValid).
|
|
24
|
+
return { next, int: (n) => Math.floor(next() * n), pick: (a) => a[Math.floor(next() * a.length)], chance: (p) => next() < p, nodes: 0 }
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const WORDS = ['ada', 'Zoë', 'order', 'x', 'north-west', 'a b', 'ÄÖÜ', 'sku-1001', 'TENOFF', 'hello world', '', '0', 'null', '😀', 'line\nbreak', ' ']
|
|
@@ -48,9 +49,18 @@ const FORMAT_EXAMPLES = {
|
|
|
48
49
|
'json-pointer': ['/a/b', 'a/b', '/a~1b', '/a~2'],
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
const { patternIsSafe, compileSafe } = require('./safe-regex')
|
|
53
|
+
|
|
54
|
+
// How many values one generated document may hold. Nested minItems multiply
|
|
55
|
+
// (20 at six levels is 64 million integers) and ran the process out of
|
|
56
|
+
// memory; past the budget the document is refused with a message instead.
|
|
57
|
+
const NODE_BUDGET = 100000
|
|
58
|
+
|
|
51
59
|
// A value meant to satisfy `schema`, built from its keywords; where the
|
|
52
60
|
// schema says little, something plausible of the kind.
|
|
53
61
|
function makeValid (schema, r, defs, depth) {
|
|
62
|
+
if (depth === 0) r.nodes = 0
|
|
63
|
+
if (++r.nodes > NODE_BUDGET) throw new Error(`a document for this schema holds more than ${NODE_BUDGET} values (nested minItems or required properties); ata verify does not generate it`)
|
|
54
64
|
if (schema === true || schema === undefined) return r.pick([1, 'x', true, null, {}, []])
|
|
55
65
|
if (schema === false) return undefined
|
|
56
66
|
if (typeof schema !== 'object' || schema === null) return null
|
|
@@ -103,16 +113,22 @@ function makeValid (schema, r, defs, depth) {
|
|
|
103
113
|
// Any other pattern: a candidate that matches, when one does, so the
|
|
104
114
|
// generated documents reach past the pattern; else a word, which the
|
|
105
115
|
// schema then refuses, and that is a document too.
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
// On the linear engine: the candidates are fixed strings, and a
|
|
117
|
+
// pattern that backtracks on them (^(((a+)+)+)+b$ on sixteen a's)
|
|
118
|
+
// held the platform RegExp for seconds. A pattern the engine does not
|
|
119
|
+
// take gets no candidate.
|
|
120
|
+
const re = patternIsSafe(schema.pattern) ? compileSafe(schema.pattern) : null
|
|
108
121
|
if (re) {
|
|
109
122
|
const matching = PATTERN_CANDIDATES.filter((c) => re.test(c) && [...c].length >= min && [...c].length <= max)
|
|
110
123
|
if (matching.length) return r.pick(matching)
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
let s = r.pick(WORDS)
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
// Counted once: padding one character at a time with the string spread
|
|
128
|
+
// for each count took 32 s for a minLength of 100000.
|
|
129
|
+
const len = [...s].length
|
|
130
|
+
if (len < min) s += 'a'.repeat(min - len)
|
|
131
|
+
else if (len > max) s = [...s].slice(0, max).join('')
|
|
116
132
|
return s
|
|
117
133
|
}
|
|
118
134
|
case 'array': {
|
|
@@ -321,7 +337,10 @@ async function verifyOne ({ schemaFile, moduleFile, schema, generate: count = 20
|
|
|
321
337
|
if (mod.schemaHash !== undefined && mod.schemaHash !== hash) report.stale = true
|
|
322
338
|
let runtime
|
|
323
339
|
try { runtime = new Validator(schema, {}) } catch (e) { report.error = `schema does not compile: ${e.message}`; return report }
|
|
324
|
-
|
|
340
|
+
let docs
|
|
341
|
+
try {
|
|
342
|
+
docs = generate(schema, count, seed, (d) => { try { return runtime.isValidObject(clone(d)) } catch { return false } }).map((d, i) => ({ source: `generated #${i + 1}`, doc: d }))
|
|
343
|
+
} catch (e) { report.error = `documents cannot be generated: ${e.message}`; return report }
|
|
325
344
|
report.generated = docs.length
|
|
326
345
|
const sampleDocs = readSamples(samples)
|
|
327
346
|
report.samples = sampleDocs.length
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.62.0",
|
|
4
4
|
"description": "JSON Schema validator that compiles to plain JavaScript, still runs where code generation is blocked, and can be compiled away at build time. Passes the full official test suite.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "index.js",
|
|
@@ -89,6 +89,11 @@
|
|
|
89
89
|
"import": "./compiled-standard.mjs",
|
|
90
90
|
"default": "./lib/compiled-standard.js"
|
|
91
91
|
},
|
|
92
|
+
"./stream": {
|
|
93
|
+
"types": "./stream.d.ts",
|
|
94
|
+
"import": "./stream.mjs",
|
|
95
|
+
"default": "./stream.js"
|
|
96
|
+
},
|
|
92
97
|
"./lite": {
|
|
93
98
|
"types": "./lite.d.ts",
|
|
94
99
|
"import": "./lite.mjs",
|
|
@@ -118,6 +123,7 @@
|
|
|
118
123
|
},
|
|
119
124
|
"browser": {
|
|
120
125
|
"./lib/native-load.js": "./lib/native-load.browser.js",
|
|
126
|
+
"./lib/native-attach.js": "./lib/native-attach.browser.js",
|
|
121
127
|
"./lib/aot.js": "./lib/aot.browser.js",
|
|
122
128
|
"./lib/buffer-gate.js": "./lib/buffer-gate.browser.js",
|
|
123
129
|
"./lib/interpreter.js": "./lib/interpreter.browser.js",
|
|
@@ -224,6 +230,9 @@
|
|
|
224
230
|
"compiled-bare-rich.d.ts",
|
|
225
231
|
"compiled-standard.mjs",
|
|
226
232
|
"compiled-standard.d.ts",
|
|
233
|
+
"stream.js",
|
|
234
|
+
"stream.mjs",
|
|
235
|
+
"stream.d.ts",
|
|
227
236
|
"lite.js",
|
|
228
237
|
"lite.mjs",
|
|
229
238
|
"lite.d.ts",
|
|
@@ -238,13 +247,13 @@
|
|
|
238
247
|
"codegen.d.ts"
|
|
239
248
|
],
|
|
240
249
|
"optionalDependencies": {
|
|
241
|
-
"@ata-validator/native-darwin-arm64": "1.
|
|
242
|
-
"@ata-validator/native-darwin-x64": "1.
|
|
243
|
-
"@ata-validator/native-linux-arm64-gnu": "1.
|
|
244
|
-
"@ata-validator/native-linux-arm64-musl": "1.
|
|
245
|
-
"@ata-validator/native-linux-x64-gnu": "1.
|
|
246
|
-
"@ata-validator/native-linux-x64-musl": "1.
|
|
247
|
-
"@ata-validator/native-win32-x64": "1.
|
|
250
|
+
"@ata-validator/native-darwin-arm64": "1.62.0",
|
|
251
|
+
"@ata-validator/native-darwin-x64": "1.62.0",
|
|
252
|
+
"@ata-validator/native-linux-arm64-gnu": "1.62.0",
|
|
253
|
+
"@ata-validator/native-linux-arm64-musl": "1.62.0",
|
|
254
|
+
"@ata-validator/native-linux-x64-gnu": "1.62.0",
|
|
255
|
+
"@ata-validator/native-linux-x64-musl": "1.62.0",
|
|
256
|
+
"@ata-validator/native-win32-x64": "1.62.0"
|
|
248
257
|
},
|
|
249
258
|
"peerDependencies": {
|
|
250
259
|
"yaml": "^2.0.0"
|
package/stream.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Validator, ValidationError } from './index';
|
|
2
|
+
|
|
3
|
+
/** Options of a record stream. */
|
|
4
|
+
export interface StreamOptions {
|
|
5
|
+
/** How the body carries its records: one JSON document per line, a JSON array, or decided from the first non-blank character (default). */
|
|
6
|
+
format?: 'ndjson' | 'array' | 'auto';
|
|
7
|
+
/** Stop at the first record that fails (default true); false sees every record and lists every failure. */
|
|
8
|
+
stopOnFirst?: boolean;
|
|
9
|
+
/** Called with each record that passed, parsed, and its index from zero. */
|
|
10
|
+
onRecord?: (record: unknown, index: number) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** One record's failure: its index from zero and the errors validate() gives for it, or a parse error with keyword `__parse__`. */
|
|
14
|
+
export interface RecordFailure {
|
|
15
|
+
valid: false;
|
|
16
|
+
record: number;
|
|
17
|
+
errors: ValidationError[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** What end() returns: whether every record passed, how many were read, and the failures seen. */
|
|
21
|
+
export interface StreamResult {
|
|
22
|
+
valid: boolean;
|
|
23
|
+
records: number;
|
|
24
|
+
errors: RecordFailure[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** A record stream: feed chunks as they arrive, get the first failure the moment its record is complete. */
|
|
28
|
+
export class RecordStream {
|
|
29
|
+
constructor(validator: Validator<unknown>, opts?: StreamOptions);
|
|
30
|
+
/** Records read so far. */
|
|
31
|
+
readonly records: number;
|
|
32
|
+
/** Failures so far. */
|
|
33
|
+
readonly failures: RecordFailure[];
|
|
34
|
+
/** True once the stream stopped, at a failure or at end(). */
|
|
35
|
+
readonly done: boolean;
|
|
36
|
+
/** Feed a chunk. Returns null while every record so far passes, or the first failure. */
|
|
37
|
+
push(chunk: string | Uint8Array): RecordFailure | null;
|
|
38
|
+
/** Close the input. An unfinished record or an unclosed array is a parse failure. */
|
|
39
|
+
end(): StreamResult;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function streamValidator(validator: Validator<unknown>, opts?: StreamOptions): RecordStream;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Read an async source (a Node Readable, a Web ReadableStream, any iterable of
|
|
46
|
+
* chunks) through a record stream. At the first failure the source is stopped:
|
|
47
|
+
* a Node stream is destroyed, a Web stream's reader cancelled.
|
|
48
|
+
*/
|
|
49
|
+
export function validateStream(validator: Validator<unknown>, source: AsyncIterable<string | Uint8Array> | Iterable<string | Uint8Array> | ReadableStream<Uint8Array | string>, opts?: StreamOptions): Promise<StreamResult>;
|
|
50
|
+
|
|
51
|
+
export const PARSE_KEYWORD: '__parse__';
|
package/stream.js
ADDED
package/stream.mjs
ADDED