@zendesk/retrace
Version:
define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API
98 lines (92 loc) • 2.78 kB
text/typescript
const COMMON_EXTENSIONS = [
'.html',
'.js',
'.css',
'.png',
'.jpg',
'.jpeg',
'.gif',
'.svg',
'.webp',
'.woff',
'.woff2',
'.ttf',
'.eot',
'.otf',
'.ico',
]
export function getCommonUrlForTracing(
url: string,
commonExtensions = COMMON_EXTENSIONS,
): {
commonUrl: string
query: Record<string, string | string[]>
hash: string
} {
let commonUrl = url
let hash = ''
const hashIndex = url.indexOf('#')
if (hashIndex >= 0) {
commonUrl = url.slice(0, hashIndex)
hash = url.slice(hashIndex)
}
// Extract query string into a separate variable
const queryStringIndex = url.indexOf('?')
const query: Record<string, string | string[]> = {}
if (queryStringIndex >= 0) {
// Split the URL to get the query string part
commonUrl = url.slice(0, queryStringIndex)
const queryString = url.slice(queryStringIndex + 1)
// Parse query string into an object
queryString
.split('&')
.map((param) => param.split('='))
.forEach(([key, value]) => {
if (!key) return
// decode URI components and handle the case for array parameters
const decodedKey = decodeURIComponent(key)
const decodedValue = value ? decodeURIComponent(value) : ''
// Check if the key already exists
const currentValue = query[decodedKey]
if (currentValue) {
// If it does and it's an array, we push the new value to it
// If it's not an array, we convert it to an array and then add the new value
query[decodedKey] = Array.isArray(currentValue)
? [...currentValue, decodedValue]
: [currentValue, decodedValue]
} else {
// If it doesn't exist, we simply add the key-value pair
query[decodedKey] = decodedValue
}
})
}
// if the URL ends with a common extension, replace file name with $file:
const urlParts = commonUrl.split('/')
const lastPart = urlParts.at(-1)!
const extensionIndex = lastPart.lastIndexOf('.')
const extension =
extensionIndex >= 0 ? lastPart.slice(extensionIndex) : undefined
if (extension && commonExtensions.includes(extension)) {
urlParts[urlParts.length - 1] = '$file'
commonUrl = urlParts.join('/')
}
// replace UUIDs:
commonUrl = commonUrl.replaceAll(
// eslint-disable-next-line unicorn/better-regex
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g,
'$uuid',
)
// replace 32-character or longer hex strings:
commonUrl = commonUrl.replaceAll(
// eslint-disable-next-line unicorn/better-regex
/[0-9a-f]{32,}/g,
'$hex',
)
// Replace numeric parts of the ID with $id
commonUrl = commonUrl.replaceAll(/\d{2,}/g, '$d')
return {
commonUrl,
query,
hash,
}
}