@akb2/react-router 0.0.0-stage → 1.1.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.
@@ -0,0 +1 @@
1
+ "use strict";var pt=Object.create;var k=Object.defineProperty;var ft=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var Rt=Object.getPrototypeOf,Ct=Object.prototype.hasOwnProperty;var ht=(t,o)=>{for(var e in o)k(t,e,{get:o[e],enumerable:!0})},z=(t,o,e,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of dt(o))!Ct.call(t,a)&&a!==e&&k(t,a,{get:()=>o[a],enumerable:!(r=ft(o,a))||r.enumerable});return t};var gt=(t,o,e)=>(e=t!=null?pt(Rt(t)):{},z(o||!t||!t.__esModule?k(e,"default",{value:t,enumerable:!0}):e,t)),bt=t=>z(k({},"__esModule",{value:!0}),t);var Et={};ht(Et,{componentsContextFabric:()=>$,reactRouterFabric:()=>et,routerContextFabric:()=>mt});module.exports=bt(Et);var h=gt(require("react"),1);var B="@akb2/react/";var H=Symbol.for(B+"components-context");var V=require("react"),D=(t,o=null)=>{let e=globalThis;return t in e||(e[t]=(0,V.createContext)(o)),e[t]};var Z=require("react"),tt=require("react/jsx-runtime"),$=()=>{let t=D(H);return{ComponentsContext:t,ComponentsProvider:({components:r,children:a})=>(0,tt.jsx)(t.Provider,{value:r,children:a}),useComponents:()=>{let r=(0,Z.useContext)(t);if(!r)throw new Error("useComponents must be used inside ComponentsProvider");return r}}};var N=require("@akb2/types-tools");var W=require("@akb2/types-tools"),ot=t=>{let o=(0,W.isDefined)(t.children)?{...t.children}:void 0;return(0,W.isDefined)(o)?{...t,children:o}:{...t}};function et(...t){let o=Array.isArray(t[0])?t[0]:t,e={},r=[],a=100;for(let d of o)for(let s in d){let l=d[s];if(!(0,N.isDefined)(l.putInKey)&&(0,N.isDefined)(e[s]))throw new Error(`Duplicate route key "${s}" found in module options.`);(0,N.isDefined)(l.putInKey)?r.push([s,l]):e[s]=l}for(;r.length>0&&a-- >0;){let d=r.findIndex(([,{putInKey:i}])=>(0,N.isDefined)(i)&&(0,N.isDefined)(e[i]));if(d===-1)throw new Error('Circular dependency detected in route configurations. Please check the "putInKey" properties.');let[s,l]=r[d],{putInKey:m,...P}=l;if(!(0,N.isDefined)(m))throw new Error('Invalid route configuration. "putInKey" is not defined.');let x=e[m],w=(0,N.isDefined)(x.children)?{...x.children}:{};if((0,N.isDefined)(w[s]))throw new Error(`Duplicate route key "${s}" found in module options.`);w[s]=ot(P),e[m]={...x,children:w},r.splice(d,1)}return e}var u=require("@akb2/types-tools");var rt=Symbol.for(B+"router-context");var nt=(t,o,e)=>{let r={...e},a=t.split("/"),d=o.split("/");if(a.length!==d.length)return!1;for(let s=0;s<a.length;s++)if(d[s].startsWith(":")){r[d[s].slice(1)]=a[s];continue}else if(a[s]!==d[s])return!1;return Object.assign(e,r),!0};var K=require("@akb2/types-tools");var S=(t,o,e=!1)=>{let a=(0,K.anyToArray)(t).reduce((s,l)=>{let m=l.split("/");for(let P of m)s.push(P.startsWith(":")&&!e?(0,K.anyToString)(o?.[P.slice(1)],"*"):P);return s},[]);return("/"+(0,K.smartJoin)("/",...a)).replace(/[\/\\]+/gim,"/")};var Q=t=>Array.isArray(t)?t:t.split(".");var X=require("@akb2/types-tools"),A=t=>Object.entries(t??{}).filter(([,o])=>(0,X.isDefined)(o)).reduce((o,[e,r])=>o+`${o?"&":"?"}${encodeURIComponent(e)}=${encodeURIComponent((0,X.anyToString)(r))}`,"");var st=(t,o,e,r,a=!1)=>{let d=Q(o),s=[],l=t;for(let m of d){if(!l.hasOwnProperty(m))break;l=l[m],s.push(l?.path??l?.paths[0]),l=l.children}return S(s,e,a)+A(r)};var it=(t,o,e,r,a=!1)=>{let d=A(r),s=Q(o),l=[],m=t;for(let x of s){if(!m.hasOwnProperty(x))break;m=m[x];let w=Array.isArray(m?.paths)?m.paths:[m?.path];l.push(w.filter(i=>typeof i=="string")),m=m.children}return l.length===0?[S([])]:l.reduce((x,w)=>x.flatMap(i=>w.map(R=>[...i,R])),[[]]).map(x=>S(x,e,a)+d)};var at=t=>Array.from(t).reduce((o,[e,r])=>(o[e]=r,o),{});var ut=require("@akb2/types-tools"),ct=t=>{if(!t)return{};let o=(0,ut.anyToArray)(t.split("&")),e={};for(let r of o){let[a,d]=r.split("=");a&&(e[a]=d??"")}return e};var j=require("react"),F=require("wouter");var U=require("react/jsx-runtime"),mt=t=>{let o=(i,R)=>{let g=i.split("/").filter(Boolean),p=R.split("/").filter(Boolean);for(let c=0;c<g.length;c++){let f=g[c].startsWith(":"),n=p[c].startsWith(":");if(f!==n)return f?1:-1}return 0},e=(i,R=[""],g=new Set)=>{if(R.length===0)throw new Error("Parent paths cannot be empty.");let p=g.size===0,c=!1;for(let f in i){let n=i[f];if([(0,u.isDefined)(n.Module),(0,u.isDefined)(n.Template),(0,u.isDefined)(n.redirectUrl)].filter(Boolean).length!==1)throw new Error(`Route with key "${f}" must have exactly one of Module, Template, or redirectUrl defined.`);if([(0,u.isDefined)(n.path),(0,u.isDefined)(n.paths),n.isNotFound===!0].filter(Boolean).length!==1)throw new Error(`Route with key "${f}" must have exactly one of path, paths, or isNotFound defined.`);if(n.isNotFound===!0)if(p){if(c)throw new Error("Only one not found route can be defined at the top level.");if((0,u.isDefined)(n.children))throw new Error("Not found route cannot have children.");c=!0;continue}else throw new Error("Not found route can only be defined at the top level.");let y=(0,u.isDefined)(n.path)?[n.path]:(0,u.isDefined)(n.paths)?n.paths:[];if(y.length===0)throw new Error(`Route with key "${f}" must have at least one path defined.`);let b=R.flatMap(E=>y.map(v=>S([E,v])));for(let E of b){if(g.has(E))throw new Error(`Duplicate route detected for URL: "${E}"`);g.add(E)}(0,u.isDefined)(n.children)&&e(n.children,b,g)}if(p&&!c)throw new Error("A not found route must be defined at the top level.")};e(t);let r=D(rt),a=()=>{let{activatedRoute:{Module:i,Template:R,redirectUrl:g,SuspenseTemplate:p,props:c}}=P(),{useComponents:f}=$(),{FullPageLoader:n}=f(),T=(0,u.isDefined)(i)?i:(0,u.isDefined)(R)?R:()=>(0,U.jsx)(F.Redirect,{to:g}),C=p?(0,U.jsx)(p,{}):(0,U.jsx)(n,{});return(0,U.jsx)(r.Provider,{value:t,children:(0,U.jsx)(j.Suspense,{fallback:C,children:(0,U.jsx)(T,{...c})})})},d=st.bind(null,t),s=it.bind(null,t),l=i=>(0,F.useRoute)(d(i,null,{},!0)),m=()=>{let[i,R]=(0,F.useLocation)();return[i,(p,c,f,n)=>{let T=s(p,c,f,!0),C=T.find(q=>{let L=q.split("/").filter(Boolean);return Object.keys(c??{}).every(_=>L.includes(":"+_))})??T[0],[y,b]=S(C,c,!1).split("?"),E=ct(b),v=y+A({...E,...f});return R(v,n)}]},P=()=>{let[i]=m(),[R]=(0,F.useSearchParams)(),g=(0,j.useMemo)(()=>{let p=i.split("/").filter(Boolean);return p.length>0?p:[""]},[i]);return(0,j.useMemo)(()=>{let p=[],c=[],f={},n=at(R.entries()),T=null,C=null,y=t,b="",E=0;for(let v of g){let q=b?b+"/"+v:v,L=new Map;for(let _ in y){let O=y[_];if(O.isNotFound===!0){if(E>0)throw new Error("Not found route must be defined at the root level");T=O;continue}((0,u.isDefined)(O.path)?[O.path]:(0,u.isDefined)(O.paths)?(0,u.anyToArray)(O.paths):[]).forEach((M,G)=>{let I={};nt(q,M,I)&&L.set((0,u.smartJoin)("/",_,(0,u.anyToString)(G)),{path:M,config:O,pathParams:I})})}if(L.size>0){let O=Array.from(L.entries()).reduce((I,J)=>o(J[1].path,I[1].path)<0?J:I),[Y,{config:M,pathParams:G}]=O;(0,u.isDefined)(C)&&c.push(C),b="",C=M,y=C.children??{},Object.assign(f,G),p.push(Y.split("/")[0]),E++}else b=b?b+"/"+v:v}return(b||!(0,u.isDefined)(C))&&(C=T),{activatedRoute:C,routeKey:p,parents:c,pathParams:f,queryParams:n,routeKeyString:p.join("."),routeUrlMask:b}},[g,R])};return{RouterContext:r,RouterProvider:a,createUrlFromRouteConfig:d,createUrlsFromRouteConfig:s,useLocation:m,useActivatedRoute:P,useRoute:l,useRoutePathState:(i,R)=>{let[,g]=m(),{routeKey:p,pathParams:c,queryParams:f}=P(),n=c[i],T=(0,j.useCallback)(C=>{n!==C&&g(p,{...c,[i]:C},f,{replace:!0})},[n,p,c,f]);return[n??R,T]},useRouteQueryState:(i,R)=>{let[,g]=m(),{routeKey:p,pathParams:c,queryParams:f}=P(),n=f[i]??R,T=(0,j.useCallback)(C=>{if(n!==C){let y={...f};(0,u.isDefined)(C)&&C!==R&&(0,u.anyToString)(C).length>0?y[i]=(0,u.anyToString)(C):delete y[i],g(p,c,y,{replace:!0})}},[n,p,c,f,R]);return[n??R,T]}}};0&&(module.exports={componentsContextFabric,reactRouterFabric,routerContextFabric});
@@ -0,0 +1,293 @@
1
+ import { Nullable, CustomObject, Undefinable } from '@akb2/types-tools';
2
+ import { ReactNode, FC, PropsWithChildren, Context, MemoExoticComponent, LazyExoticComponent } from 'react';
3
+ import { Match } from 'wouter';
4
+
5
+ type AnyComponent = (props: any) => ReactNode;
6
+
7
+ type ReactComponents<Props extends object = Record<string, object>> = {
8
+ [K in keyof Props]: Props[K] extends AnyComponent ? Props[K] : FC<Props[K]>;
9
+ };
10
+
11
+ interface RouterComponents {
12
+ FullPageLoader: {};
13
+ }
14
+
15
+ interface ComponentsProviderProps<TComponents extends ReactComponents<RouterComponents> = ReactComponents<RouterComponents>> extends PropsWithChildren {
16
+ components: TComponents;
17
+ }
18
+
19
+ interface CreateComponentsContext<TComponents extends ReactComponents<RouterComponents> = ReactComponents<RouterComponents>> {
20
+ ComponentsContext: Context<Nullable<TComponents>>;
21
+ ComponentsProvider: FC<ComponentsProviderProps<TComponents>>;
22
+ useComponents: () => TComponents;
23
+ }
24
+
25
+ declare const componentsContextFabric: <TComponents extends ReactComponents<RouterComponents>>() => CreateComponentsContext<TComponents>;
26
+
27
+ declare const TREE_CHILD_KEY: "children";
28
+
29
+ type TreeChildKey = typeof TREE_CHILD_KEY;
30
+
31
+ interface RouteConfigInputExtension {
32
+ }
33
+ type RouteConfigInput = {
34
+ SuspenseTemplate?: unknown;
35
+ props?: unknown;
36
+ putInKey?: unknown;
37
+ isNotFound?: unknown;
38
+ path?: unknown;
39
+ paths?: unknown;
40
+ Module?: unknown;
41
+ Template?: unknown;
42
+ redirectUrl?: unknown;
43
+ } & {
44
+ [K in TreeChildKey]?: Record<string, RouteConfigInput>;
45
+ } & RouteConfigInputExtension;
46
+ /**
47
+ * General types
48
+ */
49
+ type RoutesConfig<T extends Record<string, RouteConfigInput> = Record<string, RouteConfigInput>> = T;
50
+ type RoutesConfigKey<TConfig extends RoutesConfig> = Extract<keyof TConfig, string>;
51
+
52
+ type CanBeMemoExoticComponent<C extends JSX.Element | string | number> = MemoExoticComponent<() => C> | (() => C);
53
+
54
+ type RoutesDefinition<T extends Record<string, RouteDefinition<object, string>> = Record<string, RouteDefinition<{}, string>>> = T;
55
+
56
+ /**
57
+ * Config interface
58
+ */
59
+ interface RouteConfigAndDefinitionBase<Props extends object = {}> {
60
+ SuspenseTemplate?: CanBeMemoExoticComponent<JSX.Element | string | number>;
61
+ props?: Props;
62
+ putInKey?: string;
63
+ }
64
+ /**
65
+ * Children interface
66
+ */
67
+ interface RouteDefinitionBase<TRouteChildren extends Record<string, RouteDefinition> = Record<string, RouteDefinition>, Props extends object = {}> extends RouteConfigAndDefinitionBase<Props> {
68
+ [TREE_CHILD_KEY]?: RoutesDefinition<TRouteChildren>;
69
+ }
70
+ /**
71
+ * For extension
72
+ */
73
+ interface RouteDefinitionExtension {
74
+ }
75
+ /**
76
+ * Base type
77
+ */
78
+ type RouteDefinition<Props extends object = {}, Keys extends string = string> = RouteRenderConfig<Props> & RouteDefinitionBase<Record<Keys, RouteDefinition>, Props> & RouteDefinitionExtension;
79
+
80
+ /**
81
+ * Base models
82
+ */
83
+ interface RouteConfigBase<TRouteChildren extends Record<string, RouteConfig> = Record<string, RouteConfig>, Props extends object = {}> extends RouteConfigAndDefinitionBase<Props> {
84
+ [TREE_CHILD_KEY]?: RoutesConfig<TRouteChildren>;
85
+ }
86
+ /**
87
+ * Path interfaces
88
+ */
89
+ interface RouteConfigNotFoundPath {
90
+ isNotFound: true;
91
+ path?: never;
92
+ paths?: never;
93
+ }
94
+ interface RouteConfigOnePath {
95
+ isNotFound?: never;
96
+ path: string;
97
+ paths?: never;
98
+ }
99
+ interface RouteConfigManyPath {
100
+ isNotFound?: never;
101
+ path?: never;
102
+ paths: string[];
103
+ }
104
+ type RouteConfigPath = RouteConfigNotFoundPath | RouteConfigOnePath | RouteConfigManyPath;
105
+ /**
106
+ * Render interfaces
107
+ */
108
+ interface RouteConfigModule<Props extends object = {}> {
109
+ Module: LazyExoticComponent<((props?: Props) => JSX.Element) | FC<Props>>;
110
+ Template?: never;
111
+ redirectUrl?: never;
112
+ }
113
+ interface RouteConfigTemplate<Props extends object = {}> {
114
+ Module?: never;
115
+ Template: (props: Props) => JSX.Element | string | number;
116
+ redirectUrl?: never;
117
+ }
118
+ interface RouteConfigRedirect {
119
+ Module?: never;
120
+ Template?: never;
121
+ redirectUrl: string;
122
+ }
123
+ type RouteRenderConfig<Props extends object = {}> = RouteConfigModule<Props> | RouteConfigTemplate<Props> | RouteConfigRedirect;
124
+ /**
125
+ * Extensions
126
+ */
127
+ interface RouteConfigExtension {
128
+ }
129
+ /**
130
+ * General model
131
+ */
132
+ type RouteConfig<Props extends object = {}, Keys extends string = string> = RouteConfigPath & RouteRenderConfig & RouteConfigBase<Record<Keys, RouteConfig<Props>>, Props> & RouteConfigExtension;
133
+ type RouteConfigChildren<TConfig extends RouteConfigInput> = TreeChildKey extends keyof TConfig ? TConfig[TreeChildKey] extends RoutesConfig<infer TChildren extends Record<string, RouteConfigInput>> ? TChildren : {} : {};
134
+
135
+ type RouteConfigTypeError<TMessage extends string> = {
136
+ readonly __routeConfigTypeError__: TMessage;
137
+ };
138
+ type RouteConfigMapTypeErrorsDeep<TConfig> = {
139
+ [K in keyof TConfig]: TConfig[K] extends RouteConfigTypeError<string> ? TConfig[K] : TConfig[K] extends RouteConfigInput ? RouteConfigMapTypeErrorsDeep<RouteConfigChildren<TConfig[K]>> : never;
140
+ }[keyof TConfig];
141
+ /**
142
+ * Errors
143
+ */
144
+ type DuplicateRootRouteKeyError<TKey extends string> = RouteConfigTypeError<`Duplicate root route key: ${TKey}`>;
145
+ type MissingPutInKeyError<TKey extends string> = RouteConfigTypeError<`putInKey target not found: ${TKey}`>;
146
+ type DuplicatePutInRouteKeyError<TParent extends string, TKey extends string> = RouteConfigTypeError<`Duplicate child route key: ${TKey} for putInKey: ${TParent}`>;
147
+
148
+ type NormalizeMergedRoutesConfig<TConfig> = {
149
+ [K in Extract<keyof TConfig, string>]: Extract<TConfig[K], RouteConfigInput>;
150
+ };
151
+ type NormalizeResolvedRoutesConfig<TConfig extends Record<string, RouteConfigInput | RouteConfigTypeError<string>>> = {
152
+ [K in keyof TConfig as TConfig[K] extends RouteConfigTypeError<string> ? never : K]: Extract<TConfig[K], RouteConfigInput>;
153
+ };
154
+ type NormalizeRoutesConfig<TConfig extends Record<string, RouteConfigInput>> = {
155
+ [K in keyof TConfig]: TConfig[K];
156
+ };
157
+
158
+ type RouteOwnKeys = Exclude<keyof RouteConfigInput, TreeChildKey>;
159
+ type HasOwnRouteConfig<T> = Extract<keyof T, RouteOwnKeys> extends never ? false : true;
160
+ type MergeRouteNodeSafe<TLeft extends RouteConfigInput, TRight extends RouteConfigInput> = Omit<TLeft & TRight, TreeChildKey> & {
161
+ [K in TreeChildKey]: MergeRoutesConfigsDeep<RouteConfigChildren<TLeft>, RouteConfigChildren<TRight>>;
162
+ };
163
+ type RootRouteKeys<TConfig extends RoutesConfig> = Exclude<RoutesConfigKey<TConfig>, DeferredRouteKeys<TConfig>>;
164
+ type RootRoutesConfigPart<TConfig extends RoutesConfig> = {
165
+ [K in RootRouteKeys<TConfig>]: TConfig[K];
166
+ };
167
+ type MergeRouteNode<TLeft extends RouteConfigInput, TRight extends RouteConfigInput, TKey extends string> = HasOwnRouteConfig<TLeft> extends true ? HasOwnRouteConfig<TRight> extends true ? DuplicateRootRouteKeyError<TKey> : MergeRouteNodeSafe<TLeft, TRight> : MergeRouteNodeSafe<TLeft, TRight>;
168
+ type MergeRoutesConfigsDeep<TLeft extends Record<string, RouteConfigInput>, TRight extends Record<string, RouteConfigInput>> = {
169
+ [K in keyof TLeft | keyof TRight]: K extends keyof TLeft ? K extends keyof TRight ? K extends string ? MergeRouteNode<Extract<TLeft[K], RouteConfigInput>, Extract<TRight[K], RouteConfigInput>, K> : never : TLeft[K] : K extends keyof TRight ? TRight[K] : never;
170
+ };
171
+ type MergeRouteChildren<TRouteConfig extends RouteConfigInput, TDeferredChildren extends Record<string, RouteConfigInput>, TParent extends string> = Extract<Extract<keyof RouteConfigChildren<TRouteConfig>, keyof TDeferredChildren>, string> extends infer TDuplicateKey extends string ? [TDuplicateKey] extends [never] ? Omit<TRouteConfig, TreeChildKey> & {
172
+ [K in TreeChildKey]: RoutesConfig<NormalizeRoutesConfig<RouteConfigChildren<TRouteConfig> & TDeferredChildren>>;
173
+ } : DuplicatePutInRouteKeyError<TParent, TDuplicateKey> : never;
174
+ type MergeRootRoutesConfigs<TConfigs extends readonly RoutesConfig[], TResult extends Record<string, RouteConfigInput> = {}> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? MergeRoutesConfigsDeep<TResult, RootRoutesConfigPart<THead>> extends infer TMerged ? RouteConfigMapTypeErrorsDeep<TMerged> extends infer TError extends RouteConfigTypeError<string> ? [TError] extends [never] ? MergeRootRoutesConfigs<TTail, NormalizeMergedRoutesConfig<TMerged>> : TError : never : never : TResult;
175
+
176
+ type RemoveIndexSignature<T> = {
177
+ [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
178
+ };
179
+
180
+ type ChildKeys<T> = [keyof RemoveIndexSignature<T>] extends [never] ? Extract<keyof T, string | number | symbol> : Extract<keyof RemoveIndexSignature<T>, string | number | symbol>;
181
+
182
+ type ObjectChain<T> = T extends Record<any, any> ? {
183
+ [K in ChildKeys<T>]: [K] | (TreeChildKey extends keyof T[K] ? T[K][TreeChildKey] extends Record<PropertyKey, unknown> ? [K, ...ObjectChain<T[K][TreeChildKey]>] : [K] : [K]);
184
+ }[ChildKeys<T>] : never;
185
+
186
+ type RouteTreeNode = object & {
187
+ [K in TreeChildKey]?: RouteTree;
188
+ };
189
+ interface RouteTree {
190
+ [key: string]: RouteTreeNode;
191
+ }
192
+ type RouteTreeChildren<TRoute> = TRoute extends {
193
+ [K in TreeChildKey]?: infer TChildren extends RouteTree;
194
+ } ? TChildren : never;
195
+
196
+ type RoutesPathKeysMaxDepth = [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown];
197
+ type JoinRouteKey<TPrefix extends string, TKey extends string> = TPrefix extends '' ? TKey : `${TPrefix}.${TKey}`;
198
+ type RouteKey<T> = Extract<keyof T, string>;
199
+ type RoutesKeys<Routes extends RoutesConfig> = ObjectChain<Routes> | RoutesPathKeys<Routes>;
200
+ type RoutesPathKeys<TRoutes extends RouteTree, TPrefix extends string = '', TDepth extends unknown[] = []> = TDepth extends RoutesPathKeysMaxDepth ? never : {
201
+ [K in RouteKey<TRoutes>]: JoinRouteKey<TPrefix, K> | (RouteTreeChildren<TRoutes[K]> extends infer TChildren extends RouteTree ? RoutesPathKeys<TChildren, JoinRouteKey<TPrefix, K>, [...TDepth, unknown]> : never);
202
+ }[RouteKey<TRoutes>];
203
+
204
+ type ExplicitChildrenRouteKeys<TRootConfig extends Record<string, RouteConfigInput>> = {
205
+ [K in Extract<keyof TRootConfig, string>]: TreeChildKey extends keyof TRootConfig[K] ? K : never;
206
+ }[Extract<keyof TRootConfig, string>];
207
+ type NormalizePutInKey<TPutInKey, TKnownParents extends string> = TPutInKey extends string ? string extends TPutInKey ? [TKnownParents] extends [never] ? TPutInKey : TKnownParents : TPutInKey : never;
208
+ type RouteConfigPutInKey<TConfig extends RouteConfigInput> = TConfig extends {
209
+ putInKey: infer TPutInKey extends string;
210
+ } ? TPutInKey : never;
211
+ type PutInKeyFallbackParents<TRootConfig extends Record<string, RouteConfigInput>> = [
212
+ ExplicitChildrenRouteKeys<TRootConfig>
213
+ ] extends [never] ? Extract<keyof TRootConfig, string> : ExplicitChildrenRouteKeys<TRootConfig>;
214
+
215
+ type MergeDeferredRoutesForParent<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>, TParent extends string, TResult extends Record<string, RouteConfigInput> = {}> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? DeferredRoutesForParentInConfig<THead, TParent, PutInKeyFallbackParents<TRootConfig>> extends infer TDeferredRoutes extends Record<string, RouteConfigInput> ? Extract<Extract<keyof TResult, keyof TDeferredRoutes>, string> extends infer TDuplicateKey extends string ? [TDuplicateKey] extends [never] ? MergeDeferredRoutesForParent<TTail, TRootConfig, TParent, TResult & TDeferredRoutes> : DuplicatePutInRouteKeyError<TParent, TDuplicateKey> : never : never : TResult;
216
+ type ApplyDeferredRouteForKey<TRootConfig extends Record<string, RouteConfigInput>, TConfigs extends readonly RoutesConfig[], TKey extends Extract<keyof TRootConfig, string>> = MergeDeferredRoutesForParent<TConfigs, TRootConfig, TKey> extends infer TDeferredChildren ? TDeferredChildren extends RouteConfigTypeError<string> ? TDeferredChildren : TDeferredChildren extends Record<string, RouteConfigInput> ? keyof TDeferredChildren extends never ? TRootConfig[TKey] : MergeRouteChildren<TRootConfig[TKey], TDeferredChildren, TKey> : never : never;
217
+ type RouteConfigWithoutPutInKey<TConfig extends RouteConfigInput> = Omit<TConfig, 'putInKey'>;
218
+ type DeferredRoutesForParentInConfig<TConfig extends RoutesConfig, TParent extends string, TKnownParents extends string = TParent> = {
219
+ [K in DeferredRouteKeys<TConfig> as Extract<NormalizePutInKey<RouteConfigPutInKey<TConfig[K]>, TKnownParents>, TParent> extends never ? never : K]: RouteConfigWithoutPutInKey<TConfig[K]>;
220
+ };
221
+ type DeferredRouteKeys<TConfig extends RoutesConfig> = {
222
+ [K in RoutesConfigKey<TConfig>]: TConfig[K] extends {
223
+ putInKey: string;
224
+ } ? K : never;
225
+ }[RoutesConfigKey<TConfig>];
226
+ type DeferredRouteParents<TConfig extends RoutesConfig, TKnownParents extends string> = {
227
+ [K in DeferredRouteKeys<TConfig>]: NormalizePutInKey<RouteConfigPutInKey<TConfig[K]>, TKnownParents>;
228
+ }[DeferredRouteKeys<TConfig>];
229
+ type ApplyDeferredRoutes<TRootConfig extends Record<string, RouteConfigInput>, TConfigs extends readonly RoutesConfig[]> = {
230
+ [K in Extract<keyof TRootConfig, string>]: ApplyDeferredRouteForKey<TRootConfig, TConfigs, K>;
231
+ };
232
+ type ResolveAppliedDeferredRoutes<TAppliedRoutes extends Record<string, RouteConfigInput | RouteConfigTypeError<string>>> = RouteConfigMapTypeErrorsDeep<TAppliedRoutes> extends infer TError extends RouteConfigTypeError<string> ? [TError] extends [never] ? RoutesConfig<NormalizeRoutesConfig<NormalizeResolvedRoutesConfig<TAppliedRoutes>>> : TError : never;
233
+
234
+ type MissingPutInKeys<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? Exclude<DeferredRouteParents<THead, PutInKeyFallbackParents<TRootConfig>>, Extract<keyof TRootConfig, string>> | MissingPutInKeys<TTail, TRootConfig> : never;
235
+ type ValidatePutInKeys<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>> = MissingPutInKeys<TConfigs, TRootConfig> extends infer TMissingKey extends string ? [TMissingKey] extends [never] ? TRootConfig : MissingPutInKeyError<TMissingKey> : never;
236
+
237
+ /**
238
+ * General type
239
+ */
240
+ type UnionRoutesConfig<TRoutes extends readonly RoutesConfig[] = readonly RoutesConfig[]> = number extends TRoutes['length'] ? RoutesConfig : MergeRootRoutesConfigs<TRoutes> extends infer TRootRoutes ? TRootRoutes extends RouteConfigTypeError<string> ? TRootRoutes : TRootRoutes extends Record<string, RouteConfigInput> ? ValidatePutInKeys<TRoutes, TRootRoutes> extends infer TValidatedRoutes ? TValidatedRoutes extends RouteConfigTypeError<string> ? TValidatedRoutes : TValidatedRoutes extends Record<string, RouteConfigInput> ? ApplyDeferredRoutes<TValidatedRoutes, TRoutes> extends infer TAppliedRoutes extends Record<string, RouteConfigInput | RouteConfigTypeError<string>> ? ResolveAppliedDeferredRoutes<TAppliedRoutes> : never : never : never : never : never;
241
+
242
+ declare function reactRouterFabric<const TRoutes extends readonly RoutesConfig[]>(...mixedRoutesConfigs: TRoutes): UnionRoutesConfig<TRoutes>;
243
+ declare function reactRouterFabric<const TRoutes extends readonly RoutesConfig[]>(mixedRoutesConfigs: TRoutes[]): UnionRoutesConfig<TRoutes>;
244
+
245
+ type CreateUrlFromRouteConfig<Routes extends RoutesConfig> = (mixedPath: RoutesKeys<Routes>, pathParams?: Nullable<CustomObject<string | number | boolean>>, queryParams?: CustomObject<Nullable<string | number | boolean>>, safePathParams?: boolean) => string;
246
+
247
+ type CreateUrlsFromRouteConfig<Routes extends RoutesConfig> = (mixedPath: RoutesKeys<Routes>, pathParams?: Nullable<CustomObject<string | number | boolean>>, queryParams?: CustomObject<Nullable<string | number | boolean>>, safePathParams?: boolean) => string[];
248
+
249
+ type RouterProviderProps = PropsWithChildren;
250
+
251
+ interface UseActivatedRouteType<Routes extends RoutesConfig> {
252
+ activatedRoute: RouteConfig;
253
+ pathParams: Record<string, string>;
254
+ queryParams: Record<string, string>;
255
+ routeKey: ObjectChain<Routes>;
256
+ routeKeyString: RoutesPathKeys<Routes>;
257
+ routeUrlMask: string;
258
+ parents: RouteConfig[];
259
+ }
260
+
261
+ interface SetLocationOptions<S = unknown> {
262
+ replace?: boolean;
263
+ state?: S;
264
+ transition?: boolean;
265
+ }
266
+ type UseLocationType<Routes extends RoutesConfig, S = unknown> = [
267
+ string,
268
+ (key: ObjectChain<Routes> | RoutesPathKeys<Routes>, pathParams?: Nullable<Record<string | number | symbol, string | number | boolean>>, queryParams?: Record<string | number | symbol, Nullable<string | number | boolean>>, options?: SetLocationOptions<S>) => void
269
+ ];
270
+ /**
271
+ * General hook type
272
+ */
273
+ type UseLocation<Routes extends RoutesConfig> = <S = unknown>() => UseLocationType<Routes, S>;
274
+
275
+ type UseRoute<Routes extends RoutesConfig> = (key: ObjectChain<Routes> | RoutesPathKeys<Routes>) => Match<Record<string | number, Undefinable<string>>>;
276
+
277
+ type UseRouteState = <T extends string | number>(key: string, fallback: T) => [T, (value: T) => void];
278
+
279
+ interface CreateRouterContext<Routes extends RoutesConfig = RoutesConfig> {
280
+ RouterContext: Context<Nullable<Routes>>;
281
+ RouterProvider: FC<RouterProviderProps>;
282
+ createUrlFromRouteConfig: CreateUrlFromRouteConfig<Routes>;
283
+ createUrlsFromRouteConfig: CreateUrlsFromRouteConfig<Routes>;
284
+ useLocation: UseLocation<Routes>;
285
+ useActivatedRoute: () => UseActivatedRouteType<Routes>;
286
+ useRoute: UseRoute<Routes>;
287
+ useRoutePathState: UseRouteState;
288
+ useRouteQueryState: UseRouteState;
289
+ }
290
+
291
+ declare const routerContextFabric: <Routes extends RoutesConfig = RoutesConfig>(routes: Routes) => CreateRouterContext<Routes>;
292
+
293
+ export { type ReactComponents, type RouterComponents, type RoutesDefinition, type RoutesKeys, type RoutesPathKeys, componentsContextFabric, reactRouterFabric, routerContextFabric };
@@ -0,0 +1,293 @@
1
+ import { Nullable, CustomObject, Undefinable } from '@akb2/types-tools';
2
+ import { ReactNode, FC, PropsWithChildren, Context, MemoExoticComponent, LazyExoticComponent } from 'react';
3
+ import { Match } from 'wouter';
4
+
5
+ type AnyComponent = (props: any) => ReactNode;
6
+
7
+ type ReactComponents<Props extends object = Record<string, object>> = {
8
+ [K in keyof Props]: Props[K] extends AnyComponent ? Props[K] : FC<Props[K]>;
9
+ };
10
+
11
+ interface RouterComponents {
12
+ FullPageLoader: {};
13
+ }
14
+
15
+ interface ComponentsProviderProps<TComponents extends ReactComponents<RouterComponents> = ReactComponents<RouterComponents>> extends PropsWithChildren {
16
+ components: TComponents;
17
+ }
18
+
19
+ interface CreateComponentsContext<TComponents extends ReactComponents<RouterComponents> = ReactComponents<RouterComponents>> {
20
+ ComponentsContext: Context<Nullable<TComponents>>;
21
+ ComponentsProvider: FC<ComponentsProviderProps<TComponents>>;
22
+ useComponents: () => TComponents;
23
+ }
24
+
25
+ declare const componentsContextFabric: <TComponents extends ReactComponents<RouterComponents>>() => CreateComponentsContext<TComponents>;
26
+
27
+ declare const TREE_CHILD_KEY: "children";
28
+
29
+ type TreeChildKey = typeof TREE_CHILD_KEY;
30
+
31
+ interface RouteConfigInputExtension {
32
+ }
33
+ type RouteConfigInput = {
34
+ SuspenseTemplate?: unknown;
35
+ props?: unknown;
36
+ putInKey?: unknown;
37
+ isNotFound?: unknown;
38
+ path?: unknown;
39
+ paths?: unknown;
40
+ Module?: unknown;
41
+ Template?: unknown;
42
+ redirectUrl?: unknown;
43
+ } & {
44
+ [K in TreeChildKey]?: Record<string, RouteConfigInput>;
45
+ } & RouteConfigInputExtension;
46
+ /**
47
+ * General types
48
+ */
49
+ type RoutesConfig<T extends Record<string, RouteConfigInput> = Record<string, RouteConfigInput>> = T;
50
+ type RoutesConfigKey<TConfig extends RoutesConfig> = Extract<keyof TConfig, string>;
51
+
52
+ type CanBeMemoExoticComponent<C extends JSX.Element | string | number> = MemoExoticComponent<() => C> | (() => C);
53
+
54
+ type RoutesDefinition<T extends Record<string, RouteDefinition<object, string>> = Record<string, RouteDefinition<{}, string>>> = T;
55
+
56
+ /**
57
+ * Config interface
58
+ */
59
+ interface RouteConfigAndDefinitionBase<Props extends object = {}> {
60
+ SuspenseTemplate?: CanBeMemoExoticComponent<JSX.Element | string | number>;
61
+ props?: Props;
62
+ putInKey?: string;
63
+ }
64
+ /**
65
+ * Children interface
66
+ */
67
+ interface RouteDefinitionBase<TRouteChildren extends Record<string, RouteDefinition> = Record<string, RouteDefinition>, Props extends object = {}> extends RouteConfigAndDefinitionBase<Props> {
68
+ [TREE_CHILD_KEY]?: RoutesDefinition<TRouteChildren>;
69
+ }
70
+ /**
71
+ * For extension
72
+ */
73
+ interface RouteDefinitionExtension {
74
+ }
75
+ /**
76
+ * Base type
77
+ */
78
+ type RouteDefinition<Props extends object = {}, Keys extends string = string> = RouteRenderConfig<Props> & RouteDefinitionBase<Record<Keys, RouteDefinition>, Props> & RouteDefinitionExtension;
79
+
80
+ /**
81
+ * Base models
82
+ */
83
+ interface RouteConfigBase<TRouteChildren extends Record<string, RouteConfig> = Record<string, RouteConfig>, Props extends object = {}> extends RouteConfigAndDefinitionBase<Props> {
84
+ [TREE_CHILD_KEY]?: RoutesConfig<TRouteChildren>;
85
+ }
86
+ /**
87
+ * Path interfaces
88
+ */
89
+ interface RouteConfigNotFoundPath {
90
+ isNotFound: true;
91
+ path?: never;
92
+ paths?: never;
93
+ }
94
+ interface RouteConfigOnePath {
95
+ isNotFound?: never;
96
+ path: string;
97
+ paths?: never;
98
+ }
99
+ interface RouteConfigManyPath {
100
+ isNotFound?: never;
101
+ path?: never;
102
+ paths: string[];
103
+ }
104
+ type RouteConfigPath = RouteConfigNotFoundPath | RouteConfigOnePath | RouteConfigManyPath;
105
+ /**
106
+ * Render interfaces
107
+ */
108
+ interface RouteConfigModule<Props extends object = {}> {
109
+ Module: LazyExoticComponent<((props?: Props) => JSX.Element) | FC<Props>>;
110
+ Template?: never;
111
+ redirectUrl?: never;
112
+ }
113
+ interface RouteConfigTemplate<Props extends object = {}> {
114
+ Module?: never;
115
+ Template: (props: Props) => JSX.Element | string | number;
116
+ redirectUrl?: never;
117
+ }
118
+ interface RouteConfigRedirect {
119
+ Module?: never;
120
+ Template?: never;
121
+ redirectUrl: string;
122
+ }
123
+ type RouteRenderConfig<Props extends object = {}> = RouteConfigModule<Props> | RouteConfigTemplate<Props> | RouteConfigRedirect;
124
+ /**
125
+ * Extensions
126
+ */
127
+ interface RouteConfigExtension {
128
+ }
129
+ /**
130
+ * General model
131
+ */
132
+ type RouteConfig<Props extends object = {}, Keys extends string = string> = RouteConfigPath & RouteRenderConfig & RouteConfigBase<Record<Keys, RouteConfig<Props>>, Props> & RouteConfigExtension;
133
+ type RouteConfigChildren<TConfig extends RouteConfigInput> = TreeChildKey extends keyof TConfig ? TConfig[TreeChildKey] extends RoutesConfig<infer TChildren extends Record<string, RouteConfigInput>> ? TChildren : {} : {};
134
+
135
+ type RouteConfigTypeError<TMessage extends string> = {
136
+ readonly __routeConfigTypeError__: TMessage;
137
+ };
138
+ type RouteConfigMapTypeErrorsDeep<TConfig> = {
139
+ [K in keyof TConfig]: TConfig[K] extends RouteConfigTypeError<string> ? TConfig[K] : TConfig[K] extends RouteConfigInput ? RouteConfigMapTypeErrorsDeep<RouteConfigChildren<TConfig[K]>> : never;
140
+ }[keyof TConfig];
141
+ /**
142
+ * Errors
143
+ */
144
+ type DuplicateRootRouteKeyError<TKey extends string> = RouteConfigTypeError<`Duplicate root route key: ${TKey}`>;
145
+ type MissingPutInKeyError<TKey extends string> = RouteConfigTypeError<`putInKey target not found: ${TKey}`>;
146
+ type DuplicatePutInRouteKeyError<TParent extends string, TKey extends string> = RouteConfigTypeError<`Duplicate child route key: ${TKey} for putInKey: ${TParent}`>;
147
+
148
+ type NormalizeMergedRoutesConfig<TConfig> = {
149
+ [K in Extract<keyof TConfig, string>]: Extract<TConfig[K], RouteConfigInput>;
150
+ };
151
+ type NormalizeResolvedRoutesConfig<TConfig extends Record<string, RouteConfigInput | RouteConfigTypeError<string>>> = {
152
+ [K in keyof TConfig as TConfig[K] extends RouteConfigTypeError<string> ? never : K]: Extract<TConfig[K], RouteConfigInput>;
153
+ };
154
+ type NormalizeRoutesConfig<TConfig extends Record<string, RouteConfigInput>> = {
155
+ [K in keyof TConfig]: TConfig[K];
156
+ };
157
+
158
+ type RouteOwnKeys = Exclude<keyof RouteConfigInput, TreeChildKey>;
159
+ type HasOwnRouteConfig<T> = Extract<keyof T, RouteOwnKeys> extends never ? false : true;
160
+ type MergeRouteNodeSafe<TLeft extends RouteConfigInput, TRight extends RouteConfigInput> = Omit<TLeft & TRight, TreeChildKey> & {
161
+ [K in TreeChildKey]: MergeRoutesConfigsDeep<RouteConfigChildren<TLeft>, RouteConfigChildren<TRight>>;
162
+ };
163
+ type RootRouteKeys<TConfig extends RoutesConfig> = Exclude<RoutesConfigKey<TConfig>, DeferredRouteKeys<TConfig>>;
164
+ type RootRoutesConfigPart<TConfig extends RoutesConfig> = {
165
+ [K in RootRouteKeys<TConfig>]: TConfig[K];
166
+ };
167
+ type MergeRouteNode<TLeft extends RouteConfigInput, TRight extends RouteConfigInput, TKey extends string> = HasOwnRouteConfig<TLeft> extends true ? HasOwnRouteConfig<TRight> extends true ? DuplicateRootRouteKeyError<TKey> : MergeRouteNodeSafe<TLeft, TRight> : MergeRouteNodeSafe<TLeft, TRight>;
168
+ type MergeRoutesConfigsDeep<TLeft extends Record<string, RouteConfigInput>, TRight extends Record<string, RouteConfigInput>> = {
169
+ [K in keyof TLeft | keyof TRight]: K extends keyof TLeft ? K extends keyof TRight ? K extends string ? MergeRouteNode<Extract<TLeft[K], RouteConfigInput>, Extract<TRight[K], RouteConfigInput>, K> : never : TLeft[K] : K extends keyof TRight ? TRight[K] : never;
170
+ };
171
+ type MergeRouteChildren<TRouteConfig extends RouteConfigInput, TDeferredChildren extends Record<string, RouteConfigInput>, TParent extends string> = Extract<Extract<keyof RouteConfigChildren<TRouteConfig>, keyof TDeferredChildren>, string> extends infer TDuplicateKey extends string ? [TDuplicateKey] extends [never] ? Omit<TRouteConfig, TreeChildKey> & {
172
+ [K in TreeChildKey]: RoutesConfig<NormalizeRoutesConfig<RouteConfigChildren<TRouteConfig> & TDeferredChildren>>;
173
+ } : DuplicatePutInRouteKeyError<TParent, TDuplicateKey> : never;
174
+ type MergeRootRoutesConfigs<TConfigs extends readonly RoutesConfig[], TResult extends Record<string, RouteConfigInput> = {}> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? MergeRoutesConfigsDeep<TResult, RootRoutesConfigPart<THead>> extends infer TMerged ? RouteConfigMapTypeErrorsDeep<TMerged> extends infer TError extends RouteConfigTypeError<string> ? [TError] extends [never] ? MergeRootRoutesConfigs<TTail, NormalizeMergedRoutesConfig<TMerged>> : TError : never : never : TResult;
175
+
176
+ type RemoveIndexSignature<T> = {
177
+ [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
178
+ };
179
+
180
+ type ChildKeys<T> = [keyof RemoveIndexSignature<T>] extends [never] ? Extract<keyof T, string | number | symbol> : Extract<keyof RemoveIndexSignature<T>, string | number | symbol>;
181
+
182
+ type ObjectChain<T> = T extends Record<any, any> ? {
183
+ [K in ChildKeys<T>]: [K] | (TreeChildKey extends keyof T[K] ? T[K][TreeChildKey] extends Record<PropertyKey, unknown> ? [K, ...ObjectChain<T[K][TreeChildKey]>] : [K] : [K]);
184
+ }[ChildKeys<T>] : never;
185
+
186
+ type RouteTreeNode = object & {
187
+ [K in TreeChildKey]?: RouteTree;
188
+ };
189
+ interface RouteTree {
190
+ [key: string]: RouteTreeNode;
191
+ }
192
+ type RouteTreeChildren<TRoute> = TRoute extends {
193
+ [K in TreeChildKey]?: infer TChildren extends RouteTree;
194
+ } ? TChildren : never;
195
+
196
+ type RoutesPathKeysMaxDepth = [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown];
197
+ type JoinRouteKey<TPrefix extends string, TKey extends string> = TPrefix extends '' ? TKey : `${TPrefix}.${TKey}`;
198
+ type RouteKey<T> = Extract<keyof T, string>;
199
+ type RoutesKeys<Routes extends RoutesConfig> = ObjectChain<Routes> | RoutesPathKeys<Routes>;
200
+ type RoutesPathKeys<TRoutes extends RouteTree, TPrefix extends string = '', TDepth extends unknown[] = []> = TDepth extends RoutesPathKeysMaxDepth ? never : {
201
+ [K in RouteKey<TRoutes>]: JoinRouteKey<TPrefix, K> | (RouteTreeChildren<TRoutes[K]> extends infer TChildren extends RouteTree ? RoutesPathKeys<TChildren, JoinRouteKey<TPrefix, K>, [...TDepth, unknown]> : never);
202
+ }[RouteKey<TRoutes>];
203
+
204
+ type ExplicitChildrenRouteKeys<TRootConfig extends Record<string, RouteConfigInput>> = {
205
+ [K in Extract<keyof TRootConfig, string>]: TreeChildKey extends keyof TRootConfig[K] ? K : never;
206
+ }[Extract<keyof TRootConfig, string>];
207
+ type NormalizePutInKey<TPutInKey, TKnownParents extends string> = TPutInKey extends string ? string extends TPutInKey ? [TKnownParents] extends [never] ? TPutInKey : TKnownParents : TPutInKey : never;
208
+ type RouteConfigPutInKey<TConfig extends RouteConfigInput> = TConfig extends {
209
+ putInKey: infer TPutInKey extends string;
210
+ } ? TPutInKey : never;
211
+ type PutInKeyFallbackParents<TRootConfig extends Record<string, RouteConfigInput>> = [
212
+ ExplicitChildrenRouteKeys<TRootConfig>
213
+ ] extends [never] ? Extract<keyof TRootConfig, string> : ExplicitChildrenRouteKeys<TRootConfig>;
214
+
215
+ type MergeDeferredRoutesForParent<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>, TParent extends string, TResult extends Record<string, RouteConfigInput> = {}> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? DeferredRoutesForParentInConfig<THead, TParent, PutInKeyFallbackParents<TRootConfig>> extends infer TDeferredRoutes extends Record<string, RouteConfigInput> ? Extract<Extract<keyof TResult, keyof TDeferredRoutes>, string> extends infer TDuplicateKey extends string ? [TDuplicateKey] extends [never] ? MergeDeferredRoutesForParent<TTail, TRootConfig, TParent, TResult & TDeferredRoutes> : DuplicatePutInRouteKeyError<TParent, TDuplicateKey> : never : never : TResult;
216
+ type ApplyDeferredRouteForKey<TRootConfig extends Record<string, RouteConfigInput>, TConfigs extends readonly RoutesConfig[], TKey extends Extract<keyof TRootConfig, string>> = MergeDeferredRoutesForParent<TConfigs, TRootConfig, TKey> extends infer TDeferredChildren ? TDeferredChildren extends RouteConfigTypeError<string> ? TDeferredChildren : TDeferredChildren extends Record<string, RouteConfigInput> ? keyof TDeferredChildren extends never ? TRootConfig[TKey] : MergeRouteChildren<TRootConfig[TKey], TDeferredChildren, TKey> : never : never;
217
+ type RouteConfigWithoutPutInKey<TConfig extends RouteConfigInput> = Omit<TConfig, 'putInKey'>;
218
+ type DeferredRoutesForParentInConfig<TConfig extends RoutesConfig, TParent extends string, TKnownParents extends string = TParent> = {
219
+ [K in DeferredRouteKeys<TConfig> as Extract<NormalizePutInKey<RouteConfigPutInKey<TConfig[K]>, TKnownParents>, TParent> extends never ? never : K]: RouteConfigWithoutPutInKey<TConfig[K]>;
220
+ };
221
+ type DeferredRouteKeys<TConfig extends RoutesConfig> = {
222
+ [K in RoutesConfigKey<TConfig>]: TConfig[K] extends {
223
+ putInKey: string;
224
+ } ? K : never;
225
+ }[RoutesConfigKey<TConfig>];
226
+ type DeferredRouteParents<TConfig extends RoutesConfig, TKnownParents extends string> = {
227
+ [K in DeferredRouteKeys<TConfig>]: NormalizePutInKey<RouteConfigPutInKey<TConfig[K]>, TKnownParents>;
228
+ }[DeferredRouteKeys<TConfig>];
229
+ type ApplyDeferredRoutes<TRootConfig extends Record<string, RouteConfigInput>, TConfigs extends readonly RoutesConfig[]> = {
230
+ [K in Extract<keyof TRootConfig, string>]: ApplyDeferredRouteForKey<TRootConfig, TConfigs, K>;
231
+ };
232
+ type ResolveAppliedDeferredRoutes<TAppliedRoutes extends Record<string, RouteConfigInput | RouteConfigTypeError<string>>> = RouteConfigMapTypeErrorsDeep<TAppliedRoutes> extends infer TError extends RouteConfigTypeError<string> ? [TError] extends [never] ? RoutesConfig<NormalizeRoutesConfig<NormalizeResolvedRoutesConfig<TAppliedRoutes>>> : TError : never;
233
+
234
+ type MissingPutInKeys<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>> = TConfigs extends readonly [infer THead extends RoutesConfig, ...infer TTail extends readonly RoutesConfig[]] ? Exclude<DeferredRouteParents<THead, PutInKeyFallbackParents<TRootConfig>>, Extract<keyof TRootConfig, string>> | MissingPutInKeys<TTail, TRootConfig> : never;
235
+ type ValidatePutInKeys<TConfigs extends readonly RoutesConfig[], TRootConfig extends Record<string, RouteConfigInput>> = MissingPutInKeys<TConfigs, TRootConfig> extends infer TMissingKey extends string ? [TMissingKey] extends [never] ? TRootConfig : MissingPutInKeyError<TMissingKey> : never;
236
+
237
+ /**
238
+ * General type
239
+ */
240
+ type UnionRoutesConfig<TRoutes extends readonly RoutesConfig[] = readonly RoutesConfig[]> = number extends TRoutes['length'] ? RoutesConfig : MergeRootRoutesConfigs<TRoutes> extends infer TRootRoutes ? TRootRoutes extends RouteConfigTypeError<string> ? TRootRoutes : TRootRoutes extends Record<string, RouteConfigInput> ? ValidatePutInKeys<TRoutes, TRootRoutes> extends infer TValidatedRoutes ? TValidatedRoutes extends RouteConfigTypeError<string> ? TValidatedRoutes : TValidatedRoutes extends Record<string, RouteConfigInput> ? ApplyDeferredRoutes<TValidatedRoutes, TRoutes> extends infer TAppliedRoutes extends Record<string, RouteConfigInput | RouteConfigTypeError<string>> ? ResolveAppliedDeferredRoutes<TAppliedRoutes> : never : never : never : never : never;
241
+
242
+ declare function reactRouterFabric<const TRoutes extends readonly RoutesConfig[]>(...mixedRoutesConfigs: TRoutes): UnionRoutesConfig<TRoutes>;
243
+ declare function reactRouterFabric<const TRoutes extends readonly RoutesConfig[]>(mixedRoutesConfigs: TRoutes[]): UnionRoutesConfig<TRoutes>;
244
+
245
+ type CreateUrlFromRouteConfig<Routes extends RoutesConfig> = (mixedPath: RoutesKeys<Routes>, pathParams?: Nullable<CustomObject<string | number | boolean>>, queryParams?: CustomObject<Nullable<string | number | boolean>>, safePathParams?: boolean) => string;
246
+
247
+ type CreateUrlsFromRouteConfig<Routes extends RoutesConfig> = (mixedPath: RoutesKeys<Routes>, pathParams?: Nullable<CustomObject<string | number | boolean>>, queryParams?: CustomObject<Nullable<string | number | boolean>>, safePathParams?: boolean) => string[];
248
+
249
+ type RouterProviderProps = PropsWithChildren;
250
+
251
+ interface UseActivatedRouteType<Routes extends RoutesConfig> {
252
+ activatedRoute: RouteConfig;
253
+ pathParams: Record<string, string>;
254
+ queryParams: Record<string, string>;
255
+ routeKey: ObjectChain<Routes>;
256
+ routeKeyString: RoutesPathKeys<Routes>;
257
+ routeUrlMask: string;
258
+ parents: RouteConfig[];
259
+ }
260
+
261
+ interface SetLocationOptions<S = unknown> {
262
+ replace?: boolean;
263
+ state?: S;
264
+ transition?: boolean;
265
+ }
266
+ type UseLocationType<Routes extends RoutesConfig, S = unknown> = [
267
+ string,
268
+ (key: ObjectChain<Routes> | RoutesPathKeys<Routes>, pathParams?: Nullable<Record<string | number | symbol, string | number | boolean>>, queryParams?: Record<string | number | symbol, Nullable<string | number | boolean>>, options?: SetLocationOptions<S>) => void
269
+ ];
270
+ /**
271
+ * General hook type
272
+ */
273
+ type UseLocation<Routes extends RoutesConfig> = <S = unknown>() => UseLocationType<Routes, S>;
274
+
275
+ type UseRoute<Routes extends RoutesConfig> = (key: ObjectChain<Routes> | RoutesPathKeys<Routes>) => Match<Record<string | number, Undefinable<string>>>;
276
+
277
+ type UseRouteState = <T extends string | number>(key: string, fallback: T) => [T, (value: T) => void];
278
+
279
+ interface CreateRouterContext<Routes extends RoutesConfig = RoutesConfig> {
280
+ RouterContext: Context<Nullable<Routes>>;
281
+ RouterProvider: FC<RouterProviderProps>;
282
+ createUrlFromRouteConfig: CreateUrlFromRouteConfig<Routes>;
283
+ createUrlsFromRouteConfig: CreateUrlsFromRouteConfig<Routes>;
284
+ useLocation: UseLocation<Routes>;
285
+ useActivatedRoute: () => UseActivatedRouteType<Routes>;
286
+ useRoute: UseRoute<Routes>;
287
+ useRoutePathState: UseRouteState;
288
+ useRouteQueryState: UseRouteState;
289
+ }
290
+
291
+ declare const routerContextFabric: <Routes extends RoutesConfig = RoutesConfig>(routes: Routes) => CreateRouterContext<Routes>;
292
+
293
+ export { type ReactComponents, type RouterComponents, type RoutesDefinition, type RoutesKeys, type RoutesPathKeys, componentsContextFabric, reactRouterFabric, routerContextFabric };
package/.dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import*as C from"react";var _="@akb2/react/";var q=Symbol.for(_+"components-context");import{createContext as rt}from"react";var I=(t,s=null)=>{let o=globalThis;return t in o||(o[t]=rt(s)),o[t]};import{useContext as nt}from"react";import{jsx as st}from"react/jsx-runtime";var D=()=>{let t=I(q);return{ComponentsContext:t,ComponentsProvider:({components:i,children:R})=>st(t.Provider,{value:i,children:R}),useComponents:()=>{let i=nt(t);if(!i)throw new Error("useComponents must be used inside ComponentsProvider");return i}}};import{isDefined as v}from"@akb2/types-tools";import{isDefined as G}from"@akb2/types-tools";var W=t=>{let s=G(t.children)?{...t.children}:void 0;return G(s)?{...t,children:s}:{...t}};function it(...t){let s=Array.isArray(t[0])?t[0]:t,o={},i=[],R=100;for(let p of s)for(let r in p){let u=p[r];if(!v(u.putInKey)&&v(o[r]))throw new Error(`Duplicate route key "${r}" found in module options.`);v(u.putInKey)?i.push([r,u]):o[r]=u}for(;i.length>0&&R-- >0;){let p=i.findIndex(([,{putInKey:n}])=>v(n)&&v(o[n]));if(p===-1)throw new Error('Circular dependency detected in route configurations. Please check the "putInKey" properties.');let[r,u]=i[p],{putInKey:c,...P}=u;if(!v(c))throw new Error('Invalid route configuration. "putInKey" is not defined.');let x=o[c],N=v(x.children)?{...x.children}:{};if(v(N[r]))throw new Error(`Duplicate route key "${r}" found in module options.`);N[r]=W(P),o[c]={...x,children:N},i.splice(p,1)}return o}import{anyToArray as ht,anyToString as $,isDefined as g,smartJoin as gt}from"@akb2/types-tools";var Y=Symbol.for(_+"router-context");var J=(t,s,o)=>{let i={...o},R=t.split("/"),p=s.split("/");if(R.length!==p.length)return!1;for(let r=0;r<R.length;r++)if(p[r].startsWith(":")){i[p[r].slice(1)]=R[r];continue}else if(R[r]!==p[r])return!1;return Object.assign(o,i),!0};import{anyToArray as ut,anyToString as ct,smartJoin as lt}from"@akb2/types-tools";var S=(t,s,o=!1)=>{let R=ut(t).reduce((r,u)=>{let c=u.split("/");for(let P of c)r.push(P.startsWith(":")&&!o?ct(s?.[P.slice(1)],"*"):P);return r},[]);return("/"+lt("/",...R)).replace(/[\/\\]+/gim,"/")};var M=t=>Array.isArray(t)?t:t.split(".");import{anyToString as mt,isDefined as pt}from"@akb2/types-tools";var j=t=>Object.entries(t??{}).filter(([,s])=>pt(s)).reduce((s,[o,i])=>s+`${s?"&":"?"}${encodeURIComponent(o)}=${encodeURIComponent(mt(i))}`,"");var z=(t,s,o,i,R=!1)=>{let p=M(s),r=[],u=t;for(let c of p){if(!u.hasOwnProperty(c))break;u=u[c],r.push(u?.path??u?.paths[0]),u=u.children}return S(r,o,R)+j(i)};var H=(t,s,o,i,R=!1)=>{let p=j(i),r=M(s),u=[],c=t;for(let x of r){if(!c.hasOwnProperty(x))break;c=c[x];let N=Array.isArray(c?.paths)?c.paths:[c?.path];u.push(N.filter(n=>typeof n=="string")),c=c.children}return u.length===0?[S([])]:u.reduce((x,N)=>x.flatMap(n=>N.map(f=>[...n,f])),[[]]).map(x=>S(x,o,R)+p)};var V=t=>Array.from(t).reduce((s,[o,i])=>(s[o]=i,s),{});import{anyToArray as ft}from"@akb2/types-tools";var Z=t=>{if(!t)return{};let s=ft(t.split("&")),o={};for(let i of s){let[R,p]=i.split("=");R&&(o[R]=p??"")}return o};import{Suspense as bt,useCallback as ot,useMemo as et}from"react";import{Redirect as Tt,useSearchParams as yt,useLocation as Pt,useRoute as xt}from"wouter";import{jsx as F}from"react/jsx-runtime";var Et=t=>{let s=(n,f)=>{let h=n.split("/").filter(Boolean),l=f.split("/").filter(Boolean);for(let a=0;a<h.length;a++){let m=h[a].startsWith(":"),e=l[a].startsWith(":");if(m!==e)return m?1:-1}return 0},o=(n,f=[""],h=new Set)=>{if(f.length===0)throw new Error("Parent paths cannot be empty.");let l=h.size===0,a=!1;for(let m in n){let e=n[m];if([g(e.Module),g(e.Template),g(e.redirectUrl)].filter(Boolean).length!==1)throw new Error(`Route with key "${m}" must have exactly one of Module, Template, or redirectUrl defined.`);if([g(e.path),g(e.paths),e.isNotFound===!0].filter(Boolean).length!==1)throw new Error(`Route with key "${m}" must have exactly one of path, paths, or isNotFound defined.`);if(e.isNotFound===!0)if(l){if(a)throw new Error("Only one not found route can be defined at the top level.");if(g(e.children))throw new Error("Not found route cannot have children.");a=!0;continue}else throw new Error("Not found route can only be defined at the top level.");let y=g(e.path)?[e.path]:g(e.paths)?e.paths:[];if(y.length===0)throw new Error(`Route with key "${m}" must have at least one path defined.`);let b=f.flatMap(E=>y.map(w=>S([E,w])));for(let E of b){if(h.has(E))throw new Error(`Duplicate route detected for URL: "${E}"`);h.add(E)}g(e.children)&&o(e.children,b,h)}if(l&&!a)throw new Error("A not found route must be defined at the top level.")};o(t);let i=I(Y),R=()=>{let{activatedRoute:{Module:n,Template:f,redirectUrl:h,SuspenseTemplate:l,props:a}}=P(),{useComponents:m}=D(),{FullPageLoader:e}=m(),T=g(n)?n:g(f)?f:()=>F(Tt,{to:h}),d=l?F(l,{}):F(e,{});return F(i.Provider,{value:t,children:F(bt,{fallback:d,children:F(T,{...a})})})},p=z.bind(null,t),r=H.bind(null,t),u=n=>xt(p(n,null,{},!0)),c=()=>{let[n,f]=Pt();return[n,(l,a,m,e)=>{let T=r(l,a,m,!0),d=T.find(k=>{let U=k.split("/").filter(Boolean);return Object.keys(a??{}).every(K=>U.includes(":"+K))})??T[0],[y,b]=S(d,a,!1).split("?"),E=Z(b),w=y+j({...E,...m});return f(w,e)}]},P=()=>{let[n]=c(),[f]=yt(),h=et(()=>{let l=n.split("/").filter(Boolean);return l.length>0?l:[""]},[n]);return et(()=>{let l=[],a=[],m={},e=V(f.entries()),T=null,d=null,y=t,b="",E=0;for(let w of h){let k=b?b+"/"+w:w,U=new Map;for(let K in y){let O=y[K];if(O.isNotFound===!0){if(E>0)throw new Error("Not found route must be defined at the root level");T=O;continue}(g(O.path)?[O.path]:g(O.paths)?ht(O.paths):[]).forEach((L,B)=>{let A={};J(k,L,A)&&U.set(gt("/",K,$(B)),{path:L,config:O,pathParams:A})})}if(U.size>0){let O=Array.from(U.entries()).reduce((A,X)=>s(X[1].path,A[1].path)<0?X:A),[Q,{config:L,pathParams:B}]=O;g(d)&&a.push(d),b="",d=L,y=d.children??{},Object.assign(m,B),l.push(Q.split("/")[0]),E++}else b=b?b+"/"+w:w}return(b||!g(d))&&(d=T),{activatedRoute:d,routeKey:l,parents:a,pathParams:m,queryParams:e,routeKeyString:l.join("."),routeUrlMask:b}},[h,f])};return{RouterContext:i,RouterProvider:R,createUrlFromRouteConfig:p,createUrlsFromRouteConfig:r,useLocation:c,useActivatedRoute:P,useRoute:u,useRoutePathState:(n,f)=>{let[,h]=c(),{routeKey:l,pathParams:a,queryParams:m}=P(),e=a[n],T=ot(d=>{e!==d&&h(l,{...a,[n]:d},m,{replace:!0})},[e,l,a,m]);return[e??f,T]},useRouteQueryState:(n,f)=>{let[,h]=c(),{routeKey:l,pathParams:a,queryParams:m}=P(),e=m[n]??f,T=ot(d=>{if(e!==d){let y={...m};g(d)&&d!==f&&$(d).length>0?y[n]=$(d):delete y[n],h(l,a,y,{replace:!0})}},[e,l,a,m,f]);return[e??f,T]}}};export{D as componentsContextFabric,it as reactRouterFabric,Et as routerContextFabric};