Skip to content

Commit 965e653

Browse files
refactor(router-core): utils/decodePath minor performance improvements (#5865)
* refactor(router-core): utils/decodePath minor performance improvements * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent c05679e commit 965e653

File tree

1 file changed

+49
-50
lines changed

1 file changed

+49
-50
lines changed

packages/router-core/src/utils.ts

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -489,64 +489,63 @@ export function findLast<T>(
489489
return undefined
490490
}
491491

492-
const DECODE_IGNORE_LIST = Array.from(
493-
new Map([
494-
['%', '%25'],
495-
['\\', '%5C'],
496-
]).values(),
497-
)
492+
const DECODE_IGNORE_LIST = [
493+
'%25', // %
494+
'%5C', // \
495+
]
498496

499-
export function decodePath(
497+
function splitAndDecode(
500498
part: string,
501-
decodeIgnore: Array<string> = DECODE_IGNORE_LIST,
499+
decodeIgnore: Array<string>,
500+
startIndex = 0,
502501
): string {
503-
function splitAndDecode(
504-
part: string,
505-
decodeIgnore: Array<string>,
506-
startIndex = 0,
507-
): string {
508-
// decode the path / path segment by splitting it into parts defined by the ignore list.
509-
// once these pieces have been decoded, join them back together to form the final decoded path segment with the ignored character in place.
510-
// we walk through the ignore list linearly, breaking the segment up into pieces and decoding each piece individually.
511-
// use index traversal to avoid making unnecessary copies of the array.
512-
for (let i = startIndex; i < decodeIgnore.length; i++) {
513-
const char = decodeIgnore[i]!.toUpperCase()
514-
515-
// check if the part includes the current ignore character
516-
// if it doesn't continue to the next ignore character
517-
if (part.includes(char)) {
518-
// split the part into pieces that needs to be checked and decoded
519-
const partsToDecode = part.split(char)
520-
const partsToJoin: Array<string> = []
521-
522-
// now check and decode each piece individually taking into consideration the remaining ignored characters.
523-
// since we are walking through the list linearly, we only need to consider ignore items not yet traversed.
524-
for (const partToDecode of partsToDecode) {
525-
// once we have traversed the entire ignore list, each decoded part is returned.
526-
partsToJoin.push(splitAndDecode(partToDecode, decodeIgnore, i + 1))
527-
}
528-
529-
// and join them back together to form the final decoded path segment with the ignored character in place.
530-
return partsToJoin.join(char)
502+
// decode the path / path segment by splitting it into parts defined by the ignore list.
503+
// once these pieces have been decoded, join them back together to form the final decoded path segment with the ignored character in place.
504+
// we walk through the ignore list linearly, breaking the segment up into pieces and decoding each piece individually.
505+
// use index traversal to avoid making unnecessary copies of the array.
506+
for (let i = startIndex; i < decodeIgnore.length; i++) {
507+
const char = decodeIgnore[i]!.toUpperCase()
508+
509+
// check if the part includes the current ignore character
510+
// if it doesn't continue to the next ignore character
511+
if (part.includes(char)) {
512+
// split the part into pieces that needs to be checked and decoded
513+
const partsToDecode = part.split(char)
514+
const partsToJoin = new Array<string>(partsToDecode.length)
515+
516+
// now check and decode each piece individually taking into consideration the remaining ignored characters.
517+
// since we are walking through the list linearly, we only need to consider ignore items not yet traversed.
518+
for (let j = 0; j < partsToDecode.length; j++) {
519+
const partToDecode = partsToDecode[j]!
520+
// once we have traversed the entire ignore list, each decoded part is returned.
521+
partsToJoin[j] = splitAndDecode(partToDecode, decodeIgnore, i + 1)
531522
}
532-
}
533523

534-
// once we have reached the end of the ignore list, we start walking back returning each decoded part.
535-
// should there be no matching characters, the path segment as a whole will be decoded.
536-
try {
537-
return decodeURI(part)
538-
} catch {
539-
// if the decoding fails, try to decode the various parts leaving the malformed tags in place
540-
return part.replaceAll(/%[0-9A-F]{2}/g, (match) => {
541-
try {
542-
return decodeURI(match)
543-
} catch {
544-
return match
545-
}
546-
})
524+
// and join them back together to form the final decoded path segment with the ignored character in place.
525+
return partsToJoin.join(char)
547526
}
548527
}
549528

529+
// once we have reached the end of the ignore list, we start walking back returning each decoded part.
530+
// should there be no matching characters, the path segment as a whole will be decoded.
531+
try {
532+
return decodeURI(part)
533+
} catch {
534+
// if the decoding fails, try to decode the various parts leaving the malformed tags in place
535+
return part.replaceAll(/%[0-9A-F]{2}/g, (match) => {
536+
try {
537+
return decodeURI(match)
538+
} catch {
539+
return match
540+
}
541+
})
542+
}
543+
}
544+
545+
export function decodePath(
546+
part: string,
547+
decodeIgnore: Array<string> = DECODE_IGNORE_LIST,
548+
): string {
550549
// if the path segment does not contain any encoded uri components return the path as is
551550
if (part === '' || !/%[0-9A-Fa-f]{2}/g.test(part)) return part
552551

0 commit comments

Comments
 (0)