diff --git a/lib/web/underscore.js b/lib/web/underscore.js index 9d220e0f839b5..01ff20f6371bd 100644 --- a/lib/web/underscore.js +++ b/lib/web/underscore.js @@ -1,33 +1,30 @@ -(function(global, factory) { +(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define('underscore', factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function() { + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () { var current = global._; var exports = global._ = factory(); - exports.noConflict = function() { - global._ = current; - return exports; - }; + exports.noConflict = function () { global._ = current; return exports; }; }())); -}(this, (function() { - // Underscore.js 1.13.7 +}(this, (function () { + // Underscore.js 1.13.8 // https://underscorejs.org - // (c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors + // (c) 2009-2026 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. // Current version. - var VERSION = '1.13.7'; + var VERSION = '1.13.8'; // Establish the root object, `window` (`self`) in the browser, `global` // on the server, or `this` in some virtual machines. We use `self` // instead of `window` for `WebWorker` support. var root = (typeof self == 'object' && self.self === self && self) || (typeof global == 'object' && global.global === global && global) || - Function('return this')() || {}; + Function('return this')() || + {}; // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, - ObjProto = Object.prototype; + var ArrayProto = Array.prototype, ObjProto = Object.prototype; var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; // Create quick reference variables for speed access to core prototypes. @@ -52,12 +49,9 @@ _isFinite = isFinite; // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. - var hasEnumBug = !{ - toString: null - }.propertyIsEnumerable('toString'); + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', - 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString' - ]; + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; // The largest integer that can be represented exactly. var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; @@ -77,12 +71,9 @@ rest[index] = arguments[index + startIndex]; } switch (startIndex) { - case 0: - return func.call(this, rest); - case 1: - return func.call(this, arguments[0], rest); - case 2: - return func.call(this, arguments[0], arguments[1], rest); + case 0: return func.call(this, rest); + case 1: return func.call(this, arguments[0], rest); + case 2: return func.call(this, arguments[0], arguments[1], rest); } var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { @@ -243,7 +234,6 @@ // Is a given value a typed array? var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/; - function isTypedArray(obj) { // `ArrayBuffer.isView` is the most future-proof, so use it when available. // Otherwise, fall back on the above regular expression. @@ -264,9 +254,7 @@ var hash = {}; for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true; return { - contains: function(key) { - return hash[key] === true; - }, + contains: function(key) { return hash[key] === true; }, push: function(key) { hash[key] = true; return keys.push(key); @@ -301,8 +289,7 @@ if (!isObject(obj)) return []; if (nativeKeys) return nativeKeys(obj); var keys = []; - for (var key in obj) - if (has$1(obj, key)) keys.push(key); + for (var key in obj) if (has$1(obj, key)) keys.push(key); // Ahem, IE < 9. if (hasEnumBug) collectNonEnumProps(obj, keys); return keys; @@ -323,8 +310,7 @@ // Returns whether an object has a given set of `key:value` pairs. function isMatch(object, attrs) { - var _keys = keys(attrs), - length = _keys.length; + var _keys = keys(attrs), length = _keys.length; if (object == null) return !length; var obj = Object(object); for (var i = 0; i < length; i++) { @@ -371,133 +357,157 @@ // We use this string twice, so give it a name for minification. var tagDataView = '[object DataView]'; - // Internal recursive comparison function for `_.isEqual`. - function eq(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // `null` or `undefined` only equal to itself (strict comparison). - if (a == null || b == null) return false; - // `NaN`s are equivalent, but non-reflexive. - if (a !== a) return b !== b; - // Exhaust primitive checks - var type = typeof a; - if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; - return deepEq(a, b, aStack, bStack); - } - - // Internal recursive comparison function for `_.isEqual`. - function deepEq(a, b, aStack, bStack) { - // Unwrap any wrapped objects. - if (a instanceof _$1) a = a._wrapped; - if (b instanceof _$1) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - // Work around a bug in IE 10 - Edge 13. - if (hasDataViewBug && className == '[object Object]' && isDataView$1(a)) { - if (!isDataView$1(b)) return false; - className = tagDataView; - } - switch (className) { - // These types are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN. - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - case '[object Symbol]': - return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); - case '[object ArrayBuffer]': - case tagDataView: - // Coerce to typed array so we can fall through. - return deepEq(toBufferView(a), toBufferView(b), aStack, bStack); - } + // Perform a deep comparison to check if two objects are equal. + function isEqual(a, b) { + // Keep track of which pairs of values need to be compared. We will be + // trampolining on this stack instead of using function recursion. + // (CVE-2026-27601) + var todo = [{a: a, b: b}]; + // Initializing stacks of traversed objects for cycle detection. + var aStack = [], bStack = []; + + // Keep traversing pairs until there is nothing left to compare. + while (todo.length) { + var frame = todo.pop(); + // As a special case, a single `true` on the todo means that we can + // unwind the cycle detection stacks. + if (frame === true) { + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + continue; + } + a = frame.a; + b = frame.b; - var areArrays = className === '[object Array]'; - if (!areArrays && isTypedArray$1(a)) { - var byteLength = getByteLength(a); - if (byteLength !== getByteLength(b)) return false; - if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true; - areArrays = true; - } - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, - bCtor = b.constructor; - if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor && - isFunction$1(bCtor) && bCtor instanceof bCtor) && - ('constructor' in a && 'constructor' in b)) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) { + if (a !== 0 || 1 / a === 1 / b) continue; return false; } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } + // `null` or `undefined` only equal to itself (strict comparison). + if (a == null || b == null) return false; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) { + if (b !== b) continue; + return false; + } + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; + + // Internal recursive comparison function for `_.isEqual`. + // Unwrap any wrapped objects. + if (a instanceof _$1) a = a._wrapped; + if (b instanceof _$1) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + // Work around a bug in IE 10 - Edge 13. + if (hasDataViewBug && className == '[object Object]' && isDataView$1(a)) { + if (!isDataView$1(b)) return false; + className = tagDataView; + } + switch (className) { + // These types are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + if ('' + a === '' + b) continue; + return false; + case '[object Number]': + todo.push({a: +a, b: +b}); + continue; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + if (+a === +b) continue; + return false; + case '[object Symbol]': + if (SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b)) continue; + return false; + case '[object ArrayBuffer]': + case tagDataView: + // Coerce to typed array so we can fall through. + todo.push({a: toBufferView(a), b: toBufferView(b)}); + continue; + } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); + var areArrays = className === '[object Array]'; + if (!areArrays && isTypedArray$1(a)) { + var byteLength = getByteLength(a); + if (byteLength !== getByteLength(b)) return false; + if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) continue; + areArrays = true; + } + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor && + isFunction$1(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. + var length = aStack.length; while (length--) { - if (!eq(a[length], b[length], aStack, bStack)) return false; + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) { + // Cycle detected. Break out of the inner loop and continue the outer + // loop. Step 1: + if (bStack[length] === b) break; + return false; + } } - } else { - // Deep compare objects. - var _keys = keys(a), - key; - length = _keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = _keys[length]; - if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + // Step 2, use `length` to verify whether we detected a cycle: + if (length >= 0) continue; + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + // Remember to remove them again after the recursion below. + todo.push(true); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + todo.push({a: a[length], b: b[length]}); + } + } else { + // Deep compare objects. + var _keys = keys(a), key; + length = _keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = _keys[length]; + if (!has$1(b, key)) return false; + todo.push({a: a[key], b: b[key]}); + } } } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); + // We made it to the end and found no differences. return true; } - // Perform a deep comparison to check if two objects are equal. - function isEqual(a, b) { - return eq(a, b); - } - // Retrieve all the enumerable property names of an object. function allKeys(obj) { if (!isObject(obj)) return []; @@ -624,7 +634,7 @@ // Create a naked function reference for surrogate-prototype-swapping. function ctor() { - return function() {}; + return function(){}; } // An internal function for creating a new object that inherits from another. @@ -736,19 +746,16 @@ function optimizeCb(func, context, argCount) { if (context === void 0) return func; switch (argCount == null ? 3 : argCount) { - case 1: - return function(value) { - return func.call(context, value); - }; + case 1: return function(value) { + return func.call(context, value); + }; // The 2-argument case is omitted because we’re not using it. - case 3: - return function(value, index, collection) { - return func.call(context, value, index, collection); - }; - case 4: - return function(accumulator, value, index, collection) { - return func.call(context, accumulator, value, index, collection); - }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; } return function() { return func.apply(context, arguments); @@ -795,7 +802,7 @@ } // Predicate-generating function. Often useful outside of Underscore. - function noop() {} + function noop(){} // Generates a function for a given object that returns a given property. function propertyOf(obj) { @@ -991,7 +998,6 @@ // Generate a unique integer id (unique within the entire client session). // Useful for temporary DOM ids. var idCounter = 0; - function uniqueId(prefix) { var id = ++idCounter + ''; return prefix ? prefix + id : id; @@ -1022,8 +1028,7 @@ var partial = restArguments(function(func, boundArgs) { var placeholder = partial.placeholder; var bound = function() { - var position = 0, - length = boundArgs.length; + var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; @@ -1053,26 +1058,30 @@ var isArrayLike = createSizePropertyCheck(getLength); // Internal implementation of a recursive `flatten` function. - function flatten$1(input, depth, strict, output) { - output = output || []; - if (!depth && depth !== 0) { - depth = Infinity; - } else if (depth <= 0) { - return output.concat(input); - } - var idx = output.length; - for (var i = 0, length = getLength(input); i < length; i++) { - var value = input[i]; - if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) { + function flatten$1(input, depth, strict) { + if (!depth && depth !== 0) depth = Infinity; + // We will be avoiding recursive calls because this could be exploited to + // cause a stack overflow (CVE-2026-27601). Instead, we "trampoline" on an + // explicit stack. + var output = [], idx = 0, i = 0, length = getLength(input) || 0, stack = []; + while (true) { + if (i >= length) { + if (!stack.length) break; + var frame = stack.pop(); + i = frame.i; + input = frame.v; + length = getLength(input); + continue; + } + var value = input[i++]; + if (stack.length >= depth) { + output[idx++] = value; + } else if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) { // Flatten current level of array or arguments object. - if (depth > 1) { - flatten$1(value, depth - 1, strict, output); - idx = output.length; - } else { - var j = 0, - len = value.length; - while (j < len) output[idx++] = value[j++]; - } + stack.push({i: i, v: input}); + i = 0; + input = value; + length = getLength(input); } else if (!strict) { output[idx++] = value; } @@ -1258,8 +1267,7 @@ // Returns the first key on an object that passes a truth test. function findKey(obj, predicate, context) { predicate = cb(predicate, context); - var _keys = keys(obj), - key; + var _keys = keys(obj), key; for (var i = 0, length = _keys.length; i < length; i++) { key = _keys[i]; if (predicate(obj[key], key, obj)) return key; @@ -1290,12 +1298,10 @@ function sortedIndex(array, obj, iteratee, context) { iteratee = cb(iteratee, context, 1); var value = iteratee(obj); - var low = 0, - high = getLength(array); + var low = 0, high = getLength(array); while (low < high) { var mid = Math.floor((low + high) / 2); - if (iteratee(array[mid]) < value) low = mid + 1; - else high = mid; + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; } return low; } @@ -1303,8 +1309,7 @@ // Internal function to generate the `_.indexOf` and `_.lastIndexOf` functions. function createIndexFinder(dir, predicateFind, sortedIndex) { return function(array, item, idx) { - var i = 0, - length = getLength(array); + var i = 0, length = getLength(array); if (typeof idx == 'number') { if (dir > 0) { i = idx >= 0 ? idx : Math.max(idx + length, i); @@ -1496,8 +1501,7 @@ // Return the maximum element (or element-based computation). function max(obj, iteratee, context) { - var result = -Infinity, - lastComputed = -Infinity, + var result = -Infinity, lastComputed = -Infinity, value, computed; if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) { obj = isArrayLike(obj) ? obj : values(obj); @@ -1522,8 +1526,7 @@ // Return the minimum element (or element-based computation). function min(obj, iteratee, context) { - var result = Infinity, - lastComputed = Infinity, + var result = Infinity, lastComputed = Infinity, value, computed; if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) { obj = isArrayLike(obj) ? obj : values(obj); @@ -1548,7 +1551,6 @@ // Safely create a real, live array from anything iterable. var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; - function toArray(obj) { if (!obj) return []; if (isArray(obj)) return slice.call(obj); @@ -1611,10 +1613,7 @@ // An internal function used for aggregate "group by" operations. function group(behavior, partition) { return function(obj, iteratee, context) { - var result = partition ? [ - [], - [] - ] : {}; + var result = partition ? [[], []] : {}; iteratee = cb(iteratee, context); each(obj, function(value, index) { var key = iteratee(value, index, obj); @@ -1627,8 +1626,7 @@ // Groups the object's values by a criterion. Pass either a string attribute // to group by, or a function that returns the criterion. var groupBy = group(function(result, value, key) { - if (has$1(result, key)) result[key].push(value); - else result[key] = [value]; + if (has$1(result, key)) result[key].push(value); else result[key] = [value]; }); // Indexes the object's values by a criterion, similar to `_.groupBy`, but for @@ -1641,8 +1639,7 @@ // either a string attribute to count by, or a function that returns the // criterion. var countBy = group(function(result, value, key) { - if (has$1(result, key)) result[key]++; - else result[key] = 1; + if (has$1(result, key)) result[key]++; else result[key] = 1; }); // Split a collection into two arrays: one whose elements all pass the given @@ -1665,8 +1662,7 @@ // Return a copy of the object only containing the allowed properties. var pick = restArguments(function(obj, keys) { - var result = {}, - iteratee = keys[0]; + var result = {}, iteratee = keys[0]; if (obj == null) return result; if (isFunction$1(iteratee)) { if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); @@ -1686,8 +1682,7 @@ // Return a copy of the object without the disallowed properties. var omit = restArguments(function(obj, keys) { - var iteratee = keys[0], - context; + var iteratee = keys[0], context; if (isFunction$1(iteratee)) { iteratee = negate(iteratee); if (keys.length > 1) context = keys[1]; @@ -1745,7 +1740,7 @@ // Only the elements present in just the first array will remain. var difference = restArguments(function(array, rest) { rest = flatten$1(rest, true, true); - return filter(array, function(value) { + return filter(array, function(value){ return !contains(rest, value); }); }); @@ -1868,8 +1863,7 @@ function chunk(array, count) { if (count == null || count < 1) return []; var result = []; - var i = 0, - length = array.length; + var i = 0, length = array.length; while (i < length) { result.push(slice.call(array, i, i += count)); }