js-utl
Version:
A collection of JS utility functions to be used across several applications or libraries.
1,493 lines (1,365 loc) • 244 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("JSUtl", [], factory);
else if(typeof exports === 'object')
exports["JSUtl"] = factory();
else
root["JSUtl"] = factory();
})((typeof self !== 'undefined' ? self : this), function() {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/modules/array.js":
/*!******************************!*\
!*** ./src/modules/array.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "unshiftArray": () => (/* binding */ unshiftArray),
/* harmony export */ "cloneArray": () => (/* binding */ cloneArray),
/* harmony export */ "arraySliceFromValueToValue": () => (/* binding */ arraySliceFromValueToValue),
/* harmony export */ "areArrayItemsAllCoercibleToNumber": () => (/* binding */ areArrayItemsAllCoercibleToNumber),
/* harmony export */ "arrayOrArrayLike": () => (/* binding */ arrayOrArrayLike),
/* harmony export */ "lastOfArray": () => (/* binding */ lastOfArray),
/* harmony export */ "firstOfArray": () => (/* binding */ firstOfArray),
/* harmony export */ "arrayFindReverse": () => (/* binding */ arrayFindReverse),
/* harmony export */ "arrayMax": () => (/* binding */ arrayMax),
/* harmony export */ "arrayMin": () => (/* binding */ arrayMin),
/* harmony export */ "sortNums": () => (/* binding */ sortNums)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Array-related utility functions.
*/
/**
* Unshifts an array.
*
* @param {Array} arr The array.
* @param {*} item The item to unshift.
* @return {undefined}
*/
function unshiftArray(arr, item) {
let len = arr.length;
while (len) {
arr[len] = arr[len - 1];
len--;
}
arr[0] = item;
}
/**
* Clones an array.
*
* @param {Array} arr The array to clone.
* @return {Array} The cloned array.
*/
function cloneArray(arr) {
return arr.slice(0);
}
/**
* Gets a slice of an array from a value up until another.
*
* @param {Array} arr The input array.
* @param {number} from The "from" lower value.
* @param {number} to The "two" upper value.
* @return {Array} The slice as a new array.
*/
function arraySliceFromValueToValue(arr, from, to) {
const ret = [];
let include = false;
for (const value of arr) {
if (!include && value == from) {
ret.push(value);
include = true;
} else if (include && value == to) {
ret.push(value);
break;
} else if (include) {
ret.push(value);
}
}
return ret;
}
/**
* Tests whether all the elements of an array are coercible to a number or not.
*
* @param {Array} array An array.
* @return {boolean} True if all the elements are coercible to a number, false otherwise.
*/
function areArrayItemsAllCoercibleToNumber(array) {
const res = !array.some(isNaN);
return res;
}
/**
* Copies an array or converts an array-like object to a new array.
*
* @param {*} arg Array or array-like object.
* @return {Array} An array.
*/
function arrayOrArrayLike(arg) {
return Array.prototype.slice.call(arg);
}
/**
* Returns the last element of the given array.
*
* @param {Array} array An array.
* @return {*} The last element of the array or undefined if there isn't one.
*/
function lastOfArray(array) {
return array[array.length - 1];
}
/**
* Returns the first element of the given array.
*
* @param {Array} array An array.
* @return {*} The first element of the array or undefined if there isn't one.
*/
function firstOfArray(array) {
return array[0];
}
/**
* Like {@link Array.prototype.find}, but in reverse order.
*
* @param {Array} array An array.
* @param {Function} fn Function to use for the test. The function will receive the array element as parameter.
* @return {*} The first element which satisfies the test in the array by seeking for the element in reverse order
* (i.e. the last element of the array for which the test is satisfied).
* If no element satisfies the test, "undefined" is returned.
*/
function arrayFindReverse(array, fn) {
let l = array.length;
let ret = void 0;
while (l) {
l--;
if (fn(array[l])) {
ret = array[l];
break;
}
}
return ret;
}
/**
* Finds the maximum value of an array of numbers.
*
* @param {number[]} array An array of numbers.
* @return {number|undefined} The maximum value of the array, or "undefined"
* if the given array is empty.
*/
const arrayMax = array =>
array.length
? array.reduce(
(carry, current) => (current > carry ? current : carry),
-Infinity
)
: void 0;
/**
* Finds the minimum value of an array of numbers.
*
* @param {number[]} array An array of numbers.
* @return {number|undefined} The minimum value of the array, or "undefined"
* if the given array is empty.
*/
const arrayMin = array =>
array.length
? array.reduce(
(carry, current) => (current < carry ? current : carry),
+Infinity
)
: void 0;
/**
* Sorts an array of numbers returning a new array with the sorted
* numbers (does not mutate the original).
*
* @param {number[]} arrayOfNums An array of numbers.
* @param {boolean} [desc] True for descending order, false for ascending order (default).
* @return {number[]} A new array with the sorted numbers.
*/
const sortNums = (arrayOfNums, desc = false) =>
[...arrayOfNums].sort((a, b) =>
!desc // asc
? a - b
: // desc
b - a
);
/***/ }),
/***/ "./src/modules/bitwise.js":
/*!********************************!*\
!*** ./src/modules/bitwise.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "turnNthBitOff": () => (/* binding */ turnNthBitOff),
/* harmony export */ "turnNthBitOn": () => (/* binding */ turnNthBitOn),
/* harmony export */ "toggleNthBit": () => (/* binding */ toggleNthBit),
/* harmony export */ "checkNthBitOn": () => (/* binding */ checkNthBitOn)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Bitwise utility functions.
*/
/**
* Turns nth bit off.
*
* @param {number} num A number.
* @param {number} nth Nth bit to turn off (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit turned off.
*/
const turnNthBitOff = (num, nth) => num & ~(1 << (nth - 1));
/**
* Turns nth bit on.
*
* @param {number} num A number.
* @param {number} nth Nth bit to turn on (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit turned off.
*/
const turnNthBitOn = (num, nth) => num | (1 << (nth - 1));
/**
* Toggles nth bit.
*
* @param {number} num A number.
* @param {number} nth Nth bit to toggle (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit toggled.
*/
const toggleNthBit = (num, nth) => num ^ (1 << (nth - 1));
/**
* Checks if nth bit is on.
*
* @param {number} num A number.
* @param {number} nth Nth bit to check.
* @param {number} 0 if the nth bit is off, otherwise a number greater than 0 if the nth bit is on.
*/
const checkNthBitOn = (num, nth) => num & (1 << (nth - 1));
/***/ }),
/***/ "./src/modules/callback.js":
/*!*********************************!*\
!*** ./src/modules/callback.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "delay": () => (/* binding */ delay),
/* harmony export */ "debounce": () => (/* binding */ debounce),
/* harmony export */ "throttle": () => (/* binding */ throttle)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions for callback handling (like debouncing, throttling).
*/
/**
* Delays execution of a callback and cancels a previously registered callback if it wasn't executed yet.
*/
const delay = (function () {
let timer = 0;
/**
* Inner function.
*
* @param {Function} callback The callback to execute.
* @param {number} ms Milliseconds to wait before executing the callback.
* @return {undefined}
*/
return function (callback, ms) {
clearTimeout(timer);
timer = setTimeout(function () {
callback();
}, ms);
};
})();
/**
* Debounces a function.
*
* @param {Function} fn A function.
* @param {number} wait Wait interval in milliseconds.
* @return {Function} A new function, debounced.
*/
function debounce(fn, wait) {
let timer = void 0;
return function (...args) {
!(0,_core__WEBPACK_IMPORTED_MODULE_0__.isUndefined)(timer) && clearTimeout(timer);
timer = setTimeout(function () {
fn(...args);
}, wait);
};
}
/**
* Throttles a function.
*
* @see https://www.sitepoint.com/throttle-scroll-events/
*
* @param {Function} fn A function.
* @param {number} wait Wait interval in milliseconds.
* @return {Function} A new function, throttled.
*/
function throttle(fn, wait) {
let time = Date.now();
return function (...args) {
if (time + wait - Date.now() < 0) {
fn(...args);
time = Date.now();
}
};
}
/***/ }),
/***/ "./src/modules/color.js":
/*!******************************!*\
!*** ./src/modules/color.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "getLuminance": () => (/* binding */ getLuminance),
/* harmony export */ "intToRGBHexString": () => (/* binding */ intToRGBHexString),
/* harmony export */ "colorFromString": () => (/* binding */ colorFromString)
/* harmony export */ });
/* harmony import */ var _hash__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./hash */ "./src/modules/hash.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Color-related utility functions.
*/
/**
* Gets a color's luminance.
*
* @param {number} color Color int value (RGB).
* @return {number} An int greater than 160 if the color is considered dark and less than or
* equal to 160 if the color is considered light.
*/
function getLuminance(color) {
const c = parseInt(color, 16);
const r = (c & 0xff0000) >> 16;
const g = (c & 0x00ff00) >> 8;
const b = c & 0x0000ff;
return 0.299 * r + 0.587 * g + 0.114 * b;
}
/**
* Converts an integer to an RGB hex (hexadecimal) string.
*
* @param {number} i An integer.
* @return {string} An RGB hex string (uppercase).
*/
function intToRGBHexString(i) {
const c = (i & 0x00ffffff).toString(16).toUpperCase();
return "00000".substring(0, 6 - c.length) + c;
}
/**
* Converts a string to an RGB hex (hexadecimal) string representing a color.
*
* @param {string} str The string.
* @return {string} The color as an RGB hex string (uppercase).
*/
const colorFromString = str => {
const hash = (0,_hash__WEBPACK_IMPORTED_MODULE_0__.hashString)(str);
return intToRGBHexString(hash);
};
/***/ }),
/***/ "./src/modules/combinatorics.js":
/*!**************************************!*\
!*** ./src/modules/combinatorics.js ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "yieldCombinationsWithoutRepetition": () => (/* binding */ yieldCombinationsWithoutRepetition),
/* harmony export */ "uniqueProgressiveIncrementalCombinations": () => (/* binding */ uniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldUniqueProgressiveIncrementalCombinations": () => (/* binding */ yieldUniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldAllSubsequences": () => (/* binding */ yieldAllSubsequences),
/* harmony export */ "yieldUniqueSubsequences": () => (/* binding */ yieldUniqueSubsequences),
/* harmony export */ "yieldPermutations": () => (/* binding */ yieldPermutations)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./array */ "./src/modules/array.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Combinatorics utility functions.
*/
/**
* Yields all the combinations of an array without repetitions (binomial coefficient).
*
* @generator
* @param {Array} items An array.
* @param {number} numberOfItemsPerCombination The number of elements in each combination
* (this function assumes it to be less than "items.length"
* and greater than 0).
* @param {boolean} yieldCopy True if the yielded combination should be a copy (default) or
* the internal array used during the generation of the current combination.
* @yields {Array} The next combination.
*/
const yieldCombinationsWithoutRepetition = function* (
items,
numberOfItemsPerCombination,
yieldCopy = true
) {
const l = items.length;
const prefix = [];
const recurse = function* recurse(
items,
l,
prefix,
numberOfItemsPerCombination,
nextIndex = 0
) {
// Same as:
// if (nextIndex === numberOfItemsPerCombination) {
if (prefix.length === numberOfItemsPerCombination) {
// Base case:
yield yieldCopy ? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(prefix) : prefix;
} else {
// Recurrent case:
for (
let i = nextIndex;
i < l &&
// Remaining needed items
numberOfItemsPerCombination - prefix.length <=
// Remaining available items
l - i;
i++
) {
prefix.push(items[i]);
yield* recurse(items, l, prefix, numberOfItemsPerCombination, i + 1);
prefix.pop();
}
}
};
yield* recurse(items, l, prefix, numberOfItemsPerCombination);
};
/**
* Generate unique, progressive and incremental combinations.
*
* @param {Array} items An array of items.
* @return {Array[]} An array of arrays, each representing a unique progressive incremental combination.
* An empty array is returned if the given items array is empty.
*/
const uniqueProgressiveIncrementalCombinations = items => {
const len = items.length;
if (len === 0) {
return [];
}
const last = (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(items); // Shallow copy/clone of the given array.
if (len === 1) {
// [1] => [[1]]
return [last];
}
const ret = [];
// [1], [2], [3], ..., [n]
items.map(item => ret.push([item]));
if (len > 2) {
// There are at least three items.
for (
let numberOfItemsPerCombination = 2;
numberOfItemsPerCombination < len;
numberOfItemsPerCombination++
) {
for (const combination of yieldCombinationsWithoutRepetition(
items,
numberOfItemsPerCombination
)) {
ret.push(combination);
}
}
}
ret.push(last);
return ret;
};
/**
* Yields unique, progressive and incremental combinations.
*
* @generator
* @param {Array} items An array of items.
* @param {boolean} yieldCopy True if some of the yielded combinations should be a copy (default)
* of the corresponding internal array used during the generation of the current combination
* or that same array should be returned (if "yieldCopy" is "false").
* @yields {Array} An array, each representing the next unique progressive incremental combination.
* An empty array is yielded if the given items array is empty.
*/
const yieldUniqueProgressiveIncrementalCombinations = function* (
items,
yieldCopy = true
) {
const len = items.length;
if (len === 0) {
return;
}
const last = yieldCopy ? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(items) : items; // Shallow copy/clone of the given array.
if (len === 1) {
// [1] => [[1]]
yield last;
return;
}
// [1], [2], [3], ..., [n]
yield* (0,_core__WEBPACK_IMPORTED_MODULE_0__.mapYield)(items, item => [item]);
if (len > 2) {
// There are at least three items.
for (
let numberOfItemsPerCombination = 2;
numberOfItemsPerCombination < len;
numberOfItemsPerCombination++
) {
for (const combination of yieldCombinationsWithoutRepetition(
items,
numberOfItemsPerCombination,
yieldCopy
)) {
yield combination;
}
}
}
yield last;
};
/**
* Yields all the subsequences of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield subsequences.
* @yields {Array} The next subsequence.
*/
const yieldAllSubsequences = function* (items) {
const l = items.length;
for (let i = 0; i <= l; i++) {
for (const combination of yieldCombinationsWithoutRepetition(items, i)) {
yield combination;
}
}
};
/**
* Yields only the unique subsequences of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield subsequences.
* @yields {Array} The next unique subsequence.
*/
const yieldUniqueSubsequences = function* (items) {
const map = new Map();
yield [];
for (const subsequence of yieldAllSubsequences(items)) {
if (!(0,_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapHas)(map, subsequence)) {
(0,_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapSet)(map, subsequence, true);
yield subsequence;
}
}
};
/**
* Yields all the permutations of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield permutations.
* @param {boolean} yieldCopy True if the yielded permutation should be a copy (default) or
* the internal array used during the generation of the current permutation.
* @yields {Array} The next permutation.
*/
const yieldPermutations = function* (items, yieldCopy = true) {
const currentPermutationPrefix = [];
const currentPermutationIndicesMap = {};
const permute = function* () {
if (currentPermutationPrefix.length === items.length) {
yield yieldCopy
? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(currentPermutationPrefix)
: currentPermutationPrefix;
} else {
for (let i = 0; i < items.length; i++) {
if (currentPermutationIndicesMap[i]) {
continue;
}
currentPermutationPrefix.push(items[i]);
currentPermutationIndicesMap[i] = true;
yield* permute();
delete currentPermutationIndicesMap[i];
currentPermutationPrefix.pop();
}
}
};
yield* permute();
};
/***/ }),
/***/ "./src/modules/constraint.js":
/*!***********************************!*\
!*** ./src/modules/constraint.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "filterInt": () => (/* binding */ filterInt),
/* harmony export */ "filterFloat": () => (/* binding */ filterFloat)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Constraints and filtering utility functions.
*/
/**
* Filters the given string so that it only includes digit (0-9)
* and an optional leading sign ("+", which is removed if present, or "-"),
* i.e. represents a valid integer parsable with "Number.parseInt()".
*
* @param {string} str The input string.
* @return {string} The valid input string or an empty string if there isn't any digit.
*/
function filterInt(str) {
let filtered = str.replace(/[^0-9]/g, "");
filtered = filtered.replace(/^[0]+([1-9])/, "$1");
filtered = filtered.replace(/^[0]+$/, "0");
if (str && filtered.length && str[0] === "-") {
filtered = `-${filtered}`;
}
return filtered;
}
/**
* Filters the given string so that it only includes digits (0-9), a decimal separator ("." character)
* and an optional leading sign ("+", which is removed if present, or "-"),
* i.e. represents a valid float parsable with "Number.parseFloat()".
*
* @param {string} str The input string.
* @return {string} The valid float string or an empty string if there isn't any digit or decimal separator.
* If there isn't any digit in the input string and there is a decimal separator ("." character),
* the returned string will be "0.", i.e. a parsable "0." string.
*/
function filterFloat(str) {
let filtered = str.replace(/[^0-9.]/g, "");
const regex = /(\..*)\./g;
const replace = "$1";
do {
filtered = filtered.replace(regex, replace);
} while (filtered != filtered.replace(regex, replace));
filtered === "." ? (filtered = "0.") : filtered;
filtered = filtered.replace(/^[0]+([1-9])/, "$1");
filtered = filtered.replace(/^[0]+($|\.)/, "0$1");
if (str && filtered.length && str[0] === "-") {
filtered = `-${filtered}`;
}
return filtered;
}
/***/ }),
/***/ "./src/modules/convert.js":
/*!********************************!*\
!*** ./src/modules/convert.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "b2d": () => (/* binding */ b2d),
/* harmony export */ "d2b": () => (/* binding */ d2b)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions related to conversion of data from one format to another.
*/
/**
* Binary to decimal.
*
* @param {string} x Binary string.
* @return {number} Decimal number.
*/
const b2d = x => parseInt(x, 2);
/**
* Decimal to binary.
*
* @param {number} x Decimal number.
* @return {string} Binary representation.
*/
const d2b = x => x.toString(2);
/***/ }),
/***/ "./src/modules/core/compare.js":
/*!*************************************!*\
!*** ./src/modules/core/compare.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "is": () => (/* binding */ is),
/* harmony export */ "objectPropEqual": () => (/* binding */ objectPropEqual),
/* harmony export */ "shallowEqual": () => (/* binding */ shallowEqual)
/* harmony export */ });
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @typechecks
*
*/
/**
* @type {Function}
*/
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Function implementing "Object.is" behaviour.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*
* @param {*} x The first value to compare.
* @param {*} y The second value to compare.
* @return {boolean} A boolean indicating whether or not the two arguments are the same value.
*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/**
* Checks whether a prop of an object equals in the other object (shallow comparison).
*
* @param {Object} objA The first object.
* @param {Object} objB The second object.
* @param {string} prop The name of the property.
* @return {boolean} True if the value of "prop" in "objA" is shallowly equal to the value of "prop" in "objB".
*/
function objectPropEqual(objA, objB, prop) {
return hasOwnProperty.call(objB, prop) && is(objA[prop], objB[prop]);
}
/**
* Performs equality by iterating through keys on an object and returning "false"
* when any key has values which are not strictly equal between the arguments.
* Returns "true" when the values of all keys are strictly equal.
*
* @see https://stackoverflow.com/questions/22266826/how-can-i-do-a-shallow-comparison-of-the-properties-of-two-objects-with-javascri#answer-37636728
*
* @param {*} objA First object.
* @param {*} objB Second object.
* @return {boolean}
*/
function shallowEqual(objA, objB) {
if (is(objA, objB)) {
return true;
}
if (
typeof objA !== "object" ||
objA === null ||
typeof objB !== "object" ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
const prop = keysA[i];
if (!objectPropEqual(objA, objB, prop)) {
return false;
}
}
return true;
}
/***/ }),
/***/ "./src/modules/core/index.js":
/*!***********************************!*\
!*** ./src/modules/core/index.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "shallowEqual": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.shallowEqual),
/* harmony export */ "objectPropEqual": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.objectPropEqual),
/* harmony export */ "is": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.is),
/* harmony export */ "config": () => (/* binding */ config),
/* harmony export */ "isObjectEmpty": () => (/* binding */ isObjectEmpty),
/* harmony export */ "isObject": () => (/* binding */ isObject),
/* harmony export */ "isPlainObject": () => (/* binding */ isPlainObject),
/* harmony export */ "isArray": () => (/* binding */ isArray),
/* harmony export */ "isCallable": () => (/* binding */ isCallable),
/* harmony export */ "isEmpty": () => (/* binding */ isEmpty),
/* harmony export */ "isEmptyOr0": () => (/* binding */ isEmptyOr0),
/* harmony export */ "getGlobalObject": () => (/* binding */ getGlobalObject),
/* harmony export */ "uniqueId": () => (/* binding */ uniqueId),
/* harmony export */ "nestedPropertyValue": () => (/* binding */ nestedPropertyValue),
/* harmony export */ "getNestedPropertyValue": () => (/* binding */ getNestedPropertyValue),
/* harmony export */ "hasNestedPropertyValue": () => (/* binding */ hasNestedPropertyValue),
/* harmony export */ "setNestedPropertyValue": () => (/* binding */ setNestedPropertyValue),
/* harmony export */ "nestedMapSet": () => (/* binding */ nestedMapSet),
/* harmony export */ "nestedMapHas": () => (/* binding */ nestedMapHas),
/* harmony export */ "nestedMapGet": () => (/* binding */ nestedMapGet),
/* harmony export */ "nestedTreeMapSet": () => (/* binding */ nestedTreeMapSet),
/* harmony export */ "nestedTreeMapHas": () => (/* binding */ nestedTreeMapHas),
/* harmony export */ "nestedTreeMapGet": () => (/* binding */ nestedTreeMapGet),
/* harmony export */ "mapYield": () => (/* binding */ mapYield),
/* harmony export */ "deepArrayCompare": () => (/* binding */ deepArrayCompare),
/* harmony export */ "deepObjectCompare": () => (/* binding */ deepObjectCompare),
/* harmony export */ "nestedObjectConstructValue": () => (/* binding */ nestedObjectConstructValue),
/* harmony export */ "cloneDeeplyJSON": () => (/* binding */ cloneDeeplyJSON),
/* harmony export */ "isReferenceType": () => (/* binding */ isReferenceType),
/* harmony export */ "isPrimitiveType": () => (/* binding */ isPrimitiveType),
/* harmony export */ "hasCyclicReference": () => (/* binding */ hasCyclicReference),
/* harmony export */ "typeToStr": () => (/* binding */ typeToStr),
/* harmony export */ "cloneObjDeeply": () => (/* binding */ cloneObjDeeply),
/* harmony export */ "deepObjectExtend": () => (/* binding */ deepObjectExtend),
/* harmony export */ "deepObjectCloningExtend": () => (/* binding */ deepObjectCloningExtend),
/* harmony export */ "extend": () => (/* binding */ extend),
/* harmony export */ "extendDecorate": () => (/* binding */ extendDecorate),
/* harmony export */ "shallowExtend": () => (/* binding */ shallowExtend),
/* harmony export */ "includesTypeCoercion": () => (/* binding */ includesTypeCoercion),
/* harmony export */ "isUndefined": () => (/* binding */ isUndefined),
/* harmony export */ "isInt": () => (/* binding */ isInt),
/* harmony export */ "ctypeDigit": () => (/* binding */ ctypeDigit),
/* harmony export */ "isIntegerOrIntegerStr": () => (/* binding */ isIntegerOrIntegerStr),
/* harmony export */ "findIndex": () => (/* binding */ findIndex),
/* harmony export */ "firstPropValue": () => (/* binding */ firstPropValue),
/* harmony export */ "isStrictlyTrue": () => (/* binding */ isStrictlyTrue),
/* harmony export */ "isTruthy": () => (/* binding */ isTruthy),
/* harmony export */ "allTruthy": () => (/* binding */ allTruthy),
/* harmony export */ "allNotUndefined": () => (/* binding */ allNotUndefined),
/* harmony export */ "isJSONString": () => (/* binding */ isJSONString),
/* harmony export */ "noOpFn": () => (/* binding */ noOpFn),
/* harmony export */ "partialShallowEqual": () => (/* binding */ partialShallowEqual),
/* harmony export */ "shallowObjectDiff": () => (/* binding */ shallowObjectDiff),
/* harmony export */ "str": () => (/* binding */ str),
/* harmony export */ "mapObject": () => (/* binding */ mapObject),
/* harmony export */ "mapToObject": () => (/* binding */ mapToObject),
/* harmony export */ "propSelection": () => (/* binding */ propSelection),
/* harmony export */ "prototypeChainProperties": () => (/* binding */ prototypeChainProperties),
/* harmony export */ "prop": () => (/* binding */ prop),
/* harmony export */ "defineProperty": () => (/* binding */ defineProperty),
/* harmony export */ "completeObjectAssign": () => (/* binding */ completeObjectAssign)
/* harmony export */ });
/* harmony import */ var _compare__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./compare */ "./src/modules/core/compare.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Core utility functions.
*/
/**
* Optional configuration with useful properties.
*
* @type {Object}
*/
const config = {
uniqueIdPrefix: "",
elementUniqueIdPrefix: "",
checkNetworkURI: null,
};
/**
* Tests if an object is empty.
*
* @param {Object} obj The object to test.
* @return {boolean} "true" if the given object is empty (does not have own properties), "false" otherwise.
*/
function isObjectEmpty(obj) {
for (const prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
return false;
}
}
return true;
}
/**
* @type {string}
*/
const objPrototypeToString = Object.prototype.toString.call({});
/**
* Tests if a variable is an object.
*
* @param {*} obj The variable to test.
* @return {boolean} "true" if "obj" is indeed an object, "false" otherwise.
*/
const isObject = function (obj) {
return objPrototypeToString === Object.prototype.toString.call(obj);
};
/**
* Tests if a variable is a plain object (i.e. "{}", an object literal).
*
* @param {*} obj The variable to test.
* @return {boolean} "true" if "obj" is a plain object, "false" otherwise.
*/
const isPlainObject = obj => {
return (
obj !== null &&
typeof obj === "object" &&
obj.constructor === Object &&
isObject(obj)
);
};
/**
* Tests to see whether something is an array or not.
*
* @param {*} something A variable to check whether it is an array or not.
* @return {boolean} True if the parameter passed in is an array, false otherwise.
*/
function isArray(something) {
return (
Object.prototype.toString.call(something) ===
Object.prototype.toString.call([])
);
}
/**
* Tests if the given value is callable.
*
* @param {*} v The value.
* @return {boolean} True if callable, false otherwise.
*/
function isCallable(v) {
return typeof v === "function";
}
/**
* Tests if a variable is empty returning true for empty strings and empty arrays.
*
* @param {*} data The variable to test.
* @return {boolean} True if the variable is empty, false otherwise.
*/
function isEmpty(data) {
return !data || data.length === 0;
}
/**
* Tests if a variable is empty or 0 ("0" string) returning true for empty strings,
* empty arrays, the "0" string and empty values.
*
* @param {*} data The variable to test.
* @return {boolean} True if the variable is empty or "0", false otherwise.
*/
function isEmptyOr0(data) {
return !data || data === "0" || data.length === 0;
}
/**
* Returns a reference to the global object.
*
* @return {Window|global} The global object (this function is cross-platform aware).
*/
function getGlobalObject() {
return typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g : window;
}
/**
* @type {string}
*/
const JSUtlUniqueIdCounterProp = "JSUtlUniqueIdCounterLEzKKl87QCDxwVH";
/**
* Generates a unique ID which can be used as an "id" attribute.
*
* @param {string|undefined} [uniqueIdPrefix] Local unique ID prefix which overrides the prefix
* set on the "config" configuration object.
* @return {string} The unique ID.
*/
function uniqueId(uniqueIdPrefix = void 0) {
const globalObject = getGlobalObject();
globalObject[JSUtlUniqueIdCounterProp] =
globalObject[JSUtlUniqueIdCounterProp] || 0;
globalObject[JSUtlUniqueIdCounterProp]++;
const uniqueIdCounter = globalObject[JSUtlUniqueIdCounterProp];
const uniqueId = (uniqueIdPrefix || config.uniqueIdPrefix) + uniqueIdCounter;
return uniqueId;
}
/**
* Gets a nested value of an object given an array of nested property names (keys).
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @return {*} The leaf value.
*/
function nestedPropertyValue(data, props) {
let root = data;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
root = root[prop];
}
return root;
}
/**
* Alias for "nestedPropertyValue".
*
* @alias
*/
const getNestedPropertyValue = nestedPropertyValue;
/**
* Checks if a nested value of an object given an array of nested property names (keys) exists.
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @return {boolean} True if the nested key exists, false otherwise.
*/
function hasNestedPropertyValue(data, props) {
if (!props.length) {
return false;
}
let root = data;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (!root[prop]) {
return false;
}
root = root[prop];
}
return true;
}
/**
* Sets a nested value of an object given an array of nested property names (keys).
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @param {*} value Leaf value.
* @return {undefined}
*/
function setNestedPropertyValue(data, props, value) {
if (!props.length) {
return;
}
let root = data;
let prev = null;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (typeof root[prop] !== "object") {
root[prop] = {};
}
prev = root;
root = root[prop];
}
if (prev) {
prev[props[props.length - 1]] = value;
}
}
/**
* Sets a nested value on a nested map.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys to traverse. Each key will lead to a nested map.
* @param {*} value The value to set at the inner key.
* @return {undefined}
*/
const nestedMapSet = (map, keys, value) => {
let i = 0;
let current = map;
while (i < keys.length - 1) {
const key = keys[i];
const nested = current.get(key);
if (nested instanceof Map || nested instanceof WeakMap) {
current = nested;
} else {
const newMap = new Map();
current.set(key, newMap);
current = newMap;
}
i++;
}
current.set(keys[i], value);
};
/**
* Tests if a map has the given nested keys.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys to check. Each key represents a nested map.
* @return {boolean} "true" if all the nested keys exist, false otherwise.
*/
const nestedMapHas = (map, keys) => {
let current = map;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i]);
i++;
}
return i == l;
};
/**
* Gets a value from a nested map.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys. Each key represents a nested map.
* @return {*} The value of the map or "undefined" if there is no value for the given nested keys.
*/
const nestedMapGet = (map, keys) => {
let current = map;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i]);
i++;
}
return i == l ? current : void 0;
};
/**
* @type {Symbol}
*/
const treeMapSubtree = Symbol("treeMapSubtree");
/**
* Sets a nested value on a nested tree map.
*
* @param {Map|WeakMap} rootMap A map or weak map to use as the root.
* @param {Array} keys Array of keys to traverse. Each key will lead to a nested node of the tree map.
* @param {*} value The value to set at the inner nested key.
* @return {undefined}
*/
const nestedTreeMapSet = (rootMap, keys, value) => {
let i = 0;
let current = rootMap;
const MapConstructor = rootMap instanceof WeakMap ? WeakMap : Map;
while (i < keys.length - 1) {
const key = keys[i];
const nested = current.get(key);
if (nested) {
current =
nested[treeMapSubtree] ||
(nested[treeMapSubtree] = new MapConstructor());
} else {
const newMap = new MapConstructor();
const node = {
[treeMapSubtree]: newMap,
value: void 0,
};
current.set(key, node);
current = newMap;
}
i++;
}
const key = keys[i];
!current.has(key)
? current.set(key, {
value,
})
: (current.get(key).value = value);
};
/**
* Tests if a tree map has the given nested keys.
*
* @param {Map|WeakMap} rootMap The root of the map or weak map.
* @param {Array} keys Array of keys to check. Each key represents a nested node of the tree map.
* @return {boolean} "true" if all the nested keys exist, false otherwise.
*/
const nestedTreeMapHas = (rootMap, keys) => {
let current = rootMap;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i])[treeMapSubtree];
i++;
}
return i == l;
};
/**
* Gets a value from a nested tree map.
*
* @param {Map|WeakMap} rootMap The root of the map or weak map.
* @param {Array} keys Array of keys. Each key represents a nested node of the tree map.
* @return {*} The value of the tree map or "undefined" if there is no value for the given nested keys.
*/
const nestedTreeMapGet = (rootMap, keys) => {
let current = rootMap;
let i = 0;
const lastIndex = keys.length - 1;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < lastIndex
) {
current = current.get(keys[i])[treeMapSubtree];
i++;
}
if (i === lastIndex && current) {
const lastKey = keys[i];
if (current.has(lastKey)) {
const nested = current.get(lastKey);
return nested.value;
}
}
return void 0;
};
/**
* Yields values of an array mapping the yielded value.
*
* @generator
* @param {Array} items An array of items.
* @param {*} fn The function to call.
* The function will receive, in order the nth item,
* the index of the item in the array of items and t