@jsenv/navi 0.20.20 → 0.21.0

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.
@@ -9315,7 +9315,7 @@ const createRoutePattern = (pattern, { searchParams = {} } = {}) => {
9315
9315
  /**
9316
9316
  * Helper: Check if a literal value can be reached through available parameters
9317
9317
  */
9318
- const canReachLiteralValue = (literalValue, params) => {
9318
+ const canReachLiteralValue = (literalValue, params, literalPosition) => {
9319
9319
  // Check parent's own parameters (signals and user params)
9320
9320
  const parentCanProvide = connections.some((conn) => {
9321
9321
  const signalValue = conn.signal.value;
@@ -9325,31 +9325,31 @@ const createRoutePattern = (pattern, { searchParams = {} } = {}) => {
9325
9325
  effectiveValue === literalValue && conn.isCustomValue(effectiveValue)
9326
9326
  );
9327
9327
  });
9328
+ if (parentCanProvide) {
9329
+ return true;
9330
+ }
9328
9331
 
9329
9332
  // Check user-provided parameters
9330
9333
  const userCanProvide = Object.entries(params).some(
9331
9334
  ([, value]) => value === literalValue,
9332
9335
  );
9336
+ if (userCanProvide) {
9337
+ return true;
9338
+ }
9333
9339
 
9334
- // Check if any descendant signal can provide this literal
9335
- // (ancestor signals are excluded since they operate on different path positions
9336
- // that the current pattern has already "passed")
9337
- const getDescendantSignals = (pattern) => {
9338
- const signals = [...pattern.connections];
9339
- for (const child of pattern.children) {
9340
- signals.push(...getDescendantSignals(child));
9341
- }
9342
- return signals;
9343
- };
9344
-
9345
- const descendantSignals = getDescendantSignals(patternObject);
9346
-
9347
- const systemCanProvide = descendantSignals.some((conn) => {
9340
+ // Check if any descendant path signal provides this literal value AT THE SAME position.
9341
+ // A signal from /map/isochrone/:tab can provide a literal at position 2 (tab position),
9342
+ // but NOT a literal at position 1 (panel position) — even if the signal value matches.
9343
+ // descendantPathSignals is a Map<segmentIndex, conn[]> precomputed during setupPatterns.
9344
+ const connsAtPosition =
9345
+ patternObject.descendantPathSignals.get(literalPosition);
9346
+ if (!connsAtPosition) {
9347
+ return false;
9348
+ }
9349
+ return connsAtPosition.some((conn) => {
9348
9350
  const signalValue = conn.signal.value;
9349
9351
  return signalValue === literalValue && conn.isCustomValue(signalValue);
9350
9352
  });
9351
-
9352
- return parentCanProvide || userCanProvide || systemCanProvide;
9353
9353
  };
9354
9354
  const checkChildRouteCompatibility = (childPatternObj, params) => {
9355
9355
  const childParams = {};
@@ -9419,7 +9419,7 @@ const createRoutePattern = (pattern, { searchParams = {} } = {}) => {
9419
9419
  }
9420
9420
  // Parent doesn't have a segment at this position - child extends beyond parent
9421
9421
  // Check if any available parameter can produce this literal value
9422
- else if (!canReachLiteralValue(literalValue, params)) {
9422
+ else if (!canReachLiteralValue(literalValue, params, childPosition)) {
9423
9423
  if (DEBUG$2) {
9424
9424
  console.debug(
9425
9425
  `[${pattern}] INCOMPATIBLE with ${childPatternObj.originalPattern}: cannot reach literal segment "${literalValue}" at position ${childPosition} - no viable parameter path`,
@@ -11045,6 +11045,7 @@ const createRoutePattern = (pattern, { searchParams = {} } = {}) => {
11045
11045
  children: [],
11046
11046
  parent: null,
11047
11047
  depth: 0, // Will be calculated after relationships are built
11048
+ descendantPathSignals: new Map(), // Precomputed during setupPatterns (Map<segmentIndex, conn[]>)
11048
11049
 
11049
11050
  // Pattern methods (formerly patternObj methods)
11050
11051
  originalPattern: pattern,
@@ -12138,7 +12139,35 @@ const setupRoutePatterns = (routePatterns) => {
12138
12139
  );
12139
12140
  }
12140
12141
  }
12141
- // Phase 5: Calculate depths for all patterns
12142
+ // Phase 5: Precompute descendant path signals for each pattern (used by canReachLiteralValue)
12143
+ // Stored as a Map<segmentIndex, conn[]> for O(1) lookup by position.
12144
+ for (const routePattern of routePatternSet) {
12145
+ const descendantPathSignalsByIndex = new Map();
12146
+ const collectDescendantPathSignals = (patternObj) => {
12147
+ for (const conn of patternObj.connections) {
12148
+ if (conn.paramType === "path") {
12149
+ const paramSegment = patternObj.pattern.segments.find(
12150
+ (seg) => seg.type === "param" && seg.name === conn.paramName,
12151
+ );
12152
+ if (paramSegment) {
12153
+ const { index } = paramSegment;
12154
+ let conns = descendantPathSignalsByIndex.get(index);
12155
+ if (!conns) {
12156
+ conns = [];
12157
+ descendantPathSignalsByIndex.set(index, conns);
12158
+ }
12159
+ conns.push(conn);
12160
+ }
12161
+ }
12162
+ }
12163
+ for (const child of patternObj.children) {
12164
+ collectDescendantPathSignals(child);
12165
+ }
12166
+ };
12167
+ collectDescendantPathSignals(routePattern);
12168
+ routePattern.descendantPathSignals = descendantPathSignalsByIndex;
12169
+ }
12170
+ // Phase 6: Calculate depths for all patterns
12142
12171
  for (const routePattern of routePatternSet) {
12143
12172
  calculatePatternDepth(routePattern);
12144
12173
  }