UNPKG

46.5 kBJavaScriptView Raw
1import RandExp from 'randexp';
2import jsonpath from 'jsonpath';
3import $RefParser from 'json-schema-ref-parser';
4
5/**
6 * This class defines a registry for custom formats used within JSF.
7 */
8var Registry = function Registry() {
9 // empty by default
10 this.data = {};
11};
12/**
13 * Unregisters custom format(s)
14 * @param name
15 */
16
17
18Registry.prototype.unregister = function unregister (name) {
19 if (!name) {
20 this.data = {};
21 } else {
22 delete this.data[name];
23 }
24};
25/**
26 * Registers custom format
27 */
28
29
30Registry.prototype.register = function register (name, callback) {
31 this.data[name] = callback;
32};
33/**
34 * Register many formats at one shot
35 */
36
37
38Registry.prototype.registerMany = function registerMany (formats) {
39 var this$1 = this;
40
41 Object.keys(formats).forEach(function (name) {
42 this$1.data[name] = formats[name];
43 });
44};
45/**
46 * Returns element by registry key
47 */
48
49
50Registry.prototype.get = function get (name) {
51 var format = this.data[name];
52 return format;
53};
54/**
55 * Returns the whole registry content
56 */
57
58
59Registry.prototype.list = function list () {
60 return this.data;
61};
62
63var defaults = {};
64defaults.defaultInvalidTypeProduct = null;
65defaults.defaultRandExpMax = 10;
66defaults.ignoreProperties = [];
67defaults.ignoreMissingRefs = false;
68defaults.failOnInvalidTypes = true;
69defaults.failOnInvalidFormat = true;
70defaults.alwaysFakeOptionals = false;
71defaults.optionalsProbability = false;
72defaults.fixedProbabilities = false;
73defaults.useExamplesValue = false;
74defaults.useDefaultValue = false;
75defaults.requiredOnly = false;
76defaults.minItems = 0;
77defaults.maxItems = null;
78defaults.minLength = 0;
79defaults.maxLength = null;
80defaults.resolveJsonPath = false;
81defaults.reuseProperties = false;
82defaults.fillProperties = true;
83defaults.random = Math.random;
84/**
85 * This class defines a registry for custom settings used within JSF.
86 */
87
88var OptionRegistry = (function (Registry$$1) {
89 function OptionRegistry() {
90 Registry$$1.call(this);
91 this.data = Object.assign({}, defaults);
92 this._defaults = defaults;
93 }
94
95 if ( Registry$$1 ) OptionRegistry.__proto__ = Registry$$1;
96 OptionRegistry.prototype = Object.create( Registry$$1 && Registry$$1.prototype );
97 OptionRegistry.prototype.constructor = OptionRegistry;
98
99 var prototypeAccessors = { defaults: { configurable: true } };
100
101 prototypeAccessors.defaults.get = function () {
102 return Object.assign({}, this._defaults);
103 };
104
105 Object.defineProperties( OptionRegistry.prototype, prototypeAccessors );
106
107 return OptionRegistry;
108}(Registry));
109
110var registry = new OptionRegistry();
111/**
112 * Custom option API
113 *
114 * @param nameOrOptionMap
115 * @returns {any}
116 */
117
118function optionAPI(nameOrOptionMap) {
119 if (typeof nameOrOptionMap === 'string') {
120 return registry.get(nameOrOptionMap);
121 }
122
123 return registry.registerMany(nameOrOptionMap);
124}
125
126optionAPI.getDefaults = function () { return registry.defaults; };
127
128var ALL_TYPES = ['array', 'object', 'integer', 'number', 'string', 'boolean', 'null'];
129var MOST_NEAR_DATETIME = 2524608000000;
130var MIN_INTEGER = -100000000;
131var MAX_INTEGER = 100000000;
132var MIN_NUMBER = -100;
133var MAX_NUMBER = 100;
134var env = {
135 ALL_TYPES: ALL_TYPES,
136 MIN_NUMBER: MIN_NUMBER,
137 MAX_NUMBER: MAX_NUMBER,
138 MIN_INTEGER: MIN_INTEGER,
139 MAX_INTEGER: MAX_INTEGER,
140 MOST_NEAR_DATETIME: MOST_NEAR_DATETIME
141};
142
143function getRandomInteger(min, max) {
144 min = typeof min === 'undefined' ? env.MIN_INTEGER : min;
145 max = typeof max === 'undefined' ? env.MAX_INTEGER : max;
146 return Math.floor(optionAPI('random')() * (max - min + 1)) + min;
147}
148
149function _randexp(value) {
150 // set maximum default, see #193
151 RandExp.prototype.max = optionAPI('defaultRandExpMax'); // same implementation as the original except using our random
152
153 RandExp.prototype.randInt = function (a, b) { return a + Math.floor(optionAPI('random')() * (1 + (b - a))); };
154
155 var re = new RandExp(value);
156 return re.gen();
157}
158/**
159 * Returns random element of a collection
160 *
161 * @param collection
162 * @returns {T}
163 */
164
165
166function pick(collection) {
167 return collection[Math.floor(optionAPI('random')() * collection.length)];
168}
169/**
170 * Returns shuffled collection of elements
171 *
172 * @param collection
173 * @returns {T[]}
174 */
175
176
177function shuffle(collection) {
178 var tmp;
179 var key;
180 var length = collection.length;
181 var copy = collection.slice();
182
183 for (; length > 0;) {
184 key = Math.floor(optionAPI('random')() * length); // swap
185
186 length -= 1;
187 tmp = copy[length];
188 copy[length] = copy[key];
189 copy[key] = tmp;
190 }
191
192 return copy;
193}
194/**
195 * Returns a random integer between min (inclusive) and max (inclusive)
196 * Using Math.round() will give you a non-uniform distribution!
197 * @see http://stackoverflow.com/a/1527820/769384
198 */
199
200
201function getRandom(min, max) {
202 return optionAPI('random')() * (max - min) + min;
203}
204/**
205 * Generates random number according to parameters passed
206 *
207 * @param min
208 * @param max
209 * @param defMin
210 * @param defMax
211 * @param hasPrecision
212 * @returns {number}
213 */
214
215
216function number(min, max, defMin, defMax, hasPrecision) {
217 if ( hasPrecision === void 0 ) hasPrecision = false;
218
219 defMin = typeof defMin === 'undefined' ? env.MIN_NUMBER : defMin;
220 defMax = typeof defMax === 'undefined' ? env.MAX_NUMBER : defMax;
221 min = typeof min === 'undefined' ? defMin : min;
222 max = typeof max === 'undefined' ? defMax : max;
223
224 if (max < min) {
225 max += min;
226 }
227
228 if (hasPrecision) {
229 return getRandom(min, max);
230 }
231
232 return getRandomInteger(min, max);
233}
234
235function by(type) {
236 switch (type) {
237 case 'seconds':
238 return number(0, 60) * 60;
239
240 case 'minutes':
241 return number(15, 50) * 612;
242
243 case 'hours':
244 return number(12, 72) * 36123;
245
246 case 'days':
247 return number(7, 30) * 86412345;
248
249 case 'weeks':
250 return number(4, 52) * 604812345;
251
252 case 'months':
253 return number(2, 13) * 2592012345;
254
255 case 'years':
256 return number(1, 20) * 31104012345;
257
258 default:
259 break;
260 }
261}
262
263function date(step) {
264 if (step) {
265 return by(step);
266 }
267
268 var now = new Date();
269 var days = number(-1000, env.MOST_NEAR_DATETIME);
270 now.setTime(now.getTime() - days);
271 return now;
272}
273
274var random = {
275 pick: pick,
276 date: date,
277 shuffle: shuffle,
278 number: number,
279 randexp: _randexp
280};
281
282function getSubAttribute(obj, dotSeparatedKey) {
283 var keyElements = dotSeparatedKey.split('.');
284
285 while (keyElements.length) {
286 var prop = keyElements.shift();
287
288 if (!obj[prop]) {
289 break;
290 }
291
292 obj = obj[prop];
293 }
294
295 return obj;
296}
297/**
298 * Returns true/false whether the object parameter has its own properties defined
299 *
300 * @param obj
301 * @param properties
302 * @returns {boolean}
303 */
304
305
306function hasProperties(obj) {
307 var properties = [], len = arguments.length - 1;
308 while ( len-- > 0 ) properties[ len ] = arguments[ len + 1 ];
309
310 return properties.filter(function (key) {
311 return typeof obj[key] !== 'undefined';
312 }).length > 0;
313}
314/**
315 * Returns typecasted value.
316 * External generators (faker, chance, casual) may return data in non-expected formats, such as string, when you might expect an
317 * integer. This function is used to force the typecast. This is the base formatter for all result values.
318 *
319 * @param type
320 * @param schema
321 * @param callback
322 * @returns {any}
323 */
324
325
326function typecast(type, schema, callback) {
327 var params = {}; // normalize constraints
328
329 switch (type || schema.type) {
330 case 'integer':
331 case 'number':
332 if (typeof schema.minimum !== 'undefined') {
333 params.minimum = schema.minimum;
334 }
335
336 if (typeof schema.maximum !== 'undefined') {
337 params.maximum = schema.maximum;
338 }
339
340 if (schema.enum) {
341 var min = Math.max(params.minimum || 0, 0);
342 var max = Math.min(params.maximum || Infinity, Infinity);
343
344 if (schema.exclusiveMinimum && min === schema.minimum) {
345 min += schema.multipleOf || 1;
346 }
347
348 if (schema.exclusiveMaximum && max === schema.maximum) {
349 max -= schema.multipleOf || 1;
350 } // discard out-of-bounds enumerations
351
352
353 if (min || max !== Infinity) {
354 schema.enum = schema.enum.filter(function (x) {
355 if (x >= min && x <= max) {
356 return true;
357 }
358
359 return false;
360 });
361 }
362 }
363
364 break;
365
366 case 'string':
367 {
368 if (typeof schema.minLength !== 'undefined') {
369 params.minLength = schema.minLength;
370 }
371
372 if (typeof schema.maxLength !== 'undefined') {
373 params.maxLength = schema.maxLength;
374 }
375
376 var _maxLength = optionAPI('maxLength');
377
378 var _minLength = optionAPI('minLength'); // Don't allow user to set max length above our maximum
379
380
381 if (_maxLength && params.maxLength > _maxLength) {
382 params.maxLength = _maxLength;
383 } // Don't allow user to set min length above our maximum
384
385
386 if (_minLength && params.minLength < _minLength) {
387 params.minLength = _minLength;
388 }
389
390 break;
391 }
392
393 default:
394 break;
395 } // execute generator
396
397
398 var value = callback(params); // normalize output value
399
400 switch (type || schema.type) {
401 case 'number':
402 value = parseFloat(value);
403 break;
404
405 case 'integer':
406 value = parseInt(value, 10);
407 break;
408
409 case 'boolean':
410 value = !!value;
411 break;
412
413 case 'string':
414 {
415 value = String(value);
416 var min$1 = Math.max(params.minLength || 0, 0);
417 var max$1 = Math.min(params.maxLength || Infinity, Infinity);
418
419 while (value.length < min$1) {
420 value += " " + value;
421 }
422
423 if (value.length > max$1) {
424 value = value.substr(0, max$1);
425 }
426
427 break;
428 }
429
430 default:
431 break;
432 }
433
434 return value;
435}
436
437function merge(a, b) {
438 Object.keys(b).forEach(function (key) {
439 if (typeof b[key] !== 'object' || b[key] === null) {
440 a[key] = b[key];
441 } else if (Array.isArray(b[key])) {
442 a[key] = a[key] || []; // fix #292 - skip duplicated values from merge object (b)
443
444 b[key].forEach(function (value) {
445 if (a[key].indexOf(value) === -1) {
446 a[key].push(value);
447 }
448 });
449 } else if (typeof a[key] !== 'object' || a[key] === null || Array.isArray(a[key])) {
450 a[key] = merge({}, b[key]);
451 } else {
452 a[key] = merge(a[key], b[key]);
453 }
454 });
455 return a;
456}
457
458function short(schema) {
459 var s = JSON.stringify(schema);
460 var l = JSON.stringify(schema, null, 2);
461 return s.length > 400 ? ((l.substr(0, 400)) + "...") : l;
462}
463
464function anyValue() {
465 return random.pick([false, true, null, -1, NaN, Math.PI, Infinity, undefined, [], {}, Math.random(), Math.random().toString(36).substr(2)]);
466}
467
468function notValue(schema, parent) {
469 var copy = merge({}, parent);
470
471 if (typeof schema.minimum !== 'undefined') {
472 copy.maximum = schema.minimum;
473 copy.exclusiveMaximum = true;
474 }
475
476 if (typeof schema.maximum !== 'undefined') {
477 copy.minimum = schema.maximum > copy.maximum ? 0 : schema.maximum;
478 copy.exclusiveMinimum = true;
479 }
480
481 if (typeof schema.minLength !== 'undefined') {
482 copy.maxLength = schema.minLength;
483 }
484
485 if (typeof schema.maxLength !== 'undefined') {
486 copy.minLength = schema.maxLength > copy.maxLength ? 0 : schema.maxLength;
487 }
488
489 if (schema.type) {
490 copy.type = random.pick(env.ALL_TYPES.filter(function (x) {
491 var types = Array.isArray(schema.type) ? schema.type : [schema.type];
492 return types.every(function (type) {
493 // treat both types as _similar enough_ to be skipped equal
494 if (x === 'number' || x === 'integer') {
495 return type !== 'number' && type !== 'integer';
496 }
497
498 return x !== type;
499 });
500 }));
501 } else if (schema.enum) {
502 var value;
503
504 do {
505 value = anyValue();
506 } while (schema.enum.indexOf(value) !== -1);
507
508 copy.enum = [value];
509 }
510
511 if (schema.required && copy.properties) {
512 schema.required.forEach(function (prop) {
513 delete copy.properties[prop];
514 });
515 } // TODO: explore more scenarios
516
517
518 return copy;
519} // FIXME: evaluate more constraints?
520
521
522function validate(value, schemas) {
523 return !schemas.every(function (x) {
524 if (typeof x.minimum !== 'undefined' && value >= x.minimum) {
525 return true;
526 }
527
528 if (typeof x.maximum !== 'undefined' && value <= x.maximum) {
529 return true;
530 }
531
532 return false;
533 });
534}
535
536function isKey(prop) {
537 return ['enum', 'const', 'default', 'examples', 'required', 'definitions'].indexOf(prop) !== -1;
538}
539
540function omitProps(obj, props) {
541 var copy = {};
542 Object.keys(obj).forEach(function (k) {
543 if (props.indexOf(k) === -1) {
544 if (Array.isArray(obj[k])) {
545 copy[k] = obj[k].slice();
546 } else {
547 copy[k] = typeof obj[k] === 'object' ? merge({}, obj[k]) : obj[k];
548 }
549 }
550 });
551 return copy;
552}
553
554function template(value, schema) {
555 if (Array.isArray(value)) {
556 return value.map(function (x) { return template(x, schema); });
557 }
558
559 if (typeof value === 'string') {
560 value = value.replace(/#\{([\w.-]+)\}/g, function (_, $1) { return schema[$1]; });
561 }
562
563 return value;
564}
565
566var utils = {
567 getSubAttribute: getSubAttribute,
568 hasProperties: hasProperties,
569 omitProps: omitProps,
570 typecast: typecast,
571 merge: merge,
572 short: short,
573 notValue: notValue,
574 anyValue: anyValue,
575 validate: validate,
576 isKey: isKey,
577 template: template
578};
579
580function proxy(gen) {
581 return function (value, schema, property, rootSchema) {
582 var fn = value;
583 var args = []; // support for nested object, first-key is the generator
584
585 if (typeof value === 'object') {
586 fn = Object.keys(value)[0]; // treat the given array as arguments,
587
588 if (Array.isArray(value[fn])) {
589 // if the generator is expecting arrays they should be nested, e.g. `[[1, 2, 3], true, ...]`
590 args = value[fn];
591 } else {
592 args.push(value[fn]);
593 }
594 } // support for keypaths, e.g. "internet.email"
595
596
597 var props = fn.split('.'); // retrieve a fresh dependency
598
599 var ctx = gen();
600
601 while (props.length > 1) {
602 ctx = ctx[props.shift()];
603 } // retrieve last value from context object
604
605
606 value = typeof ctx === 'object' ? ctx[props[0]] : ctx; // invoke dynamic generators
607
608 if (typeof value === 'function') {
609 value = value.apply(ctx, args.map(function (x) { return utils.template(x, rootSchema); }));
610 } // test for pending callbacks
611
612
613 if (Object.prototype.toString.call(value) === '[object Object]') {
614 Object.keys(value).forEach(function (key) {
615 if (typeof value[key] === 'function') {
616 throw new Error(("Cannot resolve value for '" + property + ": " + fn + "', given: " + value));
617 }
618 });
619 }
620
621 return value;
622 };
623}
624/**
625 * Container is used to wrap external generators (faker, chance, casual, etc.) and its dependencies.
626 *
627 * - `jsf.extend('faker')` will enhance or define the given dependency.
628 * - `jsf.define('faker')` will provide the "faker" keyword support.
629 *
630 * RandExp is not longer considered an "extension".
631 */
632
633
634var Container = function Container() {
635 // dynamic requires - handle all dependencies
636 // they will NOT be included on the bundle
637 this.registry = {};
638 this.support = {};
639};
640/**
641 * Unregister extensions
642 * @param name
643 */
644
645
646Container.prototype.reset = function reset (name) {
647 if (!name) {
648 this.registry = {};
649 this.support = {};
650 } else {
651 delete this.registry[name];
652 delete this.support[name];
653 }
654};
655/**
656 * Override dependency given by name
657 * @param name
658 * @param callback
659 */
660
661
662Container.prototype.extend = function extend (name, callback) {
663 var this$1 = this;
664
665 this.registry[name] = callback(this.registry[name]); // built-in proxy (can be overridden)
666
667 if (!this.support[name]) {
668 this.support[name] = proxy(function () { return this$1.registry[name]; });
669 }
670};
671/**
672 * Set keyword support by name
673 * @param name
674 * @param callback
675 */
676
677
678Container.prototype.define = function define (name, callback) {
679 this.support[name] = callback;
680};
681/**
682 * Returns dependency given by name
683 * @param name
684 * @returns {Dependency}
685 */
686
687
688Container.prototype.get = function get (name) {
689 if (typeof this.registry[name] === 'undefined') {
690 throw new ReferenceError(("'" + name + "' dependency doesn't exist."));
691 }
692
693 return this.registry[name];
694};
695/**
696 * Apply a custom keyword
697 * @param schema
698 */
699
700
701Container.prototype.wrap = function wrap (schema) {
702 var this$1 = this;
703
704 var keys = Object.keys(schema);
705 var context = {};
706 var length = keys.length;
707
708 var loop = function () {
709 // eslint-disable-line
710 var fn = keys[length].replace(/^x-/, '');
711 var gen = this$1.support[fn];
712
713 if (typeof gen === 'function') {
714 Object.defineProperty(schema, 'generate', {
715 configurable: false,
716 enumerable: false,
717 writable: false,
718 value: function (rootSchema) { return gen.call(context, schema[keys[length]], schema, keys[length], rootSchema); } // eslint-disable-line
719
720 });
721 return 'break';
722 }
723 };
724
725 while (length--) {
726 var returned = loop();
727
728 if ( returned === 'break' ) break;
729 }
730
731 return schema;
732};
733
734var registry$1 = new Registry();
735/**
736 * Custom format API
737 *
738 * @see https://github.com/json-schema-faker/json-schema-faker#custom-formats
739 * @param nameOrFormatMap
740 * @param callback
741 * @returns {any}
742 */
743
744function formatAPI(nameOrFormatMap, callback) {
745 if (typeof nameOrFormatMap === 'undefined') {
746 return registry$1.list();
747 } else if (typeof nameOrFormatMap === 'string') {
748 if (typeof callback === 'function') {
749 registry$1.register(nameOrFormatMap, callback);
750 } else if (callback === null || callback === false) {
751 registry$1.unregister(nameOrFormatMap);
752 } else {
753 return registry$1.get(nameOrFormatMap);
754 }
755 } else {
756 registry$1.registerMany(nameOrFormatMap);
757 }
758}
759
760var ParseError = (function (Error) {
761 function ParseError(message, path) {
762 Error.call(this);
763
764 if (Error.captureStackTrace) {
765 Error.captureStackTrace(this, this.constructor);
766 }
767
768 this.name = 'ParseError';
769 this.message = message;
770 this.path = path;
771 }
772
773 if ( Error ) ParseError.__proto__ = Error;
774 ParseError.prototype = Object.create( Error && Error.prototype );
775 ParseError.prototype.constructor = ParseError;
776
777 return ParseError;
778}(Error));
779
780var inferredProperties = {
781 array: ['additionalItems', 'items', 'maxItems', 'minItems', 'uniqueItems'],
782 integer: ['exclusiveMaximum', 'exclusiveMinimum', 'maximum', 'minimum', 'multipleOf'],
783 object: ['additionalProperties', 'dependencies', 'maxProperties', 'minProperties', 'patternProperties', 'properties', 'required'],
784 string: ['maxLength', 'minLength', 'pattern', 'format']
785};
786inferredProperties.number = inferredProperties.integer;
787var subschemaProperties = ['additionalItems', 'items', 'additionalProperties', 'dependencies', 'patternProperties', 'properties'];
788/**
789 * Iterates through all keys of `obj` and:
790 * - checks whether those keys match properties of a given inferred type
791 * - makes sure that `obj` is not a subschema; _Do not attempt to infer properties named as subschema containers. The
792 * reason for this is that any property name within those containers that matches one of the properties used for
793 * inferring missing type values causes the container itself to get processed which leads to invalid output. (Issue 62)_
794 *
795 * @returns {boolean}
796 */
797
798function matchesType(obj, lastElementInPath, inferredTypeProperties) {
799 return Object.keys(obj).filter(function (prop) {
800 var isSubschema = subschemaProperties.indexOf(lastElementInPath) > -1;
801 var inferredPropertyFound = inferredTypeProperties.indexOf(prop) > -1;
802
803 if (inferredPropertyFound && !isSubschema) {
804 return true;
805 }
806
807 return false;
808 }).length > 0;
809}
810/**
811 * Checks whether given `obj` type might be inferred. The mechanism iterates through all inferred types definitions,
812 * tries to match allowed properties with properties of given `obj`. Returns type name, if inferred, or null.
813 *
814 * @returns {string|null}
815 */
816
817
818function inferType(obj, schemaPath) {
819 var keys = Object.keys(inferredProperties);
820
821 for (var i = 0; i < keys.length; i += 1) {
822 var typeName = keys[i];
823 var lastElementInPath = schemaPath[schemaPath.length - 1];
824
825 if (matchesType(obj, lastElementInPath, inferredProperties[typeName])) {
826 return typeName;
827 }
828 }
829}
830
831/**
832 * Generates randomized boolean value.
833 *
834 * @returns {boolean}
835 */
836
837function booleanGenerator() {
838 return optionAPI('random')() > 0.5;
839}
840
841var booleanType = booleanGenerator;
842
843/**
844 * Generates null value.
845 *
846 * @returns {null}
847 */
848function nullGenerator() {
849 return null;
850}
851
852var nullType = nullGenerator;
853
854function unique(path, items, value, sample, resolve, traverseCallback) {
855 var tmp = [];
856 var seen = [];
857
858 function walk(obj) {
859 var json = JSON.stringify(obj);
860
861 if (seen.indexOf(json) === -1) {
862 seen.push(json);
863 tmp.push(obj);
864 }
865 }
866
867 items.forEach(walk); // TODO: find a better solution?
868
869 var limit = 100;
870
871 while (tmp.length !== items.length) {
872 walk(traverseCallback(value.items || sample, path, resolve));
873
874 if (!limit) {
875 limit -= 1;
876 break;
877 }
878 }
879
880 return tmp;
881} // TODO provide types
882
883
884function arrayType(value, path, resolve, traverseCallback) {
885 var items = [];
886
887 if (!(value.items || value.additionalItems)) {
888 if (utils.hasProperties(value, 'minItems', 'maxItems', 'uniqueItems')) {
889 throw new ParseError(("missing items for " + (utils.short(value))), path);
890 }
891
892 return items;
893 }
894
895 if (Array.isArray(value.items)) {
896 return value.items.map(function (item, key) {
897 var itemSubpath = path.concat(['items', key]);
898 return traverseCallback(item, itemSubpath, resolve);
899 });
900 }
901
902 var minItems = value.minItems;
903 var maxItems = value.maxItems;
904
905 if (optionAPI('minItems')) {
906 // fix boundaries
907 minItems = !maxItems ? optionAPI('minItems') : Math.min(optionAPI('minItems'), maxItems);
908 }
909
910 if (optionAPI('maxItems')) {
911 // Don't allow user to set max items above our maximum
912 if (maxItems && maxItems > optionAPI('maxItems')) {
913 maxItems = optionAPI('maxItems');
914 } // Don't allow user to set min items above our maximum
915
916
917 if (minItems && minItems > optionAPI('maxItems')) {
918 minItems = maxItems;
919 }
920 }
921
922 var optionalsProbability = optionAPI('alwaysFakeOptionals') === true ? 1.0 : optionAPI('optionalsProbability');
923 var fixedProbabilities = optionAPI('fixedProbabilities') || false;
924 var length = random.number(minItems, maxItems, 1, 5);
925
926 if (optionalsProbability !== false) {
927 length = fixedProbabilities ? Math.round(maxItems * optionalsProbability) : random.number(minItems, maxItems * optionalsProbability);
928 } // TODO below looks bad. Should additionalItems be copied as-is?
929
930
931 var sample = typeof value.additionalItems === 'object' ? value.additionalItems : {};
932
933 for (var current = items.length; current < length; current += 1) {
934 var itemSubpath = path.concat(['items', current]);
935 var element = traverseCallback(value.items || sample, itemSubpath, resolve);
936 items.push(element);
937 }
938
939 if (value.uniqueItems) {
940 return unique(path.concat(['items']), items, value, sample, resolve, traverseCallback);
941 }
942
943 return items;
944}
945
946function numberType(value) {
947 var min = typeof value.minimum === 'undefined' ? env.MIN_INTEGER : value.minimum;
948 var max = typeof value.maximum === 'undefined' ? env.MAX_INTEGER : value.maximum;
949 var multipleOf = value.multipleOf;
950
951 if (multipleOf) {
952 max = Math.floor(max / multipleOf) * multipleOf;
953 min = Math.ceil(min / multipleOf) * multipleOf;
954 }
955
956 if (value.exclusiveMinimum && min === value.minimum) {
957 min += multipleOf || 1;
958 }
959
960 if (value.exclusiveMaximum && max === value.maximum) {
961 max -= multipleOf || 1;
962 }
963
964 if (min > max) {
965 return NaN;
966 }
967
968 if (multipleOf) {
969 if (String(multipleOf).indexOf('.') === -1) {
970 var base = random.number(Math.floor(min / multipleOf), Math.floor(max / multipleOf)) * multipleOf;
971
972 while (base < min) {
973 base += value.multipleOf;
974 }
975
976 return base;
977 }
978
979 var boundary = (max - min) / multipleOf;
980 var num;
981 var fix;
982
983 do {
984 num = random.number(0, boundary) * multipleOf;
985 fix = num / multipleOf % 1;
986 } while (fix !== 0); // FIXME: https://github.com/json-schema-faker/json-schema-faker/issues/379
987
988
989 return num;
990 }
991
992 return random.number(min, max, undefined, undefined, true);
993}
994
995// returns floating point numbers, and `integer` type truncates the fraction
996// part, leaving the result as an integer.
997
998function integerType(value) {
999 return numberType(Object.assign({
1000 multipleOf: 1
1001 }, value));
1002}
1003
1004var LIPSUM_WORDS = "Lorem ipsum dolor sit amet consectetur adipisicing elit sed do eiusmod tempor incididunt ut labore\net dolore magna aliqua Ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea\ncommodo consequat Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\npariatur Excepteur sint occaecat cupidatat non proident sunt in culpa qui officia deserunt mollit anim id est\nlaborum".split(/\W/);
1005/**
1006 * Generates randomized array of single lorem ipsum words.
1007 *
1008 * @param length
1009 * @returns {Array.<string>}
1010 */
1011
1012function wordsGenerator(length) {
1013 var words = random.shuffle(LIPSUM_WORDS);
1014 return words.slice(0, length);
1015}
1016
1017var anyType = {
1018 type: ['string', 'number', 'integer', 'boolean']
1019}; // TODO provide types
1020
1021function objectType(value, path, resolve, traverseCallback) {
1022 var props = {};
1023 var properties = value.properties || {};
1024 var patternProperties = value.patternProperties || {};
1025 var requiredProperties = (value.required || []).slice();
1026 var allowsAdditional = value.additionalProperties !== false;
1027 var propertyKeys = Object.keys(properties);
1028 var patternPropertyKeys = Object.keys(patternProperties);
1029 var optionalProperties = propertyKeys.concat(patternPropertyKeys).reduce(function (_response, _key) {
1030 if (requiredProperties.indexOf(_key) === -1) { _response.push(_key); }
1031 return _response;
1032 }, []);
1033 var allProperties = requiredProperties.concat(optionalProperties);
1034 var additionalProperties = allowsAdditional // eslint-disable-line
1035 ? value.additionalProperties === true ? anyType : value.additionalProperties : null;
1036
1037 if (!allowsAdditional && propertyKeys.length === 0 && patternPropertyKeys.length === 0 && utils.hasProperties(value, 'minProperties', 'maxProperties', 'dependencies', 'required')) {
1038 // just nothing
1039 return {};
1040 }
1041
1042 if (optionAPI('requiredOnly') === true) {
1043 requiredProperties.forEach(function (key) {
1044 if (properties[key]) {
1045 props[key] = properties[key];
1046 }
1047 });
1048 return traverseCallback(props, path.concat(['properties']), resolve);
1049 }
1050
1051 var optionalsProbability = optionAPI('alwaysFakeOptionals') === true ? 1.0 : optionAPI('optionalsProbability');
1052 var fixedProbabilities = optionAPI('fixedProbabilities') || false;
1053 var ignoreProperties = optionAPI('ignoreProperties') || [];
1054 var min = Math.max(value.minProperties || 0, requiredProperties.length);
1055 var max = Math.min(value.maxProperties || allProperties.length, allProperties.length);
1056 var neededExtras = Math.max(0, min - requiredProperties.length);
1057
1058 if (allProperties.length === 1 && !requiredProperties.length) {
1059 neededExtras = random.number(neededExtras, allProperties.length + (max - min));
1060 }
1061
1062 if (optionalsProbability !== false) {
1063 if (fixedProbabilities === true) {
1064 neededExtras = Math.round(min - requiredProperties.length + optionalsProbability * (max - min));
1065 } else {
1066 neededExtras = random.number(min - requiredProperties.length, optionalsProbability * (max - min));
1067 }
1068 }
1069
1070 var extraPropertiesRandomOrder = random.shuffle(optionalProperties).slice(0, neededExtras);
1071 var extraProperties = optionalProperties.filter(function (_item) {
1072 return extraPropertiesRandomOrder.indexOf(_item) !== -1;
1073 }); // properties are read from right-to-left
1074
1075 var _props = requiredProperties.concat(extraProperties).slice(0, max);
1076
1077 var skipped = [];
1078 var missing = [];
1079
1080 _props.forEach(function (key) {
1081 for (var i = 0; i < ignoreProperties.length; i += 1) {
1082 if (ignoreProperties[i] instanceof RegExp && ignoreProperties[i].test(key) || typeof ignoreProperties[i] === 'string' && ignoreProperties[i] === key || typeof ignoreProperties[i] === 'function' && ignoreProperties[i](properties[key], key)) {
1083 skipped.push(key);
1084 return;
1085 }
1086 } // first ones are the required properies
1087
1088
1089 if (properties[key]) {
1090 props[key] = properties[key];
1091 } else {
1092 var found; // then try patternProperties
1093
1094 patternPropertyKeys.forEach(function (_key) {
1095 if (key.match(new RegExp(_key))) {
1096 found = true;
1097 props[random.randexp(key)] = patternProperties[_key];
1098 }
1099 });
1100
1101 if (!found) {
1102 // try patternProperties again,
1103 var subschema = patternProperties[key] || additionalProperties; // FIXME: allow anyType as fallback when no subschema is given?
1104
1105 if (subschema) {
1106 // otherwise we can use additionalProperties?
1107 props[patternProperties[key] ? random.randexp(key) : key] = subschema;
1108 } else {
1109 missing.push(key);
1110 }
1111 }
1112 }
1113 });
1114
1115 var fillProps = optionAPI('fillProperties');
1116 var reuseProps = optionAPI('reuseProperties'); // discard already ignored props if they're not required to be filled...
1117
1118 var current = Object.keys(props).length + (fillProps ? 0 : skipped.length);
1119
1120 function get() {
1121 var one;
1122
1123 do {
1124 one = requiredProperties.shift();
1125 } while (props[one]);
1126
1127 return one;
1128 }
1129
1130 while (fillProps) {
1131 if (!(patternPropertyKeys.length || allowsAdditional)) {
1132 break;
1133 }
1134
1135 if (current >= min) {
1136 break;
1137 }
1138
1139 if (allowsAdditional) {
1140 if (reuseProps && propertyKeys.length - current > min) {
1141 var count = 0;
1142 var key = (void 0);
1143
1144 do {
1145 count += 1; // skip large objects
1146
1147 if (count > 1000) {
1148 break;
1149 }
1150
1151 key = get() || random.pick(propertyKeys);
1152 } while (typeof props[key] !== 'undefined');
1153
1154 if (typeof props[key] === 'undefined') {
1155 props[key] = properties[key];
1156 current += 1;
1157 }
1158 } else if (patternPropertyKeys.length && !additionalProperties) {
1159 var prop = random.pick(patternPropertyKeys);
1160 var word = random.randexp(prop);
1161
1162 if (!props[word]) {
1163 props[word] = patternProperties[prop];
1164 current += 1;
1165 }
1166 } else {
1167 var word$1 = get() || wordsGenerator(1) + random.randexp('[a-f\\d]{1,3}');
1168
1169 if (!props[word$1]) {
1170 props[word$1] = additionalProperties || anyType;
1171 current += 1;
1172 }
1173 }
1174 }
1175
1176 for (var i = 0; current < min && i < patternPropertyKeys.length; i += 1) {
1177 var _key = patternPropertyKeys[i];
1178 var word$2 = random.randexp(_key);
1179
1180 if (!props[word$2]) {
1181 props[word$2] = patternProperties[_key];
1182 current += 1;
1183 }
1184 }
1185 }
1186
1187 if (!allowsAdditional && current < min) {
1188 if (missing.length) {
1189 throw new ParseError(("properties '" + (missing.join(', ')) + "' were not found while additionalProperties is false:\n" + (utils.short(value))), path);
1190 }
1191
1192 throw new ParseError(("properties constraints were too strong to successfully generate a valid object for:\n" + (utils.short(value))), path);
1193 }
1194
1195 return traverseCallback(props, path.concat(['properties']), resolve);
1196}
1197
1198/**
1199 * Helper function used by thunkGenerator to produce some words for the final result.
1200 *
1201 * @returns {string}
1202 */
1203
1204function produce() {
1205 var length = random.number(1, 5);
1206 return wordsGenerator(length).join(' ');
1207}
1208/**
1209 * Generates randomized concatenated string based on words generator.
1210 *
1211 * @returns {string}
1212 */
1213
1214
1215function thunkGenerator(min, max) {
1216 if ( min === void 0 ) min = 0;
1217 if ( max === void 0 ) max = 140;
1218
1219 var _min = Math.max(0, min);
1220
1221 var _max = random.number(_min, max);
1222
1223 var result = produce(); // append until length is reached
1224
1225 while (result.length < _min) {
1226 result += produce();
1227 } // cut if needed
1228
1229
1230 if (result.length > _max) {
1231 result = result.substr(0, _max);
1232 }
1233
1234 return result;
1235}
1236
1237/**
1238 * Generates randomized ipv4 address.
1239 *
1240 * @returns {string}
1241 */
1242
1243function ipv4Generator() {
1244 return [0, 0, 0, 0].map(function () {
1245 return random.number(0, 255);
1246 }).join('.');
1247}
1248
1249/**
1250 * Generates randomized date time ISO format string.
1251 *
1252 * @returns {string}
1253 */
1254
1255function dateTimeGenerator() {
1256 return random.date().toISOString();
1257}
1258
1259/**
1260 * Generates randomized date format string.
1261 *
1262 * @returns {string}
1263 */
1264
1265function dateGenerator() {
1266 return dateTimeGenerator().slice(0, 10);
1267}
1268
1269/**
1270 * Generates randomized time format string.
1271 *
1272 * @returns {string}
1273 */
1274
1275function timeGenerator() {
1276 return dateTimeGenerator().slice(11);
1277}
1278
1279var FRAGMENT = '[a-zA-Z][a-zA-Z0-9+-.]*';
1280var URI_PATTERN = "https?://{hostname}(?:" + FRAGMENT + ")+";
1281var PARAM_PATTERN = '(?:\\?([a-z]{1,7}(=\\w{1,5})?&){0,3})?';
1282/**
1283 * Predefined core formats
1284 * @type {[key: string]: string}
1285 */
1286
1287var regexps = {
1288 email: '[a-zA-Z\\d][a-zA-Z\\d-]{1,13}[a-zA-Z\\d]@{hostname}',
1289 hostname: '[a-zA-Z]{1,33}\\.[a-z]{2,4}',
1290 ipv6: '[a-f\\d]{4}(:[a-f\\d]{4}){7}',
1291 uri: URI_PATTERN,
1292 // types from draft-0[67] (?)
1293 'uri-reference': ("" + URI_PATTERN + PARAM_PATTERN),
1294 'uri-template': URI_PATTERN.replace('(?:', '(?:/\\{[a-z][:a-zA-Z0-9-]*\\}|'),
1295 'json-pointer': ("(/(?:" + (FRAGMENT.replace(']*', '/]*')) + "|~[01]))+"),
1296 // some types from https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types (?)
1297 uuid: '^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$'
1298};
1299regexps.iri = regexps['uri-reference'];
1300regexps['iri-reference'] = regexps['uri-reference'];
1301regexps['idn-email'] = regexps.email;
1302regexps['idn-hostname'] = regexps.hostname;
1303var ALLOWED_FORMATS = new RegExp(("\\{(" + (Object.keys(regexps).join('|')) + ")\\}"));
1304/**
1305 * Generates randomized string basing on a built-in regex format
1306 *
1307 * @param coreFormat
1308 * @returns {string}
1309 */
1310
1311function coreFormatGenerator(coreFormat) {
1312 return random.randexp(regexps[coreFormat]).replace(ALLOWED_FORMATS, function (match, key) {
1313 return random.randexp(regexps[key]);
1314 });
1315}
1316
1317function generateFormat(value, invalid) {
1318 var callback = formatAPI(value.format);
1319
1320 if (typeof callback === 'function') {
1321 return callback(value);
1322 }
1323
1324 switch (value.format) {
1325 case 'date-time':
1326 case 'datetime':
1327 return dateTimeGenerator();
1328
1329 case 'date':
1330 return dateGenerator();
1331
1332 case 'time':
1333 return timeGenerator();
1334
1335 case 'ipv4':
1336 return ipv4Generator();
1337
1338 case 'regex':
1339 // TODO: discuss
1340 return '.+?';
1341
1342 case 'email':
1343 case 'hostname':
1344 case 'ipv6':
1345 case 'uri':
1346 case 'uri-reference':
1347 case 'iri':
1348 case 'iri-reference':
1349 case 'idn-email':
1350 case 'idn-hostname':
1351 case 'json-pointer':
1352 case 'uri-template':
1353 case 'uuid':
1354 return coreFormatGenerator(value.format);
1355
1356 default:
1357 if (typeof callback === 'undefined') {
1358 if (optionAPI('failOnInvalidFormat')) {
1359 throw new Error(("unknown registry key " + (utils.short(value.format))));
1360 } else {
1361 return invalid();
1362 }
1363 }
1364
1365 throw new Error(("unsupported format '" + (value.format) + "'"));
1366 }
1367}
1368
1369function stringType(value) {
1370 // here we need to force type to fix #467
1371 var output = utils.typecast('string', value, function (opts) {
1372 if (value.format) {
1373 return generateFormat(value, function () { return thunkGenerator(opts.minLength, opts.maxLength); });
1374 }
1375
1376 if (value.pattern) {
1377 return random.randexp(value.pattern);
1378 }
1379
1380 return thunkGenerator(opts.minLength, opts.maxLength);
1381 });
1382 return output;
1383}
1384
1385var typeMap = {
1386 boolean: booleanType,
1387 null: nullType,
1388 array: arrayType,
1389 integer: integerType,
1390 number: numberType,
1391 object: objectType,
1392 string: stringType
1393};
1394
1395function traverse(schema, path, resolve, rootSchema) {
1396 schema = resolve(schema, undefined, path);
1397
1398 if (!schema) {
1399 return;
1400 } // default values has higher precedence
1401
1402
1403 if (path[path.length - 1] !== 'properties') {
1404 // example values have highest precedence
1405 if (optionAPI('useExamplesValue') && Array.isArray(schema.examples)) {
1406 // include `default` value as example too
1407 var fixedExamples = schema.examples.concat('default' in schema ? [schema.default] : []);
1408 return utils.typecast(null, schema, function () { return random.pick(fixedExamples); });
1409 }
1410
1411 if (optionAPI('useDefaultValue') && 'default' in schema) {
1412 return schema.default;
1413 }
1414
1415 if ('template' in schema) {
1416 return utils.template(schema.template, rootSchema);
1417 }
1418 }
1419
1420 if (schema.not && typeof schema.not === 'object') {
1421 schema = utils.notValue(schema.not, utils.omitProps(schema, ['not']));
1422 }
1423
1424 if ('const' in schema) {
1425 return schema.const;
1426 }
1427
1428 if (Array.isArray(schema.enum)) {
1429 return utils.typecast(null, schema, function () { return random.pick(schema.enum); });
1430 } // thunks can return sub-schemas
1431
1432
1433 if (typeof schema.thunk === 'function') {
1434 return traverse(schema.thunk(), path, resolve);
1435 }
1436
1437 if (typeof schema.generate === 'function') {
1438 return utils.typecast(null, schema, function () { return schema.generate(rootSchema); });
1439 } // TODO remove the ugly overcome
1440
1441
1442 var type = schema.type;
1443
1444 if (Array.isArray(type)) {
1445 type = random.pick(type);
1446 } else if (typeof type === 'undefined') {
1447 // Attempt to infer the type
1448 type = inferType(schema, path) || type;
1449
1450 if (type) {
1451 schema.type = type;
1452 }
1453 }
1454
1455 if (typeof type === 'string') {
1456 if (!typeMap[type]) {
1457 if (optionAPI('failOnInvalidTypes')) {
1458 throw new ParseError(("unknown primitive " + (utils.short(type))), path.concat(['type']));
1459 } else {
1460 return optionAPI('defaultInvalidTypeProduct');
1461 }
1462 } else {
1463 try {
1464 return typeMap[type](schema, path, resolve, traverse);
1465 } catch (e) {
1466 if (typeof e.path === 'undefined') {
1467 throw new ParseError(e.message, path);
1468 }
1469
1470 throw e;
1471 }
1472 }
1473 }
1474
1475 var copy = {};
1476
1477 if (Array.isArray(schema)) {
1478 copy = [];
1479 }
1480
1481 Object.keys(schema).forEach(function (prop) {
1482 if (typeof schema[prop] === 'object' && prop !== 'definitions') {
1483 copy[prop] = traverse(schema[prop], path.concat([prop]), resolve, copy);
1484 } else {
1485 copy[prop] = schema[prop];
1486 }
1487 });
1488 return copy;
1489}
1490
1491function pick$1(data) {
1492 return Array.isArray(data) ? random.pick(data) : data;
1493}
1494
1495function cycle(data, reverse) {
1496 if (!Array.isArray(data)) {
1497 return data;
1498 }
1499
1500 var value = reverse ? data.pop() : data.shift();
1501
1502 if (reverse) {
1503 data.unshift(value);
1504 } else {
1505 data.push(value);
1506 }
1507
1508 return value;
1509}
1510
1511function resolve(obj, data, values, property) {
1512 if (!obj || typeof obj !== 'object') {
1513 return obj;
1514 }
1515
1516 if (!values) {
1517 values = {};
1518 }
1519
1520 if (!data) {
1521 data = obj;
1522 }
1523
1524 if (Array.isArray(obj)) {
1525 return obj.map(function (x) { return resolve(x, data, values, property); });
1526 }
1527
1528 if (obj.jsonPath) {
1529 var params = typeof obj.jsonPath !== 'object' ? {
1530 path: obj.jsonPath
1531 } : obj.jsonPath;
1532 params.group = obj.group || params.group || property;
1533 params.cycle = obj.cycle || params.cycle || false;
1534 params.reverse = obj.reverse || params.reverse || false;
1535 params.count = obj.count || params.count || 1;
1536 var key = (params.group) + "__" + (params.path);
1537
1538 if (!values[key]) {
1539 if (params.count > 1) {
1540 values[key] = jsonpath.query(data, params.path, params.count);
1541 } else {
1542 values[key] = jsonpath.query(data, params.path);
1543 }
1544 }
1545
1546 if (params.cycle || params.reverse) {
1547 return cycle(values[key], params.reverse);
1548 }
1549
1550 return pick$1(values[key]);
1551 }
1552
1553 Object.keys(obj).forEach(function (k) {
1554 obj[k] = resolve(obj[k], data, values, k);
1555 });
1556 return obj;
1557} // TODO provide types
1558
1559
1560function run(refs, schema, container) {
1561 try {
1562 var result = traverse(schema, [], function reduce(sub, maxReduceDepth, parentSchemaPath) {
1563 if (typeof maxReduceDepth === 'undefined') {
1564 maxReduceDepth = random.number(1, 3);
1565 }
1566
1567 if (!sub) {
1568 return null;
1569 }
1570
1571 if (typeof sub.generate === 'function') {
1572 return sub;
1573 } // cleanup
1574
1575
1576 var _id = sub.$id || sub.id;
1577
1578 if (typeof _id === 'string') {
1579 delete sub.id;
1580 delete sub.$id;
1581 delete sub.$schema;
1582 }
1583
1584 if (typeof sub.$ref === 'string') {
1585 if (sub.$ref === '#') {
1586 delete sub.$ref;
1587 return sub;
1588 }
1589
1590 var ref;
1591
1592 if (sub.$ref.indexOf('#/') === -1) {
1593 ref = refs[sub.$ref] || null;
1594 }
1595
1596 if (sub.$ref.indexOf('#/definitions/') === 0) {
1597 ref = schema.definitions[sub.$ref.split('#/definitions/')[1]] || null;
1598 }
1599
1600 if (typeof ref !== 'undefined') {
1601 if (!ref && optionAPI('ignoreMissingRefs') !== true) {
1602 throw new Error(("Reference not found: " + (sub.$ref)));
1603 }
1604
1605 utils.merge(sub, ref || {});
1606 } // just remove the reference
1607
1608
1609 delete sub.$ref;
1610 return sub;
1611 }
1612
1613 if (Array.isArray(sub.allOf)) {
1614 var schemas = sub.allOf;
1615 delete sub.allOf; // this is the only case where all sub-schemas
1616 // must be resolved before any merge
1617
1618 schemas.forEach(function (subSchema) {
1619 var _sub = reduce(subSchema, maxReduceDepth + 1, parentSchemaPath); // call given thunks if present
1620
1621
1622 utils.merge(sub, typeof _sub.thunk === 'function' ? _sub.thunk() : _sub);
1623 });
1624 }
1625
1626 if (Array.isArray(sub.oneOf || sub.anyOf)) {
1627 var mix = sub.oneOf || sub.anyOf; // test every value from the enum against each-oneOf
1628 // schema, only values that validate once are kept
1629
1630 if (sub.enum && sub.oneOf) {
1631 sub.enum = sub.enum.filter(function (x) { return utils.validate(x, mix); });
1632 }
1633
1634 return {
1635 thunk: function thunk() {
1636 var copy = utils.omitProps(sub, ['anyOf', 'oneOf']);
1637 utils.merge(copy, random.pick(mix));
1638 return copy;
1639 }
1640
1641 };
1642 }
1643
1644 Object.keys(sub).forEach(function (prop) {
1645 if ((Array.isArray(sub[prop]) || typeof sub[prop] === 'object') && !utils.isKey(prop)) {
1646 sub[prop] = reduce(sub[prop], maxReduceDepth, parentSchemaPath.concat(prop));
1647 }
1648 }); // avoid extra calls on sub-schemas, fixes #458
1649
1650 if (parentSchemaPath) {
1651 var lastProp = parentSchemaPath[parentSchemaPath.length - 1];
1652
1653 if (lastProp === 'properties' || lastProp === 'items') {
1654 return sub;
1655 }
1656 }
1657
1658 return container.wrap(sub);
1659 });
1660
1661 if (optionAPI('resolveJsonPath')) {
1662 return resolve(result);
1663 }
1664
1665 return result;
1666 } catch (e) {
1667 if (e.path) {
1668 throw new Error(((e.message) + " in /" + (e.path.join('/'))));
1669 } else {
1670 throw e;
1671 }
1672 }
1673}
1674
1675var container = new Container();
1676
1677function setupKeywords() {
1678 // built-in support
1679 container.define('pattern', random.randexp); // safe auto-increment values
1680
1681 container.define('autoIncrement', function autoIncrement(value, schema) {
1682 if (!this.offset) {
1683 var min = schema.minimum || 1;
1684 var max = min + env.MAX_NUMBER;
1685 var offset = value.initialOffset || schema.initialOffset;
1686 this.offset = offset || random.number(min, max);
1687 }
1688
1689 if (value === true) {
1690 return this.offset++; // eslint-disable-line
1691 }
1692
1693 return schema;
1694 }); // safe-and-sequential dates
1695
1696 container.define('sequentialDate', function sequentialDate(value, schema) {
1697 if (!this.now) {
1698 this.now = random.date();
1699 }
1700
1701 if (value) {
1702 schema = this.now.toISOString();
1703 value = value === true ? 'days' : value;
1704
1705 if (['seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'].indexOf(value) === -1) {
1706 throw new Error(("Unsupported increment by " + (utils.short(value))));
1707 }
1708
1709 this.now.setTime(this.now.getTime() + random.date(value));
1710 }
1711
1712 return schema;
1713 });
1714}
1715
1716function getRefs(refs) {
1717 var $refs = {};
1718
1719 if (Array.isArray(refs)) {
1720 refs.forEach(function (schema) {
1721 $refs[schema.$id || schema.id] = schema;
1722 });
1723 } else {
1724 $refs = refs || {};
1725 }
1726
1727 return $refs;
1728}
1729
1730var jsf = function (schema, refs, cwd) {
1731 console.log('[json-schema-faker] calling JsonSchemaFaker() is deprecated, call either .generate() or .resolve()');
1732
1733 if (cwd) {
1734 console.log('[json-schema-faker] references are only supported by calling .resolve()');
1735 }
1736
1737 return jsf.generate(schema, refs);
1738};
1739
1740jsf.generate = function (schema, refs) {
1741 var $refs = getRefs(refs);
1742 return run($refs, schema, container);
1743};
1744
1745jsf.resolve = function (schema, refs, cwd) {
1746 if (typeof refs === 'string') {
1747 cwd = refs;
1748 refs = {};
1749 } // normalize basedir (browser aware)
1750
1751
1752 cwd = cwd || (typeof process !== 'undefined' ? process.cwd() : '');
1753 cwd = (cwd.replace(/\/+$/, '')) + "/";
1754 var $refs = getRefs(refs); // identical setup as json-schema-sequelizer
1755
1756 var fixedRefs = {
1757 order: 300,
1758 canRead: true,
1759
1760 read: function read(file, callback) {
1761 try {
1762 callback(null, $refs[file.url] || $refs[file.url.split('/').pop()]);
1763 } catch (e) {
1764 callback(e);
1765 }
1766 }
1767
1768 };
1769 return $RefParser.dereference(cwd, schema, {
1770 resolve: {
1771 file: {
1772 order: 100
1773 },
1774 http: {
1775 order: 200
1776 },
1777 fixedRefs: fixedRefs
1778 },
1779 dereference: {
1780 circular: 'ignore'
1781 }
1782 }).then(function (sub) { return run($refs, sub, container); });
1783};
1784
1785setupKeywords();
1786jsf.format = formatAPI;
1787jsf.option = optionAPI;
1788jsf.random = random; // returns itself for chaining
1789
1790jsf.extend = function (name, cb) {
1791 container.extend(name, cb);
1792 return jsf;
1793};
1794
1795jsf.define = function (name, cb) {
1796 container.define(name, cb);
1797 return jsf;
1798};
1799
1800jsf.reset = function (name) {
1801 container.reset(name);
1802 setupKeywords();
1803 return jsf;
1804};
1805
1806jsf.locate = function (name) {
1807 return container.get(name);
1808};
1809
1810jsf.version = '0.5.0-rc16';
1811
1812export default jsf;