decoders 2.2.0 → 2.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +263 -270
- package/dist/index.d.cts +208 -181
- package/dist/index.d.ts +208 -181
- package/dist/index.js +265 -272
- package/package.json +5 -3
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,110 +1,36 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return typeof value === "function" ? value() : value;
|
|
5
|
-
}
|
|
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;
|
|
14
|
-
}
|
|
15
|
-
function asDate(value) {
|
|
16
|
-
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value) ? value : null;
|
|
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
|
|
2
|
+
function isDate(value) {
|
|
3
|
+
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
|
|
17
4
|
}
|
|
18
5
|
function isPojo(value) {
|
|
19
6
|
return value !== null && value !== void 0 && typeof value === "object" && // This still seems to be the only reliable way to determine whether
|
|
20
7
|
// something is a pojo... ¯\_(ツ)_/¯
|
|
21
8
|
Object.prototype.toString.call(value) === "[object Object]";
|
|
22
9
|
}
|
|
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
10
|
|
|
67
|
-
// src/annotate.ts
|
|
11
|
+
// src/core/annotate.ts
|
|
68
12
|
var _register = /* @__PURE__ */ new WeakSet();
|
|
69
13
|
function brand(ann) {
|
|
70
14
|
_register.add(ann);
|
|
71
15
|
return ann;
|
|
72
16
|
}
|
|
73
|
-
function
|
|
17
|
+
function makeObjectAnn(fields, text) {
|
|
74
18
|
return brand({ type: "object", fields, text });
|
|
75
19
|
}
|
|
76
|
-
function
|
|
77
|
-
return brand({
|
|
78
|
-
type: "array",
|
|
79
|
-
items,
|
|
80
|
-
text
|
|
81
|
-
});
|
|
20
|
+
function makeArrayAnn(items, text) {
|
|
21
|
+
return brand({ type: "array", items, text });
|
|
82
22
|
}
|
|
83
|
-
function
|
|
84
|
-
return brand({
|
|
85
|
-
type: "function",
|
|
86
|
-
text
|
|
87
|
-
});
|
|
23
|
+
function makeFunctionAnn(text) {
|
|
24
|
+
return brand({ type: "function", text });
|
|
88
25
|
}
|
|
89
|
-
function
|
|
90
|
-
return brand({
|
|
91
|
-
type: "unknown",
|
|
92
|
-
value,
|
|
93
|
-
text
|
|
94
|
-
});
|
|
26
|
+
function makeUnknownAnn(value, text) {
|
|
27
|
+
return brand({ type: "unknown", value, text });
|
|
95
28
|
}
|
|
96
|
-
function
|
|
97
|
-
return brand({
|
|
98
|
-
type: "scalar",
|
|
99
|
-
value,
|
|
100
|
-
text
|
|
101
|
-
});
|
|
29
|
+
function makeScalarAnn(value, text) {
|
|
30
|
+
return brand({ type: "scalar", value, text });
|
|
102
31
|
}
|
|
103
|
-
function
|
|
104
|
-
return brand({
|
|
105
|
-
type: "circular-ref",
|
|
106
|
-
text
|
|
107
|
-
});
|
|
32
|
+
function makeCircularRefAnn(text) {
|
|
33
|
+
return brand({ type: "circular-ref", text });
|
|
108
34
|
}
|
|
109
35
|
function updateText(annotation, text) {
|
|
110
36
|
if (text !== void 0) {
|
|
@@ -114,52 +40,53 @@ function updateText(annotation, text) {
|
|
|
114
40
|
}
|
|
115
41
|
}
|
|
116
42
|
function merge(objAnnotation, fields) {
|
|
117
|
-
const newFields =
|
|
118
|
-
return
|
|
43
|
+
const newFields = new Map([...objAnnotation.fields, ...fields]);
|
|
44
|
+
return makeObjectAnn(newFields, objAnnotation.text);
|
|
119
45
|
}
|
|
120
|
-
function
|
|
121
|
-
return
|
|
46
|
+
function isAnnotation(thing) {
|
|
47
|
+
return _register.has(thing);
|
|
122
48
|
}
|
|
123
|
-
function annotateArray(
|
|
124
|
-
seen.add(
|
|
125
|
-
const items =
|
|
126
|
-
|
|
49
|
+
function annotateArray(arr, text, seen) {
|
|
50
|
+
seen.add(arr);
|
|
51
|
+
const items = [];
|
|
52
|
+
for (const value of arr) {
|
|
53
|
+
items.push(annotate(value, void 0, seen));
|
|
54
|
+
}
|
|
55
|
+
return makeArrayAnn(items, text);
|
|
127
56
|
}
|
|
128
57
|
function annotateObject(obj, text, seen) {
|
|
129
58
|
seen.add(obj);
|
|
130
|
-
const fields =
|
|
131
|
-
for (const key of Object.
|
|
132
|
-
|
|
133
|
-
fields[key] = annotate(value, void 0, seen);
|
|
59
|
+
const fields = /* @__PURE__ */ new Map();
|
|
60
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
61
|
+
fields.set(key, annotate(value, void 0, seen));
|
|
134
62
|
}
|
|
135
|
-
return
|
|
63
|
+
return makeObjectAnn(fields, text);
|
|
136
64
|
}
|
|
137
65
|
function annotate(value, text, seen) {
|
|
138
66
|
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "symbol" || typeof value.getMonth === "function") {
|
|
139
|
-
return
|
|
67
|
+
return makeScalarAnn(value, text);
|
|
140
68
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return updateText(ann, text);
|
|
69
|
+
if (isAnnotation(value)) {
|
|
70
|
+
return updateText(value, text);
|
|
144
71
|
}
|
|
145
72
|
if (Array.isArray(value)) {
|
|
146
73
|
if (seen.has(value)) {
|
|
147
|
-
return
|
|
74
|
+
return makeCircularRefAnn(text);
|
|
148
75
|
} else {
|
|
149
76
|
return annotateArray(value, text, seen);
|
|
150
77
|
}
|
|
151
78
|
}
|
|
152
79
|
if (isPojo(value)) {
|
|
153
80
|
if (seen.has(value)) {
|
|
154
|
-
return
|
|
81
|
+
return makeCircularRefAnn(text);
|
|
155
82
|
} else {
|
|
156
83
|
return annotateObject(value, text, seen);
|
|
157
84
|
}
|
|
158
85
|
}
|
|
159
86
|
if (typeof value === "function") {
|
|
160
|
-
return
|
|
87
|
+
return makeFunctionAnn(text);
|
|
161
88
|
}
|
|
162
|
-
return
|
|
89
|
+
return makeUnknownAnn(value, text);
|
|
163
90
|
}
|
|
164
91
|
function public_annotate(value, text) {
|
|
165
92
|
return annotate(value, text, /* @__PURE__ */ new WeakSet());
|
|
@@ -168,7 +95,52 @@ function public_annotateObject(obj, text) {
|
|
|
168
95
|
return annotateObject(obj, text, /* @__PURE__ */ new WeakSet());
|
|
169
96
|
}
|
|
170
97
|
|
|
171
|
-
// src/
|
|
98
|
+
// src/lib/text.ts
|
|
99
|
+
var INDENT = " ";
|
|
100
|
+
function isMultiline(s) {
|
|
101
|
+
return s.indexOf("\n") >= 0;
|
|
102
|
+
}
|
|
103
|
+
function indent(s, prefix = INDENT) {
|
|
104
|
+
if (isMultiline(s)) {
|
|
105
|
+
return s.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
106
|
+
} else {
|
|
107
|
+
return `${prefix}${s}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/core/format.ts
|
|
112
|
+
function summarize(ann, keypath = []) {
|
|
113
|
+
const result = [];
|
|
114
|
+
if (ann.type === "array") {
|
|
115
|
+
const items = ann.items;
|
|
116
|
+
let index = 0;
|
|
117
|
+
for (const ann2 of items) {
|
|
118
|
+
for (const item of summarize(ann2, [...keypath, index++])) {
|
|
119
|
+
result.push(item);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} else if (ann.type === "object") {
|
|
123
|
+
const fields = ann.fields;
|
|
124
|
+
for (const [key, value] of fields) {
|
|
125
|
+
for (const item of summarize(value, [...keypath, key])) {
|
|
126
|
+
result.push(item);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const text = ann.text;
|
|
131
|
+
if (!text) {
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
let prefix;
|
|
135
|
+
if (keypath.length === 0) {
|
|
136
|
+
prefix = "";
|
|
137
|
+
} else if (keypath.length === 1) {
|
|
138
|
+
prefix = typeof keypath[0] === "number" ? `Value at index ${keypath[0]}: ` : `Value at key ${JSON.stringify(keypath[0])}: `;
|
|
139
|
+
} else {
|
|
140
|
+
prefix = `Value at keypath ${keypath.map(String).join(".")}: `;
|
|
141
|
+
}
|
|
142
|
+
return [...result, `${prefix}${text}`];
|
|
143
|
+
}
|
|
172
144
|
function serializeString(s, width = 80) {
|
|
173
145
|
let ser = JSON.stringify(s);
|
|
174
146
|
if (ser.length <= width) {
|
|
@@ -195,13 +167,11 @@ function serializeArray(annotation, prefix) {
|
|
|
195
167
|
}
|
|
196
168
|
function serializeObject(annotation, prefix) {
|
|
197
169
|
const { fields } = annotation;
|
|
198
|
-
|
|
199
|
-
if (fieldNames.length === 0) {
|
|
170
|
+
if (fields.size === 0) {
|
|
200
171
|
return "{}";
|
|
201
172
|
}
|
|
202
173
|
const result = [];
|
|
203
|
-
for (const key of
|
|
204
|
-
const valueAnnotation = fields[key];
|
|
174
|
+
for (const [key, valueAnnotation] of fields) {
|
|
205
175
|
const kser = serializeValue(key);
|
|
206
176
|
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
|
|
207
177
|
const [vser, vann] = serializeAnnotation(valueAnnotation, `${prefix}${INDENT}`);
|
|
@@ -215,16 +185,15 @@ function serializeObject(annotation, prefix) {
|
|
|
215
185
|
function serializeValue(value) {
|
|
216
186
|
if (typeof value === "string") {
|
|
217
187
|
return serializeString(value);
|
|
218
|
-
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
188
|
+
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "symbol") {
|
|
219
189
|
return value.toString();
|
|
220
190
|
} else if (value === null) {
|
|
221
191
|
return "null";
|
|
222
192
|
} else if (value === void 0) {
|
|
223
193
|
return "undefined";
|
|
224
194
|
} else {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return `new Date(${JSON.stringify(valueAsDate.toISOString())})`;
|
|
195
|
+
if (isDate(value)) {
|
|
196
|
+
return `new Date(${JSON.stringify(value.toISOString())})`;
|
|
228
197
|
} else if (value instanceof Date) {
|
|
229
198
|
return "(Invalid Date)";
|
|
230
199
|
} else {
|
|
@@ -268,7 +237,7 @@ function formatShort(ann) {
|
|
|
268
237
|
return summarize(ann, []).join("\n");
|
|
269
238
|
}
|
|
270
239
|
|
|
271
|
-
// src/
|
|
240
|
+
// src/core/Result.ts
|
|
272
241
|
function ok(value) {
|
|
273
242
|
return { ok: true, value, error: void 0 };
|
|
274
243
|
}
|
|
@@ -276,7 +245,7 @@ function err(error) {
|
|
|
276
245
|
return { ok: false, value: void 0, error };
|
|
277
246
|
}
|
|
278
247
|
|
|
279
|
-
// src/Decoder.ts
|
|
248
|
+
// src/core/Decoder.ts
|
|
280
249
|
function noThrow(fn) {
|
|
281
250
|
return (t) => {
|
|
282
251
|
try {
|
|
@@ -303,7 +272,7 @@ function define(fn) {
|
|
|
303
272
|
return fn(
|
|
304
273
|
blob,
|
|
305
274
|
ok,
|
|
306
|
-
(msg) => err(
|
|
275
|
+
(msg) => err(isAnnotation(msg) ? msg : public_annotate(blob, msg))
|
|
307
276
|
);
|
|
308
277
|
}
|
|
309
278
|
function verify(blob, formatter = formatInline) {
|
|
@@ -338,9 +307,9 @@ function define(fn) {
|
|
|
338
307
|
});
|
|
339
308
|
}
|
|
340
309
|
function reject(rejectFn) {
|
|
341
|
-
return then((
|
|
342
|
-
const errmsg = rejectFn(
|
|
343
|
-
return errmsg === null ? ok2(
|
|
310
|
+
return then((blob, ok2, err2) => {
|
|
311
|
+
const errmsg = rejectFn(blob);
|
|
312
|
+
return errmsg === null ? ok2(blob) : err2(typeof errmsg === "string" ? public_annotate(blob, errmsg) : errmsg);
|
|
344
313
|
});
|
|
345
314
|
}
|
|
346
315
|
function describe(message) {
|
|
@@ -353,7 +322,7 @@ function define(fn) {
|
|
|
353
322
|
}
|
|
354
323
|
});
|
|
355
324
|
}
|
|
356
|
-
function
|
|
325
|
+
function peek(next) {
|
|
357
326
|
return define((blob, ok2, err2) => {
|
|
358
327
|
const result = decode(blob);
|
|
359
328
|
return result.ok ? next([blob, result.value], ok2, err2) : result;
|
|
@@ -368,24 +337,126 @@ function define(fn) {
|
|
|
368
337
|
reject,
|
|
369
338
|
describe,
|
|
370
339
|
then,
|
|
371
|
-
|
|
372
|
-
peek_UNSTABLE
|
|
340
|
+
peek
|
|
373
341
|
});
|
|
374
342
|
}
|
|
375
343
|
|
|
376
|
-
// src/
|
|
344
|
+
// src/arrays.ts
|
|
345
|
+
var poja = define((blob, ok2, err2) => {
|
|
346
|
+
if (!Array.isArray(blob)) {
|
|
347
|
+
return err2("Must be an array");
|
|
348
|
+
}
|
|
349
|
+
return ok2(blob);
|
|
350
|
+
});
|
|
351
|
+
function all(items, blobs, ok2, err2) {
|
|
352
|
+
const results = [];
|
|
353
|
+
for (let index = 0; index < items.length; ++index) {
|
|
354
|
+
const result = items[index];
|
|
355
|
+
if (result.ok) {
|
|
356
|
+
results.push(result.value);
|
|
357
|
+
} else {
|
|
358
|
+
const ann = result.error;
|
|
359
|
+
const clone = blobs.slice();
|
|
360
|
+
clone.splice(
|
|
361
|
+
index,
|
|
362
|
+
1,
|
|
363
|
+
public_annotate(ann, ann.text ? `${ann.text} (at index ${index})` : `index ${index}`)
|
|
364
|
+
);
|
|
365
|
+
return err2(public_annotate(clone));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return ok2(results);
|
|
369
|
+
}
|
|
370
|
+
function array(decoder) {
|
|
371
|
+
const decodeFn = decoder.decode;
|
|
372
|
+
return poja.then((blobs, ok2, err2) => {
|
|
373
|
+
const results = blobs.map(decodeFn);
|
|
374
|
+
return all(results, blobs, ok2, err2);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
function isNonEmpty(arr) {
|
|
378
|
+
return arr.length > 0;
|
|
379
|
+
}
|
|
380
|
+
function nonEmptyArray(decoder) {
|
|
381
|
+
return array(decoder).refine(isNonEmpty, "Must be non-empty array");
|
|
382
|
+
}
|
|
383
|
+
function set(decoder) {
|
|
384
|
+
return array(decoder).transform((items) => new Set(items));
|
|
385
|
+
}
|
|
386
|
+
var ntuple = (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
|
|
387
|
+
function tuple(...decoders) {
|
|
388
|
+
return ntuple(decoders.length).then((blobs, ok2, err2) => {
|
|
389
|
+
let allOk = true;
|
|
390
|
+
const rvs = decoders.map((decoder, i) => {
|
|
391
|
+
const blob = blobs[i];
|
|
392
|
+
const result = decoder.decode(blob);
|
|
393
|
+
if (result.ok) {
|
|
394
|
+
return result.value;
|
|
395
|
+
} else {
|
|
396
|
+
allOk = false;
|
|
397
|
+
return result.error;
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
if (allOk) {
|
|
401
|
+
return ok2(rvs);
|
|
402
|
+
} else {
|
|
403
|
+
return err2(public_annotate(rvs));
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/misc.ts
|
|
409
|
+
function instanceOf(klass) {
|
|
410
|
+
return define(
|
|
411
|
+
(blob, ok2, err2) => blob instanceof klass ? ok2(blob) : err2(`Must be ${klass.name} instance`)
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
function lazy(decoderFn) {
|
|
415
|
+
return define((blob) => decoderFn().decode(blob));
|
|
416
|
+
}
|
|
417
|
+
function prep(mapperFn, decoder) {
|
|
418
|
+
return define((originalInput, _, err2) => {
|
|
419
|
+
let blob;
|
|
420
|
+
try {
|
|
421
|
+
blob = mapperFn(originalInput);
|
|
422
|
+
} catch (e) {
|
|
423
|
+
return err2(
|
|
424
|
+
public_annotate(
|
|
425
|
+
originalInput,
|
|
426
|
+
// istanbul ignore next
|
|
427
|
+
e instanceof Error ? e.message : String(e)
|
|
428
|
+
)
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
const r = decoder.decode(blob);
|
|
432
|
+
return r.ok ? r : err2(public_annotate(originalInput, r.error.text));
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/lib/set-methods.ts
|
|
437
|
+
function difference(xs, ys) {
|
|
438
|
+
const result = /* @__PURE__ */ new Set();
|
|
439
|
+
for (const x of xs) {
|
|
440
|
+
if (!ys.has(x)) {
|
|
441
|
+
result.add(x);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/objects.ts
|
|
377
448
|
var pojo = define(
|
|
378
449
|
(blob, ok2, err2) => isPojo(blob) ? ok2(blob) : err2("Must be an object")
|
|
379
450
|
);
|
|
380
|
-
function
|
|
381
|
-
const knownKeys = new Set(Object.keys(
|
|
451
|
+
function object(decoders) {
|
|
452
|
+
const knownKeys = new Set(Object.keys(decoders));
|
|
382
453
|
return pojo.then((plainObj, ok2, err2) => {
|
|
383
454
|
const actualKeys = new Set(Object.keys(plainObj));
|
|
384
|
-
const missingKeys =
|
|
455
|
+
const missingKeys = difference(knownKeys, actualKeys);
|
|
385
456
|
const record = {};
|
|
386
457
|
let errors = null;
|
|
387
|
-
for (const key of Object.keys(
|
|
388
|
-
const decoder =
|
|
458
|
+
for (const key of Object.keys(decoders)) {
|
|
459
|
+
const decoder = decoders[key];
|
|
389
460
|
const rawValue = plainObj[key];
|
|
390
461
|
const result = decoder.decode(rawValue);
|
|
391
462
|
if (result.ok) {
|
|
@@ -400,9 +471,9 @@ function object2(decodersByKey) {
|
|
|
400
471
|
missingKeys.add(key);
|
|
401
472
|
} else {
|
|
402
473
|
if (errors === null) {
|
|
403
|
-
errors =
|
|
474
|
+
errors = /* @__PURE__ */ new Map();
|
|
404
475
|
}
|
|
405
|
-
errors
|
|
476
|
+
errors.set(key, ann);
|
|
406
477
|
}
|
|
407
478
|
}
|
|
408
479
|
}
|
|
@@ -421,23 +492,23 @@ function object2(decodersByKey) {
|
|
|
421
492
|
return ok2(record);
|
|
422
493
|
});
|
|
423
494
|
}
|
|
424
|
-
function exact(
|
|
425
|
-
const allowedKeys = new Set(Object.keys(
|
|
495
|
+
function exact(decoders) {
|
|
496
|
+
const allowedKeys = new Set(Object.keys(decoders));
|
|
426
497
|
const checked = pojo.reject((plainObj) => {
|
|
427
498
|
const actualKeys = new Set(Object.keys(plainObj));
|
|
428
|
-
const extraKeys =
|
|
499
|
+
const extraKeys = difference(actualKeys, allowedKeys);
|
|
429
500
|
return extraKeys.size > 0 ? `Unexpected extra keys: ${Array.from(extraKeys).join(", ")}` : (
|
|
430
501
|
// Don't reject
|
|
431
502
|
null
|
|
432
503
|
);
|
|
433
504
|
});
|
|
434
|
-
return checked.then(
|
|
505
|
+
return checked.then(object(decoders).decode);
|
|
435
506
|
}
|
|
436
|
-
function inexact(
|
|
507
|
+
function inexact(decoders) {
|
|
437
508
|
return pojo.then((plainObj) => {
|
|
438
509
|
const allkeys = new Set(Object.keys(plainObj));
|
|
439
|
-
const decoder =
|
|
440
|
-
const safekeys = new Set(Object.keys(
|
|
510
|
+
const decoder = object(decoders).transform((safepart) => {
|
|
511
|
+
const safekeys = new Set(Object.keys(decoders));
|
|
441
512
|
for (const k of safekeys)
|
|
442
513
|
allkeys.add(k);
|
|
443
514
|
const rv = {};
|
|
@@ -470,9 +541,9 @@ function dict(decoder) {
|
|
|
470
541
|
} else {
|
|
471
542
|
rv = {};
|
|
472
543
|
if (errors === null) {
|
|
473
|
-
errors =
|
|
544
|
+
errors = /* @__PURE__ */ new Map();
|
|
474
545
|
}
|
|
475
|
-
errors
|
|
546
|
+
errors.set(key, result.error);
|
|
476
547
|
}
|
|
477
548
|
}
|
|
478
549
|
if (errors !== null) {
|
|
@@ -492,45 +563,13 @@ function mapping(decoder) {
|
|
|
492
563
|
);
|
|
493
564
|
}
|
|
494
565
|
|
|
495
|
-
// src/
|
|
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
|
-
});
|
|
521
|
-
}
|
|
522
|
-
function never(msg) {
|
|
523
|
-
return define((_, __, err2) => err2(msg));
|
|
524
|
-
}
|
|
525
|
-
var fail = never;
|
|
526
|
-
|
|
527
|
-
// src/lib/unions.ts
|
|
566
|
+
// src/unions.ts
|
|
528
567
|
var EITHER_PREFIX = "Either:\n";
|
|
529
568
|
function itemize(s) {
|
|
530
569
|
return `-${indent(s).substring(1)}`;
|
|
531
570
|
}
|
|
532
571
|
function nest(errText) {
|
|
533
|
-
return errText.startsWith(EITHER_PREFIX) ? errText.
|
|
572
|
+
return errText.startsWith(EITHER_PREFIX) ? errText.substring(EITHER_PREFIX.length) : itemize(errText);
|
|
534
573
|
}
|
|
535
574
|
function either(...decoders) {
|
|
536
575
|
if (decoders.length === 0) {
|
|
@@ -562,24 +601,31 @@ function oneOf(constants) {
|
|
|
562
601
|
});
|
|
563
602
|
}
|
|
564
603
|
function taggedUnion(field, mapping2) {
|
|
565
|
-
const
|
|
604
|
+
const scout = object({
|
|
566
605
|
[field]: prep(String, oneOf(Object.keys(mapping2)))
|
|
567
606
|
}).transform((o) => o[field]);
|
|
568
|
-
return
|
|
569
|
-
|
|
607
|
+
return select(
|
|
608
|
+
scout,
|
|
609
|
+
// peek...
|
|
610
|
+
(key) => mapping2[key]
|
|
611
|
+
// ...then select
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
function select(scout, selectFn) {
|
|
615
|
+
return scout.peek(([blob, peekResult]) => {
|
|
616
|
+
const decoder = selectFn(peekResult);
|
|
570
617
|
return decoder.decode(blob);
|
|
571
618
|
});
|
|
572
619
|
}
|
|
573
620
|
|
|
574
|
-
// src/
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
var
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
(blob, ok2, err2) => blob === void 0 || blob === null ? ok2(blob) : (
|
|
621
|
+
// src/basics.ts
|
|
622
|
+
function lazyval(value) {
|
|
623
|
+
return typeof value === "function" ? value() : value;
|
|
624
|
+
}
|
|
625
|
+
var null_ = constant(null);
|
|
626
|
+
var undefined_ = constant(void 0);
|
|
627
|
+
var nullish_ = define(
|
|
628
|
+
(blob, ok2, err2) => blob == null ? ok2(blob) : (
|
|
583
629
|
// Combine error message into a single line for readability
|
|
584
630
|
err2("Must be undefined or null")
|
|
585
631
|
)
|
|
@@ -592,13 +638,16 @@ function nullable(decoder, defaultValue) {
|
|
|
592
638
|
const rv = either(null_, decoder);
|
|
593
639
|
return arguments.length >= 2 ? rv.transform((value) => _nullishCoalesce(value, () => ( lazyval(defaultValue)))) : rv;
|
|
594
640
|
}
|
|
595
|
-
|
|
596
|
-
|
|
641
|
+
var maybe = nullish;
|
|
642
|
+
function nullish(decoder, defaultValue) {
|
|
643
|
+
const rv = either(nullish_, decoder);
|
|
597
644
|
return arguments.length >= 2 ? rv.transform((value) => _nullishCoalesce(value, () => ( lazyval(defaultValue)))) : rv;
|
|
598
645
|
}
|
|
599
646
|
function constant(value) {
|
|
600
647
|
return define(
|
|
601
|
-
(blob, ok2, err2) => blob === value ? ok2(value) : err2(
|
|
648
|
+
(blob, ok2, err2) => blob === value ? ok2(value) : err2(
|
|
649
|
+
`Must be ${typeof value === "symbol" ? String(value) : JSON.stringify(value)}`
|
|
650
|
+
)
|
|
602
651
|
);
|
|
603
652
|
}
|
|
604
653
|
function always(value) {
|
|
@@ -606,75 +655,15 @@ function always(value) {
|
|
|
606
655
|
typeof value === "function" ? (_, ok2) => ok2(value()) : (_, ok2) => ok2(value)
|
|
607
656
|
);
|
|
608
657
|
}
|
|
609
|
-
|
|
610
|
-
|
|
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
|
-
});
|
|
658
|
+
function never(msg) {
|
|
659
|
+
return define((_, __, err2) => err2(msg));
|
|
675
660
|
}
|
|
661
|
+
var fail = never;
|
|
662
|
+
var hardcoded = always;
|
|
663
|
+
var unknown = define((blob, ok2, _) => ok2(blob));
|
|
664
|
+
var mixed = unknown;
|
|
676
665
|
|
|
677
|
-
// src/
|
|
666
|
+
// src/numbers.ts
|
|
678
667
|
var anyNumber = define(
|
|
679
668
|
(blob, ok2, err2) => typeof blob === "number" ? ok2(blob) : err2("Must be number")
|
|
680
669
|
);
|
|
@@ -688,15 +677,18 @@ var integer = number.refine(
|
|
|
688
677
|
);
|
|
689
678
|
var positiveNumber = number.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
690
679
|
var positiveInteger = integer.refine((n) => n >= 0, "Number must be positive").transform(Math.abs);
|
|
680
|
+
var bigint = define(
|
|
681
|
+
(blob, ok2, err2) => typeof blob === "bigint" ? ok2(blob) : err2("Must be bigint")
|
|
682
|
+
);
|
|
691
683
|
|
|
692
|
-
// src/
|
|
684
|
+
// src/booleans.ts
|
|
693
685
|
var boolean = define((blob, ok2, err2) => {
|
|
694
686
|
return typeof blob === "boolean" ? ok2(blob) : err2("Must be boolean");
|
|
695
687
|
});
|
|
696
688
|
var truthy = define((blob, ok2, _) => ok2(!!blob));
|
|
697
689
|
var numericBoolean = number.transform((n) => !!n);
|
|
698
690
|
|
|
699
|
-
// src/
|
|
691
|
+
// src/strings.ts
|
|
700
692
|
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
693
|
var string = define(
|
|
702
694
|
(blob, ok2, err2) => typeof blob === "string" ? ok2(blob) : err2("Must be string")
|
|
@@ -731,11 +723,10 @@ var uuidv4 = (
|
|
|
731
723
|
uuid.refine((value) => value[14] === "4", "Must be uuidv4")
|
|
732
724
|
);
|
|
733
725
|
|
|
734
|
-
// src/
|
|
726
|
+
// src/dates.ts
|
|
735
727
|
var iso8601_re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
|
|
736
728
|
var date = define((blob, ok2, err2) => {
|
|
737
|
-
|
|
738
|
-
return date2 !== null ? ok2(date2) : err2("Must be a Date");
|
|
729
|
+
return isDate(blob) ? ok2(blob) : err2("Must be a Date");
|
|
739
730
|
});
|
|
740
731
|
var iso8601 = (
|
|
741
732
|
// Input itself needs to match the ISO8601 regex...
|
|
@@ -751,9 +742,9 @@ var iso8601 = (
|
|
|
751
742
|
)
|
|
752
743
|
);
|
|
753
744
|
|
|
754
|
-
// src/
|
|
745
|
+
// src/json.ts
|
|
755
746
|
var jsonObject = lazy(() => dict(json));
|
|
756
|
-
var jsonArray = lazy(() =>
|
|
747
|
+
var jsonArray = lazy(() => array(json));
|
|
757
748
|
var json = either(
|
|
758
749
|
null_,
|
|
759
750
|
string,
|
|
@@ -819,5 +810,7 @@ var json = either(
|
|
|
819
810
|
|
|
820
811
|
|
|
821
812
|
|
|
822
|
-
|
|
823
|
-
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
exports.always = always; exports.anyNumber = anyNumber; exports.array = array; exports.bigint = bigint; 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.nullish = nullish; exports.number = number; 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.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;
|