route-sprout 2.0.0 → 3.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.
package/README.md CHANGED
@@ -39,10 +39,10 @@ const Api = root([
39
39
  ]),
40
40
  ]);
41
41
 
42
- Api.invoices(); // "/invoices"
43
- Api.invoices("page=1"); // "/invoices?page=1"
44
- Api.invoices.id("abc")("a=1"); // "/invoices/abc?a=1"
45
- Api.invoices.id("abc").customers(); // "/invoices/abc/customers"
42
+ Api.invoices(); // "/invoices"
43
+ Api.invoices("page=1"); // "/invoices?page=1"
44
+ Api.invoices.$id("abc")("a=1"); // "/invoices/abc?a=1"
45
+ Api.invoices.$id("abc").customers(); // "/invoices/abc/customers"
46
46
  ```
47
47
 
48
48
  ---
@@ -69,7 +69,7 @@ When you have lots of endpoints, you usually end up with:
69
69
  This DSL gives you:
70
70
 
71
71
  - a single, declarative source of truth
72
- - fluent, discoverable usage (`Api.invoices.id("x").customers()`)
72
+ - fluent, discoverable usage (`Api.invoices.$id("x").customers()`)
73
73
  - TypeScript autocomplete and type checking from **usage**, not comments
74
74
 
75
75
  ---
@@ -80,6 +80,31 @@ This DSL gives you:
80
80
 
81
81
  An entry point for your root tree that naturally denotes '/' path.
82
82
 
83
+ ### `base(segs, list)` (hidden prefix)
84
+
85
+ `base()` adds one or more URL segments **without creating an object key in the chain**.
86
+
87
+ - Useful for global prefixes like `api`, `v2`, `internal`, etc.
88
+ - The prefix is **transparent** at the type level and runtime chain level.
89
+ - Supports a single segment or an array of segments: `Segment | Segment[]`.
90
+
91
+ ```ts
92
+ import { base, keep, path, root, slot } from 'route-sprout'
93
+
94
+ export const Api = root([
95
+ base('api', [
96
+ path('orders', [keep()]),
97
+ path('customers', [slot('id', [keep()])]),
98
+ ]),
99
+ ])
100
+
101
+ Api.orders() // "/api/orders"
102
+ Api.customers.$id(7)() // "/api/customers/7"
103
+
104
+ // There is no Api.api property:
105
+ (Api as any).api // undefined
106
+ ```
107
+
83
108
  ### `path(name, children?)`
84
109
 
85
110
  A **static** path segment.
@@ -111,7 +136,7 @@ The `name` is only the **property key**. It is **not** inserted into the path.
111
136
 
112
137
  ```ts
113
138
  path("invoices", [slot("id")]);
114
- // Api.invoices.id("abc")() -> "/invoices/abc"
139
+ // Api.invoices.$id("abc")() -> "/invoices/abc"
115
140
  ```
116
141
 
117
142
  With children:
@@ -124,7 +149,7 @@ path("invoices", [
124
149
  ]),
125
150
  ]);
126
151
 
127
- // Api.invoices.id("abc").customers() -> "/invoices/abc/customers"
152
+ // Api.invoices.$id("abc").customers() -> "/invoices/abc/customers"
128
153
  ```
129
154
 
130
155
  ### `wrap(name, predicate, children?)`
@@ -143,12 +168,42 @@ path("core", [
143
168
  ]),
144
169
  ]);
145
170
 
146
- Api.core.admin({ isAdmin: true }).invoices(); // "/core/admin/invoices"
147
- Api.core.admin({ isAdmin: false }).invoices(); // "/core/invoices"
171
+ Api.core.$admin({ isAdmin: true }).invoices(); // "/core/admin/invoices"
172
+ Api.core.$admin({ isAdmin: false }).invoices(); // "/core/invoices"
148
173
  ```
149
174
 
150
175
  > `wrap` is ideal for *well-known*, reusable gates: `admin`, `v2`, `tenant`, etc.
151
176
 
177
+ ### `pick(name, segments, children?)`
178
+
179
+ An enumerated segment group *defined in the tree*.
180
+
181
+ ```ts
182
+ type User = { isAdmin: boolean } | null;
183
+
184
+ path("core", [
185
+ pick("role", { admin: "admin", user: ["user", "role"] }, [
186
+ path("invoices", [keep()]),
187
+ ]),
188
+ ]);
189
+
190
+ Api.core.$role("admin").invoices(); // "/core/admin/invoices"
191
+ Api.core.$role("user").invoices(); // "/core/user/role/invoices"
192
+ ```
193
+
194
+ > **Type inference tip:** to have TypeScript restrict `$mode(...)` to known keys,
195
+ > define the `mode` object with `as const`:
196
+ >
197
+ > ```ts
198
+ > pick('mode', {
199
+ > admin: ['admin'],
200
+ > user: [],
201
+ > }, [...])
202
+ > ```
203
+ >
204
+ > Then `$mode('nope')` is a type error.
205
+ ```
206
+
152
207
  ### `.$when(cond, segment | segment[])`
153
208
 
154
209
  Ad‑hoc conditional segment insertion at **runtime**, anywhere in the chain.
@@ -156,7 +211,7 @@ Ad‑hoc conditional segment insertion at **runtime**, anywhere in the chain.
156
211
  ```ts
157
212
  Api.core.$when(isAdmin, "admin").invoices();
158
213
  Api.core.$when(true, ["tenant", tenantId]).invoices();
159
- Api.invoices.id("abc").$when(flags.preview, "preview").activities();
214
+ Api.invoices.$id("abc").$when(flags.preview, "preview").activities();
160
215
  ```
161
216
 
162
217
  - `cond = false` → no-op
@@ -216,18 +271,18 @@ export const Api = root([
216
271
 
217
272
  // usage
218
273
  Api.invoices(); // "/invoices"
219
- Api.invoices.id("123").customers(); // "/invoices/123/customers"
274
+ Api.invoices.$id("123").customers(); // "/invoices/123/customers"
220
275
 
221
276
  // runtime insert
222
277
  Api.core.$when(true, "v2").invoices(); // "/core/v2/invoices"
223
- Api.core.admin({ isAdmin: true }).$when(true, "v2").invoices(); // "/core/admin/v2/invoices"
278
+ Api.core.$admin({ isAdmin: true }).$when(true, "v2").invoices(); // "/core/admin/v2/invoices"
224
279
  ```
225
280
 
226
281
  ### Autocomplete-friendly patterns
227
282
  Because everything is computed from the definition tree, your editor can autocomplete:
228
283
 
229
284
  - paths (`Api.invoices`, `Api.orders.export`)
230
- - slots (`Api.invoices.id(…)`)
285
+ - slots (`Api.invoices.$id(…)`)
231
286
  - nested children (`…id("x").customers()`)
232
287
 
233
288
  ---
@@ -237,9 +292,11 @@ Because everything is computed from the definition tree, your editor can autocom
237
292
  ### Exports
238
293
 
239
294
  - `root(defs)`
240
- - `path(name, rest?)`
241
- - `slot(name, rest?)`
242
- - `wrap(name, when, rest?)`
295
+ - `base(segs, defs?)`
296
+ - `path(name, defs?)`
297
+ - `slot(name, defs?)`
298
+ - `wrap(name, when, defs?)`
299
+ - `pick(name, mode, defs?)`
243
300
  - `keep()`
244
301
 
245
302
  ### Path level builders
@@ -272,7 +329,7 @@ const Api = root([
272
329
  path("invoices", [keep(), slot("id")]),
273
330
  ]);
274
331
 
275
- Api.invoices.id("123")(); // "/invoices/123"
332
+ Api.invoices.$id("123")(); // "/invoices/123"
276
333
  ```
277
334
 
278
335
  #### `route-sprout/dialect-step`
@@ -302,7 +359,7 @@ const Api = grow([
302
359
  ]),
303
360
  ]);
304
361
 
305
- Api.core.admin({ isAdmin: true }).jobs(); // "/core/admin/jobs"
362
+ Api.core.$admin({ isAdmin: true }).jobs(); // "/core/admin/jobs"
306
363
  ```
307
364
 
308
365
  #### `route-sprout/dialect-node`
@@ -315,7 +372,7 @@ const Api = link([
315
372
  node("tasks", [base(), bind("id", [node("logs")])]),
316
373
  ]);
317
374
 
318
- Api.tasks.id("x").logs(); // "/tasks/x/logs"
375
+ Api.tasks.$id("x").logs(); // "/tasks/x/logs"
319
376
  ```
320
377
 
321
378
  ### Mix-and-match?
@@ -347,7 +404,7 @@ import { root, path, slot, keep } from "route-sprout";
347
404
  test("builds routes", () => {
348
405
  const Api = root([path("invoices", [keep(), slot("id")])] as const);
349
406
  expect(Api.invoices()).toBe("/invoices");
350
- expect(Api.invoices.id("x")()).toBe("/invoices/x");
407
+ expect(Api.invoices.$id("x")()).toBe("/invoices/x");
351
408
  });
352
409
  ```
353
410
 
package/dist/api.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var a in e)f(t,a,{get:e[a],enumerable:!0})},b=(t,e,a,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of N(e))!P.call(t,s)&&s!==a&&f(t,s,{get:()=>e[s],enumerable:!(r=y(e,s))||r.enumerable});return t};var D=t=>b(f({},"__esModule",{value:!0}),t);var $={};w($,{keep:()=>R,path:()=>p,root:()=>F,slot:()=>k,wrap:()=>x});module.exports=D($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),R=()=>({kind:"keep"}),p=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),k=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),x=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),K=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!K.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function F(t){return u([],p("",t))}function u(t,e){let a=n=>n.rest.some(o=>o.kind==="keep"),r=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(r,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=o=>{let l=[...r,o];return c(d=>m(l,d),l,[])}:s[n.uuid]=o=>{let l=u([...r,o],n);return Object.assign(a(n)?i=>m([...r,o],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let o=[...r,n.uuid],l=i=>m(o,i);s[n.uuid]=c(l,o,[])}else s[n.uuid]=u(r,n);else n.kind==="wrap"&&(s[n.uuid]=o=>{let i=n.when(o)?[...r,n.uuid]:r,d=u(i,n);return Object.assign(a(n)?h=>m(i,h):Object.create(null),d)});return c(s,r,e.rest)}function c(t,e,a){let r=(s,n)=>{let o=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(o,i),o,a):u(o,p("",a))};return t.$when=r,t.$join=s=>r(!0,s),t}0&&(module.exports={keep,path,root,slot,wrap});
1
+ "use strict";var h=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var x=(e,t)=>{for(var s in t)h(e,s,{get:t[s],enumerable:!0})},N=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!w.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(a=y(t,o))||a.enumerable});return e};var D=e=>N(h({},"__esModule",{value:!0}),e);var E={};x(E,{base:()=>A,keep:()=>L,path:()=>u,pick:()=>j,root:()=>T,slot:()=>P,wrap:()=>C});module.exports=D(E);var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),b=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!b.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var S=e=>Array.isArray(e)?e:[e],L=()=>({kind:"keep"}),u=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),P=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),C=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),j=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),A=(e,t)=>({kind:"base",segs:e,list:t??[]}),T=e=>l([],u("",e)),_=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${t}`:""}`;function l(e,t){let s=n=>n.list.some(i=>i.kind==="keep"),a=t.kind==="path"&&t.name?[...e,t.name]:e,o=c(s(t),a);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="base"){let i=[...a,...S(n.segs)],d=l(i,u("",n.list));for(let r of Reflect.ownKeys(d)){if(r==="$when"||r==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,r);if(m?.enumerable){if(r in o)throw new Error(`base() merge collision on key "${String(r)}" under "${a.join("/")||"/"}"`);Object.defineProperty(o,r,m)}}}else if(n.kind==="slot")o[n.uuid]=function(d){let r=[...a,d];return n.list.length===0?f(c(!0,r),r,[]):Object.assign(c(s(n),r),l(r,n))};else if(n.kind==="path")if(n.list.length===0){let i=[...a,n.name];o[n.uuid]=f(c(!0,i),i,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(d){let m=n.when(d)?[...a,n.name]:a,k=l(m,n);return Object.assign(c(s(n),m),k)}:n.kind==="pick"&&(o[n.uuid]=i=>{if(n.mode[i])return l([...a,...n.mode[i]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(i)}`)})}return f(o,a,t.list)}function f(e,t,s){let a=(o,n)=>{let i=o?[...t,...S(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,i),i,s):l(i,u("",s))};return e.$when=a,e.$join=function(n){return a(!0,n)},e}var c=(e,t)=>e?s=>_(t,s):Object.create(null);0&&(module.exports={base,keep,path,pick,root,slot,wrap});
2
2
  //# sourceMappingURL=api.cjs.map
package/dist/api.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["api_exports","__export","keep","path","root","slot","wrap","__toCommonJS","toCamel","s","_","c","name","rest","assertValidName","when","IDENT","kind","url","search","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"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","names":["api_exports","__export","base","keep","path","pick","root","slot","wrap","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","list","when","mode","segs","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
package/dist/api.d.cts CHANGED
@@ -1,6 +1,9 @@
1
1
  // ---------- Helpers ----------------------
2
- type KebabToCamel<S extends string> = S extends `${infer A}-${infer B}`
3
- ? `${A}${Capitalize<KebabToCamel<B>>}`
2
+ type Delimiter = '_' | '-'
3
+ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}`
4
+ ? A extends ''
5
+ ? ToCamelCase<B>
6
+ : `${A}${Capitalize<ToCamelCase<B>>}`
4
7
  : S
5
8
 
6
9
  // ---------- Shared public types ----------
@@ -13,93 +16,96 @@ type Keep = { kind: 'keep' }
13
16
  type Path<
14
17
  Name extends string = string,
15
18
  Uuid extends string = string,
16
- Rest extends readonly PathDef[] = readonly PathDef[],
17
- > = { kind: 'path'; name: Name; uuid: Uuid; rest: Rest }
19
+ List extends readonly PathDef[] = readonly PathDef[],
20
+ > = { kind: 'path'; name: Name; uuid: Uuid; list: List }
18
21
 
19
22
  type Slot<
20
23
  Name extends string = string,
21
24
  Uuid extends string = string,
22
- Rest extends readonly PathDef[] = readonly PathDef[],
23
- > = { kind: 'slot'; name: Name; uuid: Uuid; rest: Rest }
25
+ List extends readonly PathDef[] = readonly PathDef[],
26
+ > = { kind: 'slot'; name: Name; uuid: Uuid; list: List }
24
27
 
25
28
  type Wrap<
26
29
  Name extends string = string,
27
30
  Uuid extends string = string,
28
- Rest extends readonly PathDef[] = readonly PathDef[],
31
+ List extends readonly PathDef[] = readonly PathDef[],
29
32
  Args = unknown,
30
- > = { kind: 'wrap'; name: Name; uuid: Uuid; rest: Rest; when: (args: Args) => boolean }
33
+ > = { kind: 'wrap'; name: Name; uuid: Uuid; list: List; when: (args: Args) => boolean }
31
34
 
32
- type SlotDef =
33
- | Path<string, readonly PathDef[]>
34
- | Slot<string, readonly PathDef[]>
35
- | Wrap<string, readonly PathDef[], any>
36
- type PathDef = SlotDef | Keep
35
+ type Pick<
36
+ Name extends string = string,
37
+ Uuid extends string = string,
38
+ Mode extends Record<string, readonly Segment[]> = Record<string, readonly Segment[]>,
39
+ List extends readonly PathDef[] = readonly PathDef[],
40
+ > = { kind: 'pick'; name: Name; uuid: Uuid; mode: Mode; list: List }
41
+
42
+ type Base<
43
+ Segs extends Segment | readonly Segment[] = Segment | readonly Segment[],
44
+ List extends readonly PathDef[] = readonly PathDef[],
45
+ > = { kind: 'base'; segs: Segs; list: List }
46
+ type PathDef = Path | Slot | Wrap | Pick | Keep | Base<any>
37
47
 
38
48
  // ---------- Type-level route builder ----------
39
- interface Whenable {
49
+ type PickKey<M> = Extract<keyof M, string>
50
+ type List<Defs extends readonly PathDef[]> = Defs[number]
51
+ type CallIfKeep<U, Props> =
52
+ Extract<U, Keep> extends never ? Props : ((search?: SParams) => string) & Props
53
+ type WithWhen<T> = T & {
40
54
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
41
55
  $join(seg: Segment | readonly Segment[]): this
42
56
  }
57
+ type ExpandBase<U> =
58
+ U extends Base<any, infer L extends readonly PathDef[]>
59
+ ? ExpandBase<Exclude<L[number], Keep>>
60
+ : U
43
61
 
44
- type HasKeep<Rest extends readonly PathDef[]> =
45
- Extract<Rest[number], Keep> extends never ? false : true
62
+ type VisibleChild<Defs extends readonly PathDef[]> = ExpandBase<Exclude<List<Defs>, Keep>>
46
63
 
47
- type NonKeepChildren<Rest extends readonly PathDef[]> = Exclude<Rest[number], Keep>
48
-
49
- type PropsFromChildren<Rest extends readonly PathDef[]> = {
50
- [C in NonKeepChildren<Rest> as C extends { name: infer N extends string }
51
- ? N
64
+ type PropsFromChildren<Defs extends readonly PathDef[]> = {
65
+ [C in VisibleChild<Defs> as C extends { uuid: infer N extends string }
66
+ ? ToCamelCase<N>
52
67
  : never]: C extends Path<any, any, any>
53
68
  ? RouteFromPath<C>
54
69
  : C extends Slot<any, any, any>
55
70
  ? RouteFromSlot<C>
56
71
  : C extends Wrap<any, any, any, any>
57
72
  ? RouteFromWrap<C>
58
- : never
73
+ : C extends Pick<any, any, any, any>
74
+ ? RouteFromPick<C>
75
+ : never
59
76
  }
60
77
 
61
- type WithWhen<T> = T & Whenable
62
-
63
- // Example: apply it to the outputs
64
- type RouteFromPath<N extends Path<any, any, any>> = WithWhen<
65
- N['rest'] extends readonly []
78
+ type RouteFromPath<Node extends Path<any, any, any>> = WithWhen<
79
+ Node['list'] extends readonly []
66
80
  ? (search?: SParams) => string
67
- : HasKeep<N['rest']> extends true
68
- ? ((search?: SParams) => string) & PropsFromChildren<N['rest']>
69
- : PropsFromChildren<N['rest']>
81
+ : CallIfKeep<List<Node['list']>, PropsFromChildren<Node['list']>>
70
82
  >
71
83
 
72
- type SlotResult<Rest extends readonly PathDef[]> = WithWhen<
73
- Rest extends readonly []
84
+ type RouteFromSlot<Node extends Slot<any, any, any>> = (param: Segment) => SlotResult<Node['list']>
85
+ type SlotResult<Defs extends readonly PathDef[]> = WithWhen<
86
+ Defs extends readonly []
74
87
  ? (search?: SParams) => string
75
- : HasKeep<Rest> extends true
76
- ? ((search?: SParams) => string) & PropsFromChildren<Rest>
77
- : PropsFromChildren<Rest>
88
+ : CallIfKeep<List<Defs>, PropsFromChildren<Defs>>
78
89
  >
79
90
 
80
- type RouteFromSlot<I extends Slot<any, any, any>> = (param: Segment) => SlotResult<I['rest']>
91
+ type RouteFromWrap<W extends Wrap<any, any, any, any>> = (
92
+ arg: Parameters<W['when']>[0]
93
+ ) => WithWhen<CallIfKeep<List<W['list']>, PropsFromChildren<W['list']>>>
81
94
 
82
- type WrapArg<W extends Wrap<any, any, any, any>> = Parameters<W['when']>[0]
83
-
84
- type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
85
- HasKeep<Rest> extends true
86
- ? ((search?: SParams) => string) & PropsFromChildren<Rest>
87
- : PropsFromChildren<Rest>
88
- >
89
-
90
- type RouteFromWrap<W extends Wrap<any, any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
95
+ type RouteFromPick<P extends Pick<any, any, any, any>> = (
96
+ val: PickKey<P['mode']>
97
+ ) => RoutesFromDefs<P['list']>
91
98
 
92
99
  type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
93
- HasKeep<Defs> extends true
94
- ? ((search?: SParams) => string) & PropsFromChildren<Defs>
95
- : PropsFromChildren<Defs>
100
+ CallIfKeep<List<Defs>, PropsFromChildren<Defs>>
96
101
  >
97
102
 
98
- type KeyFromSeg<S extends string> = KebabToCamel<S>;
99
103
  declare const keep: () => Keep;
100
- declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, KeyFromSeg<Name>, Rest>;
101
- declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, KeyFromSeg<Name>, Rest>;
102
- declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, KeyFromSeg<Name>, Rest, Args>;
103
- declare function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs>;
104
-
105
- export { keep, path, root, slot, wrap };
104
+ declare const path: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Path<Name, ToCamelCase<Name>, List>;
105
+ declare const slot: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Slot<Name, `$${ToCamelCase<Name>}`, List>;
106
+ declare const wrap: <const Name extends string, const List extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, list?: List) => Wrap<Name, `$${ToCamelCase<Name>}`, List, Args>;
107
+ declare const pick: <const Name extends string, const Mode extends Record<string, readonly Segment[]>, const List extends readonly PathDef[] = readonly []>(name: Name, mode: Mode, list?: List) => Pick<Name, `$${ToCamelCase<Name>}`, Mode, List>;
108
+ declare const base: <const Segs extends Segment | readonly Segment[], const List extends readonly PathDef[] = readonly []>(segs: Segs, list?: List) => Base<Segs, List>;
109
+ declare const root: <const Defs extends readonly PathDef[]>(defs: Defs) => RoutesFromDefs<Defs>;
110
+
111
+ export { base, keep, path, pick, root, slot, wrap };
package/dist/api.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // ---------- Helpers ----------------------
2
- type KebabToCamel<S extends string> = S extends `${infer A}-${infer B}`
3
- ? `${A}${Capitalize<KebabToCamel<B>>}`
2
+ type Delimiter = '_' | '-'
3
+ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}`
4
+ ? A extends ''
5
+ ? ToCamelCase<B>
6
+ : `${A}${Capitalize<ToCamelCase<B>>}`
4
7
  : S
5
8
 
6
9
  // ---------- Shared public types ----------
@@ -13,93 +16,96 @@ type Keep = { kind: 'keep' }
13
16
  type Path<
14
17
  Name extends string = string,
15
18
  Uuid extends string = string,
16
- Rest extends readonly PathDef[] = readonly PathDef[],
17
- > = { kind: 'path'; name: Name; uuid: Uuid; rest: Rest }
19
+ List extends readonly PathDef[] = readonly PathDef[],
20
+ > = { kind: 'path'; name: Name; uuid: Uuid; list: List }
18
21
 
19
22
  type Slot<
20
23
  Name extends string = string,
21
24
  Uuid extends string = string,
22
- Rest extends readonly PathDef[] = readonly PathDef[],
23
- > = { kind: 'slot'; name: Name; uuid: Uuid; rest: Rest }
25
+ List extends readonly PathDef[] = readonly PathDef[],
26
+ > = { kind: 'slot'; name: Name; uuid: Uuid; list: List }
24
27
 
25
28
  type Wrap<
26
29
  Name extends string = string,
27
30
  Uuid extends string = string,
28
- Rest extends readonly PathDef[] = readonly PathDef[],
31
+ List extends readonly PathDef[] = readonly PathDef[],
29
32
  Args = unknown,
30
- > = { kind: 'wrap'; name: Name; uuid: Uuid; rest: Rest; when: (args: Args) => boolean }
33
+ > = { kind: 'wrap'; name: Name; uuid: Uuid; list: List; when: (args: Args) => boolean }
31
34
 
32
- type SlotDef =
33
- | Path<string, readonly PathDef[]>
34
- | Slot<string, readonly PathDef[]>
35
- | Wrap<string, readonly PathDef[], any>
36
- type PathDef = SlotDef | Keep
35
+ type Pick<
36
+ Name extends string = string,
37
+ Uuid extends string = string,
38
+ Mode extends Record<string, readonly Segment[]> = Record<string, readonly Segment[]>,
39
+ List extends readonly PathDef[] = readonly PathDef[],
40
+ > = { kind: 'pick'; name: Name; uuid: Uuid; mode: Mode; list: List }
41
+
42
+ type Base<
43
+ Segs extends Segment | readonly Segment[] = Segment | readonly Segment[],
44
+ List extends readonly PathDef[] = readonly PathDef[],
45
+ > = { kind: 'base'; segs: Segs; list: List }
46
+ type PathDef = Path | Slot | Wrap | Pick | Keep | Base<any>
37
47
 
38
48
  // ---------- Type-level route builder ----------
39
- interface Whenable {
49
+ type PickKey<M> = Extract<keyof M, string>
50
+ type List<Defs extends readonly PathDef[]> = Defs[number]
51
+ type CallIfKeep<U, Props> =
52
+ Extract<U, Keep> extends never ? Props : ((search?: SParams) => string) & Props
53
+ type WithWhen<T> = T & {
40
54
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
41
55
  $join(seg: Segment | readonly Segment[]): this
42
56
  }
57
+ type ExpandBase<U> =
58
+ U extends Base<any, infer L extends readonly PathDef[]>
59
+ ? ExpandBase<Exclude<L[number], Keep>>
60
+ : U
43
61
 
44
- type HasKeep<Rest extends readonly PathDef[]> =
45
- Extract<Rest[number], Keep> extends never ? false : true
62
+ type VisibleChild<Defs extends readonly PathDef[]> = ExpandBase<Exclude<List<Defs>, Keep>>
46
63
 
47
- type NonKeepChildren<Rest extends readonly PathDef[]> = Exclude<Rest[number], Keep>
48
-
49
- type PropsFromChildren<Rest extends readonly PathDef[]> = {
50
- [C in NonKeepChildren<Rest> as C extends { name: infer N extends string }
51
- ? N
64
+ type PropsFromChildren<Defs extends readonly PathDef[]> = {
65
+ [C in VisibleChild<Defs> as C extends { uuid: infer N extends string }
66
+ ? ToCamelCase<N>
52
67
  : never]: C extends Path<any, any, any>
53
68
  ? RouteFromPath<C>
54
69
  : C extends Slot<any, any, any>
55
70
  ? RouteFromSlot<C>
56
71
  : C extends Wrap<any, any, any, any>
57
72
  ? RouteFromWrap<C>
58
- : never
73
+ : C extends Pick<any, any, any, any>
74
+ ? RouteFromPick<C>
75
+ : never
59
76
  }
60
77
 
61
- type WithWhen<T> = T & Whenable
62
-
63
- // Example: apply it to the outputs
64
- type RouteFromPath<N extends Path<any, any, any>> = WithWhen<
65
- N['rest'] extends readonly []
78
+ type RouteFromPath<Node extends Path<any, any, any>> = WithWhen<
79
+ Node['list'] extends readonly []
66
80
  ? (search?: SParams) => string
67
- : HasKeep<N['rest']> extends true
68
- ? ((search?: SParams) => string) & PropsFromChildren<N['rest']>
69
- : PropsFromChildren<N['rest']>
81
+ : CallIfKeep<List<Node['list']>, PropsFromChildren<Node['list']>>
70
82
  >
71
83
 
72
- type SlotResult<Rest extends readonly PathDef[]> = WithWhen<
73
- Rest extends readonly []
84
+ type RouteFromSlot<Node extends Slot<any, any, any>> = (param: Segment) => SlotResult<Node['list']>
85
+ type SlotResult<Defs extends readonly PathDef[]> = WithWhen<
86
+ Defs extends readonly []
74
87
  ? (search?: SParams) => string
75
- : HasKeep<Rest> extends true
76
- ? ((search?: SParams) => string) & PropsFromChildren<Rest>
77
- : PropsFromChildren<Rest>
88
+ : CallIfKeep<List<Defs>, PropsFromChildren<Defs>>
78
89
  >
79
90
 
80
- type RouteFromSlot<I extends Slot<any, any, any>> = (param: Segment) => SlotResult<I['rest']>
91
+ type RouteFromWrap<W extends Wrap<any, any, any, any>> = (
92
+ arg: Parameters<W['when']>[0]
93
+ ) => WithWhen<CallIfKeep<List<W['list']>, PropsFromChildren<W['list']>>>
81
94
 
82
- type WrapArg<W extends Wrap<any, any, any, any>> = Parameters<W['when']>[0]
83
-
84
- type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
85
- HasKeep<Rest> extends true
86
- ? ((search?: SParams) => string) & PropsFromChildren<Rest>
87
- : PropsFromChildren<Rest>
88
- >
89
-
90
- type RouteFromWrap<W extends Wrap<any, any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
95
+ type RouteFromPick<P extends Pick<any, any, any, any>> = (
96
+ val: PickKey<P['mode']>
97
+ ) => RoutesFromDefs<P['list']>
91
98
 
92
99
  type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
93
- HasKeep<Defs> extends true
94
- ? ((search?: SParams) => string) & PropsFromChildren<Defs>
95
- : PropsFromChildren<Defs>
100
+ CallIfKeep<List<Defs>, PropsFromChildren<Defs>>
96
101
  >
97
102
 
98
- type KeyFromSeg<S extends string> = KebabToCamel<S>;
99
103
  declare const keep: () => Keep;
100
- declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, KeyFromSeg<Name>, Rest>;
101
- declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, KeyFromSeg<Name>, Rest>;
102
- declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, KeyFromSeg<Name>, Rest, Args>;
103
- declare function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs>;
104
-
105
- export { keep, path, root, slot, wrap };
104
+ declare const path: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Path<Name, ToCamelCase<Name>, List>;
105
+ declare const slot: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Slot<Name, `$${ToCamelCase<Name>}`, List>;
106
+ declare const wrap: <const Name extends string, const List extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, list?: List) => Wrap<Name, `$${ToCamelCase<Name>}`, List, Args>;
107
+ declare const pick: <const Name extends string, const Mode extends Record<string, readonly Segment[]>, const List extends readonly PathDef[] = readonly []>(name: Name, mode: Mode, list?: List) => Pick<Name, `$${ToCamelCase<Name>}`, Mode, List>;
108
+ declare const base: <const Segs extends Segment | readonly Segment[], const List extends readonly PathDef[] = readonly []>(segs: Segs, list?: List) => Base<Segs, List>;
109
+ declare const root: <const Defs extends readonly PathDef[]>(defs: Defs) => RoutesFromDefs<Defs>;
110
+
111
+ export { base, keep, path, pick, root, slot, wrap };
package/dist/api.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a,b,c,d,e}from"./chunk-5ZW66SPO.js";export{a as keep,b as path,e as root,c as slot,d as wrap};
1
+ import{a,b,c,d,e,f,g}from"./chunk-3GHZA2PG.js";export{f as base,a as keep,b as path,e as pick,g as root,c as slot,d as wrap};
2
2
  //# sourceMappingURL=api.js.map
@@ -0,0 +1,2 @@
1
+ var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(n,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(n,s)=>s.toUpperCase()),k=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,n){if(e==="path"&&n==="")return n.trim();if(!n)throw new Error(`${e} name cannot be empty`);if(!k.test(n))throw new Error(`${e} name "${n}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return n.trim()}var h=e=>Array.isArray(e)?e:[e],$=()=>({kind:"keep"}),f=(e,n)=>({kind:"path",name:g("path",e),uuid:p(e),list:n??[]}),w=(e,n)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:n??[]}),x=(e,n,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:n,list:s??[]}),N=(e,n,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:n,list:s??[]}),D=(e,n)=>({kind:"base",segs:e,list:n??[]}),b=e=>l([],f("",e)),y=(e,n)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${n?`?${n}`:""}`;function l(e,n){let s=t=>t.list.some(o=>o.kind==="keep"),a=n.kind==="path"&&n.name?[...e,n.name]:e,i=c(s(n),a);for(let t of n.list){if(t.kind!=="keep"&&t.uuid in i)throw new Error(`Duplicate uuid "${String(t.uuid)}" under "${a.join("/")||"/"}"`);if(t.kind==="base"){let o=[...a,...h(t.segs)],d=l(o,f("",t.list));for(let r of Reflect.ownKeys(d)){if(r==="$when"||r==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,r);if(m?.enumerable){if(r in i)throw new Error(`base() merge collision on key "${String(r)}" under "${a.join("/")||"/"}"`);Object.defineProperty(i,r,m)}}}else if(t.kind==="slot")i[t.uuid]=function(d){let r=[...a,d];return t.list.length===0?u(c(!0,r),r,[]):Object.assign(c(s(t),r),l(r,t))};else if(t.kind==="path")if(t.list.length===0){let o=[...a,t.name];i[t.uuid]=u(c(!0,o),o,[])}else i[t.uuid]=l(a,t);else t.kind==="wrap"?i[t.uuid]=function(d){let m=t.when(d)?[...a,t.name]:a,S=l(m,t);return Object.assign(c(s(t),m),S)}:t.kind==="pick"&&(i[t.uuid]=o=>{if(t.mode[o])return l([...a,...t.mode[o]],f("",t.list));throw new Error(`pick("${t.name}") got unknown value: ${String(o)}`)})}return u(i,a,n.list)}function u(e,n,s){let a=(i,t)=>{let o=i?[...n,...h(t)]:n;return s.length===0&&typeof e=="function"?u(c(!0,o),o,s):l(o,f("",s))};return e.$when=a,e.$join=function(t){return a(!0,t)},e}var c=(e,n)=>e?s=>y(n,s):Object.create(null);export{$ as a,f as b,w as c,x as d,N as e,D as f,b as g};
2
+ //# sourceMappingURL=chunk-3GHZA2PG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"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","names":["toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","keep","path","list","slot","wrap","when","pick","mode","base","segs","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of k(e))!D.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=w(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{base:()=>h,bind:()=>y,link:()=>P,mask:()=>N,node:()=>d});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?b=>m(i,b):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={base,bind,link,mask,node});
1
+ "use strict";var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)h(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!P.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(a=D(t,o))||a.enumerable});return e};var A=e=>j(h({},"__esModule",{value:!0}),e);var E={};C(E,{base:()=>x,bind:()=>y,call:()=>S,link:()=>N,mask:()=>$,node:()=>m,pick:()=>w});module.exports=A(E);var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),T=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!T.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var k=e=>Array.isArray(e)?e:[e],S=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),y=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),$=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),w=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),x=(e,t)=>({kind:"base",segs:e,list:t??[]}),N=e=>l([],m("",e)),_=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${t}`:""}`;function l(e,t){let s=n=>n.list.some(i=>i.kind==="keep"),a=t.kind==="path"&&t.name?[...e,t.name]:e,o=c(s(t),a);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="base"){let i=[...a,...k(n.segs)],d=l(i,m("",n.list));for(let r of Reflect.ownKeys(d)){if(r==="$when"||r==="$join")continue;let u=Object.getOwnPropertyDescriptor(d,r);if(u?.enumerable){if(r in o)throw new Error(`base() merge collision on key "${String(r)}" under "${a.join("/")||"/"}"`);Object.defineProperty(o,r,u)}}}else if(n.kind==="slot")o[n.uuid]=function(d){let r=[...a,d];return n.list.length===0?f(c(!0,r),r,[]):Object.assign(c(s(n),r),l(r,n))};else if(n.kind==="path")if(n.list.length===0){let i=[...a,n.name];o[n.uuid]=f(c(!0,i),i,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(d){let u=n.when(d)?[...a,n.name]:a,b=l(u,n);return Object.assign(c(s(n),u),b)}:n.kind==="pick"&&(o[n.uuid]=i=>{if(n.mode[i])return l([...a,...n.mode[i]],m("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(i)}`)})}return f(o,a,t.list)}function f(e,t,s){let a=(o,n)=>{let i=o?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,i),i,s):l(i,m("",s))};return e.$when=a,e.$join=function(n){return a(!0,n)},e}var c=(e,t)=>e?s=>_(t,s):Object.create(null);0&&(module.exports={base,bind,call,link,mask,node,pick});
2
2
  //# sourceMappingURL=dialect-node.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dialect-node.ts","../src/api.ts"],"sourcesContent":["export { root as link, path as node, slot as bind, keep as base, wrap as mask } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAP,GCcA,IAAMQ,EAAWC,GAAcA,EAAE,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAIxEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBC,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAInBH,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaG,EAAO,CAKnBJ,EACAK,EACAJ,KAC+C,CAC/C,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAAK,EACA,KAAOJ,GAAQ,CAAC,CACjB,GAEMK,EAAQ,2BAEd,SAASJ,EACRK,EACAP,EACO,CAEP,GAAIO,IAAS,QAAUP,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGO,CAAI,uBAAuB,EACzD,GAAI,CAACD,EAAM,KAAKN,CAAI,EACnB,MAAM,IAAI,MACT,GAAGO,CAAI,UAAUP,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAGA,IAAMQ,EAAM,CAACT,EAAiBU,IAC7B,IAAIV,EAAK,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,QAAQ,WAAa,GAAG,CAAC,GAAGU,EAAS,IAAIA,CAAM,GAAK,EAAE,GAGnF,SAASC,EAA4CC,EAAkC,CAC7F,OAAOC,EAAU,CAAC,EAAGb,EAAK,GAAIY,CAAI,CAAC,CACpC,CAEA,SAASC,EAAUC,EAAmBC,EAAc,CACnD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMnB,GAAWA,EAAE,OAAS,MAAM,EAC/EoB,EACLH,EAAI,OAAS,QAAUA,EAAI,OAAS,OACjCD,EACAC,EAAI,KACH,CAAC,GAAGD,EAAQC,EAAI,IAAI,EACpBD,EAGCK,EAAcH,EAAQD,CAAG,EAC3BL,GAAqBD,EAAIS,EAASR,CAAM,EACzC,OAAO,OAAO,IAAI,EAErB,QAAWU,KAASL,EAAI,KACvB,GAAIK,EAAM,OAAS,OACdA,EAAM,KAAK,SAAW,EACzBD,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CACxC,IAAMC,EAAW,CAAC,GAAGJ,EAASG,CAAK,EAEnC,OAAOE,EADUb,GAAqBD,EAAIa,EAAUZ,CAAM,EAC7BY,EAAU,CAAC,CAAC,CAC1C,EAEAH,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CAGxC,IAAMG,EAAUX,EAAU,CAAC,GAAGK,EAASG,CAAK,EAAGD,CAAK,EAGpD,OAAO,OAAO,OACbJ,EAAQI,CAAK,EACTV,GAAqBD,EAAI,CAAC,GAAGS,EAASG,CAAK,EAAGX,CAAM,EACrD,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,UAESJ,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAME,EAAW,CAAC,GAAGJ,EAASE,EAAM,IAAI,EAClCK,EAAWf,GAAqBD,EAAIa,EAAUZ,CAAM,EAC1DS,EAAOC,EAAM,IAAI,EAAIG,EAAkBE,EAAIH,EAAU,CAAC,CAAC,CACxD,MACCH,EAAOC,EAAM,IAAI,EAAIP,EAAUK,EAASE,CAAK,OAEpCA,EAAM,OAAS,SACzBD,EAAOC,EAAM,IAAI,EAAKM,GAAiB,CAEtC,IAAMC,EADUP,EAAM,KAAKM,CAAG,EACJ,CAAC,GAAGR,EAASE,EAAM,IAAI,EAAIF,EAC/CM,EAAUX,EAAUc,EAASP,CAAY,EAE/C,OAAO,OAAO,OAEbJ,EAAQI,CAAY,EAChBV,GAAqBD,EAAIkB,EAASjB,CAAM,EACzC,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,GAIF,OAAOD,EAAkBJ,EAAQD,EAASH,EAAI,IAAI,CACnD,CAEA,SAASQ,EAAkBJ,EAAaS,EAAqB1B,EAA0B,CACtF,IAAMI,EAAO,CAACuB,EAAeC,IAAsC,CAClE,IAAMC,EAAWF,EAAO,CAAC,GAAGD,EAAU,GAAI,MAAM,QAAQE,CAAG,EAAIA,EAAM,CAACA,CAAG,CAAE,EAAIF,EAG/E,OAAI1B,EAAK,SAAW,GAAK,OAAOiB,GAAW,WAEnCI,EADYb,GAAqBD,EAAIsB,EAAUrB,CAAM,EAC7BqB,EAAU7B,CAAI,EAKvCW,EAAUkB,EAAU/B,EAAK,GAAIE,CAAI,CAAC,CAC1C,EAEA,OAAAiB,EAAO,MAAQb,EACfa,EAAO,MAASW,GAAsCxB,EAAK,GAAMwB,CAAG,EAE7DX,CACR","names":["dialect_node_exports","__export","keep","slot","root","wrap","path","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
1
+ {"version":3,"sources":["../src/dialect-node.ts","../src/api.ts"],"sourcesContent":["export {\n\troot as link,\n\tpath as node,\n\tslot as bind,\n\tkeep as call,\n\twrap as mask,\n\tpick,\n\tbase,\n} from './api'\n","import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAT,GCgBA,IAAMU,EAAiCC,GACtCA,EACE,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EACpD,QAAQ,kBAAmB,CAACD,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAEjDC,EAAQ,6BAEd,SAASC,EACRC,EACAC,EACO,CAEP,GAAID,IAAS,QAAUC,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGD,CAAI,uBAAuB,EACzD,GAAI,CAACF,EAAM,KAAKG,CAAI,EACnB,MAAM,IAAI,MACT,GAAGD,CAAI,UAAUC,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAEA,IAAMC,EAAUC,GAAuC,MAAM,QAAQA,CAAG,EAAIA,EAAM,CAACA,CAAG,EAGzEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBJ,EACAK,KAC0C,CAC1C,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAMP,EAAYO,CAAI,EACtB,KAAOK,GAAQ,CAAC,CACjB,GAEaC,EAAO,CAInBN,EACAK,KACgD,CAChD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAOK,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAKnBP,EACAQ,EACAH,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAQ,EACA,KAAOH,GAAQ,CAAC,CACjB,GAEaI,EAAO,CAKnBT,EACAU,EACAL,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAU,EACA,KAAOL,GAAQ,CAAC,CACjB,GAEaM,EAAO,CAInBC,EACAP,KACuB,CAAE,KAAM,OAAQ,KAAAO,EAAM,KAAOP,GAAQ,CAAC,CAAW,GAE5DQ,EAA+CC,GAC3DC,EAAU,CAAC,EAAGX,EAAK,GAAIU,CAAI,CAAC,EAGvBE,EAAM,CAACZ,EAAiBa,IAC7B,IAAIb,EACF,OAAO,OAAO,EACd,KAAK,GAAG,EACR,QAAQ,UAAW,GAAG,CAAC,GAAGa,EAAS,IAAIA,CAAM,GAAK,EAAE,GAEvD,SAASF,EAAUG,EAAmBC,EAAiB,CACtD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMC,GAAcA,EAAK,OAAS,MAAM,EACrFC,EAAUJ,EAAO,OAAS,QAAUA,EAAO,KAAO,CAAC,GAAGD,EAAQC,EAAO,IAAI,EAAID,EAG7EM,EAAcC,EAAWL,EAAQD,CAAM,EAAGI,CAAO,EAEvD,QAAWG,KAASP,EAAO,KAAM,CAChC,GAAIO,EAAM,OAAS,QACdA,EAAM,QAAQF,EACjB,MAAM,IAAI,MACT,mBAAmB,OAAOE,EAAM,IAAI,CAAC,YAAYH,EAAQ,KAAK,GAAG,GAAK,GAAG,GAC1E,EAIF,GAAIG,EAAM,OAAS,OAAQ,CAC1B,IAAMC,EAAa,CAAC,GAAGJ,EAAS,GAAGtB,EAAOyB,EAAM,IAAI,CAAC,EAC/CE,EAAWb,EAAUY,EAAYvB,EAAK,GAAIsB,EAAM,IAAI,CAAC,EAE3D,QAAWG,KAAO,QAAQ,QAAQD,CAAG,EAAG,CACvC,GAAIC,IAAQ,SAAWA,IAAQ,QAAS,SACxC,IAAMC,EAAO,OAAO,yBAAyBF,EAAKC,CAAG,EACrD,GAAKC,GAAM,WAEX,IAAID,KAAOL,EACV,MAAM,IAAI,MACT,kCAAkC,OAAOK,CAAG,CAAC,YAAYN,EAAQ,KAAK,GAAG,GAAK,GAAG,GAClF,EAED,OAAO,eAAeC,EAAQK,EAAKC,CAAI,EACxC,CACD,SAAWJ,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcK,EAAgB,CAClD,IAAMC,EAAO,CAAC,GAAGT,EAASQ,CAAK,EAG/B,OAAIL,EAAM,KAAK,SAAW,EAClBO,EAAkBR,EAAW,GAAMO,CAAI,EAAGA,EAAM,CAAC,CAAC,EAInD,OAAO,OAAOP,EAAWL,EAAQM,CAAK,EAAGM,CAAI,EAAGjB,EAAUiB,EAAMN,CAAK,CAAC,CAC9E,UACUA,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAMQ,EAAW,CAAC,GAAGX,EAASG,EAAM,IAAI,EACxCF,EAAOE,EAAM,IAAI,EAAIO,EAAkBR,EAAW,GAAMS,CAAQ,EAAGA,EAAU,CAAC,CAAC,CAChF,MACCV,EAAOE,EAAM,IAAI,EAAIX,EAAUQ,EAASG,CAAK,OAEpCA,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcS,EAAc,CAEhD,IAAMC,EADUV,EAAM,KAAKS,CAAG,EACJ,CAAC,GAAGZ,EAASG,EAAM,IAAI,EAAIH,EAC/Cc,EAAUtB,EAAUqB,EAASV,CAAK,EAExC,OAAO,OAAO,OAAOD,EAAWL,EAAQM,CAAK,EAAGU,CAAO,EAAGC,CAAO,CAClE,EACUX,EAAM,OAAS,SACzBF,EAAOE,EAAM,IAAI,EAAKY,GAAmC,CACxD,GAAIZ,EAAM,KAAKY,CAAK,EACnB,OAAOvB,EAAU,CAAC,GAAGQ,EAAS,GAAGG,EAAM,KAAKY,CAAK,CAAC,EAAGlC,EAAK,GAAIsB,EAAM,IAAI,CAAC,EAEzE,MAAM,IAAI,MAAM,SAASA,EAAM,IAAI,yBAAyB,OAAOY,CAAK,CAAC,EAAE,CAE7E,EAEF,CAEA,OAAOL,EAAkBT,EAAQD,EAASJ,EAAO,IAAI,CACtD,CAEA,SAASc,EAAkBT,EAAae,EAAqBlC,EAA0B,CACtF,IAAMG,EAAO,CAACgC,EAAetC,IAAsC,CAClE,IAAMuC,EAAWD,EAAO,CAAC,GAAGD,EAAU,GAAGtC,EAAOC,CAAG,CAAC,EAAIqC,EAGxD,OAAIlC,EAAK,SAAW,GAAK,OAAOmB,GAAW,WACnCS,EAAkBR,EAAW,GAAMgB,CAAQ,EAAGA,EAAUpC,CAAI,EAK7DU,EAAU0B,EAAUrC,EAAK,GAAIC,CAAI,CAAC,CAC1C,EAEA,OAAAmB,EAAO,MAAQhB,EACfgB,EAAO,MAAQ,SAActB,EAAmC,CAC/D,OAAOM,EAAK,GAAMN,CAAG,CACtB,EAEOsB,CACR,CAEA,IAAMC,EAAa,CAACiB,EAAmBC,IAC/BD,EAAYzB,GAAqBD,EAAI2B,EAAa1B,CAAM,EAAI,OAAO,OAAO,IAAI","names":["dialect_node_exports","__export","base","slot","keep","root","wrap","path","pick","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","keep","path","list","slot","wrap","when","pick","mode","base","segs","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { keep as base, slot as bind, root as link, wrap as mask, path as node } from './api.cjs';
1
+ export { base, slot as bind, keep as call, root as link, wrap as mask, path as node, pick } from './api.cjs';
@@ -1 +1 @@
1
- export { keep as base, slot as bind, root as link, wrap as mask, path as node } from './api.js';
1
+ export { base, slot as bind, keep as call, root as link, wrap as mask, path as node, pick } from './api.js';
@@ -1,2 +1,2 @@
1
- import{a,b as s,c as o,d as e,e as p}from"./chunk-5ZW66SPO.js";export{a as base,o as bind,p as link,e as mask,s as node};
1
+ import{a,b as s,c as o,d as e,e as p,f as k,g as l}from"./chunk-3GHZA2PG.js";export{k as base,o as bind,a as call,l as link,e as mask,s as node,p as pick};
2
2
  //# sourceMappingURL=dialect-node.js.map
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=b(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{keep:()=>h,path:()=>d,root:()=>P,slot:()=>y,wrap:()=>N});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?w=>m(i,w):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={keep,path,root,slot,wrap});
1
+ "use strict";var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)h(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!P.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(a=D(t,o))||a.enumerable});return e};var A=e=>j(h({},"__esModule",{value:!0}),e);var E={};C(E,{base:()=>x,keep:()=>S,path:()=>m,pick:()=>w,root:()=>N,slot:()=>y,wrap:()=>$});module.exports=A(E);var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),T=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!T.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var k=e=>Array.isArray(e)?e:[e],S=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),y=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),$=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),w=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),x=(e,t)=>({kind:"base",segs:e,list:t??[]}),N=e=>l([],m("",e)),_=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${t}`:""}`;function l(e,t){let s=n=>n.list.some(r=>r.kind==="keep"),a=t.kind==="path"&&t.name?[...e,t.name]:e,o=d(s(t),a);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="base"){let r=[...a,...k(n.segs)],c=l(r,m("",n.list));for(let i of Reflect.ownKeys(c)){if(i==="$when"||i==="$join")continue;let u=Object.getOwnPropertyDescriptor(c,i);if(u?.enumerable){if(i in o)throw new Error(`base() merge collision on key "${String(i)}" under "${a.join("/")||"/"}"`);Object.defineProperty(o,i,u)}}}else if(n.kind==="slot")o[n.uuid]=function(c){let i=[...a,c];return n.list.length===0?f(d(!0,i),i,[]):Object.assign(d(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];o[n.uuid]=f(d(!0,r),r,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(c){let u=n.when(c)?[...a,n.name]:a,b=l(u,n);return Object.assign(d(s(n),u),b)}:n.kind==="pick"&&(o[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],m("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(o,a,t.list)}function f(e,t,s){let a=(o,n)=>{let r=o?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(d(!0,r),r,s):l(r,m("",s))};return e.$when=a,e.$join=function(n){return a(!0,n)},e}var d=(e,t)=>e?s=>_(t,s):Object.create(null);0&&(module.exports={base,keep,path,pick,root,slot,wrap});
2
2
  //# sourceMappingURL=dialect-path.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dialect-path.ts","../src/api.ts"],"sourcesContent":["export { root, path, slot, keep, wrap } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_path_exports","__export","keep","path","root","slot","wrap","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
1
+ {"version":3,"sources":["../src/dialect-path.ts","../src/api.ts"],"sourcesContent":["export { root, path, slot, keep, wrap, pick, base } from './api'\n","import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAT,GCgBA,IAAMU,EAAiCC,GACtCA,EACE,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EACpD,QAAQ,kBAAmB,CAACD,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAEjDC,EAAQ,6BAEd,SAASC,EACRC,EACAC,EACO,CAEP,GAAID,IAAS,QAAUC,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGD,CAAI,uBAAuB,EACzD,GAAI,CAACF,EAAM,KAAKG,CAAI,EACnB,MAAM,IAAI,MACT,GAAGD,CAAI,UAAUC,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAEA,IAAMC,EAAUC,GAAuC,MAAM,QAAQA,CAAG,EAAIA,EAAM,CAACA,CAAG,EAGzEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBJ,EACAK,KAC0C,CAC1C,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAMP,EAAYO,CAAI,EACtB,KAAOK,GAAQ,CAAC,CACjB,GAEaC,EAAO,CAInBN,EACAK,KACgD,CAChD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAOK,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAKnBP,EACAQ,EACAH,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAQ,EACA,KAAOH,GAAQ,CAAC,CACjB,GAEaI,EAAO,CAKnBT,EACAU,EACAL,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAU,EACA,KAAOL,GAAQ,CAAC,CACjB,GAEaM,EAAO,CAInBC,EACAP,KACuB,CAAE,KAAM,OAAQ,KAAAO,EAAM,KAAOP,GAAQ,CAAC,CAAW,GAE5DQ,EAA+CC,GAC3DC,EAAU,CAAC,EAAGX,EAAK,GAAIU,CAAI,CAAC,EAGvBE,EAAM,CAACZ,EAAiBa,IAC7B,IAAIb,EACF,OAAO,OAAO,EACd,KAAK,GAAG,EACR,QAAQ,UAAW,GAAG,CAAC,GAAGa,EAAS,IAAIA,CAAM,GAAK,EAAE,GAEvD,SAASF,EAAUG,EAAmBC,EAAiB,CACtD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMC,GAAcA,EAAK,OAAS,MAAM,EACrFC,EAAUJ,EAAO,OAAS,QAAUA,EAAO,KAAO,CAAC,GAAGD,EAAQC,EAAO,IAAI,EAAID,EAG7EM,EAAcC,EAAWL,EAAQD,CAAM,EAAGI,CAAO,EAEvD,QAAWG,KAASP,EAAO,KAAM,CAChC,GAAIO,EAAM,OAAS,QACdA,EAAM,QAAQF,EACjB,MAAM,IAAI,MACT,mBAAmB,OAAOE,EAAM,IAAI,CAAC,YAAYH,EAAQ,KAAK,GAAG,GAAK,GAAG,GAC1E,EAIF,GAAIG,EAAM,OAAS,OAAQ,CAC1B,IAAMC,EAAa,CAAC,GAAGJ,EAAS,GAAGtB,EAAOyB,EAAM,IAAI,CAAC,EAC/CE,EAAWb,EAAUY,EAAYvB,EAAK,GAAIsB,EAAM,IAAI,CAAC,EAE3D,QAAWG,KAAO,QAAQ,QAAQD,CAAG,EAAG,CACvC,GAAIC,IAAQ,SAAWA,IAAQ,QAAS,SACxC,IAAMC,EAAO,OAAO,yBAAyBF,EAAKC,CAAG,EACrD,GAAKC,GAAM,WAEX,IAAID,KAAOL,EACV,MAAM,IAAI,MACT,kCAAkC,OAAOK,CAAG,CAAC,YAAYN,EAAQ,KAAK,GAAG,GAAK,GAAG,GAClF,EAED,OAAO,eAAeC,EAAQK,EAAKC,CAAI,EACxC,CACD,SAAWJ,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcK,EAAgB,CAClD,IAAMC,EAAO,CAAC,GAAGT,EAASQ,CAAK,EAG/B,OAAIL,EAAM,KAAK,SAAW,EAClBO,EAAkBR,EAAW,GAAMO,CAAI,EAAGA,EAAM,CAAC,CAAC,EAInD,OAAO,OAAOP,EAAWL,EAAQM,CAAK,EAAGM,CAAI,EAAGjB,EAAUiB,EAAMN,CAAK,CAAC,CAC9E,UACUA,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAMQ,EAAW,CAAC,GAAGX,EAASG,EAAM,IAAI,EACxCF,EAAOE,EAAM,IAAI,EAAIO,EAAkBR,EAAW,GAAMS,CAAQ,EAAGA,EAAU,CAAC,CAAC,CAChF,MACCV,EAAOE,EAAM,IAAI,EAAIX,EAAUQ,EAASG,CAAK,OAEpCA,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcS,EAAc,CAEhD,IAAMC,EADUV,EAAM,KAAKS,CAAG,EACJ,CAAC,GAAGZ,EAASG,EAAM,IAAI,EAAIH,EAC/Cc,EAAUtB,EAAUqB,EAASV,CAAK,EAExC,OAAO,OAAO,OAAOD,EAAWL,EAAQM,CAAK,EAAGU,CAAO,EAAGC,CAAO,CAClE,EACUX,EAAM,OAAS,SACzBF,EAAOE,EAAM,IAAI,EAAKY,GAAmC,CACxD,GAAIZ,EAAM,KAAKY,CAAK,EACnB,OAAOvB,EAAU,CAAC,GAAGQ,EAAS,GAAGG,EAAM,KAAKY,CAAK,CAAC,EAAGlC,EAAK,GAAIsB,EAAM,IAAI,CAAC,EAEzE,MAAM,IAAI,MAAM,SAASA,EAAM,IAAI,yBAAyB,OAAOY,CAAK,CAAC,EAAE,CAE7E,EAEF,CAEA,OAAOL,EAAkBT,EAAQD,EAASJ,EAAO,IAAI,CACtD,CAEA,SAASc,EAAkBT,EAAae,EAAqBlC,EAA0B,CACtF,IAAMG,EAAO,CAACgC,EAAetC,IAAsC,CAClE,IAAMuC,EAAWD,EAAO,CAAC,GAAGD,EAAU,GAAGtC,EAAOC,CAAG,CAAC,EAAIqC,EAGxD,OAAIlC,EAAK,SAAW,GAAK,OAAOmB,GAAW,WACnCS,EAAkBR,EAAW,GAAMgB,CAAQ,EAAGA,EAAUpC,CAAI,EAK7DU,EAAU0B,EAAUrC,EAAK,GAAIC,CAAI,CAAC,CAC1C,EAEA,OAAAmB,EAAO,MAAQhB,EACfgB,EAAO,MAAQ,SAActB,EAAmC,CAC/D,OAAOM,EAAK,GAAMN,CAAG,CACtB,EAEOsB,CACR,CAEA,IAAMC,EAAa,CAACiB,EAAmBC,IAC/BD,EAAYzB,GAAqBD,EAAI2B,EAAa1B,CAAM,EAAI,OAAO,OAAO,IAAI","names":["dialect_path_exports","__export","base","keep","path","pick","root","slot","wrap","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","keep","path","list","slot","wrap","when","pick","mode","base","segs","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { keep, path, root, slot, wrap } from './api.cjs';
1
+ export { base, keep, path, pick, root, slot, wrap } from './api.cjs';
@@ -1 +1 @@
1
- export { keep, path, root, slot, wrap } from './api.js';
1
+ export { base, keep, path, pick, root, slot, wrap } from './api.js';
@@ -1,2 +1,2 @@
1
- import{a as o,b as p,c as r,d as t,e}from"./chunk-5ZW66SPO.js";export{o as keep,p as path,e as root,r as slot,t as wrap};
1
+ import{a as o,b as p,c as e,d as r,e as t,f as a,g as k}from"./chunk-3GHZA2PG.js";export{a as base,o as keep,p as path,t as pick,k as root,e as slot,r as wrap};
2
2
  //# sourceMappingURL=dialect-path.js.map
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=b(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{gate:()=>N,item:()=>y,make:()=>P,self:()=>h,step:()=>d});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?w=>m(i,w):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={gate,item,make,self,step});
1
+ "use strict";var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)h(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!P.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(a=D(t,o))||a.enumerable});return e};var A=e=>j(h({},"__esModule",{value:!0}),e);var E={};C(E,{base:()=>x,gate:()=>$,item:()=>y,make:()=>N,pick:()=>w,self:()=>S,step:()=>m});module.exports=A(E);var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),T=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!T.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var k=e=>Array.isArray(e)?e:[e],S=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),y=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),$=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),w=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),x=(e,t)=>({kind:"base",segs:e,list:t??[]}),N=e=>l([],m("",e)),_=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${t}`:""}`;function l(e,t){let s=n=>n.list.some(r=>r.kind==="keep"),a=t.kind==="path"&&t.name?[...e,t.name]:e,o=d(s(t),a);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="base"){let r=[...a,...k(n.segs)],c=l(r,m("",n.list));for(let i of Reflect.ownKeys(c)){if(i==="$when"||i==="$join")continue;let u=Object.getOwnPropertyDescriptor(c,i);if(u?.enumerable){if(i in o)throw new Error(`base() merge collision on key "${String(i)}" under "${a.join("/")||"/"}"`);Object.defineProperty(o,i,u)}}}else if(n.kind==="slot")o[n.uuid]=function(c){let i=[...a,c];return n.list.length===0?f(d(!0,i),i,[]):Object.assign(d(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];o[n.uuid]=f(d(!0,r),r,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(c){let u=n.when(c)?[...a,n.name]:a,b=l(u,n);return Object.assign(d(s(n),u),b)}:n.kind==="pick"&&(o[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],m("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(o,a,t.list)}function f(e,t,s){let a=(o,n)=>{let r=o?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(d(!0,r),r,s):l(r,m("",s))};return e.$when=a,e.$join=function(n){return a(!0,n)},e}var d=(e,t)=>e?s=>_(t,s):Object.create(null);0&&(module.exports={base,gate,item,make,pick,self,step});
2
2
  //# sourceMappingURL=dialect-step.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dialect-step.ts","../src/api.ts"],"sourcesContent":["export { root as make, path as step, slot as item, keep as self, wrap as gate } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAP,GCcA,IAAMQ,EAAWC,GAAcA,EAAE,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAIxEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBC,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAInBH,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaG,EAAO,CAKnBJ,EACAK,EACAJ,KAC+C,CAC/C,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAAK,EACA,KAAOJ,GAAQ,CAAC,CACjB,GAEMK,EAAQ,2BAEd,SAASJ,EACRK,EACAP,EACO,CAEP,GAAIO,IAAS,QAAUP,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGO,CAAI,uBAAuB,EACzD,GAAI,CAACD,EAAM,KAAKN,CAAI,EACnB,MAAM,IAAI,MACT,GAAGO,CAAI,UAAUP,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAGA,IAAMQ,EAAM,CAACT,EAAiBU,IAC7B,IAAIV,EAAK,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,QAAQ,WAAa,GAAG,CAAC,GAAGU,EAAS,IAAIA,CAAM,GAAK,EAAE,GAGnF,SAASC,EAA4CC,EAAkC,CAC7F,OAAOC,EAAU,CAAC,EAAGb,EAAK,GAAIY,CAAI,CAAC,CACpC,CAEA,SAASC,EAAUC,EAAmBC,EAAc,CACnD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMnB,GAAWA,EAAE,OAAS,MAAM,EAC/EoB,EACLH,EAAI,OAAS,QAAUA,EAAI,OAAS,OACjCD,EACAC,EAAI,KACH,CAAC,GAAGD,EAAQC,EAAI,IAAI,EACpBD,EAGCK,EAAcH,EAAQD,CAAG,EAC3BL,GAAqBD,EAAIS,EAASR,CAAM,EACzC,OAAO,OAAO,IAAI,EAErB,QAAWU,KAASL,EAAI,KACvB,GAAIK,EAAM,OAAS,OACdA,EAAM,KAAK,SAAW,EACzBD,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CACxC,IAAMC,EAAW,CAAC,GAAGJ,EAASG,CAAK,EAEnC,OAAOE,EADUb,GAAqBD,EAAIa,EAAUZ,CAAM,EAC7BY,EAAU,CAAC,CAAC,CAC1C,EAEAH,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CAGxC,IAAMG,EAAUX,EAAU,CAAC,GAAGK,EAASG,CAAK,EAAGD,CAAK,EAGpD,OAAO,OAAO,OACbJ,EAAQI,CAAK,EACTV,GAAqBD,EAAI,CAAC,GAAGS,EAASG,CAAK,EAAGX,CAAM,EACrD,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,UAESJ,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAME,EAAW,CAAC,GAAGJ,EAASE,EAAM,IAAI,EAClCK,EAAWf,GAAqBD,EAAIa,EAAUZ,CAAM,EAC1DS,EAAOC,EAAM,IAAI,EAAIG,EAAkBE,EAAIH,EAAU,CAAC,CAAC,CACxD,MACCH,EAAOC,EAAM,IAAI,EAAIP,EAAUK,EAASE,CAAK,OAEpCA,EAAM,OAAS,SACzBD,EAAOC,EAAM,IAAI,EAAKM,GAAiB,CAEtC,IAAMC,EADUP,EAAM,KAAKM,CAAG,EACJ,CAAC,GAAGR,EAASE,EAAM,IAAI,EAAIF,EAC/CM,EAAUX,EAAUc,EAASP,CAAY,EAE/C,OAAO,OAAO,OAEbJ,EAAQI,CAAY,EAChBV,GAAqBD,EAAIkB,EAASjB,CAAM,EACzC,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,GAIF,OAAOD,EAAkBJ,EAAQD,EAASH,EAAI,IAAI,CACnD,CAEA,SAASQ,EAAkBJ,EAAaS,EAAqB1B,EAA0B,CACtF,IAAMI,EAAO,CAACuB,EAAeC,IAAsC,CAClE,IAAMC,EAAWF,EAAO,CAAC,GAAGD,EAAU,GAAI,MAAM,QAAQE,CAAG,EAAIA,EAAM,CAACA,CAAG,CAAE,EAAIF,EAG/E,OAAI1B,EAAK,SAAW,GAAK,OAAOiB,GAAW,WAEnCI,EADYb,GAAqBD,EAAIsB,EAAUrB,CAAM,EAC7BqB,EAAU7B,CAAI,EAKvCW,EAAUkB,EAAU/B,EAAK,GAAIE,CAAI,CAAC,CAC1C,EAEA,OAAAiB,EAAO,MAAQb,EACfa,EAAO,MAASW,GAAsCxB,EAAK,GAAMwB,CAAG,EAE7DX,CACR","names":["dialect_step_exports","__export","wrap","slot","root","keep","path","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
1
+ {"version":3,"sources":["../src/dialect-step.ts","../src/api.ts"],"sourcesContent":["export {\n\troot as make,\n\tpath as step,\n\tslot as item,\n\tkeep as self,\n\twrap as gate,\n\tpick,\n\tbase,\n} from './api'\n","import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"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","names":["dialect_step_exports","__export","base","wrap","slot","root","pick","keep","path","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","keep","path","list","slot","wrap","when","pick","mode","base","segs","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { wrap as gate, slot as item, root as make, keep as self, path as step } from './api.cjs';
1
+ export { base, wrap as gate, slot as item, root as make, pick, keep as self, path as step } from './api.cjs';
@@ -1 +1 @@
1
- export { wrap as gate, slot as item, root as make, keep as self, path as step } from './api.js';
1
+ export { base, wrap as gate, slot as item, root as make, pick, keep as self, path as step } from './api.js';
@@ -1,2 +1,2 @@
1
- import{a,b as e,c as s,d as t,e as o}from"./chunk-5ZW66SPO.js";export{t as gate,s as item,o as make,a as self,e as step};
1
+ import{a,b as e,c as s,d as t,e as p,f as o,g as r}from"./chunk-3GHZA2PG.js";export{o as base,t as gate,s as item,r as make,p as pick,a as self,e as step};
2
2
  //# sourceMappingURL=dialect-step.js.map
@@ -1,2 +1,2 @@
1
- "use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(r=b(e,s))||r.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{grow:()=>w,nest:()=>N,seed:()=>y,tree:()=>d,twig:()=>h});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function w(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(o=>o.kind==="keep"),r=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(r,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=o=>{let l=[...r,o];return c(f=>m(l,f),l,[])}:s[n.uuid]=o=>{let l=u([...r,o],n);return Object.assign(a(n)?i=>m([...r,o],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let o=[...r,n.uuid],l=i=>m(o,i);s[n.uuid]=c(l,o,[])}else s[n.uuid]=u(r,n);else n.kind==="wrap"&&(s[n.uuid]=o=>{let i=n.when(o)?[...r,n.uuid]:r,f=u(i,n);return Object.assign(a(n)?P=>m(i,P):Object.create(null),f)});return c(s,r,e.rest)}function c(t,e,a){let r=(s,n)=>{let o=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(o,i),o,a):u(o,d("",a))};return t.$when=r,t.$join=s=>r(!0,s),t}0&&(module.exports={grow,nest,seed,tree,twig});
1
+ "use strict";var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)h(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!P.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(a=D(t,o))||a.enumerable});return e};var A=e=>j(h({},"__esModule",{value:!0}),e);var E={};C(E,{base:()=>x,grow:()=>N,nest:()=>$,pick:()=>w,seed:()=>y,tree:()=>m,twig:()=>S});module.exports=A(E);var p=e=>e.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),T=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!T.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var k=e=>Array.isArray(e)?e:[e],S=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),y=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),$=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),w=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),x=(e,t)=>({kind:"base",segs:e,list:t??[]}),N=e=>l([],m("",e)),_=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${t}`:""}`;function l(e,t){let s=n=>n.list.some(r=>r.kind==="keep"),a=t.kind==="path"&&t.name?[...e,t.name]:e,o=c(s(t),a);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="base"){let r=[...a,...k(n.segs)],d=l(r,m("",n.list));for(let i of Reflect.ownKeys(d)){if(i==="$when"||i==="$join")continue;let u=Object.getOwnPropertyDescriptor(d,i);if(u?.enumerable){if(i in o)throw new Error(`base() merge collision on key "${String(i)}" under "${a.join("/")||"/"}"`);Object.defineProperty(o,i,u)}}}else if(n.kind==="slot")o[n.uuid]=function(d){let i=[...a,d];return n.list.length===0?f(c(!0,i),i,[]):Object.assign(c(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];o[n.uuid]=f(c(!0,r),r,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(d){let u=n.when(d)?[...a,n.name]:a,b=l(u,n);return Object.assign(c(s(n),u),b)}:n.kind==="pick"&&(o[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],m("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(o,a,t.list)}function f(e,t,s){let a=(o,n)=>{let r=o?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,m("",s))};return e.$when=a,e.$join=function(n){return a(!0,n)},e}var c=(e,t)=>e?s=>_(t,s):Object.create(null);0&&(module.exports={base,grow,nest,pick,seed,tree,twig});
2
2
  //# sourceMappingURL=dialect-tree.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dialect-tree.ts","../src/api.ts"],"sourcesContent":["export { root as grow, path as tree, slot as seed, keep as twig, wrap as nest } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_tree_exports","__export","root","wrap","slot","path","keep","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
1
+ {"version":3,"sources":["../src/dialect-tree.ts","../src/api.ts"],"sourcesContent":["export {\n\troot as grow,\n\tpath as tree,\n\tslot as seed,\n\tkeep as twig,\n\twrap as nest,\n\tpick,\n\tbase,\n} from './api'\n","import {\n\tBase,\n\tKeep,\n\tPath,\n\tPathDef,\n\tPick,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tToCamelCase,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamelCase = <S extends string>(s: S) =>\n\ts\n\t\t.replace(/^-+/, '')\n\t\t.replace(/-+$/, '')\n\t\t.replace(/^_+/, '')\n\t\t.replace(/_+$/, '')\n\t\t.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\n\t\t.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase()) as ToCamelCase<S>\n\nconst IDENT = /^[A-Za-z_-][A-Za-z0-9_-]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap' | 'pick',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\nconst toSegs = (seg: Segment | readonly Segment[]) => (Array.isArray(seg) ? seg : [seg])\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Path<Name, ToCamelCase<Name>, List> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamelCase(name),\n\tlist: (list ?? []) as List,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tlist?: List\n): Slot<Name, `$${ToCamelCase<Name>}`, List> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tlist: (list ?? []) as List,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst List extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\tlist?: List\n): Wrap<Name, `$${ToCamelCase<Name>}`, List, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: `$${toCamelCase(name)}`,\n\twhen,\n\tlist: (list ?? []) as List,\n})\n\nexport const pick = <\n\tconst Name extends string,\n\tconst Mode extends Record<string, readonly Segment[]>,\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\tmode: Mode,\n\tlist?: List\n): Pick<Name, `$${ToCamelCase<Name>}`, Mode, List> => ({\n\tkind: 'pick',\n\tname: assertValidName('pick', name),\n\tuuid: `$${toCamelCase(name)}`,\n\tmode,\n\tlist: (list ?? []) as List,\n})\n\nexport const base = <\n\tconst Segs extends Segment | readonly Segment[],\n\tconst List extends readonly PathDef[] = readonly [],\n>(\n\tsegs: Segs,\n\tlist?: List\n): Base<Segs, List> => ({ kind: 'base', segs, list: (list ?? []) as List })\n\nexport const root = <const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> =>\n\tbuildNode([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${search}` : ''}`\n\nfunction buildNode(prefix: Segment[], parent: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.list.some((node: any) => node.kind === 'keep')\n\tconst allPath = parent.kind === 'path' && parent.name ? [...prefix, parent.name] : prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = makeTarget(hasKeep(parent), allPath)\n\n\tfor (const child of parent.list) {\n\t\tif (child.kind !== 'keep') {\n\t\t\tif (child.uuid in target) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Duplicate uuid \"${String(child.uuid)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tif (child.kind === 'base') {\n\t\t\tconst nextPrefix = [...allPath, ...toSegs(child.segs)]\n\t\t\tconst sub: any = buildNode(nextPrefix, path('', child.list))\n\n\t\t\tfor (const key of Reflect.ownKeys(sub)) {\n\t\t\t\tif (key === '$when' || key === '$join') continue\n\t\t\t\tconst desc = Object.getOwnPropertyDescriptor(sub, key)\n\t\t\t\tif (!desc?.enumerable) continue\n\n\t\t\t\tif (key in target) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`base() merge collision on key \"${String(key)}\" under \"${allPath.join('/') || '/'}\"`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tObject.defineProperty(target, key, desc)\n\t\t\t}\n\t\t} else if (child.kind === 'slot') {\n\t\t\ttarget[child.uuid] = function bind(param: Segment) {\n\t\t\t\tconst next = [...allPath, param]\n\n\t\t\t\t// leaf slot => callable endpoint directly\n\t\t\t\tif (child.list.length === 0) {\n\t\t\t\t\treturn attachWhenAndJoin(makeTarget(true, next), next, [])\n\t\t\t\t}\n\n\t\t\t\t// non-leaf => subtree (optionally callable if keep())\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), next), buildNode(next, child))\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.list.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.name]\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(makeTarget(true, leafPath), leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildNode(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = function wrap(arg: unknown) {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.name] : allPath\n\t\t\t\tconst subTree = buildNode(wrapped, child)\n\n\t\t\t\treturn Object.assign(makeTarget(hasKeep(child), wrapped), subTree)\n\t\t\t}\n\t\t} else if (child.kind === 'pick') {\n\t\t\ttarget[child.uuid] = (value: keyof typeof child.mode) => {\n\t\t\t\tif (child.mode[value]) {\n\t\t\t\t\treturn buildNode([...allPath, ...child.mode[value]], path('', child.list))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`pick(\"${child.name}\") got unknown value: ${String(value)}`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, parent.list)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], list: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...toSegs(seg)] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (list.length === 0 && typeof target === 'function') {\n\t\t\treturn attachWhenAndJoin(makeTarget(true, nextPath), nextPath, list)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildNode(nextPath, path('', list))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = function join(seg: Segment | readonly Segment[]) {\n\t\treturn when(true, seg)\n\t}\n\n\treturn target\n}\n\nconst makeTarget = (callable: boolean, currentPath: Segment[]) => {\n\treturn callable ? (search?: SParams) => url(currentPath, search) : Object.create(null)\n}\n"],"mappings":"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","names":["dialect_tree_exports","__export","base","root","wrap","pick","slot","path","keep","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","toSegs","seg","keep","path","list","slot","wrap","when","pick","mode","base","segs","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","key","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { root as grow, wrap as nest, slot as seed, path as tree, keep as twig } from './api.cjs';
1
+ export { base, root as grow, wrap as nest, pick, slot as seed, path as tree, keep as twig } from './api.cjs';
@@ -1 +1 @@
1
- export { root as grow, wrap as nest, slot as seed, path as tree, keep as twig } from './api.js';
1
+ export { base, root as grow, wrap as nest, pick, slot as seed, path as tree, keep as twig } from './api.js';
@@ -1,2 +1,2 @@
1
- import{a as e,b as s,c as a,d as t,e as o}from"./chunk-5ZW66SPO.js";export{o as grow,t as nest,a as seed,s as tree,e as twig};
1
+ import{a as e,b as s,c as a,d as t,e as o,f as r,g as p}from"./chunk-3GHZA2PG.js";export{r as base,p as grow,t as nest,o as pick,a as seed,s as tree,e as twig};
2
2
  //# sourceMappingURL=dialect-tree.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "route-sprout",
3
- "version": "2.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "A tiny, cute DSL that grows type-safe, composable URL builders from a declarative route tree.",
5
5
  "author": "Piotr Siatkowski <p.siatkowski@gmail.com>",
6
6
  "license": "MIT",
@@ -1,2 +0,0 @@
1
- var f=e=>e.replace(/-([a-zA-Z0-9])/g,(t,r)=>r.toUpperCase()),y=()=>({kind:"keep"}),p=(e,t)=>({kind:"path",name:g("path",e),uuid:f(e),rest:t??[]}),N=(e,t)=>({kind:"slot",name:g("slot",e),uuid:f(e),rest:t??[]}),P=(e,t,r)=>({kind:"wrap",name:g("wrap",e),uuid:f(e),when:t,rest:r??[]}),h=/^[A-Za-z_][A-Za-z0-9_]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!h.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var m=(e,t)=>`/${e.filter(Boolean).join("/").replace("//{2,}/g","/")}${t?`?${t}`:""}`;function w(e){return u([],p("",e))}function u(e,t){let r=n=>n.rest.some(a=>a.kind==="keep"),s=t.kind==="slot"||t.kind==="wrap"?e:t.uuid?[...e,t.uuid]:e,o=r(t)?n=>m(s,n):Object.create(null);for(let n of t.rest)if(n.kind==="slot")n.rest.length===0?o[n.uuid]=a=>{let l=[...s,a];return c(d=>m(l,d),l,[])}:o[n.uuid]=a=>{let l=u([...s,a],n);return Object.assign(r(n)?i=>m([...s,a],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let a=[...s,n.uuid],l=i=>m(a,i);o[n.uuid]=c(l,a,[])}else o[n.uuid]=u(s,n);else n.kind==="wrap"&&(o[n.uuid]=a=>{let i=n.when(a)?[...s,n.uuid]:s,d=u(i,n);return Object.assign(r(n)?S=>m(i,S):Object.create(null),d)});return c(o,s,t.rest)}function c(e,t,r){let s=(o,n)=>{let a=o?[...t,...Array.isArray(n)?n:[n]]:t;return r.length===0&&typeof e=="function"?c(i=>m(a,i),a,r):u(a,p("",r))};return e.$when=s,e.$join=o=>s(!0,o),e}export{y as a,p as b,N as c,P as d,w as e};
2
- //# sourceMappingURL=chunk-5ZW66SPO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"AAcA,IAAMA,EAAWC,GAAcA,EAAE,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAIxEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBC,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAInBH,EACAC,KACyC,CACzC,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAOC,GAAQ,CAAC,CACjB,GAEaG,EAAO,CAKnBJ,EACAK,EACAJ,KAC+C,CAC/C,KAAM,OACN,KAAMC,EAAgB,OAAQF,CAAI,EAClC,KAAMN,EAAQM,CAAI,EAClB,KAAAK,EACA,KAAOJ,GAAQ,CAAC,CACjB,GAEMK,EAAQ,2BAEd,SAASJ,EACRK,EACAP,EACO,CAEP,GAAIO,IAAS,QAAUP,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGO,CAAI,uBAAuB,EACzD,GAAI,CAACD,EAAM,KAAKN,CAAI,EACnB,MAAM,IAAI,MACT,GAAGO,CAAI,UAAUP,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAGA,IAAMQ,EAAM,CAACT,EAAiBU,IAC7B,IAAIV,EAAK,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,QAAQ,WAAa,GAAG,CAAC,GAAGU,EAAS,IAAIA,CAAM,GAAK,EAAE,GAGnF,SAASC,EAA4CC,EAAkC,CAC7F,OAAOC,EAAU,CAAC,EAAGb,EAAK,GAAIY,CAAI,CAAC,CACpC,CAEA,SAASC,EAAUC,EAAmBC,EAAc,CACnD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMnB,GAAWA,EAAE,OAAS,MAAM,EAC/EoB,EACLH,EAAI,OAAS,QAAUA,EAAI,OAAS,OACjCD,EACAC,EAAI,KACH,CAAC,GAAGD,EAAQC,EAAI,IAAI,EACpBD,EAGCK,EAAcH,EAAQD,CAAG,EAC3BL,GAAqBD,EAAIS,EAASR,CAAM,EACzC,OAAO,OAAO,IAAI,EAErB,QAAWU,KAASL,EAAI,KACvB,GAAIK,EAAM,OAAS,OACdA,EAAM,KAAK,SAAW,EACzBD,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CACxC,IAAMC,EAAW,CAAC,GAAGJ,EAASG,CAAK,EAEnC,OAAOE,EADUb,GAAqBD,EAAIa,EAAUZ,CAAM,EAC7BY,EAAU,CAAC,CAAC,CAC1C,EAEAH,EAAOC,EAAM,IAAI,EAAKC,GAAmB,CAGxC,IAAMG,EAAUX,EAAU,CAAC,GAAGK,EAASG,CAAK,EAAGD,CAAK,EAGpD,OAAO,OAAO,OACbJ,EAAQI,CAAK,EACTV,GAAqBD,EAAI,CAAC,GAAGS,EAASG,CAAK,EAAGX,CAAM,EACrD,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,UAESJ,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAME,EAAW,CAAC,GAAGJ,EAASE,EAAM,IAAI,EAClCK,EAAWf,GAAqBD,EAAIa,EAAUZ,CAAM,EAC1DS,EAAOC,EAAM,IAAI,EAAIG,EAAkBE,EAAIH,EAAU,CAAC,CAAC,CACxD,MACCH,EAAOC,EAAM,IAAI,EAAIP,EAAUK,EAASE,CAAK,OAEpCA,EAAM,OAAS,SACzBD,EAAOC,EAAM,IAAI,EAAKM,GAAiB,CAEtC,IAAMC,EADUP,EAAM,KAAKM,CAAG,EACJ,CAAC,GAAGR,EAASE,EAAM,IAAI,EAAIF,EAC/CM,EAAUX,EAAUc,EAASP,CAAY,EAE/C,OAAO,OAAO,OAEbJ,EAAQI,CAAY,EAChBV,GAAqBD,EAAIkB,EAASjB,CAAM,EACzC,OAAO,OAAO,IAAI,EACrBc,CACD,CACD,GAIF,OAAOD,EAAkBJ,EAAQD,EAASH,EAAI,IAAI,CACnD,CAEA,SAASQ,EAAkBJ,EAAaS,EAAqB1B,EAA0B,CACtF,IAAMI,EAAO,CAACuB,EAAeC,IAAsC,CAClE,IAAMC,EAAWF,EAAO,CAAC,GAAGD,EAAU,GAAI,MAAM,QAAQE,CAAG,EAAIA,EAAM,CAACA,CAAG,CAAE,EAAIF,EAG/E,OAAI1B,EAAK,SAAW,GAAK,OAAOiB,GAAW,WAEnCI,EADYb,GAAqBD,EAAIsB,EAAUrB,CAAM,EAC7BqB,EAAU7B,CAAI,EAKvCW,EAAUkB,EAAU/B,EAAK,GAAIE,CAAI,CAAC,CAC1C,EAEA,OAAAiB,EAAO,MAAQb,EACfa,EAAO,MAASW,GAAsCxB,EAAK,GAAMwB,CAAG,EAE7DX,CACR","names":["toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}