@jsenv/navi 0.16.30 → 0.16.32
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/jsenv_navi.js +251 -288
- package/dist/jsenv_navi.js.map +5 -5
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -2499,7 +2499,7 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2499
2499
|
if (globalSignalRegistry.has(signalIdString)) {
|
|
2500
2500
|
const conflictInfo = globalSignalRegistry.get(signalIdString);
|
|
2501
2501
|
throw new Error(
|
|
2502
|
-
`Signal ID conflict: A signal with ID "${signalIdString}" already exists (existing default: ${conflictInfo.options.
|
|
2502
|
+
`Signal ID conflict: A signal with ID "${signalIdString}" already exists (existing default: ${conflictInfo.options.getDefaultValue()})`,
|
|
2503
2503
|
);
|
|
2504
2504
|
}
|
|
2505
2505
|
|
|
@@ -2509,45 +2509,61 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2509
2509
|
persists
|
|
2510
2510
|
? valueInLocalStorage(localStorageKey, { type })
|
|
2511
2511
|
: NO_LOCAL_STORAGE;
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
);
|
|
2520
|
-
}
|
|
2521
|
-
return valueFromLocalStorage;
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Returns the current default value from code logic only (static or dynamic).
|
|
2514
|
+
* NEVER considers localStorage - used for URL building and route matching.
|
|
2515
|
+
*
|
|
2516
|
+
* @returns {any} The current code default value, undefined if no default
|
|
2517
|
+
*/
|
|
2518
|
+
const getDefaultValue = (internalCall) => {
|
|
2524
2519
|
if (dynamicDefaultSignal) {
|
|
2525
2520
|
const dynamicValue = dynamicDefaultSignal.peek();
|
|
2526
2521
|
if (dynamicValue === undefined) {
|
|
2527
2522
|
if (staticDefaultValue === undefined) {
|
|
2528
2523
|
return undefined;
|
|
2529
2524
|
}
|
|
2530
|
-
if (debug) {
|
|
2525
|
+
if (debug && internalCall) {
|
|
2531
2526
|
console.debug(
|
|
2532
2527
|
`[stateSignal:${signalIdString}] dynamic default is undefined, using static default=${staticDefaultValue}`,
|
|
2533
2528
|
);
|
|
2534
2529
|
}
|
|
2535
2530
|
return staticDefaultValue;
|
|
2536
2531
|
}
|
|
2537
|
-
if (debug) {
|
|
2532
|
+
if (debug && internalCall) {
|
|
2538
2533
|
console.debug(
|
|
2539
2534
|
`[stateSignal:${signalIdString}] using value from dynamic default signal=${dynamicValue}`,
|
|
2540
2535
|
);
|
|
2541
2536
|
}
|
|
2542
2537
|
return dynamicValue;
|
|
2543
2538
|
}
|
|
2544
|
-
if (debug) {
|
|
2539
|
+
if (debug && internalCall) {
|
|
2545
2540
|
console.debug(
|
|
2546
2541
|
`[stateSignal:${signalIdString}] using static default value=${staticDefaultValue}`,
|
|
2547
2542
|
);
|
|
2548
2543
|
}
|
|
2549
2544
|
return staticDefaultValue;
|
|
2550
2545
|
};
|
|
2546
|
+
|
|
2547
|
+
/**
|
|
2548
|
+
* Returns fallback value: localStorage first, then code default.
|
|
2549
|
+
* Used for signal initialization and resets.
|
|
2550
|
+
*
|
|
2551
|
+
* @returns {any} The fallback value (localStorage or code default)
|
|
2552
|
+
*/
|
|
2553
|
+
const getFallbackValue = () => {
|
|
2554
|
+
if (persists) {
|
|
2555
|
+
const valueFromLocalStorage = readFromLocalStorage();
|
|
2556
|
+
if (valueFromLocalStorage !== undefined) {
|
|
2557
|
+
if (debug) {
|
|
2558
|
+
console.debug(
|
|
2559
|
+
`[stateSignal:${signalIdString}] using value from localStorage "${localStorageKey}"=${valueFromLocalStorage}`,
|
|
2560
|
+
);
|
|
2561
|
+
}
|
|
2562
|
+
return valueFromLocalStorage;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
return getDefaultValue(true);
|
|
2566
|
+
};
|
|
2551
2567
|
const isCustomValue = (value) => {
|
|
2552
2568
|
if (value === undefined) {
|
|
2553
2569
|
return false;
|
|
@@ -2563,7 +2579,7 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2563
2579
|
};
|
|
2564
2580
|
|
|
2565
2581
|
// Create signal with initial value: use stored value, or undefined to indicate no explicit value
|
|
2566
|
-
const advancedSignal = signal(
|
|
2582
|
+
const advancedSignal = signal(getFallbackValue());
|
|
2567
2583
|
const validity = { valid: true };
|
|
2568
2584
|
advancedSignal.validity = validity;
|
|
2569
2585
|
advancedSignal.__signalId = signalIdString;
|
|
@@ -2581,16 +2597,16 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2581
2597
|
if (value !== undefined) {
|
|
2582
2598
|
return;
|
|
2583
2599
|
}
|
|
2584
|
-
const
|
|
2585
|
-
if (
|
|
2600
|
+
const fallbackValue = getFallbackValue();
|
|
2601
|
+
if (fallbackValue === value) {
|
|
2586
2602
|
return;
|
|
2587
2603
|
}
|
|
2588
2604
|
if (debug) {
|
|
2589
2605
|
console.debug(
|
|
2590
|
-
`[stateSignal:${signalIdString}] becomes undefined, reset to ${
|
|
2606
|
+
`[stateSignal:${signalIdString}] becomes undefined, reset to ${fallbackValue}`,
|
|
2591
2607
|
);
|
|
2592
2608
|
}
|
|
2593
|
-
advancedSignal.value =
|
|
2609
|
+
advancedSignal.value = fallbackValue;
|
|
2594
2610
|
});
|
|
2595
2611
|
}
|
|
2596
2612
|
dynamic_signal_effect: {
|
|
@@ -2630,18 +2646,18 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2630
2646
|
}
|
|
2631
2647
|
|
|
2632
2648
|
// Signal was using default value, update to new default
|
|
2633
|
-
const
|
|
2634
|
-
if (
|
|
2649
|
+
const newFallbackValue = getFallbackValue();
|
|
2650
|
+
if (newFallbackValue === value) {
|
|
2635
2651
|
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2636
2652
|
return;
|
|
2637
2653
|
}
|
|
2638
2654
|
if (debug) {
|
|
2639
2655
|
console.debug(
|
|
2640
|
-
`[stateSignal:${signalIdString}] dynamic default updated, update to ${
|
|
2656
|
+
`[stateSignal:${signalIdString}] dynamic default updated, update to ${newFallbackValue}`,
|
|
2641
2657
|
);
|
|
2642
2658
|
}
|
|
2643
2659
|
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2644
|
-
advancedSignal.value =
|
|
2660
|
+
advancedSignal.value = newFallbackValue;
|
|
2645
2661
|
});
|
|
2646
2662
|
}
|
|
2647
2663
|
persist_in_local_storage: {
|
|
@@ -2711,8 +2727,8 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2711
2727
|
globalSignalRegistry.set(signalIdString, {
|
|
2712
2728
|
signal: advancedSignal,
|
|
2713
2729
|
options: {
|
|
2730
|
+
staticDefaultValue,
|
|
2714
2731
|
getDefaultValue,
|
|
2715
|
-
defaultValue: staticDefaultValue,
|
|
2716
2732
|
dynamicDefaultSignal,
|
|
2717
2733
|
isCustomValue,
|
|
2718
2734
|
type,
|
|
@@ -7755,9 +7771,9 @@ const detectSignals = (routePattern) => {
|
|
|
7755
7771
|
updatedPattern = updatedPattern.replace(fullMatch, replacement);
|
|
7756
7772
|
|
|
7757
7773
|
signalConnections.push({
|
|
7758
|
-
signal,
|
|
7759
7774
|
paramName,
|
|
7760
|
-
|
|
7775
|
+
signal,
|
|
7776
|
+
...options,
|
|
7761
7777
|
});
|
|
7762
7778
|
} else {
|
|
7763
7779
|
console.warn(
|
|
@@ -7780,30 +7796,18 @@ const detectSignals = (routePattern) => {
|
|
|
7780
7796
|
const createRoutePattern = (pattern) => {
|
|
7781
7797
|
// Detect and process signals in the pattern first
|
|
7782
7798
|
const [cleanPattern, connections] = detectSignals(pattern);
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
const parameterDefaults = new Map();
|
|
7786
|
-
for (const connection of connections) {
|
|
7787
|
-
const { paramName, options } = connection;
|
|
7788
|
-
if (options.defaultValue !== undefined) {
|
|
7789
|
-
parameterDefaults.set(paramName, options.defaultValue);
|
|
7790
|
-
}
|
|
7791
|
-
}
|
|
7792
|
-
|
|
7793
|
-
const parsedPattern = parsePattern(
|
|
7794
|
-
cleanPattern,
|
|
7795
|
-
parameterDefaults,
|
|
7796
|
-
connections,
|
|
7797
|
-
);
|
|
7798
|
-
|
|
7799
|
+
// Build parameter connection map for efficient lookups
|
|
7800
|
+
const connectionMap = new Map();
|
|
7799
7801
|
// Create signalSet to track all signals this pattern depends on
|
|
7800
7802
|
const signalSet = new Set();
|
|
7801
7803
|
for (const connection of connections) {
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7804
|
+
connectionMap.set(connection.paramName, connection);
|
|
7805
|
+
|
|
7806
|
+
signalSet.add(connection.signal);
|
|
7805
7807
|
}
|
|
7806
7808
|
|
|
7809
|
+
const parsedPattern = parsePattern(cleanPattern, connectionMap);
|
|
7810
|
+
|
|
7807
7811
|
if (DEBUG$2) {
|
|
7808
7812
|
console.debug(`[CustomPattern] Created pattern:`, parsedPattern);
|
|
7809
7813
|
console.debug(`[CustomPattern] Signal connections:`, connections);
|
|
@@ -7831,26 +7835,34 @@ const createRoutePattern = (pattern) => {
|
|
|
7831
7835
|
let resolvedParams = { ...providedParams };
|
|
7832
7836
|
|
|
7833
7837
|
// Process all connections for parameter resolution
|
|
7834
|
-
for (const connection of
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
+
for (const [paramName, connection] of connectionMap) {
|
|
7839
|
+
if (paramName in providedParams) {
|
|
7840
|
+
// Parameter was explicitly provided - always respect explicit parameters
|
|
7841
|
+
// Don't check signal value - explicit parameter takes precedence
|
|
7842
|
+
continue;
|
|
7843
|
+
}
|
|
7844
|
+
const signalValue = connection.signal.value;
|
|
7845
|
+
if (signalValue !== undefined) {
|
|
7838
7846
|
// Parameter was not provided, check signal value
|
|
7839
|
-
resolvedParams[paramName] =
|
|
7847
|
+
resolvedParams[paramName] = signalValue;
|
|
7840
7848
|
}
|
|
7841
7849
|
}
|
|
7842
7850
|
|
|
7843
|
-
// Add
|
|
7844
|
-
//
|
|
7845
|
-
for (const [paramName,
|
|
7846
|
-
if (
|
|
7847
|
-
|
|
7851
|
+
// Add defaults for parameters that are still missing
|
|
7852
|
+
// Use current dynamic defaults from signal connections
|
|
7853
|
+
for (const [paramName, connection] of connectionMap) {
|
|
7854
|
+
if (paramName in resolvedParams) {
|
|
7855
|
+
continue;
|
|
7856
|
+
}
|
|
7857
|
+
const currentDefault = connection.getDefaultValue();
|
|
7858
|
+
if (currentDefault !== undefined) {
|
|
7859
|
+
resolvedParams[paramName] = currentDefault;
|
|
7848
7860
|
}
|
|
7849
7861
|
}
|
|
7850
7862
|
|
|
7851
7863
|
// Include active non-default parameters from child routes for URL optimization
|
|
7852
7864
|
// Only include from child routes that would actually match the current parameters
|
|
7853
|
-
const childPatternObjs = patternObject.children
|
|
7865
|
+
const childPatternObjs = patternObject.children;
|
|
7854
7866
|
for (const childPatternObj of childPatternObjs) {
|
|
7855
7867
|
// Check if this child route would match the current resolved parameters
|
|
7856
7868
|
// by simulating URL building and seeing if the child segments align
|
|
@@ -7876,20 +7888,20 @@ const createRoutePattern = (pattern) => {
|
|
|
7876
7888
|
}
|
|
7877
7889
|
|
|
7878
7890
|
if (childWouldMatch) {
|
|
7879
|
-
for (const
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7891
|
+
for (const [
|
|
7892
|
+
childParam,
|
|
7893
|
+
childConnection,
|
|
7894
|
+
] of childPatternObj.connectionMap) {
|
|
7895
|
+
if (childParam in resolvedParams) {
|
|
7896
|
+
continue;
|
|
7897
|
+
}
|
|
7898
|
+
const childSignalValue = childConnection.signal.value;
|
|
7886
7899
|
// Only include if not already resolved and is non-default
|
|
7887
7900
|
if (
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
childSignal.value !== childOptions.defaultValue
|
|
7901
|
+
childSignalValue !== undefined &&
|
|
7902
|
+
childSignalValue !== childConnection.getDefaultValue()
|
|
7891
7903
|
) {
|
|
7892
|
-
resolvedParams[childParam] =
|
|
7904
|
+
resolvedParams[childParam] = childSignalValue;
|
|
7893
7905
|
}
|
|
7894
7906
|
}
|
|
7895
7907
|
}
|
|
@@ -7914,18 +7926,21 @@ const createRoutePattern = (pattern) => {
|
|
|
7914
7926
|
const removeDefaultValues = (params) => {
|
|
7915
7927
|
const filtered = { ...params };
|
|
7916
7928
|
|
|
7917
|
-
for (const connection of
|
|
7918
|
-
const { paramName, signal, options } = connection;
|
|
7919
|
-
|
|
7929
|
+
for (const [paramName, connection] of connectionMap) {
|
|
7920
7930
|
if (paramName in filtered) {
|
|
7921
7931
|
// Parameter is explicitly provided - check if we should remove it
|
|
7922
|
-
|
|
7923
|
-
|
|
7932
|
+
const paramValue = filtered[paramName];
|
|
7933
|
+
|
|
7934
|
+
if (!connection.isCustomValue(paramValue)) {
|
|
7924
7935
|
delete filtered[paramName];
|
|
7925
7936
|
}
|
|
7926
|
-
} else
|
|
7927
|
-
// Parameter not provided but signal has
|
|
7928
|
-
|
|
7937
|
+
} else {
|
|
7938
|
+
// Parameter not provided but signal has a value
|
|
7939
|
+
const signalValue = connection.signal.value;
|
|
7940
|
+
if (connection.isCustomValue(signalValue)) {
|
|
7941
|
+
// Only include custom values
|
|
7942
|
+
filtered[paramName] = signalValue;
|
|
7943
|
+
}
|
|
7929
7944
|
}
|
|
7930
7945
|
}
|
|
7931
7946
|
|
|
@@ -7938,12 +7953,11 @@ const createRoutePattern = (pattern) => {
|
|
|
7938
7953
|
const canReachLiteralValue = (literalValue, params) => {
|
|
7939
7954
|
// Check parent's own parameters (signals and user params)
|
|
7940
7955
|
const parentCanProvide = connections.some((conn) => {
|
|
7941
|
-
const signalValue = conn.signal
|
|
7956
|
+
const signalValue = conn.signal.value;
|
|
7942
7957
|
const userValue = params[conn.paramName];
|
|
7943
7958
|
const effectiveValue = userValue !== undefined ? userValue : signalValue;
|
|
7944
7959
|
return (
|
|
7945
|
-
effectiveValue === literalValue &&
|
|
7946
|
-
conn.options.isCustomValue?.(effectiveValue)
|
|
7960
|
+
effectiveValue === literalValue && conn.isCustomValue(effectiveValue)
|
|
7947
7961
|
);
|
|
7948
7962
|
});
|
|
7949
7963
|
|
|
@@ -7966,7 +7980,7 @@ const createRoutePattern = (pattern) => {
|
|
|
7966
7980
|
|
|
7967
7981
|
const getDescendantSignals = (pattern) => {
|
|
7968
7982
|
const signals = [...pattern.connections];
|
|
7969
|
-
for (const child of pattern.children
|
|
7983
|
+
for (const child of pattern.children) {
|
|
7970
7984
|
signals.push(...getDescendantSignals(child));
|
|
7971
7985
|
}
|
|
7972
7986
|
return signals;
|
|
@@ -7978,11 +7992,8 @@ const createRoutePattern = (pattern) => {
|
|
|
7978
7992
|
];
|
|
7979
7993
|
|
|
7980
7994
|
const systemCanProvide = allRelevantSignals.some((conn) => {
|
|
7981
|
-
const signalValue = conn.signal
|
|
7982
|
-
return (
|
|
7983
|
-
signalValue === literalValue &&
|
|
7984
|
-
conn.options.isCustomValue?.(signalValue)
|
|
7985
|
-
);
|
|
7995
|
+
const signalValue = conn.signal.value;
|
|
7996
|
+
return signalValue === literalValue && conn.isCustomValue(signalValue);
|
|
7986
7997
|
});
|
|
7987
7998
|
|
|
7988
7999
|
return parentCanProvide || userCanProvide || systemCanProvide;
|
|
@@ -8034,10 +8045,8 @@ const createRoutePattern = (pattern) => {
|
|
|
8034
8045
|
|
|
8035
8046
|
// If not in params, check signals
|
|
8036
8047
|
if (parentParamValue === undefined) {
|
|
8037
|
-
const parentConnection =
|
|
8038
|
-
|
|
8039
|
-
);
|
|
8040
|
-
if (parentConnection && parentConnection.signal) {
|
|
8048
|
+
const parentConnection = connectionMap.get(paramName);
|
|
8049
|
+
if (parentConnection) {
|
|
8041
8050
|
parentParamValue = parentConnection.signal.value;
|
|
8042
8051
|
}
|
|
8043
8052
|
}
|
|
@@ -8122,16 +8131,12 @@ const createRoutePattern = (pattern) => {
|
|
|
8122
8131
|
paramName = item.paramName;
|
|
8123
8132
|
paramValue = item.userValue;
|
|
8124
8133
|
} else {
|
|
8125
|
-
|
|
8126
|
-
|
|
8134
|
+
paramName = item.paramName;
|
|
8135
|
+
paramValue = item.signal.value;
|
|
8127
8136
|
// Only include custom parent signal values (not using defaults)
|
|
8128
|
-
if (
|
|
8129
|
-
signal?.value === undefined ||
|
|
8130
|
-
!options.isCustomValue?.(signal.value)
|
|
8131
|
-
) {
|
|
8137
|
+
if (paramValue === undefined || !item.isCustomValue(paramValue)) {
|
|
8132
8138
|
return { isCompatible: true, shouldInclude: false };
|
|
8133
8139
|
}
|
|
8134
|
-
paramValue = signal.value;
|
|
8135
8140
|
}
|
|
8136
8141
|
|
|
8137
8142
|
// Check if parameter value matches a literal segment in child pattern
|
|
@@ -8151,9 +8156,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8151
8156
|
|
|
8152
8157
|
// ROBUST FIX: For path parameters, check semantic compatibility by verifying
|
|
8153
8158
|
// that parent parameter values can actually produce the child route structure
|
|
8154
|
-
const isParentPathParam =
|
|
8155
|
-
(conn) => conn.paramName === paramName,
|
|
8156
|
-
);
|
|
8159
|
+
const isParentPathParam = connectionMap.has(paramName);
|
|
8157
8160
|
if (isParentPathParam) {
|
|
8158
8161
|
// Check if parent parameter value matches any child literal where it should
|
|
8159
8162
|
// The key insight: if parent has a specific parameter value, child route must
|
|
@@ -8187,9 +8190,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8187
8190
|
// Check for generic parameter-literal conflicts (only for path parameters)
|
|
8188
8191
|
if (!matchesChildLiteral) {
|
|
8189
8192
|
// Check if this is a path parameter from parent pattern
|
|
8190
|
-
const isParentPathParam =
|
|
8191
|
-
(conn) => conn.paramName === paramName,
|
|
8192
|
-
);
|
|
8193
|
+
const isParentPathParam = connectionMap.has(paramName);
|
|
8193
8194
|
if (isParentPathParam) {
|
|
8194
8195
|
// Parameter value (from user or signal) doesn't match this child's literals
|
|
8195
8196
|
// Check if child has any literal segments that would conflict with this parameter
|
|
@@ -8224,49 +8225,41 @@ const createRoutePattern = (pattern) => {
|
|
|
8224
8225
|
// CRITICAL: Check if user explicitly passed undefined for parameters that would
|
|
8225
8226
|
// normally be used to select this child route via sibling route relationships
|
|
8226
8227
|
for (const [paramName, paramValue] of Object.entries(params)) {
|
|
8227
|
-
if (paramValue
|
|
8228
|
-
|
|
8229
|
-
|
|
8228
|
+
if (paramValue !== undefined) {
|
|
8229
|
+
continue;
|
|
8230
|
+
}
|
|
8230
8231
|
|
|
8231
|
-
|
|
8232
|
-
|
|
8232
|
+
// Look for sibling routes (other children of the same parent) that use this parameter
|
|
8233
|
+
const siblingPatternObjs = patternObject.children;
|
|
8234
|
+
for (const siblingPatternObj of siblingPatternObjs) {
|
|
8235
|
+
if (siblingPatternObj === childPatternObj) continue; // Skip self
|
|
8233
8236
|
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
+
// Check if sibling route uses this parameter and get the connection
|
|
8238
|
+
const siblingConnection =
|
|
8239
|
+
siblingPatternObj.connectionMap.get(paramName);
|
|
8240
|
+
if (!siblingConnection) {
|
|
8241
|
+
continue;
|
|
8242
|
+
}
|
|
8243
|
+
const siblingSignalValue = siblingConnection.signal.value;
|
|
8244
|
+
if (siblingSignalValue === undefined) {
|
|
8245
|
+
continue;
|
|
8246
|
+
}
|
|
8247
|
+
// Check if this child route has a literal that matches the signal value
|
|
8248
|
+
const signalMatchesThisChildLiteral =
|
|
8249
|
+
childPatternObj.pattern.segments.some(
|
|
8250
|
+
(segment) =>
|
|
8251
|
+
segment.type === "literal" &&
|
|
8252
|
+
segment.value === siblingSignalValue,
|
|
8237
8253
|
);
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8254
|
+
if (signalMatchesThisChildLiteral) {
|
|
8255
|
+
// This child route's literal matches the sibling's signal value
|
|
8256
|
+
// User passed undefined to override that signal - don't use this child route
|
|
8257
|
+
if (DEBUG$2) {
|
|
8258
|
+
console.debug(
|
|
8259
|
+
`[${pattern}] Blocking child route ${childPatternObj.originalPattern} because ${paramName}:undefined overrides sibling signal value "${siblingSignalValue}"`,
|
|
8243
8260
|
);
|
|
8244
|
-
|
|
8245
|
-
if (
|
|
8246
|
-
siblingConnection &&
|
|
8247
|
-
siblingConnection.signal?.value !== undefined
|
|
8248
|
-
) {
|
|
8249
|
-
const signalValue = siblingConnection.signal.value;
|
|
8250
|
-
|
|
8251
|
-
// Check if this child route has a literal that matches the signal value
|
|
8252
|
-
const signalMatchesThisChildLiteral =
|
|
8253
|
-
childPatternObj.pattern.segments.some(
|
|
8254
|
-
(segment) =>
|
|
8255
|
-
segment.type === "literal" && segment.value === signalValue,
|
|
8256
|
-
);
|
|
8257
|
-
|
|
8258
|
-
if (signalMatchesThisChildLiteral) {
|
|
8259
|
-
// This child route's literal matches the sibling's signal value
|
|
8260
|
-
// User passed undefined to override that signal - don't use this child route
|
|
8261
|
-
if (DEBUG$2) {
|
|
8262
|
-
console.debug(
|
|
8263
|
-
`[${pattern}] Blocking child route ${childPatternObj.originalPattern} because ${paramName}:undefined overrides sibling signal value "${signalValue}"`,
|
|
8264
|
-
);
|
|
8265
|
-
}
|
|
8266
|
-
return false;
|
|
8267
|
-
}
|
|
8268
|
-
}
|
|
8269
8261
|
}
|
|
8262
|
+
return false;
|
|
8270
8263
|
}
|
|
8271
8264
|
}
|
|
8272
8265
|
}
|
|
@@ -8275,9 +8268,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8275
8268
|
let hasActiveParams = false;
|
|
8276
8269
|
const childParams = { ...compatibility.childParams };
|
|
8277
8270
|
|
|
8278
|
-
for (const connection of childPatternObj.
|
|
8279
|
-
const { paramName, signal, options } = connection;
|
|
8280
|
-
|
|
8271
|
+
for (const [paramName, connection] of childPatternObj.connectionMap) {
|
|
8281
8272
|
// Check if parameter was explicitly provided by user
|
|
8282
8273
|
const hasExplicitParam = paramName in params;
|
|
8283
8274
|
const explicitValue = params[paramName];
|
|
@@ -8287,15 +8278,18 @@ const createRoutePattern = (pattern) => {
|
|
|
8287
8278
|
childParams[paramName] = explicitValue;
|
|
8288
8279
|
if (
|
|
8289
8280
|
explicitValue !== undefined &&
|
|
8290
|
-
|
|
8281
|
+
connection.isCustomValue(explicitValue)
|
|
8291
8282
|
) {
|
|
8292
8283
|
hasActiveParams = true;
|
|
8293
8284
|
}
|
|
8294
|
-
} else
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8285
|
+
} else {
|
|
8286
|
+
const signalValue = connection.signal.value;
|
|
8287
|
+
if (signalValue !== undefined) {
|
|
8288
|
+
// No explicit override - use signal value
|
|
8289
|
+
childParams[paramName] = signalValue;
|
|
8290
|
+
if (connection.isCustomValue(signalValue)) {
|
|
8291
|
+
hasActiveParams = true;
|
|
8292
|
+
}
|
|
8299
8293
|
}
|
|
8300
8294
|
}
|
|
8301
8295
|
}
|
|
@@ -8320,19 +8314,17 @@ const createRoutePattern = (pattern) => {
|
|
|
8320
8314
|
if (value === undefined) return false;
|
|
8321
8315
|
|
|
8322
8316
|
// Check if this parameter has a default value in child's connections
|
|
8323
|
-
const childConnection = childPatternObj.
|
|
8324
|
-
(conn) => conn.paramName === paramName,
|
|
8325
|
-
);
|
|
8317
|
+
const childConnection = childPatternObj.connectionMap.get(paramName);
|
|
8326
8318
|
if (childConnection) {
|
|
8327
|
-
|
|
8319
|
+
const childDefault = childConnection.getDefaultValue();
|
|
8320
|
+
return value !== childDefault;
|
|
8328
8321
|
}
|
|
8329
8322
|
|
|
8330
8323
|
// Check if this parameter has a default value in parent's connections (current pattern)
|
|
8331
|
-
const parentConnection =
|
|
8332
|
-
(conn) => conn.paramName === paramName,
|
|
8333
|
-
);
|
|
8324
|
+
const parentConnection = connectionMap.get(paramName);
|
|
8334
8325
|
if (parentConnection) {
|
|
8335
|
-
|
|
8326
|
+
const parentDefault = parentConnection.getDefaultValue();
|
|
8327
|
+
return value !== parentDefault;
|
|
8336
8328
|
}
|
|
8337
8329
|
|
|
8338
8330
|
return true; // Non-connection parameters are considered non-default
|
|
@@ -8373,18 +8365,17 @@ const createRoutePattern = (pattern) => {
|
|
|
8373
8365
|
|
|
8374
8366
|
// Check if parameters that determine child selection are non-default
|
|
8375
8367
|
// OR if any descendant parameters indicate explicit navigation
|
|
8376
|
-
for (const connection of
|
|
8377
|
-
const
|
|
8378
|
-
const defaultValue = parameterDefaults.get(paramName);
|
|
8368
|
+
for (const [paramName, connection] of connectionMap) {
|
|
8369
|
+
const currentDefault = connection.getDefaultValue(); // Use current dynamic default
|
|
8379
8370
|
const resolvedValue = resolvedParams[paramName];
|
|
8380
8371
|
const userProvidedParam = paramName in params;
|
|
8381
8372
|
|
|
8382
|
-
if (extraLiterals.includes(
|
|
8373
|
+
if (extraLiterals.includes(currentDefault)) {
|
|
8383
8374
|
// This literal corresponds to a parameter in the parent
|
|
8384
8375
|
if (
|
|
8385
8376
|
userProvidedParam ||
|
|
8386
8377
|
(resolvedValue !== undefined &&
|
|
8387
|
-
|
|
8378
|
+
connection.isCustomValue(resolvedValue))
|
|
8388
8379
|
) {
|
|
8389
8380
|
// Parameter was explicitly provided or has custom value - child is needed
|
|
8390
8381
|
childSpecificParamsAreDefaults = false;
|
|
@@ -8399,7 +8390,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8399
8390
|
if (childSpecificParamsAreDefaults) {
|
|
8400
8391
|
for (const childConnection of childPatternObj.connections) {
|
|
8401
8392
|
const childParamName = childConnection.paramName;
|
|
8402
|
-
const childDefaultValue = childConnection.
|
|
8393
|
+
const childDefaultValue = childConnection.getDefaultValue();
|
|
8403
8394
|
const childResolvedValue = resolvedParams[childParamName];
|
|
8404
8395
|
|
|
8405
8396
|
// Only consider path parameters, not query parameters
|
|
@@ -8427,19 +8418,18 @@ const createRoutePattern = (pattern) => {
|
|
|
8427
8418
|
// When structural parameters (those that determine child selection) are defaults,
|
|
8428
8419
|
// prefer parent route regardless of whether child has other non-default parameters
|
|
8429
8420
|
if (childSpecificParamsAreDefaults) {
|
|
8430
|
-
for (const connection of
|
|
8431
|
-
const
|
|
8432
|
-
const defaultValue = parameterDefaults.get(paramName);
|
|
8421
|
+
for (const [paramName, connection] of connectionMap) {
|
|
8422
|
+
const currentDefault = connection.getDefaultValue(); // Use current dynamic default
|
|
8433
8423
|
const userProvidedParam = paramName in params;
|
|
8434
8424
|
|
|
8435
|
-
if (extraLiterals.includes(
|
|
8425
|
+
if (extraLiterals.includes(currentDefault) && !userProvidedParam) {
|
|
8436
8426
|
// This child includes a literal that represents a default value
|
|
8437
8427
|
// AND user didn't explicitly provide this parameter
|
|
8438
8428
|
// When structural parameters are defaults, prefer parent for cleaner URL
|
|
8439
8429
|
shouldUse = false;
|
|
8440
8430
|
if (DEBUG$2) {
|
|
8441
8431
|
console.debug(
|
|
8442
|
-
`[${pattern}] Preferring parent over child - child includes default literal '${
|
|
8432
|
+
`[${pattern}] Preferring parent over child - child includes default literal '${currentDefault}' for param '${paramName}' (structural parameter is default)`,
|
|
8443
8433
|
);
|
|
8444
8434
|
}
|
|
8445
8435
|
break;
|
|
@@ -8472,9 +8462,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8472
8462
|
) => {
|
|
8473
8463
|
// Start with child signal values
|
|
8474
8464
|
const baseParams = {};
|
|
8475
|
-
for (const connection of childPatternObj.
|
|
8476
|
-
const { paramName, signal, options } = connection;
|
|
8477
|
-
|
|
8465
|
+
for (const [paramName, connection] of childPatternObj.connectionMap) {
|
|
8478
8466
|
// Check if parameter was explicitly provided by user
|
|
8479
8467
|
const hasExplicitParam = paramName in params;
|
|
8480
8468
|
const explicitValue = params[paramName];
|
|
@@ -8485,12 +8473,15 @@ const createRoutePattern = (pattern) => {
|
|
|
8485
8473
|
baseParams[paramName] = explicitValue;
|
|
8486
8474
|
}
|
|
8487
8475
|
// If explicitly undefined, don't include it (which means don't use child route)
|
|
8488
|
-
} else
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8476
|
+
} else {
|
|
8477
|
+
const signalValue = connection.signal.value;
|
|
8478
|
+
if (
|
|
8479
|
+
signalValue !== undefined &&
|
|
8480
|
+
connection.isCustomValue(signalValue)
|
|
8481
|
+
) {
|
|
8482
|
+
// No explicit override - use signal value if non-default
|
|
8483
|
+
baseParams[paramName] = signalValue;
|
|
8484
|
+
}
|
|
8494
8485
|
}
|
|
8495
8486
|
}
|
|
8496
8487
|
|
|
@@ -8504,13 +8495,10 @@ const createRoutePattern = (pattern) => {
|
|
|
8504
8495
|
|
|
8505
8496
|
// Add parent's signal parameters
|
|
8506
8497
|
for (const connection of parentPatternObj.connections) {
|
|
8507
|
-
const { paramName
|
|
8498
|
+
const { paramName } = connection;
|
|
8508
8499
|
|
|
8509
8500
|
// Skip if child route already handles this parameter
|
|
8510
|
-
|
|
8511
|
-
(conn) => conn.paramName === paramName,
|
|
8512
|
-
);
|
|
8513
|
-
if (childConnection) {
|
|
8501
|
+
if (childPatternObj.connectionMap.has(paramName)) {
|
|
8514
8502
|
continue; // Child route handles this parameter directly
|
|
8515
8503
|
}
|
|
8516
8504
|
|
|
@@ -8519,18 +8507,19 @@ const createRoutePattern = (pattern) => {
|
|
|
8519
8507
|
continue; // Already have this parameter
|
|
8520
8508
|
}
|
|
8521
8509
|
|
|
8510
|
+
const signalValue = connection.signal.value;
|
|
8522
8511
|
// Only include custom signal values (not using defaults)
|
|
8523
8512
|
if (
|
|
8524
|
-
|
|
8525
|
-
|
|
8513
|
+
signalValue !== undefined &&
|
|
8514
|
+
connection.isCustomValue(signalValue)
|
|
8526
8515
|
) {
|
|
8527
8516
|
// Skip if parameter is consumed by child's literal path segments
|
|
8528
8517
|
const isConsumedByChildPath = childPatternObj.pattern.segments.some(
|
|
8529
8518
|
(segment) =>
|
|
8530
|
-
segment.type === "literal" && segment.value ===
|
|
8519
|
+
segment.type === "literal" && segment.value === signalValue,
|
|
8531
8520
|
);
|
|
8532
8521
|
if (!isConsumedByChildPath) {
|
|
8533
|
-
baseParams[paramName] =
|
|
8522
|
+
baseParams[paramName] = signalValue;
|
|
8534
8523
|
}
|
|
8535
8524
|
}
|
|
8536
8525
|
}
|
|
@@ -8552,10 +8541,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8552
8541
|
}
|
|
8553
8542
|
|
|
8554
8543
|
// Skip if child route already handles this parameter
|
|
8555
|
-
|
|
8556
|
-
(conn) => conn.paramName === paramName,
|
|
8557
|
-
);
|
|
8558
|
-
if (childConnection) {
|
|
8544
|
+
if (childPatternObj.connectionMap.has(paramName)) {
|
|
8559
8545
|
continue; // Child route handles this parameter directly
|
|
8560
8546
|
}
|
|
8561
8547
|
|
|
@@ -8569,10 +8555,10 @@ const createRoutePattern = (pattern) => {
|
|
|
8569
8555
|
}
|
|
8570
8556
|
|
|
8571
8557
|
// Check if parent parameter is at default value
|
|
8572
|
-
const parentConnection =
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8558
|
+
const parentConnection = connectionMap.get(paramName);
|
|
8559
|
+
const parentDefault = parentConnection
|
|
8560
|
+
? parentConnection.getDefaultValue()
|
|
8561
|
+
: undefined;
|
|
8576
8562
|
if (parentValue === parentDefault) {
|
|
8577
8563
|
continue; // Don't inherit default values
|
|
8578
8564
|
}
|
|
@@ -8583,15 +8569,11 @@ const createRoutePattern = (pattern) => {
|
|
|
8583
8569
|
|
|
8584
8570
|
// Apply user params with filtering logic
|
|
8585
8571
|
for (const [paramName, userValue] of Object.entries(params)) {
|
|
8586
|
-
const childConnection = childPatternObj.
|
|
8587
|
-
(conn) => conn.paramName === paramName,
|
|
8588
|
-
);
|
|
8572
|
+
const childConnection = childPatternObj.connectionMap.get(paramName);
|
|
8589
8573
|
|
|
8590
8574
|
if (childConnection) {
|
|
8591
|
-
const { options } = childConnection;
|
|
8592
|
-
|
|
8593
8575
|
// Only include if it's a custom value (not default)
|
|
8594
|
-
if (
|
|
8576
|
+
if (childConnection.isCustomValue(userValue)) {
|
|
8595
8577
|
baseParams[paramName] = userValue;
|
|
8596
8578
|
} else {
|
|
8597
8579
|
// User provided the default value - complete omission
|
|
@@ -8648,10 +8630,9 @@ const createRoutePattern = (pattern) => {
|
|
|
8648
8630
|
|
|
8649
8631
|
if (childParent && childParent.originalPattern === pattern) {
|
|
8650
8632
|
// Check if child has any non-default signal values
|
|
8651
|
-
const hasNonDefaultChildParams =
|
|
8633
|
+
const hasNonDefaultChildParams = childPatternObj.connections.some(
|
|
8652
8634
|
(childConnection) => {
|
|
8653
|
-
|
|
8654
|
-
return options.isCustomValue?.(signal?.value);
|
|
8635
|
+
return childConnection.isCustomValue(childConnection.signal.value);
|
|
8655
8636
|
},
|
|
8656
8637
|
);
|
|
8657
8638
|
|
|
@@ -8867,9 +8848,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8867
8848
|
(qp) => qp.name === connection.paramName,
|
|
8868
8849
|
);
|
|
8869
8850
|
// Allow non-default query parameters, but not path parameters
|
|
8870
|
-
return (
|
|
8871
|
-
!isQueryParam && connection.options.isCustomValue?.(resolvedValue)
|
|
8872
|
-
);
|
|
8851
|
+
return !isQueryParam && connection.isCustomValue(resolvedValue);
|
|
8873
8852
|
});
|
|
8874
8853
|
|
|
8875
8854
|
if (hasNonDefaultPathParams) {
|
|
@@ -8899,7 +8878,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8899
8878
|
// For non-immediate parents, only allow optimization if all resolved parameters have default values
|
|
8900
8879
|
const hasNonDefaultParameters = connections.some((connection) => {
|
|
8901
8880
|
const resolvedValue = resolvedParams[connection.paramName];
|
|
8902
|
-
return connection.
|
|
8881
|
+
return connection.isCustomValue(resolvedValue);
|
|
8903
8882
|
});
|
|
8904
8883
|
|
|
8905
8884
|
if (hasNonDefaultParameters) {
|
|
@@ -9077,7 +9056,7 @@ const createRoutePattern = (pattern) => {
|
|
|
9077
9056
|
const connection = targetAncestor.connections.find(
|
|
9078
9057
|
(conn) => conn.paramName === param.name,
|
|
9079
9058
|
);
|
|
9080
|
-
if (!connection || connection.
|
|
9059
|
+
if (!connection || connection.getDefaultValue() !== segment) {
|
|
9081
9060
|
if (DEBUG$2) {
|
|
9082
9061
|
console.debug(
|
|
9083
9062
|
`[${pattern}] tryDirectOptimization: Parameter default mismatch for ${param.name}`,
|
|
@@ -9124,10 +9103,8 @@ const createRoutePattern = (pattern) => {
|
|
|
9124
9103
|
// Include parameters that target pattern specifically needs
|
|
9125
9104
|
if (targetQueryParamNames.has(paramName)) {
|
|
9126
9105
|
// Only include if the value is not the default value
|
|
9127
|
-
const connection = targetAncestor.
|
|
9128
|
-
|
|
9129
|
-
);
|
|
9130
|
-
if (connection && connection.options.defaultValue !== value) {
|
|
9106
|
+
const connection = targetAncestor.connectionMap.get(paramName);
|
|
9107
|
+
if (connection && connection.getDefaultValue() !== value) {
|
|
9131
9108
|
ancestorParams[paramName] = value;
|
|
9132
9109
|
if (DEBUG$2) {
|
|
9133
9110
|
console.debug(
|
|
@@ -9142,7 +9119,7 @@ const createRoutePattern = (pattern) => {
|
|
|
9142
9119
|
const connection = sourceConnections.find(
|
|
9143
9120
|
(conn) => conn.paramName === paramName,
|
|
9144
9121
|
);
|
|
9145
|
-
if (connection && connection.
|
|
9122
|
+
if (connection && connection.getDefaultValue() !== value) {
|
|
9146
9123
|
ancestorParams[paramName] = value;
|
|
9147
9124
|
if (DEBUG$2) {
|
|
9148
9125
|
console.debug(
|
|
@@ -9167,14 +9144,14 @@ const createRoutePattern = (pattern) => {
|
|
|
9167
9144
|
|
|
9168
9145
|
// Also check target ancestor's own signal values for parameters not in resolvedParams
|
|
9169
9146
|
for (const connection of targetAncestor.connections) {
|
|
9170
|
-
const { paramName
|
|
9147
|
+
const { paramName } = connection;
|
|
9148
|
+
if (paramName in ancestorParams) {
|
|
9149
|
+
continue;
|
|
9150
|
+
}
|
|
9171
9151
|
|
|
9172
9152
|
// Only include if not already processed and has custom value (not default)
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
signal?.value !== undefined &&
|
|
9176
|
-
options.isCustomValue?.(signal.value)
|
|
9177
|
-
) {
|
|
9153
|
+
const signalValue = connection.signal.value;
|
|
9154
|
+
if (signalValue !== undefined && connection.isCustomValue(signalValue)) {
|
|
9178
9155
|
// Don't include path parameters that correspond to literal segments we're optimizing away
|
|
9179
9156
|
const targetParam = targetParams.find((p) => p.name === paramName);
|
|
9180
9157
|
const isPathParam = targetParam !== undefined; // Any param in segments is a path param
|
|
@@ -9182,16 +9159,16 @@ const createRoutePattern = (pattern) => {
|
|
|
9182
9159
|
// Skip path parameters - we want them to use default values for optimization
|
|
9183
9160
|
if (DEBUG$2) {
|
|
9184
9161
|
console.debug(
|
|
9185
|
-
`[${pattern}] tryDirectOptimization: Skipping path param ${paramName}=${
|
|
9162
|
+
`[${pattern}] tryDirectOptimization: Skipping path param ${paramName}=${signalValue} (will use default)`,
|
|
9186
9163
|
);
|
|
9187
9164
|
}
|
|
9188
9165
|
continue;
|
|
9189
9166
|
}
|
|
9190
9167
|
|
|
9191
|
-
ancestorParams[paramName] =
|
|
9168
|
+
ancestorParams[paramName] = signalValue;
|
|
9192
9169
|
if (DEBUG$2) {
|
|
9193
9170
|
console.debug(
|
|
9194
|
-
`[${pattern}] tryDirectOptimization: Added target signal param ${paramName}=${
|
|
9171
|
+
`[${pattern}] tryDirectOptimization: Added target signal param ${paramName}=${signalValue}`,
|
|
9195
9172
|
);
|
|
9196
9173
|
}
|
|
9197
9174
|
}
|
|
@@ -9202,24 +9179,25 @@ const createRoutePattern = (pattern) => {
|
|
|
9202
9179
|
|
|
9203
9180
|
while (currentParent) {
|
|
9204
9181
|
for (const connection of currentParent.connections) {
|
|
9205
|
-
const { paramName
|
|
9182
|
+
const { paramName } = connection;
|
|
9183
|
+
if (paramName in ancestorParams) {
|
|
9184
|
+
continue;
|
|
9185
|
+
}
|
|
9206
9186
|
|
|
9207
9187
|
// Only inherit custom values (not defaults) that we don't already have
|
|
9188
|
+
const signalValue = connection.signal.value;
|
|
9208
9189
|
if (
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
options.isCustomValue?.(signal.value)
|
|
9190
|
+
signalValue !== undefined &&
|
|
9191
|
+
connection.isCustomValue(signalValue)
|
|
9212
9192
|
) {
|
|
9213
9193
|
// Check if this parameter would be redundant with target ancestor's literal segments
|
|
9214
9194
|
const isRedundant = isParameterRedundantWithLiteralSegments(
|
|
9215
9195
|
targetAncestor.pattern,
|
|
9216
9196
|
currentParent.pattern,
|
|
9217
|
-
paramName
|
|
9218
|
-
signal.value,
|
|
9219
|
-
);
|
|
9197
|
+
paramName);
|
|
9220
9198
|
|
|
9221
9199
|
if (!isRedundant) {
|
|
9222
|
-
ancestorParams[paramName] =
|
|
9200
|
+
ancestorParams[paramName] = signalValue;
|
|
9223
9201
|
}
|
|
9224
9202
|
}
|
|
9225
9203
|
}
|
|
@@ -9282,24 +9260,25 @@ const createRoutePattern = (pattern) => {
|
|
|
9282
9260
|
while (currentParent) {
|
|
9283
9261
|
// Check parent's signal connections for non-default values to inherit
|
|
9284
9262
|
for (const parentConnection of currentParent.connections) {
|
|
9285
|
-
const { paramName
|
|
9263
|
+
const { paramName } = parentConnection;
|
|
9264
|
+
if (paramName in finalParams) {
|
|
9265
|
+
continue; // Already have this parameter
|
|
9266
|
+
}
|
|
9286
9267
|
|
|
9287
9268
|
// Only inherit if we don't have this param and parent has custom value (not default)
|
|
9269
|
+
const parentSignalValue = parentConnection.signal.value;
|
|
9288
9270
|
if (
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
options.isCustomValue?.(signal.value)
|
|
9271
|
+
parentSignalValue !== undefined &&
|
|
9272
|
+
parentConnection.isCustomValue(parentSignalValue)
|
|
9292
9273
|
) {
|
|
9293
9274
|
// Don't inherit if parameter corresponds to a literal in our path
|
|
9294
9275
|
const shouldInherit = !isParameterRedundantWithLiteralSegments(
|
|
9295
9276
|
parsedPattern,
|
|
9296
9277
|
currentParent.pattern,
|
|
9297
|
-
paramName
|
|
9298
|
-
signal.value,
|
|
9299
|
-
);
|
|
9278
|
+
paramName);
|
|
9300
9279
|
|
|
9301
9280
|
if (shouldInherit) {
|
|
9302
|
-
finalParams[paramName] =
|
|
9281
|
+
finalParams[paramName] = parentSignalValue;
|
|
9303
9282
|
}
|
|
9304
9283
|
}
|
|
9305
9284
|
}
|
|
@@ -9349,9 +9328,9 @@ const createRoutePattern = (pattern) => {
|
|
|
9349
9328
|
urlPatternRaw: pattern,
|
|
9350
9329
|
cleanPattern,
|
|
9351
9330
|
connections,
|
|
9331
|
+
connectionMap,
|
|
9352
9332
|
parsedPattern,
|
|
9353
9333
|
signalSet,
|
|
9354
|
-
parameterDefaults, // Add parameterDefaults for signal clearing logic
|
|
9355
9334
|
children: [],
|
|
9356
9335
|
parent: null,
|
|
9357
9336
|
depth: 0, // Will be calculated after relationships are built
|
|
@@ -9419,11 +9398,7 @@ const canParameterReachChildRoute = (
|
|
|
9419
9398
|
/**
|
|
9420
9399
|
* Parse a route pattern string into structured segments
|
|
9421
9400
|
*/
|
|
9422
|
-
const parsePattern = (
|
|
9423
|
-
pattern,
|
|
9424
|
-
parameterDefaults = new Map(),
|
|
9425
|
-
connections = [],
|
|
9426
|
-
) => {
|
|
9401
|
+
const parsePattern = (pattern, connectionMap) => {
|
|
9427
9402
|
// Handle root route
|
|
9428
9403
|
if (pattern === "/") {
|
|
9429
9404
|
return {
|
|
@@ -9497,18 +9472,18 @@ const parsePattern = (
|
|
|
9497
9472
|
// 1. Explicitly marked with ?
|
|
9498
9473
|
// 2. Has a default value
|
|
9499
9474
|
// 3. Connected signal has undefined value and no explicit default (allows /map to match /map/:panel)
|
|
9500
|
-
|
|
9475
|
+
const connection = connectionMap.get(paramName);
|
|
9476
|
+
const hasDefault =
|
|
9477
|
+
connection && connection.getDefaultValue() !== undefined;
|
|
9478
|
+
let isOptional = seg.endsWith("?") || hasDefault;
|
|
9501
9479
|
|
|
9502
9480
|
if (!isOptional) {
|
|
9503
9481
|
// Check if connected signal has undefined value (making parameter optional for index routes)
|
|
9504
|
-
const connection = connections.find(
|
|
9505
|
-
(conn) => conn.paramName === paramName,
|
|
9506
|
-
);
|
|
9507
9482
|
if (
|
|
9508
9483
|
connection &&
|
|
9509
9484
|
connection.signal &&
|
|
9510
9485
|
connection.signal.value === undefined &&
|
|
9511
|
-
!
|
|
9486
|
+
!hasDefault
|
|
9512
9487
|
) {
|
|
9513
9488
|
isOptional = true;
|
|
9514
9489
|
}
|
|
@@ -9551,7 +9526,7 @@ const checkIfLiteralCanBeOptionalWithPatternObj = (
|
|
|
9551
9526
|
|
|
9552
9527
|
// Check current pattern's connections
|
|
9553
9528
|
for (const connection of patternObj.connections) {
|
|
9554
|
-
if (connection.
|
|
9529
|
+
if (connection.getDefaultValue() === literalValue) {
|
|
9555
9530
|
return true;
|
|
9556
9531
|
}
|
|
9557
9532
|
}
|
|
@@ -9560,7 +9535,7 @@ const checkIfLiteralCanBeOptionalWithPatternObj = (
|
|
|
9560
9535
|
let currentParent = patternObj.parent;
|
|
9561
9536
|
while (currentParent) {
|
|
9562
9537
|
for (const connection of currentParent.connections) {
|
|
9563
|
-
if (connection.
|
|
9538
|
+
if (connection.getDefaultValue() === literalValue) {
|
|
9564
9539
|
return true;
|
|
9565
9540
|
}
|
|
9566
9541
|
}
|
|
@@ -9571,7 +9546,7 @@ const checkIfLiteralCanBeOptionalWithPatternObj = (
|
|
|
9571
9546
|
const checkChildrenRecursively = (pattern) => {
|
|
9572
9547
|
for (const child of pattern.children || []) {
|
|
9573
9548
|
for (const connection of child.connections) {
|
|
9574
|
-
if (connection.
|
|
9549
|
+
if (connection.getDefaultValue() === literalValue) {
|
|
9575
9550
|
return true;
|
|
9576
9551
|
}
|
|
9577
9552
|
}
|
|
@@ -9699,8 +9674,7 @@ const matchUrl = (
|
|
|
9699
9674
|
// Patterns with trailing slashes can match additional URL segments (like wildcards)
|
|
9700
9675
|
// Patterns without trailing slashes should match exactly (unless they're wildcards)
|
|
9701
9676
|
// BUT: if pattern has children, it can also match additional segments (hierarchical matching)
|
|
9702
|
-
const hasChildren =
|
|
9703
|
-
patternObj && patternObj.children && patternObj.children.length > 0;
|
|
9677
|
+
const hasChildren = patternObj && patternObj.children.length > 0;
|
|
9704
9678
|
if (
|
|
9705
9679
|
!parsedPattern.wildcard &&
|
|
9706
9680
|
!parsedPattern.trailingSlash &&
|
|
@@ -9730,8 +9704,8 @@ const extractSearchParams = (urlObj, connections = []) => {
|
|
|
9730
9704
|
// Create a map for quick signal type lookup
|
|
9731
9705
|
const signalTypes = new Map();
|
|
9732
9706
|
for (const connection of connections) {
|
|
9733
|
-
if (connection.
|
|
9734
|
-
signalTypes.set(connection.paramName, connection.
|
|
9707
|
+
if (connection.type) {
|
|
9708
|
+
signalTypes.set(connection.paramName, connection.type);
|
|
9735
9709
|
}
|
|
9736
9710
|
}
|
|
9737
9711
|
|
|
@@ -10176,9 +10150,7 @@ const setupPatterns = (patternDefinitions) => {
|
|
|
10176
10150
|
let parentPatternObj = currentPatternObj.parent;
|
|
10177
10151
|
while (parentPatternObj) {
|
|
10178
10152
|
for (const connection of parentPatternObj.connections) {
|
|
10179
|
-
|
|
10180
|
-
allRelevantSignals.add(connection.signal);
|
|
10181
|
-
}
|
|
10153
|
+
allRelevantSignals.add(connection.signal);
|
|
10182
10154
|
}
|
|
10183
10155
|
// Move up the parent chain
|
|
10184
10156
|
parentPatternObj = parentPatternObj.parent;
|
|
@@ -10189,9 +10161,7 @@ const setupPatterns = (patternDefinitions) => {
|
|
|
10189
10161
|
for (const childPatternObj of patternObj.children || []) {
|
|
10190
10162
|
// Add child's own signals
|
|
10191
10163
|
for (const connection of childPatternObj.connections) {
|
|
10192
|
-
|
|
10193
|
-
allRelevantSignals.add(connection.signal);
|
|
10194
|
-
}
|
|
10164
|
+
allRelevantSignals.add(connection.signal);
|
|
10195
10165
|
}
|
|
10196
10166
|
// Recursively add grandchildren signals
|
|
10197
10167
|
addDescendantSignals(childPatternObj);
|
|
@@ -10357,14 +10327,10 @@ const updateRoutes = (
|
|
|
10357
10327
|
newMatching,
|
|
10358
10328
|
} of routeMatchInfoSet) {
|
|
10359
10329
|
const { routePattern } = routePrivateProperties;
|
|
10360
|
-
const {
|
|
10330
|
+
const { connectionMap } = routePattern;
|
|
10361
10331
|
|
|
10362
|
-
for (const {
|
|
10363
|
-
signal:
|
|
10364
|
-
paramName,
|
|
10365
|
-
options = {},
|
|
10366
|
-
} of connections) {
|
|
10367
|
-
const { debug } = options;
|
|
10332
|
+
for (const [paramName, connection] of connectionMap) {
|
|
10333
|
+
const { signal: paramSignal, debug } = connection;
|
|
10368
10334
|
const params = routePrivateProperties.rawParamsSignal.value;
|
|
10369
10335
|
const urlParamValue = params[paramName];
|
|
10370
10336
|
|
|
@@ -10445,7 +10411,7 @@ const updateRoutes = (
|
|
|
10445
10411
|
// 2. AND no matching route extracts this parameter from URL
|
|
10446
10412
|
// 3. AND parameter has no default value (making it truly optional)
|
|
10447
10413
|
if (matchingRouteInSameFamily && !parameterExtractedByMatchingRoute) {
|
|
10448
|
-
const defaultValue =
|
|
10414
|
+
const defaultValue = connection.getDefaultValue();
|
|
10449
10415
|
if (defaultValue === undefined) {
|
|
10450
10416
|
// Parameter is not extracted within same family and has no default - reset it
|
|
10451
10417
|
if (debug) {
|
|
@@ -10453,21 +10419,21 @@ const updateRoutes = (
|
|
|
10453
10419
|
`[route] Same family navigation, ${paramName} not extracted and has no default: resetting signal`,
|
|
10454
10420
|
);
|
|
10455
10421
|
}
|
|
10456
|
-
|
|
10422
|
+
paramSignal.value = undefined;
|
|
10457
10423
|
} else if (debug) {
|
|
10458
10424
|
// Parameter has a default value - preserve current signal value
|
|
10459
10425
|
console.debug(
|
|
10460
|
-
`[route] Parameter ${paramName} has default value ${defaultValue}: preserving signal value: ${
|
|
10426
|
+
`[route] Parameter ${paramName} has default value ${defaultValue}: preserving signal value: ${paramSignal.value}`,
|
|
10461
10427
|
);
|
|
10462
10428
|
}
|
|
10463
10429
|
} else if (debug) {
|
|
10464
10430
|
if (!matchingRouteInSameFamily) {
|
|
10465
10431
|
console.debug(
|
|
10466
|
-
`[route] Different route family: preserving ${paramName} signal value: ${
|
|
10432
|
+
`[route] Different route family: preserving ${paramName} signal value: ${paramSignal.value}`,
|
|
10467
10433
|
);
|
|
10468
10434
|
} else {
|
|
10469
10435
|
console.debug(
|
|
10470
|
-
`[route] Parameter ${paramName} extracted by matching route: preserving signal value: ${
|
|
10436
|
+
`[route] Parameter ${paramName} extracted by matching route: preserving signal value: ${paramSignal.value}`,
|
|
10471
10437
|
);
|
|
10472
10438
|
}
|
|
10473
10439
|
}
|
|
@@ -10476,11 +10442,11 @@ const updateRoutes = (
|
|
|
10476
10442
|
|
|
10477
10443
|
// URL -> Signal sync: When route matches, ensure signal matches URL state
|
|
10478
10444
|
// URL is the source of truth for explicit parameters
|
|
10479
|
-
const value =
|
|
10445
|
+
const value = paramSignal.peek();
|
|
10480
10446
|
if (urlParamValue === undefined) {
|
|
10481
10447
|
// No URL parameter - reset signal to its current default value
|
|
10482
10448
|
// (handles both static fallback and dynamic default cases)
|
|
10483
|
-
const defaultValue =
|
|
10449
|
+
const defaultValue = connection.getDefaultValue();
|
|
10484
10450
|
if (value === defaultValue) {
|
|
10485
10451
|
// Signal already has correct default value, no sync needed
|
|
10486
10452
|
continue;
|
|
@@ -10490,7 +10456,7 @@ const updateRoutes = (
|
|
|
10490
10456
|
`[route] URL->Signal: ${paramName} not in URL, reset signal to default (${defaultValue})`,
|
|
10491
10457
|
);
|
|
10492
10458
|
}
|
|
10493
|
-
|
|
10459
|
+
paramSignal.value = defaultValue;
|
|
10494
10460
|
continue;
|
|
10495
10461
|
}
|
|
10496
10462
|
if (urlParamValue === value) {
|
|
@@ -10502,7 +10468,7 @@ const updateRoutes = (
|
|
|
10502
10468
|
`[route] URL->Signal: ${paramName}=${urlParamValue} in url, sync signal with url`,
|
|
10503
10469
|
);
|
|
10504
10470
|
}
|
|
10505
|
-
|
|
10471
|
+
paramSignal.value = urlParamValue;
|
|
10506
10472
|
continue;
|
|
10507
10473
|
}
|
|
10508
10474
|
}
|
|
@@ -10607,7 +10573,7 @@ const getRoutePrivateProperties = (route) => {
|
|
|
10607
10573
|
|
|
10608
10574
|
const registerRoute = (routePattern) => {
|
|
10609
10575
|
const urlPatternRaw = routePattern.originalPattern;
|
|
10610
|
-
const { cleanPattern,
|
|
10576
|
+
const { cleanPattern, connectionMap } = routePattern;
|
|
10611
10577
|
|
|
10612
10578
|
const cleanupCallbackSet = new Set();
|
|
10613
10579
|
const cleanup = () => {
|
|
@@ -10697,22 +10663,19 @@ const registerRoute = (routePattern) => {
|
|
|
10697
10663
|
}
|
|
10698
10664
|
});
|
|
10699
10665
|
|
|
10700
|
-
for (const
|
|
10701
|
-
const { debug } =
|
|
10666
|
+
for (const [paramName, connection] of connectionMap) {
|
|
10667
|
+
const { signal: paramSignal, debug } = connection;
|
|
10702
10668
|
|
|
10703
10669
|
if (debug) {
|
|
10704
10670
|
console.debug(
|
|
10705
10671
|
`[route] connecting url param "${paramName}" to signal`,
|
|
10706
|
-
|
|
10672
|
+
paramSignal,
|
|
10707
10673
|
);
|
|
10708
10674
|
}
|
|
10709
|
-
|
|
10710
|
-
// URL -> Signal synchronization now handled in updateRoutes() to eliminate circular dependency
|
|
10711
|
-
|
|
10712
10675
|
// Signal -> URL sync: When signal changes, update URL to reflect meaningful state
|
|
10713
10676
|
// Only sync non-default values to keep URLs clean (static fallbacks stay invisible)
|
|
10714
10677
|
effect(() => {
|
|
10715
|
-
const value =
|
|
10678
|
+
const value = paramSignal.value;
|
|
10716
10679
|
const params = rawParamsSignal.value;
|
|
10717
10680
|
const urlParamValue = params[paramName];
|
|
10718
10681
|
const matching = matchingSignal.value;
|
|
@@ -10723,7 +10686,7 @@ const registerRoute = (routePattern) => {
|
|
|
10723
10686
|
}
|
|
10724
10687
|
if (urlParamValue === undefined) {
|
|
10725
10688
|
// No URL parameter exists - check if signal has meaningful value to add
|
|
10726
|
-
const defaultValue =
|
|
10689
|
+
const defaultValue = connection.getDefaultValue();
|
|
10727
10690
|
if (value === defaultValue) {
|
|
10728
10691
|
// Signal using default value, keep URL clean (no parameter needed)
|
|
10729
10692
|
return;
|