package.build.cjs.normalize.js.map Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils Show documentation
Show all versions of utils Show documentation
Utilities for all Sentry JavaScript SDKs
{"version":3,"file":"normalize.js","sources":["../../src/normalize.ts"],"sourcesContent":["import type { Primitive } from '@sentry/types';\n\nimport { isSyntheticEvent, isVueViewModel } from './is';\nimport type { MemoFunc } from './memo';\nimport { memoBuilder } from './memo';\nimport { convertToPlainObject } from './object';\nimport { getFunctionName } from './stacktrace';\n\ntype Prototype = { constructor: (...args: unknown[]) => unknown };\n// This is a hack to placate TS, relying on the fact that technically, arrays are objects with integer keys. Normally we\n// think of those keys as actual numbers, but `arr['0']` turns out to work just as well as `arr[0]`, and doing it this\n// way lets us use a single type in the places where behave as if we are only dealing with objects, even if some of them\n// might be arrays.\ntype ObjOrArray = { [key: string]: T };\n\n/**\n * Recursively normalizes the given object.\n *\n * - Creates a copy to prevent original input mutation\n * - Skips non-enumerable properties\n * - When stringifying, calls `toJSON` if implemented\n * - Removes circular references\n * - Translates non-serializable values (`undefined`/`NaN`/functions) to serializable format\n * - Translates known global objects/classes to a string representations\n * - Takes care of `Error` object serialization\n * - Optionally limits depth of final output\n * - Optionally limits number of properties/elements included in any single object/array\n *\n * @param input The object to be normalized.\n * @param depth The max depth to which to normalize the object. (Anything deeper stringified whole.)\n * @param maxProperties The max number of elements or properties to be included in any single array or\n * object in the normallized output.\n * @returns A normalized version of the object, or `\"**non-serializable**\"` if any errors are thrown during normalization.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function normalize(input: unknown, depth: number = 100, maxProperties: number = +Infinity): any {\n try {\n // since we're at the outermost level, we don't provide a key\n return visit('', input, depth, maxProperties);\n } catch (err) {\n return { ERROR: `**non-serializable** (${err})` };\n }\n}\n\n/** JSDoc */\nexport function normalizeToSize(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n object: { [key: string]: any },\n // Default Node.js REPL depth\n depth: number = 3,\n // 100kB, as 200kB is max payload size, so half sounds reasonable\n maxSize: number = 100 * 1024,\n): T {\n const normalized = normalize(object, depth);\n\n if (jsonSize(normalized) > maxSize) {\n return normalizeToSize(object, depth - 1, maxSize);\n }\n\n return normalized as T;\n}\n\n/**\n * Visits a node to perform normalization on it\n *\n * @param key The key corresponding to the given node\n * @param value The node to be visited\n * @param depth Optional number indicating the maximum recursion depth\n * @param maxProperties Optional maximum number of properties/elements included in any single object/array\n * @param memo Optional Memo class handling decycling\n */\nfunction visit(\n key: string,\n value: unknown,\n depth: number = +Infinity,\n maxProperties: number = +Infinity,\n memo: MemoFunc = memoBuilder(),\n): Primitive | ObjOrArray {\n const [memoize, unmemoize] = memo;\n\n // Get the simple cases out of the way first\n if (\n value == null || // this matches null and undefined -> eqeq not eqeqeq\n ['boolean', 'string'].includes(typeof value) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n return value as Primitive;\n }\n\n const stringified = stringifyValue(key, value);\n\n // Anything we could potentially dig into more (objects or arrays) will have come back as `\"[object XXXX]\"`.\n // Everything else will have already been serialized, so if we don't see that pattern, we're done.\n if (!stringified.startsWith('[object ')) {\n return stringified;\n }\n\n // From here on, we can assert that `value` is either an object or an array.\n\n // Do not normalize objects that we know have already been normalized. As a general rule, the\n // \"__sentry_skip_normalization__\" property should only be used sparingly and only should only be set on objects that\n // have already been normalized.\n if ((value as ObjOrArray)['__sentry_skip_normalization__']) {\n return value as ObjOrArray;\n }\n\n // We can set `__sentry_override_normalization_depth__` on an object to ensure that from there\n // We keep a certain amount of depth.\n // This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state.\n const remainingDepth =\n typeof (value as ObjOrArray)['__sentry_override_normalization_depth__'] === 'number'\n ? ((value as ObjOrArray)['__sentry_override_normalization_depth__'] as number)\n : depth;\n\n // We're also done if we've reached the max depth\n if (remainingDepth === 0) {\n // At this point we know `serialized` is a string of the form `\"[object XXXX]\"`. Clean it up so it's just `\"[XXXX]\"`.\n return stringified.replace('object ', '');\n }\n\n // If we've already visited this branch, bail out, as it's circular reference. If not, note that we're seeing it now.\n if (memoize(value)) {\n return '[Circular ~]';\n }\n\n // If the value has a `toJSON` method, we call it to extract more information\n const valueWithToJSON = value as unknown & { toJSON?: () => unknown };\n if (valueWithToJSON && typeof valueWithToJSON.toJSON === 'function') {\n try {\n const jsonValue = valueWithToJSON.toJSON();\n // We need to normalize the return value of `.toJSON()` in case it has circular references\n return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);\n } catch (err) {\n // pass (The built-in `toJSON` failed, but we can still try to do it ourselves)\n }\n }\n\n // At this point we know we either have an object or an array, we haven't seen it before, and we're going to recurse\n // because we haven't yet reached the max depth. Create an accumulator to hold the results of visiting each\n // property/entry, and keep track of the number of items we add to it.\n const normalized = (Array.isArray(value) ? [] : {}) as ObjOrArray;\n let numAdded = 0;\n\n // Before we begin, convert`Error` and`Event` instances into plain objects, since some of each of their relevant\n // properties are non-enumerable and otherwise would get missed.\n const visitable = convertToPlainObject(value as ObjOrArray);\n\n for (const visitKey in visitable) {\n // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.\n if (!Object.prototype.hasOwnProperty.call(visitable, visitKey)) {\n continue;\n }\n\n if (numAdded >= maxProperties) {\n normalized[visitKey] = '[MaxProperties ~]';\n break;\n }\n\n // Recursively visit all the child nodes\n const visitValue = visitable[visitKey];\n normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);\n\n numAdded++;\n }\n\n // Once we've visited all the branches, remove the parent from memo storage\n unmemoize(value);\n\n // Return accumulated values\n return normalized;\n}\n\n/* eslint-disable complexity */\n/**\n * Stringify the given value. Handles various known special values and types.\n *\n * Not meant to be used on simple primitives which already have a string representation, as it will, for example, turn\n * the number 1231 into \"[Object Number]\", nor on `null`, as it will throw.\n *\n * @param value The value to stringify\n * @returns A stringified representation of the given value\n */\nfunction stringifyValue(\n key: unknown,\n // this type is a tiny bit of a cheat, since this function does handle NaN (which is technically a number), but for\n // our internal use, it'll do\n value: Exclude,\n): string {\n try {\n if (key === 'domain' && value && typeof value === 'object' && (value as { _events: unknown })._events) {\n return '[Domain]';\n }\n\n if (key === 'domainEmitter') {\n return '[DomainEmitter]';\n }\n\n // It's safe to use `global`, `window`, and `document` here in this manner, as we are asserting using `typeof` first\n // which won't throw if they are not present.\n\n if (typeof global !== 'undefined' && value === global) {\n return '[Global]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof window !== 'undefined' && value === window) {\n return '[Window]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof document !== 'undefined' && value === document) {\n return '[Document]';\n }\n\n if (isVueViewModel(value)) {\n return '[VueViewModel]';\n }\n\n // React's SyntheticEvent thingy\n if (isSyntheticEvent(value)) {\n return '[SyntheticEvent]';\n }\n\n if (typeof value === 'number' && !Number.isFinite(value)) {\n return `[${value}]`;\n }\n\n if (typeof value === 'function') {\n return `[Function: ${getFunctionName(value)}]`;\n }\n\n if (typeof value === 'symbol') {\n return `[${String(value)}]`;\n }\n\n // stringified BigInts are indistinguishable from regular numbers, so we need to label them to avoid confusion\n if (typeof value === 'bigint') {\n return `[BigInt: ${String(value)}]`;\n }\n\n // Now that we've knocked out all the special cases and the primitives, all we have left are objects. Simply casting\n // them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as\n // `\"[object Object]\"`. If we instead look at the constructor's name (which is the same as the name of the class),\n // we can make sure that only plain objects come out that way.\n const objName = getConstructorName(value);\n\n // Handle HTML Elements\n if (/^HTML(\\w*)Element$/.test(objName)) {\n return `[HTMLElement: ${objName}]`;\n }\n\n return `[object ${objName}]`;\n } catch (err) {\n return `**non-serializable** (${err})`;\n }\n}\n/* eslint-enable complexity */\n\nfunction getConstructorName(value: unknown): string {\n const prototype: Prototype | null = Object.getPrototypeOf(value);\n\n return prototype ? prototype.constructor.name : 'null prototype';\n}\n\n/** Calculates bytes size of input string */\nfunction utf8Length(value: string): number {\n // eslint-disable-next-line no-bitwise\n return ~-encodeURI(value).split(/%..|./).length;\n}\n\n/** Calculates bytes size of input object */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction jsonSize(value: any): number {\n return utf8Length(JSON.stringify(value));\n}\n\n/**\n * Normalizes URLs in exceptions and stacktraces to a base path so Sentry can fingerprint\n * across platforms and working directory.\n *\n * @param url The URL to be normalized.\n * @param basePath The application base path.\n * @returns The normalized URL.\n */\nexport function normalizeUrlToBase(url: string, basePath: string): string {\n const escapedBase = basePath\n // Backslash to forward\n .replace(/\\\\/g, '/')\n // Escape RegExp special characters\n .replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');\n\n let newUrl = url;\n try {\n newUrl = decodeURI(url);\n } catch (_Oo) {\n // Sometime this breaks\n }\n return (\n newUrl\n .replace(/\\\\/g, '/')\n .replace(/webpack:\\/?/g, '') // Remove intermediate base path\n // eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor\n .replace(new RegExp(`(file://)?/*${escapedBase}/*`, 'ig'), 'app:///')\n );\n}\n"],"names":["memo","memoBuilder","convertToPlainObject","isVueViewModel","isSyntheticEvent","getFunctionName"],"mappings":"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"}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy