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 +322 -295
- package/dist/index.d.cts +237 -183
- package/dist/index.d.ts +237 -183
- package/dist/index.js +324 -297
- 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,45 @@
|
|
|
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;
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
16
|
-
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value)
|
|
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
|
|
26
|
+
function makeObjectAnn(fields, text) {
|
|
74
27
|
return brand({ type: "object", fields, text });
|
|
75
28
|
}
|
|
76
|
-
function
|
|
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
|
|
84
|
-
return brand({
|
|
85
|
-
type: "function",
|
|
86
|
-
text
|
|
87
|
-
});
|
|
32
|
+
function makeFunctionAnn(text) {
|
|
33
|
+
return brand({ type: "function", text });
|
|
88
34
|
}
|
|
89
|
-
function
|
|
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
|
|
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
|
|
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 =
|
|
118
|
-
return
|
|
52
|
+
const newFields = new Map([...objAnnotation.fields, ...fields]);
|
|
53
|
+
return makeObjectAnn(newFields, objAnnotation.text);
|
|
119
54
|
}
|
|
120
|
-
function
|
|
121
|
-
return
|
|
55
|
+
function isAnnotation(thing) {
|
|
56
|
+
return _register.has(thing);
|
|
122
57
|
}
|
|
123
|
-
function annotateArray(
|
|
124
|
-
seen.add(
|
|
125
|
-
const items =
|
|
126
|
-
|
|
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.
|
|
132
|
-
|
|
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
|
|
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
|
|
76
|
+
return makeScalarAnn(value, text);
|
|
140
77
|
}
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
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
|
|
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
|
|
96
|
+
return makeFunctionAnn(text);
|
|
161
97
|
}
|
|
162
|
-
return
|
|
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/
|
|
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
|
-
|
|
199
|
-
if (fieldNames.length === 0) {
|
|
179
|
+
if (fields.size === 0) {
|
|
200
180
|
return "{}";
|
|
201
181
|
}
|
|
202
182
|
const result = [];
|
|
203
|
-
for (const key of
|
|
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
|
-
|
|
226
|
-
|
|
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/
|
|
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(
|
|
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((
|
|
342
|
-
const errmsg = rejectFn(
|
|
343
|
-
return errmsg === null ? ok2(
|
|
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
|
|
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
|
-
|
|
372
|
-
peek_UNSTABLE
|
|
349
|
+
peek
|
|
373
350
|
});
|
|
374
351
|
}
|
|
375
352
|
|
|
376
|
-
// src/
|
|
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
|
|
381
|
-
const knownKeys = new Set(Object.keys(
|
|
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 =
|
|
385
|
-
const
|
|
464
|
+
const missingKeys = difference(knownKeys, actualKeys);
|
|
465
|
+
const record2 = {};
|
|
386
466
|
let errors = null;
|
|
387
|
-
for (const key of Object.keys(
|
|
388
|
-
const decoder =
|
|
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
|
-
|
|
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
|
|
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(
|
|
501
|
+
return ok2(record2);
|
|
422
502
|
});
|
|
423
503
|
}
|
|
424
|
-
function exact(
|
|
425
|
-
const allowedKeys = new Set(Object.keys(
|
|
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 =
|
|
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(
|
|
514
|
+
return checked.then(object(decoders).decode);
|
|
435
515
|
}
|
|
436
|
-
function inexact(
|
|
516
|
+
function inexact(decoders) {
|
|
437
517
|
return pojo.then((plainObj) => {
|
|
438
518
|
const allkeys = new Set(Object.keys(plainObj));
|
|
439
|
-
const decoder =
|
|
440
|
-
const safekeys = new Set(Object.keys(
|
|
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
|
|
460
|
-
|
|
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
|
-
|
|
463
|
-
for (const key of Object.
|
|
464
|
-
const
|
|
465
|
-
|
|
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 ===
|
|
468
|
-
rv[
|
|
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
|
|
479
|
-
return err2(merge(public_annotateObject(
|
|
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
|
|
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/
|
|
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.
|
|
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
|
|
627
|
+
const scout = object({
|
|
566
628
|
[field]: prep(String, oneOf(Object.keys(mapping2)))
|
|
567
629
|
}).transform((o) => o[field]);
|
|
568
|
-
return
|
|
569
|
-
|
|
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/
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
var
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
596
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
});
|
|
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/
|
|
689
|
+
// src/numbers.ts
|
|
678
690
|
var anyNumber = define(
|
|
679
|
-
(blob, ok2, err2) =>
|
|
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/
|
|
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/
|
|
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) =>
|
|
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/
|
|
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
|
-
|
|
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/
|
|
755
|
-
var jsonObject = lazy(() =>
|
|
756
|
-
var jsonArray = lazy(() =>
|
|
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
|
-
|
|
823
|
-
|
|
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;
|