decoders 2.10.0 → 2.11.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/dist/index.cjs +137 -98
- package/dist/index.d.cts +62 -54
- package/dist/index.d.ts +62 -54
- package/dist/index.js +136 -97
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -29,56 +29,87 @@ function isPlainObject(value) {
|
|
|
29
29
|
// something is a pojo... ¯\_(ツ)_/¯
|
|
30
30
|
Object.prototype.toString.call(value) === "[object Object]";
|
|
31
31
|
}
|
|
32
|
+
function assertNever(_value, msg = "Unhandled case") {
|
|
33
|
+
throw new Error(msg);
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
// src/core/annotate.ts
|
|
34
37
|
var kAnnotationRegistry = /* @__PURE__ */ Symbol.for("decoders.kAnnotationRegistry");
|
|
35
|
-
var
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
+
var _stamped = globalThis[kAnnotationRegistry] ??= /* @__PURE__ */ new WeakSet();
|
|
39
|
+
function stamp(ann) {
|
|
40
|
+
_stamped.add(ann);
|
|
38
41
|
return ann;
|
|
39
42
|
}
|
|
40
|
-
function makeObjectAnn(
|
|
41
|
-
|
|
43
|
+
function makeObjectAnn(getFields, text) {
|
|
44
|
+
let fields;
|
|
45
|
+
return stamp({
|
|
46
|
+
type: "object",
|
|
47
|
+
get fields() {
|
|
48
|
+
return fields ??= getFields();
|
|
49
|
+
},
|
|
50
|
+
text
|
|
51
|
+
});
|
|
42
52
|
}
|
|
43
|
-
function makeArrayAnn(
|
|
44
|
-
|
|
53
|
+
function makeArrayAnn(getItems, text) {
|
|
54
|
+
let items;
|
|
55
|
+
return stamp({
|
|
56
|
+
type: "array",
|
|
57
|
+
get items() {
|
|
58
|
+
return items ??= getItems();
|
|
59
|
+
},
|
|
60
|
+
text
|
|
61
|
+
});
|
|
45
62
|
}
|
|
46
63
|
function makeOpaqueAnn(value, text) {
|
|
47
|
-
return
|
|
64
|
+
return stamp({ type: "opaque", value, text });
|
|
48
65
|
}
|
|
49
66
|
function makeScalarAnn(value, text) {
|
|
50
|
-
return
|
|
67
|
+
return stamp({ type: "scalar", value, text });
|
|
51
68
|
}
|
|
52
69
|
function updateText(annotation, text) {
|
|
53
|
-
if (text
|
|
54
|
-
return brand({ ...annotation, text });
|
|
55
|
-
} else {
|
|
70
|
+
if (text === void 0) {
|
|
56
71
|
return annotation;
|
|
57
72
|
}
|
|
73
|
+
switch (annotation.type) {
|
|
74
|
+
case "object":
|
|
75
|
+
return makeObjectAnn(() => annotation.fields, text);
|
|
76
|
+
case "array":
|
|
77
|
+
return makeArrayAnn(() => annotation.items, text);
|
|
78
|
+
case "scalar":
|
|
79
|
+
return makeScalarAnn(annotation.value, text);
|
|
80
|
+
case "opaque":
|
|
81
|
+
return makeOpaqueAnn(annotation.value, text);
|
|
82
|
+
// istanbul ignore next -- @preserve
|
|
83
|
+
default:
|
|
84
|
+
return assertNever(annotation, "Unknown annotation type");
|
|
85
|
+
}
|
|
58
86
|
}
|
|
59
87
|
function merge(objAnnotation, fields) {
|
|
60
|
-
|
|
61
|
-
|
|
88
|
+
return makeObjectAnn(
|
|
89
|
+
() => new Map([...objAnnotation.fields, ...fields]),
|
|
90
|
+
objAnnotation.text
|
|
91
|
+
);
|
|
62
92
|
}
|
|
63
93
|
function isAnnotation(thing) {
|
|
64
|
-
return
|
|
94
|
+
return _stamped.has(thing);
|
|
65
95
|
}
|
|
66
96
|
function annotateArray(arr, text, seen) {
|
|
67
97
|
seen.add(arr);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return makeArrayAnn(items, text);
|
|
98
|
+
return makeArrayAnn(
|
|
99
|
+
() => Array.from(arr, (value) => __annotate(value, void 0, seen)),
|
|
100
|
+
text
|
|
101
|
+
);
|
|
73
102
|
}
|
|
74
103
|
function annotateObject(obj, text, seen) {
|
|
75
104
|
seen.add(obj);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
105
|
+
return makeObjectAnn(() => {
|
|
106
|
+
const fields = /* @__PURE__ */ new Map();
|
|
107
|
+
for (const key of Object.keys(obj)) {
|
|
108
|
+
const value = obj[key];
|
|
109
|
+
fields.set(key, __annotate(value, void 0, seen));
|
|
110
|
+
}
|
|
111
|
+
return fields;
|
|
112
|
+
}, text);
|
|
82
113
|
}
|
|
83
114
|
function __annotate(value, text, seen) {
|
|
84
115
|
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "symbol" || typeof value === "bigint" || typeof value.getMonth === "function") {
|
|
@@ -299,6 +330,9 @@ function* iterAnnotation(ann, stack) {
|
|
|
299
330
|
case "opaque": {
|
|
300
331
|
break;
|
|
301
332
|
}
|
|
333
|
+
// istanbul ignore next -- @preserve
|
|
334
|
+
default:
|
|
335
|
+
assertNever(ann, "Unknown annotation type");
|
|
302
336
|
}
|
|
303
337
|
}
|
|
304
338
|
function formatAsIssues(ann) {
|
|
@@ -398,7 +432,7 @@ function define(fn) {
|
|
|
398
432
|
}
|
|
399
433
|
});
|
|
400
434
|
}
|
|
401
|
-
const
|
|
435
|
+
const newDecoder = {
|
|
402
436
|
verify,
|
|
403
437
|
value,
|
|
404
438
|
decode,
|
|
@@ -423,80 +457,18 @@ function define(fn) {
|
|
|
423
457
|
}
|
|
424
458
|
}
|
|
425
459
|
};
|
|
426
|
-
const self =
|
|
460
|
+
const self = stamp2(newDecoder);
|
|
427
461
|
return self;
|
|
428
462
|
}
|
|
429
463
|
var kDecoderRegistry = /* @__PURE__ */ Symbol.for("decoders.kDecoderRegistry");
|
|
430
|
-
var
|
|
431
|
-
function
|
|
432
|
-
|
|
464
|
+
var _stamped2 = globalThis[kDecoderRegistry] ??= /* @__PURE__ */ new WeakSet();
|
|
465
|
+
function stamp2(decoder) {
|
|
466
|
+
_stamped2.add(decoder);
|
|
433
467
|
return decoder;
|
|
434
468
|
}
|
|
435
469
|
// @__NO_SIDE_EFFECTS__
|
|
436
470
|
function isDecoder(value) {
|
|
437
|
-
return
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// src/arrays.ts
|
|
441
|
-
var poja = define((blob, ok2, err2) => {
|
|
442
|
-
if (!Array.isArray(blob)) {
|
|
443
|
-
return err2("Must be an array");
|
|
444
|
-
}
|
|
445
|
-
return ok2(blob);
|
|
446
|
-
});
|
|
447
|
-
// @__NO_SIDE_EFFECTS__
|
|
448
|
-
function array(decoder) {
|
|
449
|
-
const decodeFn = decoder.decode;
|
|
450
|
-
return poja.chain((inputs, ok2, err2) => {
|
|
451
|
-
const results = [];
|
|
452
|
-
for (let i = 0; i < inputs.length; ++i) {
|
|
453
|
-
const blob = inputs[i];
|
|
454
|
-
const result = decodeFn(blob);
|
|
455
|
-
if (result.ok) {
|
|
456
|
-
results.push(result.value);
|
|
457
|
-
} else {
|
|
458
|
-
results.length = 0;
|
|
459
|
-
const ann = result.error;
|
|
460
|
-
const clone = inputs.slice();
|
|
461
|
-
clone.splice(
|
|
462
|
-
i,
|
|
463
|
-
1,
|
|
464
|
-
public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
|
|
465
|
-
);
|
|
466
|
-
return err2(public_annotate(clone));
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
return ok2(results);
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
function isNonEmpty(arr) {
|
|
473
|
-
return arr.length > 0;
|
|
474
|
-
}
|
|
475
|
-
// @__NO_SIDE_EFFECTS__
|
|
476
|
-
function nonEmptyArray(decoder) {
|
|
477
|
-
return (/* @__PURE__ */ array(decoder)).refine(isNonEmpty, "Must have at least 1 item");
|
|
478
|
-
}
|
|
479
|
-
var ntuple = /* @__NO_SIDE_EFFECTS__ */ (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
|
|
480
|
-
// @__NO_SIDE_EFFECTS__
|
|
481
|
-
function tuple(...decoders) {
|
|
482
|
-
return (/* @__PURE__ */ ntuple(decoders.length)).chain((blobs, ok2, err2) => {
|
|
483
|
-
let allOk = true;
|
|
484
|
-
const rvs = decoders.map((decoder, i) => {
|
|
485
|
-
const blob = blobs[i];
|
|
486
|
-
const result = decoder.decode(blob);
|
|
487
|
-
if (result.ok) {
|
|
488
|
-
return result.value;
|
|
489
|
-
} else {
|
|
490
|
-
allOk = false;
|
|
491
|
-
return result.error;
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
if (allOk) {
|
|
495
|
-
return ok2(rvs);
|
|
496
|
-
} else {
|
|
497
|
-
return err2(public_annotate(rvs));
|
|
498
|
-
}
|
|
499
|
-
});
|
|
471
|
+
return _stamped2.has(value);
|
|
500
472
|
}
|
|
501
473
|
|
|
502
474
|
// src/lib/size-options.ts
|
|
@@ -561,6 +533,66 @@ function prep(mapperFn, decoder) {
|
|
|
561
533
|
});
|
|
562
534
|
}
|
|
563
535
|
|
|
536
|
+
// src/arrays.ts
|
|
537
|
+
var poja = define((blob, ok2, err2) => {
|
|
538
|
+
if (!Array.isArray(blob)) {
|
|
539
|
+
return err2("Must be an array");
|
|
540
|
+
}
|
|
541
|
+
return ok2(blob);
|
|
542
|
+
});
|
|
543
|
+
// @__NO_SIDE_EFFECTS__
|
|
544
|
+
function array(decoder, options) {
|
|
545
|
+
const decodeFn = decoder.decode;
|
|
546
|
+
const base = options !== void 0 ? sized(poja, options) : poja;
|
|
547
|
+
return base.chain((inputs, ok2, err2) => {
|
|
548
|
+
const results = [];
|
|
549
|
+
for (let i = 0; i < inputs.length; ++i) {
|
|
550
|
+
const blob = inputs[i];
|
|
551
|
+
const result = decodeFn(blob);
|
|
552
|
+
if (result.ok) {
|
|
553
|
+
results.push(result.value);
|
|
554
|
+
} else {
|
|
555
|
+
results.length = 0;
|
|
556
|
+
const ann = result.error;
|
|
557
|
+
const clone = inputs.slice();
|
|
558
|
+
clone.splice(
|
|
559
|
+
i,
|
|
560
|
+
1,
|
|
561
|
+
public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
|
|
562
|
+
);
|
|
563
|
+
return err2(public_annotate(clone));
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return ok2(results);
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
// @__NO_SIDE_EFFECTS__
|
|
570
|
+
function nonEmptyArray(decoder) {
|
|
571
|
+
return (/* @__PURE__ */ array(decoder, { min: 1 })).refineType();
|
|
572
|
+
}
|
|
573
|
+
var ntuple = /* @__NO_SIDE_EFFECTS__ */ (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
|
|
574
|
+
// @__NO_SIDE_EFFECTS__
|
|
575
|
+
function tuple(...decoders) {
|
|
576
|
+
return (/* @__PURE__ */ ntuple(decoders.length)).chain((blobs, ok2, err2) => {
|
|
577
|
+
let allOk = true;
|
|
578
|
+
const rvs = decoders.map((decoder, i) => {
|
|
579
|
+
const blob = blobs[i];
|
|
580
|
+
const result = decoder.decode(blob);
|
|
581
|
+
if (result.ok) {
|
|
582
|
+
return result.value;
|
|
583
|
+
} else {
|
|
584
|
+
allOk = false;
|
|
585
|
+
return result.error;
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
if (allOk) {
|
|
589
|
+
return ok2(rvs);
|
|
590
|
+
} else {
|
|
591
|
+
return err2(public_annotate(rvs));
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
|
|
564
596
|
// src/lib/set-methods.ts
|
|
565
597
|
// @__NO_SIDE_EFFECTS__
|
|
566
598
|
function difference(xs, ys) {
|
|
@@ -900,7 +932,9 @@ function nanoid(options) {
|
|
|
900
932
|
return sized(/* @__PURE__ */ regex(/^[a-z0-9_-]+$/i, "Must be nano ID"), _nullishCoalesce(options, () => ( { size: 21 })));
|
|
901
933
|
}
|
|
902
934
|
var uuid = /* @__PURE__ */ regex(
|
|
903
|
-
|
|
935
|
+
// https://www.rfc-editor.org/rfc/rfc9562#section-4
|
|
936
|
+
// Version 1-8 with variant 8, 9, a, or b, plus the Nil and Max UUIDs (sections 5.9, 5.10)
|
|
937
|
+
/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i,
|
|
904
938
|
"Must be uuid"
|
|
905
939
|
);
|
|
906
940
|
var uuidv1 = (
|
|
@@ -953,14 +987,16 @@ var integer = /* @__PURE__ */ number.refine(
|
|
|
953
987
|
(n) => Number.isInteger(n),
|
|
954
988
|
"Number must be an integer"
|
|
955
989
|
);
|
|
956
|
-
var
|
|
990
|
+
var nonNegativeNumber = /* @__PURE__ */ number.refine(
|
|
957
991
|
(n) => n >= 0 && !Object.is(n, -0),
|
|
958
992
|
"Number must be positive"
|
|
959
993
|
);
|
|
960
|
-
var
|
|
994
|
+
var natural = /* @__PURE__ */ integer.refine(
|
|
961
995
|
(n) => n >= 0 && !Object.is(n, -0),
|
|
962
996
|
"Number must be positive"
|
|
963
997
|
);
|
|
998
|
+
var positiveNumber = nonNegativeNumber;
|
|
999
|
+
var positiveInteger = natural;
|
|
964
1000
|
// @__NO_SIDE_EFFECTS__
|
|
965
1001
|
function min(min2, decoder = number) {
|
|
966
1002
|
return decoder.reject(
|
|
@@ -1074,5 +1110,8 @@ var json = /* @__PURE__ */ either(
|
|
|
1074
1110
|
|
|
1075
1111
|
|
|
1076
1112
|
|
|
1077
|
-
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
exports._annotate = public_annotate; exports.always = always; exports.anyNumber = anyNumber; exports.anything = anything; exports.array = array; exports.between = between; exports.bigint = bigint; exports.boolean = boolean; exports.constant = constant; exports.date = date; exports.dateString = dateString; exports.datelike = datelike; exports.decimal = decimal; exports.define = define; exports.either = either; exports.email = email; exports.endsWith = endsWith; exports.enum_ = enum_; exports.err = err; exports.exact = exact; exports.fail = fail; exports.flexDate = flexDate; exports.formatInline = formatInline; exports.formatShort = formatShort; exports.hexadecimal = hexadecimal; exports.httpsUrl = httpsUrl; exports.identifier = identifier; exports.inexact = inexact; exports.instanceOf = instanceOf; exports.integer = integer; exports.isDate = isDate; exports.isDecoder = isDecoder; exports.isPlainObject = isPlainObject; exports.isPromiseLike = isPromiseLike; exports.iso8601 = iso8601; exports.isoDate = isoDate; exports.isoDateString = isoDateString; exports.json = json; exports.jsonArray = jsonArray; exports.jsonObject = jsonObject; exports.lazy = lazy; exports.mapping = mapping; exports.max = max; exports.min = min; exports.nanoid = nanoid; exports.natural = natural; exports.never = never; exports.nonEmptyArray = nonEmptyArray; exports.nonEmptyString = nonEmptyString; exports.nonNegativeNumber = nonNegativeNumber; exports.null_ = null_; exports.nullable = nullable; exports.nullish = nullish; exports.number = number; exports.numeric = numeric; 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.setFromArray = setFromArray; exports.sized = sized; exports.startsWith = startsWith; exports.string = string; exports.taggedUnion = taggedUnion; exports.truthy = truthy; exports.tuple = tuple; exports.undefined_ = undefined_; exports.unknown = unknown; exports.url = url; exports.urlString = urlString; exports.uuid = uuid; exports.uuidv1 = uuidv1; exports.uuidv4 = uuidv4;
|
|
1116
|
+
// istanbul ignore next -- @preserve
|
|
1078
1117
|
// istanbul ignore else -- @preserve
|
package/dist/index.d.cts
CHANGED
|
@@ -109,7 +109,6 @@ type DecodeResult<T> = Result<T, Annotation>;
|
|
|
109
109
|
* param. One of these should be called and its value returned.
|
|
110
110
|
*/
|
|
111
111
|
type AcceptanceFn<O, I = unknown> = (blob: I, ok: (value: O) => DecodeResult<O>, err: (msg: string | Annotation) => DecodeResult<O>) => DecodeResult<O>;
|
|
112
|
-
type Next<O, I = unknown> = Decoder<O> | ((blob: I, ok: (value: O) => DecodeResult<O>, err: (msg: string | Annotation) => DecodeResult<O>) => DecodeResult<O> | Decoder<O>);
|
|
113
112
|
interface Decoder<T> {
|
|
114
113
|
/**
|
|
115
114
|
* Verifies untrusted input. Either returns a value, or throws a decoding
|
|
@@ -151,16 +150,18 @@ interface Decoder<T> {
|
|
|
151
150
|
*/
|
|
152
151
|
describe(message: string): Decoder<T>;
|
|
153
152
|
/**
|
|
154
|
-
* Send the output of the current decoder into
|
|
155
|
-
*
|
|
156
|
-
*
|
|
153
|
+
* Send the output of the current decoder into an acceptance function. The
|
|
154
|
+
* given acceptance function will receive the output of the current decoder
|
|
155
|
+
* as its input.
|
|
157
156
|
*
|
|
158
157
|
* > _**NOTE:** This is an advanced, low-level, API. It's not recommended
|
|
159
158
|
* > to reach for this construct unless there is no other way. Most cases can
|
|
160
159
|
* > be covered more elegantly by `.transform()`, `.refine()`, or `.pipe()`
|
|
161
160
|
* > instead._
|
|
162
161
|
*/
|
|
163
|
-
chain<V>(next:
|
|
162
|
+
chain<V>(next: (blob: T, ok: (value: V) => DecodeResult<V>, err: (msg: string | Annotation) => DecodeResult<V>) => DecodeResult<V> | Decoder<V>): Decoder<V>;
|
|
163
|
+
/** @deprecated To send the output into another decoder, use `.pipe()` instead. */
|
|
164
|
+
chain<V>(next: Decoder<V>): Decoder<V>;
|
|
164
165
|
/**
|
|
165
166
|
* Send the output of this decoder as input to another decoder.
|
|
166
167
|
*
|
|
@@ -218,6 +219,46 @@ type Formatter = (err: Annotation) => string | Error;
|
|
|
218
219
|
declare function formatInline(ann: Annotation): string;
|
|
219
220
|
declare function formatShort(ann: Annotation): string;
|
|
220
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Forces TypeScript to "evaluate" named helper types, making API signatures
|
|
224
|
+
* clearer in IDEs.
|
|
225
|
+
*
|
|
226
|
+
* @see https://effectivetypescript.com/2022/02/25/gentips-4-display/
|
|
227
|
+
*/
|
|
228
|
+
type Resolve$1<T> = T extends (...args: unknown[]) => unknown ? T : {
|
|
229
|
+
[K in keyof T]: T[K];
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Relaxes a discriminated union type definition, by explicitly adding
|
|
233
|
+
* properties defined in any other member as optional `never`.
|
|
234
|
+
*
|
|
235
|
+
* This makes accessing the members much more relaxed in TypeScript.
|
|
236
|
+
*/
|
|
237
|
+
type Relax<T> = DistributiveRelax<T, T extends any ? keyof T : never>;
|
|
238
|
+
type DistributiveRelax<T, Ks extends string | number | symbol> = T extends any ? Resolve$1<{
|
|
239
|
+
[K in keyof T]: T[K];
|
|
240
|
+
} & {
|
|
241
|
+
[K in Exclude<Ks, keyof T>]?: never;
|
|
242
|
+
}> : never;
|
|
243
|
+
|
|
244
|
+
type SizeOptions = Relax<{
|
|
245
|
+
size: number;
|
|
246
|
+
} | {
|
|
247
|
+
min: number;
|
|
248
|
+
max?: number;
|
|
249
|
+
} | {
|
|
250
|
+
min?: number;
|
|
251
|
+
max: number;
|
|
252
|
+
}>;
|
|
253
|
+
/**
|
|
254
|
+
* Anything with a .length or .size property, like strings, arrays, or sets.
|
|
255
|
+
*/
|
|
256
|
+
type Sized = Relax<{
|
|
257
|
+
length: number;
|
|
258
|
+
} | {
|
|
259
|
+
size: number;
|
|
260
|
+
}>;
|
|
261
|
+
|
|
221
262
|
/**
|
|
222
263
|
* Accepts any array, but doesn't validate its items further.
|
|
223
264
|
*
|
|
@@ -227,7 +268,7 @@ declare const poja: Decoder<unknown[]>;
|
|
|
227
268
|
/**
|
|
228
269
|
* Accepts arrays of whatever the given decoder accepts.
|
|
229
270
|
*/
|
|
230
|
-
declare function array<T>(decoder: Decoder<T
|
|
271
|
+
declare function array<T>(decoder: Decoder<T>, options?: SizeOptions): Decoder<T[]>;
|
|
231
272
|
/**
|
|
232
273
|
* Like `array()`, but will reject arrays with 0 elements.
|
|
233
274
|
*/
|
|
@@ -365,7 +406,7 @@ declare const isoDate: Decoder<Date>;
|
|
|
365
406
|
declare const flexDate: Decoder<Date>;
|
|
366
407
|
/** @deprecated Renamed to `isoDateString`. This alias will be removed in 3.x. */
|
|
367
408
|
declare const dateString: Decoder<string>;
|
|
368
|
-
/**
|
|
409
|
+
/** @deprecated Renamed to `isoDate`. */
|
|
369
410
|
declare const iso8601: Decoder<Date>;
|
|
370
411
|
/** @deprecated Renamed to `flexDate`. This alias will be removed in 3.x. */
|
|
371
412
|
declare const datelike: Decoder<Date>;
|
|
@@ -401,46 +442,6 @@ declare const jsonArray: Decoder<JSONArray>;
|
|
|
401
442
|
*/
|
|
402
443
|
declare const json: Decoder<JSONValue>;
|
|
403
444
|
|
|
404
|
-
/**
|
|
405
|
-
* Forces TypeScript to "evaluate" named helper types, making API signatures
|
|
406
|
-
* clearer in IDEs.
|
|
407
|
-
*
|
|
408
|
-
* @see https://effectivetypescript.com/2022/02/25/gentips-4-display/
|
|
409
|
-
*/
|
|
410
|
-
type Resolve$1<T> = T extends (...args: unknown[]) => unknown ? T : {
|
|
411
|
-
[K in keyof T]: T[K];
|
|
412
|
-
};
|
|
413
|
-
/**
|
|
414
|
-
* Relaxes a discriminated union type definition, by explicitly adding
|
|
415
|
-
* properties defined in any other member as optional `never`.
|
|
416
|
-
*
|
|
417
|
-
* This makes accessing the members much more relaxed in TypeScript.
|
|
418
|
-
*/
|
|
419
|
-
type Relax<T> = DistributiveRelax<T, T extends any ? keyof T : never>;
|
|
420
|
-
type DistributiveRelax<T, Ks extends string | number | symbol> = T extends any ? Resolve$1<{
|
|
421
|
-
[K in keyof T]: T[K];
|
|
422
|
-
} & {
|
|
423
|
-
[K in Exclude<Ks, keyof T>]?: never;
|
|
424
|
-
}> : never;
|
|
425
|
-
|
|
426
|
-
type SizeOptions = Relax<{
|
|
427
|
-
size: number;
|
|
428
|
-
} | {
|
|
429
|
-
min: number;
|
|
430
|
-
max?: number;
|
|
431
|
-
} | {
|
|
432
|
-
min?: number;
|
|
433
|
-
max: number;
|
|
434
|
-
}>;
|
|
435
|
-
/**
|
|
436
|
-
* Anything with a .length or .size property, like strings, arrays, or sets.
|
|
437
|
-
*/
|
|
438
|
-
type Sized = Relax<{
|
|
439
|
-
length: number;
|
|
440
|
-
} | {
|
|
441
|
-
size: number;
|
|
442
|
-
}>;
|
|
443
|
-
|
|
444
445
|
interface Klass<T> extends Function {
|
|
445
446
|
new (...args: readonly any[]): T;
|
|
446
447
|
}
|
|
@@ -475,21 +476,28 @@ declare function prep<T>(mapperFn: (blob: unknown) => unknown, decoder: Decoder<
|
|
|
475
476
|
*/
|
|
476
477
|
declare const anyNumber: Decoder<number>;
|
|
477
478
|
/**
|
|
478
|
-
* Accepts finite numbers (
|
|
479
|
-
* or
|
|
479
|
+
* Accepts only finite numbers (e.g. -3.14, 0, 1, 42, ...).
|
|
480
|
+
* Integers or floats, but not `NaN` or `Infinity`.
|
|
480
481
|
*/
|
|
481
482
|
declare const number: Decoder<number>;
|
|
482
483
|
/**
|
|
483
|
-
* Accepts only
|
|
484
|
+
* Accepts only integers (e.g. ..., -2, -1, 0, 1, 2, ...).
|
|
485
|
+
* Whole numbers, and finite.
|
|
484
486
|
*/
|
|
485
487
|
declare const integer: Decoder<number>;
|
|
486
488
|
/**
|
|
487
|
-
* Accepts only non-negative (
|
|
489
|
+
* Accepts only non-negative numbers (e.g. 0, 0.5, 1, 3.14, ...).
|
|
490
|
+
* Integers or floats, >= 0, and finite.
|
|
488
491
|
*/
|
|
489
|
-
declare const
|
|
492
|
+
declare const nonNegativeNumber: Decoder<number>;
|
|
490
493
|
/**
|
|
491
|
-
* Accepts only
|
|
494
|
+
* Accepts only the natural numbers (e.g. 0, 1, 2, 3, ...).
|
|
495
|
+
* Whole numbers, >= 0, and finite.
|
|
492
496
|
*/
|
|
497
|
+
declare const natural: Decoder<number>;
|
|
498
|
+
/** @deprecated Renamed to `nonNegativeNumber`. */
|
|
499
|
+
declare const positiveNumber: Decoder<number>;
|
|
500
|
+
/** @deprecated Renamed to `natural`. */
|
|
493
501
|
declare const positiveInteger: Decoder<number>;
|
|
494
502
|
/**
|
|
495
503
|
* Accepts numbers greater than or equal to the given minimum.
|
|
@@ -724,4 +732,4 @@ declare function isPromiseLike(value: unknown): value is PromiseLike<unknown>;
|
|
|
724
732
|
*/
|
|
725
733
|
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
726
734
|
|
|
727
|
-
export { type Annotation, type ArrayAnnotation, type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type ObjectAnnotation, type Ok, type OpaqueAnnotation, type Relax, type Result, type Scalar, type ScalarAnnotation, type SizeOptions, type Sized, public_annotate as _annotate, always, anyNumber, anything, array, between, bigint, boolean, constant, date, dateString, datelike, decimal, define, either, email, endsWith, enum_, err, exact, fail, flexDate, formatInline, formatShort, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, isDate, isDecoder, isPlainObject, isPromiseLike, iso8601, isoDate, isoDateString, json, jsonArray, jsonObject, lazy, mapping, max, min, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, setFromArray, sized, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, urlString, uuid, uuidv1, uuidv4 };
|
|
735
|
+
export { type Annotation, type ArrayAnnotation, type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type ObjectAnnotation, type Ok, type OpaqueAnnotation, type Relax, type Result, type Scalar, type ScalarAnnotation, type SizeOptions, type Sized, public_annotate as _annotate, always, anyNumber, anything, array, between, bigint, boolean, constant, date, dateString, datelike, decimal, define, either, email, endsWith, enum_, err, exact, fail, flexDate, formatInline, formatShort, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, isDate, isDecoder, isPlainObject, isPromiseLike, iso8601, isoDate, isoDateString, json, jsonArray, jsonObject, lazy, mapping, max, min, nanoid, natural, never, nonEmptyArray, nonEmptyString, nonNegativeNumber, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, setFromArray, sized, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, urlString, uuid, uuidv1, uuidv4 };
|
package/dist/index.d.ts
CHANGED
|
@@ -109,7 +109,6 @@ type DecodeResult<T> = Result<T, Annotation>;
|
|
|
109
109
|
* param. One of these should be called and its value returned.
|
|
110
110
|
*/
|
|
111
111
|
type AcceptanceFn<O, I = unknown> = (blob: I, ok: (value: O) => DecodeResult<O>, err: (msg: string | Annotation) => DecodeResult<O>) => DecodeResult<O>;
|
|
112
|
-
type Next<O, I = unknown> = Decoder<O> | ((blob: I, ok: (value: O) => DecodeResult<O>, err: (msg: string | Annotation) => DecodeResult<O>) => DecodeResult<O> | Decoder<O>);
|
|
113
112
|
interface Decoder<T> {
|
|
114
113
|
/**
|
|
115
114
|
* Verifies untrusted input. Either returns a value, or throws a decoding
|
|
@@ -151,16 +150,18 @@ interface Decoder<T> {
|
|
|
151
150
|
*/
|
|
152
151
|
describe(message: string): Decoder<T>;
|
|
153
152
|
/**
|
|
154
|
-
* Send the output of the current decoder into
|
|
155
|
-
*
|
|
156
|
-
*
|
|
153
|
+
* Send the output of the current decoder into an acceptance function. The
|
|
154
|
+
* given acceptance function will receive the output of the current decoder
|
|
155
|
+
* as its input.
|
|
157
156
|
*
|
|
158
157
|
* > _**NOTE:** This is an advanced, low-level, API. It's not recommended
|
|
159
158
|
* > to reach for this construct unless there is no other way. Most cases can
|
|
160
159
|
* > be covered more elegantly by `.transform()`, `.refine()`, or `.pipe()`
|
|
161
160
|
* > instead._
|
|
162
161
|
*/
|
|
163
|
-
chain<V>(next:
|
|
162
|
+
chain<V>(next: (blob: T, ok: (value: V) => DecodeResult<V>, err: (msg: string | Annotation) => DecodeResult<V>) => DecodeResult<V> | Decoder<V>): Decoder<V>;
|
|
163
|
+
/** @deprecated To send the output into another decoder, use `.pipe()` instead. */
|
|
164
|
+
chain<V>(next: Decoder<V>): Decoder<V>;
|
|
164
165
|
/**
|
|
165
166
|
* Send the output of this decoder as input to another decoder.
|
|
166
167
|
*
|
|
@@ -218,6 +219,46 @@ type Formatter = (err: Annotation) => string | Error;
|
|
|
218
219
|
declare function formatInline(ann: Annotation): string;
|
|
219
220
|
declare function formatShort(ann: Annotation): string;
|
|
220
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Forces TypeScript to "evaluate" named helper types, making API signatures
|
|
224
|
+
* clearer in IDEs.
|
|
225
|
+
*
|
|
226
|
+
* @see https://effectivetypescript.com/2022/02/25/gentips-4-display/
|
|
227
|
+
*/
|
|
228
|
+
type Resolve$1<T> = T extends (...args: unknown[]) => unknown ? T : {
|
|
229
|
+
[K in keyof T]: T[K];
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Relaxes a discriminated union type definition, by explicitly adding
|
|
233
|
+
* properties defined in any other member as optional `never`.
|
|
234
|
+
*
|
|
235
|
+
* This makes accessing the members much more relaxed in TypeScript.
|
|
236
|
+
*/
|
|
237
|
+
type Relax<T> = DistributiveRelax<T, T extends any ? keyof T : never>;
|
|
238
|
+
type DistributiveRelax<T, Ks extends string | number | symbol> = T extends any ? Resolve$1<{
|
|
239
|
+
[K in keyof T]: T[K];
|
|
240
|
+
} & {
|
|
241
|
+
[K in Exclude<Ks, keyof T>]?: never;
|
|
242
|
+
}> : never;
|
|
243
|
+
|
|
244
|
+
type SizeOptions = Relax<{
|
|
245
|
+
size: number;
|
|
246
|
+
} | {
|
|
247
|
+
min: number;
|
|
248
|
+
max?: number;
|
|
249
|
+
} | {
|
|
250
|
+
min?: number;
|
|
251
|
+
max: number;
|
|
252
|
+
}>;
|
|
253
|
+
/**
|
|
254
|
+
* Anything with a .length or .size property, like strings, arrays, or sets.
|
|
255
|
+
*/
|
|
256
|
+
type Sized = Relax<{
|
|
257
|
+
length: number;
|
|
258
|
+
} | {
|
|
259
|
+
size: number;
|
|
260
|
+
}>;
|
|
261
|
+
|
|
221
262
|
/**
|
|
222
263
|
* Accepts any array, but doesn't validate its items further.
|
|
223
264
|
*
|
|
@@ -227,7 +268,7 @@ declare const poja: Decoder<unknown[]>;
|
|
|
227
268
|
/**
|
|
228
269
|
* Accepts arrays of whatever the given decoder accepts.
|
|
229
270
|
*/
|
|
230
|
-
declare function array<T>(decoder: Decoder<T
|
|
271
|
+
declare function array<T>(decoder: Decoder<T>, options?: SizeOptions): Decoder<T[]>;
|
|
231
272
|
/**
|
|
232
273
|
* Like `array()`, but will reject arrays with 0 elements.
|
|
233
274
|
*/
|
|
@@ -365,7 +406,7 @@ declare const isoDate: Decoder<Date>;
|
|
|
365
406
|
declare const flexDate: Decoder<Date>;
|
|
366
407
|
/** @deprecated Renamed to `isoDateString`. This alias will be removed in 3.x. */
|
|
367
408
|
declare const dateString: Decoder<string>;
|
|
368
|
-
/**
|
|
409
|
+
/** @deprecated Renamed to `isoDate`. */
|
|
369
410
|
declare const iso8601: Decoder<Date>;
|
|
370
411
|
/** @deprecated Renamed to `flexDate`. This alias will be removed in 3.x. */
|
|
371
412
|
declare const datelike: Decoder<Date>;
|
|
@@ -401,46 +442,6 @@ declare const jsonArray: Decoder<JSONArray>;
|
|
|
401
442
|
*/
|
|
402
443
|
declare const json: Decoder<JSONValue>;
|
|
403
444
|
|
|
404
|
-
/**
|
|
405
|
-
* Forces TypeScript to "evaluate" named helper types, making API signatures
|
|
406
|
-
* clearer in IDEs.
|
|
407
|
-
*
|
|
408
|
-
* @see https://effectivetypescript.com/2022/02/25/gentips-4-display/
|
|
409
|
-
*/
|
|
410
|
-
type Resolve$1<T> = T extends (...args: unknown[]) => unknown ? T : {
|
|
411
|
-
[K in keyof T]: T[K];
|
|
412
|
-
};
|
|
413
|
-
/**
|
|
414
|
-
* Relaxes a discriminated union type definition, by explicitly adding
|
|
415
|
-
* properties defined in any other member as optional `never`.
|
|
416
|
-
*
|
|
417
|
-
* This makes accessing the members much more relaxed in TypeScript.
|
|
418
|
-
*/
|
|
419
|
-
type Relax<T> = DistributiveRelax<T, T extends any ? keyof T : never>;
|
|
420
|
-
type DistributiveRelax<T, Ks extends string | number | symbol> = T extends any ? Resolve$1<{
|
|
421
|
-
[K in keyof T]: T[K];
|
|
422
|
-
} & {
|
|
423
|
-
[K in Exclude<Ks, keyof T>]?: never;
|
|
424
|
-
}> : never;
|
|
425
|
-
|
|
426
|
-
type SizeOptions = Relax<{
|
|
427
|
-
size: number;
|
|
428
|
-
} | {
|
|
429
|
-
min: number;
|
|
430
|
-
max?: number;
|
|
431
|
-
} | {
|
|
432
|
-
min?: number;
|
|
433
|
-
max: number;
|
|
434
|
-
}>;
|
|
435
|
-
/**
|
|
436
|
-
* Anything with a .length or .size property, like strings, arrays, or sets.
|
|
437
|
-
*/
|
|
438
|
-
type Sized = Relax<{
|
|
439
|
-
length: number;
|
|
440
|
-
} | {
|
|
441
|
-
size: number;
|
|
442
|
-
}>;
|
|
443
|
-
|
|
444
445
|
interface Klass<T> extends Function {
|
|
445
446
|
new (...args: readonly any[]): T;
|
|
446
447
|
}
|
|
@@ -475,21 +476,28 @@ declare function prep<T>(mapperFn: (blob: unknown) => unknown, decoder: Decoder<
|
|
|
475
476
|
*/
|
|
476
477
|
declare const anyNumber: Decoder<number>;
|
|
477
478
|
/**
|
|
478
|
-
* Accepts finite numbers (
|
|
479
|
-
* or
|
|
479
|
+
* Accepts only finite numbers (e.g. -3.14, 0, 1, 42, ...).
|
|
480
|
+
* Integers or floats, but not `NaN` or `Infinity`.
|
|
480
481
|
*/
|
|
481
482
|
declare const number: Decoder<number>;
|
|
482
483
|
/**
|
|
483
|
-
* Accepts only
|
|
484
|
+
* Accepts only integers (e.g. ..., -2, -1, 0, 1, 2, ...).
|
|
485
|
+
* Whole numbers, and finite.
|
|
484
486
|
*/
|
|
485
487
|
declare const integer: Decoder<number>;
|
|
486
488
|
/**
|
|
487
|
-
* Accepts only non-negative (
|
|
489
|
+
* Accepts only non-negative numbers (e.g. 0, 0.5, 1, 3.14, ...).
|
|
490
|
+
* Integers or floats, >= 0, and finite.
|
|
488
491
|
*/
|
|
489
|
-
declare const
|
|
492
|
+
declare const nonNegativeNumber: Decoder<number>;
|
|
490
493
|
/**
|
|
491
|
-
* Accepts only
|
|
494
|
+
* Accepts only the natural numbers (e.g. 0, 1, 2, 3, ...).
|
|
495
|
+
* Whole numbers, >= 0, and finite.
|
|
492
496
|
*/
|
|
497
|
+
declare const natural: Decoder<number>;
|
|
498
|
+
/** @deprecated Renamed to `nonNegativeNumber`. */
|
|
499
|
+
declare const positiveNumber: Decoder<number>;
|
|
500
|
+
/** @deprecated Renamed to `natural`. */
|
|
493
501
|
declare const positiveInteger: Decoder<number>;
|
|
494
502
|
/**
|
|
495
503
|
* Accepts numbers greater than or equal to the given minimum.
|
|
@@ -724,4 +732,4 @@ declare function isPromiseLike(value: unknown): value is PromiseLike<unknown>;
|
|
|
724
732
|
*/
|
|
725
733
|
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
726
734
|
|
|
727
|
-
export { type Annotation, type ArrayAnnotation, type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type ObjectAnnotation, type Ok, type OpaqueAnnotation, type Relax, type Result, type Scalar, type ScalarAnnotation, type SizeOptions, type Sized, public_annotate as _annotate, always, anyNumber, anything, array, between, bigint, boolean, constant, date, dateString, datelike, decimal, define, either, email, endsWith, enum_, err, exact, fail, flexDate, formatInline, formatShort, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, isDate, isDecoder, isPlainObject, isPromiseLike, iso8601, isoDate, isoDateString, json, jsonArray, jsonObject, lazy, mapping, max, min, nanoid, never, nonEmptyArray, nonEmptyString, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, setFromArray, sized, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, urlString, uuid, uuidv1, uuidv4 };
|
|
735
|
+
export { type Annotation, type ArrayAnnotation, type DecodeResult, type Decoder, type DecoderType, type Err, type Formatter, type JSONArray, type JSONObject, type JSONValue, type ObjectAnnotation, type Ok, type OpaqueAnnotation, type Relax, type Result, type Scalar, type ScalarAnnotation, type SizeOptions, type Sized, public_annotate as _annotate, always, anyNumber, anything, array, between, bigint, boolean, constant, date, dateString, datelike, decimal, define, either, email, endsWith, enum_, err, exact, fail, flexDate, formatInline, formatShort, hexadecimal, httpsUrl, identifier, inexact, instanceOf, integer, isDate, isDecoder, isPlainObject, isPromiseLike, iso8601, isoDate, isoDateString, json, jsonArray, jsonObject, lazy, mapping, max, min, nanoid, natural, never, nonEmptyArray, nonEmptyString, nonNegativeNumber, null_, nullable, nullish, number, numeric, object, ok, oneOf, optional, poja, pojo, positiveInteger, positiveNumber, prep, record, regex, select, setFromArray, sized, startsWith, string, taggedUnion, truthy, tuple, undefined_, unknown, url, urlString, uuid, uuidv1, uuidv4 };
|
package/dist/index.js
CHANGED
|
@@ -29,56 +29,87 @@ function isPlainObject(value) {
|
|
|
29
29
|
// something is a pojo... ¯\_(ツ)_/¯
|
|
30
30
|
Object.prototype.toString.call(value) === "[object Object]";
|
|
31
31
|
}
|
|
32
|
+
function assertNever(_value, msg = "Unhandled case") {
|
|
33
|
+
throw new Error(msg);
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
// src/core/annotate.ts
|
|
34
37
|
var kAnnotationRegistry = /* @__PURE__ */ Symbol.for("decoders.kAnnotationRegistry");
|
|
35
|
-
var
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
+
var _stamped = globalThis[kAnnotationRegistry] ??= /* @__PURE__ */ new WeakSet();
|
|
39
|
+
function stamp(ann) {
|
|
40
|
+
_stamped.add(ann);
|
|
38
41
|
return ann;
|
|
39
42
|
}
|
|
40
|
-
function makeObjectAnn(
|
|
41
|
-
|
|
43
|
+
function makeObjectAnn(getFields, text) {
|
|
44
|
+
let fields;
|
|
45
|
+
return stamp({
|
|
46
|
+
type: "object",
|
|
47
|
+
get fields() {
|
|
48
|
+
return fields ??= getFields();
|
|
49
|
+
},
|
|
50
|
+
text
|
|
51
|
+
});
|
|
42
52
|
}
|
|
43
|
-
function makeArrayAnn(
|
|
44
|
-
|
|
53
|
+
function makeArrayAnn(getItems, text) {
|
|
54
|
+
let items;
|
|
55
|
+
return stamp({
|
|
56
|
+
type: "array",
|
|
57
|
+
get items() {
|
|
58
|
+
return items ??= getItems();
|
|
59
|
+
},
|
|
60
|
+
text
|
|
61
|
+
});
|
|
45
62
|
}
|
|
46
63
|
function makeOpaqueAnn(value, text) {
|
|
47
|
-
return
|
|
64
|
+
return stamp({ type: "opaque", value, text });
|
|
48
65
|
}
|
|
49
66
|
function makeScalarAnn(value, text) {
|
|
50
|
-
return
|
|
67
|
+
return stamp({ type: "scalar", value, text });
|
|
51
68
|
}
|
|
52
69
|
function updateText(annotation, text) {
|
|
53
|
-
if (text
|
|
54
|
-
return brand({ ...annotation, text });
|
|
55
|
-
} else {
|
|
70
|
+
if (text === void 0) {
|
|
56
71
|
return annotation;
|
|
57
72
|
}
|
|
73
|
+
switch (annotation.type) {
|
|
74
|
+
case "object":
|
|
75
|
+
return makeObjectAnn(() => annotation.fields, text);
|
|
76
|
+
case "array":
|
|
77
|
+
return makeArrayAnn(() => annotation.items, text);
|
|
78
|
+
case "scalar":
|
|
79
|
+
return makeScalarAnn(annotation.value, text);
|
|
80
|
+
case "opaque":
|
|
81
|
+
return makeOpaqueAnn(annotation.value, text);
|
|
82
|
+
// istanbul ignore next -- @preserve
|
|
83
|
+
default:
|
|
84
|
+
return assertNever(annotation, "Unknown annotation type");
|
|
85
|
+
}
|
|
58
86
|
}
|
|
59
87
|
function merge(objAnnotation, fields) {
|
|
60
|
-
|
|
61
|
-
|
|
88
|
+
return makeObjectAnn(
|
|
89
|
+
() => new Map([...objAnnotation.fields, ...fields]),
|
|
90
|
+
objAnnotation.text
|
|
91
|
+
);
|
|
62
92
|
}
|
|
63
93
|
function isAnnotation(thing) {
|
|
64
|
-
return
|
|
94
|
+
return _stamped.has(thing);
|
|
65
95
|
}
|
|
66
96
|
function annotateArray(arr, text, seen) {
|
|
67
97
|
seen.add(arr);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return makeArrayAnn(items, text);
|
|
98
|
+
return makeArrayAnn(
|
|
99
|
+
() => Array.from(arr, (value) => __annotate(value, void 0, seen)),
|
|
100
|
+
text
|
|
101
|
+
);
|
|
73
102
|
}
|
|
74
103
|
function annotateObject(obj, text, seen) {
|
|
75
104
|
seen.add(obj);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
105
|
+
return makeObjectAnn(() => {
|
|
106
|
+
const fields = /* @__PURE__ */ new Map();
|
|
107
|
+
for (const key of Object.keys(obj)) {
|
|
108
|
+
const value = obj[key];
|
|
109
|
+
fields.set(key, __annotate(value, void 0, seen));
|
|
110
|
+
}
|
|
111
|
+
return fields;
|
|
112
|
+
}, text);
|
|
82
113
|
}
|
|
83
114
|
function __annotate(value, text, seen) {
|
|
84
115
|
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "symbol" || typeof value === "bigint" || typeof value.getMonth === "function") {
|
|
@@ -299,6 +330,9 @@ function* iterAnnotation(ann, stack) {
|
|
|
299
330
|
case "opaque": {
|
|
300
331
|
break;
|
|
301
332
|
}
|
|
333
|
+
// istanbul ignore next -- @preserve
|
|
334
|
+
default:
|
|
335
|
+
assertNever(ann, "Unknown annotation type");
|
|
302
336
|
}
|
|
303
337
|
}
|
|
304
338
|
function formatAsIssues(ann) {
|
|
@@ -398,7 +432,7 @@ function define(fn) {
|
|
|
398
432
|
}
|
|
399
433
|
});
|
|
400
434
|
}
|
|
401
|
-
const
|
|
435
|
+
const newDecoder = {
|
|
402
436
|
verify,
|
|
403
437
|
value,
|
|
404
438
|
decode,
|
|
@@ -423,80 +457,18 @@ function define(fn) {
|
|
|
423
457
|
}
|
|
424
458
|
}
|
|
425
459
|
};
|
|
426
|
-
const self =
|
|
460
|
+
const self = stamp2(newDecoder);
|
|
427
461
|
return self;
|
|
428
462
|
}
|
|
429
463
|
var kDecoderRegistry = /* @__PURE__ */ Symbol.for("decoders.kDecoderRegistry");
|
|
430
|
-
var
|
|
431
|
-
function
|
|
432
|
-
|
|
464
|
+
var _stamped2 = globalThis[kDecoderRegistry] ??= /* @__PURE__ */ new WeakSet();
|
|
465
|
+
function stamp2(decoder) {
|
|
466
|
+
_stamped2.add(decoder);
|
|
433
467
|
return decoder;
|
|
434
468
|
}
|
|
435
469
|
// @__NO_SIDE_EFFECTS__
|
|
436
470
|
function isDecoder(value) {
|
|
437
|
-
return
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// src/arrays.ts
|
|
441
|
-
var poja = define((blob, ok2, err2) => {
|
|
442
|
-
if (!Array.isArray(blob)) {
|
|
443
|
-
return err2("Must be an array");
|
|
444
|
-
}
|
|
445
|
-
return ok2(blob);
|
|
446
|
-
});
|
|
447
|
-
// @__NO_SIDE_EFFECTS__
|
|
448
|
-
function array(decoder) {
|
|
449
|
-
const decodeFn = decoder.decode;
|
|
450
|
-
return poja.chain((inputs, ok2, err2) => {
|
|
451
|
-
const results = [];
|
|
452
|
-
for (let i = 0; i < inputs.length; ++i) {
|
|
453
|
-
const blob = inputs[i];
|
|
454
|
-
const result = decodeFn(blob);
|
|
455
|
-
if (result.ok) {
|
|
456
|
-
results.push(result.value);
|
|
457
|
-
} else {
|
|
458
|
-
results.length = 0;
|
|
459
|
-
const ann = result.error;
|
|
460
|
-
const clone = inputs.slice();
|
|
461
|
-
clone.splice(
|
|
462
|
-
i,
|
|
463
|
-
1,
|
|
464
|
-
public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
|
|
465
|
-
);
|
|
466
|
-
return err2(public_annotate(clone));
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
return ok2(results);
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
function isNonEmpty(arr) {
|
|
473
|
-
return arr.length > 0;
|
|
474
|
-
}
|
|
475
|
-
// @__NO_SIDE_EFFECTS__
|
|
476
|
-
function nonEmptyArray(decoder) {
|
|
477
|
-
return (/* @__PURE__ */ array(decoder)).refine(isNonEmpty, "Must have at least 1 item");
|
|
478
|
-
}
|
|
479
|
-
var ntuple = /* @__NO_SIDE_EFFECTS__ */ (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
|
|
480
|
-
// @__NO_SIDE_EFFECTS__
|
|
481
|
-
function tuple(...decoders) {
|
|
482
|
-
return (/* @__PURE__ */ ntuple(decoders.length)).chain((blobs, ok2, err2) => {
|
|
483
|
-
let allOk = true;
|
|
484
|
-
const rvs = decoders.map((decoder, i) => {
|
|
485
|
-
const blob = blobs[i];
|
|
486
|
-
const result = decoder.decode(blob);
|
|
487
|
-
if (result.ok) {
|
|
488
|
-
return result.value;
|
|
489
|
-
} else {
|
|
490
|
-
allOk = false;
|
|
491
|
-
return result.error;
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
if (allOk) {
|
|
495
|
-
return ok2(rvs);
|
|
496
|
-
} else {
|
|
497
|
-
return err2(public_annotate(rvs));
|
|
498
|
-
}
|
|
499
|
-
});
|
|
471
|
+
return _stamped2.has(value);
|
|
500
472
|
}
|
|
501
473
|
|
|
502
474
|
// src/lib/size-options.ts
|
|
@@ -561,6 +533,66 @@ function prep(mapperFn, decoder) {
|
|
|
561
533
|
});
|
|
562
534
|
}
|
|
563
535
|
|
|
536
|
+
// src/arrays.ts
|
|
537
|
+
var poja = define((blob, ok2, err2) => {
|
|
538
|
+
if (!Array.isArray(blob)) {
|
|
539
|
+
return err2("Must be an array");
|
|
540
|
+
}
|
|
541
|
+
return ok2(blob);
|
|
542
|
+
});
|
|
543
|
+
// @__NO_SIDE_EFFECTS__
|
|
544
|
+
function array(decoder, options) {
|
|
545
|
+
const decodeFn = decoder.decode;
|
|
546
|
+
const base = options !== void 0 ? sized(poja, options) : poja;
|
|
547
|
+
return base.chain((inputs, ok2, err2) => {
|
|
548
|
+
const results = [];
|
|
549
|
+
for (let i = 0; i < inputs.length; ++i) {
|
|
550
|
+
const blob = inputs[i];
|
|
551
|
+
const result = decodeFn(blob);
|
|
552
|
+
if (result.ok) {
|
|
553
|
+
results.push(result.value);
|
|
554
|
+
} else {
|
|
555
|
+
results.length = 0;
|
|
556
|
+
const ann = result.error;
|
|
557
|
+
const clone = inputs.slice();
|
|
558
|
+
clone.splice(
|
|
559
|
+
i,
|
|
560
|
+
1,
|
|
561
|
+
public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
|
|
562
|
+
);
|
|
563
|
+
return err2(public_annotate(clone));
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return ok2(results);
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
// @__NO_SIDE_EFFECTS__
|
|
570
|
+
function nonEmptyArray(decoder) {
|
|
571
|
+
return (/* @__PURE__ */ array(decoder, { min: 1 })).refineType();
|
|
572
|
+
}
|
|
573
|
+
var ntuple = /* @__NO_SIDE_EFFECTS__ */ (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
|
|
574
|
+
// @__NO_SIDE_EFFECTS__
|
|
575
|
+
function tuple(...decoders) {
|
|
576
|
+
return (/* @__PURE__ */ ntuple(decoders.length)).chain((blobs, ok2, err2) => {
|
|
577
|
+
let allOk = true;
|
|
578
|
+
const rvs = decoders.map((decoder, i) => {
|
|
579
|
+
const blob = blobs[i];
|
|
580
|
+
const result = decoder.decode(blob);
|
|
581
|
+
if (result.ok) {
|
|
582
|
+
return result.value;
|
|
583
|
+
} else {
|
|
584
|
+
allOk = false;
|
|
585
|
+
return result.error;
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
if (allOk) {
|
|
589
|
+
return ok2(rvs);
|
|
590
|
+
} else {
|
|
591
|
+
return err2(public_annotate(rvs));
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
|
|
564
596
|
// src/lib/set-methods.ts
|
|
565
597
|
// @__NO_SIDE_EFFECTS__
|
|
566
598
|
function difference(xs, ys) {
|
|
@@ -900,7 +932,9 @@ function nanoid(options) {
|
|
|
900
932
|
return sized(/* @__PURE__ */ regex(/^[a-z0-9_-]+$/i, "Must be nano ID"), options ?? { size: 21 });
|
|
901
933
|
}
|
|
902
934
|
var uuid = /* @__PURE__ */ regex(
|
|
903
|
-
|
|
935
|
+
// https://www.rfc-editor.org/rfc/rfc9562#section-4
|
|
936
|
+
// Version 1-8 with variant 8, 9, a, or b, plus the Nil and Max UUIDs (sections 5.9, 5.10)
|
|
937
|
+
/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i,
|
|
904
938
|
"Must be uuid"
|
|
905
939
|
);
|
|
906
940
|
var uuidv1 = (
|
|
@@ -953,14 +987,16 @@ var integer = /* @__PURE__ */ number.refine(
|
|
|
953
987
|
(n) => Number.isInteger(n),
|
|
954
988
|
"Number must be an integer"
|
|
955
989
|
);
|
|
956
|
-
var
|
|
990
|
+
var nonNegativeNumber = /* @__PURE__ */ number.refine(
|
|
957
991
|
(n) => n >= 0 && !Object.is(n, -0),
|
|
958
992
|
"Number must be positive"
|
|
959
993
|
);
|
|
960
|
-
var
|
|
994
|
+
var natural = /* @__PURE__ */ integer.refine(
|
|
961
995
|
(n) => n >= 0 && !Object.is(n, -0),
|
|
962
996
|
"Number must be positive"
|
|
963
997
|
);
|
|
998
|
+
var positiveNumber = nonNegativeNumber;
|
|
999
|
+
var positiveInteger = natural;
|
|
964
1000
|
// @__NO_SIDE_EFFECTS__
|
|
965
1001
|
function min(min2, decoder = number) {
|
|
966
1002
|
return decoder.reject(
|
|
@@ -1040,9 +1076,11 @@ export {
|
|
|
1040
1076
|
max,
|
|
1041
1077
|
min,
|
|
1042
1078
|
nanoid,
|
|
1079
|
+
natural,
|
|
1043
1080
|
never,
|
|
1044
1081
|
nonEmptyArray,
|
|
1045
1082
|
nonEmptyString,
|
|
1083
|
+
nonNegativeNumber,
|
|
1046
1084
|
null_,
|
|
1047
1085
|
nullable,
|
|
1048
1086
|
nullish,
|
|
@@ -1075,4 +1113,5 @@ export {
|
|
|
1075
1113
|
uuidv1,
|
|
1076
1114
|
uuidv4
|
|
1077
1115
|
};
|
|
1116
|
+
// istanbul ignore next -- @preserve
|
|
1078
1117
|
// istanbul ignore else -- @preserve
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decoders",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Elegant and battle-tested validation library for type-safe input data for TypeScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsup",
|
|
38
|
-
"docs": "
|
|
38
|
+
"docs": "pnpm run build && cp -r dist/ docs/decoders-latest-snapshot/ && cd docs && rm -rf .next && pnpm run dev",
|
|
39
39
|
"docs:update-sources": "node bin/update-source-lines.js",
|
|
40
40
|
"docs:update-redirects": "node bin/update-decoder-redirects.js",
|
|
41
41
|
"lint": "oxlint src/ test/ && prettier --list-different src/ test/ test-d/ && node bin/lint-side-effects.js",
|
|
42
42
|
"lint:package": "publint --strict && attw --pack",
|
|
43
|
-
"format": "oxlint --fix src/ test/ ; prettier --write src/ test/ test-d/ docs/content/ ;
|
|
43
|
+
"format": "oxlint --fix src/ test/ ; prettier --write src/ test/ test-d/ docs/content/ ; pnpm run docs:update-sources ; pnpm run docs:update-redirects",
|
|
44
44
|
"test": "vitest run --coverage",
|
|
45
|
-
"test:treeshake": "
|
|
45
|
+
"test:treeshake": "pnpm run build && node bin/test-treeshake.js",
|
|
46
46
|
"test:completeness": "./bin/check.sh",
|
|
47
47
|
"test:typescript": "tsc --noEmit",
|
|
48
|
-
"test:types": "
|
|
48
|
+
"test:types": "pnpm run build && tsd --typings ./dist/index.d.ts",
|
|
49
49
|
"test:watch": "vitest --coverage",
|
|
50
50
|
"release": "release-it"
|
|
51
51
|
},
|
|
@@ -80,5 +80,6 @@
|
|
|
80
80
|
"vitest": "^4.1.11"
|
|
81
81
|
},
|
|
82
82
|
"githubUrl": "https://github.com/nvie/decoders",
|
|
83
|
-
"sideEffects": false
|
|
83
|
+
"sideEffects": false,
|
|
84
|
+
"packageManager": "pnpm@11.24.0"
|
|
84
85
|
}
|