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