decoders 2.3.0-beta.1 → 2.3.0-beta.2
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 +67 -33
- package/dist/index.d.cts +41 -14
- package/dist/index.d.ts +41 -14
- package/dist/index.js +65 -31
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/lib/utils.ts
|
|
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
|
+
function isNumber(value) {
|
|
3
|
+
return typeof value === "number";
|
|
4
|
+
}
|
|
5
|
+
function isString(value) {
|
|
6
|
+
return typeof value === "string";
|
|
7
|
+
}
|
|
8
|
+
function isBigInt(value) {
|
|
9
|
+
return typeof value === "bigint";
|
|
10
|
+
}
|
|
2
11
|
function isDate(value) {
|
|
3
12
|
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
|
|
4
13
|
}
|
|
@@ -453,7 +462,7 @@ function object(decoders) {
|
|
|
453
462
|
return pojo.then((plainObj, ok2, err2) => {
|
|
454
463
|
const actualKeys = new Set(Object.keys(plainObj));
|
|
455
464
|
const missingKeys = difference(knownKeys, actualKeys);
|
|
456
|
-
const
|
|
465
|
+
const record2 = {};
|
|
457
466
|
let errors = null;
|
|
458
467
|
for (const key of Object.keys(decoders)) {
|
|
459
468
|
const decoder = decoders[key];
|
|
@@ -462,7 +471,7 @@ function object(decoders) {
|
|
|
462
471
|
if (result.ok) {
|
|
463
472
|
const value = result.value;
|
|
464
473
|
if (value !== void 0) {
|
|
465
|
-
|
|
474
|
+
record2[key] = value;
|
|
466
475
|
}
|
|
467
476
|
missingKeys.delete(key);
|
|
468
477
|
} else {
|
|
@@ -489,7 +498,7 @@ function object(decoders) {
|
|
|
489
498
|
}
|
|
490
499
|
return err2(objAnn);
|
|
491
500
|
}
|
|
492
|
-
return ok2(
|
|
501
|
+
return ok2(record2);
|
|
493
502
|
});
|
|
494
503
|
}
|
|
495
504
|
function exact(decoders) {
|
|
@@ -527,40 +536,43 @@ function inexact(decoders) {
|
|
|
527
536
|
return decoder.decode(plainObj);
|
|
528
537
|
});
|
|
529
538
|
}
|
|
530
|
-
function
|
|
531
|
-
|
|
539
|
+
function record(fst, snd) {
|
|
540
|
+
const keyDecoder = snd !== void 0 ? fst : void 0;
|
|
541
|
+
const valueDecoder = snd !== void 0 ? snd : fst;
|
|
542
|
+
return pojo.then((rec, ok2, err2) => {
|
|
532
543
|
let rv = {};
|
|
533
|
-
|
|
534
|
-
for (const key of Object.
|
|
535
|
-
const
|
|
536
|
-
|
|
544
|
+
const errors = /* @__PURE__ */ new Map();
|
|
545
|
+
for (const [key, value] of Object.entries(rec)) {
|
|
546
|
+
const keyResult = _optionalChain([keyDecoder, 'optionalAccess', _2 => _2.decode, 'call', _3 => _3(key)]);
|
|
547
|
+
if (_optionalChain([keyResult, 'optionalAccess', _4 => _4.ok]) === false) {
|
|
548
|
+
return err2(
|
|
549
|
+
public_annotate(
|
|
550
|
+
rec,
|
|
551
|
+
`Invalid key ${JSON.stringify(key)}: ${formatShort(keyResult.error)}`
|
|
552
|
+
)
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
const k = _nullishCoalesce(_optionalChain([keyResult, 'optionalAccess', _5 => _5.value]), () => ( key));
|
|
556
|
+
const result = valueDecoder.decode(value);
|
|
537
557
|
if (result.ok) {
|
|
538
|
-
if (errors ===
|
|
539
|
-
rv[
|
|
558
|
+
if (errors.size === 0) {
|
|
559
|
+
rv[k] = result.value;
|
|
540
560
|
}
|
|
541
561
|
} else {
|
|
542
|
-
rv = {};
|
|
543
|
-
if (errors === null) {
|
|
544
|
-
errors = /* @__PURE__ */ new Map();
|
|
545
|
-
}
|
|
546
562
|
errors.set(key, result.error);
|
|
563
|
+
rv = {};
|
|
547
564
|
}
|
|
548
565
|
}
|
|
549
|
-
if (errors
|
|
550
|
-
return err2(merge(public_annotateObject(
|
|
566
|
+
if (errors.size > 0) {
|
|
567
|
+
return err2(merge(public_annotateObject(rec), errors));
|
|
551
568
|
} else {
|
|
552
569
|
return ok2(rv);
|
|
553
570
|
}
|
|
554
571
|
});
|
|
555
572
|
}
|
|
573
|
+
var dict = record;
|
|
556
574
|
function mapping(decoder) {
|
|
557
|
-
return
|
|
558
|
-
(obj) => new Map(
|
|
559
|
-
// This is effectively Object.entries(obj), but in a way that Flow
|
|
560
|
-
// will know the types are okay
|
|
561
|
-
Object.keys(obj).map((key) => [key, obj[key]])
|
|
562
|
-
)
|
|
563
|
-
);
|
|
575
|
+
return record(decoder).transform((obj) => new Map(Object.entries(obj)));
|
|
564
576
|
}
|
|
565
577
|
|
|
566
578
|
// src/unions.ts
|
|
@@ -600,6 +612,17 @@ function oneOf(constants) {
|
|
|
600
612
|
);
|
|
601
613
|
});
|
|
602
614
|
}
|
|
615
|
+
function enum_(enumObj) {
|
|
616
|
+
const values = Object.values(enumObj);
|
|
617
|
+
if (!values.some(isNumber)) {
|
|
618
|
+
return oneOf(values);
|
|
619
|
+
} else {
|
|
620
|
+
const nums = values.filter(isNumber);
|
|
621
|
+
const ignore = new Set(nums.map((val) => enumObj[val]));
|
|
622
|
+
const strings = values.filter(isString).filter((val) => !ignore.has(val));
|
|
623
|
+
return oneOf([...nums, ...strings]);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
603
626
|
function taggedUnion(field, mapping2) {
|
|
604
627
|
const scout = object({
|
|
605
628
|
[field]: prep(String, oneOf(Object.keys(mapping2)))
|
|
@@ -625,9 +648,9 @@ function lazyval(value) {
|
|
|
625
648
|
var null_ = constant(null);
|
|
626
649
|
var undefined_ = constant(void 0);
|
|
627
650
|
var nullish_ = define(
|
|
628
|
-
(blob, ok2, err2) =>
|
|
629
|
-
//
|
|
630
|
-
err2("Must be undefined or null")
|
|
651
|
+
(blob, ok2, err2) => (
|
|
652
|
+
// Equiv to either(undefined_, null_), but combined for better error message
|
|
653
|
+
blob == null ? ok2(blob) : err2("Must be undefined or null")
|
|
631
654
|
)
|
|
632
655
|
);
|
|
633
656
|
function optional(decoder, defaultValue) {
|
|
@@ -665,7 +688,7 @@ var mixed = unknown;
|
|
|
665
688
|
|
|
666
689
|
// src/numbers.ts
|
|
667
690
|
var anyNumber = define(
|
|
668
|
-
(blob, ok2, err2) =>
|
|
691
|
+
(blob, ok2, err2) => isNumber(blob) ? ok2(blob) : err2("Must be number")
|
|
669
692
|
);
|
|
670
693
|
var number = anyNumber.refine(
|
|
671
694
|
(n) => Number.isFinite(n),
|
|
@@ -678,7 +701,7 @@ var integer = number.refine(
|
|
|
678
701
|
var positiveNumber = number.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
679
702
|
var positiveInteger = integer.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
680
703
|
var bigint = define(
|
|
681
|
-
(blob, ok2, err2) =>
|
|
704
|
+
(blob, ok2, err2) => isBigInt(blob) ? ok2(blob) : err2("Must be bigint")
|
|
682
705
|
);
|
|
683
706
|
|
|
684
707
|
// src/booleans.ts
|
|
@@ -691,7 +714,7 @@ var numericBoolean = number.transform((n) => !!n);
|
|
|
691
714
|
// src/strings.ts
|
|
692
715
|
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,/\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
693
716
|
var string = define(
|
|
694
|
-
(blob, ok2, err2) =>
|
|
717
|
+
(blob, ok2, err2) => isString(blob) ? ok2(blob) : err2("Must be string")
|
|
695
718
|
);
|
|
696
719
|
var nonEmptyString = regex(/\S/, "Must be non-empty string");
|
|
697
720
|
function regex(regex2, msg) {
|
|
@@ -722,6 +745,12 @@ var uuidv4 = (
|
|
|
722
745
|
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
723
746
|
uuid.refine((value) => value[14] === "4", "Must be uuidv4")
|
|
724
747
|
);
|
|
748
|
+
var decimal = regex(/^[0-9]+$/, "Must only contain digits");
|
|
749
|
+
var hexadecimal = regex(
|
|
750
|
+
/^[0-9a-f]+$/i,
|
|
751
|
+
"Must only contain hexadecimal digits"
|
|
752
|
+
);
|
|
753
|
+
var numeric = decimal.transform(Number);
|
|
725
754
|
|
|
726
755
|
// src/dates.ts
|
|
727
756
|
var iso8601_re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
|
|
@@ -743,7 +772,7 @@ var iso8601 = (
|
|
|
743
772
|
);
|
|
744
773
|
|
|
745
774
|
// src/json.ts
|
|
746
|
-
var jsonObject = lazy(() =>
|
|
775
|
+
var jsonObject = lazy(() => record(json));
|
|
747
776
|
var jsonArray = lazy(() => array(json));
|
|
748
777
|
var json = either(
|
|
749
778
|
null_,
|
|
@@ -813,4 +842,9 @@ var json = either(
|
|
|
813
842
|
|
|
814
843
|
|
|
815
844
|
|
|
816
|
-
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
exports.always = always; exports.anyNumber = anyNumber; exports.array = array; exports.bigint = bigint; exports.boolean = boolean; exports.constant = constant; exports.date = date; exports.decimal = decimal; exports.define = define; exports.dict = dict; exports.either = either; exports.email = email; exports.enum_ = enum_; exports.err = err; exports.exact = exact; exports.fail = fail; exports.formatInline = formatInline; exports.formatShort = formatShort; exports.hardcoded = hardcoded; exports.hexadecimal = hexadecimal; exports.httpsUrl = httpsUrl; exports.inexact = inexact; exports.instanceOf = instanceOf; exports.integer = integer; exports.iso8601 = iso8601; exports.json = json; exports.jsonArray = jsonArray; exports.jsonObject = jsonObject; exports.lazy = lazy; exports.mapping = mapping; exports.maybe = maybe; exports.mixed = mixed; exports.never = never; exports.nonEmptyArray = nonEmptyArray; exports.nonEmptyString = nonEmptyString; exports.null_ = null_; exports.nullable = nullable; exports.nullish = nullish; exports.number = number; exports.numeric = numeric; exports.numericBoolean = numericBoolean; exports.object = object; exports.ok = ok; exports.oneOf = oneOf; exports.optional = optional; exports.poja = poja; exports.pojo = pojo; exports.positiveInteger = positiveInteger; exports.positiveNumber = positiveNumber; exports.prep = prep; exports.record = record; exports.regex = regex; exports.select = select; exports.set = set; exports.string = string; exports.taggedUnion = taggedUnion; exports.truthy = truthy; exports.tuple = tuple; exports.undefined_ = undefined_; exports.unknown = unknown; exports.url = url; exports.uuid = uuid; exports.uuidv1 = uuidv1; exports.uuidv4 = uuidv4;
|
package/dist/index.d.cts
CHANGED
|
@@ -206,7 +206,7 @@ declare function nullable<T, C extends Scalar>(decoder: Decoder<T>, defaultValue
|
|
|
206
206
|
declare function nullable<T, V>(decoder: Decoder<T>, defaultValue: (() => V) | V): Decoder<NonNullable<T> | V>;
|
|
207
207
|
/**
|
|
208
208
|
* @deprecated
|
|
209
|
-
* Alias of nullish()
|
|
209
|
+
* Alias of `nullish()`.
|
|
210
210
|
*/
|
|
211
211
|
declare const maybe: typeof nullish;
|
|
212
212
|
/**
|
|
@@ -236,12 +236,12 @@ declare function always<T>(value: (() => T) | T): Decoder<T>;
|
|
|
236
236
|
*/
|
|
237
237
|
declare function never(msg: string): Decoder<never>;
|
|
238
238
|
/**
|
|
239
|
-
* Alias of never()
|
|
239
|
+
* Alias of `never()`.
|
|
240
240
|
*/
|
|
241
241
|
declare const fail: typeof never;
|
|
242
242
|
/**
|
|
243
243
|
* @deprecated
|
|
244
|
-
* Alias of always
|
|
244
|
+
* Alias of `always()`.
|
|
245
245
|
*/
|
|
246
246
|
declare const hardcoded: typeof always;
|
|
247
247
|
/**
|
|
@@ -254,7 +254,7 @@ declare const hardcoded: typeof always;
|
|
|
254
254
|
declare const unknown: Decoder<unknown>;
|
|
255
255
|
/**
|
|
256
256
|
* @deprecated
|
|
257
|
-
* Alias of unknown
|
|
257
|
+
* Alias of `unknown`.
|
|
258
258
|
*/
|
|
259
259
|
declare const mixed: Decoder<unknown>;
|
|
260
260
|
|
|
@@ -268,6 +268,9 @@ declare const boolean: Decoder<boolean>;
|
|
|
268
268
|
declare const truthy: Decoder<boolean>;
|
|
269
269
|
/**
|
|
270
270
|
* Accepts numbers, but return their boolean representation.
|
|
271
|
+
*
|
|
272
|
+
* @deprecated This decoder will be removed in a future version. You can use
|
|
273
|
+
* `truthy` to get almost the same effect.
|
|
271
274
|
*/
|
|
272
275
|
declare const numericBoolean: Decoder<boolean>;
|
|
273
276
|
|
|
@@ -422,17 +425,22 @@ declare function inexact(decoders: Record<any, never>): Decoder<Record<string, u
|
|
|
422
425
|
declare function inexact<Ds extends Record<string, Decoder<unknown>>>(decoders: Ds): Decoder<ObjectDecoderType<Ds> & Record<string, unknown>>;
|
|
423
426
|
/**
|
|
424
427
|
* Accepts objects where all values match the given decoder, and returns the
|
|
425
|
-
* result as a `Record<string,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
428
|
+
* result as a `Record<string, V>`.
|
|
429
|
+
*/
|
|
430
|
+
declare function record<V>(valueDecoder: Decoder<V>): Decoder<Record<string, V>>;
|
|
431
|
+
/**
|
|
432
|
+
* Accepts objects where all keys and values match the given decoders, and
|
|
433
|
+
* returns the result as a `Record<K, V>`. The given key decoder must return
|
|
434
|
+
* strings.
|
|
435
|
+
*/
|
|
436
|
+
declare function record<K extends string, V>(keyDecoder: Decoder<K>, valueDecoder: Decoder<V>): Decoder<Record<K, V>>;
|
|
437
|
+
/**
|
|
438
|
+
* @deprecated
|
|
439
|
+
* Alias of `record()`.
|
|
432
440
|
*/
|
|
433
|
-
declare
|
|
441
|
+
declare const dict: typeof record;
|
|
434
442
|
/**
|
|
435
|
-
* Similar to `
|
|
443
|
+
* Similar to `record()`, but returns the result as a `Map<string, T>` (an [ES6
|
|
436
444
|
* Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map))
|
|
437
445
|
* instead.
|
|
438
446
|
*/
|
|
@@ -482,6 +490,21 @@ declare const uuidv1: Decoder<string>;
|
|
|
482
490
|
* strings.
|
|
483
491
|
*/
|
|
484
492
|
declare const uuidv4: Decoder<string>;
|
|
493
|
+
/**
|
|
494
|
+
* Accepts and returns strings with decimal digits only (base-10).
|
|
495
|
+
* To convert these to numbers, use the `numeric` decoder.
|
|
496
|
+
*/
|
|
497
|
+
declare const decimal: Decoder<string>;
|
|
498
|
+
/**
|
|
499
|
+
* Accepts and returns strings with hexadecimal digits only (base-16).
|
|
500
|
+
*/
|
|
501
|
+
declare const hexadecimal: Decoder<string>;
|
|
502
|
+
/**
|
|
503
|
+
* Accepts valid numerical strings (in base-10) and returns them as a number.
|
|
504
|
+
* To only accept numerical strings and keep them as string values, use the
|
|
505
|
+
* `decimal` decoder.
|
|
506
|
+
*/
|
|
507
|
+
declare const numeric: Decoder<number>;
|
|
485
508
|
|
|
486
509
|
/**
|
|
487
510
|
* Accepts values accepted by any of the given decoders.
|
|
@@ -496,6 +519,10 @@ declare function either<TDecoders extends readonly Decoder<unknown>[], T = Decod
|
|
|
496
519
|
* specified values.
|
|
497
520
|
*/
|
|
498
521
|
declare function oneOf<C extends Scalar>(constants: readonly C[]): Decoder<C>;
|
|
522
|
+
/**
|
|
523
|
+
* Accepts and return an enum value.
|
|
524
|
+
*/
|
|
525
|
+
declare function enum_<TEnum extends Record<string, string | number>>(enumObj: TEnum): Decoder<TEnum[keyof TEnum]>;
|
|
499
526
|
/**
|
|
500
527
|
* If you are decoding tagged unions you may want to use the `taggedUnion()`
|
|
501
528
|
* decoder instead of the general purpose `either()` decoder to get better
|
|
@@ -536,4 +563,4 @@ declare function taggedUnion<O extends Record<string, Decoder<unknown>>, T = Dec
|
|
|
536
563
|
*/
|
|
537
564
|
declare function select<T, D extends Decoder<unknown>>(scout: Decoder<T>, selectFn: (result: T) => D): Decoder<DecoderType<D>>;
|
|
538
565
|
|
|
539
|
-
export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, always, anyNumber, array, bigint, boolean, constant, date, define, dict, either, email, err, exact, fail, formatInline, formatShort, hardcoded, httpsUrl, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numericBoolean, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, regex, select, set, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
|
|
566
|
+
export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, always, anyNumber, array, bigint, boolean, constant, date, decimal, define, dict, either, email, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, numericBoolean, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
|
package/dist/index.d.ts
CHANGED
|
@@ -206,7 +206,7 @@ declare function nullable<T, C extends Scalar>(decoder: Decoder<T>, defaultValue
|
|
|
206
206
|
declare function nullable<T, V>(decoder: Decoder<T>, defaultValue: (() => V) | V): Decoder<NonNullable<T> | V>;
|
|
207
207
|
/**
|
|
208
208
|
* @deprecated
|
|
209
|
-
* Alias of nullish()
|
|
209
|
+
* Alias of `nullish()`.
|
|
210
210
|
*/
|
|
211
211
|
declare const maybe: typeof nullish;
|
|
212
212
|
/**
|
|
@@ -236,12 +236,12 @@ declare function always<T>(value: (() => T) | T): Decoder<T>;
|
|
|
236
236
|
*/
|
|
237
237
|
declare function never(msg: string): Decoder<never>;
|
|
238
238
|
/**
|
|
239
|
-
* Alias of never()
|
|
239
|
+
* Alias of `never()`.
|
|
240
240
|
*/
|
|
241
241
|
declare const fail: typeof never;
|
|
242
242
|
/**
|
|
243
243
|
* @deprecated
|
|
244
|
-
* Alias of always
|
|
244
|
+
* Alias of `always()`.
|
|
245
245
|
*/
|
|
246
246
|
declare const hardcoded: typeof always;
|
|
247
247
|
/**
|
|
@@ -254,7 +254,7 @@ declare const hardcoded: typeof always;
|
|
|
254
254
|
declare const unknown: Decoder<unknown>;
|
|
255
255
|
/**
|
|
256
256
|
* @deprecated
|
|
257
|
-
* Alias of unknown
|
|
257
|
+
* Alias of `unknown`.
|
|
258
258
|
*/
|
|
259
259
|
declare const mixed: Decoder<unknown>;
|
|
260
260
|
|
|
@@ -268,6 +268,9 @@ declare const boolean: Decoder<boolean>;
|
|
|
268
268
|
declare const truthy: Decoder<boolean>;
|
|
269
269
|
/**
|
|
270
270
|
* Accepts numbers, but return their boolean representation.
|
|
271
|
+
*
|
|
272
|
+
* @deprecated This decoder will be removed in a future version. You can use
|
|
273
|
+
* `truthy` to get almost the same effect.
|
|
271
274
|
*/
|
|
272
275
|
declare const numericBoolean: Decoder<boolean>;
|
|
273
276
|
|
|
@@ -422,17 +425,22 @@ declare function inexact(decoders: Record<any, never>): Decoder<Record<string, u
|
|
|
422
425
|
declare function inexact<Ds extends Record<string, Decoder<unknown>>>(decoders: Ds): Decoder<ObjectDecoderType<Ds> & Record<string, unknown>>;
|
|
423
426
|
/**
|
|
424
427
|
* Accepts objects where all values match the given decoder, and returns the
|
|
425
|
-
* result as a `Record<string,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
428
|
+
* result as a `Record<string, V>`.
|
|
429
|
+
*/
|
|
430
|
+
declare function record<V>(valueDecoder: Decoder<V>): Decoder<Record<string, V>>;
|
|
431
|
+
/**
|
|
432
|
+
* Accepts objects where all keys and values match the given decoders, and
|
|
433
|
+
* returns the result as a `Record<K, V>`. The given key decoder must return
|
|
434
|
+
* strings.
|
|
435
|
+
*/
|
|
436
|
+
declare function record<K extends string, V>(keyDecoder: Decoder<K>, valueDecoder: Decoder<V>): Decoder<Record<K, V>>;
|
|
437
|
+
/**
|
|
438
|
+
* @deprecated
|
|
439
|
+
* Alias of `record()`.
|
|
432
440
|
*/
|
|
433
|
-
declare
|
|
441
|
+
declare const dict: typeof record;
|
|
434
442
|
/**
|
|
435
|
-
* Similar to `
|
|
443
|
+
* Similar to `record()`, but returns the result as a `Map<string, T>` (an [ES6
|
|
436
444
|
* Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map))
|
|
437
445
|
* instead.
|
|
438
446
|
*/
|
|
@@ -482,6 +490,21 @@ declare const uuidv1: Decoder<string>;
|
|
|
482
490
|
* strings.
|
|
483
491
|
*/
|
|
484
492
|
declare const uuidv4: Decoder<string>;
|
|
493
|
+
/**
|
|
494
|
+
* Accepts and returns strings with decimal digits only (base-10).
|
|
495
|
+
* To convert these to numbers, use the `numeric` decoder.
|
|
496
|
+
*/
|
|
497
|
+
declare const decimal: Decoder<string>;
|
|
498
|
+
/**
|
|
499
|
+
* Accepts and returns strings with hexadecimal digits only (base-16).
|
|
500
|
+
*/
|
|
501
|
+
declare const hexadecimal: Decoder<string>;
|
|
502
|
+
/**
|
|
503
|
+
* Accepts valid numerical strings (in base-10) and returns them as a number.
|
|
504
|
+
* To only accept numerical strings and keep them as string values, use the
|
|
505
|
+
* `decimal` decoder.
|
|
506
|
+
*/
|
|
507
|
+
declare const numeric: Decoder<number>;
|
|
485
508
|
|
|
486
509
|
/**
|
|
487
510
|
* Accepts values accepted by any of the given decoders.
|
|
@@ -496,6 +519,10 @@ declare function either<TDecoders extends readonly Decoder<unknown>[], T = Decod
|
|
|
496
519
|
* specified values.
|
|
497
520
|
*/
|
|
498
521
|
declare function oneOf<C extends Scalar>(constants: readonly C[]): Decoder<C>;
|
|
522
|
+
/**
|
|
523
|
+
* Accepts and return an enum value.
|
|
524
|
+
*/
|
|
525
|
+
declare function enum_<TEnum extends Record<string, string | number>>(enumObj: TEnum): Decoder<TEnum[keyof TEnum]>;
|
|
499
526
|
/**
|
|
500
527
|
* If you are decoding tagged unions you may want to use the `taggedUnion()`
|
|
501
528
|
* decoder instead of the general purpose `either()` decoder to get better
|
|
@@ -536,4 +563,4 @@ declare function taggedUnion<O extends Record<string, Decoder<unknown>>, T = Dec
|
|
|
536
563
|
*/
|
|
537
564
|
declare function select<T, D extends Decoder<unknown>>(scout: Decoder<T>, selectFn: (result: T) => D): Decoder<DecoderType<D>>;
|
|
538
565
|
|
|
539
|
-
export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, always, anyNumber, array, bigint, boolean, constant, date, define, dict, either, email, err, exact, fail, formatInline, formatShort, hardcoded, httpsUrl, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numericBoolean, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, regex, select, set, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
|
|
566
|
+
export { type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type Ok, type Result, type Scalar, always, anyNumber, array, bigint, boolean, constant, date, decimal, define, dict, either, email, enum_, err, exact, fail, formatInline, formatShort, hardcoded, hexadecimal, httpsUrl, inexact, instanceOf, integer, iso8601, json, jsonArray, jsonObject, lazy, mapping, maybe, mixed, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, numericBoolean, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, set, string, taggedUnion, truthy, tuple, undefined_, unknown, url, uuid, uuidv1, uuidv4 };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
// src/lib/utils.ts
|
|
2
|
+
function isNumber(value) {
|
|
3
|
+
return typeof value === "number";
|
|
4
|
+
}
|
|
5
|
+
function isString(value) {
|
|
6
|
+
return typeof value === "string";
|
|
7
|
+
}
|
|
8
|
+
function isBigInt(value) {
|
|
9
|
+
return typeof value === "bigint";
|
|
10
|
+
}
|
|
2
11
|
function isDate(value) {
|
|
3
12
|
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
|
|
4
13
|
}
|
|
@@ -453,7 +462,7 @@ function object(decoders) {
|
|
|
453
462
|
return pojo.then((plainObj, ok2, err2) => {
|
|
454
463
|
const actualKeys = new Set(Object.keys(plainObj));
|
|
455
464
|
const missingKeys = difference(knownKeys, actualKeys);
|
|
456
|
-
const
|
|
465
|
+
const record2 = {};
|
|
457
466
|
let errors = null;
|
|
458
467
|
for (const key of Object.keys(decoders)) {
|
|
459
468
|
const decoder = decoders[key];
|
|
@@ -462,7 +471,7 @@ function object(decoders) {
|
|
|
462
471
|
if (result.ok) {
|
|
463
472
|
const value = result.value;
|
|
464
473
|
if (value !== void 0) {
|
|
465
|
-
|
|
474
|
+
record2[key] = value;
|
|
466
475
|
}
|
|
467
476
|
missingKeys.delete(key);
|
|
468
477
|
} else {
|
|
@@ -489,7 +498,7 @@ function object(decoders) {
|
|
|
489
498
|
}
|
|
490
499
|
return err2(objAnn);
|
|
491
500
|
}
|
|
492
|
-
return ok2(
|
|
501
|
+
return ok2(record2);
|
|
493
502
|
});
|
|
494
503
|
}
|
|
495
504
|
function exact(decoders) {
|
|
@@ -527,40 +536,43 @@ function inexact(decoders) {
|
|
|
527
536
|
return decoder.decode(plainObj);
|
|
528
537
|
});
|
|
529
538
|
}
|
|
530
|
-
function
|
|
531
|
-
|
|
539
|
+
function record(fst, snd) {
|
|
540
|
+
const keyDecoder = snd !== void 0 ? fst : void 0;
|
|
541
|
+
const valueDecoder = snd !== void 0 ? snd : fst;
|
|
542
|
+
return pojo.then((rec, ok2, err2) => {
|
|
532
543
|
let rv = {};
|
|
533
|
-
|
|
534
|
-
for (const key of Object.
|
|
535
|
-
const
|
|
536
|
-
|
|
544
|
+
const errors = /* @__PURE__ */ new Map();
|
|
545
|
+
for (const [key, value] of Object.entries(rec)) {
|
|
546
|
+
const keyResult = keyDecoder?.decode(key);
|
|
547
|
+
if (keyResult?.ok === false) {
|
|
548
|
+
return err2(
|
|
549
|
+
public_annotate(
|
|
550
|
+
rec,
|
|
551
|
+
`Invalid key ${JSON.stringify(key)}: ${formatShort(keyResult.error)}`
|
|
552
|
+
)
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
const k = keyResult?.value ?? key;
|
|
556
|
+
const result = valueDecoder.decode(value);
|
|
537
557
|
if (result.ok) {
|
|
538
|
-
if (errors ===
|
|
539
|
-
rv[
|
|
558
|
+
if (errors.size === 0) {
|
|
559
|
+
rv[k] = result.value;
|
|
540
560
|
}
|
|
541
561
|
} else {
|
|
542
|
-
rv = {};
|
|
543
|
-
if (errors === null) {
|
|
544
|
-
errors = /* @__PURE__ */ new Map();
|
|
545
|
-
}
|
|
546
562
|
errors.set(key, result.error);
|
|
563
|
+
rv = {};
|
|
547
564
|
}
|
|
548
565
|
}
|
|
549
|
-
if (errors
|
|
550
|
-
return err2(merge(public_annotateObject(
|
|
566
|
+
if (errors.size > 0) {
|
|
567
|
+
return err2(merge(public_annotateObject(rec), errors));
|
|
551
568
|
} else {
|
|
552
569
|
return ok2(rv);
|
|
553
570
|
}
|
|
554
571
|
});
|
|
555
572
|
}
|
|
573
|
+
var dict = record;
|
|
556
574
|
function mapping(decoder) {
|
|
557
|
-
return
|
|
558
|
-
(obj) => new Map(
|
|
559
|
-
// This is effectively Object.entries(obj), but in a way that Flow
|
|
560
|
-
// will know the types are okay
|
|
561
|
-
Object.keys(obj).map((key) => [key, obj[key]])
|
|
562
|
-
)
|
|
563
|
-
);
|
|
575
|
+
return record(decoder).transform((obj) => new Map(Object.entries(obj)));
|
|
564
576
|
}
|
|
565
577
|
|
|
566
578
|
// src/unions.ts
|
|
@@ -600,6 +612,17 @@ function oneOf(constants) {
|
|
|
600
612
|
);
|
|
601
613
|
});
|
|
602
614
|
}
|
|
615
|
+
function enum_(enumObj) {
|
|
616
|
+
const values = Object.values(enumObj);
|
|
617
|
+
if (!values.some(isNumber)) {
|
|
618
|
+
return oneOf(values);
|
|
619
|
+
} else {
|
|
620
|
+
const nums = values.filter(isNumber);
|
|
621
|
+
const ignore = new Set(nums.map((val) => enumObj[val]));
|
|
622
|
+
const strings = values.filter(isString).filter((val) => !ignore.has(val));
|
|
623
|
+
return oneOf([...nums, ...strings]);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
603
626
|
function taggedUnion(field, mapping2) {
|
|
604
627
|
const scout = object({
|
|
605
628
|
[field]: prep(String, oneOf(Object.keys(mapping2)))
|
|
@@ -625,9 +648,9 @@ function lazyval(value) {
|
|
|
625
648
|
var null_ = constant(null);
|
|
626
649
|
var undefined_ = constant(void 0);
|
|
627
650
|
var nullish_ = define(
|
|
628
|
-
(blob, ok2, err2) =>
|
|
629
|
-
//
|
|
630
|
-
err2("Must be undefined or null")
|
|
651
|
+
(blob, ok2, err2) => (
|
|
652
|
+
// Equiv to either(undefined_, null_), but combined for better error message
|
|
653
|
+
blob == null ? ok2(blob) : err2("Must be undefined or null")
|
|
631
654
|
)
|
|
632
655
|
);
|
|
633
656
|
function optional(decoder, defaultValue) {
|
|
@@ -665,7 +688,7 @@ var mixed = unknown;
|
|
|
665
688
|
|
|
666
689
|
// src/numbers.ts
|
|
667
690
|
var anyNumber = define(
|
|
668
|
-
(blob, ok2, err2) =>
|
|
691
|
+
(blob, ok2, err2) => isNumber(blob) ? ok2(blob) : err2("Must be number")
|
|
669
692
|
);
|
|
670
693
|
var number = anyNumber.refine(
|
|
671
694
|
(n) => Number.isFinite(n),
|
|
@@ -678,7 +701,7 @@ var integer = number.refine(
|
|
|
678
701
|
var positiveNumber = number.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
679
702
|
var positiveInteger = integer.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
680
703
|
var bigint = define(
|
|
681
|
-
(blob, ok2, err2) =>
|
|
704
|
+
(blob, ok2, err2) => isBigInt(blob) ? ok2(blob) : err2("Must be bigint")
|
|
682
705
|
);
|
|
683
706
|
|
|
684
707
|
// src/booleans.ts
|
|
@@ -691,7 +714,7 @@ var numericBoolean = number.transform((n) => !!n);
|
|
|
691
714
|
// src/strings.ts
|
|
692
715
|
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,/\w]*)?(?:#[.,!/\w]*)?)?$/;
|
|
693
716
|
var string = define(
|
|
694
|
-
(blob, ok2, err2) =>
|
|
717
|
+
(blob, ok2, err2) => isString(blob) ? ok2(blob) : err2("Must be string")
|
|
695
718
|
);
|
|
696
719
|
var nonEmptyString = regex(/\S/, "Must be non-empty string");
|
|
697
720
|
function regex(regex2, msg) {
|
|
@@ -722,6 +745,12 @@ var uuidv4 = (
|
|
|
722
745
|
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
|
|
723
746
|
uuid.refine((value) => value[14] === "4", "Must be uuidv4")
|
|
724
747
|
);
|
|
748
|
+
var decimal = regex(/^[0-9]+$/, "Must only contain digits");
|
|
749
|
+
var hexadecimal = regex(
|
|
750
|
+
/^[0-9a-f]+$/i,
|
|
751
|
+
"Must only contain hexadecimal digits"
|
|
752
|
+
);
|
|
753
|
+
var numeric = decimal.transform(Number);
|
|
725
754
|
|
|
726
755
|
// src/dates.ts
|
|
727
756
|
var iso8601_re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
|
|
@@ -743,7 +772,7 @@ var iso8601 = (
|
|
|
743
772
|
);
|
|
744
773
|
|
|
745
774
|
// src/json.ts
|
|
746
|
-
var jsonObject = lazy(() =>
|
|
775
|
+
var jsonObject = lazy(() => record(json));
|
|
747
776
|
var jsonArray = lazy(() => array(json));
|
|
748
777
|
var json = either(
|
|
749
778
|
null_,
|
|
@@ -761,16 +790,19 @@ export {
|
|
|
761
790
|
boolean,
|
|
762
791
|
constant,
|
|
763
792
|
date,
|
|
793
|
+
decimal,
|
|
764
794
|
define,
|
|
765
795
|
dict,
|
|
766
796
|
either,
|
|
767
797
|
email,
|
|
798
|
+
enum_,
|
|
768
799
|
err,
|
|
769
800
|
exact,
|
|
770
801
|
fail,
|
|
771
802
|
formatInline,
|
|
772
803
|
formatShort,
|
|
773
804
|
hardcoded,
|
|
805
|
+
hexadecimal,
|
|
774
806
|
httpsUrl,
|
|
775
807
|
inexact,
|
|
776
808
|
instanceOf,
|
|
@@ -790,6 +822,7 @@ export {
|
|
|
790
822
|
nullable,
|
|
791
823
|
nullish,
|
|
792
824
|
number,
|
|
825
|
+
numeric,
|
|
793
826
|
numericBoolean,
|
|
794
827
|
object,
|
|
795
828
|
ok,
|
|
@@ -800,6 +833,7 @@ export {
|
|
|
800
833
|
positiveInteger,
|
|
801
834
|
positiveNumber,
|
|
802
835
|
prep,
|
|
836
|
+
record,
|
|
803
837
|
regex,
|
|
804
838
|
select,
|
|
805
839
|
set,
|