ata-validator 1.60.0 → 1.61.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/lib/verify.js ADDED
@@ -0,0 +1,321 @@
1
+ 'use strict'
2
+ // `ata verify`: the proof that a compiled module answers as the runtime
3
+ // Validator does, run against a project's own schemas. For every schema the
4
+ // module written by `ata build` is loaded, documents are made from the schema
5
+ // (valid ones, and ones with one rule broken) and read from the project's
6
+ // samples, and both the module and a Validator built from the schema at
7
+ // verification time answer each one; the verdicts and the error lists have to
8
+ // agree. The module's schema hash is checked against the schema as it is now,
9
+ // so a module built from an older schema is reported stale.
10
+ //
11
+ // A validator that wrongly rejects gets a bug report; one that wrongly accepts
12
+ // does not. This command exists so a build-time module gets checked in CI the
13
+ // way the engine is checked here, on every change.
14
+
15
+ const fs = require('fs')
16
+ const path = require('path')
17
+ const { pathToFileURL } = require('url')
18
+
19
+ // A small deterministic generator (xorshift32), so a run can be repeated.
20
+ function rng (seed) {
21
+ let x = (seed >>> 0) || 0x9e3779b9
22
+ const next = () => { x ^= x << 13; x ^= x >>> 17; x ^= x << 5; return (x >>> 0) / 4294967296 }
23
+ return { next, int: (n) => Math.floor(next() * n), pick: (a) => a[Math.floor(next() * a.length)], chance: (p) => next() < p }
24
+ }
25
+
26
+ const WORDS = ['ada', 'Zoë', 'order', 'x', 'north-west', 'a b', 'ÄÖÜ', 'sku-1001', 'TENOFF', 'hello world', '', '0', 'null', '😀', 'line\nbreak', ' ']
27
+ // Strings tried against a `pattern` the generator cannot read: the common
28
+ // shapes of identifiers, codes, addresses, dates and numbers.
29
+ const PATTERN_CANDIDATES = [
30
+ 'a', 'ab', 'abc', 'abc-123', 'ABC', 'A1', 'x_y', 'hello', 'Hello World', 'sku-1001', 'SKU-1001', 'TENOFF',
31
+ 'zoe@example.com', 'a@b.co', 'user.name+tag@example.org', '2026-10-25', '2026-10-25T10:00:00Z', '10:00:00',
32
+ '0', '1', '42', '-7', '3.14', '1e3', '0001', '+905551112233', '555-1234', '#fff', '#a1b2c3',
33
+ 'https://example.com/path', 'http://x.io', 'example.com', '/a/b/c', 'v1.2.3', '1.2.3', 'en-US', 'TR',
34
+ '123e4567-e89b-12d3-a456-426614174000', '192.168.0.1', '::1', 'true', 'null', 'aaaaaaaaaaaaaaaa', 'ÄÖÜ', 'çş'
35
+ ]
36
+ const FORMAT_EXAMPLES = {
37
+ email: ['zoe@example.com', 'a@b.co', 'not an email', 'x@', '@y.com'],
38
+ 'date-time': ['2026-10-25T10:00:00Z', '2026-10-25T10:00:00+03:00', '2026-10-25 10:00', 'yesterday'],
39
+ date: ['2026-10-25', '2026-13-01', '2026-2-5'],
40
+ time: ['10:00:00Z', '25:00:00Z', '10:00'],
41
+ uuid: ['123e4567-e89b-12d3-a456-426614174000', '123e4567-e89b-12d3-a456', 'not-a-uuid'],
42
+ uri: ['https://example.com/a?b=1', 'example.com', '/relative', 'mailto:a@b.co'],
43
+ 'uri-reference': ['https://example.com', '/path', '#frag', ' spaced'],
44
+ ipv4: ['192.168.0.1', '256.1.1.1', '1.2.3'],
45
+ ipv6: ['::1', '2001:db8::1', '2001:db8:::1', '1.2.3.4'],
46
+ hostname: ['example.com', 'a-b.c', '-bad.com', 'x'.repeat(70)],
47
+ regex: ['^a+$', '([', '\\d+'],
48
+ 'json-pointer': ['/a/b', 'a/b', '/a~1b', '/a~2'],
49
+ }
50
+
51
+ // A value meant to satisfy `schema`, built from its keywords; where the
52
+ // schema says little, something plausible of the kind.
53
+ function makeValid (schema, r, defs, depth) {
54
+ if (schema === true || schema === undefined) return r.pick([1, 'x', true, null, {}, []])
55
+ if (schema === false) return undefined
56
+ if (typeof schema !== 'object' || schema === null) return null
57
+ if (schema.$ref !== undefined && typeof schema.$ref === 'string') {
58
+ const t = resolveLocal(schema.$ref, defs)
59
+ if (t !== undefined && depth < 6) return makeValid(t, r, defs, depth + 1)
60
+ }
61
+ if (schema.const !== undefined) return clone(schema.const)
62
+ if (Array.isArray(schema.enum) && schema.enum.length) return clone(r.pick(schema.enum))
63
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length) return makeValid(r.pick(schema.oneOf), r, defs, depth + 1)
64
+ if (Array.isArray(schema.anyOf) && schema.anyOf.length) return makeValid(r.pick(schema.anyOf), r, defs, depth + 1)
65
+ if (Array.isArray(schema.allOf) && schema.allOf.length) return makeValid(mergeAllOf(schema), r, defs, depth + 1)
66
+ let type = schema.type
67
+ if (Array.isArray(type)) type = r.pick(type)
68
+ if (type === undefined) {
69
+ if (schema.properties || schema.required || schema.additionalProperties !== undefined) type = 'object'
70
+ else if (schema.items || schema.prefixItems || schema.minItems !== undefined) type = 'array'
71
+ else if (schema.minLength !== undefined || schema.maxLength !== undefined || schema.pattern !== undefined || schema.format !== undefined) type = 'string'
72
+ else if (schema.minimum !== undefined || schema.maximum !== undefined || schema.multipleOf !== undefined) type = 'number'
73
+ else type = r.pick(['string', 'number', 'object', 'array', 'boolean', 'null'])
74
+ }
75
+ switch (type) {
76
+ case 'null': return null
77
+ case 'boolean': return r.chance(0.5)
78
+ case 'integer':
79
+ case 'number': {
80
+ let lo = schema.minimum !== undefined ? schema.minimum : schema.exclusiveMinimum !== undefined && typeof schema.exclusiveMinimum === 'number' ? schema.exclusiveMinimum + 1 : -1000
81
+ let hi = schema.maximum !== undefined ? schema.maximum : schema.exclusiveMaximum !== undefined && typeof schema.exclusiveMaximum === 'number' ? schema.exclusiveMaximum - 1 : 1000
82
+ if (hi < lo) hi = lo
83
+ let v = lo + r.next() * (hi - lo)
84
+ if (type === 'integer' || r.chance(0.6)) v = Math.round(v)
85
+ if (typeof schema.multipleOf === 'number' && schema.multipleOf > 0) v = Math.round(v / schema.multipleOf) * schema.multipleOf
86
+ if (v < lo) v = lo
87
+ if (v > hi) v = hi
88
+ return v
89
+ }
90
+ case 'string': {
91
+ if (schema.format && FORMAT_EXAMPLES[schema.format]) return r.pick(FORMAT_EXAMPLES[schema.format])
92
+ const min = schema.minLength || 0
93
+ const max = schema.maxLength !== undefined ? schema.maxLength : Math.max(min, 12)
94
+ if (schema.pattern) {
95
+ const simple = /^\^?\[([a-zA-Z0-9-]+)\]([+*])?\$?$/.exec(schema.pattern)
96
+ if (simple) {
97
+ const set = simple[1].includes('a-z') ? 'abcdefgh' : simple[1].includes('0-9') ? '0123456789' : simple[1].includes('A-Z') ? 'ABCDEFGH' : simple[1].replace(/-/g, '')
98
+ let s = ''
99
+ const n = Math.max(min, Math.min(max, 1 + r.int(8)))
100
+ for (let i = 0; i < n; i++) s += set[r.int(set.length)]
101
+ return s
102
+ }
103
+ // Any other pattern: a candidate that matches, when one does, so the
104
+ // generated documents reach past the pattern; else a word, which the
105
+ // schema then refuses, and that is a document too.
106
+ let re = null
107
+ try { re = new RegExp(schema.pattern, 'u') } catch {}
108
+ if (re) {
109
+ const matching = PATTERN_CANDIDATES.filter((c) => re.test(c) && [...c].length >= min && [...c].length <= max)
110
+ if (matching.length) return r.pick(matching)
111
+ }
112
+ }
113
+ let s = r.pick(WORDS)
114
+ while ([...s].length < min) s += 'a'
115
+ if ([...s].length > max) s = [...s].slice(0, max).join('')
116
+ return s
117
+ }
118
+ case 'array': {
119
+ const min = schema.minItems || 0
120
+ const max = schema.maxItems !== undefined ? schema.maxItems : Math.max(min, 4)
121
+ const n = depth > 4 ? min : min + r.int(Math.max(1, max - min + 1))
122
+ const out = []
123
+ for (let i = 0; i < n; i++) {
124
+ const sub = Array.isArray(schema.prefixItems) && i < schema.prefixItems.length ? schema.prefixItems[i] : Array.isArray(schema.items) ? (schema.items[i] !== undefined ? schema.items[i] : schema.additionalItems) : schema.items
125
+ if (sub === false) break
126
+ out.push(makeValid(sub === undefined ? true : sub, r, defs, depth + 1))
127
+ }
128
+ if (schema.uniqueItems) return out.filter((v, i, a) => a.findIndex((w) => JSON.stringify(w) === JSON.stringify(v)) === i)
129
+ return out
130
+ }
131
+ case 'object':
132
+ default: {
133
+ const out = {}
134
+ const props = schema.properties && typeof schema.properties === 'object' ? schema.properties : {}
135
+ const required = new Set(Array.isArray(schema.required) ? schema.required : [])
136
+ for (const k of Object.keys(props)) {
137
+ if (k === '__proto__') continue
138
+ if (required.has(k) || r.chance(0.7)) out[k] = makeValid(props[k], r, defs, depth + 1)
139
+ }
140
+ for (const k of required) if (!(k in out) && k !== '__proto__') out[k] = makeValid(props[k] === undefined ? true : props[k], r, defs, depth + 1)
141
+ if (schema.additionalProperties !== false && !schema.patternProperties && r.chance(0.2) && depth < 4) out[`extra${r.int(3)}`] = makeValid(typeof schema.additionalProperties === 'object' ? schema.additionalProperties : true, r, defs, depth + 1)
142
+ if (schema.patternProperties && r.chance(0.5)) {
143
+ for (const [p, sub] of Object.entries(schema.patternProperties)) {
144
+ const m = /^\^?([a-zA-Z_]+)/.exec(p)
145
+ if (m) out[m[1] + r.int(9)] = makeValid(sub, r, defs, depth + 1)
146
+ }
147
+ }
148
+ return out
149
+ }
150
+ }
151
+ }
152
+
153
+ function mergeAllOf (schema) {
154
+ const merged = {}
155
+ for (const b of schema.allOf) if (typeof b === 'object' && b !== null) Object.assign(merged, b, { properties: { ...(merged.properties || {}), ...(b.properties || {}) }, required: [...(merged.required || []), ...(b.required || [])] })
156
+ for (const k of Object.keys(schema)) if (k !== 'allOf' && merged[k] === undefined) merged[k] = schema[k]
157
+ return merged
158
+ }
159
+
160
+ function resolveLocal (ref, defs) {
161
+ const m = /^#\/(\$defs|definitions)\/([^/]+)$/.exec(ref)
162
+ if (!m || !defs[m[1]]) return undefined
163
+ const key = decodeURIComponent(m[2].replace(/~1/g, '/').replace(/~0/g, '~'))
164
+ return Object.prototype.hasOwnProperty.call(defs[m[1]], key) ? defs[m[1]][key] : undefined
165
+ }
166
+
167
+ function clone (v) { return v === undefined ? v : JSON.parse(JSON.stringify(v)) }
168
+
169
+ // One rule broken somewhere in `doc`: a kind swapped, a key dropped or added,
170
+ // a number pushed out of range, a string lengthened or emptied, an array
171
+ // emptied or an element duplicated. The point is a document the schema is
172
+ // likely to refuse, so both engines get to disagree on refusals too.
173
+ function mutate (doc, r) {
174
+ const paths = []
175
+ const walk = (v, p) => {
176
+ paths.push(p)
177
+ if (Array.isArray(v)) v.forEach((x, i) => walk(x, [...p, i]))
178
+ else if (v && typeof v === 'object') for (const k of Object.keys(v)) walk(v[k], [...p, k])
179
+ }
180
+ walk(doc, [])
181
+ const p = r.pick(paths)
182
+ const get = (o, q) => q.reduce((a, k) => (a == null ? a : a[k]), o)
183
+ const set = (o, q, val) => { if (q.length === 0) return val; const parent = get(o, q.slice(0, -1)); if (parent != null) parent[q[q.length - 1]] = val; return o }
184
+ const del = (o, q) => { const parent = get(o, q.slice(0, -1)); if (Array.isArray(parent)) parent.splice(q[q.length - 1], 1); else if (parent) delete parent[q[q.length - 1]]; return o }
185
+ const v = get(doc, p)
186
+ switch (r.int(8)) {
187
+ case 0: return set(doc, p, r.pick([null, true, 'str', 0, [], {}]))
188
+ case 1: return p.length ? del(doc, p) : set(doc, p, null)
189
+ case 2: if (v && typeof v === 'object' && !Array.isArray(v)) { v[`unexpected${r.int(5)}`] = r.pick([1, 'x', null]); return doc } return set(doc, p, 'unexpected')
190
+ case 3: return set(doc, p, typeof v === 'number' ? r.pick([v * 1000 + 1, -v - 1, v + 0.5, Number.MAX_SAFE_INTEGER, -1]) : -1)
191
+ case 4: return set(doc, p, typeof v === 'string' ? r.pick(['', v.repeat(40), v + ' ', '😀' + v, v.toUpperCase()]) : '')
192
+ case 5: if (Array.isArray(v)) { if (v.length && r.chance(0.5)) v.push(clone(v[0])); else v.length = 0; return doc } return set(doc, p, [])
193
+ case 6: return set(doc, p, typeof v === 'boolean' ? !v : typeof v === 'number' ? String(v) : typeof v === 'string' ? Number(v) || 7 : v)
194
+ default: return JSON.parse(JSON.stringify(doc).replace(/"([a-zA-Z]+)":/, '"$1_":'))
195
+ }
196
+ }
197
+
198
+ // Documents for `schema`: `count` made, half of them with one rule broken.
199
+ function generate (schema, count, seed) {
200
+ const r = rng(seed)
201
+ const defs = { $defs: schema && schema.$defs, definitions: schema && schema.definitions }
202
+ const docs = []
203
+ for (let i = 0; i < count; i++) {
204
+ let d = makeValid(schema, r, defs, 0)
205
+ if (i % 2 === 1 && d !== undefined) d = mutate(clone(d), r)
206
+ docs.push(d)
207
+ }
208
+ return docs
209
+ }
210
+
211
+ // The project's own documents: a JSON file is one document, a JSON Lines
212
+ // file one per line, a JSON array is taken as one document, not several.
213
+ function readSamples (paths) {
214
+ const docs = []
215
+ const files = []
216
+ for (const p of paths) {
217
+ if (!fs.existsSync(p)) continue
218
+ if (fs.statSync(p).isDirectory()) {
219
+ for (const f of fs.readdirSync(p).sort()) if (/\.(json|jsonl|ndjson)$/.test(f)) files.push(path.join(p, f))
220
+ } else files.push(p)
221
+ }
222
+ for (const f of files) {
223
+ const text = fs.readFileSync(f, 'utf8')
224
+ if (/\.(jsonl|ndjson)$/.test(f)) {
225
+ text.split('\n').forEach((line, i) => { if (line.trim()) { try { docs.push({ source: `${f}:${i + 1}`, doc: JSON.parse(line) }) } catch {} } })
226
+ } else {
227
+ try { docs.push({ source: f, doc: JSON.parse(text) }) } catch { docs.push({ source: f, doc: undefined, bad: true }) }
228
+ }
229
+ }
230
+ return docs
231
+ }
232
+
233
+ function errorKey (e) { return `${e.keyword || ''}@${e.instancePath || ''}` }
234
+ function summarize (result) {
235
+ if (!result || typeof result !== 'object') return 'no result'
236
+ const errs = Array.isArray(result.errors) ? result.errors.map(errorKey).sort() : []
237
+ return `${result.valid ? 'valid' : 'invalid'} ${errs.join(' ')}`
238
+ }
239
+
240
+ async function loadModule (file) {
241
+ if (/\.cjs$/.test(file)) { delete require.cache[require.resolve(file)]; return require(file) }
242
+ return import(pathToFileURL(file).href + `?t=${Date.now()}`)
243
+ }
244
+
245
+ // Verifies one schema against its module. Returns a report object.
246
+ async function verifyOne ({ schemaFile, moduleFile, schema, generate: count = 200, seed = 1, samples = [] }) {
247
+ const { Validator } = require('..')
248
+ const { schemaHash } = require('./schema-hash')
249
+ const report = { schema: schemaFile, module: moduleFile, documents: 0, generated: 0, samples: 0, valid: 0, agree: 0, disagreements: [], stale: false, missing: false, ataVersion: null, error: null }
250
+ if (!fs.existsSync(moduleFile)) { report.missing = true; return report }
251
+ let mod
252
+ try { mod = await loadModule(moduleFile) } catch (e) { report.error = `module does not load: ${e.message}`; return report }
253
+ if (typeof mod.isValid !== 'function' || typeof mod.validate !== 'function') { report.error = 'module exports no isValid and validate'; return report }
254
+ report.ataVersion = mod.ataVersion || null
255
+ const hash = schemaHash(schema)
256
+ if (mod.schemaHash !== undefined && mod.schemaHash !== hash) report.stale = true
257
+ let runtime
258
+ try { runtime = new Validator(schema, {}) } catch (e) { report.error = `schema does not compile: ${e.message}`; return report }
259
+ const docs = generate(schema, count, seed).map((d, i) => ({ source: `generated #${i + 1}`, doc: d }))
260
+ report.generated = docs.length
261
+ const sampleDocs = readSamples(samples)
262
+ report.samples = sampleDocs.length
263
+ for (const { source, doc, bad } of [...docs, ...sampleDocs]) {
264
+ if (bad || doc === undefined) continue
265
+ report.documents++
266
+ const text = JSON.stringify(doc)
267
+ const a = runtime.validate(JSON.parse(text))
268
+ const b = mod.validate(JSON.parse(text))
269
+ const aIs = runtime.isValidObject(JSON.parse(text))
270
+ const bIs = mod.isValid(JSON.parse(text))
271
+ if (a.valid) report.valid++
272
+ const sa = summarize(a), sb = summarize(b)
273
+ if (sa === sb && aIs === bIs && aIs === a.valid) { report.agree++; continue }
274
+ if (report.disagreements.length < 20) report.disagreements.push({ source, document: text.length > 400 ? text.slice(0, 400) + '…' : text, runtime: sa, module: sb, runtimeIsValid: aIs, moduleIsValid: bIs })
275
+ else report.disagreements.push(null)
276
+ }
277
+ report.disagreements = report.disagreements.filter(Boolean).concat(report.documents - report.agree > 20 ? [{ more: report.documents - report.agree - 20 }] : [])
278
+ return report
279
+ }
280
+
281
+ function renderReport (reports, { json = false } = {}) {
282
+ if (json) return JSON.stringify({ ok: reports.every(ok), schemas: reports }, null, 2)
283
+ const lines = []
284
+ for (const r of reports) {
285
+ const name = path.relative(process.cwd(), r.schema) || r.schema
286
+ if (r.missing) { lines.push(`${name}: no module at ${path.relative(process.cwd(), r.module)}; run ata build first`); continue }
287
+ if (r.error) { lines.push(`${name}: ${r.error}`); continue }
288
+ const dis = r.documents - r.agree
289
+ lines.push(`${name}: ${r.documents} documents (${r.generated} generated, ${r.samples} from samples), ${r.valid} valid by the runtime, ${r.agree} agree, ${dis} disagree${r.stale ? '; STALE: the module was built from a different schema' : ''}${r.ataVersion ? ` (module from ata ${r.ataVersion})` : ''}`)
290
+ for (const d of r.disagreements) {
291
+ if (d.more) { lines.push(` ... and ${d.more} more`); continue }
292
+ lines.push(` ${d.source}`)
293
+ lines.push(` document ${d.document}`)
294
+ lines.push(` runtime ${d.runtime}${d.runtimeIsValid !== (d.runtime.startsWith('valid')) ? ` (isValidObject ${d.runtimeIsValid})` : ''}`)
295
+ lines.push(` module ${d.module}${d.moduleIsValid !== (d.module.startsWith('valid')) ? ` (isValid ${d.moduleIsValid})` : ''}`)
296
+ }
297
+ }
298
+ const bad = reports.filter((r) => !ok(r))
299
+ lines.push(bad.length === 0
300
+ ? `ata verify: ${reports.length} schema${reports.length === 1 ? '' : 's'}, every module answers as the runtime does`
301
+ : `ata verify: ${bad.length} of ${reports.length} schema${reports.length === 1 ? '' : 's'} failed`)
302
+ return lines.join('\n')
303
+ }
304
+
305
+ function ok (r) { return !r.missing && !r.error && !r.stale && r.documents === r.agree }
306
+
307
+ // A module given as source text (a plugin's inlined module) held against the
308
+ // runtime the same way: written to a temporary file, loaded, verified.
309
+ async function verifySource (schema, src, opts = {}) {
310
+ const os = require('os')
311
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ata-verify-src-'))
312
+ const file = path.join(dir, `m.${opts.format === 'cjs' ? 'cjs' : 'mjs'}`)
313
+ fs.writeFileSync(file, src)
314
+ try {
315
+ return await verifyOne({ schemaFile: opts.name || 'schema', moduleFile: file, schema, generate: opts.generate, seed: opts.seed, samples: opts.samples || [] })
316
+ } finally {
317
+ fs.rmSync(dir, { recursive: true, force: true })
318
+ }
319
+ }
320
+
321
+ module.exports = { verifyOne, verifySource, renderReport, generate, mutate, readSamples, ok }
package/lib/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  //
8
8
  // Kept in lockstep with package.json by `tests/test_version_sync.js`.
9
9
 
10
- module.exports = '1.60.0';
10
+ module.exports = '1.61.0';
package/lite.js CHANGED
@@ -21,5 +21,6 @@ module.exports = {
21
21
  validateAsync: core.validateAsync,
22
22
  parseAsync: core.parseAsync,
23
23
  defineSchema: core.defineSchema,
24
+ schemaOf: core.schemaOf,
24
25
  version: core.version,
25
26
  };
package/lite.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import mod from './lite.js';
2
- export const { Validator, validate, validateAsync, parseAsync, defineSchema, version } = mod;
2
+ export const { Validator, validate, validateAsync, parseAsync, defineSchema, schemaOf, version } = mod;
3
3
  export default mod;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ata-validator",
3
- "version": "1.60.0",
3
+ "version": "1.61.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",
@@ -88,7 +88,8 @@
88
88
  "./lib/native-load.js": "./lib/native-load.browser.js",
89
89
  "./lib/aot.js": "./lib/aot.browser.js",
90
90
  "./lib/buffer-gate.js": "./lib/buffer-gate.browser.js",
91
- "./lib/interpreter.js": "./lib/interpreter.browser.js"
91
+ "./lib/interpreter.js": "./lib/interpreter.browser.js",
92
+ "./lib/aot-order.js": false
92
93
  },
93
94
  "scripts": {
94
95
  "prepublishOnly": "node tests/test_pack_purity.js && ATA_ALLOW_DOC_PLACEHOLDERS=1 node scripts/check-doc-coverage.js && node tests/test_error_codes_lock.js && node tests/test_safe_regex_embed.js && node tests/test_version_sync.js",
@@ -186,13 +187,13 @@
186
187
  "codegen.d.ts"
187
188
  ],
188
189
  "optionalDependencies": {
189
- "@ata-validator/native-darwin-arm64": "1.60.0",
190
- "@ata-validator/native-darwin-x64": "1.60.0",
191
- "@ata-validator/native-linux-arm64-gnu": "1.60.0",
192
- "@ata-validator/native-linux-arm64-musl": "1.60.0",
193
- "@ata-validator/native-linux-x64-gnu": "1.60.0",
194
- "@ata-validator/native-linux-x64-musl": "1.60.0",
195
- "@ata-validator/native-win32-x64": "1.60.0"
190
+ "@ata-validator/native-darwin-arm64": "1.61.0",
191
+ "@ata-validator/native-darwin-x64": "1.61.0",
192
+ "@ata-validator/native-linux-arm64-gnu": "1.61.0",
193
+ "@ata-validator/native-linux-arm64-musl": "1.61.0",
194
+ "@ata-validator/native-linux-x64-gnu": "1.61.0",
195
+ "@ata-validator/native-linux-x64-musl": "1.61.0",
196
+ "@ata-validator/native-win32-x64": "1.61.0"
196
197
  },
197
198
  "peerDependencies": {
198
199
  "yaml": "^2.0.0"