Skip to content
Snippets Groups Projects
json-schema-faker.js 758 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * json-schema-faker library v0.5.0-rc15
    
     * http://json-schema-faker.js.org
     *
    
     * Copyright (c) 2014-2018 Alvaro Cabrera & Tomasz Ducin
    
     * Released under the MIT license
     *
    
    Alvaro Cabrera's avatar
    Alvaro Cabrera committed
     * Date: 2018-04-09 17:23:23.954Z
    
    Alvaro Cabrera's avatar
    Alvaro Cabrera committed
    (function (global, factory) {
    
        typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
        typeof define === 'function' && define.amd ? define(factory) :
        (global.JSONSchemaFaker = factory());
    
    Alvaro Cabrera's avatar
    Alvaro Cabrera committed
    }(this, (function () { 'use strict';
    
        /*! *****************************************************************************
        Copyright (c) Microsoft Corporation. All rights reserved.
        Licensed under the Apache License, Version 2.0 (the "License"); you may not use
        this file except in compliance with the License. You may obtain a copy of the
        License at http://www.apache.org/licenses/LICENSE-2.0
    
        THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
        WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
        MERCHANTABLITY OR NON-INFRINGEMENT.
    
        See the Apache Version 2.0 License for specific language governing permissions
        and limitations under the License.
        ***************************************************************************** */
        /* global Reflect, Promise */
    
        var extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    
        function __extends(d, b) {
            extendStatics(d, b);
            function __() { this.constructor = d; }
            d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
        }
    
        var __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
    
        function __rest(s, e) {
            var t = {};
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
                t[p] = s[p];
            if (s != null && typeof Object.getOwnPropertySymbols === "function")
                for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
                    t[p[i]] = s[p[i]];
            return t;
        }
    
        function __decorate(decorators, target, key, desc) {
            var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
            if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
            else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
            return c > 3 && r && Object.defineProperty(target, key, r), r;
        }
    
        function __param(paramIndex, decorator) {
            return function (target, key) { decorator(target, key, paramIndex); }
        }
    
        function __metadata(metadataKey, metadataValue) {
            if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
        }
    
        function __awaiter(thisArg, _arguments, P, generator) {
            return new (P || (P = Promise))(function (resolve, reject) {
                function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
                function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
                function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
                step((generator = generator.apply(thisArg, _arguments || [])).next());
            });
        }
    
        function __generator(thisArg, body) {
            var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
            return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
            function verb(n) { return function (v) { return step([n, v]); }; }
            function step(op) {
                if (f) throw new TypeError("Generator is already executing.");
                while (_) try {
                    if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
                    if (y = 0, t) op = [0, t.value];
                    switch (op[0]) {
                        case 0: case 1: t = op; break;
                        case 4: _.label++; return { value: op[1], done: false };
                        case 5: _.label++; y = op[1]; op = [0]; continue;
                        case 7: op = _.ops.pop(); _.trys.pop(); continue;
                        default:
                            if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                            if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                            if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                            if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                            if (t[2]) _.ops.pop();
                            _.trys.pop(); continue;
                    }
                    op = body.call(thisArg, _);
                } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
                if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
            }
        }
    
        function __exportStar(m, exports) {
            for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
        }
    
        function __values(o) {
            var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
            if (m) return m.call(o);
            return {
                next: function () {
                    if (o && i >= o.length) o = void 0;
                    return { value: o && o[i++], done: !o };
                }
            };
        }
    
        function __read(o, n) {
            var m = typeof Symbol === "function" && o[Symbol.iterator];
            if (!m) return o;
            var i = m.call(o), r, ar = [], e;
            try {
                while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
            }
            catch (error) { e = { error: error }; }
            finally {
                try {
                    if (r && !r.done && (m = i["return"])) m.call(i);
                }
                finally { if (e) throw e.error; }
            }
            return ar;
        }
    
        function __spread() {
            for (var ar = [], i = 0; i < arguments.length; i++)
                ar = ar.concat(__read(arguments[i]));
            return ar;
        }
    
        function __await(v) {
            return this instanceof __await ? (this.v = v, this) : new __await(v);
        }
    
        function __asyncGenerator(thisArg, _arguments, generator) {
            if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
            var g = generator.apply(thisArg, _arguments || []), i, q = [];
            return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
            function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
            function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
            function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);  }
            function fulfill(value) { resume("next", value); }
            function reject(value) { resume("throw", value); }
            function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
        }
    
        function __asyncDelegator(o) {
            var i, p;
            return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
            function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; }
        }
    
        function __asyncValues(o) {
            if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
            var m = o[Symbol.asyncIterator];
            return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator]();
        }
    
        function __makeTemplateObject(cooked, raw) {
            if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
            return cooked;
        }
    
        var tslib_es6 = /*#__PURE__*/Object.freeze({
            __extends: __extends,
            __assign: __assign,
            __rest: __rest,
            __decorate: __decorate,
            __param: __param,
            __metadata: __metadata,
            __awaiter: __awaiter,
            __generator: __generator,
            __exportStar: __exportStar,
            __values: __values,
            __read: __read,
            __spread: __spread,
            __await: __await,
            __asyncGenerator: __asyncGenerator,
            __asyncDelegator: __asyncDelegator,
            __asyncValues: __asyncValues,
            __makeTemplateObject: __makeTemplateObject
        });
    
        var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
    
        function commonjsRequire () {
        	throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
        }
    
        function createCommonjsModule(fn, module) {
        	return module = { exports: {} }, fn(module, module.exports), module.exports;
        }
    
        var types = {
          ROOT       : 0,
          GROUP      : 1,
          POSITION   : 2,
          SET        : 3,
          RANGE      : 4,
          REPETITION : 5,
          REFERENCE  : 6,
          CHAR       : 7,
        };
    
        var INTS = function() {
         return [{ type: types.RANGE , from: 48, to: 57 }];
        };
    
        var WORDS = function() {
         return [
            { type: types.CHAR, value: 95 },
            { type: types.RANGE, from: 97, to: 122 },
            { type: types.RANGE, from: 65, to: 90 }
          ].concat(INTS());
        };
    
        var WHITESPACE = function() {
         return [
            { type: types.CHAR, value: 9 },
            { type: types.CHAR, value: 10 },
            { type: types.CHAR, value: 11 },
            { type: types.CHAR, value: 12 },
            { type: types.CHAR, value: 13 },
            { type: types.CHAR, value: 32 },
            { type: types.CHAR, value: 160 },
            { type: types.CHAR, value: 5760 },
            { type: types.CHAR, value: 6158 },
            { type: types.CHAR, value: 8192 },
            { type: types.CHAR, value: 8193 },
            { type: types.CHAR, value: 8194 },
            { type: types.CHAR, value: 8195 },
            { type: types.CHAR, value: 8196 },
            { type: types.CHAR, value: 8197 },
            { type: types.CHAR, value: 8198 },
            { type: types.CHAR, value: 8199 },
            { type: types.CHAR, value: 8200 },
            { type: types.CHAR, value: 8201 },
            { type: types.CHAR, value: 8202 },
            { type: types.CHAR, value: 8232 },
            { type: types.CHAR, value: 8233 },
            { type: types.CHAR, value: 8239 },
            { type: types.CHAR, value: 8287 },
            { type: types.CHAR, value: 12288 },
            { type: types.CHAR, value: 65279 }
          ];
        };
    
        var NOTANYCHAR = function() {
          return [
            { type: types.CHAR, value: 10 },
            { type: types.CHAR, value: 13 },
            { type: types.CHAR, value: 8232 },
            { type: types.CHAR, value: 8233 },
          ];
        };
    
        // Predefined class objects.
        var words = function() {
          return { type: types.SET, set: WORDS(), not: false };
        };
    
        var notWords = function() {
          return { type: types.SET, set: WORDS(), not: true };
        };
    
        var ints = function() {
          return { type: types.SET, set: INTS(), not: false };
        };
    
        var notInts = function() {
          return { type: types.SET, set: INTS(), not: true };
        };
    
        var whitespace = function() {
          return { type: types.SET, set: WHITESPACE(), not: false };
        };
    
        var notWhitespace = function() {
          return { type: types.SET, set: WHITESPACE(), not: true };
        };
    
        var anyChar = function() {
          return { type: types.SET, set: NOTANYCHAR(), not: true };
        };
    
        var sets = {
        	words: words,
        	notWords: notWords,
        	ints: ints,
        	notInts: notInts,
        	whitespace: whitespace,
        	notWhitespace: notWhitespace,
        	anyChar: anyChar
        };
    
        var util = createCommonjsModule(function (module, exports) {
        // All of these are private and only used by randexp.
        // It's assumed that they will always be called with the correct input.
    
        var CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?';
        var SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 };
    
        /**
         * Finds character representations in str and convert all to
         * their respective characters
         *
         * @param {String} str
         * @return {String}
         */
        exports.strToChars = function(str) {
          /* jshint maxlen: false */
          var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z\[\\\]\^?])|([0tnvfr]))/g;
          str = str.replace(chars_regex, function(s, b, lbs, a16, b16, c8, dctrl, eslsh) {
            if (lbs) {
              return s;
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
            }
    
    
            var code = b     ? 8 :
                       a16   ? parseInt(a16, 16) :
                       b16   ? parseInt(b16, 16) :
                       c8    ? parseInt(c8,   8) :
                       dctrl ? CTRL.indexOf(dctrl) :
                       SLSH[eslsh];
    
            var c = String.fromCharCode(code);
    
            // Escape special regex characters.
            if (/[\[\]{}\^$.|?*+()]/.test(c)) {
              c = '\\' + c;
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
            }
    
    Alvaro Cabrera's avatar
    Alvaro Cabrera committed
          });
    
        /**
         * turns class into tokens
         * reads str until it encounters a ] not preceeded by a \
         *
         * @param {String} str
         * @param {String} regexpStr
         * @return {Array.<Array.<Object>, Number>}
         */
        exports.tokenizeClass = function(str, regexpStr) {
          /* jshint maxlen: false */
          var tokens = [];
          var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?(.)/g;
          var rs, c;
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
          while ((rs = regexp.exec(str)) != null) {
            if (rs[1]) {
              tokens.push(sets.words());
    
            } else if (rs[2]) {
              tokens.push(sets.ints());
    
            } else if (rs[3]) {
              tokens.push(sets.whitespace());
    
            } else if (rs[4]) {
              tokens.push(sets.notWords());
    
            } else if (rs[5]) {
              tokens.push(sets.notInts());
    
            } else if (rs[6]) {
              tokens.push(sets.notWhitespace());
    
            } else if (rs[7]) {
              tokens.push({
                type: types.RANGE,
                from: (rs[8] || rs[9]).charCodeAt(0),
                  to: rs[10].charCodeAt(0),
              });
    
            } else if (c = rs[12]) {
              tokens.push({
                type: types.CHAR,
                value: c.charCodeAt(0),
              });
    
            } else {
              return [tokens, regexp.lastIndex];
            }
    
          exports.error(regexpStr, 'Unterminated character class');
        };
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
        /**
         * Shortcut to throw errors.
         *
         * @param {String} regexp
         * @param {String} msg
         */
        exports.error = function(regexp, msg) {
          throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg);
        };
        });
        var util_1 = util.strToChars;
        var util_2 = util.tokenizeClass;
        var util_3 = util.error;
    
        var wordBoundary = function() {
          return { type: types.POSITION, value: 'b' };
        };
    
        var nonWordBoundary = function() {
          return { type: types.POSITION, value: 'B' };
        };
    
        var begin = function() {
          return { type: types.POSITION, value: '^' };
        };
    
        var end = function() {
          return { type: types.POSITION, value: '$' };
        };
    
        var positions = {
        	wordBoundary: wordBoundary,
        	nonWordBoundary: nonWordBoundary,
        	begin: begin,
        	end: end
        };
    
        var lib = function(regexpStr) {
          var i = 0, l, c,
              start = { type: types.ROOT, stack: []},
    
              // Keep track of last clause/group and stack.
              lastGroup = start,
              last = start.stack,
              groupStack = [];
    
          var repeatErr = function(i) {
            util.error(regexpStr, 'Nothing to repeat at column ' + (i - 1));
          };
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
          // Decode a few escaped characters.
          var str = util.strToChars(regexpStr);
          l = str.length;
    
          // Iterate through each character in string.
          while (i < l) {
            c = str[i++];
    
            switch (c) {
              // Handle escaped characters, inclues a few sets.
              case '\\':
                c = str[i++];
    
                switch (c) {
                  case 'b':
                    last.push(positions.wordBoundary());
                    break;
    
                  case 'B':
                    last.push(positions.nonWordBoundary());
                    break;
    
                  case 'S':
                    last.push(sets.notWhitespace());
                    break;
    
                  default:
                    // Check if c is integer.
                    // In which case it's a reference.
                    if (/\d/.test(c)) {
                      last.push({ type: types.REFERENCE, value: parseInt(c, 10) });
    
                    // Escaped character.
                    } else {
                      last.push({ type: types.CHAR, value: c.charCodeAt(0) });
                    }
                }
    
              // Positionals.
              case '^':
                  last.push(positions.begin());
                break;
    
              // Handle custom sets.
              case '[':
                // Check if this class is 'anti' i.e. [^abc].
                var not;
                if (str[i] === '^') {
                  not = true;
                  i++;
                } else {
                  not = false;
                }
    
                // Get all the characters in class.
                var classTokens = util.tokenizeClass(str.slice(i), regexpStr);
    
                // Increase index by length of class.
                i += classTokens[1];
                last.push({
                  type: types.SET,
                  set: classTokens[0],
                  not: not,
                });
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
              // Class of any character except \n.
              case '.':
                last.push(sets.anyChar());
                break;
    
              // Push group onto stack.
              case '(':
                // Create group.
                var group = {
                  type: types.GROUP,
                  stack: [],
                  remember: true,
                };
    
    Alvaro Cabrera's avatar
    Alvaro Cabrera committed
    
    
                // If if this is a special kind of group.
                if (c === '?') {
                  c = str[i + 1];
                  i += 2;
    
                  // Match if followed by.
                  if (c === '=') {
                    group.followedBy = true;
    
                  // Match if not followed by.
                  } else if (c === '!') {
                    group.notFollowedBy = true;
    
                  } else if (c !== ':') {
                    util.error(regexpStr,
                      'Invalid group, character \'' + c +
                      '\' after \'?\' at column ' + (i - 1));
                  }
    
                // Insert subgroup into current group stack.
                last.push(group);
    
                // Remember the current group for when the group closes.
                groupStack.push(lastGroup);
    
                // Make this new group the current group.
                lastGroup = group;
                last = group.stack;
                break;
    
              // Pop group out of stack.
              case ')':
                if (groupStack.length === 0) {
                  util.error(regexpStr, 'Unmatched ) at column ' + (i - 1));
                }
                lastGroup = groupStack.pop();
    
                // Check if this group has a PIPE.
                // To get back the correct last stack.
                last = lastGroup.options ?
                  lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack;
                break;
    
              // Use pipe character to give more choices.
              case '|':
                // Create array where options are if this is the first PIPE
                // in this clause.
                if (!lastGroup.options) {
                  lastGroup.options = [lastGroup.stack];
                  delete lastGroup.stack;
                }
    
                // Create a new stack and add to options for rest of clause.
                var stack = [];
                lastGroup.options.push(stack);
                last = stack;
                break;
    
              // Repetition.
              // For every repetition, remove last element from last stack
              // then insert back a RANGE object.
              // This design is chosen because there could be more than
              // one repetition symbols in a regex i.e. `a?+{2,3}`.
              case '{':
                var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)), min, max;
                if (rs !== null) {
                  if (last.length === 0) {
                    repeatErr(i);
                  }
                  min = parseInt(rs[1], 10);
                  max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min;
                  i += rs[0].length;
    
                  last.push({
                    type: types.REPETITION,
                    min: min,
                    max: max,
                    value: last.pop(),
                  });
                } else {
                  last.push({
                    type: types.CHAR,
                    value: 123,
                  });
                }
                break;
    
              case '?':
                if (last.length === 0) {
                  repeatErr(i);
                }
                last.push({
                  type: types.REPETITION,
                  min: 0,
                  max: 1,
                  value: last.pop(),
                });
                break;
    
              case '+':
                if (last.length === 0) {
                  repeatErr(i);
                }
                last.push({
                  type: types.REPETITION,
                  min: 1,
                  max: Infinity,
                  value: last.pop(),
                });
                break;
    
              case '*':
                if (last.length === 0) {
                  repeatErr(i);
                }
                last.push({
                  type: types.REPETITION,
                  min: 0,
                  max: Infinity,
                  value: last.pop(),
                });
                break;
    
              // Default is a character that is not `\[](){}?+*^$`.
              default:
                last.push({
                  type: types.CHAR,
                  value: c.charCodeAt(0),
                });
            }
    
    
          // Check if any groups have not been closed.
          if (groupStack.length !== 0) {
            util.error(regexpStr, 'Unterminated group');
    
        var types_1$1 = types;
        lib.types = types_1$1;
    
        //protected helper class
        function _SubRange(low, high) {
            this.low = low;
            this.high = high;
            this.length = 1 + high - low;
        }
    
        _SubRange.prototype.overlaps = function (range) {
            return !(this.high < range.low || this.low > range.high);
        };
    
        _SubRange.prototype.touches = function (range) {
            return !(this.high + 1 < range.low || this.low - 1 > range.high);
        };
    
        //returns inclusive combination of _SubRanges as a _SubRange
        _SubRange.prototype.add = function (range) {
            return this.touches(range) && new _SubRange(Math.min(this.low, range.low), Math.max(this.high, range.high));
        };
    
        //returns subtraction of _SubRanges as an array of _SubRanges (there's a case where subtraction divides it in 2)
        _SubRange.prototype.subtract = function (range) {
            if (!this.overlaps(range)) return false;
            if (range.low <= this.low && range.high >= this.high) return [];
            if (range.low > this.low && range.high < this.high) return [new _SubRange(this.low, range.low - 1), new _SubRange(range.high + 1, this.high)];
            if (range.low <= this.low) return [new _SubRange(range.high + 1, this.high)];
            return [new _SubRange(this.low, range.low - 1)];
    
        _SubRange.prototype.toString = function () {
            if (this.low == this.high) return this.low.toString();
            return this.low + '-' + this.high;
        };
    
        _SubRange.prototype.clone = function () {
            return new _SubRange(this.low, this.high);
        };
    
    
        function DiscontinuousRange(a, b) {
            if (this instanceof DiscontinuousRange) {
                this.ranges = [];
                this.length = 0;
                if (a !== undefined) this.add(a, b);
            } else {
                return new DiscontinuousRange(a, b);
            }
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
        }
    
        function _update_length(self) {
            self.length = self.ranges.reduce(function (previous, range) {return previous + range.length}, 0);
        }
    
        DiscontinuousRange.prototype.add = function (a, b) {
            var self = this;
            function _add(subrange) {
                var new_ranges = [];
                var i = 0;
                while (i < self.ranges.length && !subrange.touches(self.ranges[i])) {
                    new_ranges.push(self.ranges[i].clone());
                    i++;
                }
                while (i < self.ranges.length && subrange.touches(self.ranges[i])) {
                    subrange = subrange.add(self.ranges[i]);
                    i++;
                }
                new_ranges.push(subrange);
                while (i < self.ranges.length) {
                    new_ranges.push(self.ranges[i].clone());
                    i++;
                }
                self.ranges = new_ranges;
                _update_length(self);
            }
    
            if (a instanceof DiscontinuousRange) {
                a.ranges.forEach(_add);
            } else {
                if (a instanceof _SubRange) {
                    _add(a);
                } else {
                    if (b === undefined) b = a;
                    _add(new _SubRange(a, b));
                }
            }
            return this;
        };
    
        DiscontinuousRange.prototype.subtract = function (a, b) {
            var self = this;
            function _subtract(subrange) {
                var new_ranges = [];
                var i = 0;
                while (i < self.ranges.length && !subrange.overlaps(self.ranges[i])) {
                    new_ranges.push(self.ranges[i].clone());
                    i++;
                }
                while (i < self.ranges.length && subrange.overlaps(self.ranges[i])) {
                    new_ranges = new_ranges.concat(self.ranges[i].subtract(subrange));
                    i++;
                }
                while (i < self.ranges.length) {
                    new_ranges.push(self.ranges[i].clone());
                    i++;
                }
                self.ranges = new_ranges;
                _update_length(self);
            }
            if (a instanceof DiscontinuousRange) {
                a.ranges.forEach(_subtract);
            } else {
                if (a instanceof _SubRange) {
                    _subtract(a);
                } else {
                    if (b === undefined) b = a;
                    _subtract(new _SubRange(a, b));
                }
            }
            return this;
        };
    
    
        DiscontinuousRange.prototype.index = function (index) {
            var i = 0;
            while (i < this.ranges.length && this.ranges[i].length <= index) {
                index -= this.ranges[i].length;
                i++;
            }
            if (i >= this.ranges.length) return null;
            return this.ranges[i].low + index;
        };
    
    
        DiscontinuousRange.prototype.toString = function () {
            return '[ ' + this.ranges.join(', ') + ' ]'
        };
    
        DiscontinuousRange.prototype.clone = function () {
            return new DiscontinuousRange(this);
        };
    
        var discontinuousRange = DiscontinuousRange;
    
        var randexp = createCommonjsModule(function (module) {
        var types = lib.types;
    
    
        /**
         * If code is alphabetic, converts to other case.
         * If not alphabetic, returns back code.
         *
         * @param {Number} code
         * @return {Number}
         */
        function toOtherCase(code) {
          return code + (97 <= code && code <= 122 ? -32 :
                         65 <= code && code <= 90  ?  32 : 0);
        }
    
    
        /**
         * Randomly returns a true or false value.
         *
         * @return {Boolean}
         */
        function randBool() {
          return !this.randInt(0, 1);
        }
    
    
        /**
         * Randomly selects and returns a value from the array.
         *
         * @param {Array.<Object>} arr
         * @return {Object}
         */
        function randSelect(arr) {
          if (arr instanceof discontinuousRange) {
            return arr.index(this.randInt(0, arr.length - 1));
    
          return arr[this.randInt(0, arr.length - 1)];
        }
    
    
        /**
         * expands a token to a DiscontinuousRange of characters which has a
         * length and an index function (for random selecting)
         *
         * @param {Object} token
         * @return {DiscontinuousRange}
         */
        function expand(token) {
          if (token.type === lib.types.CHAR) {
            return new discontinuousRange(token.value);
          } else if (token.type === lib.types.RANGE) {
            return new discontinuousRange(token.from, token.to);
          } else {
            var drange = new discontinuousRange();
            for (var i = 0; i < token.set.length; i++) {
              var subrange = expand.call(this, token.set[i]);
              drange.add(subrange);
              if (this.ignoreCase) {
                for (var j = 0; j < subrange.length; j++) {
                  var code = subrange.index(j);
                  var otherCaseCode = toOtherCase(code);
                  if (code !== otherCaseCode) {
                    drange.add(otherCaseCode);
                  }
                }
              }
            }
            if (token.not) {
              return this.defaultRange.clone().subtract(drange);
            } else {
              return drange;
            }
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
        }
    
    
        /**
         * Checks if some custom properties have been set for this regexp.
         *
         * @param {RandExp} randexp
         * @param {RegExp} regexp
         */
        function checkCustom(randexp, regexp) {
          if (typeof regexp.max === 'number') {
            randexp.max = regexp.max;
    
          if (regexp.defaultRange instanceof discontinuousRange) {
            randexp.defaultRange = regexp.defaultRange;
          }
          if (typeof regexp.randInt === 'function') {
            randexp.randInt = regexp.randInt;
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
        }
    
    Tomasz Ducin's avatar
    Tomasz Ducin committed
    
    
        /**
         * @constructor
         * @param {RegExp|String} regexp
         * @param {String} m
         */
        var RandExp = module.exports = function(regexp, m) {
          this.defaultRange = this.defaultRange.clone();
          if (regexp instanceof RegExp) {
            this.ignoreCase = regexp.ignoreCase;
            this.multiline = regexp.multiline;
            checkCustom(this, regexp);
            regexp = regexp.source;
    
          } else if (typeof regexp === 'string') {
            this.ignoreCase = m && m.indexOf('i') !== -1;
            this.multiline = m && m.indexOf('m') !== -1;
          } else {
            throw new Error('Expected a regexp or string');
          }
    
        // When a repetitional token has its max set to Infinite,
        // randexp won't actually generate a random amount between min and Infinite
        // instead it will see Infinite as min + 100.
        RandExp.prototype.max = 100;