decoders 2.12.1 → 2.12.3

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/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/lib/utils.ts
2
+ var MAX_ERRORS = 3;
2
3
  // @__NO_SIDE_EFFECTS__
3
4
  function qty(n, unit) {
4
5
  return n === 1 ? `${n} ${unit}` : `${n} ${unit}s`;
@@ -220,8 +221,12 @@ function serializeArray(annotation, prefix) {
220
221
  return "[]";
221
222
  }
222
223
  const result = [];
223
- for (const item of items) {
224
- const [ser, ann] = serializeAnnotation(item, `${prefix}${INDENT}`);
224
+ for (let i = 0; i < items.length; ++i) {
225
+ const [ser, ann] = serializeAnnotation(
226
+ items[i],
227
+ `${prefix}${INDENT}`,
228
+ `(at index ${i})`
229
+ );
225
230
  result.push(`${prefix}${INDENT}${ser},`);
226
231
  if (ann !== void 0) {
227
232
  result.push(indent(ann, `${prefix}${INDENT}`));
@@ -267,7 +272,7 @@ function serializeValue(value) {
267
272
  }
268
273
  }
269
274
  }
270
- function serializeAnnotation(ann, prefix = "") {
275
+ function serializeAnnotation(ann, prefix = "", location) {
271
276
  let serialized;
272
277
  if (ann.type === "array") {
273
278
  serialized = serializeArray(ann, prefix);
@@ -283,7 +288,8 @@ function serializeAnnotation(ann, prefix = "") {
283
288
  const text = ann.text;
284
289
  if (text !== void 0) {
285
290
  const sep = "^".repeat(isMultiline(serialized) ? 1 : serialized.length);
286
- return [serialized, [sep, text].join(isMultiline(text) ? "\n" : " ")];
291
+ const annotation = isMultiline(text) ? [location ? `${sep} ${location}` : sep, text].join("\n") : [sep, text, location].filter(Boolean).join(" ");
292
+ return [serialized, annotation];
287
293
  } else {
288
294
  return [serialized, void 0];
289
295
  }
@@ -623,24 +629,25 @@ function array(decoder, options) {
623
629
  const base = options !== void 0 ? sized(poja, options) : poja;
624
630
  return base.chain((inputs, ok2, err2) => {
625
631
  const results = [];
632
+ let clone = null;
633
+ let errorCount = 0;
626
634
  for (let i = 0; i < inputs.length; ++i) {
627
635
  const blob = inputs[i];
628
636
  const result = decodeFn(blob);
629
637
  if (result.ok) {
630
- results.push(result.value);
638
+ if (clone === null) {
639
+ results.push(result.value);
640
+ }
631
641
  } else {
632
642
  results.length = 0;
633
- const ann = result.error;
634
- const clone = inputs.slice();
635
- clone.splice(
636
- i,
637
- 1,
638
- public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
639
- );
640
- return err2(public_annotate(clone));
643
+ clone ??= inputs.slice();
644
+ clone[i] = result.error;
645
+ if (++errorCount >= MAX_ERRORS) {
646
+ break;
647
+ }
641
648
  }
642
649
  }
643
- return ok2(results);
650
+ return clone !== null ? err2(public_annotate(clone)) : ok2(results);
644
651
  });
645
652
  }
646
653
  // @__NO_SIDE_EFFECTS__
@@ -670,18 +677,6 @@ function tuple(...decoders) {
670
677
  });
671
678
  }
672
679
 
673
- // src/lib/set-methods.ts
674
- // @__NO_SIDE_EFFECTS__
675
- function difference(xs, ys) {
676
- const result = /* @__PURE__ */ new Set();
677
- for (const x of xs) {
678
- if (!ys.has(x)) {
679
- result.add(x);
680
- }
681
- }
682
- return result;
683
- }
684
-
685
680
  // src/objects.ts
686
681
  // @__NO_SIDE_EFFECTS__
687
682
  function rejectUnsafeKey(decoders) {
@@ -703,13 +698,12 @@ var pojo = define(
703
698
  );
704
699
  // @__NO_SIDE_EFFECTS__
705
700
  function buildObject(decoders) {
706
- const knownKeys = new Set(Object.keys(decoders));
701
+ const knownKeys = Object.keys(decoders);
707
702
  return pojo.chain((plainObj, ok2, err2) => {
708
- const actualKeys = new Set(Object.keys(plainObj));
709
- const missingKeys = difference(knownKeys, actualKeys);
710
703
  const record2 = {};
711
704
  let errors = null;
712
- for (const key of Object.keys(decoders)) {
705
+ let missingKeys = null;
706
+ for (const key of knownKeys) {
713
707
  const decoder = decoders[key];
714
708
  const rawValue = plainObj[key];
715
709
  const result = decoder.decode(rawValue);
@@ -718,25 +712,23 @@ function buildObject(decoders) {
718
712
  if (value !== void 0) {
719
713
  record2[key] = value;
720
714
  }
721
- missingKeys.delete(key);
722
715
  } else {
723
716
  const ann = result.error;
724
717
  if (rawValue === void 0) {
725
- missingKeys.add(key);
718
+ (missingKeys ??= []).push(key);
726
719
  } else {
727
- errors ??= /* @__PURE__ */ new Map();
728
- errors.set(key, ann);
720
+ (errors ??= /* @__PURE__ */ new Map()).set(key, ann);
729
721
  }
730
722
  }
731
723
  }
732
- if (errors || missingKeys.size > 0) {
724
+ if (errors || missingKeys) {
733
725
  let objAnn = public_annotateObject(plainObj);
734
726
  if (errors) {
735
727
  objAnn = merge(objAnn, errors);
736
728
  }
737
- if (missingKeys.size > 0) {
738
- const errMsg = Array.from(missingKeys).map(quote).join(", ");
739
- const pluralized = missingKeys.size > 1 ? "keys" : "key";
729
+ if (missingKeys) {
730
+ const errMsg = missingKeys.map(quote).join(", ");
731
+ const pluralized = missingKeys.length > 1 ? "keys" : "key";
740
732
  objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
741
733
  }
742
734
  return err2(objAnn);
@@ -753,41 +745,50 @@ function object(decoders) {
753
745
  function exact(decoders) {
754
746
  /* @__PURE__ */ rejectUnsafeKey(decoders);
755
747
  const allowedKeys = new Set(Object.keys(decoders));
756
- const checked = pojo.chain((plainObj, ok2, err2) => {
757
- const actualKeys = new Set(Object.keys(plainObj));
758
- if (actualKeys.has("__proto__")) {
759
- return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
748
+ const objDecoder = /* @__PURE__ */ buildObject(decoders);
749
+ return pojo.chain((plainObj, _ok, err2) => {
750
+ let extraKeys = null;
751
+ for (const key of Object.keys(plainObj)) {
752
+ if (key === "__proto__") {
753
+ return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
754
+ }
755
+ if (!allowedKeys.has(key)) {
756
+ (extraKeys ??= []).push(key);
757
+ }
758
+ }
759
+ if (extraKeys) {
760
+ return err2(`Unexpected extra keys: ${extraKeys.map(quote).join(", ")}`);
760
761
  }
761
- const extraKeys = difference(actualKeys, allowedKeys);
762
- return extraKeys.size > 0 ? err2(`Unexpected extra keys: ${Array.from(extraKeys).map(quote).join(", ")}`) : ok2(plainObj);
762
+ return objDecoder.decode(plainObj);
763
763
  });
764
- return checked.pipe(/* @__PURE__ */ buildObject(decoders));
765
764
  }
766
765
  // @__NO_SIDE_EFFECTS__
767
766
  function inexact(decoders) {
768
767
  /* @__PURE__ */ rejectUnsafeKey(decoders);
768
+ const safekeys = new Set(Object.keys(decoders));
769
+ const safeDecoder = /* @__PURE__ */ buildObject(decoders);
769
770
  return pojo.chain(
770
- (plainObj, _ok, err2) => {
771
+ (plainObj, ok2, err2) => {
771
772
  const allkeys = new Set(Object.keys(plainObj));
772
773
  if (allkeys.has("__proto__")) {
773
774
  return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
774
775
  }
775
- return (/* @__PURE__ */ buildObject(decoders)).transform((safepart) => {
776
- const safekeys = new Set(Object.keys(decoders));
777
- for (const k of safekeys) allkeys.add(k);
778
- const rv = {};
779
- for (const k of allkeys) {
780
- if (safekeys.has(k)) {
781
- const value = safepart[k];
782
- if (value !== void 0) {
783
- rv[k] = value;
784
- }
785
- } else {
786
- rv[k] = plainObj[k];
776
+ const result = safeDecoder.decode(plainObj);
777
+ if (!result.ok) return result;
778
+ const safepart = result.value;
779
+ for (const k of safekeys) allkeys.add(k);
780
+ const rv = {};
781
+ for (const k of allkeys) {
782
+ if (safekeys.has(k)) {
783
+ const value = safepart[k];
784
+ if (value !== void 0) {
785
+ rv[k] = value;
787
786
  }
787
+ } else {
788
+ rv[k] = plainObj[k];
788
789
  }
789
- return rv;
790
- });
790
+ }
791
+ return ok2(rv);
791
792
  }
792
793
  );
793
794
  }
@@ -945,6 +946,9 @@ function record(fst, snd) {
945
946
  errors.set(key, result.error);
946
947
  rv = {};
947
948
  }
949
+ if (errors.size >= MAX_ERRORS) {
950
+ break;
951
+ }
948
952
  }
949
953
  if (errors.size > 0) {
950
954
  return err2(merge(public_annotateObject(input), errors));
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/lib/utils.ts
2
+ var MAX_ERRORS = 3;
2
3
  // @__NO_SIDE_EFFECTS__
3
4
  function qty(n, unit) {
4
5
  return n === 1 ? `${n} ${unit}` : `${n} ${unit}s`;
@@ -220,8 +221,12 @@ function serializeArray(annotation, prefix) {
220
221
  return "[]";
221
222
  }
222
223
  const result = [];
223
- for (const item of items) {
224
- const [ser, ann] = serializeAnnotation(item, `${prefix}${INDENT}`);
224
+ for (let i = 0; i < items.length; ++i) {
225
+ const [ser, ann] = serializeAnnotation(
226
+ items[i],
227
+ `${prefix}${INDENT}`,
228
+ `(at index ${i})`
229
+ );
225
230
  result.push(`${prefix}${INDENT}${ser},`);
226
231
  if (ann !== void 0) {
227
232
  result.push(indent(ann, `${prefix}${INDENT}`));
@@ -267,7 +272,7 @@ function serializeValue(value) {
267
272
  }
268
273
  }
269
274
  }
270
- function serializeAnnotation(ann, prefix = "") {
275
+ function serializeAnnotation(ann, prefix = "", location) {
271
276
  let serialized;
272
277
  if (ann.type === "array") {
273
278
  serialized = serializeArray(ann, prefix);
@@ -283,7 +288,8 @@ function serializeAnnotation(ann, prefix = "") {
283
288
  const text = ann.text;
284
289
  if (text !== void 0) {
285
290
  const sep = "^".repeat(isMultiline(serialized) ? 1 : serialized.length);
286
- return [serialized, [sep, text].join(isMultiline(text) ? "\n" : " ")];
291
+ const annotation = isMultiline(text) ? [location ? `${sep} ${location}` : sep, text].join("\n") : [sep, text, location].filter(Boolean).join(" ");
292
+ return [serialized, annotation];
287
293
  } else {
288
294
  return [serialized, void 0];
289
295
  }
@@ -623,24 +629,25 @@ function array(decoder, options) {
623
629
  const base = options !== void 0 ? sized(poja, options) : poja;
624
630
  return base.chain((inputs, ok2, err2) => {
625
631
  const results = [];
632
+ let clone = null;
633
+ let errorCount = 0;
626
634
  for (let i = 0; i < inputs.length; ++i) {
627
635
  const blob = inputs[i];
628
636
  const result = decodeFn(blob);
629
637
  if (result.ok) {
630
- results.push(result.value);
638
+ if (clone === null) {
639
+ results.push(result.value);
640
+ }
631
641
  } else {
632
642
  results.length = 0;
633
- const ann = result.error;
634
- const clone = inputs.slice();
635
- clone.splice(
636
- i,
637
- 1,
638
- public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
639
- );
640
- return err2(public_annotate(clone));
643
+ clone ??= inputs.slice();
644
+ clone[i] = result.error;
645
+ if (++errorCount >= MAX_ERRORS) {
646
+ break;
647
+ }
641
648
  }
642
649
  }
643
- return ok2(results);
650
+ return clone !== null ? err2(public_annotate(clone)) : ok2(results);
644
651
  });
645
652
  }
646
653
  // @__NO_SIDE_EFFECTS__
@@ -670,18 +677,6 @@ function tuple(...decoders) {
670
677
  });
671
678
  }
672
679
 
673
- // src/lib/set-methods.ts
674
- // @__NO_SIDE_EFFECTS__
675
- function difference(xs, ys) {
676
- const result = /* @__PURE__ */ new Set();
677
- for (const x of xs) {
678
- if (!ys.has(x)) {
679
- result.add(x);
680
- }
681
- }
682
- return result;
683
- }
684
-
685
680
  // src/objects.ts
686
681
  // @__NO_SIDE_EFFECTS__
687
682
  function rejectUnsafeKey(decoders) {
@@ -703,13 +698,12 @@ var pojo = define(
703
698
  );
704
699
  // @__NO_SIDE_EFFECTS__
705
700
  function buildObject(decoders) {
706
- const knownKeys = new Set(Object.keys(decoders));
701
+ const knownKeys = Object.keys(decoders);
707
702
  return pojo.chain((plainObj, ok2, err2) => {
708
- const actualKeys = new Set(Object.keys(plainObj));
709
- const missingKeys = difference(knownKeys, actualKeys);
710
703
  const record2 = {};
711
704
  let errors = null;
712
- for (const key of Object.keys(decoders)) {
705
+ let missingKeys = null;
706
+ for (const key of knownKeys) {
713
707
  const decoder = decoders[key];
714
708
  const rawValue = plainObj[key];
715
709
  const result = decoder.decode(rawValue);
@@ -718,25 +712,23 @@ function buildObject(decoders) {
718
712
  if (value !== void 0) {
719
713
  record2[key] = value;
720
714
  }
721
- missingKeys.delete(key);
722
715
  } else {
723
716
  const ann = result.error;
724
717
  if (rawValue === void 0) {
725
- missingKeys.add(key);
718
+ (missingKeys ??= []).push(key);
726
719
  } else {
727
- errors ??= /* @__PURE__ */ new Map();
728
- errors.set(key, ann);
720
+ (errors ??= /* @__PURE__ */ new Map()).set(key, ann);
729
721
  }
730
722
  }
731
723
  }
732
- if (errors || missingKeys.size > 0) {
724
+ if (errors || missingKeys) {
733
725
  let objAnn = public_annotateObject(plainObj);
734
726
  if (errors) {
735
727
  objAnn = merge(objAnn, errors);
736
728
  }
737
- if (missingKeys.size > 0) {
738
- const errMsg = Array.from(missingKeys).map(quote).join(", ");
739
- const pluralized = missingKeys.size > 1 ? "keys" : "key";
729
+ if (missingKeys) {
730
+ const errMsg = missingKeys.map(quote).join(", ");
731
+ const pluralized = missingKeys.length > 1 ? "keys" : "key";
740
732
  objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
741
733
  }
742
734
  return err2(objAnn);
@@ -753,41 +745,50 @@ function object(decoders) {
753
745
  function exact(decoders) {
754
746
  /* @__PURE__ */ rejectUnsafeKey(decoders);
755
747
  const allowedKeys = new Set(Object.keys(decoders));
756
- const checked = pojo.chain((plainObj, ok2, err2) => {
757
- const actualKeys = new Set(Object.keys(plainObj));
758
- if (actualKeys.has("__proto__")) {
759
- return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
748
+ const objDecoder = /* @__PURE__ */ buildObject(decoders);
749
+ return pojo.chain((plainObj, _ok, err2) => {
750
+ let extraKeys = null;
751
+ for (const key of Object.keys(plainObj)) {
752
+ if (key === "__proto__") {
753
+ return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
754
+ }
755
+ if (!allowedKeys.has(key)) {
756
+ (extraKeys ??= []).push(key);
757
+ }
758
+ }
759
+ if (extraKeys) {
760
+ return err2(`Unexpected extra keys: ${extraKeys.map(quote).join(", ")}`);
760
761
  }
761
- const extraKeys = difference(actualKeys, allowedKeys);
762
- return extraKeys.size > 0 ? err2(`Unexpected extra keys: ${Array.from(extraKeys).map(quote).join(", ")}`) : ok2(plainObj);
762
+ return objDecoder.decode(plainObj);
763
763
  });
764
- return checked.pipe(/* @__PURE__ */ buildObject(decoders));
765
764
  }
766
765
  // @__NO_SIDE_EFFECTS__
767
766
  function inexact(decoders) {
768
767
  /* @__PURE__ */ rejectUnsafeKey(decoders);
768
+ const safekeys = new Set(Object.keys(decoders));
769
+ const safeDecoder = /* @__PURE__ */ buildObject(decoders);
769
770
  return pojo.chain(
770
- (plainObj, _ok, err2) => {
771
+ (plainObj, ok2, err2) => {
771
772
  const allkeys = new Set(Object.keys(plainObj));
772
773
  if (allkeys.has("__proto__")) {
773
774
  return err2(/* @__PURE__ */ annotateUnsafeKey(plainObj));
774
775
  }
775
- return (/* @__PURE__ */ buildObject(decoders)).transform((safepart) => {
776
- const safekeys = new Set(Object.keys(decoders));
777
- for (const k of safekeys) allkeys.add(k);
778
- const rv = {};
779
- for (const k of allkeys) {
780
- if (safekeys.has(k)) {
781
- const value = safepart[k];
782
- if (value !== void 0) {
783
- rv[k] = value;
784
- }
785
- } else {
786
- rv[k] = plainObj[k];
776
+ const result = safeDecoder.decode(plainObj);
777
+ if (!result.ok) return result;
778
+ const safepart = result.value;
779
+ for (const k of safekeys) allkeys.add(k);
780
+ const rv = {};
781
+ for (const k of allkeys) {
782
+ if (safekeys.has(k)) {
783
+ const value = safepart[k];
784
+ if (value !== void 0) {
785
+ rv[k] = value;
787
786
  }
787
+ } else {
788
+ rv[k] = plainObj[k];
788
789
  }
789
- return rv;
790
- });
790
+ }
791
+ return ok2(rv);
791
792
  }
792
793
  );
793
794
  }
@@ -945,6 +946,9 @@ function record(fst, snd) {
945
946
  errors.set(key, result.error);
946
947
  rv = {};
947
948
  }
949
+ if (errors.size >= MAX_ERRORS) {
950
+ break;
951
+ }
948
952
  }
949
953
  if (errors.size > 0) {
950
954
  return err2(merge(public_annotateObject(input), errors));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "decoders",
3
- "version": "2.12.1",
3
+ "version": "2.12.3",
4
4
  "description": "Elegant and battle-tested validation library for type-safe input data for TypeScript",
5
5
  "license": "MIT",
6
6
  "repository": {