decoders 2.2.0 → 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 CHANGED
@@ -1,110 +1,45 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/_utils.ts
2
- var INDENT = " ";
3
- function lazyval(value) {
4
- return typeof value === "function" ? value() : value;
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";
5
4
  }
6
- function subtract(xs, ys) {
7
- const result = /* @__PURE__ */ new Set();
8
- for (const x of xs) {
9
- if (!ys.has(x)) {
10
- result.add(x);
11
- }
12
- }
13
- return result;
5
+ function isString(value) {
6
+ return typeof value === "string";
7
+ }
8
+ function isBigInt(value) {
9
+ return typeof value === "bigint";
14
10
  }
15
- function asDate(value) {
16
- return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value) ? value : null;
11
+ function isDate(value) {
12
+ return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
17
13
  }
18
14
  function isPojo(value) {
19
15
  return value !== null && value !== void 0 && typeof value === "object" && // This still seems to be the only reliable way to determine whether
20
16
  // something is a pojo... ¯\_(ツ)_/¯
21
17
  Object.prototype.toString.call(value) === "[object Object]";
22
18
  }
23
- function isMultiline(s) {
24
- return s.indexOf("\n") >= 0;
25
- }
26
- function indent(s, prefix = INDENT) {
27
- if (isMultiline(s)) {
28
- return s.split("\n").map((line) => `${prefix}${line}`).join("\n");
29
- } else {
30
- return `${prefix}${s}`;
31
- }
32
- }
33
- function summarize(ann, keypath = []) {
34
- const result = [];
35
- if (ann.type === "array") {
36
- const items = ann.items;
37
- let index = 0;
38
- for (const ann2 of items) {
39
- for (const item of summarize(ann2, [...keypath, index++])) {
40
- result.push(item);
41
- }
42
- }
43
- } else if (ann.type === "object") {
44
- const fields = ann.fields;
45
- for (const key of Object.keys(fields)) {
46
- const value = fields[key];
47
- for (const item of summarize(value, [...keypath, key])) {
48
- result.push(item);
49
- }
50
- }
51
- }
52
- const text = ann.text;
53
- if (!text) {
54
- return result;
55
- }
56
- let prefix;
57
- if (keypath.length === 0) {
58
- prefix = "";
59
- } else if (keypath.length === 1) {
60
- prefix = typeof keypath[0] === "number" ? `Value at index ${keypath[0]}: ` : `Value at key ${JSON.stringify(keypath[0])}: `;
61
- } else {
62
- prefix = `Value at keypath ${keypath.map(String).join(".")}: `;
63
- }
64
- return [...result, `${prefix}${text}`];
65
- }
66
19
 
67
- // src/annotate.ts
20
+ // src/core/annotate.ts
68
21
  var _register = /* @__PURE__ */ new WeakSet();
69
22
  function brand(ann) {
70
23
  _register.add(ann);
71
24
  return ann;
72
25
  }
73
- function object(fields, text) {
26
+ function makeObjectAnn(fields, text) {
74
27
  return brand({ type: "object", fields, text });
75
28
  }
76
- function array(items, text) {
77
- return brand({
78
- type: "array",
79
- items,
80
- text
81
- });
29
+ function makeArrayAnn(items, text) {
30
+ return brand({ type: "array", items, text });
82
31
  }
83
- function func(text) {
84
- return brand({
85
- type: "function",
86
- text
87
- });
32
+ function makeFunctionAnn(text) {
33
+ return brand({ type: "function", text });
88
34
  }
89
- function unknown(value, text) {
90
- return brand({
91
- type: "unknown",
92
- value,
93
- text
94
- });
35
+ function makeUnknownAnn(value, text) {
36
+ return brand({ type: "unknown", value, text });
95
37
  }
96
- function scalar(value, text) {
97
- return brand({
98
- type: "scalar",
99
- value,
100
- text
101
- });
38
+ function makeScalarAnn(value, text) {
39
+ return brand({ type: "scalar", value, text });
102
40
  }
103
- function circularRef(text) {
104
- return brand({
105
- type: "circular-ref",
106
- text
107
- });
41
+ function makeCircularRefAnn(text) {
42
+ return brand({ type: "circular-ref", text });
108
43
  }
109
44
  function updateText(annotation, text) {
110
45
  if (text !== void 0) {
@@ -114,52 +49,53 @@ function updateText(annotation, text) {
114
49
  }
115
50
  }
116
51
  function merge(objAnnotation, fields) {
117
- const newFields = { ...objAnnotation.fields, ...fields };
118
- return object(newFields, objAnnotation.text);
52
+ const newFields = new Map([...objAnnotation.fields, ...fields]);
53
+ return makeObjectAnn(newFields, objAnnotation.text);
119
54
  }
120
- function asAnnotation(thing) {
121
- return typeof thing === "object" && thing !== null && _register.has(thing) ? thing : void 0;
55
+ function isAnnotation(thing) {
56
+ return _register.has(thing);
122
57
  }
123
- function annotateArray(value, text, seen) {
124
- seen.add(value);
125
- const items = value.map((v) => annotate(v, void 0, seen));
126
- return array(items, text);
58
+ function annotateArray(arr, text, seen) {
59
+ seen.add(arr);
60
+ const items = [];
61
+ for (const value of arr) {
62
+ items.push(annotate(value, void 0, seen));
63
+ }
64
+ return makeArrayAnn(items, text);
127
65
  }
128
66
  function annotateObject(obj, text, seen) {
129
67
  seen.add(obj);
130
- const fields = {};
131
- for (const key of Object.keys(obj)) {
132
- const value = obj[key];
133
- fields[key] = annotate(value, void 0, seen);
68
+ const fields = /* @__PURE__ */ new Map();
69
+ for (const [key, value] of Object.entries(obj)) {
70
+ fields.set(key, annotate(value, void 0, seen));
134
71
  }
135
- return object(fields, text);
72
+ return makeObjectAnn(fields, text);
136
73
  }
137
74
  function annotate(value, text, seen) {
138
75
  if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "symbol" || typeof value.getMonth === "function") {
139
- return scalar(value, text);
76
+ return makeScalarAnn(value, text);
140
77
  }
141
- const ann = asAnnotation(value);
142
- if (ann) {
143
- return updateText(ann, text);
78
+ if (isAnnotation(value)) {
79
+ return updateText(value, text);
144
80
  }
145
81
  if (Array.isArray(value)) {
146
82
  if (seen.has(value)) {
147
- return circularRef(text);
83
+ return makeCircularRefAnn(text);
148
84
  } else {
149
85
  return annotateArray(value, text, seen);
150
86
  }
151
87
  }
152
88
  if (isPojo(value)) {
153
89
  if (seen.has(value)) {
154
- return circularRef(text);
90
+ return makeCircularRefAnn(text);
155
91
  } else {
156
92
  return annotateObject(value, text, seen);
157
93
  }
158
94
  }
159
95
  if (typeof value === "function") {
160
- return func(text);
96
+ return makeFunctionAnn(text);
161
97
  }
162
- return unknown(value, text);
98
+ return makeUnknownAnn(value, text);
163
99
  }
164
100
  function public_annotate(value, text) {
165
101
  return annotate(value, text, /* @__PURE__ */ new WeakSet());
@@ -168,7 +104,52 @@ function public_annotateObject(obj, text) {
168
104
  return annotateObject(obj, text, /* @__PURE__ */ new WeakSet());
169
105
  }
170
106
 
171
- // src/format.ts
107
+ // src/lib/text.ts
108
+ var INDENT = " ";
109
+ function isMultiline(s) {
110
+ return s.indexOf("\n") >= 0;
111
+ }
112
+ function indent(s, prefix = INDENT) {
113
+ if (isMultiline(s)) {
114
+ return s.split("\n").map((line) => `${prefix}${line}`).join("\n");
115
+ } else {
116
+ return `${prefix}${s}`;
117
+ }
118
+ }
119
+
120
+ // src/core/format.ts
121
+ function summarize(ann, keypath = []) {
122
+ const result = [];
123
+ if (ann.type === "array") {
124
+ const items = ann.items;
125
+ let index = 0;
126
+ for (const ann2 of items) {
127
+ for (const item of summarize(ann2, [...keypath, index++])) {
128
+ result.push(item);
129
+ }
130
+ }
131
+ } else if (ann.type === "object") {
132
+ const fields = ann.fields;
133
+ for (const [key, value] of fields) {
134
+ for (const item of summarize(value, [...keypath, key])) {
135
+ result.push(item);
136
+ }
137
+ }
138
+ }
139
+ const text = ann.text;
140
+ if (!text) {
141
+ return result;
142
+ }
143
+ let prefix;
144
+ if (keypath.length === 0) {
145
+ prefix = "";
146
+ } else if (keypath.length === 1) {
147
+ prefix = typeof keypath[0] === "number" ? `Value at index ${keypath[0]}: ` : `Value at key ${JSON.stringify(keypath[0])}: `;
148
+ } else {
149
+ prefix = `Value at keypath ${keypath.map(String).join(".")}: `;
150
+ }
151
+ return [...result, `${prefix}${text}`];
152
+ }
172
153
  function serializeString(s, width = 80) {
173
154
  let ser = JSON.stringify(s);
174
155
  if (ser.length <= width) {
@@ -195,13 +176,11 @@ function serializeArray(annotation, prefix) {
195
176
  }
196
177
  function serializeObject(annotation, prefix) {
197
178
  const { fields } = annotation;
198
- const fieldNames = Object.keys(fields);
199
- if (fieldNames.length === 0) {
179
+ if (fields.size === 0) {
200
180
  return "{}";
201
181
  }
202
182
  const result = [];
203
- for (const key of fieldNames) {
204
- const valueAnnotation = fields[key];
183
+ for (const [key, valueAnnotation] of fields) {
205
184
  const kser = serializeValue(key);
206
185
  const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
207
186
  const [vser, vann] = serializeAnnotation(valueAnnotation, `${prefix}${INDENT}`);
@@ -215,16 +194,15 @@ function serializeObject(annotation, prefix) {
215
194
  function serializeValue(value) {
216
195
  if (typeof value === "string") {
217
196
  return serializeString(value);
218
- } else if (typeof value === "number" || typeof value === "boolean") {
197
+ } else if (typeof value === "number" || typeof value === "boolean" || typeof value === "symbol") {
219
198
  return value.toString();
220
199
  } else if (value === null) {
221
200
  return "null";
222
201
  } else if (value === void 0) {
223
202
  return "undefined";
224
203
  } else {
225
- const valueAsDate = asDate(value);
226
- if (valueAsDate !== null) {
227
- return `new Date(${JSON.stringify(valueAsDate.toISOString())})`;
204
+ if (isDate(value)) {
205
+ return `new Date(${JSON.stringify(value.toISOString())})`;
228
206
  } else if (value instanceof Date) {
229
207
  return "(Invalid Date)";
230
208
  } else {
@@ -268,7 +246,7 @@ function formatShort(ann) {
268
246
  return summarize(ann, []).join("\n");
269
247
  }
270
248
 
271
- // src/result.ts
249
+ // src/core/Result.ts
272
250
  function ok(value) {
273
251
  return { ok: true, value, error: void 0 };
274
252
  }
@@ -276,7 +254,7 @@ function err(error) {
276
254
  return { ok: false, value: void 0, error };
277
255
  }
278
256
 
279
- // src/Decoder.ts
257
+ // src/core/Decoder.ts
280
258
  function noThrow(fn) {
281
259
  return (t) => {
282
260
  try {
@@ -303,7 +281,7 @@ function define(fn) {
303
281
  return fn(
304
282
  blob,
305
283
  ok,
306
- (msg) => err(typeof msg === "string" ? public_annotate(blob, msg) : msg)
284
+ (msg) => err(isAnnotation(msg) ? msg : public_annotate(blob, msg))
307
285
  );
308
286
  }
309
287
  function verify(blob, formatter = formatInline) {
@@ -338,9 +316,9 @@ function define(fn) {
338
316
  });
339
317
  }
340
318
  function reject(rejectFn) {
341
- return then((value2, ok2, err2) => {
342
- const errmsg = rejectFn(value2);
343
- return errmsg === null ? ok2(value2) : err2(typeof errmsg === "string" ? public_annotate(value2, errmsg) : errmsg);
319
+ return then((blob, ok2, err2) => {
320
+ const errmsg = rejectFn(blob);
321
+ return errmsg === null ? ok2(blob) : err2(typeof errmsg === "string" ? public_annotate(blob, errmsg) : errmsg);
344
322
  });
345
323
  }
346
324
  function describe(message) {
@@ -353,7 +331,7 @@ function define(fn) {
353
331
  }
354
332
  });
355
333
  }
356
- function peek_UNSTABLE(next) {
334
+ function peek(next) {
357
335
  return define((blob, ok2, err2) => {
358
336
  const result = decode(blob);
359
337
  return result.ok ? next([blob, result.value], ok2, err2) : result;
@@ -368,30 +346,132 @@ function define(fn) {
368
346
  reject,
369
347
  describe,
370
348
  then,
371
- // EXPERIMENTAL - please DO NOT rely on this method
372
- peek_UNSTABLE
349
+ peek
373
350
  });
374
351
  }
375
352
 
376
- // src/lib/objects.ts
353
+ // src/arrays.ts
354
+ var poja = define((blob, ok2, err2) => {
355
+ if (!Array.isArray(blob)) {
356
+ return err2("Must be an array");
357
+ }
358
+ return ok2(blob);
359
+ });
360
+ function all(items, blobs, ok2, err2) {
361
+ const results = [];
362
+ for (let index = 0; index < items.length; ++index) {
363
+ const result = items[index];
364
+ if (result.ok) {
365
+ results.push(result.value);
366
+ } else {
367
+ const ann = result.error;
368
+ const clone = blobs.slice();
369
+ clone.splice(
370
+ index,
371
+ 1,
372
+ public_annotate(ann, ann.text ? `${ann.text} (at index ${index})` : `index ${index}`)
373
+ );
374
+ return err2(public_annotate(clone));
375
+ }
376
+ }
377
+ return ok2(results);
378
+ }
379
+ function array(decoder) {
380
+ const decodeFn = decoder.decode;
381
+ return poja.then((blobs, ok2, err2) => {
382
+ const results = blobs.map(decodeFn);
383
+ return all(results, blobs, ok2, err2);
384
+ });
385
+ }
386
+ function isNonEmpty(arr) {
387
+ return arr.length > 0;
388
+ }
389
+ function nonEmptyArray(decoder) {
390
+ return array(decoder).refine(isNonEmpty, "Must be non-empty array");
391
+ }
392
+ function set(decoder) {
393
+ return array(decoder).transform((items) => new Set(items));
394
+ }
395
+ var ntuple = (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
396
+ function tuple(...decoders) {
397
+ return ntuple(decoders.length).then((blobs, ok2, err2) => {
398
+ let allOk = true;
399
+ const rvs = decoders.map((decoder, i) => {
400
+ const blob = blobs[i];
401
+ const result = decoder.decode(blob);
402
+ if (result.ok) {
403
+ return result.value;
404
+ } else {
405
+ allOk = false;
406
+ return result.error;
407
+ }
408
+ });
409
+ if (allOk) {
410
+ return ok2(rvs);
411
+ } else {
412
+ return err2(public_annotate(rvs));
413
+ }
414
+ });
415
+ }
416
+
417
+ // src/misc.ts
418
+ function instanceOf(klass) {
419
+ return define(
420
+ (blob, ok2, err2) => blob instanceof klass ? ok2(blob) : err2(`Must be ${klass.name} instance`)
421
+ );
422
+ }
423
+ function lazy(decoderFn) {
424
+ return define((blob) => decoderFn().decode(blob));
425
+ }
426
+ function prep(mapperFn, decoder) {
427
+ return define((originalInput, _, err2) => {
428
+ let blob;
429
+ try {
430
+ blob = mapperFn(originalInput);
431
+ } catch (e) {
432
+ return err2(
433
+ public_annotate(
434
+ originalInput,
435
+ // istanbul ignore next
436
+ e instanceof Error ? e.message : String(e)
437
+ )
438
+ );
439
+ }
440
+ const r = decoder.decode(blob);
441
+ return r.ok ? r : err2(public_annotate(originalInput, r.error.text));
442
+ });
443
+ }
444
+
445
+ // src/lib/set-methods.ts
446
+ function difference(xs, ys) {
447
+ const result = /* @__PURE__ */ new Set();
448
+ for (const x of xs) {
449
+ if (!ys.has(x)) {
450
+ result.add(x);
451
+ }
452
+ }
453
+ return result;
454
+ }
455
+
456
+ // src/objects.ts
377
457
  var pojo = define(
378
458
  (blob, ok2, err2) => isPojo(blob) ? ok2(blob) : err2("Must be an object")
379
459
  );
380
- function object2(decodersByKey) {
381
- const knownKeys = new Set(Object.keys(decodersByKey));
460
+ function object(decoders) {
461
+ const knownKeys = new Set(Object.keys(decoders));
382
462
  return pojo.then((plainObj, ok2, err2) => {
383
463
  const actualKeys = new Set(Object.keys(plainObj));
384
- const missingKeys = subtract(knownKeys, actualKeys);
385
- const record = {};
464
+ const missingKeys = difference(knownKeys, actualKeys);
465
+ const record2 = {};
386
466
  let errors = null;
387
- for (const key of Object.keys(decodersByKey)) {
388
- const decoder = decodersByKey[key];
467
+ for (const key of Object.keys(decoders)) {
468
+ const decoder = decoders[key];
389
469
  const rawValue = plainObj[key];
390
470
  const result = decoder.decode(rawValue);
391
471
  if (result.ok) {
392
472
  const value = result.value;
393
473
  if (value !== void 0) {
394
- record[key] = value;
474
+ record2[key] = value;
395
475
  }
396
476
  missingKeys.delete(key);
397
477
  } else {
@@ -400,9 +480,9 @@ function object2(decodersByKey) {
400
480
  missingKeys.add(key);
401
481
  } else {
402
482
  if (errors === null) {
403
- errors = {};
483
+ errors = /* @__PURE__ */ new Map();
404
484
  }
405
- errors[key] = ann;
485
+ errors.set(key, ann);
406
486
  }
407
487
  }
408
488
  }
@@ -418,26 +498,26 @@ function object2(decodersByKey) {
418
498
  }
419
499
  return err2(objAnn);
420
500
  }
421
- return ok2(record);
501
+ return ok2(record2);
422
502
  });
423
503
  }
424
- function exact(decodersByKey) {
425
- const allowedKeys = new Set(Object.keys(decodersByKey));
504
+ function exact(decoders) {
505
+ const allowedKeys = new Set(Object.keys(decoders));
426
506
  const checked = pojo.reject((plainObj) => {
427
507
  const actualKeys = new Set(Object.keys(plainObj));
428
- const extraKeys = subtract(actualKeys, allowedKeys);
508
+ const extraKeys = difference(actualKeys, allowedKeys);
429
509
  return extraKeys.size > 0 ? `Unexpected extra keys: ${Array.from(extraKeys).join(", ")}` : (
430
510
  // Don't reject
431
511
  null
432
512
  );
433
513
  });
434
- return checked.then(object2(decodersByKey).decode);
514
+ return checked.then(object(decoders).decode);
435
515
  }
436
- function inexact(decodersByKey) {
516
+ function inexact(decoders) {
437
517
  return pojo.then((plainObj) => {
438
518
  const allkeys = new Set(Object.keys(plainObj));
439
- const decoder = object2(decodersByKey).transform((safepart) => {
440
- const safekeys = new Set(Object.keys(decodersByKey));
519
+ const decoder = object(decoders).transform((safepart) => {
520
+ const safekeys = new Set(Object.keys(decoders));
441
521
  for (const k of safekeys)
442
522
  allkeys.add(k);
443
523
  const rv = {};
@@ -456,81 +536,52 @@ function inexact(decodersByKey) {
456
536
  return decoder.decode(plainObj);
457
537
  });
458
538
  }
459
- function dict(decoder) {
460
- return pojo.then((plainObj, ok2, err2) => {
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) => {
461
543
  let rv = {};
462
- let errors = null;
463
- for (const key of Object.keys(plainObj)) {
464
- const value = plainObj[key];
465
- const result = decoder.decode(value);
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);
466
557
  if (result.ok) {
467
- if (errors === null) {
468
- rv[key] = result.value;
558
+ if (errors.size === 0) {
559
+ rv[k] = result.value;
469
560
  }
470
561
  } else {
562
+ errors.set(key, result.error);
471
563
  rv = {};
472
- if (errors === null) {
473
- errors = {};
474
- }
475
- errors[key] = result.error;
476
564
  }
477
565
  }
478
- if (errors !== null) {
479
- return err2(merge(public_annotateObject(plainObj), errors));
566
+ if (errors.size > 0) {
567
+ return err2(merge(public_annotateObject(rec), errors));
480
568
  } else {
481
569
  return ok2(rv);
482
570
  }
483
571
  });
484
572
  }
573
+ var dict = record;
485
574
  function mapping(decoder) {
486
- return dict(decoder).transform(
487
- (obj) => new Map(
488
- // This is effectively Object.entries(obj), but in a way that Flow
489
- // will know the types are okay
490
- Object.keys(obj).map((key) => [key, obj[key]])
491
- )
492
- );
493
- }
494
-
495
- // src/lib/utilities.ts
496
- function instanceOf(klass) {
497
- return define(
498
- (blob, ok2, err2) => blob instanceof klass ? ok2(blob) : err2(`Must be ${klass.name} instance`)
499
- );
500
- }
501
- function lazy(decoderFn) {
502
- return define((blob) => decoderFn().decode(blob));
503
- }
504
- function prep(mapperFn, decoder) {
505
- return define((originalInput, _, err2) => {
506
- let blob;
507
- try {
508
- blob = mapperFn(originalInput);
509
- } catch (e) {
510
- return err2(
511
- public_annotate(
512
- originalInput,
513
- // istanbul ignore next
514
- e instanceof Error ? e.message : String(e)
515
- )
516
- );
517
- }
518
- const r = decoder.decode(blob);
519
- return r.ok ? r : err2(public_annotate(originalInput, r.error.text));
520
- });
575
+ return record(decoder).transform((obj) => new Map(Object.entries(obj)));
521
576
  }
522
- function never(msg) {
523
- return define((_, __, err2) => err2(msg));
524
- }
525
- var fail = never;
526
577
 
527
- // src/lib/unions.ts
578
+ // src/unions.ts
528
579
  var EITHER_PREFIX = "Either:\n";
529
580
  function itemize(s) {
530
581
  return `-${indent(s).substring(1)}`;
531
582
  }
532
583
  function nest(errText) {
533
- return errText.startsWith(EITHER_PREFIX) ? errText.substr(EITHER_PREFIX.length) : itemize(errText);
584
+ return errText.startsWith(EITHER_PREFIX) ? errText.substring(EITHER_PREFIX.length) : itemize(errText);
534
585
  }
535
586
  function either(...decoders) {
536
587
  if (decoders.length === 0) {
@@ -561,27 +612,45 @@ function oneOf(constants) {
561
612
  );
562
613
  });
563
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
+ }
564
626
  function taggedUnion(field, mapping2) {
565
- const base = object2({
627
+ const scout = object({
566
628
  [field]: prep(String, oneOf(Object.keys(mapping2)))
567
629
  }).transform((o) => o[field]);
568
- return base.peek_UNSTABLE(([blob, key]) => {
569
- const decoder = mapping2[key];
630
+ return select(
631
+ scout,
632
+ // peek...
633
+ (key) => mapping2[key]
634
+ // ...then select
635
+ );
636
+ }
637
+ function select(scout, selectFn) {
638
+ return scout.peek(([blob, peekResult]) => {
639
+ const decoder = selectFn(peekResult);
570
640
  return decoder.decode(blob);
571
641
  });
572
642
  }
573
643
 
574
- // src/lib/basics.ts
575
- var null_ = define(
576
- (blob, ok2, err2) => blob === null ? ok2(blob) : err2("Must be null")
577
- );
578
- var undefined_ = define(
579
- (blob, ok2, err2) => blob === void 0 ? ok2(blob) : err2("Must be undefined")
580
- );
581
- var undefined_or_null = define(
582
- (blob, ok2, err2) => blob === void 0 || blob === null ? ok2(blob) : (
583
- // Combine error message into a single line for readability
584
- err2("Must be undefined or null")
644
+ // src/basics.ts
645
+ function lazyval(value) {
646
+ return typeof value === "function" ? value() : value;
647
+ }
648
+ var null_ = constant(null);
649
+ var undefined_ = constant(void 0);
650
+ var nullish_ = define(
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")
585
654
  )
586
655
  );
587
656
  function optional(decoder, defaultValue) {
@@ -592,13 +661,16 @@ function nullable(decoder, defaultValue) {
592
661
  const rv = either(null_, decoder);
593
662
  return arguments.length >= 2 ? rv.transform((value) => _nullishCoalesce(value, () => ( lazyval(defaultValue)))) : rv;
594
663
  }
595
- function maybe(decoder, defaultValue) {
596
- const rv = either(undefined_or_null, decoder);
664
+ var maybe = nullish;
665
+ function nullish(decoder, defaultValue) {
666
+ const rv = either(nullish_, decoder);
597
667
  return arguments.length >= 2 ? rv.transform((value) => _nullishCoalesce(value, () => ( lazyval(defaultValue)))) : rv;
598
668
  }
599
669
  function constant(value) {
600
670
  return define(
601
- (blob, ok2, err2) => blob === value ? ok2(value) : err2(`Must be constant ${String(value)}`)
671
+ (blob, ok2, err2) => blob === value ? ok2(value) : err2(
672
+ `Must be ${typeof value === "symbol" ? String(value) : JSON.stringify(value)}`
673
+ )
602
674
  );
603
675
  }
604
676
  function always(value) {
@@ -606,77 +678,17 @@ function always(value) {
606
678
  typeof value === "function" ? (_, ok2) => ok2(value()) : (_, ok2) => ok2(value)
607
679
  );
608
680
  }
609
- var hardcoded = always;
610
- var unknown2 = define((blob, ok2, _) => ok2(blob));
611
- var mixed = unknown2;
612
-
613
- // src/lib/arrays.ts
614
- var poja = define((blob, ok2, err2) => {
615
- if (!Array.isArray(blob)) {
616
- return err2("Must be an array");
617
- }
618
- return ok2(blob);
619
- });
620
- function all(items, blobs, ok2, err2) {
621
- const results = [];
622
- for (let index = 0; index < items.length; ++index) {
623
- const result = items[index];
624
- if (result.ok) {
625
- results.push(result.value);
626
- } else {
627
- const ann = result.error;
628
- const clone = blobs.slice();
629
- clone.splice(
630
- index,
631
- 1,
632
- public_annotate(ann, ann.text ? `${ann.text} (at index ${index})` : `index ${index}`)
633
- );
634
- return err2(public_annotate(clone));
635
- }
636
- }
637
- return ok2(results);
638
- }
639
- function array2(decoder) {
640
- const decodeFn = decoder.decode;
641
- return poja.then((blobs, ok2, err2) => {
642
- const results = blobs.map(decodeFn);
643
- return all(results, blobs, ok2, err2);
644
- });
645
- }
646
- function isNonEmpty(arr) {
647
- return arr.length > 0;
648
- }
649
- function nonEmptyArray(decoder) {
650
- return array2(decoder).refine(isNonEmpty, "Must be non-empty array");
651
- }
652
- function set(decoder) {
653
- return array2(decoder).transform((items) => new Set(items));
654
- }
655
- var ntuple = (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
656
- function tuple(...decoders) {
657
- return ntuple(decoders.length).then((blobs, ok2, err2) => {
658
- let allOk = true;
659
- const rvs = decoders.map((decoder, i) => {
660
- const blob = blobs[i];
661
- const result = decoder.decode(blob);
662
- if (result.ok) {
663
- return result.value;
664
- } else {
665
- allOk = false;
666
- return result.error;
667
- }
668
- });
669
- if (allOk) {
670
- return ok2(rvs);
671
- } else {
672
- return err2(public_annotate(rvs));
673
- }
674
- });
681
+ function never(msg) {
682
+ return define((_, __, err2) => err2(msg));
675
683
  }
684
+ var fail = never;
685
+ var hardcoded = always;
686
+ var unknown = define((blob, ok2, _) => ok2(blob));
687
+ var mixed = unknown;
676
688
 
677
- // src/lib/numbers.ts
689
+ // src/numbers.ts
678
690
  var anyNumber = define(
679
- (blob, ok2, err2) => typeof blob === "number" ? ok2(blob) : err2("Must be number")
691
+ (blob, ok2, err2) => isNumber(blob) ? ok2(blob) : err2("Must be number")
680
692
  );
681
693
  var number = anyNumber.refine(
682
694
  (n) => Number.isFinite(n),
@@ -688,18 +700,21 @@ var integer = number.refine(
688
700
  );
689
701
  var positiveNumber = number.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
690
702
  var positiveInteger = integer.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
703
+ var bigint = define(
704
+ (blob, ok2, err2) => isBigInt(blob) ? ok2(blob) : err2("Must be bigint")
705
+ );
691
706
 
692
- // src/lib/booleans.ts
707
+ // src/booleans.ts
693
708
  var boolean = define((blob, ok2, err2) => {
694
709
  return typeof blob === "boolean" ? ok2(blob) : err2("Must be boolean");
695
710
  });
696
711
  var truthy = define((blob, ok2, _) => ok2(!!blob));
697
712
  var numericBoolean = number.transform((n) => !!n);
698
713
 
699
- // src/lib/strings.ts
714
+ // src/strings.ts
700
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]*)?)?$/;
701
716
  var string = define(
702
- (blob, ok2, err2) => typeof blob === "string" ? ok2(blob) : err2("Must be string")
717
+ (blob, ok2, err2) => isString(blob) ? ok2(blob) : err2("Must be string")
703
718
  );
704
719
  var nonEmptyString = regex(/\S/, "Must be non-empty string");
705
720
  function regex(regex2, msg) {
@@ -730,12 +745,17 @@ var uuidv4 = (
730
745
  // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
731
746
  uuid.refine((value) => value[14] === "4", "Must be uuidv4")
732
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);
733
754
 
734
- // src/lib/dates.ts
755
+ // src/dates.ts
735
756
  var iso8601_re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
736
757
  var date = define((blob, ok2, err2) => {
737
- const date2 = asDate(blob);
738
- return date2 !== null ? ok2(date2) : err2("Must be a Date");
758
+ return isDate(blob) ? ok2(blob) : err2("Must be a Date");
739
759
  });
740
760
  var iso8601 = (
741
761
  // Input itself needs to match the ISO8601 regex...
@@ -751,9 +771,9 @@ var iso8601 = (
751
771
  )
752
772
  );
753
773
 
754
- // src/lib/json.ts
755
- var jsonObject = lazy(() => dict(json));
756
- var jsonArray = lazy(() => array2(json));
774
+ // src/json.ts
775
+ var jsonObject = lazy(() => record(json));
776
+ var jsonArray = lazy(() => array(json));
757
777
  var json = either(
758
778
  null_,
759
779
  string,
@@ -819,5 +839,12 @@ var json = either(
819
839
 
820
840
 
821
841
 
822
- exports.always = always; exports.anyNumber = anyNumber; exports.array = array2; exports.boolean = boolean; exports.constant = constant; exports.date = date; exports.define = define; exports.dict = dict; exports.either = either; exports.email = email; exports.err = err; exports.exact = exact; exports.fail = fail; exports.formatInline = formatInline; exports.formatShort = formatShort; exports.hardcoded = hardcoded; 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.number = number; exports.numericBoolean = numericBoolean; exports.object = object2; 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.regex = regex; exports.set = set; exports.string = string; exports.taggedUnion = taggedUnion; exports.truthy = truthy; exports.tuple = tuple; exports.undefined_ = undefined_; exports.unknown = unknown2; exports.url = url; exports.uuid = uuid; exports.uuidv1 = uuidv1; exports.uuidv4 = uuidv4;
823
- //# sourceMappingURL=index.cjs.map
842
+
843
+
844
+
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;