@jsenv/navi 0.16.21 → 0.16.22
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 +161 -4
- package/dist/jsenv_navi.js.map +3 -3
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -7770,6 +7770,53 @@ const createRoutePattern = (pattern) => {
|
|
|
7770
7770
|
}
|
|
7771
7771
|
}
|
|
7772
7772
|
|
|
7773
|
+
// Include active non-default parameters from child routes for URL optimization
|
|
7774
|
+
// Only include from child routes that would actually match the current parameters
|
|
7775
|
+
const childPatternObjs = patternObject.children || [];
|
|
7776
|
+
for (const childPatternObj of childPatternObjs) {
|
|
7777
|
+
// Check if this child route would match the current resolved parameters
|
|
7778
|
+
// by simulating URL building and seeing if the child segments align
|
|
7779
|
+
let childWouldMatch = true;
|
|
7780
|
+
|
|
7781
|
+
// Compare child segments with what would be built from current params
|
|
7782
|
+
for (let i = 0; i < childPatternObj.pattern.segments.length; i++) {
|
|
7783
|
+
const childSegment = childPatternObj.pattern.segments[i];
|
|
7784
|
+
const parentSegment = parsedPattern.segments[i];
|
|
7785
|
+
|
|
7786
|
+
if (childSegment.type === "literal") {
|
|
7787
|
+
if (parentSegment && parentSegment.type === "param") {
|
|
7788
|
+
// Child has literal where parent has parameter - check if values match
|
|
7789
|
+
const paramValue = resolvedParams[parentSegment.name];
|
|
7790
|
+
if (paramValue !== childSegment.value) {
|
|
7791
|
+
childWouldMatch = false;
|
|
7792
|
+
break;
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
// If parent also has literal at this position, they should already match from route hierarchy
|
|
7796
|
+
}
|
|
7797
|
+
// Parameter segments are always compatible
|
|
7798
|
+
}
|
|
7799
|
+
|
|
7800
|
+
if (childWouldMatch) {
|
|
7801
|
+
for (const childConnection of childPatternObj.connections) {
|
|
7802
|
+
const {
|
|
7803
|
+
paramName: childParam,
|
|
7804
|
+
signal: childSignal,
|
|
7805
|
+
options: childOptions,
|
|
7806
|
+
} = childConnection;
|
|
7807
|
+
|
|
7808
|
+
// Only include if not already resolved and is non-default
|
|
7809
|
+
if (
|
|
7810
|
+
!(childParam in resolvedParams) &&
|
|
7811
|
+
childSignal?.value !== undefined &&
|
|
7812
|
+
childSignal.value !== childOptions.defaultValue
|
|
7813
|
+
) {
|
|
7814
|
+
resolvedParams[childParam] = childSignal.value;
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
}
|
|
7819
|
+
|
|
7773
7820
|
return resolvedParams;
|
|
7774
7821
|
};
|
|
7775
7822
|
|
|
@@ -7785,8 +7832,8 @@ const createRoutePattern = (pattern) => {
|
|
|
7785
7832
|
const filtered = { ...params };
|
|
7786
7833
|
|
|
7787
7834
|
for (const connection of connections) {
|
|
7788
|
-
const { paramName, signal
|
|
7789
|
-
const defaultValue =
|
|
7835
|
+
const { paramName, signal } = connection;
|
|
7836
|
+
const defaultValue = parameterDefaults.get(paramName);
|
|
7790
7837
|
|
|
7791
7838
|
if (paramName in filtered && filtered[paramName] === defaultValue) {
|
|
7792
7839
|
delete filtered[paramName];
|
|
@@ -8085,7 +8132,12 @@ const createRoutePattern = (pattern) => {
|
|
|
8085
8132
|
/**
|
|
8086
8133
|
* Helper: Determine if child route should be used based on active parameters
|
|
8087
8134
|
*/
|
|
8088
|
-
const shouldUseChildRoute = (
|
|
8135
|
+
const shouldUseChildRoute = (
|
|
8136
|
+
childPatternObj,
|
|
8137
|
+
params,
|
|
8138
|
+
compatibility,
|
|
8139
|
+
resolvedParams,
|
|
8140
|
+
) => {
|
|
8089
8141
|
// CRITICAL: Check if user explicitly passed undefined for parameters that would
|
|
8090
8142
|
// normally be used to select this child route via sibling route relationships
|
|
8091
8143
|
for (const [paramName, paramValue] of Object.entries(params)) {
|
|
@@ -8207,10 +8259,114 @@ const createRoutePattern = (pattern) => {
|
|
|
8207
8259
|
// Use child route if:
|
|
8208
8260
|
// 1. Child has active non-default parameters, OR
|
|
8209
8261
|
// 2. User provided non-default params AND child can be built completely
|
|
8210
|
-
|
|
8262
|
+
// EXCEPT: Don't use child if parent can produce cleaner URL by omitting defaults
|
|
8263
|
+
let shouldUse =
|
|
8211
8264
|
hasActiveParams ||
|
|
8212
8265
|
(hasNonDefaultProvidedParams && canBuildChildCompletely);
|
|
8213
8266
|
|
|
8267
|
+
// Optimization: Check if child would include literal segments that represent default values
|
|
8268
|
+
if (shouldUse) {
|
|
8269
|
+
// Check if child pattern has literal segments that correspond to default parameter values
|
|
8270
|
+
const childLiterals = childPatternObj.pattern.segments
|
|
8271
|
+
.filter((seg) => seg.type === "literal")
|
|
8272
|
+
.map((seg) => seg.value);
|
|
8273
|
+
|
|
8274
|
+
const parentLiterals = parsedPattern.segments
|
|
8275
|
+
.filter((seg) => seg.type === "literal")
|
|
8276
|
+
.map((seg) => seg.value);
|
|
8277
|
+
|
|
8278
|
+
// If child has more literal segments than parent, check if the extra ones are defaults
|
|
8279
|
+
if (childLiterals.length > parentLiterals.length) {
|
|
8280
|
+
const extraLiterals = childLiterals.slice(parentLiterals.length);
|
|
8281
|
+
|
|
8282
|
+
// Check if any extra literal matches a default parameter value
|
|
8283
|
+
// BUT only skip if user didn't explicitly provide that parameter AND
|
|
8284
|
+
// both conditions are true:
|
|
8285
|
+
// 1. The parameters that would cause us to use this child route are defaults
|
|
8286
|
+
// 2. The child route doesn't have non-default parameters that would be lost
|
|
8287
|
+
let childSpecificParamsAreDefaults = true;
|
|
8288
|
+
|
|
8289
|
+
// Check if parameters that determine child selection are non-default
|
|
8290
|
+
// OR if any descendant parameters indicate explicit navigation
|
|
8291
|
+
for (const connection of connections) {
|
|
8292
|
+
const { paramName } = connection;
|
|
8293
|
+
const defaultValue = parameterDefaults.get(paramName);
|
|
8294
|
+
const resolvedValue = resolvedParams[paramName];
|
|
8295
|
+
const userProvidedParam = paramName in params;
|
|
8296
|
+
|
|
8297
|
+
if (extraLiterals.includes(defaultValue)) {
|
|
8298
|
+
// This literal corresponds to a parameter in the parent
|
|
8299
|
+
if (
|
|
8300
|
+
userProvidedParam ||
|
|
8301
|
+
(resolvedValue !== undefined && resolvedValue !== defaultValue)
|
|
8302
|
+
) {
|
|
8303
|
+
// Parameter was explicitly provided or has non-default value - child is needed
|
|
8304
|
+
childSpecificParamsAreDefaults = false;
|
|
8305
|
+
break;
|
|
8306
|
+
}
|
|
8307
|
+
}
|
|
8308
|
+
}
|
|
8309
|
+
|
|
8310
|
+
// Additional check: if child route has path parameters that are non-default,
|
|
8311
|
+
// this indicates explicit navigation even if structural parameters happen to be default
|
|
8312
|
+
// (Query parameters don't count as they don't indicate structural navigation)
|
|
8313
|
+
if (childSpecificParamsAreDefaults) {
|
|
8314
|
+
for (const childConnection of childPatternObj.connections) {
|
|
8315
|
+
const childParamName = childConnection.paramName;
|
|
8316
|
+
const childDefaultValue = childConnection.options?.defaultValue;
|
|
8317
|
+
const childResolvedValue = resolvedParams[childParamName];
|
|
8318
|
+
|
|
8319
|
+
// Only consider path parameters, not query parameters
|
|
8320
|
+
const isPathParam = childPatternObj.pattern.segments.some(
|
|
8321
|
+
(seg) => seg.type === "param" && seg.name === childParamName,
|
|
8322
|
+
);
|
|
8323
|
+
|
|
8324
|
+
if (
|
|
8325
|
+
isPathParam &&
|
|
8326
|
+
childResolvedValue !== undefined &&
|
|
8327
|
+
childResolvedValue !== childDefaultValue
|
|
8328
|
+
) {
|
|
8329
|
+
// Child has non-default path parameters, indicating explicit navigation
|
|
8330
|
+
childSpecificParamsAreDefaults = false;
|
|
8331
|
+
if (DEBUG$2) {
|
|
8332
|
+
console.debug(
|
|
8333
|
+
`[${pattern}] Child has non-default path parameter '${childParamName}=${childResolvedValue}' (default: ${childDefaultValue}) - indicates explicit navigation`,
|
|
8334
|
+
);
|
|
8335
|
+
}
|
|
8336
|
+
break;
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
|
|
8341
|
+
// When structural parameters (those that determine child selection) are defaults,
|
|
8342
|
+
// prefer parent route regardless of whether child has other non-default parameters
|
|
8343
|
+
if (childSpecificParamsAreDefaults) {
|
|
8344
|
+
for (const connection of connections) {
|
|
8345
|
+
const { paramName } = connection;
|
|
8346
|
+
const defaultValue = parameterDefaults.get(paramName);
|
|
8347
|
+
const userProvidedParam = paramName in params;
|
|
8348
|
+
|
|
8349
|
+
if (extraLiterals.includes(defaultValue) && !userProvidedParam) {
|
|
8350
|
+
// This child includes a literal that represents a default value
|
|
8351
|
+
// AND user didn't explicitly provide this parameter
|
|
8352
|
+
// When structural parameters are defaults, prefer parent for cleaner URL
|
|
8353
|
+
shouldUse = false;
|
|
8354
|
+
if (DEBUG$2) {
|
|
8355
|
+
console.debug(
|
|
8356
|
+
`[${pattern}] Preferring parent over child - child includes default literal '${defaultValue}' for param '${paramName}' (structural parameter is default)`,
|
|
8357
|
+
);
|
|
8358
|
+
}
|
|
8359
|
+
break;
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
8362
|
+
} else if (DEBUG$2) {
|
|
8363
|
+
console.debug(
|
|
8364
|
+
`[${pattern}] Using child route - parameters that determine child selection are non-default`,
|
|
8365
|
+
);
|
|
8366
|
+
}
|
|
8367
|
+
}
|
|
8368
|
+
}
|
|
8369
|
+
|
|
8214
8370
|
if (DEBUG$2 && shouldUse) {
|
|
8215
8371
|
console.debug(
|
|
8216
8372
|
`[${pattern}] Will use child route ${childPatternObj.originalPattern}`,
|
|
@@ -8996,6 +9152,7 @@ const createRoutePattern = (pattern) => {
|
|
|
8996
9152
|
descendantPatternObj,
|
|
8997
9153
|
params,
|
|
8998
9154
|
compatibility,
|
|
9155
|
+
parentResolvedParams,
|
|
8999
9156
|
);
|
|
9000
9157
|
if (!shouldUse) {
|
|
9001
9158
|
return null;
|