@tanstack/router-core 1.133.27 → 1.133.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/path.cjs +1 -1
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +22 -0
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/rewrite.cjs.map +1 -1
- package/dist/cjs/rewrite.d.cts +4 -0
- package/dist/cjs/router.cjs +12 -10
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +14 -0
- package/dist/cjs/searchParams.cjs.map +1 -1
- package/dist/cjs/searchParams.d.cts +2 -0
- package/dist/cjs/utils.cjs +44 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +24 -0
- package/dist/esm/path.d.ts +22 -0
- package/dist/esm/path.js +2 -2
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/rewrite.d.ts +4 -0
- package/dist/esm/rewrite.js.map +1 -1
- package/dist/esm/router.js +13 -11
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +14 -0
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/searchParams.d.ts +2 -0
- package/dist/esm/searchParams.js.map +1 -1
- package/dist/esm/utils.d.ts +24 -0
- package/dist/esm/utils.js +44 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/path.ts +24 -7
- package/src/qss.ts +1 -0
- package/src/rewrite.ts +4 -0
- package/src/router.ts +13 -10
- package/src/scroll-restoration.ts +14 -0
- package/src/searchParams.ts +2 -0
- package/src/utils.ts +93 -0
package/src/utils.ts
CHANGED
|
@@ -184,6 +184,10 @@ export type LooseAsyncReturnType<T> = T extends (
|
|
|
184
184
|
: TReturn
|
|
185
185
|
: never
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Return the last element of an array.
|
|
189
|
+
* Intended for non-empty arrays used within router internals.
|
|
190
|
+
*/
|
|
187
191
|
export function last<T>(arr: Array<T>) {
|
|
188
192
|
return arr[arr.length - 1]
|
|
189
193
|
}
|
|
@@ -192,6 +196,10 @@ function isFunction(d: any): d is Function {
|
|
|
192
196
|
return typeof d === 'function'
|
|
193
197
|
}
|
|
194
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Apply a value-or-updater to a previous value.
|
|
201
|
+
* Accepts either a literal value or a function of the previous value.
|
|
202
|
+
*/
|
|
195
203
|
export function functionalUpdate<TPrevious, TResult = TPrevious>(
|
|
196
204
|
updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,
|
|
197
205
|
previous: TPrevious,
|
|
@@ -311,10 +319,17 @@ function hasObjectPrototype(o: any) {
|
|
|
311
319
|
return Object.prototype.toString.call(o) === '[object Object]'
|
|
312
320
|
}
|
|
313
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Check if a value is a "plain" array (no extra enumerable keys).
|
|
324
|
+
*/
|
|
314
325
|
export function isPlainArray(value: unknown): value is Array<unknown> {
|
|
315
326
|
return Array.isArray(value) && value.length === Object.keys(value).length
|
|
316
327
|
}
|
|
317
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Perform a deep equality check with options for partial comparison and
|
|
331
|
+
* ignoring `undefined` values. Optimized for router state comparisons.
|
|
332
|
+
*/
|
|
318
333
|
export function deepEqual(
|
|
319
334
|
a: any,
|
|
320
335
|
b: any,
|
|
@@ -407,6 +422,10 @@ export type ControlledPromise<T> = Promise<T> & {
|
|
|
407
422
|
value?: T
|
|
408
423
|
}
|
|
409
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Create a promise with exposed resolve/reject and status fields.
|
|
427
|
+
* Useful for coordinating async router lifecycle operations.
|
|
428
|
+
*/
|
|
410
429
|
export function createControlledPromise<T>(onResolve?: (value: T) => void) {
|
|
411
430
|
let resolveLoadPromise!: (value: T) => void
|
|
412
431
|
let rejectLoadPromise!: (value: any) => void
|
|
@@ -433,6 +452,10 @@ export function createControlledPromise<T>(onResolve?: (value: T) => void) {
|
|
|
433
452
|
return controlledPromise
|
|
434
453
|
}
|
|
435
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Heuristically detect dynamic import "module not found" errors
|
|
457
|
+
* across major browsers for lazy route component handling.
|
|
458
|
+
*/
|
|
436
459
|
export function isModuleNotFoundError(error: any): boolean {
|
|
437
460
|
// chrome: "Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
438
461
|
// firefox: "error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
@@ -465,3 +488,73 @@ export function findLast<T>(
|
|
|
465
488
|
}
|
|
466
489
|
return undefined
|
|
467
490
|
}
|
|
491
|
+
|
|
492
|
+
const DECODE_IGNORE_LIST = Array.from(
|
|
493
|
+
new Map([
|
|
494
|
+
['%', '%25'],
|
|
495
|
+
['\\', '%5C'],
|
|
496
|
+
['/', '%2F'],
|
|
497
|
+
[';', '%3B'],
|
|
498
|
+
[':', '%3A'],
|
|
499
|
+
['@', '%40'],
|
|
500
|
+
['&', '%26'],
|
|
501
|
+
['=', '%3D'],
|
|
502
|
+
['+', '%2B'],
|
|
503
|
+
['$', '%24'],
|
|
504
|
+
[',', '%2C'],
|
|
505
|
+
]).values(),
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
export function decodePathSegment(
|
|
509
|
+
part: string,
|
|
510
|
+
decodeIgnore: Array<string> = DECODE_IGNORE_LIST,
|
|
511
|
+
startIndex = 0,
|
|
512
|
+
): string {
|
|
513
|
+
function decode(part: string): string {
|
|
514
|
+
try {
|
|
515
|
+
return decodeURIComponent(part)
|
|
516
|
+
} catch {
|
|
517
|
+
// if the decoding fails, try to decode the various parts leaving the malformed tags in place
|
|
518
|
+
return part.replaceAll(/%[0-9A-Fa-f]{2}/g, (match) => {
|
|
519
|
+
try {
|
|
520
|
+
return decodeURIComponent(match)
|
|
521
|
+
} catch {
|
|
522
|
+
return match
|
|
523
|
+
}
|
|
524
|
+
})
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// if the path segment does not contain any encoded uri components return the path as is
|
|
529
|
+
if (part === '' || !part.match(/%[0-9A-Fa-f]{2}/g)) return part
|
|
530
|
+
|
|
531
|
+
// decode the path / path segment by splitting it into parts defined by the ignore list.
|
|
532
|
+
// once these pieces have been decoded, join them back together to form the final decoded path segment with the ignored character in place.
|
|
533
|
+
// we walk through the ignore list linearly, breaking the segment up into pieces and decoding each piece individually.
|
|
534
|
+
// use index traversal to avoid making unnecessary copies of the array.
|
|
535
|
+
for (let i = startIndex; i < decodeIgnore.length; i++) {
|
|
536
|
+
const char = decodeIgnore[i]
|
|
537
|
+
|
|
538
|
+
// check if the part includes the current ignore character
|
|
539
|
+
// if it doesn't continue to the next ignore character
|
|
540
|
+
if (char && part.includes(char)) {
|
|
541
|
+
// split the part into pieces that needs to be checked and decoded
|
|
542
|
+
const partsToDecode = part.split(char)
|
|
543
|
+
const partsToJoin: Array<string> = []
|
|
544
|
+
|
|
545
|
+
// now check and decode each piece individually taking into consideration the remaining ignored characters.
|
|
546
|
+
// since we are walking through the list linearly, we only need to consider ignore items not yet traversed.
|
|
547
|
+
for (const partToDecode of partsToDecode) {
|
|
548
|
+
// once we have traversed the entire ignore list, each decoded part is returned.
|
|
549
|
+
partsToJoin.push(decodePathSegment(partToDecode, decodeIgnore, i + 1))
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// and join them back together to form the final decoded path segment with the ignored character in place.
|
|
553
|
+
return partsToJoin.join(char)
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// once we have reached the end of the ignore list, we start walking back returning each decoded part.
|
|
558
|
+
// should there be no matching characters, the path segment as a whole will be decoded.
|
|
559
|
+
return decode(part)
|
|
560
|
+
}
|