UNPKG

26.6 kBJavaScriptView Raw
1/**
2 * Define a struct error.
3 *
4 * @type {StructError}
5 */
6
7class StructError extends TypeError {
8 static format(attrs) {
9 const { type, path, value } = attrs;
10 const message = `Expected a value of type \`${type}\`${path.length ? ` for \`${path.join('.')}\`` : ''} but received \`${JSON.stringify(value)}\`.`;
11 return message;
12 }
13
14 constructor(attrs) {
15 const message = StructError.format(attrs);
16 super(message);
17
18 const { data, path, value, reason, type, errors = [] } = attrs;
19 this.data = data;
20 this.path = path;
21 this.value = value;
22 this.reason = reason;
23 this.type = type;
24 this.errors = errors;
25
26 if (!errors.length) {
27 errors.push(this);
28 }
29
30 if (Error.captureStackTrace) {
31 Error.captureStackTrace(this, this.constructor);
32 } else {
33 this.stack = new Error().stack;
34 }
35 }
36}
37
38var toString = Object.prototype.toString;
39
40var kindOf = function kindOf(val) {
41 if (val === void 0) return 'undefined';
42 if (val === null) return 'null';
43
44 var type = typeof val;
45 if (type === 'boolean') return 'boolean';
46 if (type === 'string') return 'string';
47 if (type === 'number') return 'number';
48 if (type === 'symbol') return 'symbol';
49 if (type === 'function') {
50 return isGeneratorFn(val) ? 'generatorfunction' : 'function';
51 }
52
53 if (isArray(val)) return 'array';
54 if (isBuffer(val)) return 'buffer';
55 if (isArguments(val)) return 'arguments';
56 if (isDate(val)) return 'date';
57 if (isError(val)) return 'error';
58 if (isRegexp(val)) return 'regexp';
59
60 switch (ctorName(val)) {
61 case 'Symbol': return 'symbol';
62 case 'Promise': return 'promise';
63
64 // Set, Map, WeakSet, WeakMap
65 case 'WeakMap': return 'weakmap';
66 case 'WeakSet': return 'weakset';
67 case 'Map': return 'map';
68 case 'Set': return 'set';
69
70 // 8-bit typed arrays
71 case 'Int8Array': return 'int8array';
72 case 'Uint8Array': return 'uint8array';
73 case 'Uint8ClampedArray': return 'uint8clampedarray';
74
75 // 16-bit typed arrays
76 case 'Int16Array': return 'int16array';
77 case 'Uint16Array': return 'uint16array';
78
79 // 32-bit typed arrays
80 case 'Int32Array': return 'int32array';
81 case 'Uint32Array': return 'uint32array';
82 case 'Float32Array': return 'float32array';
83 case 'Float64Array': return 'float64array';
84 }
85
86 if (isGeneratorObj(val)) {
87 return 'generator';
88 }
89
90 // Non-plain objects
91 type = toString.call(val);
92 switch (type) {
93 case '[object Object]': return 'object';
94 // iterators
95 case '[object Map Iterator]': return 'mapiterator';
96 case '[object Set Iterator]': return 'setiterator';
97 case '[object String Iterator]': return 'stringiterator';
98 case '[object Array Iterator]': return 'arrayiterator';
99 }
100
101 // other
102 return type.slice(8, -1).toLowerCase().replace(/\s/g, '');
103};
104
105function ctorName(val) {
106 return val.constructor ? val.constructor.name : null;
107}
108
109function isArray(val) {
110 if (Array.isArray) return Array.isArray(val);
111 return val instanceof Array;
112}
113
114function isError(val) {
115 return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number');
116}
117
118function isDate(val) {
119 if (val instanceof Date) return true;
120 return typeof val.toDateString === 'function'
121 && typeof val.getDate === 'function'
122 && typeof val.setDate === 'function';
123}
124
125function isRegexp(val) {
126 if (val instanceof RegExp) return true;
127 return typeof val.flags === 'string'
128 && typeof val.ignoreCase === 'boolean'
129 && typeof val.multiline === 'boolean'
130 && typeof val.global === 'boolean';
131}
132
133function isGeneratorFn(name, val) {
134 return ctorName(name) === 'GeneratorFunction';
135}
136
137function isGeneratorObj(val) {
138 return typeof val.throw === 'function'
139 && typeof val.return === 'function'
140 && typeof val.next === 'function';
141}
142
143function isArguments(val) {
144 try {
145 if (typeof val.length === 'number' && typeof val.callee === 'function') {
146 return true;
147 }
148 } catch (err) {
149 if (err.message.indexOf('callee') !== -1) {
150 return true;
151 }
152 }
153 return false;
154}
155
156/**
157 * If you need to support Safari 5-7 (8-10 yr-old browser),
158 * take a look at https://github.com/feross/is-buffer
159 */
160
161function isBuffer(val) {
162 if (val.constructor && typeof val.constructor.isBuffer === 'function') {
163 return val.constructor.isBuffer(val);
164 }
165 return false;
166}
167
168/**
169 * A private string to identify structs by.
170 *
171 * @type {String}
172 */
173
174const IS_STRUCT = '@@__STRUCT__@@';
175
176/**
177 * A private string to refer to a struct's kind.
178 *
179 * @type {String}
180 */
181
182const KIND = '@@__KIND__@@';
183
184/**
185 * Check if a `value` is a struct.
186 *
187 * @param {Any} value
188 * @return {Boolean}
189 */
190
191function isStruct(value) {
192 return !!(value && value[IS_STRUCT]);
193}
194
195/**
196 * Resolve `defaults`, for an optional `value`.
197 *
198 * @param {Function|Any} defaults
199 * @param {Any} value
200 * @return {Any}
201 */
202
203function resolveDefaults(defaults, value) {
204 return typeof defaults === 'function' ? defaults(value) : defaults;
205}
206
207var _extends = Object.assign || function (target) {
208 for (var i = 1; i < arguments.length; i++) {
209 var source = arguments[i];
210
211 for (var key in source) {
212 if (Object.prototype.hasOwnProperty.call(source, key)) {
213 target[key] = source[key];
214 }
215 }
216 }
217
218 return target;
219};
220
221/**
222 * Kind.
223 *
224 * @type {Kind}
225 */
226
227class Kind {
228 constructor(name, type, validate) {
229 this.name = name;
230 this.type = type;
231 this.validate = validate;
232 }
233}
234
235/**
236 * Any.
237 *
238 * @param {Array|Function|Object|String} schema
239 * @param {Any} defaults
240 * @param {Object} options
241 */
242
243function any(schema, defaults$$1, options) {
244 if (isStruct(schema)) {
245 return schema[KIND];
246 }
247
248 if (schema instanceof Kind) {
249 return schema;
250 }
251
252 switch (kindOf(schema)) {
253 case 'array':
254 {
255 return schema.length > 1 ? tuple(schema, defaults$$1, options) : list(schema, defaults$$1, options);
256 }
257
258 case 'function':
259 {
260 return func(schema, defaults$$1, options);
261 }
262
263 case 'object':
264 {
265 return object(schema, defaults$$1, options);
266 }
267
268 case 'string':
269 {
270 let required = true;
271 let type;
272
273 if (schema.endsWith('?')) {
274 required = false;
275 schema = schema.slice(0, -1);
276 }
277
278 if (schema.includes('|')) {
279 const scalars = schema.split(/\s*\|\s*/g);
280 type = union(scalars, defaults$$1, options);
281 } else if (schema.includes('&')) {
282 const scalars = schema.split(/\s*&\s*/g);
283 type = intersection(scalars, defaults$$1, options);
284 } else {
285 type = scalar(schema, defaults$$1, options);
286 }
287
288 if (!required) {
289 type = optional(type, undefined, options);
290 }
291
292 return type;
293 }
294 }
295
296 if (process.env.NODE_ENV !== 'production') {
297 throw new Error(`A schema definition must be an object, array, string or function, but you passed: ${schema}`);
298 } else {
299 throw new Error(`Invalid schema: ${schema}`);
300 }
301}
302
303/**
304 * Dict.
305 *
306 * @param {Array} schema
307 * @param {Object} defaults
308 * @param {Object} options
309 */
310
311function dict(schema, defaults$$1, options) {
312 if (kindOf(schema) !== 'array' || schema.length !== 2) {
313 if (process.env.NODE_ENV !== 'production') {
314 throw new Error(`Dict structs must be defined as an array with two elements, but you passed: ${schema}`);
315 } else {
316 throw new Error(`Invalid schema: ${schema}`);
317 }
318 }
319
320 const obj = scalar('object', undefined, options);
321 const keys = any(schema[0], undefined, options);
322 const values = any(schema[1], undefined, options);
323 const name = 'dict';
324 const type = `dict<${keys.type},${values.type}>`;
325 const validate = (value = resolveDefaults(defaults$$1)) => {
326 const [error] = obj.validate(value);
327
328 if (error) {
329 error.type = type;
330 return [error];
331 }
332
333 const ret = {};
334 const errors = [];
335
336 for (let k in value) {
337 const v = value[k];
338 const [e, r] = keys.validate(k);
339
340 if (e) {
341 e.path = [k].concat(e.path);
342 e.data = value;
343 errors.push(e);
344 continue;
345 }
346
347 k = r;
348 const [e2, r2] = values.validate(v);
349
350 if (e2) {
351 e2.path = [k].concat(e2.path);
352 e2.data = value;
353 errors.push(e2);
354 continue;
355 }
356
357 ret[k] = r2;
358 }
359
360 if (errors.length) {
361 const first = errors[0];
362 first.errors = errors;
363 return [first];
364 }
365
366 return [undefined, ret];
367 };
368
369 return new Kind(name, type, validate);
370}
371
372/**
373 * Enum.
374 *
375 * @param {Array} schema
376 * @param {Any} defaults
377 * @param {Object} options
378 */
379
380function en(schema, defaults$$1, options) {
381 if (kindOf(schema) !== 'array') {
382 if (process.env.NODE_ENV !== 'production') {
383 throw new Error(`Enum structs must be defined as an array, but you passed: ${schema}`);
384 } else {
385 throw new Error(`Invalid schema: ${schema}`);
386 }
387 }
388
389 const name = 'enum';
390 const type = schema.map(s => {
391 try {
392 return JSON.stringify(s);
393 } catch (e) {
394 return String(s);
395 }
396 }).join(' | ');
397
398 const validate = (value = resolveDefaults(defaults$$1)) => {
399 return schema.includes(value) ? [undefined, value] : [{ data: value, path: [], value, type }];
400 };
401
402 return new Kind(name, type, validate);
403}
404
405/**
406 * Enums.
407 *
408 * @param {Array} schema
409 * @param {Any} defaults
410 * @param {Object} options
411 */
412
413function enums(schema, defaults$$1, options) {
414 const e = en(schema, undefined, options);
415 const l = list([e], defaults$$1, options);
416 return l;
417}
418
419/**
420 * Function.
421 *
422 * @param {Function} schema
423 * @param {Any} defaults
424 * @param {Object} options
425 */
426
427function func(schema, defaults$$1, options) {
428 if (kindOf(schema) !== 'function') {
429 if (process.env.NODE_ENV !== 'production') {
430 throw new Error(`Function structs must be defined as a function, but you passed: ${schema}`);
431 } else {
432 throw new Error(`Invalid schema: ${schema}`);
433 }
434 }
435
436 const name = 'function';
437 const type = '<function>';
438 const validate = (value = resolveDefaults(defaults$$1), data) => {
439 const result = schema(value, data);
440 let failure = { path: [], reason: null };
441 let isValid;
442
443 switch (kindOf(result)) {
444 case 'boolean':
445 {
446 isValid = result;
447 break;
448 }
449 case 'string':
450 {
451 isValid = false;
452 failure.reason = result;
453 break;
454 }
455 case 'object':
456 {
457 isValid = false;
458 failure = _extends({}, failure, result);
459 break;
460 }
461 default:
462 {
463 if (process.env.NODE_ENV !== 'production') {
464 throw new Error(`Validator functions must return a boolean, an error reason string or an error reason object, but you passed: ${schema}`);
465 } else {
466 throw new Error(`Invalid result: ${result}`);
467 }
468 }
469 }
470
471 return isValid ? [undefined, value] : [_extends({ type, value, data: value }, failure)];
472 };
473
474 return new Kind(name, type, validate);
475}
476
477/**
478 * Instance.
479 *
480 * @param {Array} schema
481 * @param {Any} defaults
482 * @param {Object} options
483 */
484
485function instance(schema, defaults$$1, options) {
486 const name = 'instance';
487 const type = `instance<${schema.name}>`;
488 const validate = (value = resolveDefaults(defaults$$1)) => {
489 return value instanceof schema ? [undefined, value] : [{ data: value, path: [], value, type }];
490 };
491
492 return new Kind(name, type, validate);
493}
494
495/**
496 * Interface.
497 *
498 * @param {Object} schema
499 * @param {Object} defaults
500 * @param {Object} options
501 */
502
503function inter(schema, defaults$$1, options) {
504 if (kindOf(schema) !== 'object') {
505 if (process.env.NODE_ENV !== 'production') {
506 throw new Error(`Interface structs must be defined as an object, but you passed: ${schema}`);
507 } else {
508 throw new Error(`Invalid schema: ${schema}`);
509 }
510 }
511
512 const ks = [];
513 const properties = {};
514
515 for (const key in schema) {
516 ks.push(key);
517 const s = schema[key];
518 const kind = any(s, undefined, options);
519 properties[key] = kind;
520 }
521
522 const name = 'interface';
523 const type = `{${ks.join()}}`;
524 const validate = (value = resolveDefaults(defaults$$1)) => {
525 const errors = [];
526
527 for (const key in properties) {
528 const v = value[key];
529 const kind = properties[key];
530 const [e] = kind.validate(v);
531
532 if (e) {
533 e.path = [key].concat(e.path);
534 e.data = value;
535 errors.push(e);
536 continue;
537 }
538 }
539
540 if (errors.length) {
541 const first = errors[0];
542 first.errors = errors;
543 return [first];
544 }
545
546 return [undefined, value];
547 };
548
549 return new Kind(name, type, validate);
550}
551
552/**
553 * Lazy.
554 *
555 * @param {Function} schema
556 * @param {Any} defaults
557 * @param {Object} options
558 */
559
560function lazy(schema, defaults$$1, options) {
561 if (kindOf(schema) !== 'function') {
562 if (process.env.NODE_ENV !== 'production') {
563 throw new Error(`Lazy structs must be defined as an function that returns a schema, but you passed: ${schema}`);
564 } else {
565 throw new Error(`Invalid schema: ${schema}`);
566 }
567 }
568
569 let kind;
570 let struct;
571 const name = 'lazy';
572 const type = `lazy...`;
573 const compile = value => {
574 struct = schema();
575 kind.name = struct.kind;
576 kind.type = struct.type;
577 kind.validate = struct.validate;
578 return kind.validate(value);
579 };
580
581 kind = new Kind(name, type, compile);
582 return kind;
583}
584
585/**
586 * List.
587 *
588 * @param {Array} schema
589 * @param {Array} defaults
590 * @param {Object} options
591 */
592
593function list(schema, defaults$$1, options) {
594 if (kindOf(schema) !== 'array' || schema.length !== 1) {
595 if (process.env.NODE_ENV !== 'production') {
596 throw new Error(`List structs must be defined as an array with a single element, but you passed: ${schema}`);
597 } else {
598 throw new Error(`Invalid schema: ${schema}`);
599 }
600 }
601
602 const array = scalar('array', undefined, options);
603 const element = any(schema[0], undefined, options);
604 const name = 'list';
605 const type = `[${element.type}]`;
606 const validate = (value = resolveDefaults(defaults$$1)) => {
607 const [error, result] = array.validate(value);
608
609 if (error) {
610 error.type = type;
611 return [error];
612 }
613
614 value = result;
615 const errors = [];
616 const ret = [];
617
618 for (let i = 0; i < value.length; i++) {
619 const v = value[i];
620 const [e, r] = element.validate(v);
621
622 if (e) {
623 e.path = [i].concat(e.path);
624 e.data = value;
625 errors.push(e);
626 continue;
627 }
628
629 ret[i] = r;
630 }
631
632 if (errors.length) {
633 const first = errors[0];
634 first.errors = errors;
635 return [first];
636 }
637
638 return [undefined, ret];
639 };
640
641 return new Kind(name, type, validate);
642}
643
644/**
645 * Literal.
646 *
647 * @param {Array} schema
648 * @param {Any} defaults
649 * @param {Object} options
650 */
651
652function literal(schema, defaults$$1, options) {
653 const name = 'literal';
654 const type = `literal: ${JSON.stringify(schema)}`;
655 const validate = (value = resolveDefaults(defaults$$1)) => {
656 return value === schema ? [undefined, value] : [{ data: value, path: [], value, type }];
657 };
658
659 return new Kind(name, type, validate);
660}
661
662/**
663 * Object.
664 *
665 * @param {Object} schema
666 * @param {Object} defaults
667 * @param {Object} options
668 */
669
670function object(schema, defaults$$1, options) {
671 if (kindOf(schema) !== 'object') {
672 if (process.env.NODE_ENV !== 'production') {
673 throw new Error(`Object structs must be defined as an object, but you passed: ${schema}`);
674 } else {
675 throw new Error(`Invalid schema: ${schema}`);
676 }
677 }
678
679 const obj = scalar('object', undefined, options);
680 const ks = [];
681 const properties = {};
682
683 for (const key in schema) {
684 ks.push(key);
685 const s = schema[key];
686 const kind = any(s, undefined, options);
687 properties[key] = kind;
688 }
689
690 const name = 'object';
691 const type = `{${ks.join()}}`;
692 const validate = (value = resolveDefaults(defaults$$1)) => {
693 const [error] = obj.validate(value);
694
695 if (error) {
696 error.type = type;
697 return [error];
698 }
699
700 const errors = [];
701 const ret = {};
702 const valueKeys = Object.keys(value);
703 const propertiesKeys = Object.keys(properties);
704 const keys = new Set(valueKeys.concat(propertiesKeys));
705
706 keys.forEach(key => {
707 let v = value[key];
708 const kind = properties[key];
709
710 if (v === undefined) {
711 const d = defaults$$1 && defaults$$1[key];
712 v = resolveDefaults(d, value);
713 }
714
715 if (!kind) {
716 const e = { data: value, path: [key], value: v };
717 errors.push(e);
718 return;
719 }
720
721 const [e, r] = kind.validate(v, value);
722
723 if (e) {
724 e.path = [key].concat(e.path);
725 e.data = value;
726 errors.push(e);
727 return;
728 }
729
730 if (key in value || r !== undefined) {
731 ret[key] = r;
732 }
733 });
734
735 if (errors.length) {
736 const first = errors[0];
737 first.errors = errors;
738 return [first];
739 }
740
741 return [undefined, ret];
742 };
743
744 return new Kind(name, type, validate);
745}
746
747/**
748 * Optional.
749 *
750 * @param {Any} schema
751 * @param {Any} defaults
752 * @param {Object} options
753 */
754
755function optional(schema, defaults$$1, options) {
756 return union([schema, 'undefined'], defaults$$1, options);
757}
758
759/**
760 * Partial.
761 *
762 * @param {Object} schema
763 * @param {Object} defaults
764 * @param {Object} options
765 */
766
767function partial(schema, defaults$$1, options) {
768 if (kindOf(schema) !== 'object') {
769 if (process.env.NODE_ENV !== 'production') {
770 throw new Error(`Partial structs must be defined as an object, but you passed: ${schema}`);
771 } else {
772 throw new Error(`Invalid schema: ${schema}`);
773 }
774 }
775
776 const obj = scalar('object', undefined, options);
777 const ks = [];
778 const properties = {};
779
780 for (const key in schema) {
781 ks.push(key);
782 const s = schema[key];
783 const kind = any(s, undefined, options);
784 properties[key] = kind;
785 }
786
787 const name = 'partial';
788 const type = `{${ks.join()},...}`;
789 const validate = (value = resolveDefaults(defaults$$1)) => {
790 const [error] = obj.validate(value);
791
792 if (error) {
793 error.type = type;
794 return [error];
795 }
796
797 const errors = [];
798 const ret = {};
799
800 for (const key in properties) {
801 let v = value[key];
802 const kind = properties[key];
803
804 if (v === undefined) {
805 const d = defaults$$1 && defaults$$1[key];
806 v = resolveDefaults(d, value);
807 }
808
809 const [e, r] = kind.validate(v, value);
810
811 if (e) {
812 e.path = [key].concat(e.path);
813 e.data = value;
814 errors.push(e);
815 continue;
816 }
817
818 if (key in value || r !== undefined) {
819 ret[key] = r;
820 }
821 }
822
823 if (errors.length) {
824 const first = errors[0];
825 first.errors = errors;
826 return [first];
827 }
828
829 return [undefined, ret];
830 };
831
832 return new Kind(name, type, validate);
833}
834
835/**
836 * Scalar.
837 *
838 * @param {String} schema
839 * @param {Any} defaults
840 * @param {Object} options
841 */
842
843function scalar(schema, defaults$$1, options) {
844 if (kindOf(schema) !== 'string') {
845 if (process.env.NODE_ENV !== 'production') {
846 throw new Error(`Scalar structs must be defined as a string, but you passed: ${schema}`);
847 } else {
848 throw new Error(`Invalid schema: ${schema}`);
849 }
850 }
851
852 const { types } = options;
853 const fn = types[schema];
854
855 if (kindOf(fn) !== 'function') {
856 if (process.env.NODE_ENV !== 'production') {
857 throw new Error(`No struct validator function found for type "${schema}".`);
858 } else {
859 throw new Error(`Invalid type: ${schema}`);
860 }
861 }
862
863 const kind = func(fn, defaults$$1, options);
864 const name = 'scalar';
865 const type = schema;
866 const validate = value => {
867 const [error, result] = kind.validate(value);
868
869 if (error) {
870 error.type = type;
871 return [error];
872 }
873
874 return [undefined, result];
875 };
876
877 return new Kind(name, type, validate);
878}
879
880/**
881 * Tuple.
882 *
883 * @param {Array} schema
884 * @param {Array} defaults
885 * @param {Object} options
886 */
887
888function tuple(schema, defaults$$1, options) {
889 if (kindOf(schema) !== 'array') {
890 if (process.env.NODE_ENV !== 'production') {
891 throw new Error(`Tuple structs must be defined as an array, but you passed: ${schema}`);
892 } else {
893 throw new Error(`Invalid schema: ${schema}`);
894 }
895 }
896
897 const kinds = schema.map(s => any(s, undefined, options));
898 const array = scalar('array', undefined, options);
899 const name = 'tuple';
900 const type = `[${kinds.map(k => k.type).join()}]`;
901 const validate = (value = resolveDefaults(defaults$$1)) => {
902 const [error] = array.validate(value);
903
904 if (error) {
905 error.type = type;
906 return [error];
907 }
908
909 const ret = [];
910 const errors = [];
911 const length = Math.max(value.length, kinds.length);
912
913 for (let i = 0; i < length; i++) {
914 const kind = kinds[i];
915 const v = value[i];
916
917 if (!kind) {
918 const e = { data: value, path: [i], value: v };
919 errors.push(e);
920 continue;
921 }
922
923 const [e, r] = kind.validate(v);
924
925 if (e) {
926 e.path = [i].concat(e.path);
927 e.data = value;
928 errors.push(e);
929 continue;
930 }
931
932 ret[i] = r;
933 }
934
935 if (errors.length) {
936 const first = errors[0];
937 first.errors = errors;
938 return [first];
939 }
940
941 return [undefined, ret];
942 };
943
944 return new Kind(name, type, validate);
945}
946
947/**
948 * Union.
949 *
950 * @param {Array} schema
951 * @param {Any} defaults
952 * @param {Object} options
953 */
954
955function union(schema, defaults$$1, options) {
956 if (kindOf(schema) !== 'array') {
957 if (process.env.NODE_ENV !== 'production') {
958 throw new Error(`Union structs must be defined as an array, but you passed: ${schema}`);
959 } else {
960 throw new Error(`Invalid schema: ${schema}`);
961 }
962 }
963
964 const kinds = schema.map(s => any(s, undefined, options));
965 const name = 'union';
966 const type = kinds.map(k => k.type).join(' | ');
967 const validate = (value = resolveDefaults(defaults$$1)) => {
968 const errors = [];
969
970 for (const k of kinds) {
971 const [e, r] = k.validate(value);
972
973 if (!e) {
974 return [undefined, r];
975 }
976
977 errors.push(e);
978 }
979 errors[0].type = type;
980 return errors;
981 };
982
983 return new Kind(name, type, validate);
984}
985
986/**
987 * Intersection.
988 *
989 * @param {Array} schema
990 * @param {Any} defaults
991 * @param {Object} options
992 */
993
994function intersection(schema, defaults$$1, options) {
995 if (kindOf(schema) !== 'array') {
996 if (process.env.NODE_ENV !== 'production') {
997 throw new Error(`Intersection structs must be defined as an array, but you passed: ${schema}`);
998 } else {
999 throw new Error(`Invalid schema: ${schema}`);
1000 }
1001 }
1002
1003 const types = schema.map(s => any(s, undefined, options));
1004 const name = 'intersection';
1005 const type = types.map(t => t.type).join(' & ');
1006 const validate = (value = resolveDefaults(defaults$$1)) => {
1007 let v = value;
1008
1009 for (const t of types) {
1010 const [e, r] = t.validate(v);
1011
1012 if (e) {
1013 e.type = type;
1014 return [e];
1015 }
1016
1017 v = r;
1018 }
1019
1020 return [undefined, v];
1021 };
1022
1023 return new Kind(name, type, validate);
1024}
1025
1026/**
1027 * Kinds.
1028 *
1029 * @type {Object}
1030 */
1031
1032const Kinds = {
1033 any,
1034 dict,
1035 enum: en,
1036 enums,
1037 function: func,
1038 instance,
1039 interface: inter,
1040 lazy,
1041 list,
1042 literal,
1043 object,
1044 optional,
1045 partial,
1046 scalar,
1047 tuple,
1048 union,
1049 intersection
1050
1051 /**
1052 * Export.
1053 *
1054 * @type {Object}
1055 */
1056
1057};
1058
1059/**
1060 * The types that `kind-of` supports.
1061 *
1062 * @type {Array}
1063 */
1064
1065const TYPES = ['arguments', 'array', 'boolean', 'buffer', 'date', 'error', 'float32array', 'float64array', 'function', 'generatorfunction', 'int16array', 'int32array', 'int8array', 'map', 'null', 'number', 'object', 'promise', 'regexp', 'set', 'string', 'symbol', 'uint16array', 'uint32array', 'uint8array', 'uint8clampedarray', 'undefined', 'weakmap', 'weakset'];
1066
1067/**
1068 * The default types that Superstruct ships with.
1069 *
1070 * @type {Object}
1071 */
1072
1073const Types = {
1074 any: value => value !== undefined
1075};
1076
1077TYPES.forEach(type => {
1078 Types[type] = value => kindOf(value) === type;
1079});
1080
1081/**
1082 * Create a struct factory with a `config`.
1083 *
1084 * @param {Object} config
1085 * @return {Function}
1086 */
1087
1088function superstruct(config = {}) {
1089 const types = _extends({}, Types, config.types || {});
1090
1091 /**
1092 * Create a `kind` struct with `schema`, `defaults` and `options`.
1093 *
1094 * @param {Any} schema
1095 * @param {Any} defaults
1096 * @param {Object} options
1097 * @return {Function}
1098 */
1099
1100 function struct(schema, defaults$$1, options = {}) {
1101 if (isStruct(schema)) {
1102 schema = schema.schema;
1103 }
1104
1105 const kind = Kinds.any(schema, defaults$$1, _extends({}, options, { types }));
1106
1107 function Struct(data) {
1108 if (this instanceof Struct) {
1109 if (process.env.NODE_ENV !== 'production') {
1110 throw new Error('The `Struct` creation function should not be used with the `new` keyword.');
1111 } else {
1112 throw new Error('Invalid `new` keyword!');
1113 }
1114 }
1115
1116 return Struct.assert(data);
1117 }
1118
1119 Object.defineProperty(Struct, IS_STRUCT, { value: true });
1120 Object.defineProperty(Struct, KIND, { value: kind });
1121
1122 Struct.kind = kind.name;
1123 Struct.type = kind.type;
1124 Struct.schema = schema;
1125 Struct.defaults = defaults$$1;
1126 Struct.options = options;
1127
1128 Struct.assert = value => {
1129 const [error, result] = kind.validate(value);
1130
1131 if (error) {
1132 throw new StructError(error);
1133 }
1134
1135 return result;
1136 };
1137
1138 Struct.test = value => {
1139 const [error] = kind.validate(value);
1140 return !error;
1141 };
1142
1143 Struct.validate = value => {
1144 const [error, result] = kind.validate(value);
1145
1146 if (error) {
1147 return [new StructError(error)];
1148 }
1149
1150 return [undefined, result];
1151 };
1152
1153 return Struct;
1154 }
1155
1156 /**
1157 * Mix in a factory for each specific kind of struct.
1158 */
1159
1160 Object.keys(Kinds).forEach(name => {
1161 const kind = Kinds[name];
1162
1163 struct[name] = (schema, defaults$$1, options) => {
1164 const type = kind(schema, defaults$$1, _extends({}, options, { types }));
1165 const s = struct(type, defaults$$1, options);
1166 return s;
1167 };
1168 });
1169
1170 /**
1171 * Return the struct factory.
1172 */
1173
1174 return struct;
1175}
1176
1177/**
1178 * Create a convenience `struct` factory for the default types.
1179 *
1180 * @type {Function}
1181 */
1182
1183const struct = superstruct();
1184
1185export { struct, superstruct, isStruct, StructError };
1186//# sourceMappingURL=index.es.js.map