ata-validator 1.38.0 → 1.39.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/lib/rejections.js CHANGED
@@ -76,7 +76,7 @@ class RichRejection {
76
76
  }
77
77
  _ataRaw() {
78
78
  let raw = this._result.errors || [];
79
- if (raw.length > 1) raw = sortErrorsBySchemaOrder(this._root, raw);
79
+ if (needsOrdering(raw)) raw = sortErrorsBySchemaOrder(this._root, raw);
80
80
  return raw;
81
81
  }
82
82
  }
@@ -88,7 +88,7 @@ Object.defineProperty(RichRejection.prototype, 'errors', {
88
88
  const self = this._self;
89
89
  const enrich = this._enrich;
90
90
  let raw = this._result.errors || [];
91
- if (raw.length > 1) raw = sortErrorsBySchemaOrder(this._root, raw);
91
+ if (needsOrdering(raw)) raw = sortErrorsBySchemaOrder(this._root, raw);
92
92
  // The position map, resolved now that an error is actually being read.
93
93
  let positions = null;
94
94
  if (enrich && raw.length && this._rawInput != null) {
@@ -172,7 +172,7 @@ Object.defineProperty(LazyJsonRejection.prototype, 'errors', {
172
172
  const positions = self._pos().targeted(jsonStr, wantedPointersFor(raw));
173
173
  // Declaration order, as validate() applies it; the text path used to
174
174
  // enrich in emission order.
175
- const ordered = raw.length > 1 ? sortErrorsBySchemaOrder(self._schemaObj, raw) : raw;
175
+ const ordered = needsOrdering(raw) ? sortErrorsBySchemaOrder(self._schemaObj, raw) : raw;
176
176
  const enrichOpts = {
177
177
  data: parsedData,
178
178
  positions,
@@ -246,11 +246,23 @@ function wantedPointersFor (errors) {
246
246
  return wanted;
247
247
  }
248
248
 
249
- // A raw error without the `_o` ordering key, for the legacy error shape.
249
+ // A raw error in the legacy shape. The error generator writes `code` and
250
+ // `docUrl` into its literals because a standalone module returns them as they
251
+ // are; the runtime's legacy shape never had them, and the interpreter leaves
252
+ // them out, so they are dropped here with the ordering key `_o`. A collapsed
253
+ // oneOf/anyOf error keeps its code, which both engines give it, and its
254
+ // branch errors get the same treatment, so the shape does not depend on
255
+ // which engine answered.
256
+ const COLLAPSE_CODES = new Set(['ATA4001', 'ATA4002', 'ATA4003']);
250
257
  function stripOrdinal(e) {
251
- if (e === null || typeof e !== 'object' || e._o === undefined) return e;
258
+ if (e === null || typeof e !== 'object') return e;
259
+ if (e._o === undefined && e.docUrl === undefined && (e.code === undefined || COLLAPSE_CODES.has(e.code)) && !e.branchErrors) return e;
252
260
  const out = {};
253
- for (const k in e) if (k !== '_o') out[k] = e[k];
261
+ for (const k in e) {
262
+ if (k === '_o' || k === 'docUrl') continue;
263
+ if (k === 'code' && !COLLAPSE_CODES.has(e.code)) continue;
264
+ out[k] = k === 'branchErrors' && Array.isArray(e[k]) ? e[k].map(stripOrdinal) : e[k];
265
+ }
254
266
  return out;
255
267
  }
256
268
 
@@ -261,7 +273,33 @@ function stripOrdinal(e) {
261
273
  // place in the target (rankFor), so they come out in the order they would
262
274
  // inline, whichever engine produced them. Most rejections come out already
263
275
  // ordered, and those return without sorting or allocating.
276
+ // A list of one can still hold a collapsed error whose branch errors, at any
277
+ // depth, need ordering.
278
+ function needsOrdering(raw) {
279
+ if (raw.length > 1) return true;
280
+ const e = raw[0];
281
+ return raw.length === 1 && e !== null && typeof e === 'object' && Array.isArray(e.branchErrors) && needsOrdering(e.branchErrors);
282
+ }
283
+
284
+ // A collapsed oneOf/anyOf error carries the closest branch's errors, which
285
+ // each engine produces in its own walk order. They go in schema order like the
286
+ // list they sit in, so which engine answered cannot be read off them.
287
+ function sortBranchErrors(rootSchema, errors) {
288
+ let out = null;
289
+ for (let i = 0; i < errors.length; i++) {
290
+ const e = errors[i];
291
+ const b = e !== null && typeof e === 'object' ? e.branchErrors : undefined;
292
+ if (!Array.isArray(b) || b.length === 0) continue;
293
+ const sb = sortErrorsBySchemaOrder(rootSchema, b);
294
+ if (sb === b) continue;
295
+ if (out === null) out = errors.slice();
296
+ out[i] = Object.assign({}, e, { branchErrors: sb });
297
+ }
298
+ return out === null ? errors : out;
299
+ }
300
+
264
301
  function sortErrorsBySchemaOrder(rootSchema, errors) {
302
+ errors = sortBranchErrors(rootSchema, errors);
265
303
  const n = errors.length;
266
304
  const keys = new Array(n);
267
305
  let sorted = true;