@jsenv/navi 0.16.14 → 0.16.16
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 +184 -23
- package/dist/jsenv_navi.js.map +6 -9
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -7716,9 +7716,18 @@ const createRoutePattern = (pattern) => {
|
|
|
7716
7716
|
|
|
7717
7717
|
const parsedPattern = parsePattern(cleanPattern, parameterDefaults);
|
|
7718
7718
|
|
|
7719
|
+
// Create signalSet to track all signals this pattern depends on
|
|
7720
|
+
const signalSet = new Set();
|
|
7721
|
+
for (const connection of connections) {
|
|
7722
|
+
if (connection.signal) {
|
|
7723
|
+
signalSet.add(connection.signal);
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
|
|
7719
7727
|
if (DEBUG$2) {
|
|
7720
7728
|
console.debug(`[CustomPattern] Created pattern:`, parsedPattern);
|
|
7721
7729
|
console.debug(`[CustomPattern] Signal connections:`, connections);
|
|
7730
|
+
console.debug(`[CustomPattern] SignalSet size:`, signalSet.size);
|
|
7722
7731
|
}
|
|
7723
7732
|
|
|
7724
7733
|
const applyOn = (url) => {
|
|
@@ -7821,13 +7830,6 @@ const createRoutePattern = (pattern) => {
|
|
|
7821
7830
|
const childParams = {};
|
|
7822
7831
|
let isCompatible = true;
|
|
7823
7832
|
|
|
7824
|
-
if (DEBUG$2) {
|
|
7825
|
-
console.debug(
|
|
7826
|
-
`[${pattern}] Checking compatibility with child: ${childPatternObj.originalPattern}`,
|
|
7827
|
-
);
|
|
7828
|
-
console.debug(`[${pattern}] Params passed to buildUrl:`, params);
|
|
7829
|
-
}
|
|
7830
|
-
|
|
7831
7833
|
// CRITICAL: Check if parent route can reach all child route's literal segments
|
|
7832
7834
|
// A route can only optimize to a descendant if there's a viable path through parameters
|
|
7833
7835
|
// to reach all the descendant's literal segments (e.g., "/" cannot reach "/admin"
|
|
@@ -7863,7 +7865,30 @@ const createRoutePattern = (pattern) => {
|
|
|
7863
7865
|
}
|
|
7864
7866
|
if (parentSegmentAtPosition.type === "param") {
|
|
7865
7867
|
// Parent has a parameter at this position - child literal can satisfy this parameter
|
|
7866
|
-
//
|
|
7868
|
+
// BUT we need to check if the parent's parameter value matches the child's literal
|
|
7869
|
+
|
|
7870
|
+
// Find the parent's parameter value from signals or params
|
|
7871
|
+
const paramName = parentSegmentAtPosition.name;
|
|
7872
|
+
let parentParamValue = params[paramName];
|
|
7873
|
+
|
|
7874
|
+
// If not in params, check signals
|
|
7875
|
+
if (parentParamValue === undefined) {
|
|
7876
|
+
const parentConnection = connections.find(
|
|
7877
|
+
(conn) => conn.paramName === paramName,
|
|
7878
|
+
);
|
|
7879
|
+
if (parentConnection && parentConnection.signal) {
|
|
7880
|
+
parentParamValue = parentConnection.signal.value;
|
|
7881
|
+
}
|
|
7882
|
+
}
|
|
7883
|
+
|
|
7884
|
+
// If parent has a specific value for this parameter, it must match the child literal
|
|
7885
|
+
if (
|
|
7886
|
+
parentParamValue !== undefined &&
|
|
7887
|
+
parentParamValue !== literalValue
|
|
7888
|
+
) {
|
|
7889
|
+
return { isCompatible: false, childParams: {} };
|
|
7890
|
+
}
|
|
7891
|
+
|
|
7867
7892
|
continue;
|
|
7868
7893
|
}
|
|
7869
7894
|
}
|
|
@@ -7953,7 +7978,6 @@ const createRoutePattern = (pattern) => {
|
|
|
7953
7978
|
paramValue,
|
|
7954
7979
|
childParsedPattern,
|
|
7955
7980
|
);
|
|
7956
|
-
|
|
7957
7981
|
if (matchesChildLiteral) {
|
|
7958
7982
|
// Compatible - parameter value matches child literal
|
|
7959
7983
|
return {
|
|
@@ -7964,11 +7988,31 @@ const createRoutePattern = (pattern) => {
|
|
|
7964
7988
|
};
|
|
7965
7989
|
}
|
|
7966
7990
|
|
|
7991
|
+
// ROBUST FIX: For path parameters, check semantic compatibility by verifying
|
|
7992
|
+
// that parent parameter values can actually produce the child route structure
|
|
7993
|
+
const isParentPathParam = connections.some(
|
|
7994
|
+
(conn) => conn.paramName === paramName,
|
|
7995
|
+
);
|
|
7996
|
+
if (isParentPathParam) {
|
|
7997
|
+
// Check if parent parameter value matches any child literal where it should
|
|
7998
|
+
// The key insight: if parent has a specific parameter value, child route must
|
|
7999
|
+
// be reachable with that value or they're incompatible
|
|
8000
|
+
const parameterCanReachChild = canParameterReachChildRoute(
|
|
8001
|
+
paramName,
|
|
8002
|
+
paramValue,
|
|
8003
|
+
parsedPattern,
|
|
8004
|
+
childParsedPattern,
|
|
8005
|
+
);
|
|
8006
|
+
|
|
8007
|
+
if (!parameterCanReachChild) {
|
|
8008
|
+
return { isCompatible: false };
|
|
8009
|
+
}
|
|
8010
|
+
}
|
|
8011
|
+
|
|
7967
8012
|
// Check if this is a query parameter in the parent pattern
|
|
7968
8013
|
const isParentQueryParam = parsedPattern.queryParams.some(
|
|
7969
8014
|
(qp) => qp.name === paramName,
|
|
7970
8015
|
);
|
|
7971
|
-
|
|
7972
8016
|
if (isParentQueryParam) {
|
|
7973
8017
|
// Query parameters are always compatible and can be inherited by child routes
|
|
7974
8018
|
return {
|
|
@@ -7985,7 +8029,6 @@ const createRoutePattern = (pattern) => {
|
|
|
7985
8029
|
const isParentPathParam = connections.some(
|
|
7986
8030
|
(conn) => conn.paramName === paramName,
|
|
7987
8031
|
);
|
|
7988
|
-
|
|
7989
8032
|
if (isParentPathParam) {
|
|
7990
8033
|
// Parameter value (from user or signal) doesn't match this child's literals
|
|
7991
8034
|
// Check if child has any literal segments that would conflict with this parameter
|
|
@@ -7993,7 +8036,6 @@ const createRoutePattern = (pattern) => {
|
|
|
7993
8036
|
(segment) =>
|
|
7994
8037
|
segment.type === "literal" && segment.value !== paramValue,
|
|
7995
8038
|
);
|
|
7996
|
-
|
|
7997
8039
|
if (hasConflictingLiteral) {
|
|
7998
8040
|
return { isCompatible: false };
|
|
7999
8041
|
}
|
|
@@ -8288,6 +8330,22 @@ const createRoutePattern = (pattern) => {
|
|
|
8288
8330
|
console.debug(`[${pattern}] buildMostPreciseUrl called`);
|
|
8289
8331
|
}
|
|
8290
8332
|
|
|
8333
|
+
// Get the updated signalSet from pattern registry (set by setupPatterns)
|
|
8334
|
+
const patternData = patternRegistry.get(pattern);
|
|
8335
|
+
const effectiveSignalSet = patternData?.signalSet || signalSet;
|
|
8336
|
+
|
|
8337
|
+
// Access signal.value to trigger dependency tracking
|
|
8338
|
+
if (DEBUG$2) {
|
|
8339
|
+
console.debug(
|
|
8340
|
+
`[${pattern}] Reading ${effectiveSignalSet.size} signals for reactive dependencies`,
|
|
8341
|
+
);
|
|
8342
|
+
}
|
|
8343
|
+
// for (const signal of effectiveSignalSet) {
|
|
8344
|
+
// // Access signal.value to trigger dependency tracking
|
|
8345
|
+
// // eslint-disable-next-line no-unused-expressions
|
|
8346
|
+
// signal.value; // This line is critical for signal reactivity - when commented out, routes may not update properly
|
|
8347
|
+
// }
|
|
8348
|
+
|
|
8291
8349
|
// Step 1: Resolve and clean parameters
|
|
8292
8350
|
const resolvedParams = resolveParams(params);
|
|
8293
8351
|
|
|
@@ -8958,6 +9016,46 @@ const paramMatchesChildLiteral = (paramValue, childParsedPattern) => {
|
|
|
8958
9016
|
);
|
|
8959
9017
|
};
|
|
8960
9018
|
|
|
9019
|
+
/**
|
|
9020
|
+
* Helper: Check if a parent parameter can semantically reach a child route
|
|
9021
|
+
* This replaces the fragile position-based matching with semantic verification
|
|
9022
|
+
*/
|
|
9023
|
+
const canParameterReachChildRoute = (
|
|
9024
|
+
paramName,
|
|
9025
|
+
paramValue,
|
|
9026
|
+
parentPattern,
|
|
9027
|
+
childPattern,
|
|
9028
|
+
) => {
|
|
9029
|
+
// Find the parent parameter segment
|
|
9030
|
+
const parentParamSegment = parentPattern.segments.find(
|
|
9031
|
+
(segment) => segment.type === "param" && segment.name === paramName,
|
|
9032
|
+
);
|
|
9033
|
+
|
|
9034
|
+
if (!parentParamSegment) {
|
|
9035
|
+
return true; // Not a path parameter, no conflict
|
|
9036
|
+
}
|
|
9037
|
+
|
|
9038
|
+
// Get parameter's logical path position (not array index)
|
|
9039
|
+
const paramPathPosition = parentParamSegment.index;
|
|
9040
|
+
|
|
9041
|
+
// Find corresponding child segment at the same logical path position
|
|
9042
|
+
const childSegmentAtSamePosition = childPattern.segments.find(
|
|
9043
|
+
(segment) => segment.index === paramPathPosition,
|
|
9044
|
+
);
|
|
9045
|
+
|
|
9046
|
+
if (!childSegmentAtSamePosition) {
|
|
9047
|
+
return true; // Child doesn't extend to this position, no conflict
|
|
9048
|
+
}
|
|
9049
|
+
|
|
9050
|
+
if (childSegmentAtSamePosition.type === "literal") {
|
|
9051
|
+
// Child has a literal at this position - parent parameter must match exactly
|
|
9052
|
+
return childSegmentAtSamePosition.value === paramValue;
|
|
9053
|
+
}
|
|
9054
|
+
|
|
9055
|
+
// Child has parameter at same position - compatible
|
|
9056
|
+
return true;
|
|
9057
|
+
};
|
|
9058
|
+
|
|
8961
9059
|
/**
|
|
8962
9060
|
* Parse a route pattern string into structured segments
|
|
8963
9061
|
*/
|
|
@@ -9564,7 +9662,25 @@ const setupPatterns = (patternDefinitions) => {
|
|
|
9564
9662
|
|
|
9565
9663
|
for (const [key, urlPatternRaw] of Object.entries(patternDefinitions)) {
|
|
9566
9664
|
const [cleanPattern, connections] = detectSignals(urlPatternRaw);
|
|
9567
|
-
|
|
9665
|
+
|
|
9666
|
+
// Build parameter defaults from signal connections
|
|
9667
|
+
const parameterDefaults = new Map();
|
|
9668
|
+
for (const connection of connections) {
|
|
9669
|
+
const { paramName, options } = connection;
|
|
9670
|
+
if (options.defaultValue !== undefined) {
|
|
9671
|
+
parameterDefaults.set(paramName, options.defaultValue);
|
|
9672
|
+
}
|
|
9673
|
+
}
|
|
9674
|
+
|
|
9675
|
+
const parsedPattern = parsePattern(cleanPattern, parameterDefaults);
|
|
9676
|
+
|
|
9677
|
+
// Create signalSet for this pattern
|
|
9678
|
+
const signalSet = new Set();
|
|
9679
|
+
for (const connection of connections) {
|
|
9680
|
+
if (connection.signal) {
|
|
9681
|
+
signalSet.add(connection.signal);
|
|
9682
|
+
}
|
|
9683
|
+
}
|
|
9568
9684
|
|
|
9569
9685
|
const patternData = {
|
|
9570
9686
|
key,
|
|
@@ -9572,6 +9688,7 @@ const setupPatterns = (patternDefinitions) => {
|
|
|
9572
9688
|
cleanPattern,
|
|
9573
9689
|
connections,
|
|
9574
9690
|
parsedPattern,
|
|
9691
|
+
signalSet,
|
|
9575
9692
|
childPatterns: [],
|
|
9576
9693
|
parent: null,
|
|
9577
9694
|
};
|
|
@@ -9620,6 +9737,60 @@ const setupPatterns = (patternDefinitions) => {
|
|
|
9620
9737
|
});
|
|
9621
9738
|
}
|
|
9622
9739
|
|
|
9740
|
+
// Phase 3: Collect all relevant signals for each pattern based on relationships
|
|
9741
|
+
for (const currentPattern of allPatterns) {
|
|
9742
|
+
const currentData = patternRegistry.get(currentPattern);
|
|
9743
|
+
const allRelevantSignals = new Set();
|
|
9744
|
+
|
|
9745
|
+
// Add own signals
|
|
9746
|
+
for (const signal of currentData.signalSet) {
|
|
9747
|
+
allRelevantSignals.add(signal);
|
|
9748
|
+
}
|
|
9749
|
+
|
|
9750
|
+
// Add signals from ancestors (they might be inherited)
|
|
9751
|
+
let parentData = currentData.parent
|
|
9752
|
+
? patternRegistry.get(currentData.parent.originalPattern)
|
|
9753
|
+
: null;
|
|
9754
|
+
while (parentData) {
|
|
9755
|
+
for (const connection of parentData.connections) {
|
|
9756
|
+
if (connection.signal) {
|
|
9757
|
+
allRelevantSignals.add(connection.signal);
|
|
9758
|
+
}
|
|
9759
|
+
}
|
|
9760
|
+
// Move up the parent chain
|
|
9761
|
+
parentData = parentData.parent
|
|
9762
|
+
? patternRegistry.get(parentData.parent.originalPattern)
|
|
9763
|
+
: null;
|
|
9764
|
+
}
|
|
9765
|
+
|
|
9766
|
+
// Add signals from descendants (they might be used for optimization)
|
|
9767
|
+
const addDescendantSignals = (patternData) => {
|
|
9768
|
+
for (const childPatternObj of patternData.childPatterns) {
|
|
9769
|
+
const childData = patternRegistry.get(childPatternObj.originalPattern);
|
|
9770
|
+
if (childData) {
|
|
9771
|
+
// Add child's own signals
|
|
9772
|
+
for (const connection of childData.connections) {
|
|
9773
|
+
if (connection.signal) {
|
|
9774
|
+
allRelevantSignals.add(connection.signal);
|
|
9775
|
+
}
|
|
9776
|
+
}
|
|
9777
|
+
// Recursively add grandchildren signals
|
|
9778
|
+
addDescendantSignals(childData);
|
|
9779
|
+
}
|
|
9780
|
+
}
|
|
9781
|
+
};
|
|
9782
|
+
addDescendantSignals(currentData);
|
|
9783
|
+
|
|
9784
|
+
// Update the pattern's signalSet with all relevant signals
|
|
9785
|
+
currentData.signalSet = allRelevantSignals;
|
|
9786
|
+
|
|
9787
|
+
if (DEBUG$2 && allRelevantSignals.size > 0) {
|
|
9788
|
+
console.debug(
|
|
9789
|
+
`[${currentPattern}] Collected ${allRelevantSignals.size} relevant signals`,
|
|
9790
|
+
);
|
|
9791
|
+
}
|
|
9792
|
+
}
|
|
9793
|
+
|
|
9623
9794
|
if (DEBUG$2) {
|
|
9624
9795
|
console.debug("Pattern registry updated");
|
|
9625
9796
|
}
|
|
@@ -10846,9 +11017,6 @@ const navTo = (target, options) => {
|
|
|
10846
11017
|
}
|
|
10847
11018
|
return browserIntegration.navTo(url, options);
|
|
10848
11019
|
};
|
|
10849
|
-
const replaceUrl = (target, options = {}) => {
|
|
10850
|
-
return navTo(target, { ...options, replace: true });
|
|
10851
|
-
};
|
|
10852
11020
|
const stopLoad = (reason = "stopLoad() called") => {
|
|
10853
11021
|
const windowIsLoading = windowIsLoadingSignal.value;
|
|
10854
11022
|
if (windowIsLoading) {
|
|
@@ -11231,13 +11399,6 @@ const initRouteObserver = ({
|
|
|
11231
11399
|
const Element = element;
|
|
11232
11400
|
element = jsx(Element, {});
|
|
11233
11401
|
}
|
|
11234
|
-
// ensure we re-render on document url change (useful when navigating from /users/list to /users)
|
|
11235
|
-
// so that we re-replace urls back to /users/list when /users/list is an index
|
|
11236
|
-
useDocumentUrl();
|
|
11237
|
-
if (matchingRouteInfo && matchingRouteInfo.index && !matchingRouteInfo.route.matching) {
|
|
11238
|
-
const routeUrl = matchingRouteInfo.route.routeFromProps.buildUrl();
|
|
11239
|
-
replaceUrl(routeUrl);
|
|
11240
|
-
}
|
|
11241
11402
|
return jsx(RouteInfoContext.Provider, {
|
|
11242
11403
|
value: matchingRouteInfo,
|
|
11243
11404
|
children: jsx(SlotContext.Provider, {
|