@devp0nt/route0 1.0.0-next.64 → 1.0.0-next.66

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.
@@ -1,3 +1,5 @@
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+
1
3
  /**
2
4
  * Strongly typed route descriptor and URL builder.
3
5
  *
@@ -138,14 +140,19 @@ declare class Route0<TDefinition extends string> {
138
140
  getLocation(location: AnyLocation): KnownLocation<TDefinition>;
139
141
  getLocation(url: AnyLocation): KnownLocation<TDefinition>;
140
142
  getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): KnownLocation<TDefinition>;
141
- /**
142
- * Safe parser for flat input objects.
143
- *
144
- * Returns structured success/error result instead of throwing.
145
- */
146
- safeParseFlatInput<TLoose extends boolean = HasLooseSearch<TDefinition>>(input: unknown, loose?: TLoose): TLoose extends true ? SafeParseInputLooseResult<TDefinition> : SafeParseInputStrictResult<TDefinition>;
147
- /** Throwing variant of `safeParseFlatInput()`. */
148
- parseFlatInput<TLoose extends boolean = HasLooseSearch<TDefinition>>(input: unknown, loose?: TLoose): TLoose extends true ? LooseFlatOutput<TDefinition> : StrictFlatOutput<TDefinition>;
143
+ private _validateParamsInput;
144
+ private _validateSearchInput;
145
+ private _validateFlatInput;
146
+ private _safeParseSchemaResult;
147
+ private _parseSchemaResult;
148
+ /** Standard Schema for route params input. */
149
+ readonly paramsInputSchema: Route0Schema<ParamsInput<TDefinition> | undefined, ParamsOutput<TDefinition>>;
150
+ /** Standard Schema for strict search input. */
151
+ readonly strictSearchInputSchema: Route0Schema<StrictSearchInput<TDefinition> | undefined, StrictSearchOutput<TDefinition>>;
152
+ /** Standard Schema for loose search input. */
153
+ readonly looseSearchInputSchema: Route0Schema<LooseSearchInput<TDefinition> | undefined, LooseSearchOutput<TDefinition>>;
154
+ /** Standard Schema for route flat input (uses route default strict/loose mode). */
155
+ readonly flatInputSchema: Route0Schema<FlatInput<TDefinition, HasLooseSearch<TDefinition>> | undefined, FlatOutput<TDefinition, HasLooseSearch<TDefinition>>>;
149
156
  /** True when path structure is equal (param names are ignored). */
150
157
  isSame(other: AnyRoute): boolean;
151
158
  /** Static convenience wrapper for `isSame`. */
@@ -173,7 +180,7 @@ declare class Routes<const T extends RoutesRecord = any> {
173
180
  _: {
174
181
  routes: Routes<T>['_routes'];
175
182
  getLocation: Routes<T>['_getLocation'];
176
- override: Routes<T>['_override'];
183
+ clone: Routes<T>['_clone'];
177
184
  pathsOrdering: Routes<T>['_pathsOrdering'];
178
185
  keysOrdering: Routes<T>['_keysOrdering'];
179
186
  ordered: Routes<T>['_ordered'];
@@ -197,7 +204,7 @@ declare class Routes<const T extends RoutesRecord = any> {
197
204
  _getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation;
198
205
  private static makeOrdering;
199
206
  /** Returns a cloned routes collection with config applied to each route. */
200
- _override(config: RouteConfigInput): RoutesPretty<T>;
207
+ _clone(config: RouteConfigInput): RoutesPretty<T>;
201
208
  static _: {
202
209
  prettify: typeof Routes.prettify;
203
210
  hydrate: typeof Routes.hydrate;
@@ -221,7 +228,7 @@ type RoutesRecordHydrated<TRoutesRecord extends RoutesRecord = any> = {
221
228
  [K in keyof TRoutesRecord]: CallableRoute<TRoutesRecord[K]>;
222
229
  };
223
230
  /** Public shape returned by `Routes.create()`. Default `any` so `satisfies RoutesPretty` accepts any created routes. */
224
- type RoutesPretty<TRoutesRecord extends RoutesRecord = any> = RoutesRecordHydrated<TRoutesRecord> & Omit<Routes<TRoutesRecord>, '_routes' | '_getLocation' | '_override' | '_pathsOrdering' | '_keysOrdering' | '_ordered'>;
231
+ type RoutesPretty<TRoutesRecord extends RoutesRecord = any> = RoutesRecordHydrated<TRoutesRecord> & Omit<Routes<TRoutesRecord>, '_routes' | '_getLocation' | '_clone' | '_pathsOrdering' | '_keysOrdering' | '_ordered'>;
225
232
  type ExtractRoutesKeys<TRoutes extends RoutesPretty | RoutesRecord> = TRoutes extends RoutesPretty ? Extract<keyof TRoutes['_']['routes'], string> : TRoutes extends RoutesRecord ? Extract<keyof TRoutes, string> : never;
226
233
  type ExtractRoute<TRoutes extends RoutesPretty | RoutesRecord, TKey extends ExtractRoutesKeys<TRoutes>> = TRoutes extends RoutesPretty ? TRoutes['_']['routes'][TKey] : TRoutes extends RoutesRecord ? TRoutes[TKey] : never;
227
234
  type Definition<T extends AnyRoute | string> = T extends AnyRoute ? T['definition'] : T extends string ? T : never;
@@ -508,5 +515,9 @@ type _SafeParseInputResult<TInputParsed extends Record<string, unknown>> = {
508
515
  };
509
516
  type SafeParseInputStrictResult<TDefinition extends string> = _SafeParseInputResult<StrictFlatOutput<TDefinition>>;
510
517
  type SafeParseInputLooseResult<TDefinition extends string> = _SafeParseInputResult<LooseFlatOutput<TDefinition>>;
518
+ type Route0Schema<TInput extends Record<string, unknown> | undefined, TOutput extends Record<string, unknown>> = StandardSchemaV1<TInput, TOutput> & {
519
+ parse: (input: unknown) => TOutput;
520
+ safeParse: (input: unknown) => _SafeParseInputResult<TOutput>;
521
+ };
511
522
 
512
- export { type AmpSplit, type AncestorLocation, type AncestorLocationState, type AnyLocation, type AnyRoute, type AnyRouteOrDefinition, type CallableRoute, type CanInputBeEmpty, type DedupeSlashes, type Definition, type DescendantLocation, type DescendantLocationState, type EmptyRecord, type ExactLocation, type ExactLocationState, type Extended, type ExtractPathParams, type ExtractRoute, type ExtractRoutesKeys, type FlatInput, type FlatInputStringOnly, type FlatInputWithHash, type FlatOutput, type FlatOutputWithHash, type HasLooseSearch, type HasNamedSearch, type HasParams, type HasSearch, type IsAncestor, type IsDescendant, type IsSame, type IsSameParams, type JoinPath, type KnownLocation, type LocationParams, type LocationSearch, type LooseFlatInput, type LooseFlatInputStringOnly, type LooseFlatInputWithHash, type LooseFlatOutput, type LooseFlatOutputWithHash, type LooseSearchInput, type LooseSearchInputStringOnly, type LooseSearchOutput, type NonEmpty, type OnlyIfHasParams, type OnlyIfNoParams, type ParamsDefinition, type ParamsInput, type ParamsInputStringOnly, type ParamsOutput, type PathDefinition, type PathExtended, type ReplacePathParams, Route0, type RouteConfigInput, Routes, type RoutesPretty, type RoutesRecord, type RoutesRecordHydrated, type SafeParseInputLooseResult, type SafeParseInputStrictResult, type SearchDefinition, type SearchTailDefinitionWithFirstAmp, type SearchTailDefinitionWithoutFirstAmp, type SearchTailDefinitionWithoutFirstAndLastAmp, type StrictFlatInput, type StrictFlatInputStringOnly, type StrictFlatInputWithHash, type StrictFlatOutput, type StrictFlatOutputWithHash, type StrictSearchInput, type StrictSearchInputStringOnly, type StrictSearchOutput, type TrimSearchTailDefinition, type UnknownLocation, type UnknownLocationState, type UnmatchedLocation, type UnmatchedLocationState, type WeakAncestorLocation, type WeakAncestorLocationState, type WeakDescendantLocation, type WeakDescendantLocationState, type WithParamsInput, type _GeneralLocation, type _IsAncestor, type _IsDescendant, type _IsSame, type _IsSameParams, type _LooseFlatInput, type _LooseFlatInputStringOnly, type _LooseSearchInput, type _LooseSearchInputStringOnly, type _ParamsDefinition, type _ParamsInput, type _ParamsInputStringOnly, type _PathDefinition, type _SafeParseInputResult, type _SearchDefinition, type _StrictFlatInput, type _StrictFlatInputStringOnly, type _StrictSearchInput, type _StrictSearchInputStringOnly };
523
+ export { type AmpSplit, type AncestorLocation, type AncestorLocationState, type AnyLocation, type AnyRoute, type AnyRouteOrDefinition, type CallableRoute, type CanInputBeEmpty, type DedupeSlashes, type Definition, type DescendantLocation, type DescendantLocationState, type EmptyRecord, type ExactLocation, type ExactLocationState, type Extended, type ExtractPathParams, type ExtractRoute, type ExtractRoutesKeys, type FlatInput, type FlatInputStringOnly, type FlatInputWithHash, type FlatOutput, type FlatOutputWithHash, type HasLooseSearch, type HasNamedSearch, type HasParams, type HasSearch, type IsAncestor, type IsDescendant, type IsSame, type IsSameParams, type JoinPath, type KnownLocation, type LocationParams, type LocationSearch, type LooseFlatInput, type LooseFlatInputStringOnly, type LooseFlatInputWithHash, type LooseFlatOutput, type LooseFlatOutputWithHash, type LooseSearchInput, type LooseSearchInputStringOnly, type LooseSearchOutput, type NonEmpty, type OnlyIfHasParams, type OnlyIfNoParams, type ParamsDefinition, type ParamsInput, type ParamsInputStringOnly, type ParamsOutput, type PathDefinition, type PathExtended, type ReplacePathParams, Route0, type Route0Schema, type RouteConfigInput, Routes, type RoutesPretty, type RoutesRecord, type RoutesRecordHydrated, type SafeParseInputLooseResult, type SafeParseInputStrictResult, type SearchDefinition, type SearchTailDefinitionWithFirstAmp, type SearchTailDefinitionWithoutFirstAmp, type SearchTailDefinitionWithoutFirstAndLastAmp, type StrictFlatInput, type StrictFlatInputStringOnly, type StrictFlatInputWithHash, type StrictFlatOutput, type StrictFlatOutputWithHash, type StrictSearchInput, type StrictSearchInputStringOnly, type StrictSearchOutput, type TrimSearchTailDefinition, type UnknownLocation, type UnknownLocationState, type UnmatchedLocation, type UnmatchedLocationState, type WeakAncestorLocation, type WeakAncestorLocationState, type WeakDescendantLocation, type WeakDescendantLocationState, type WithParamsInput, type _GeneralLocation, type _IsAncestor, type _IsDescendant, type _IsSame, type _IsSameParams, type _LooseFlatInput, type _LooseFlatInputStringOnly, type _LooseSearchInput, type _LooseSearchInputStringOnly, type _ParamsDefinition, type _ParamsInput, type _ParamsInputStringOnly, type _PathDefinition, type _SafeParseInputResult, type _SearchDefinition, type _StrictFlatInput, type _StrictFlatInputStringOnly, type _StrictSearchInput, type _StrictSearchInputStringOnly };
package/dist/esm/index.js CHANGED
@@ -9,7 +9,7 @@ class Route0 {
9
9
  get origin() {
10
10
  if (!this._origin) {
11
11
  throw new Error(
12
- "origin for route " + this.definition + ' is not set, please provide it like Route0.create(route, {origin: "https://example.com"}) in config or set via overrides like routes._.override({origin: "https://example.com"})'
12
+ "origin for route " + this.definition + ' is not set, please provide it like Route0.create(route, {origin: "https://example.com"}) in config or set via clones like routes._.clone({origin: "https://example.com"})'
13
13
  );
14
14
  }
15
15
  return this._origin;
@@ -434,76 +434,171 @@ class Route0 {
434
434
  unmatched
435
435
  };
436
436
  }
437
- /**
438
- * Safe parser for flat input objects.
439
- *
440
- * Returns structured success/error result instead of throwing.
441
- */
442
- safeParseFlatInput(input, loose) {
443
- loose ??= this.hasLooseSearch;
437
+ _validateParamsInput(input) {
444
438
  const paramsKeys = this.getParamsKeys();
445
439
  if (input === void 0) {
446
440
  if (paramsKeys.length) {
447
441
  return {
448
- success: false,
449
- data: void 0,
450
- error: new Error(`Missing params: ${paramsKeys.map((k) => `"${k}"`).join(", ")}`)
442
+ issues: [
443
+ {
444
+ message: `Missing params: ${paramsKeys.map((k) => `"${k}"`).join(", ")}`
445
+ }
446
+ ]
451
447
  };
452
448
  }
453
449
  input = {};
454
450
  }
455
451
  if (typeof input !== "object" || input === null) {
456
452
  return {
457
- success: false,
458
- data: void 0,
459
- error: new Error("Invalid input: expected object")
453
+ issues: [{ message: "Invalid input: expected object" }]
460
454
  };
461
455
  }
462
- const inputKeys = Object.keys(input);
456
+ const inputObj = input;
457
+ const inputKeys = Object.keys(inputObj);
463
458
  const notDefinedKeys = paramsKeys.filter((k) => !inputKeys.includes(k));
464
459
  if (notDefinedKeys.length) {
465
460
  return {
466
- success: false,
467
- data: void 0,
468
- error: new Error(`Missing params: ${notDefinedKeys.map((k) => `"${k}"`).join(", ")}`)
461
+ issues: [
462
+ {
463
+ message: `Missing params: ${notDefinedKeys.map((k) => `"${k}"`).join(", ")}`
464
+ }
465
+ ]
469
466
  };
470
467
  }
471
468
  const data = {};
472
- const filterKeys = !loose ? [...paramsKeys, ...this.getSearchKeys()] : false;
473
- for (const [k, v] of Object.entries(input)) {
474
- if (filterKeys && !filterKeys.includes(k)) {
475
- continue;
469
+ for (const k of paramsKeys) {
470
+ const v = inputObj[k];
471
+ if (typeof v === "string") {
472
+ data[k] = v;
473
+ } else if (typeof v === "number") {
474
+ data[k] = String(v);
475
+ } else {
476
+ return {
477
+ issues: [{ message: `Invalid input: expected string, number, got ${typeof v} for "${k}"` }]
478
+ };
476
479
  }
480
+ }
481
+ return {
482
+ value: data
483
+ };
484
+ }
485
+ _validateSearchInput(input, loose) {
486
+ if (input === void 0) {
487
+ input = {};
488
+ }
489
+ if (typeof input !== "object" || input === null) {
490
+ return {
491
+ issues: [{ message: "Invalid input: expected object" }]
492
+ };
493
+ }
494
+ const inputObj = input;
495
+ const paramsKeys = this.getParamsKeys();
496
+ const searchKeys = this.getSearchKeys();
497
+ const data = {};
498
+ for (const [k, v] of Object.entries(inputObj)) {
499
+ if (k === "hash") continue;
500
+ if (paramsKeys.includes(k)) continue;
501
+ if (!loose && !searchKeys.includes(k)) continue;
502
+ if (v === void 0) continue;
477
503
  if (typeof v === "string") {
478
504
  data[k] = v;
479
505
  } else if (typeof v === "number") {
480
506
  data[k] = String(v);
481
507
  } else {
482
- const isParamKey = paramsKeys.includes(k);
483
508
  return {
484
- success: false,
485
- data: void 0,
486
- error: new Error(
487
- `Invalid input: expected string, number,${!isParamKey ? " or undefined," : ""} got ${typeof v} for "${k}"`
488
- )
509
+ issues: [{ message: `Invalid input: expected string, number, or undefined, got ${typeof v} for "${k}"` }]
489
510
  };
490
511
  }
491
512
  }
492
513
  return {
493
- success: true,
494
- data,
495
- error: void 0
514
+ value: data
515
+ };
516
+ }
517
+ _validateFlatInput(input, loose) {
518
+ const paramsResult = this._validateParamsInput(input);
519
+ if ("issues" in paramsResult) {
520
+ return {
521
+ issues: paramsResult.issues ?? []
522
+ };
523
+ }
524
+ const searchResult = this._validateSearchInput(input, loose);
525
+ if ("issues" in searchResult) {
526
+ return {
527
+ issues: searchResult.issues ?? []
528
+ };
529
+ }
530
+ return {
531
+ value: {
532
+ ...searchResult.value,
533
+ ...paramsResult.value
534
+ }
496
535
  };
497
536
  }
498
- /** Throwing variant of `safeParseFlatInput()`. */
499
- parseFlatInput(input, loose) {
500
- loose ??= this.hasLooseSearch;
501
- const result = this.safeParseFlatInput(input, loose);
502
- if (result.error) {
503
- throw result.error;
537
+ _safeParseSchemaResult(result) {
538
+ if ("issues" in result) {
539
+ return {
540
+ success: false,
541
+ data: void 0,
542
+ error: new Error(result.issues?.[0]?.message ?? "Invalid input")
543
+ };
504
544
  }
505
- return result.data;
545
+ return {
546
+ success: true,
547
+ data: result.value,
548
+ error: void 0
549
+ };
506
550
  }
551
+ _parseSchemaResult(result) {
552
+ const safeResult = this._safeParseSchemaResult(result);
553
+ if (safeResult.error) {
554
+ throw safeResult.error;
555
+ }
556
+ return safeResult.data;
557
+ }
558
+ /** Standard Schema for route params input. */
559
+ paramsInputSchema = {
560
+ "~standard": {
561
+ version: 1,
562
+ vendor: "route0",
563
+ validate: (value) => this._validateParamsInput(value),
564
+ types: void 0
565
+ },
566
+ parse: (value) => this._parseSchemaResult(this._validateParamsInput(value)),
567
+ safeParse: (value) => this._safeParseSchemaResult(this._validateParamsInput(value))
568
+ };
569
+ /** Standard Schema for strict search input. */
570
+ strictSearchInputSchema = {
571
+ "~standard": {
572
+ version: 1,
573
+ vendor: "route0",
574
+ validate: (value) => this._validateSearchInput(value, false),
575
+ types: void 0
576
+ },
577
+ parse: (value) => this._parseSchemaResult(this._validateSearchInput(value, false)),
578
+ safeParse: (value) => this._safeParseSchemaResult(this._validateSearchInput(value, false))
579
+ };
580
+ /** Standard Schema for loose search input. */
581
+ looseSearchInputSchema = {
582
+ "~standard": {
583
+ version: 1,
584
+ vendor: "route0",
585
+ validate: (value) => this._validateSearchInput(value, true),
586
+ types: void 0
587
+ },
588
+ parse: (value) => this._parseSchemaResult(this._validateSearchInput(value, true)),
589
+ safeParse: (value) => this._safeParseSchemaResult(this._validateSearchInput(value, true))
590
+ };
591
+ /** Standard Schema for route flat input (uses route default strict/loose mode). */
592
+ flatInputSchema = {
593
+ "~standard": {
594
+ version: 1,
595
+ vendor: "route0",
596
+ validate: (value) => this._validateFlatInput(value, this.hasLooseSearch),
597
+ types: void 0
598
+ },
599
+ parse: (value) => this._parseSchemaResult(this._validateFlatInput(value, this.hasLooseSearch)),
600
+ safeParse: (value) => this._safeParseSchemaResult(this._validateFlatInput(value, this.hasLooseSearch))
601
+ };
507
602
  /** True when path structure is equal (param names are ignored). */
508
603
  isSame(other) {
509
604
  return this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "__PARAM__") === other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, "__PARAM__");
@@ -631,7 +726,7 @@ class Routes {
631
726
  this._ = {
632
727
  routes: this._routes,
633
728
  getLocation: this._getLocation.bind(this),
634
- override: this._override.bind(this),
729
+ clone: this._clone.bind(this),
635
730
  pathsOrdering: this._pathsOrdering,
636
731
  keysOrdering: this._keysOrdering,
637
732
  ordered: this._ordered
@@ -643,7 +738,7 @@ class Routes {
643
738
  if (!override) {
644
739
  return result;
645
740
  }
646
- return result._.override(override);
741
+ return result._.clone(override);
647
742
  }
648
743
  static prettify(instance) {
649
744
  Object.setPrototypeOf(instance, Routes.prototype);
@@ -651,7 +746,7 @@ class Routes {
651
746
  value: "Routes"
652
747
  });
653
748
  Object.assign(instance, {
654
- override: instance._override.bind(instance)
749
+ clone: instance._clone.bind(instance)
655
750
  });
656
751
  Object.assign(instance, instance._routes);
657
752
  return instance;
@@ -700,7 +795,7 @@ class Routes {
700
795
  return { pathsOrdering, keysOrdering };
701
796
  }
702
797
  /** Returns a cloned routes collection with config applied to each route. */
703
- _override(config) {
798
+ _clone(config) {
704
799
  const newRoutes = {};
705
800
  for (const key in this._routes) {
706
801
  if (Object.hasOwn(this._routes, key)) {