@devp0nt/route0 1.0.0-next.49 → 1.0.0-next.50

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/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export class Route0<TDefinition extends string> {
29
29
  readonly pathDefinition: _PathDefinition<TDefinition>
30
30
  readonly paramsDefinition: _ParamsDefinition<TDefinition>
31
31
  readonly searchDefinition: _SearchDefinition<TDefinition>
32
+ readonly hasLooseSearch: HasLooseSearch<TDefinition>
32
33
  baseUrl: string
33
34
 
34
35
  private constructor(definition: TDefinition, config: RouteConfigInput = {}) {
@@ -36,6 +37,7 @@ export class Route0<TDefinition extends string> {
36
37
  this.pathDefinition = Route0._getPathDefinitionBydefinition(definition)
37
38
  this.paramsDefinition = Route0._getParamsDefinitionBydefinition(definition)
38
39
  this.searchDefinition = Route0._getSearchDefinitionBydefinition(definition)
40
+ this.hasLooseSearch = Route0._hasLooseSearch(definition)
39
41
 
40
42
  const { baseUrl } = config
41
43
  if (baseUrl && typeof baseUrl === 'string' && baseUrl.length) {
@@ -132,6 +134,12 @@ export class Route0<TDefinition extends string> {
132
134
  return searchDefinition as _SearchDefinition<TDefinition>
133
135
  }
134
136
 
137
+ private static _hasLooseSearch<TDefinition extends string>(definition: TDefinition): HasLooseSearch<TDefinition> {
138
+ // ends with &
139
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
140
+ return /&$/.test(definition) as HasLooseSearch<TDefinition>
141
+ }
142
+
135
143
  extend<TSuffixDefinition extends string>(
136
144
  suffixDefinition: TSuffixDefinition,
137
145
  ): CallableRoute<PathExtended<TDefinition, TSuffixDefinition>> {
@@ -184,10 +192,10 @@ export class Route0<TDefinition extends string> {
184
192
 
185
193
  get(
186
194
  input: OnlyIfHasParams<
187
- _ParamsDefinition<TDefinition>,
188
- WithParamsInput<TDefinition, { search?: _SearchInput<TDefinition>; abs?: boolean; hash?: string | number }>
195
+ TDefinition,
196
+ WithParamsInput<TDefinition, { search?: _LooseSearchInput<TDefinition>; abs?: boolean; hash?: string | number }>
189
197
  >,
190
- ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, string>
198
+ ): OnlyIfHasParams<TDefinition, string>
191
199
 
192
200
  // no params
193
201
  // get(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>
@@ -224,13 +232,13 @@ export class Route0<TDefinition extends string> {
224
232
  // >,
225
233
  // ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathRouteValue<TDefinition>>
226
234
 
227
- get(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): string
235
+ get(...args: OnlyIfNoParams<TDefinition, [], [never]>): string
228
236
  get(
229
237
  input: OnlyIfNoParams<
230
- _ParamsDefinition<TDefinition>,
231
- { search?: _SearchInput<TDefinition>; abs?: boolean; hash?: string | number }
238
+ TDefinition,
239
+ { search?: _LooseSearchInput<TDefinition>; abs?: boolean; hash?: string | number }
232
240
  >,
233
- ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, string>
241
+ ): OnlyIfNoParams<TDefinition, string>
234
242
 
235
243
  // implementation
236
244
  get(...args: any[]): string {
@@ -323,11 +331,11 @@ export class Route0<TDefinition extends string> {
323
331
 
324
332
  flat(
325
333
  input: OnlyIfHasParams<
326
- _ParamsDefinition<TDefinition>,
327
- WithParamsInput<TDefinition, _SearchInput<TDefinition> & { hash?: string | number }>
334
+ TDefinition,
335
+ WithParamsInput<TDefinition, LooseFlatInput<TDefinition> & { hash?: string | number }>
328
336
  >,
329
337
  abs?: boolean,
330
- ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, string>
338
+ ): OnlyIfHasParams<TDefinition, string>
331
339
 
332
340
  // no params
333
341
  // flat(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>
@@ -358,11 +366,11 @@ export class Route0<TDefinition extends string> {
358
366
  // abs: true,
359
367
  // ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathRouteValue<TDefinition>>
360
368
 
361
- flat(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): string
369
+ flat(...args: OnlyIfNoParams<TDefinition, [], [never]>): string
362
370
  flat(
363
- input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, _SearchInput<TDefinition> & { hash?: string | number }>,
371
+ input: OnlyIfNoParams<TDefinition, LooseFlatInput<TDefinition> & { hash?: string | number }>,
364
372
  abs?: boolean,
365
- ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, string>
373
+ ): OnlyIfNoParams<TDefinition, string>
366
374
 
367
375
  // implementation
368
376
  flat(...args: any[]): string {
@@ -646,10 +654,11 @@ export class Route0<TDefinition extends string> {
646
654
  } as KnownLocation<TDefinition>
647
655
  }
648
656
 
649
- parseFlatInputSafe<TStrict extends boolean = false>(
657
+ safeParseFlatInput<TLoose extends boolean = HasLooseSearch<TDefinition>>(
650
658
  input: unknown,
651
- strict?: TStrict,
652
- ): TStrict extends false ? SafeParseInputResult<TDefinition> : SafeParseInputStrictResult<TDefinition> {
659
+ loose?: TLoose,
660
+ ): TLoose extends true ? SafeParseInputLooseResult<TDefinition> : SafeParseInputStrictResult<TDefinition> {
661
+ loose ??= this.hasLooseSearch as TLoose
653
662
  const paramsKeys = this.getParamsKeys()
654
663
  if (input === undefined) {
655
664
  if (paramsKeys.length) {
@@ -678,7 +687,7 @@ export class Route0<TDefinition extends string> {
678
687
  }
679
688
  }
680
689
  const data: Record<string, string> = {}
681
- const filterKeys = strict ? [...paramsKeys, ...this.getSearchKeys()] : false
690
+ const filterKeys = !loose ? [...paramsKeys, ...this.getSearchKeys()] : false
682
691
  for (const [k, v] of Object.entries(input)) {
683
692
  if (filterKeys && !filterKeys.includes(k)) {
684
693
  continue
@@ -698,18 +707,19 @@ export class Route0<TDefinition extends string> {
698
707
  }
699
708
  }
700
709
  }
701
- return { success: true, data: data as FlatOutputWithHash<TDefinition>, error: undefined }
710
+ return { success: true, data: data as LooseFlatOutputWithHash<TDefinition>, error: undefined }
702
711
  }
703
712
 
704
- parseFlatInput<TStrict extends boolean = false>(
713
+ parseFlatInput<TLoose extends boolean = HasLooseSearch<TDefinition>>(
705
714
  input: unknown,
706
- strict?: TStrict,
707
- ): TStrict extends false ? FlatOutput<TDefinition> : StrictFlatOutput<TDefinition> {
708
- const result = this.parseFlatInputSafe(input, strict)
715
+ loose?: TLoose,
716
+ ): TLoose extends true ? LooseFlatOutput<TDefinition> : StrictFlatOutput<TDefinition> {
717
+ loose ??= this.hasLooseSearch as TLoose
718
+ const result = this.safeParseFlatInput(input, loose)
709
719
  if (result.error) {
710
720
  throw result.error
711
721
  }
712
- return result.data as TStrict extends false ? FlatOutput<TDefinition> : StrictFlatOutput<TDefinition>
722
+ return result.data as TLoose extends true ? LooseFlatOutput<TDefinition> : StrictFlatOutput<TDefinition>
713
723
  }
714
724
 
715
725
  isSame(other: Route0<TDefinition>): boolean {
@@ -1090,19 +1100,15 @@ export type IsSameParams<T1 extends AnyRoute | string, T2 extends AnyRoute | str
1090
1100
 
1091
1101
  export type HasParams<T extends AnyRoute | string> =
1092
1102
  ExtractPathParams<PathDefinition<T>> extends infer U ? ([U] extends [never] ? false : true) : false
1093
- export type HasSearch<T extends AnyRoute | string> =
1094
- NonEmpty<SearchTailDefinitionWithoutFirstAmp<Definition<T>>> extends infer Tail extends string
1095
- ? AmpSplit<Tail> extends infer U
1096
- ? [U] extends [never]
1097
- ? false
1098
- : true
1099
- : false
1100
- : false
1103
+ export type HasSearch<T extends AnyRoute | string> = Definition<T> extends `${string}&${string}` ? true : false
1104
+ export type HasNamedSearch<T extends AnyRoute | string> = // Definition<T> extends `${string}&${string}` ? true : false
1105
+ SearchTailDefinitionWithoutFirstAndLastAmp<Definition<T>> extends '' ? false : true
1106
+ export type HasLooseSearch<T extends AnyRoute | string> = Definition<T> extends `${string}&` ? true : false
1101
1107
 
1102
1108
  export type ParamsOutput<T extends AnyRoute | string> = {
1103
1109
  [K in keyof ParamsDefinition<T>]: string
1104
1110
  }
1105
- export type SearchOutput<T extends AnyRoute | string = string> = Partial<
1111
+ export type LooseSearchOutput<T extends AnyRoute | string = string> = Partial<
1106
1112
  {
1107
1113
  [K in keyof SearchDefinition<T>]?: string
1108
1114
  } & Record<string, string | undefined>
@@ -1110,27 +1116,31 @@ export type SearchOutput<T extends AnyRoute | string = string> = Partial<
1110
1116
  export type StrictSearchOutput<T extends AnyRoute | string> = Partial<{
1111
1117
  [K in keyof SearchDefinition<T>]?: string | undefined
1112
1118
  }>
1113
- export type FlatOutput<T extends AnyRoute | string = string> =
1114
- HasParams<Definition<T>> extends true ? ParamsOutput<T> & SearchOutput<T> : SearchOutput<T>
1119
+ export type LooseFlatOutput<T extends AnyRoute | string = string> =
1120
+ HasParams<Definition<T>> extends true ? ParamsOutput<T> & LooseSearchOutput<T> : LooseSearchOutput<T>
1115
1121
  export type StrictFlatOutput<T extends AnyRoute | string> =
1116
1122
  HasParams<Definition<T>> extends true ? ParamsOutput<T> & StrictSearchOutput<T> : StrictSearchOutput<T>
1117
- export type FlatOutputWithHash<T extends AnyRoute | string = string> = FlatOutput<T> & { hash?: string | undefined }
1123
+ export type LooseFlatOutputWithHash<T extends AnyRoute | string = string> = LooseFlatOutput<T> & {
1124
+ hash?: string | undefined
1125
+ }
1118
1126
  export type StrictFlatOutputWithHash<T extends AnyRoute | string> = StrictFlatOutput<T> & { hash?: string | undefined }
1119
1127
  export type ParamsInput<T extends AnyRoute | string = string> = _ParamsInput<PathDefinition<T>>
1120
- export type SearchInput<T extends AnyRoute | string = string> = _SearchInput<Definition<T>>
1128
+ export type LooseSearchInput<T extends AnyRoute | string = string> = _LooseSearchInput<Definition<T>>
1121
1129
  export type StrictSearchInput<T extends AnyRoute | string> = _StrictSearchInput<Definition<T>>
1122
- export type FlatInput<T extends AnyRoute | string> = _FlatInput<Definition<T>>
1130
+ export type LooseFlatInput<T extends AnyRoute | string> = _FlatInput<Definition<T>>
1123
1131
  export type StrictFlatInput<T extends AnyRoute | string> = _StrictFlatInput<Definition<T>>
1124
- export type FlatInputWithHash<T extends AnyRoute | string> = _FlatInput<Definition<T>> & { hash?: string | number }
1132
+ export type LooseFlatInputWithHash<T extends AnyRoute | string> = _FlatInput<Definition<T>> & { hash?: string | number }
1125
1133
  export type StrictFlatInputWithHash<T extends AnyRoute | string> = _StrictFlatInput<Definition<T>> & {
1126
1134
  hash?: string | number
1127
1135
  }
1128
1136
  export type CanInputBeEmpty<T extends AnyRoute | string> = HasParams<Definition<T>> extends true ? false : true
1129
1137
 
1130
1138
  export type ParamsInputStringOnly<T extends AnyRoute | string = string> = _ParamsInputStringOnly<PathDefinition<T>>
1131
- export type SearchInputStringOnly<T extends AnyRoute | string = string> = _SearchInputStringOnly<Definition<T>>
1139
+ export type LooseSearchInputStringOnly<T extends AnyRoute | string = string> = _LooseSearchInputStringOnly<
1140
+ Definition<T>
1141
+ >
1132
1142
  export type StrictSearchInputStringOnly<T extends AnyRoute | string> = _StrictSearchInputStringOnly<Definition<T>>
1133
- export type FlatInputStringOnly<T extends AnyRoute | string> = _FlatInputStringOnly<Definition<T>>
1143
+ export type LooseFlatInputStringOnly<T extends AnyRoute | string> = _LooseFlatInputStringOnly<Definition<T>>
1134
1144
  export type StrictFlatInputStringOnly<T extends AnyRoute | string> = _StrictFlatInputStringOnly<Definition<T>>
1135
1145
 
1136
1146
  // location
@@ -1156,7 +1166,7 @@ export type _GeneralLocation = {
1156
1166
  }
1157
1167
  export type UnknownLocation = _GeneralLocation & {
1158
1168
  params: undefined
1159
- searchParams: SearchOutput
1169
+ searchParams: LooseSearchOutput
1160
1170
  route: undefined
1161
1171
  exact: false
1162
1172
  parent: false
@@ -1164,7 +1174,7 @@ export type UnknownLocation = _GeneralLocation & {
1164
1174
  }
1165
1175
  export type UnmatchedLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {
1166
1176
  params: Record<never, never>
1167
- searchParams: SearchOutput<TRoute>
1177
+ searchParams: LooseSearchOutput<TRoute>
1168
1178
  route: Definition<TRoute>
1169
1179
  exact: false
1170
1180
  parent: false
@@ -1172,7 +1182,7 @@ export type UnmatchedLocation<TRoute extends AnyRoute | string = AnyRoute | stri
1172
1182
  }
1173
1183
  export type ExactLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {
1174
1184
  params: ParamsOutput<TRoute>
1175
- searchParams: SearchOutput<TRoute>
1185
+ searchParams: LooseSearchOutput<TRoute>
1176
1186
  route: Definition<TRoute>
1177
1187
  exact: true
1178
1188
  parent: false
@@ -1180,7 +1190,7 @@ export type ExactLocation<TRoute extends AnyRoute | string = AnyRoute | string>
1180
1190
  }
1181
1191
  export type ParentLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {
1182
1192
  params: Partial<ParamsOutput<TRoute>> // in fact maybe there will be whole params object, but does not matter now
1183
- searchParams: SearchOutput<TRoute>
1193
+ searchParams: LooseSearchOutput<TRoute>
1184
1194
  route: Definition<TRoute>
1185
1195
  exact: false
1186
1196
  parent: true
@@ -1188,7 +1198,7 @@ export type ParentLocation<TRoute extends AnyRoute | string = AnyRoute | string>
1188
1198
  }
1189
1199
  export type ChildrenLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {
1190
1200
  params: ParamsOutput<TRoute>
1191
- searchParams: SearchOutput<TRoute>
1201
+ searchParams: LooseSearchOutput<TRoute>
1192
1202
  route: Definition<TRoute>
1193
1203
  exact: false
1194
1204
  parent: false
@@ -1211,7 +1221,7 @@ export type _ParamsDefinition<TDefinition extends string> =
1211
1221
  : { [K in Extract<U, string>]: true }
1212
1222
  : undefined
1213
1223
  export type _SearchDefinition<TDefinition extends string> =
1214
- NonEmpty<SearchTailDefinitionWithoutFirstAmp<TDefinition>> extends infer Tail extends string
1224
+ NonEmpty<SearchTailDefinitionWithoutFirstAndLastAmp<TDefinition>> extends infer Tail extends string
1215
1225
  ? AmpSplit<Tail> extends infer U
1216
1226
  ? [U] extends [never]
1217
1227
  ? undefined
@@ -1225,7 +1235,7 @@ export type _ParamsInput<TDefinition extends string> =
1225
1235
  : {
1226
1236
  [K in keyof _ParamsDefinition<TDefinition>]: string | number
1227
1237
  }
1228
- export type _SearchInput<TDefinition extends string> =
1238
+ export type _LooseSearchInput<TDefinition extends string> =
1229
1239
  _SearchDefinition<TDefinition> extends undefined
1230
1240
  ? Record<string, string | number>
1231
1241
  : Partial<{
@@ -1237,14 +1247,14 @@ export type _StrictSearchInput<TDefinition extends string> = Partial<{
1237
1247
  }>
1238
1248
  export type _FlatInput<TDefinition extends string> =
1239
1249
  HasParams<TDefinition> extends true
1240
- ? _ParamsInput<TDefinition> & _SearchInput<TDefinition>
1241
- : _SearchInput<TDefinition>
1250
+ ? _ParamsInput<TDefinition> & _LooseSearchInput<TDefinition>
1251
+ : _LooseSearchInput<TDefinition>
1242
1252
  export type _StrictFlatInput<TDefinition extends string> =
1243
1253
  HasParams<TDefinition> extends true
1244
- ? HasSearch<TDefinition> extends true
1254
+ ? HasNamedSearch<TDefinition> extends true
1245
1255
  ? _StrictSearchInput<TDefinition> & _ParamsInput<TDefinition>
1246
1256
  : _ParamsInput<TDefinition>
1247
- : HasSearch<TDefinition> extends true
1257
+ : HasNamedSearch<TDefinition> extends true
1248
1258
  ? _StrictSearchInput<TDefinition>
1249
1259
  : Record<never, never>
1250
1260
 
@@ -1254,7 +1264,7 @@ export type _ParamsInputStringOnly<TDefinition extends string> =
1254
1264
  : {
1255
1265
  [K in keyof _ParamsDefinition<TDefinition>]: string
1256
1266
  }
1257
- export type _SearchInputStringOnly<TDefinition extends string> =
1267
+ export type _LooseSearchInputStringOnly<TDefinition extends string> =
1258
1268
  _SearchDefinition<TDefinition> extends undefined
1259
1269
  ? Record<string, string>
1260
1270
  : Partial<{
@@ -1264,21 +1274,26 @@ export type _SearchInputStringOnly<TDefinition extends string> =
1264
1274
  export type _StrictSearchInputStringOnly<TDefinition extends string> = Partial<{
1265
1275
  [K in keyof _SearchDefinition<TDefinition>]: string
1266
1276
  }>
1267
- export type _FlatInputStringOnly<TDefinition extends string> =
1277
+ export type _LooseFlatInputStringOnly<TDefinition extends string> =
1268
1278
  HasParams<TDefinition> extends true
1269
- ? _ParamsInputStringOnly<TDefinition> & _SearchInputStringOnly<TDefinition>
1270
- : _SearchInputStringOnly<TDefinition>
1279
+ ? _ParamsInputStringOnly<TDefinition> & _LooseSearchInputStringOnly<TDefinition>
1280
+ : _LooseSearchInputStringOnly<TDefinition>
1271
1281
  export type _StrictFlatInputStringOnly<TDefinition extends string> =
1272
1282
  HasParams<TDefinition> extends true
1273
- ? HasSearch<TDefinition> extends true
1283
+ ? HasNamedSearch<TDefinition> extends true
1274
1284
  ? _StrictSearchInputStringOnly<TDefinition> & _ParamsInputStringOnly<TDefinition>
1275
1285
  : _ParamsInputStringOnly<TDefinition>
1276
- : HasSearch<TDefinition> extends true
1286
+ : HasNamedSearch<TDefinition> extends true
1277
1287
  ? _StrictSearchInputStringOnly<TDefinition>
1278
1288
  : Record<never, never>
1279
1289
 
1280
1290
  export type TrimSearchTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S
1281
1291
  export type SearchTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''
1292
+ export type SearchTailDefinitionWithoutFirstAndLastAmp<S extends string> = S extends `${string}&${infer T}&`
1293
+ ? T
1294
+ : S extends `${string}&${infer T}`
1295
+ ? T
1296
+ : ''
1282
1297
  export type SearchTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''
1283
1298
  export type AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | AmpSplit<B> : S
1284
1299
  // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
@@ -1316,8 +1331,10 @@ export type JoinPath<Parent extends string, Suffix extends string> = DedupeSlash
1316
1331
  : never
1317
1332
  >
1318
1333
 
1319
- export type OnlyIfNoParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? Yes : No
1320
- export type OnlyIfHasParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? No : Yes
1334
+ export type OnlyIfNoParams<TRoute extends AnyRoute | string, Yes, No = never> =
1335
+ HasParams<TRoute> extends false ? Yes : No
1336
+ export type OnlyIfHasParams<TRoute extends AnyRoute | string, Yes, No = never> =
1337
+ HasParams<TRoute> extends true ? Yes : No
1321
1338
 
1322
1339
  // export type PathRouteValue<TDefinition extends string> = `${ReplacePathParams<PathDefinition<TDefinition>>}`
1323
1340
  // export type PathOnlyRouteValue<TDefinition extends string> = `${ReplacePathParams<PathDefinition<TDefinition>>}`
@@ -1338,7 +1355,7 @@ export type WithParamsInput<
1338
1355
  TDefinition extends string,
1339
1356
  T extends
1340
1357
  | {
1341
- search?: _SearchInput<any>
1358
+ search?: _LooseSearchInput<any>
1342
1359
  abs?: boolean
1343
1360
  hash?: string | number
1344
1361
  }
@@ -1387,4 +1404,4 @@ export type _SafeParseInputResult<TInputParsed extends Record<string, unknown>>
1387
1404
  export type SafeParseInputStrictResult<TDefinition extends string> = _SafeParseInputResult<
1388
1405
  StrictFlatOutput<TDefinition>
1389
1406
  >
1390
- export type SafeParseInputResult<TDefinition extends string> = _SafeParseInputResult<FlatOutput<TDefinition>>
1407
+ export type SafeParseInputLooseResult<TDefinition extends string> = _SafeParseInputResult<LooseFlatOutput<TDefinition>>