jointjs
Version:
JavaScript diagramming library
1,786 lines (1,512 loc) • 66.8 kB
JavaScript
// code is inspired by https://github.com/lodash/lodash
/* eslint-disable no-case-declarations */
// -- helper constants
const argsTag = '[object Arguments]';
const arrayTag = '[object Array]';
const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const funcTag = '[object Function]';
const mapTag = '[object Map]';
const numberTag = '[object Number]';
const nullTag = '[object Null]';
const objectTag = '[object Object]';
const regexpTag = '[object RegExp]';
const setTag = '[object Set]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const undefinedTag = '[object Undefined]';
const weakMapTag = '[object WeakMap]';
const arrayBufferTag = '[object ArrayBuffer]';
const dataViewTag = '[object DataView]';
const float32Tag = '[object Float32Array]';
const float64Tag = '[object Float64Array]';
const int8Tag = '[object Int8Array]';
const int16Tag = '[object Int16Array]';
const int32Tag = '[object Int32Array]';
const uint8Tag = '[object Uint8Array]';
const uint8ClampedTag = '[object Uint8ClampedArray]';
const uint16Tag = '[object Uint16Array]';
const uint32Tag = '[object Uint32Array]';
const CLONEABLE_TAGS = {
[argsTag]: true,
[arrayTag]: true,
[arrayBufferTag]: true,
[dataViewTag]: true,
[boolTag]: true,
[dateTag]: true,
[float32Tag]: true,
[float64Tag]: true,
[int8Tag]: true,
[int16Tag]: true,
[int32Tag]: true,
[mapTag]: true,
[numberTag]: true,
[objectTag]: true,
[regexpTag]: true,
[setTag]: true,
[stringTag]: true,
[symbolTag]: true,
[uint8Tag]: true,
[uint8ClampedTag]: true,
[uint16Tag]: true,
[uint32Tag]: true,
[errorTag]: false,
[funcTag]: false,
[weakMapTag]: false,
};
/** Used to compose unicode character classes. */
const rsAstralRange = '\\ud800-\\udfff';
const rsComboMarksRange = '\\u0300-\\u036f';
const reComboHalfMarksRange = '\\ufe20-\\ufe2f';
const rsComboSymbolsRange = '\\u20d0-\\u20ff';
const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff';
const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff';
const rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;
const rsDingbatRange = '\\u2700-\\u27bf';
const rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff';
const rsMathOpRange = '\\xac\\xb1\\xd7\\xf7';
const rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf';
const rsPunctuationRange = '\\u2000-\\u206f';
const rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000';
const rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde';
const rsVarRange = '\\ufe0e\\ufe0f';
const rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
/** Used to compose unicode capture groups. */
const rsApos = '[\'\u2019]';
const rsBreak = `[${rsBreakRange}]`;
const rsCombo = `[${rsComboRange}]`;
const rsDigit = '\\d';
const rsDingbat = `[${rsDingbatRange}]`;
const rsLower = `[${rsLowerRange}]`;
const rsMisc = `[^${rsAstralRange}${rsBreakRange + rsDigit + rsDingbatRange + rsLowerRange + rsUpperRange}]`;
const rsFitz = '\\ud83c[\\udffb-\\udfff]';
const rsModifier = `(?:${rsCombo}|${rsFitz})`;
const rsNonAstral = `[^${rsAstralRange}]`;
const rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}';
const rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]';
const rsUpper = `[${rsUpperRange}]`;
const rsZWJ = '\\u200d';
/** Used to compose unicode regexes. */
const rsMiscLower = `(?:${rsLower}|${rsMisc})`;
const rsMiscUpper = `(?:${rsUpper}|${rsMisc})`;
const rsOptContrLower = `(?:${rsApos}(?:d|ll|m|re|s|t|ve))?`;
const rsOptContrUpper = `(?:${rsApos}(?:D|LL|M|RE|S|T|VE))?`;
const reOptMod = `${rsModifier}?`;
const rsOptVar = `[${rsVarRange}]?`;
const rsOptJoin = `(?:${rsZWJ}(?:${[rsNonAstral, rsRegional, rsSurrPair].join('|')})${rsOptVar + reOptMod})*`;
const rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])';
const rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])';
const rsSeq = rsOptVar + reOptMod + rsOptJoin;
const rsEmoji = `(?:${[rsDingbat, rsRegional, rsSurrPair].join('|')})${rsSeq}`;
const reUnicodeWords = RegExp([
`${rsUpper}?${rsLower}+${rsOptContrLower}(?=${[rsBreak, rsUpper, '$'].join('|')})`,
`${rsMiscUpper}+${rsOptContrUpper}(?=${[rsBreak, rsUpper + rsMiscLower, '$'].join('|')})`,
`${rsUpper}?${rsMiscLower}+${rsOptContrLower}`,
`${rsUpper}+${rsOptContrUpper}`,
rsOrdUpper,
rsOrdLower,
`${rsDigit}+`,
rsEmoji
].join('|'), 'g');
const LARGE_ARRAY_SIZE = 200;
const HASH_UNDEFINED = '__hash_undefined__';
// Used to match `toStringTag` values of typed arrays
const reTypedTag = /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/;
// Used to compose unicode capture groups
const rsAstral = `[${rsAstralRange}]`;
// Used to compose unicode regexes
const rsNonAstralCombo = `${rsNonAstral}${rsCombo}?`;
const rsSymbol = `(?:${[rsNonAstralCombo, rsCombo, rsRegional, rsSurrPair, rsAstral].join('|')})`;
// Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode)
const reUnicode = RegExp(`${rsFitz}(?=${rsFitz})|${rsSymbol + rsSeq}`, 'g');
const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/;
const reIsPlainProp = /^\w*$/;
const charCodeOfDot = '.'.charCodeAt(0);
const reEscapeChar = /\\(\\)?/g;
const rePropName = RegExp(
// Match anything that isn't a dot or bracket.
'[^.[\\]]+' + '|' +
// Or match property names within brackets.
'\\[(?:' +
// Match a non-string expression.
'([^"\'][^[]*)' + '|' +
// Or match strings (supports escaping characters).
'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' +
')\\]'+ '|' +
// Or match "" as the space between consecutive dots or empty brackets.
'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))'
, 'g');
const reIsUint = /^(?:0|[1-9]\d*)$/;
const hasUnicodeWord = RegExp.prototype.test.bind(
/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/
);
const MAX_ARRAY_INDEX = 4294967295 - 1;
/** Used to match words composed of alphanumeric characters. */
// eslint-disable-next-line no-control-regex
const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
// -- helper functions
const hasUnicode = (string) => {
return reUnicode.test(string);
};
const unicodeToArray = (string) => {
return string.match(reUnicode) || [];
};
const asciiToArray = (string) => {
return string.split('');
};
const stringToArray = (string) => {
return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string);
};
const values = (object) => {
if (object == null) {
return [];
}
return keys(object).map((key) => object[key]);
};
const keys = (object) => {
return isArrayLike(object) ? arrayLikeKeys(object) : Object.keys(Object(object));
};
const baseKeys = (object) => {
if (!isPrototype(object)) {
return Object.keys(object);
}
var result = [];
for (var key in Object(object)) {
if (hasOwnProperty.call(object, key) && key != 'constructor') {
result.push(key);
}
}
return result;
};
const arrayLikeKeys = (value, inherited) => {
const isArr = Array.isArray(value);
const isArg = !isArr && isObjectLike(value) && getTag(value) === argsTag;
const isType = !isArr && !isArg && isTypedArray(value);
const skipIndexes = isArr || isArg || isType;
const length = value.length;
const result = new Array(skipIndexes ? length : 0);
let index = skipIndexes ? -1 : length;
while (++index < length) {
result[index] = `${index}`;
}
for (const key in value) {
if ((inherited || hasOwnProperty.call(value, key)) &&
!(skipIndexes && (
// Safari 9 has enumerable `arguments.length` in strict mode.
key === 'length' ||
// Skip index properties.
isIndex(key, length)
))
) {
result.push(key);
}
}
return result;
};
const assocIndexOf = (array, key) => {
let { length } = array;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
};
const eq = (value, other) => {
return value === other || (value !== value && other !== other);
};
const isObjectLike = (value) => {
return value != null && typeof value == 'object';
};
const isIterateeCall = (value, index, object) => {
if (!isObject(object)) {
return false;
}
const type = typeof index;
const isPossibleIteratee = type == 'number' ?
(isArrayLike(object) && index > -1 && index < object.length) :
(type == 'string' && index in object);
if (isPossibleIteratee) {
return eq(object[index], value);
}
return false;
};
const isSet = (value) => {
return isObjectLike(value) && getTag(value) == setTag;
};
const isMap = (value) => {
return isObjectLike(value) && getTag(value) == mapTag;
};
const isPrototype = (value) => {
const Ctor = value && value.constructor;
const proto = (typeof Ctor === 'function' && Ctor.prototype) || Object.prototype;
return value === proto;
};
const assignValue = (object, key, value) => {
const objValue = object[key];
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
(value === undefined && !(key in object))) {
object[key] = value;
}
};
const copyObject = (source, props, object) => {
let index = -1;
const length = props.length;
while (++index < length) {
const key = props[index];
assignValue(object, key, source[key]);
}
return object;
};
const isArrayLike = (value) => {
return value != null && typeof value !== 'function' && typeof value.length === 'number' &&
value.length > -1 && value.length % 1 === 0;
};
const isSymbol = (value) => {
return typeof value == 'symbol' ||
(isObjectLike(value) && getTag(value) === symbolTag);
};
const initCloneArray = (array) => {
const length = array.length;
let result = new array.constructor(length);
if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
result.index = array.index;
result.input = array.input;
}
return result;
};
const copyArray = (source, array) => {
let index = -1;
const length = source.length;
array || (array = new Array(length));
while (++index < length) {
array[index] = source[index];
}
return array;
};
const getTag = (value) => {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return Object.prototype.toString.call(value);
};
const cloneArrayBuffer = (arrayBuffer) => {
const result = new arrayBuffer.constructor(arrayBuffer.byteLength);
new Uint8Array(result).set(new Uint8Array(arrayBuffer));
return result;
};
const cloneTypedArray = (typedArray, isDeep) => {
const buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
};
const cloneRegExp = (regexp) =>{
const result = new regexp.constructor(regexp.source, /\w*$/.exec(regexp));
result.lastIndex = regexp.lastIndex;
return result;
};
const initCloneObject = (object) => {
return (typeof object.constructor == 'function' && !isPrototype(object))
? Object.create(Object.getPrototypeOf(object))
: {};
};
const getSymbols = (object) => {
if (object == null) {
return [];
}
object = Object(object);
const symbols = Object.getOwnPropertySymbols(object);
return symbols.filter((symbol) => propertyIsEnumerable.call(object, symbol));
};
const copySymbols = (source, object) => {
return copyObject(source, getSymbols(source), object);
};
function cloneDataView(dataView, isDeep) {
const buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
}
const initCloneByTag = (object, tag, isDeep) => {
const Constructor = object.constructor;
switch(tag) {
case arrayBufferTag:
return cloneArrayBuffer(object, isDeep);
case boolTag:
case dateTag:
return new Constructor(+object);
case dataViewTag:
return cloneDataView(object, isDeep);
case float32Tag:
case float64Tag:
case int8Tag:
case int16Tag:
case int32Tag:
case uint8Tag:
case uint8ClampedTag:
case uint16Tag:
case uint32Tag:
return cloneTypedArray(object, isDeep);
case mapTag:
return new Constructor(object);
case numberTag:
case stringTag:
return new Constructor(object);
case regexpTag:
return cloneRegExp(object);
case setTag:
return new Constructor;
case symbolTag:
return Symbol.prototype.valueOf ? Object(Symbol.prototype.valueOf.call(object)) : {};
}
};
const isTypedArray = (value) => {
return isObjectLike(value) && reTypedTag.test(getTag(value));
};
const getAllKeys = (object) => {
const result = Object.keys(object);
if(!Array.isArray(object) && object != null) {
result.push(...getSymbols(Object(object)));
}
return result;
};
const getSymbolsIn = (object) => {
const result = [];
while (object) {
result.push(...getSymbols(object));
object = Object.getPrototypeOf(Object(object));
}
return result;
};
const getAllKeysIn = (object) => {
const result = [];
for (const key in object) {
result.push(key);
}
if (!Array.isArray(object)) {
result.push(...getSymbolsIn(object));
}
return result;
};
const getMapData = ({ __data__ }, key) => {
const data = __data__;
return isKeyable(key)
? data[typeof key === 'string' ? 'string' : 'hash']
: data.map;
};
const equalObjects = (object, other, equalFunc, stack) => {
const objProps = getAllKeys(object);
const objLength = objProps.length;
const othProps = getAllKeys(other);
const othLength = othProps.length;
if (objLength != othLength) {
return false;
}
let key;
let index = objLength;
while (index--) {
key = objProps[index];
if (!(hasOwnProperty.call(other, key))) {
return false;
}
}
const objStacked = stack.get(object);
const othStacked = stack.get(other);
if (objStacked && othStacked) {
return objStacked == other && othStacked == object;
}
let result = true;
stack.set(object, other);
stack.set(other, object);
let compared;
let skipCtor;
while (++index < objLength) {
key = objProps[index];
const objValue = object[key];
const othValue = other[key];
if (!(compared === undefined
? (objValue === othValue || equalFunc(objValue, othValue, stack))
: compared
)) {
result = false;
break;
}
skipCtor || (skipCtor = key == 'constructor');
}
if (result && !skipCtor) {
const objCtor = object.constructor;
const othCtor = other.constructor;
if (objCtor != othCtor &&
('constructor' in object && 'constructor' in other) &&
!(typeof objCtor === 'function' && objCtor instanceof objCtor &&
typeof othCtor === 'function' && othCtor instanceof othCtor)) {
result = false;
}
}
stack['delete'](object);
stack['delete'](other);
return result;
};
const baseIsEqual = (value, other, stack) => {
if (value === other) {
return true;
}
if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
return value !== value && other !== other;
}
return baseIsEqualDeep(value, other, baseIsEqual, stack);
};
const baseIsEqualDeep = (object, other, equalFunc, stack) => {
let objIsArr = Array.isArray(object);
const othIsArr = Array.isArray(other);
let objTag = objIsArr ? arrayTag : getTag(object);
let othTag = othIsArr ? arrayTag : getTag(other);
objTag = objTag == argsTag ? objectTag : objTag;
othTag = othTag == argsTag ? objectTag : othTag;
let objIsObj = objTag == objectTag;
const othIsObj = othTag == objectTag;
const isSameTag = objTag == othTag;
if (isSameTag && !objIsObj) {
stack || (stack = new Stack);
return (objIsArr || isTypedArray(object))
? equalArrays(object, other, false, equalFunc, stack)
: equalByTag(object, other, objTag, equalFunc, stack);
}
const objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__');
const othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
if (objIsWrapped || othIsWrapped) {
const objUnwrapped = objIsWrapped ? object.value() : object;
const othUnwrapped = othIsWrapped ? other.value() : other;
stack || (stack = new Stack);
return equalFunc(objUnwrapped, othUnwrapped, stack);
}
if (!isSameTag) {
return false;
}
stack || (stack = new Stack);
return equalObjects(object, other, equalFunc, stack);
};
const equalArrays = (array, other, compareUnordered, equalFunc, stack) => {
const isPartial = false;
const arrLength = array.length;
const othLength = other.length;
if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
return false;
}
// Assume cyclic values are equal.
const arrStacked = stack.get(array);
const othStacked = stack.get(other);
if (arrStacked && othStacked) {
return arrStacked == other && othStacked == array;
}
let index = -1;
let result = true;
const seen = compareUnordered ? new SetCache : undefined;
stack.set(array, other);
stack.set(other, array);
while (++index < arrLength) {
let compared;
const arrValue = array[index];
const othValue = other[index];
if (compared !== undefined) {
if (compared) {
continue;
}
result = false;
break;
}
if (seen) {
if (!some(other, (othValue, othIndex) => {
if (!cacheHas(seen, othIndex) &&
(arrValue === othValue || equalFunc(arrValue, othValue, stack))) {
return seen.push(othIndex);
}
})) {
result = false;
break;
}
} else if (!(
arrValue === othValue ||
equalFunc(arrValue, othValue, stack)
)) {
result = false;
break;
}
}
stack['delete'](array);
stack['delete'](other);
return result;
};
const some = (array, predicate) => {
let index = -1;
const length = array == null ? 0 : array.length;
while (++index < length) {
if (predicate(array[index], index, array)) {
return true;
}
}
return false;
};
const cacheHas = (cache, key) => {
return cache.has(key);
};
const compareArrayBufferTag = (object, other, equalFunc, stack) => {
if ((object.byteLength != other.byteLength) ||
!equalFunc(new Uint8Array(object), new Uint8Array(other), stack)) {
return false;
}
return true;
};
const equalByTag = (object, other, tag, equalFunc, stack) => {
switch (tag) {
case dataViewTag:
if ((object.byteLength != other.byteLength) ||
(object.byteOffset != other.byteOffset)) {
return false;
}
object = object.buffer;
other = other.buffer;
return compareArrayBufferTag(object, other, equalFunc, stack);
case arrayBufferTag:
return compareArrayBufferTag(object, other, equalFunc, stack);
case boolTag:
case dateTag:
case numberTag:
return eq(+object, +other);
case errorTag:
return object.name == other.name && object.message == other.message;
case regexpTag:
case stringTag:
return object == `${other}`;
case mapTag:
let convert = mapToArray;
// Intentional fallthrough
// eslint-disable-next-line no-fallthrough
case setTag:
convert || (convert = setToArray);
if (object.size != other.size) {
return false;
}
// Assume cyclic values are equal.
const stacked = stack.get(object);
if (stacked) {
return stacked == other;
}
// Recursively compare objects (susceptible to call stack limits).
stack.set(object, other);
const result = equalArrays(convert(object), convert(other), true, equalFunc, stack);
stack['delete'](object);
return result;
case symbolTag:
return Symbol.prototype.valueOf.call(object) == Symbol.prototype.valueOf.call(other);
}
return false;
};
const mapToArray = (map) => {
let index = -1;
let result = Array(map.size);
map.forEach((value, key) => {
result[++index] = [key, value];
});
return result;
};
const setToArray = (set) => {
let index = -1;
const result = new Array(set.size);
set.forEach((value) => {
result[++index] = value;
});
return result;
};
const isKey = (value, object) => {
if (Array.isArray(value)) {
return false;
}
const type = typeof value;
if (type === 'number' || type === 'boolean' || value == null || isSymbol(value)) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
};
const stringToPath = (string) => {
const result = [];
if (string.charCodeAt(0) === charCodeOfDot) {
result.push('');
}
string.replace(rePropName, (match, expression, quote, subString) => {
let key = match;
if (quote) {
key = subString.replace(reEscapeChar, '$1');
}
else if (expression) {
key = expression.trim();
}
result.push(key);
});
return result;
};
const castPath = (path, object) => {
if (Array.isArray(path)) {
return path;
}
return isKey(path, object) ? [path] : stringToPath(`${path}`);
};
const get = (object, path) => {
path = castPath(path, object);
let index = 0;
const length = path.length;
while (object != null && index < length) {
object = object[toKey(path[index])];
index++;
}
return (index && index == length) ? object : undefined;
};
function compareAscending(value, other) {
if (value !== other) {
const valIsDefined = value !== undefined;
const valIsNull = value === null;
const valIsReflexive = value === value;
const valIsSymbol = isSymbol(value);
const othIsDefined = other !== undefined;
const othIsNull = other === null;
const othIsReflexive = other === other;
const othIsSymbol = isSymbol(other);
if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
(valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
(valIsNull && othIsDefined && othIsReflexive) ||
(!valIsDefined && othIsReflexive) ||
!valIsReflexive) {
return 1;
}
if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
(othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
(othIsNull && valIsDefined && valIsReflexive) ||
(!othIsDefined && valIsReflexive) ||
!othIsReflexive) {
return -1;
}
}
return 0;
}
function compareMultiple(object, other, orders) {
let index = -1;
const objCriteria = object.criteria;
const othCriteria = other.criteria;
const length = objCriteria.length;
const ordersLength = orders.length;
while (++index < length) {
const order = index < ordersLength ? orders[index] : null;
const cmpFn = (order && typeof order === 'function') ? order : compareAscending;
const result = cmpFn(objCriteria[index], othCriteria[index]);
if (result) {
if (order && typeof order !== 'function') {
return result * (order == 'desc' ? -1 : 1);
}
return result;
}
}
return object.index - other.index;
}
const diff = (array, values) => {
let includes = (array, value) => {
const length = array == null ? 0 : array.length;
return !!length && array.indexOf(value) > -1;
};
let isCommon = true;
const result = [];
const valuesLength = values.length;
if (!array.length) {
return result;
}
if (values.length >= LARGE_ARRAY_SIZE) {
includes = (cache, key) => cache.has(key);
isCommon = false;
values = new SetCache(values);
}
outer:
for (let key in array) {
let value = array[key];
const computed = value;
value = (value !== 0) ? value : 0;
if (isCommon && computed === computed) {
let valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed)) {
result.push(value);
}
}
return result;
};
const intersect = (arrays) => {
const includes = (array, value) => {
const length = array == null ? 0 : array.length;
return !!length && array.indexOf(value) > -1;
};
const cacheHas = (cache, key) => cache.has(key);
const length = arrays[0].length;
const othLength = arrays.length;
const caches = new Array(othLength);
const result = [];
let array;
let maxLength = Infinity;
let othIndex = othLength;
while (othIndex--) {
array = arrays[othIndex];
maxLength = Math.min(array.length, maxLength);
caches[othIndex] = length >= 120 && array.length >= 120
? new SetCache(othIndex && array)
: undefined;
}
array = arrays[0];
let index = -1;
const seen = caches[0];
outer:
while (++index < length && result.length < maxLength) {
let value = array[index];
const computed = value;
value = (value !== 0) ? value : 0;
if (!(seen
? cacheHas(seen, computed)
: includes(result, computed)
)) {
othIndex = othLength;
while (--othIndex) {
const cache = caches[othIndex];
if (!(cache
? cacheHas(cache, computed)
: includes(arrays[othIndex], computed))
) {
continue outer;
}
}
if (seen) {
seen.push(computed);
}
result.push(value);
}
}
return result;
};
const toKey = (value) => {
if (typeof value === 'string' || isSymbol(value)) {
return value;
}
const result = `${value}`;
return (result == '0' && (1 / value) == -Infinity) ? '-0' : result;
};
const baseClone = (value, isDeep = false, isFlat = false, isFull = true, customizer, key, object, stack) => {
let result;
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value);
}
if (result !== undefined) {
return result;
}
if (!isObject(value)) {
return value;
}
const isArr = Array.isArray(value);
const tag = getTag(value);
if (isArr) {
result = initCloneArray(value);
if (!isDeep) {
return copyArray(value, result);
}
} else {
const isFunc = typeof value === 'function';
if (tag === objectTag || tag === argsTag || (isFunc && !object)) {
result = (isFlat || isFunc) ? {} : initCloneObject(value);
if (!isDeep) {
return isFlat ?
copySymbolsIn(value, copyObject(value, Object.keys(value), result)) :
copySymbols(value, Object.assign(result, value));
}
} else {
if (isFunc || !CLONEABLE_TAGS[tag]) {
return object ? value : {};
}
result = initCloneByTag(value, tag, isDeep);
}
}
stack || (stack = new Stack);
const stacked = stack.get(value);
if (stacked) {
return stacked;
}
stack.set(value, result);
if (isMap(value)) {
value.forEach((subValue, key) => {
result.set(key, baseClone(subValue, isDeep, isFlat, isFull, customizer, key, value, stack));
});
return result;
}
if (isSet(value)) {
value.forEach(subValue => {
result.add(baseClone(subValue, isDeep, isFlat, isFull, customizer, subValue, value, stack));
});
return result;
}
if(isTypedArray(value)) {
return result;
}
const keysFunc = isFull
? (isFlat ? getAllKeysIn : getAllKeys)
: (isFlat ? keysIn : keys);
const props = isArr ? undefined : keysFunc(value);
(props || value).forEach((subValue, key) => {
if (props) {
key = subValue;
subValue = value[key];
}
assignValue(result, key, baseClone(subValue, isDeep, isFlat, isFull, customizer, key, value, stack));
});
return result;
};
const copySymbolsIn = (source, object) => {
return copyObject(source, getSymbolsIn(source), object);
};
const parent = (object, path) => {
return path.length < 2 ? object : get(object, path.slice(0, -1));
};
const set = (object, path, value) => {
if (!isObject(object)) {
return object;
}
path = castPath(path, object);
const length = path.length;
const lastIndex = length - 1;
let index = -1;
let nested = object;
while (nested != null && ++index < length) {
const key = toKey(path[index]);
let newValue = value;
if (index != lastIndex) {
const objValue = nested[key];
newValue = undefined;
if (newValue === undefined) {
newValue = isObject(objValue)
? objValue
: (isIndex(path[index + 1]) ? [] : {});
}
}
assignValue(nested, key, newValue);
nested = nested[key];
}
return object;
};
const isIndex = (value, length) => {
const type = typeof value;
length = length == null ? Number.MAX_SAFE_INTEGER : length;
return !!length &&
(type === 'number' ||
(type !== 'symbol' && reIsUint.test(value))) &&
(value > -1 && value % 1 == 0 && value < length);
};
const unset = (object, path) => {
path = castPath(path, object);
object = parent(object, path);
const lastSegment = path[path.length - 1];
return object == null || delete object[toKey(lastSegment)];
};
const isKeyable = (value) => {
const type = typeof value;
return (type === 'string' || type === 'number' || type === 'symbol' || type === 'boolean')
? (value !== '__proto__')
: (value === null);
};
const keysIn = (object) => {
const result = [];
for (const key in object) {
result.push(key);
}
return result;
};
const toPlainObject = (value) => {
value = Object(value);
const result = {};
for (const key in value) {
result[key] = value[key];
}
return result;
};
const safeGet = (object, key) => {
if (key === 'constructor' && typeof object[key] === 'function') {
return;
}
if (key == '__proto__') {
return;
}
return object[key];
};
function createAssigner(assigner, isMerge = false) {
return (object, ...sources) => {
let index = -1;
let length = sources.length;
let customizer = length > 1 ? sources[length - 1] : undefined;
const guard = length > 2 ? sources[2] : undefined;
customizer = (assigner.length > 3 && typeof customizer === 'function')
? (length--, customizer)
: isMerge ? (a, b) => {
if (Array.isArray(a) && !Array.isArray(b)) {
return b;
}
} : undefined;
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
customizer = length < 3 ? undefined : customizer;
length = 1;
}
object = Object(object);
while (++index < length) {
const source = sources[index];
if (source) {
assigner(object, source, index, customizer);
}
}
return object;
};
}
const baseMerge = (object, source, srcIndex, customizer, stack) => {
if (object === source) {
return;
}
forIn(source, (srcValue, key) => {
if (isObject(srcValue)) {
stack || (stack = new Stack);
baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
} else {
let newValue = customizer
? customizer(object[key], srcValue, `${key}`, object, source, stack)
: undefined;
if (newValue === undefined) {
newValue = srcValue;
}
assignMergeValue(object, key, newValue);
}
}, keysIn);
};
const baseMergeDeep = (object, source, key, srcIndex, mergeFunc, customizer, stack) => {
const objValue = safeGet(object, key);
const srcValue = safeGet(source, key);
const stacked = stack.get(srcValue);
if (stacked) {
assignMergeValue(object, key, stacked);
return;
}
let newValue = customizer
? customizer(objValue, srcValue, `${key}`, object, source, stack)
: undefined;
let isCommon = newValue === undefined;
if (isCommon) {
const isArr = Array.isArray(srcValue);
const isTyped = !isArr && isTypedArray(srcValue);
newValue = srcValue;
if (isArr || isTyped) {
if (Array.isArray(objValue)) {
newValue = objValue;
}
else if (isObjectLike(objValue) && isArrayLike(objValue)) {
newValue = copyArray(objValue);
}
else if (isTyped) {
isCommon = false;
newValue = cloneTypedArray(srcValue, true);
}
else {
newValue = [];
}
}
else if (isPlainObject(srcValue) || isArguments(srcValue)) {
newValue = objValue;
if (isArguments(objValue)) {
newValue = toPlainObject(objValue);
}
else if (typeof objValue === 'function' || !isObject(objValue)) {
newValue = initCloneObject(srcValue);
}
}
else {
isCommon = false;
}
}
if (isCommon) {
// Recursively merge objects and arrays (susceptible to call stack limits).
stack.set(srcValue, newValue);
mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
stack['delete'](srcValue);
}
assignMergeValue(object, key, newValue);
};
const assignMergeValue = (object, key, value) => {
if ((value !== undefined && !eq(object[key], value)) ||
(value === undefined && !(key in object))) {
assignValue(object, key, value);
}
};
function baseFor(object, iteratee, keysFunc) {
const iterable = Object(object);
const props = keysFunc(object);
let { length } = props;
let index = -1;
while (length--) {
const key = props[++index];
if (iteratee(iterable[key], key, iterable) === false) {
break;
}
}
return object;
}
const baseForOwn = (object, iteratee) => {
return object && baseFor(object, iteratee, keys);
};
const baseEach = (collection, iteratee) => {
if (collection == null) {
return collection;
}
if (!isArrayLike(collection)) {
return baseForOwn(collection, iteratee);
}
const length = collection.length;
const iterable = Object(collection);
let index = -1;
while (++index < length) {
if (iteratee(iterable[index], index, iterable) === false) {
break;
}
}
return collection;
};
function last(array) {
const length = array == null ? 0 : array.length;
return length ? array[length - 1] : undefined;
}
const createSet = (Set && (1 / setToArray(new Set([undefined,-0]))[1]) == 1 / 0)
? (values) => new Set(values)
: () => {};
function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
if (isObject(objValue) && isObject(srcValue)) {
// Recursively merge objects and arrays (susceptible to call stack limits).
stack.set(srcValue, objValue);
baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
stack['delete'](srcValue);
}
return objValue;
}
function baseOrderBy(collection, iteratees, orders) {
if (iteratees.length) {
iteratees = iteratees.map((iteratee) => {
if (Array.isArray(iteratee)) {
return (value) => get(value, iteratee.length === 1 ? iteratee[0] : iteratee);
}
return iteratee;
});
} else {
iteratees = [(value) => value];
}
let criteriaIndex = -1;
let eachIndex = -1;
const result = isArrayLike(collection) ? new Array(collection.length) : [];
baseEach(collection, (value) => {
const criteria = iteratees.map((iteratee) => iteratee(value));
result[++eachIndex] = {
criteria,
index: ++criteriaIndex,
value
};
});
return baseSortBy(result, (object, other) => compareMultiple(object, other, orders));
}
function baseSortBy(array, comparer) {
let { length } = array;
array.sort(comparer);
while (length--) {
array[length] = array[length].value;
}
return array;
}
function isStrictComparable(value) {
return value === value && !isObject(value);
}
function matchesStrictComparable(key, srcValue) {
return (object) => {
if (object == null) {
return false;
}
return object[key] === srcValue &&
(srcValue !== undefined || (key in Object(object)));
};
}
function hasIn(object, path) {
return object != null && hasPath(object, path, baseHasIn);
}
function baseMatchesProperty(path, srcValue) {
if (isKey(path) && isStrictComparable(srcValue)) {
return matchesStrictComparable(toKey(path), srcValue);
}
return (object) => {
const objValue = get(object, path);
return (objValue === undefined && objValue === srcValue)
? hasIn(object, path)
: baseIsEqual(srcValue, objValue);
};
}
function baseMatches(source) {
const matchData = getMatchData(source);
if (matchData.length === 1 && matchData[0][2]) {
return matchesStrictComparable(matchData[0][0], matchData[0][1]);
}
return (object) => object === source || baseIsMatch(object, source, matchData);
}
function getMatchData(object) {
const result = keys(object);
let length = result.length;
while (length--) {
const key = result[length];
const value = object[key];
result[length] = [key, value, isStrictComparable(value)];
}
return result;
}
function baseIsMatch(object, source, matchData, customizer) {
let index = matchData.length;
const length = index;
const noCustomizer = !customizer;
if (object == null) {
return !length;
}
let data;
let result;
object = Object(object);
while (index--) {
data = matchData[index];
if ((noCustomizer && data[2])
? data[1] !== object[data[0]]
: !(data[0] in object)
) {
return false;
}
}
while (++index < length) {
data = matchData[index];
const key = data[0];
const objValue = object[key];
const srcValue = data[1];
if (noCustomizer && data[2]) {
if (objValue === undefined && !(key in object)) {
return false;
}
} else {
const stack = new Stack;
if (customizer) {
result = customizer(objValue, srcValue, key, object, source, stack);
}
if (!(result === undefined
? baseIsEqual(srcValue, objValue, stack)
: result
)) {
return false;
}
}
}
return true;
}
function property(path) {
return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
}
function baseProperty(key) {
return (object) => object == null ? undefined : object[key];
}
function basePropertyDeep(path) {
return (object) => get(object, path);
}
function baseIteratee(value) {
if (typeof value == 'function') {
return value;
}
if (value == null) {
return (val) => val;
}
if (typeof value == 'object') {
return Array.isArray(value)
? baseMatchesProperty(value[0], value[1])
: baseMatches(value);
}
return property(value);
}
function getIteratee() {
const result = baseIteratee;
return arguments.length ? result(arguments[0], arguments[1]) : result;
}
const arrayReduce = (array, iteratee, accumulator, initAccum) => {
let index = -1;
const length = array == null ? 0 : array.length;
if (initAccum && length) {
accumulator = array[++index];
}
while (++index < length) {
accumulator = iteratee(accumulator, array[index], index, array);
}
return accumulator;
};
const baseReduce = (collection, iteratee, accumulator, initAccum, eachFunc) => {
eachFunc(collection, (value, index, collection) => {
accumulator = initAccum
? (initAccum = false, value)
: iteratee(accumulator, value, index, collection);
});
return accumulator;
};
function reduce(collection, iteratee, accumulator) {
const func = Array.isArray(collection) ? arrayReduce : baseReduce;
const initAccum = arguments.length < 3;
return func(collection, iteratee, accumulator, initAccum, baseEach);
}
const isFlattenable = (value) => {
return Array.isArray(value) || isArguments(value) ||
!!(value && value[Symbol.isConcatSpreadable]);
};
function baseFlatten(array, depth, predicate, isStrict, result) {
let index = -1;
const length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
result.push(...value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
const isArguments = (value) => {
return isObjectLike(value) && getTag(value) == '[object Arguments]';
};
const basePick = (object, paths) => {
return basePickBy(object, paths, (value, path) => hasIn(object, path));
};
const basePickBy = (object, paths, predicate) => {
let index = -1;
const length = paths.length;
const result = {};
while (++index < length) {
const path = paths[index];
const value = get(object, path);
if (predicate(value, path)) {
set(result, castPath(path, object), value);
}
}
return result;
};
const isLength = (value) => {
return typeof value == 'number' &&
value > -1 && value % 1 == 0 && value <= Number.MAX_SAFE_INTEGER;
};
const baseHasIn = (object, key) =>{
return object != null && key in Object(object);
};
const hasPath = (object, path, hasFunc) => {
path = castPath(path, object);
var index = -1,
length = path.length,
result = false;
while (++index < length) {
var key = toKey(path[index]);
if (!(result = object != null && hasFunc(object, key))) {
break;
}
object = object[key];
}
if (result || ++index != length) {
return result;
}
length = object == null ? 0 : object.length;
return !!length && isLength(length) && isIndex(key, length) &&
(Array.isArray(object) || isArguments(object));
};
const asciiWords = (string) => {
return string.match(reAsciiWord);
};
const unicodeWords = (string) => {
return string.match(reUnicodeWords);
};
const words = (string, pattern) => {
if (pattern === undefined) {
const result = hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
return result || [];
}
return string.match(pattern) || [];
};
const castSlice = (array, start, end) => {
const { length } = array;
end = end === undefined ? length : end;
return (!start && end >= length) ? array : array.slice(start, end);
};
const upperFirst = createCaseFirst('toUpperCase');
function createCaseFirst(methodName) {
return (string) => {
if (!string) {
return '';
}
const strSymbols = hasUnicode(string)
? stringToArray(string)
: undefined;
const chr = strSymbols
? strSymbols[0]
: string[0];
const trailing = strSymbols
? castSlice(strSymbols, 1).join('')
: string.slice(1);
return chr[methodName]() + trailing;
};
}
// -- helper classes
class Stack {
constructor(entries) {
const data = this.__data__ = new ListCache(entries);
this.size = data.size;
}
clear() {
this.__data__ = new ListCache;
this.size = 0;
}
delete(key) {
const data = this.__data__;
const result = data['delete'](key);
this.size = data.size;
return result;
}
get(key) {
return this.__data__.get(key);
}
has(key) {
return this.__data__.has(key);
}
set(key, value) {
let data = this.__data__;
if (data instanceof ListCache) {
const pairs = data.__data__;
if (pairs.length < LARGE_ARRAY_SIZE - 1) {
pairs.push([key, value]);
this.size = ++data.size;
return this;
}
data = this.__data__ = new MapCache(pairs);
}
data.set(key, value);
this.size = data.size;
return this;
}
}
class ListCache {
constructor(entries) {
let index = -1;
const length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
const entry = entries[index];
this.set(entry[0], entry[1]);
}
}
clear() {
this.__data__ = [];
this.size = 0;
}
delete(key) {
const data = this.__data__;
const index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
const lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
data.splice(index, 1);
}
--this.size;
return true;
}
get(key) {
const data = this.__data__;
const index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
has(key) {
return assocIndexOf(this.__data__, key) > -1;
}
set(key, value) {
const data = this.__data__;
const index = assocIndexOf(data, key);
if (index < 0) {
++this.size;
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
}
class MapCache {
constructor(entries) {
let index = -1;
const length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
const entry = entries[index];
this.set(entry[0], entry[1]);
}
}
clear() {
this.size = 0;
this.__data__ = {
'hash': new Hash,
'map': new Map,
'string': new Hash
};
}
delete(key) {
const result = getMapData(this, key)['delete'](key);
this.size -= result ? 1 : 0;
return result;
}
get(key) {
return getMapData(this, key).get(key);
}
has(key) {
return getMapData(this, key).has(key);
}
set(key, value) {
const data = getMapData(this, key);
const size = data.size;
data.set(key, value);
this.size += data.size == size ? 0 : 1;
return this;
}
}
class Hash {
constructor(entries) {
let index = -1;
const length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
const entry = entries[index];
this.set(entry[0], entry[1]);
}
}
clear() {
this.__data__ = Object.create(null);
this.size = 0;
}
delete(key) {
con