diff options
| author | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
|---|---|---|
| committer | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
| commit | bce557cc2dc767628bed6aac87301a1be7c5431b (patch) | |
| tree | b51a051228d01fe3306cd7626d4a96768aadb944 /shared/logger/node_modules/@sentry/utils/esm/object.js | |
init commit
Diffstat (limited to 'shared/logger/node_modules/@sentry/utils/esm/object.js')
| -rw-r--r-- | shared/logger/node_modules/@sentry/utils/esm/object.js | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/utils/esm/object.js b/shared/logger/node_modules/@sentry/utils/esm/object.js new file mode 100644 index 0000000..0f5c411 --- /dev/null +++ b/shared/logger/node_modules/@sentry/utils/esm/object.js @@ -0,0 +1,279 @@ +import { htmlTreeAsString } from './browser.js'; +import { isError, isEvent, isInstanceOf, isElement, isPlainObject, isPrimitive } from './is.js'; +import { truncate } from './string.js'; + +/** + * Replace a method in an object with a wrapped version of itself. + * + * @param source An object that contains a method to be wrapped. + * @param name The name of the method to be wrapped. + * @param replacementFactory A higher-order function that takes the original version of the given method and returns a + * wrapped version. Note: The function returned by `replacementFactory` needs to be a non-arrow function, in order to + * preserve the correct value of `this`, and the original method must be called using `origMethod.call(this, <other + * args>)` or `origMethod.apply(this, [<other args>])` (rather than being called directly), again to preserve `this`. + * @returns void + */ +function fill(source, name, replacementFactory) { + if (!(name in source)) { + return; + } + + const original = source[name] ; + const wrapped = replacementFactory(original) ; + + // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work + // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" + if (typeof wrapped === 'function') { + try { + markFunctionWrapped(wrapped, original); + } catch (_Oo) { + // This can throw if multiple fill happens on a global object like XMLHttpRequest + // Fixes https://github.com/getsentry/sentry-javascript/issues/2043 + } + } + + source[name] = wrapped; +} + +/** + * Defines a non-enumerable property on the given object. + * + * @param obj The object on which to set the property + * @param name The name of the property to be set + * @param value The value to which to set the property + */ +function addNonEnumerableProperty(obj, name, value) { + Object.defineProperty(obj, name, { + // enumerable: false, // the default, so we can save on bundle size by not explicitly setting it + value: value, + writable: true, + configurable: true, + }); +} + +/** + * Remembers the original function on the wrapped function and + * patches up the prototype. + * + * @param wrapped the wrapper function + * @param original the original function that gets wrapped + */ +function markFunctionWrapped(wrapped, original) { + const proto = original.prototype || {}; + wrapped.prototype = original.prototype = proto; + addNonEnumerableProperty(wrapped, '__sentry_original__', original); +} + +/** + * This extracts the original function if available. See + * `markFunctionWrapped` for more information. + * + * @param func the function to unwrap + * @returns the unwrapped version of the function if available. + */ +function getOriginalFunction(func) { + return func.__sentry_original__; +} + +/** + * Encodes given object into url-friendly format + * + * @param object An object that contains serializable values + * @returns string Encoded + */ +function urlEncode(object) { + return Object.keys(object) + .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(object[key])}`) + .join('&'); +} + +/** + * Transforms any `Error` or `Event` into a plain object with all of their enumerable properties, and some of their + * non-enumerable properties attached. + * + * @param value Initial source that we have to transform in order for it to be usable by the serializer + * @returns An Event or Error turned into an object - or the value argurment itself, when value is neither an Event nor + * an Error. + */ +function convertToPlainObject(value) + + { + if (isError(value)) { + return { + message: value.message, + name: value.name, + stack: value.stack, + ...getOwnProperties(value), + }; + } else if (isEvent(value)) { + const newObj + + = { + type: value.type, + target: serializeEventTarget(value.target), + currentTarget: serializeEventTarget(value.currentTarget), + ...getOwnProperties(value), + }; + + if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) { + newObj.detail = value.detail; + } + + return newObj; + } else { + return value; + } +} + +/** Creates a string representation of the target of an `Event` object */ +function serializeEventTarget(target) { + try { + return isElement(target) ? htmlTreeAsString(target) : Object.prototype.toString.call(target); + } catch (_oO) { + return '<unknown>'; + } +} + +/** Filters out all but an object's own properties */ +function getOwnProperties(obj) { + if (typeof obj === 'object' && obj !== null) { + const extractedProps = {}; + for (const property in obj) { + if (Object.prototype.hasOwnProperty.call(obj, property)) { + extractedProps[property] = (obj )[property]; + } + } + return extractedProps; + } else { + return {}; + } +} + +/** + * Given any captured exception, extract its keys and create a sorted + * and truncated list that will be used inside the event message. + * eg. `Non-error exception captured with keys: foo, bar, baz` + */ +function extractExceptionKeysForMessage(exception, maxLength = 40) { + const keys = Object.keys(convertToPlainObject(exception)); + keys.sort(); + + if (!keys.length) { + return '[object has no keys]'; + } + + if (keys[0].length >= maxLength) { + return truncate(keys[0], maxLength); + } + + for (let includedKeys = keys.length; includedKeys > 0; includedKeys--) { + const serialized = keys.slice(0, includedKeys).join(', '); + if (serialized.length > maxLength) { + continue; + } + if (includedKeys === keys.length) { + return serialized; + } + return truncate(serialized, maxLength); + } + + return ''; +} + +/** + * Given any object, return a new object having removed all fields whose value was `undefined`. + * Works recursively on objects and arrays. + * + * Attention: This function keeps circular references in the returned object. + */ +function dropUndefinedKeys(inputValue) { + // This map keeps track of what already visited nodes map to. + // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular + // references as the input object. + const memoizationMap = new Map(); + + // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API + return _dropUndefinedKeys(inputValue, memoizationMap); +} + +function _dropUndefinedKeys(inputValue, memoizationMap) { + if (isPlainObject(inputValue)) { + // If this node has already been visited due to a circular reference, return the object it was mapped to in the new object + const memoVal = memoizationMap.get(inputValue); + if (memoVal !== undefined) { + return memoVal ; + } + + const returnValue = {}; + // Store the mapping of this value in case we visit it again, in case of circular data + memoizationMap.set(inputValue, returnValue); + + for (const key of Object.keys(inputValue)) { + if (typeof inputValue[key] !== 'undefined') { + returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap); + } + } + + return returnValue ; + } + + if (Array.isArray(inputValue)) { + // If this node has already been visited due to a circular reference, return the array it was mapped to in the new object + const memoVal = memoizationMap.get(inputValue); + if (memoVal !== undefined) { + return memoVal ; + } + + const returnValue = []; + // Store the mapping of this value in case we visit it again, in case of circular data + memoizationMap.set(inputValue, returnValue); + + inputValue.forEach((item) => { + returnValue.push(_dropUndefinedKeys(item, memoizationMap)); + }); + + return returnValue ; + } + + return inputValue; +} + +/** + * Ensure that something is an object. + * + * Turns `undefined` and `null` into `String`s and all other primitives into instances of their respective wrapper + * classes (String, Boolean, Number, etc.). Acts as the identity function on non-primitives. + * + * @param wat The subject of the objectification + * @returns A version of `wat` which can safely be used with `Object` class methods + */ +function objectify(wat) { + let objectified; + switch (true) { + case wat === undefined || wat === null: + objectified = new String(wat); + break; + + // Though symbols and bigints do have wrapper classes (`Symbol` and `BigInt`, respectively), for whatever reason + // those classes don't have constructors which can be used with the `new` keyword. We therefore need to cast each as + // an object in order to wrap it. + case typeof wat === 'symbol' || typeof wat === 'bigint': + objectified = Object(wat); + break; + + // this will catch the remaining primitives: `String`, `Number`, and `Boolean` + case isPrimitive(wat): + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + objectified = new (wat ).constructor(wat); + break; + + // by process of elimination, at this point we know that `wat` must already be an object + default: + objectified = wat; + break; + } + return objectified; +} + +export { addNonEnumerableProperty, convertToPlainObject, dropUndefinedKeys, extractExceptionKeysForMessage, fill, getOriginalFunction, markFunctionWrapped, objectify, urlEncode }; +//# sourceMappingURL=object.js.map |
