1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | class StructError extends TypeError {
|
14 | constructor(failure, failures) {
|
15 | let cached;
|
16 | const {
|
17 | message,
|
18 | ...rest
|
19 | } = failure;
|
20 | const {
|
21 | path
|
22 | } = failure;
|
23 | const msg = path.length === 0 ? message : "At path: " + path.join('.') + " -- " + message;
|
24 | super(msg);
|
25 | this.value = void 0;
|
26 | this.key = void 0;
|
27 | this.type = void 0;
|
28 | this.refinement = void 0;
|
29 | this.path = void 0;
|
30 | this.branch = void 0;
|
31 | this.failures = void 0;
|
32 | Object.assign(this, rest);
|
33 | this.name = this.constructor.name;
|
34 |
|
35 | this.failures = () => {
|
36 | var _cached;
|
37 |
|
38 | return (_cached = cached) != null ? _cached : cached = [failure, ...failures()];
|
39 | };
|
40 | }
|
41 |
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | function isIterable(x) {
|
48 | return isObject(x) && typeof x[Symbol.iterator] === 'function';
|
49 | }
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | function isObject(x) {
|
56 | return typeof x === 'object' && x != null;
|
57 | }
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | function isPlainObject(x) {
|
63 | if (Object.prototype.toString.call(x) !== '[object Object]') {
|
64 | return false;
|
65 | }
|
66 |
|
67 | const prototype = Object.getPrototypeOf(x);
|
68 | return prototype === null || prototype === Object.prototype;
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | function print(value) {
|
75 | return typeof value === 'string' ? JSON.stringify(value) : "" + value;
|
76 | }
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | function shiftIterator(input) {
|
83 | const {
|
84 | done,
|
85 | value
|
86 | } = input.next();
|
87 | return done ? undefined : value;
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | function toFailure(result, context, struct, value) {
|
94 | if (result === true) {
|
95 | return;
|
96 | } else if (result === false) {
|
97 | result = {};
|
98 | } else if (typeof result === 'string') {
|
99 | result = {
|
100 | message: result
|
101 | };
|
102 | }
|
103 |
|
104 | const {
|
105 | path,
|
106 | branch
|
107 | } = context;
|
108 | const {
|
109 | type
|
110 | } = struct;
|
111 | const {
|
112 | refinement,
|
113 | message = "Expected a value of type `" + type + "`" + (refinement ? " with refinement `" + refinement + "`" : '') + ", but received: `" + print(value) + "`"
|
114 | } = result;
|
115 | return {
|
116 | value,
|
117 | type,
|
118 | refinement,
|
119 | key: path[path.length - 1],
|
120 | path,
|
121 | branch,
|
122 | ...result,
|
123 | message
|
124 | };
|
125 | }
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | function* toFailures(result, context, struct, value) {
|
131 | if (!isIterable(result)) {
|
132 | result = [result];
|
133 | }
|
134 |
|
135 | for (const r of result) {
|
136 | const failure = toFailure(r, context, struct, value);
|
137 |
|
138 | if (failure) {
|
139 | yield failure;
|
140 | }
|
141 | }
|
142 | }
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | function* run(value, struct, options = {}) {
|
149 | const {
|
150 | path = [],
|
151 | branch = [value],
|
152 | coerce = false,
|
153 | mask = false
|
154 | } = options;
|
155 | const ctx = {
|
156 | path,
|
157 | branch
|
158 | };
|
159 |
|
160 | if (coerce) {
|
161 | value = struct.coercer(value, ctx);
|
162 |
|
163 | if (mask && struct.type !== 'type' && isObject(struct.schema) && isObject(value) && !Array.isArray(value)) {
|
164 | for (const key in value) {
|
165 | if (struct.schema[key] === undefined) {
|
166 | delete value[key];
|
167 | }
|
168 | }
|
169 | }
|
170 | }
|
171 |
|
172 | let valid = true;
|
173 |
|
174 | for (const failure of struct.validator(value, ctx)) {
|
175 | valid = false;
|
176 | yield [failure, undefined];
|
177 | }
|
178 |
|
179 | for (let [k, v, s] of struct.entries(value, ctx)) {
|
180 | const ts = run(v, s, {
|
181 | path: k === undefined ? path : [...path, k],
|
182 | branch: k === undefined ? branch : [...branch, v],
|
183 | coerce,
|
184 | mask
|
185 | });
|
186 |
|
187 | for (const t of ts) {
|
188 | if (t[0]) {
|
189 | valid = false;
|
190 | yield [t[0], undefined];
|
191 | } else if (coerce) {
|
192 | v = t[1];
|
193 |
|
194 | if (k === undefined) {
|
195 | value = v;
|
196 | } else if (value instanceof Map) {
|
197 | value.set(k, v);
|
198 | } else if (value instanceof Set) {
|
199 | value.add(v);
|
200 | } else if (isObject(value)) {
|
201 | value[k] = v;
|
202 | }
|
203 | }
|
204 | }
|
205 | }
|
206 |
|
207 | if (valid) {
|
208 | for (const failure of struct.refiner(value, ctx)) {
|
209 | valid = false;
|
210 | yield [failure, undefined];
|
211 | }
|
212 | }
|
213 |
|
214 | if (valid) {
|
215 | yield [undefined, value];
|
216 | }
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | class Struct {
|
226 | constructor(props) {
|
227 | this.TYPE = void 0;
|
228 | this.type = void 0;
|
229 | this.schema = void 0;
|
230 | this.coercer = void 0;
|
231 | this.validator = void 0;
|
232 | this.refiner = void 0;
|
233 | this.entries = void 0;
|
234 | const {
|
235 | type,
|
236 | schema,
|
237 | validator,
|
238 | refiner,
|
239 | coercer = value => value,
|
240 | entries = function* () {}
|
241 | } = props;
|
242 | this.type = type;
|
243 | this.schema = schema;
|
244 | this.entries = entries;
|
245 | this.coercer = coercer;
|
246 |
|
247 | if (validator) {
|
248 | this.validator = (value, context) => {
|
249 | const result = validator(value, context);
|
250 | return toFailures(result, context, this, value);
|
251 | };
|
252 | } else {
|
253 | this.validator = () => [];
|
254 | }
|
255 |
|
256 | if (refiner) {
|
257 | this.refiner = (value, context) => {
|
258 | const result = refiner(value, context);
|
259 | return toFailures(result, context, this, value);
|
260 | };
|
261 | } else {
|
262 | this.refiner = () => [];
|
263 | }
|
264 | }
|
265 | |
266 |
|
267 |
|
268 |
|
269 |
|
270 | assert(value) {
|
271 | return assert(value, this);
|
272 | }
|
273 | |
274 |
|
275 |
|
276 |
|
277 |
|
278 | create(value) {
|
279 | return create(value, this);
|
280 | }
|
281 | |
282 |
|
283 |
|
284 |
|
285 |
|
286 | is(value) {
|
287 | return is(value, this);
|
288 | }
|
289 | |
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | mask(value) {
|
296 | return mask(value, this);
|
297 | }
|
298 | |
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 | validate(value, options = {}) {
|
309 | return validate(value, this, options);
|
310 | }
|
311 |
|
312 | }
|
313 |
|
314 |
|
315 |
|
316 |
|
317 | function assert(value, struct) {
|
318 | const result = validate(value, struct);
|
319 |
|
320 | if (result[0]) {
|
321 | throw result[0];
|
322 | }
|
323 | }
|
324 |
|
325 |
|
326 |
|
327 |
|
328 | function create(value, struct) {
|
329 | const result = validate(value, struct, {
|
330 | coerce: true
|
331 | });
|
332 |
|
333 | if (result[0]) {
|
334 | throw result[0];
|
335 | } else {
|
336 | return result[1];
|
337 | }
|
338 | }
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | function mask(value, struct) {
|
344 | const result = validate(value, struct, {
|
345 | coerce: true,
|
346 | mask: true
|
347 | });
|
348 |
|
349 | if (result[0]) {
|
350 | throw result[0];
|
351 | } else {
|
352 | return result[1];
|
353 | }
|
354 | }
|
355 |
|
356 |
|
357 |
|
358 |
|
359 | function is(value, struct) {
|
360 | const result = validate(value, struct);
|
361 | return !result[0];
|
362 | }
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 | function validate(value, struct, options = {}) {
|
369 | const tuples = run(value, struct, options);
|
370 | const tuple = shiftIterator(tuples);
|
371 |
|
372 | if (tuple[0]) {
|
373 | const error = new StructError(tuple[0], function* () {
|
374 | for (const t of tuples) {
|
375 | if (t[0]) {
|
376 | yield t[0];
|
377 | }
|
378 | }
|
379 | });
|
380 | return [error, undefined];
|
381 | } else {
|
382 | const v = tuple[1];
|
383 | return [undefined, v];
|
384 | }
|
385 | }
|
386 |
|
387 | function assign(...Structs) {
|
388 | const isType = Structs[0].type === 'type';
|
389 | const schemas = Structs.map(s => s.schema);
|
390 | const schema = Object.assign({}, ...schemas);
|
391 | return isType ? type(schema) : object(schema);
|
392 | }
|
393 |
|
394 |
|
395 |
|
396 |
|
397 | function define(name, validator) {
|
398 | return new Struct({
|
399 | type: name,
|
400 | schema: null,
|
401 | validator
|
402 | });
|
403 | }
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 | function deprecated(struct, log) {
|
410 | return new Struct({ ...struct,
|
411 | refiner: (value, ctx) => value === undefined || struct.refiner(value, ctx),
|
412 |
|
413 | validator(value, ctx) {
|
414 | if (value === undefined) {
|
415 | return true;
|
416 | } else {
|
417 | log(value, ctx);
|
418 | return struct.validator(value, ctx);
|
419 | }
|
420 | }
|
421 |
|
422 | });
|
423 | }
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 | function dynamic(fn) {
|
433 | return new Struct({
|
434 | type: 'dynamic',
|
435 | schema: null,
|
436 |
|
437 | *entries(value, ctx) {
|
438 | const struct = fn(value, ctx);
|
439 | yield* struct.entries(value, ctx);
|
440 | },
|
441 |
|
442 | validator(value, ctx) {
|
443 | const struct = fn(value, ctx);
|
444 | return struct.validator(value, ctx);
|
445 | },
|
446 |
|
447 | coercer(value, ctx) {
|
448 | const struct = fn(value, ctx);
|
449 | return struct.coercer(value, ctx);
|
450 | }
|
451 |
|
452 | });
|
453 | }
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 | function lazy(fn) {
|
464 | let struct;
|
465 | return new Struct({
|
466 | type: 'lazy',
|
467 | schema: null,
|
468 |
|
469 | *entries(value, ctx) {
|
470 | var _struct;
|
471 |
|
472 | (_struct = struct) != null ? _struct : struct = fn();
|
473 | yield* struct.entries(value, ctx);
|
474 | },
|
475 |
|
476 | validator(value, ctx) {
|
477 | var _struct2;
|
478 |
|
479 | (_struct2 = struct) != null ? _struct2 : struct = fn();
|
480 | return struct.validator(value, ctx);
|
481 | },
|
482 |
|
483 | coercer(value, ctx) {
|
484 | var _struct3;
|
485 |
|
486 | (_struct3 = struct) != null ? _struct3 : struct = fn();
|
487 | return struct.coercer(value, ctx);
|
488 | }
|
489 |
|
490 | });
|
491 | }
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 | function omit(struct, keys) {
|
500 | const {
|
501 | schema
|
502 | } = struct;
|
503 | const subschema = { ...schema
|
504 | };
|
505 |
|
506 | for (const key of keys) {
|
507 | delete subschema[key];
|
508 | }
|
509 |
|
510 | return object(subschema);
|
511 | }
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 | function partial(struct) {
|
520 | const schema = struct instanceof Struct ? { ...struct.schema
|
521 | } : { ...struct
|
522 | };
|
523 |
|
524 | for (const key in schema) {
|
525 | schema[key] = optional(schema[key]);
|
526 | }
|
527 |
|
528 | return object(schema);
|
529 | }
|
530 |
|
531 |
|
532 |
|
533 |
|
534 |
|
535 |
|
536 |
|
537 | function pick(struct, keys) {
|
538 | const {
|
539 | schema
|
540 | } = struct;
|
541 | const subschema = {};
|
542 |
|
543 | for (const key of keys) {
|
544 | subschema[key] = schema[key];
|
545 | }
|
546 |
|
547 | return object(subschema);
|
548 | }
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 | function struct(name, validator) {
|
556 | console.warn('superstruct@0.11 - The `struct` helper has been renamed to `define`.');
|
557 | return define(name, validator);
|
558 | }
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 | function any() {
|
565 | return define('any', () => true);
|
566 | }
|
567 | function array(Element) {
|
568 | return new Struct({
|
569 | type: 'array',
|
570 | schema: Element,
|
571 |
|
572 | *entries(value) {
|
573 | if (Element && Array.isArray(value)) {
|
574 | for (const [i, v] of value.entries()) {
|
575 | yield [i, v, Element];
|
576 | }
|
577 | }
|
578 | },
|
579 |
|
580 | coercer(value) {
|
581 | return Array.isArray(value) ? value.slice() : value;
|
582 | },
|
583 |
|
584 | validator(value) {
|
585 | return Array.isArray(value) || "Expected an array value, but received: " + print(value);
|
586 | }
|
587 |
|
588 | });
|
589 | }
|
590 |
|
591 |
|
592 |
|
593 |
|
594 | function bigint() {
|
595 | return define('bigint', value => {
|
596 | return typeof value === 'bigint';
|
597 | });
|
598 | }
|
599 |
|
600 |
|
601 |
|
602 |
|
603 | function boolean() {
|
604 | return define('boolean', value => {
|
605 | return typeof value === 'boolean';
|
606 | });
|
607 | }
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 | function date() {
|
616 | return define('date', value => {
|
617 | return value instanceof Date && !isNaN(value.getTime()) || "Expected a valid `Date` object, but received: " + print(value);
|
618 | });
|
619 | }
|
620 | function enums(values) {
|
621 | const schema = {};
|
622 | const description = values.map(v => print(v)).join();
|
623 |
|
624 | for (const key of values) {
|
625 | schema[key] = key;
|
626 | }
|
627 |
|
628 | return new Struct({
|
629 | type: 'enums',
|
630 | schema,
|
631 |
|
632 | validator(value) {
|
633 | return values.includes(value) || "Expected one of `" + description + "`, but received: " + print(value);
|
634 | }
|
635 |
|
636 | });
|
637 | }
|
638 |
|
639 |
|
640 |
|
641 |
|
642 | function func() {
|
643 | return define('func', value => {
|
644 | return typeof value === 'function' || "Expected a function, but received: " + print(value);
|
645 | });
|
646 | }
|
647 |
|
648 |
|
649 |
|
650 |
|
651 | function instance(Class) {
|
652 | return define('instance', value => {
|
653 | return value instanceof Class || "Expected a `" + Class.name + "` instance, but received: " + print(value);
|
654 | });
|
655 | }
|
656 |
|
657 |
|
658 |
|
659 |
|
660 | function integer() {
|
661 | return define('integer', value => {
|
662 | return typeof value === 'number' && !isNaN(value) && Number.isInteger(value) || "Expected an integer, but received: " + print(value);
|
663 | });
|
664 | }
|
665 |
|
666 |
|
667 |
|
668 |
|
669 | function intersection(Structs) {
|
670 | return new Struct({
|
671 | type: 'intersection',
|
672 | schema: null,
|
673 |
|
674 | *entries(value, ctx) {
|
675 | for (const S of Structs) {
|
676 | yield* S.entries(value, ctx);
|
677 | }
|
678 | },
|
679 |
|
680 | *validator(value, ctx) {
|
681 | for (const S of Structs) {
|
682 | yield* S.validator(value, ctx);
|
683 | }
|
684 | },
|
685 |
|
686 | *refiner(value, ctx) {
|
687 | for (const S of Structs) {
|
688 | yield* S.refiner(value, ctx);
|
689 | }
|
690 | }
|
691 |
|
692 | });
|
693 | }
|
694 | function literal(constant) {
|
695 | const description = print(constant);
|
696 | const t = typeof constant;
|
697 | return new Struct({
|
698 | type: 'literal',
|
699 | schema: t === 'string' || t === 'number' || t === 'boolean' ? constant : null,
|
700 |
|
701 | validator(value) {
|
702 | return value === constant || "Expected the literal `" + description + "`, but received: " + print(value);
|
703 | }
|
704 |
|
705 | });
|
706 | }
|
707 | function map(Key, Value) {
|
708 | return new Struct({
|
709 | type: 'map',
|
710 | schema: null,
|
711 |
|
712 | *entries(value) {
|
713 | if (Key && Value && value instanceof Map) {
|
714 | for (const [k, v] of value.entries()) {
|
715 | yield [k, k, Key];
|
716 | yield [k, v, Value];
|
717 | }
|
718 | }
|
719 | },
|
720 |
|
721 | coercer(value) {
|
722 | return value instanceof Map ? new Map(value) : value;
|
723 | },
|
724 |
|
725 | validator(value) {
|
726 | return value instanceof Map || "Expected a `Map` object, but received: " + print(value);
|
727 | }
|
728 |
|
729 | });
|
730 | }
|
731 |
|
732 |
|
733 |
|
734 |
|
735 | function never() {
|
736 | return define('never', () => false);
|
737 | }
|
738 |
|
739 |
|
740 |
|
741 |
|
742 | function nullable(struct) {
|
743 | return new Struct({ ...struct,
|
744 | validator: (value, ctx) => value === null || struct.validator(value, ctx),
|
745 | refiner: (value, ctx) => value === null || struct.refiner(value, ctx)
|
746 | });
|
747 | }
|
748 |
|
749 |
|
750 |
|
751 |
|
752 | function number() {
|
753 | return define('number', value => {
|
754 | return typeof value === 'number' && !isNaN(value) || "Expected a number, but received: " + print(value);
|
755 | });
|
756 | }
|
757 | function object(schema) {
|
758 | const knowns = schema ? Object.keys(schema) : [];
|
759 | const Never = never();
|
760 | return new Struct({
|
761 | type: 'object',
|
762 | schema: schema ? schema : null,
|
763 |
|
764 | *entries(value) {
|
765 | if (schema && isObject(value)) {
|
766 | const unknowns = new Set(Object.keys(value));
|
767 |
|
768 | for (const key of knowns) {
|
769 | unknowns.delete(key);
|
770 | yield [key, value[key], schema[key]];
|
771 | }
|
772 |
|
773 | for (const key of unknowns) {
|
774 | yield [key, value[key], Never];
|
775 | }
|
776 | }
|
777 | },
|
778 |
|
779 | validator(value) {
|
780 | return isObject(value) || "Expected an object, but received: " + print(value);
|
781 | },
|
782 |
|
783 | coercer(value) {
|
784 | return isObject(value) ? { ...value
|
785 | } : value;
|
786 | }
|
787 |
|
788 | });
|
789 | }
|
790 |
|
791 |
|
792 |
|
793 |
|
794 | function optional(struct) {
|
795 | return new Struct({ ...struct,
|
796 | validator: (value, ctx) => value === undefined || struct.validator(value, ctx),
|
797 | refiner: (value, ctx) => value === undefined || struct.refiner(value, ctx)
|
798 | });
|
799 | }
|
800 |
|
801 |
|
802 |
|
803 |
|
804 |
|
805 |
|
806 |
|
807 | function record(Key, Value) {
|
808 | return new Struct({
|
809 | type: 'record',
|
810 | schema: null,
|
811 |
|
812 | *entries(value) {
|
813 | if (isObject(value)) {
|
814 | for (const k in value) {
|
815 | const v = value[k];
|
816 | yield [k, k, Key];
|
817 | yield [k, v, Value];
|
818 | }
|
819 | }
|
820 | },
|
821 |
|
822 | validator(value) {
|
823 | return isObject(value) || "Expected an object, but received: " + print(value);
|
824 | }
|
825 |
|
826 | });
|
827 | }
|
828 |
|
829 |
|
830 |
|
831 |
|
832 |
|
833 |
|
834 |
|
835 | function regexp() {
|
836 | return define('regexp', value => {
|
837 | return value instanceof RegExp;
|
838 | });
|
839 | }
|
840 | function set(Element) {
|
841 | return new Struct({
|
842 | type: 'set',
|
843 | schema: null,
|
844 |
|
845 | *entries(value) {
|
846 | if (Element && value instanceof Set) {
|
847 | for (const v of value) {
|
848 | yield [v, v, Element];
|
849 | }
|
850 | }
|
851 | },
|
852 |
|
853 | coercer(value) {
|
854 | return value instanceof Set ? new Set(value) : value;
|
855 | },
|
856 |
|
857 | validator(value) {
|
858 | return value instanceof Set || "Expected a `Set` object, but received: " + print(value);
|
859 | }
|
860 |
|
861 | });
|
862 | }
|
863 |
|
864 |
|
865 |
|
866 |
|
867 | function string() {
|
868 | return define('string', value => {
|
869 | return typeof value === 'string' || "Expected a string, but received: " + print(value);
|
870 | });
|
871 | }
|
872 |
|
873 |
|
874 |
|
875 |
|
876 |
|
877 | function tuple(Structs) {
|
878 | const Never = never();
|
879 | return new Struct({
|
880 | type: 'tuple',
|
881 | schema: null,
|
882 |
|
883 | *entries(value) {
|
884 | if (Array.isArray(value)) {
|
885 | const length = Math.max(Structs.length, value.length);
|
886 |
|
887 | for (let i = 0; i < length; i++) {
|
888 | yield [i, value[i], Structs[i] || Never];
|
889 | }
|
890 | }
|
891 | },
|
892 |
|
893 | validator(value) {
|
894 | return Array.isArray(value) || "Expected an array, but received: " + print(value);
|
895 | }
|
896 |
|
897 | });
|
898 | }
|
899 |
|
900 |
|
901 |
|
902 |
|
903 |
|
904 |
|
905 |
|
906 | function type(schema) {
|
907 | const keys = Object.keys(schema);
|
908 | return new Struct({
|
909 | type: 'type',
|
910 | schema,
|
911 |
|
912 | *entries(value) {
|
913 | if (isObject(value)) {
|
914 | for (const k of keys) {
|
915 | yield [k, value[k], schema[k]];
|
916 | }
|
917 | }
|
918 | },
|
919 |
|
920 | validator(value) {
|
921 | return isObject(value) || "Expected an object, but received: " + print(value);
|
922 | }
|
923 |
|
924 | });
|
925 | }
|
926 |
|
927 |
|
928 |
|
929 |
|
930 | function union(Structs) {
|
931 | const description = Structs.map(s => s.type).join(' | ');
|
932 | return new Struct({
|
933 | type: 'union',
|
934 | schema: null,
|
935 |
|
936 | coercer(value, ctx) {
|
937 | const firstMatch = Structs.find(s => {
|
938 | const [e] = s.validate(value, {
|
939 | coerce: true
|
940 | });
|
941 | return !e;
|
942 | }) || unknown();
|
943 | return firstMatch.coercer(value, ctx);
|
944 | },
|
945 |
|
946 | validator(value, ctx) {
|
947 | const failures = [];
|
948 |
|
949 | for (const S of Structs) {
|
950 | const [...tuples] = run(value, S, ctx);
|
951 | const [first] = tuples;
|
952 |
|
953 | if (!first[0]) {
|
954 | return [];
|
955 | } else {
|
956 | for (const [failure] of tuples) {
|
957 | if (failure) {
|
958 | failures.push(failure);
|
959 | }
|
960 | }
|
961 | }
|
962 | }
|
963 |
|
964 | return ["Expected the value to satisfy a union of `" + description + "`, but received: " + print(value), ...failures];
|
965 | }
|
966 |
|
967 | });
|
968 | }
|
969 |
|
970 |
|
971 |
|
972 |
|
973 | function unknown() {
|
974 | return define('unknown', () => true);
|
975 | }
|
976 |
|
977 |
|
978 |
|
979 |
|
980 |
|
981 |
|
982 |
|
983 |
|
984 |
|
985 |
|
986 |
|
987 |
|
988 | function coerce(struct, condition, coercer) {
|
989 | return new Struct({ ...struct,
|
990 | coercer: (value, ctx) => {
|
991 | return is(value, condition) ? struct.coercer(coercer(value, ctx), ctx) : struct.coercer(value, ctx);
|
992 | }
|
993 | });
|
994 | }
|
995 |
|
996 |
|
997 |
|
998 |
|
999 |
|
1000 |
|
1001 |
|
1002 | function defaulted(struct, fallback, options = {}) {
|
1003 | return coerce(struct, unknown(), x => {
|
1004 | const f = typeof fallback === 'function' ? fallback() : fallback;
|
1005 |
|
1006 | if (x === undefined) {
|
1007 | return f;
|
1008 | }
|
1009 |
|
1010 | if (!options.strict && isPlainObject(x) && isPlainObject(f)) {
|
1011 | const ret = { ...x
|
1012 | };
|
1013 | let changed = false;
|
1014 |
|
1015 | for (const key in f) {
|
1016 | if (ret[key] === undefined) {
|
1017 | ret[key] = f[key];
|
1018 | changed = true;
|
1019 | }
|
1020 | }
|
1021 |
|
1022 | if (changed) {
|
1023 | return ret;
|
1024 | }
|
1025 | }
|
1026 |
|
1027 | return x;
|
1028 | });
|
1029 | }
|
1030 |
|
1031 |
|
1032 |
|
1033 |
|
1034 |
|
1035 |
|
1036 |
|
1037 | function trimmed(struct) {
|
1038 | return coerce(struct, string(), x => x.trim());
|
1039 | }
|
1040 |
|
1041 |
|
1042 |
|
1043 |
|
1044 |
|
1045 | function empty(struct) {
|
1046 | return refine(struct, 'empty', value => {
|
1047 | const size = getSize(value);
|
1048 | return size === 0 || "Expected an empty " + struct.type + " but received one with a size of `" + size + "`";
|
1049 | });
|
1050 | }
|
1051 |
|
1052 | function getSize(value) {
|
1053 | if (value instanceof Map || value instanceof Set) {
|
1054 | return value.size;
|
1055 | } else {
|
1056 | return value.length;
|
1057 | }
|
1058 | }
|
1059 |
|
1060 |
|
1061 |
|
1062 |
|
1063 |
|
1064 | function max(struct, threshold, options = {}) {
|
1065 | const {
|
1066 | exclusive
|
1067 | } = options;
|
1068 | return refine(struct, 'max', value => {
|
1069 | return exclusive ? value < threshold : value <= threshold || "Expected a " + struct.type + " less than " + (exclusive ? '' : 'or equal to ') + threshold + " but received `" + value + "`";
|
1070 | });
|
1071 | }
|
1072 |
|
1073 |
|
1074 |
|
1075 |
|
1076 | function min(struct, threshold, options = {}) {
|
1077 | const {
|
1078 | exclusive
|
1079 | } = options;
|
1080 | return refine(struct, 'min', value => {
|
1081 | return exclusive ? value > threshold : value >= threshold || "Expected a " + struct.type + " greater than " + (exclusive ? '' : 'or equal to ') + threshold + " but received `" + value + "`";
|
1082 | });
|
1083 | }
|
1084 |
|
1085 |
|
1086 |
|
1087 |
|
1088 | function nonempty(struct) {
|
1089 | return refine(struct, 'nonempty', value => {
|
1090 | const size = getSize(value);
|
1091 | return size > 0 || "Expected a nonempty " + struct.type + " but received an empty one";
|
1092 | });
|
1093 | }
|
1094 |
|
1095 |
|
1096 |
|
1097 |
|
1098 | function pattern(struct, regexp) {
|
1099 | return refine(struct, 'pattern', value => {
|
1100 | return regexp.test(value) || "Expected a " + struct.type + " matching `/" + regexp.source + "/` but received \"" + value + "\"";
|
1101 | });
|
1102 | }
|
1103 |
|
1104 |
|
1105 |
|
1106 |
|
1107 | function size(struct, min, max = min) {
|
1108 | const expected = "Expected a " + struct.type;
|
1109 | const of = min === max ? "of `" + min + "`" : "between `" + min + "` and `" + max + "`";
|
1110 | return refine(struct, 'size', value => {
|
1111 | if (typeof value === 'number' || value instanceof Date) {
|
1112 | return min <= value && value <= max || expected + " " + of + " but received `" + value + "`";
|
1113 | } else if (value instanceof Map || value instanceof Set) {
|
1114 | const {
|
1115 | size
|
1116 | } = value;
|
1117 | return min <= size && size <= max || expected + " with a size " + of + " but received one with a size of `" + size + "`";
|
1118 | } else {
|
1119 | const {
|
1120 | length
|
1121 | } = value;
|
1122 | return min <= length && length <= max || expected + " with a length " + of + " but received one with a length of `" + length + "`";
|
1123 | }
|
1124 | });
|
1125 | }
|
1126 |
|
1127 |
|
1128 |
|
1129 |
|
1130 |
|
1131 |
|
1132 |
|
1133 |
|
1134 | function refine(struct, name, refiner) {
|
1135 | return new Struct({ ...struct,
|
1136 |
|
1137 | *refiner(value, ctx) {
|
1138 | yield* struct.refiner(value, ctx);
|
1139 | const result = refiner(value, ctx);
|
1140 | const failures = toFailures(result, ctx, struct, value);
|
1141 |
|
1142 | for (const failure of failures) {
|
1143 | yield { ...failure,
|
1144 | refinement: name
|
1145 | };
|
1146 | }
|
1147 | }
|
1148 |
|
1149 | });
|
1150 | }
|
1151 |
|
1152 | export { Struct, StructError, any, array, assert, assign, bigint, boolean, coerce, create, date, defaulted, define, deprecated, dynamic, empty, enums, func, instance, integer, intersection, is, lazy, literal, map, mask, max, min, never, nonempty, nullable, number, object, omit, optional, partial, pattern, pick, record, refine, regexp, set, size, string, struct, trimmed, tuple, type, union, unknown, validate };
|
1153 | //# sourceMappingURL=index.es.js.map
|