route-sprout 3.0.0 → 3.2.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,8 +39,8 @@ const Api = root([
39
39
  ]),
40
40
  ]);
41
41
 
42
- Api.invoices(); // "/invoices"
43
- Api.invoices("page=1"); // "/invoices?page=1"
42
+ Api.invoices(); // "/invoices"
43
+ Api.invoices("page=1"); // "/invoices?page=1"
44
44
  Api.invoices.$id("abc")("a=1"); // "/invoices/abc?a=1"
45
45
  Api.invoices.$id("abc").customers(); // "/invoices/abc/customers"
46
46
  ```
@@ -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.
@@ -163,7 +188,20 @@ path("core", [
163
188
  ]);
164
189
 
165
190
  Api.core.$role("admin").invoices(); // "/core/admin/invoices"
166
- Api.core.$role("user").invoices(); // "/core/user/role/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.
167
205
  ```
168
206
 
169
207
  ### `.$when(cond, segment | segment[])`
@@ -254,6 +292,7 @@ Because everything is computed from the definition tree, your editor can autocom
254
292
  ### Exports
255
293
 
256
294
  - `root(defs)`
295
+ - `base(segs, defs?)`
257
296
  - `path(name, defs?)`
258
297
  - `slot(name, defs?)`
259
298
  - `wrap(name, when, defs?)`
package/dist/api.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var g=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var S=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var s in e)g(t,s,{get:e[s],enumerable:!0})},y=(t,e,s,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of N(e))!S.call(t,o)&&o!==s&&g(t,o,{get:()=>e[o],enumerable:!(a=$(e,o))||a.enumerable});return t};var x=t=>y(g({},"__esModule",{value:!0}),t);var _={};w(_,{keep:()=>C,path:()=>p,pick:()=>b,root:()=>A,slot:()=>L,wrap:()=>P});module.exports=x(_);var u=t=>t.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()),D=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function m(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!D.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var C=()=>({kind:"keep"}),p=(t,e)=>({kind:"path",name:m("path",t),uuid:u(t),list:e??[]}),L=(t,e)=>({kind:"slot",name:m("slot",t),uuid:`$${u(t)}`,list:e??[]}),P=(t,e,s)=>({kind:"wrap",name:m("wrap",t),uuid:`$${u(t)}`,when:e,list:s??[]}),b=(t,e,s)=>({kind:"pick",name:m("pick",t),uuid:`$${u(t)}`,mode:e,list:s??[]}),A=t=>l([],p("",t)),T=(t,e)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${e?`?${e}`:""}`;function l(t,e){let s=n=>n.list.some(r=>r.kind==="keep"),a=e.kind==="path"&&e.name?[...t,e.name]:t,o=i(s(e),a);for(let n of e.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="slot")o[n.uuid]=function(f){let d=[...a,f];return n.list.length===0?c(i(!0,d),d,[]):Object.assign(i(s(n),d),l(d,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];o[n.uuid]=c(i(!0,r),r,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(f){let h=n.when(f)?[...a,n.name]:a,k=l(h,n);return Object.assign(i(s(n),h),k)}:n.kind==="pick"&&(o[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],p("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return c(o,a,e.list)}function c(t,e,s){let a=(o,n)=>{let r=o?[...e,...Array.isArray(n)?n:[n]]:e;return s.length===0&&typeof t=="function"?c(i(!0,r),r,s):l(r,p("",s))};return t.$when=a,t.$join=function(n){return a(!0,n)},t}var i=(t,e)=>t?s=>T(e,s):Object.create(null);0&&(module.exports={keep,path,pick,root,slot,wrap});
1
+ "use strict";var S=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var x=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},N=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of $(t))!w.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=k(t,a))||o.enumerable});return e};var P=e=>N(S({},"__esModule",{value:!0}),e);var R={};x(R,{base:()=>A,keep:()=>b,path:()=>m,pick:()=>j,root:()=>T,slot:()=>D,wrap:()=>C});module.exports=P(R);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()),L=/^[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(!L.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var h=e=>Array.isArray(e)?e:[e],b=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),D=(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([],m("",e)),_=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},O=(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"),o=t.kind==="path"&&t.name?[...e,t.name]:e,a=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...h(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 a)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(a,i,u)}}}else if(n.kind==="slot")a[n.uuid]=function(d){let i=[...o,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=[...o,n.name];a[n.uuid]=f(c(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(d){let u=n.when(d)?[...o,n.name]:o,y=l(u,n);return Object.assign(c(s(n),u),y)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],m("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(a,o,t.list)}function f(e,t,s){let o=(a,n)=>{let r=a?[...t,...h(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,m("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>O(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\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\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 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 === '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, ...(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 (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","keep","path","pick","root","slot","wrap","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","list","when","mode","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}
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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
package/dist/api.d.cts CHANGED
@@ -8,7 +8,10 @@ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}
8
8
 
9
9
  // ---------- Shared public types ----------
10
10
  type Segment = string | number
11
- type SParams = string | URLSearchParams
11
+ type SParams =
12
+ | string
13
+ | URLSearchParams
14
+ | Record<string, string | number | boolean | null | undefined>
12
15
 
13
16
  // ---------- DSL definition types ----------
14
17
  type Keep = { kind: 'keep' }
@@ -38,7 +41,12 @@ type Pick<
38
41
  Mode extends Record<string, readonly Segment[]> = Record<string, readonly Segment[]>,
39
42
  List extends readonly PathDef[] = readonly PathDef[],
40
43
  > = { kind: 'pick'; name: Name; uuid: Uuid; mode: Mode; list: List }
41
- type PathDef = Path | Slot | Wrap | Pick | Keep
44
+
45
+ type Base<
46
+ Segs extends Segment | readonly Segment[] = Segment | readonly Segment[],
47
+ List extends readonly PathDef[] = readonly PathDef[],
48
+ > = { kind: 'base'; segs: Segs; list: List }
49
+ type PathDef = Path | Slot | Wrap | Pick | Keep | Base<any>
42
50
 
43
51
  // ---------- Type-level route builder ----------
44
52
  type PickKey<M> = Extract<keyof M, string>
@@ -49,9 +57,15 @@ type WithWhen<T> = T & {
49
57
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
50
58
  $join(seg: Segment | readonly Segment[]): this
51
59
  }
60
+ type ExpandBase<U> =
61
+ U extends Base<any, infer L extends readonly PathDef[]>
62
+ ? ExpandBase<Exclude<L[number], Keep>>
63
+ : U
64
+
65
+ type VisibleChild<Defs extends readonly PathDef[]> = ExpandBase<Exclude<List<Defs>, Keep>>
52
66
 
53
67
  type PropsFromChildren<Defs extends readonly PathDef[]> = {
54
- [C in Exclude<List<Defs>, Keep> as C extends { uuid: infer N extends string }
68
+ [C in VisibleChild<Defs> as C extends { uuid: infer N extends string }
55
69
  ? ToCamelCase<N>
56
70
  : never]: C extends Path<any, any, any>
57
71
  ? RouteFromPath<C>
@@ -94,6 +108,7 @@ declare const path: <const Name extends string, const List extends readonly Path
94
108
  declare const slot: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Slot<Name, `$${ToCamelCase<Name>}`, List>;
95
109
  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>;
96
110
  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>;
111
+ declare const base: <const Segs extends Segment | readonly Segment[], const List extends readonly PathDef[] = readonly []>(segs: Segs, list?: List) => Base<Segs, List>;
97
112
  declare const root: <const Defs extends readonly PathDef[]>(defs: Defs) => RoutesFromDefs<Defs>;
98
113
 
99
- export { keep, path, pick, root, slot, wrap };
114
+ export { base, keep, path, pick, root, slot, wrap };
package/dist/api.d.ts CHANGED
@@ -8,7 +8,10 @@ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}
8
8
 
9
9
  // ---------- Shared public types ----------
10
10
  type Segment = string | number
11
- type SParams = string | URLSearchParams
11
+ type SParams =
12
+ | string
13
+ | URLSearchParams
14
+ | Record<string, string | number | boolean | null | undefined>
12
15
 
13
16
  // ---------- DSL definition types ----------
14
17
  type Keep = { kind: 'keep' }
@@ -38,7 +41,12 @@ type Pick<
38
41
  Mode extends Record<string, readonly Segment[]> = Record<string, readonly Segment[]>,
39
42
  List extends readonly PathDef[] = readonly PathDef[],
40
43
  > = { kind: 'pick'; name: Name; uuid: Uuid; mode: Mode; list: List }
41
- type PathDef = Path | Slot | Wrap | Pick | Keep
44
+
45
+ type Base<
46
+ Segs extends Segment | readonly Segment[] = Segment | readonly Segment[],
47
+ List extends readonly PathDef[] = readonly PathDef[],
48
+ > = { kind: 'base'; segs: Segs; list: List }
49
+ type PathDef = Path | Slot | Wrap | Pick | Keep | Base<any>
42
50
 
43
51
  // ---------- Type-level route builder ----------
44
52
  type PickKey<M> = Extract<keyof M, string>
@@ -49,9 +57,15 @@ type WithWhen<T> = T & {
49
57
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
50
58
  $join(seg: Segment | readonly Segment[]): this
51
59
  }
60
+ type ExpandBase<U> =
61
+ U extends Base<any, infer L extends readonly PathDef[]>
62
+ ? ExpandBase<Exclude<L[number], Keep>>
63
+ : U
64
+
65
+ type VisibleChild<Defs extends readonly PathDef[]> = ExpandBase<Exclude<List<Defs>, Keep>>
52
66
 
53
67
  type PropsFromChildren<Defs extends readonly PathDef[]> = {
54
- [C in Exclude<List<Defs>, Keep> as C extends { uuid: infer N extends string }
68
+ [C in VisibleChild<Defs> as C extends { uuid: infer N extends string }
55
69
  ? ToCamelCase<N>
56
70
  : never]: C extends Path<any, any, any>
57
71
  ? RouteFromPath<C>
@@ -94,6 +108,7 @@ declare const path: <const Name extends string, const List extends readonly Path
94
108
  declare const slot: <const Name extends string, const List extends readonly PathDef[] = readonly []>(name: Name, list?: List) => Slot<Name, `$${ToCamelCase<Name>}`, List>;
95
109
  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>;
96
110
  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>;
111
+ declare const base: <const Segs extends Segment | readonly Segment[], const List extends readonly PathDef[] = readonly []>(segs: Segs, list?: List) => Base<Segs, List>;
97
112
  declare const root: <const Defs extends readonly PathDef[]>(defs: Defs) => RoutesFromDefs<Defs>;
98
113
 
99
- export { keep, path, pick, root, slot, wrap };
114
+ export { base, keep, path, pick, root, slot, wrap };
package/dist/api.js CHANGED
@@ -1,2 +1,2 @@
1
- import{a,b,c,d,e,f}from"./chunk-TB22YO7J.js";export{a as keep,b as path,e as pick,f as root,c as slot,d as wrap};
1
+ import{a,b,c,d,e,f,g}from"./chunk-J4HUZKRH.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,(t,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(t,s)=>s.toUpperCase()),y=/^[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(!y.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],w=()=>({kind:"keep"}),f=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),x=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),N=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),P=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),L=(e,t)=>({kind:"base",segs:e,list:t??[]}),b=e=>l([],f("",e)),k=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},$=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${k(t)}`:""}`;function l(e,t){let s=n=>n.list.some(a=>a.kind==="keep"),o=t.kind==="path"&&t.name?[...e,t.name]:e,r=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in r)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let a=[...o,...S(n.segs)],d=l(a,f("",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 r)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(r,i,u)}}}else if(n.kind==="slot")r[n.uuid]=function(d){let i=[...o,d];return n.list.length===0?m(c(!0,i),i,[]):Object.assign(c(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let a=[...o,n.name];r[n.uuid]=m(c(!0,a),a,[])}else r[n.uuid]=l(o,n);else n.kind==="wrap"?r[n.uuid]=function(d){let u=n.when(d)?[...o,n.name]:o,h=l(u,n);return Object.assign(c(s(n),u),h)}:n.kind==="pick"&&(r[n.uuid]=a=>{if(n.mode[a])return l([...o,...n.mode[a]],f("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(a)}`)})}return m(r,o,t.list)}function m(e,t,s){let o=(r,n)=>{let a=r?[...t,...S(n)]:t;return s.length===0&&typeof e=="function"?m(c(!0,a),a,s):l(a,f("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>$(t,s):Object.create(null);export{w as a,f as b,x as c,N as d,P as e,L as f,b as g};
2
+ //# sourceMappingURL=chunk-J4HUZKRH.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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
@@ -1,2 +1,2 @@
1
- "use strict";var h=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var s in e)h(t,s,{get:e[s],enumerable:!0})},P=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of D(e))!C.call(t,a)&&a!==s&&h(t,a,{get:()=>e[a],enumerable:!(o=x(e,a))||o.enumerable});return t};var b=t=>P(h({},"__esModule",{value:!0}),t);var _={};L(_,{base:()=>k,bind:()=>$,link:()=>S,mask:()=>w,node:()=>c,pick:()=>N});module.exports=b(_);var u=t=>t.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()),A=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function p(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!A.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var k=()=>({kind:"keep"}),c=(t,e)=>({kind:"path",name:p("path",t),uuid:u(t),list:e??[]}),$=(t,e)=>({kind:"slot",name:p("slot",t),uuid:`$${u(t)}`,list:e??[]}),w=(t,e,s)=>({kind:"wrap",name:p("wrap",t),uuid:`$${u(t)}`,when:e,list:s??[]}),N=(t,e,s)=>({kind:"pick",name:p("pick",t),uuid:`$${u(t)}`,mode:e,list:s??[]}),S=t=>l([],c("",t)),T=(t,e)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${e?`?${e}`:""}`;function l(t,e){let s=n=>n.list.some(r=>r.kind==="keep"),o=e.kind==="path"&&e.name?[...t,e.name]:t,a=i(s(e),o);for(let n of e.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="slot")a[n.uuid]=function(f){let d=[...o,f];return n.list.length===0?m(i(!0,d),d,[]):Object.assign(i(s(n),d),l(d,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...o,n.name];a[n.uuid]=m(i(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(f){let g=n.when(f)?[...o,n.name]:o,y=l(g,n);return Object.assign(i(s(n),g),y)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],c("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return m(a,o,e.list)}function m(t,e,s){let o=(a,n)=>{let r=a?[...e,...Array.isArray(n)?n:[n]]:e;return s.length===0&&typeof t=="function"?m(i(!0,r),r,s):l(r,c("",s))};return t.$when=o,t.$join=function(n){return o(!0,n)},t}var i=(t,e)=>t?s=>T(e,s):Object.create(null);0&&(module.exports={base,bind,link,mask,node,pick});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of L(t))!D.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var A=e=>j(S({},"__esModule",{value:!0}),e);var R={};C(R,{base:()=>x,bind:()=>y,call:()=>h,link:()=>N,mask:()=>$,node:()=>u,pick:()=>w});module.exports=A(R);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],h=()=>({kind:"keep"}),u=(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([],u("",e)),_=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},O=(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"),o=t.kind==="path"&&t.name?[...e,t.name]:e,a=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...k(n.segs)],d=l(r,u("",n.list));for(let i of Reflect.ownKeys(d)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,i);if(m?.enumerable){if(i in a)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(a,i,m)}}}else if(n.kind==="slot")a[n.uuid]=function(d){let i=[...o,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=[...o,n.name];a[n.uuid]=f(c(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(d){let m=n.when(d)?[...o,n.name]:o,P=l(m,n);return Object.assign(c(s(n),m),P)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(a,o,t.list)}function f(e,t,s){let o=(a,n)=>{let r=a?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>O(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, pick } from './api'\n","import {\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\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 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 === '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, ...(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 (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_node_exports","__export","keep","slot","root","wrap","path","pick","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","keep","path","list","slot","wrap","when","pick","mode","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}
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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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_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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { keep as base, slot as bind, root as link, wrap as mask, path as node, pick } 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, pick } 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,f as k}from"./chunk-TB22YO7J.js";export{a as base,o as bind,k as link,e as mask,s as node,p as pick};
1
+ import{a,b as s,c as o,d as e,e as p,f as k,g as l}from"./chunk-J4HUZKRH.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 h=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var o in e)h(t,o,{get:e[o],enumerable:!0})},P=(t,e,o,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!C.call(t,s)&&s!==o&&h(t,s,{get:()=>e[s],enumerable:!(a=x(e,s))||a.enumerable});return t};var b=t=>P(h({},"__esModule",{value:!0}),t);var _={};L(_,{keep:()=>k,path:()=>c,pick:()=>N,root:()=>S,slot:()=>$,wrap:()=>w});module.exports=b(_);var u=t=>t.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(e,o)=>o.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(e,o)=>o.toUpperCase()),A=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function p(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!A.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var k=()=>({kind:"keep"}),c=(t,e)=>({kind:"path",name:p("path",t),uuid:u(t),list:e??[]}),$=(t,e)=>({kind:"slot",name:p("slot",t),uuid:`$${u(t)}`,list:e??[]}),w=(t,e,o)=>({kind:"wrap",name:p("wrap",t),uuid:`$${u(t)}`,when:e,list:o??[]}),N=(t,e,o)=>({kind:"pick",name:p("pick",t),uuid:`$${u(t)}`,mode:e,list:o??[]}),S=t=>l([],c("",t)),T=(t,e)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${e?`?${e}`:""}`;function l(t,e){let o=n=>n.list.some(r=>r.kind==="keep"),a=e.kind==="path"&&e.name?[...t,e.name]:t,s=i(o(e),a);for(let n of e.list){if(n.kind!=="keep"&&n.uuid in s)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="slot")s[n.uuid]=function(f){let d=[...a,f];return n.list.length===0?m(i(!0,d),d,[]):Object.assign(i(o(n),d),l(d,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];s[n.uuid]=m(i(!0,r),r,[])}else s[n.uuid]=l(a,n);else n.kind==="wrap"?s[n.uuid]=function(f){let g=n.when(f)?[...a,n.name]:a,y=l(g,n);return Object.assign(i(o(n),g),y)}:n.kind==="pick"&&(s[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],c("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return m(s,a,e.list)}function m(t,e,o){let a=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return o.length===0&&typeof t=="function"?m(i(!0,r),r,o):l(r,c("",o))};return t.$when=a,t.$join=function(n){return a(!0,n)},t}var i=(t,e)=>t?o=>T(e,o):Object.create(null);0&&(module.exports={keep,path,pick,root,slot,wrap});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of L(t))!D.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var A=e=>j(S({},"__esModule",{value:!0}),e);var R={};C(R,{base:()=>x,keep:()=>k,path:()=>u,pick:()=>w,root:()=>N,slot:()=>y,wrap:()=>$});module.exports=A(R);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 h=e=>Array.isArray(e)?e:[e],k=()=>({kind:"keep"}),u=(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([],u("",e)),_=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},O=(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"),o=t.kind==="path"&&t.name?[...e,t.name]:e,a=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...h(n.segs)],d=l(r,u("",n.list));for(let i of Reflect.ownKeys(d)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,i);if(m?.enumerable){if(i in a)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(a,i,m)}}}else if(n.kind==="slot")a[n.uuid]=function(d){let i=[...o,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=[...o,n.name];a[n.uuid]=f(c(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(d){let m=n.when(d)?[...o,n.name]:o,P=l(m,n);return Object.assign(c(s(n),m),P)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(a,o,t.list)}function f(e,t,s){let o=(a,n)=>{let r=a?[...t,...h(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>O(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, pick } from './api'\n","import {\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\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 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 === '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, ...(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 (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_path_exports","__export","keep","path","pick","root","slot","wrap","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","keep","path","list","slot","wrap","when","pick","mode","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}
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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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_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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { keep, path, pick, root, slot, wrap } from './api.cjs';
1
+ export { base, keep, path, pick, root, slot, wrap } from './api.cjs';
@@ -1 +1 @@
1
- export { keep, path, pick, 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,f as a}from"./chunk-TB22YO7J.js";export{o as keep,p as path,e as pick,a 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-J4HUZKRH.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 g=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var s in e)g(t,s,{get:e[s],enumerable:!0})},P=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of D(e))!C.call(t,a)&&a!==s&&g(t,a,{get:()=>e[a],enumerable:!(o=x(e,a))||o.enumerable});return t};var b=t=>P(g({},"__esModule",{value:!0}),t);var _={};L(_,{gate:()=>w,item:()=>$,make:()=>S,pick:()=>N,self:()=>k,step:()=>c});module.exports=b(_);var u=t=>t.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()),A=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function p(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!A.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var k=()=>({kind:"keep"}),c=(t,e)=>({kind:"path",name:p("path",t),uuid:u(t),list:e??[]}),$=(t,e)=>({kind:"slot",name:p("slot",t),uuid:`$${u(t)}`,list:e??[]}),w=(t,e,s)=>({kind:"wrap",name:p("wrap",t),uuid:`$${u(t)}`,when:e,list:s??[]}),N=(t,e,s)=>({kind:"pick",name:p("pick",t),uuid:`$${u(t)}`,mode:e,list:s??[]}),S=t=>l([],c("",t)),T=(t,e)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${e?`?${e}`:""}`;function l(t,e){let s=n=>n.list.some(r=>r.kind==="keep"),o=e.kind==="path"&&e.name?[...t,e.name]:t,a=i(s(e),o);for(let n of e.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="slot")a[n.uuid]=function(f){let d=[...o,f];return n.list.length===0?m(i(!0,d),d,[]):Object.assign(i(s(n),d),l(d,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...o,n.name];a[n.uuid]=m(i(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(f){let h=n.when(f)?[...o,n.name]:o,y=l(h,n);return Object.assign(i(s(n),h),y)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],c("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return m(a,o,e.list)}function m(t,e,s){let o=(a,n)=>{let r=a?[...e,...Array.isArray(n)?n:[n]]:e;return s.length===0&&typeof t=="function"?m(i(!0,r),r,s):l(r,c("",s))};return t.$when=o,t.$join=function(n){return o(!0,n)},t}var i=(t,e)=>t?s=>T(e,s):Object.create(null);0&&(module.exports={gate,item,make,pick,self,step});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of L(t))!D.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var A=e=>j(S({},"__esModule",{value:!0}),e);var R={};C(R,{base:()=>x,gate:()=>$,item:()=>y,make:()=>N,pick:()=>w,self:()=>h,step:()=>u});module.exports=A(R);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],h=()=>({kind:"keep"}),u=(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([],u("",e)),_=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},O=(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"),o=t.kind==="path"&&t.name?[...e,t.name]:e,a=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...k(n.segs)],d=l(r,u("",n.list));for(let i of Reflect.ownKeys(d)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,i);if(m?.enumerable){if(i in a)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(a,i,m)}}}else if(n.kind==="slot")a[n.uuid]=function(d){let i=[...o,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=[...o,n.name];a[n.uuid]=f(c(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(d){let m=n.when(d)?[...o,n.name]:o,P=l(m,n);return Object.assign(c(s(n),m),P)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(a,o,t.list)}function f(e,t,s){let o=(a,n)=>{let r=a?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>O(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, pick } from './api'\n","import {\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\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 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 === '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, ...(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 (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","wrap","slot","root","pick","keep","path","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","keep","path","list","slot","wrap","when","pick","mode","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}
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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { wrap as gate, slot as item, root as make, pick, 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, pick, 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 p,f as o}from"./chunk-TB22YO7J.js";export{t as gate,s as item,o as make,p as pick,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-J4HUZKRH.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 g=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var s in e)g(t,s,{get:e[s],enumerable:!0})},P=(t,e,s,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of D(e))!C.call(t,o)&&o!==s&&g(t,o,{get:()=>e[o],enumerable:!(a=x(e,o))||a.enumerable});return t};var b=t=>P(g({},"__esModule",{value:!0}),t);var _={};L(_,{grow:()=>S,nest:()=>w,pick:()=>N,seed:()=>$,tree:()=>c,twig:()=>k});module.exports=b(_);var u=t=>t.replace(/^-+/,"").replace(/-+$/,"").replace(/^_+/,"").replace(/_+$/,"").replace(/-([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()).replace(/_([a-zA-Z0-9])/g,(e,s)=>s.toUpperCase()),A=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function p(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!A.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var k=()=>({kind:"keep"}),c=(t,e)=>({kind:"path",name:p("path",t),uuid:u(t),list:e??[]}),$=(t,e)=>({kind:"slot",name:p("slot",t),uuid:`$${u(t)}`,list:e??[]}),w=(t,e,s)=>({kind:"wrap",name:p("wrap",t),uuid:`$${u(t)}`,when:e,list:s??[]}),N=(t,e,s)=>({kind:"pick",name:p("pick",t),uuid:`$${u(t)}`,mode:e,list:s??[]}),S=t=>l([],c("",t)),T=(t,e)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${e?`?${e}`:""}`;function l(t,e){let s=n=>n.list.some(r=>r.kind==="keep"),a=e.kind==="path"&&e.name?[...t,e.name]:t,o=i(s(e),a);for(let n of e.list){if(n.kind!=="keep"&&n.uuid in o)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${a.join("/")||"/"}"`);if(n.kind==="slot")o[n.uuid]=function(f){let d=[...a,f];return n.list.length===0?m(i(!0,d),d,[]):Object.assign(i(s(n),d),l(d,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...a,n.name];o[n.uuid]=m(i(!0,r),r,[])}else o[n.uuid]=l(a,n);else n.kind==="wrap"?o[n.uuid]=function(f){let h=n.when(f)?[...a,n.name]:a,y=l(h,n);return Object.assign(i(s(n),h),y)}:n.kind==="pick"&&(o[n.uuid]=r=>{if(n.mode[r])return l([...a,...n.mode[r]],c("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return m(o,a,e.list)}function m(t,e,s){let a=(o,n)=>{let r=o?[...e,...Array.isArray(n)?n:[n]]:e;return s.length===0&&typeof t=="function"?m(i(!0,r),r,s):l(r,c("",s))};return t.$when=a,t.$join=function(n){return a(!0,n)},t}var i=(t,e)=>t?s=>T(e,s):Object.create(null);0&&(module.exports={grow,nest,pick,seed,tree,twig});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var C=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of L(t))!D.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var A=e=>j(S({},"__esModule",{value:!0}),e);var R={};C(R,{base:()=>x,grow:()=>N,nest:()=>w,pick:()=>$,seed:()=>y,tree:()=>u,twig:()=>k});module.exports=A(R);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 h=e=>Array.isArray(e)?e:[e],k=()=>({kind:"keep"}),u=(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??[]}),w=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),$=(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([],u("",e)),_=e=>{if(e instanceof URLSearchParams)return e.toString();if(typeof e=="string")return e;let t=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&t.append(s,String(o));return t.toString()},O=(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"),o=t.kind==="path"&&t.name?[...e,t.name]:e,a=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in a)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...h(n.segs)],d=l(r,u("",n.list));for(let i of Reflect.ownKeys(d)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(d,i);if(m?.enumerable){if(i in a)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(a,i,m)}}}else if(n.kind==="slot")a[n.uuid]=function(d){let i=[...o,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=[...o,n.name];a[n.uuid]=f(c(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(d){let m=n.when(d)?[...o,n.name]:o,P=l(m,n);return Object.assign(c(s(n),m),P)}:n.kind==="pick"&&(a[n.uuid]=r=>{if(n.mode[r])return l([...o,...n.mode[r]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(r)}`)})}return f(a,o,t.list)}function f(e,t,s){let o=(a,n)=>{let r=a?[...t,...h(n)]:t;return s.length===0&&typeof e=="function"?f(c(!0,r),r,s):l(r,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e}var c=(e,t)=>e?s=>O(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, pick } from './api'\n","import {\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\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 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 === '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, ...(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 (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","root","wrap","pick","slot","path","keep","__toCommonJS","toCamelCase","s","_","c","IDENT","assertValidName","kind","name","keep","path","list","slot","wrap","when","pick","mode","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}
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 sParamsToString = (search: SParams): string => {\n\tif (search instanceof URLSearchParams) {\n\t\treturn search.toString()\n\t}\n\n\tif (typeof search === 'string') {\n\t\treturn search\n\t}\n\n\t// Record case\n\tconst params = new URLSearchParams()\n\tfor (const [key, value] of Object.entries(search)) {\n\t\tif (value === null || value === undefined) continue\n\t\tparams.append(key, String(value))\n\t}\n\n\treturn params.toString()\n}\n\nconst url = (path: Segment[], search?: SParams | null | undefined) =>\n\t`/${path\n\t\t.filter(Boolean)\n\t\t.join('/')\n\t\t.replace(/\\/{2,}/g, '/')}${search ? `?${sParamsToString(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","sParamsToString","search","params","key","value","url","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","nextPrefix","sub","desc","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","basePath","cond","nextPath","callable","currentPath"]}
@@ -1 +1 @@
1
- export { root as grow, wrap as nest, pick, 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, pick, 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,f as r}from"./chunk-TB22YO7J.js";export{r as grow,t as nest,o as pick,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-J4HUZKRH.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": "3.0.0",
3
+ "version": "3.2.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 u=t=>t.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 m(t,n){if(t==="path"&&n==="")return n.trim();if(!n)throw new Error(`${t} name cannot be empty`);if(!k.test(n))throw new Error(`${t} name "${n}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return n.trim()}var N=()=>({kind:"keep"}),f=(t,n)=>({kind:"path",name:m("path",t),uuid:u(t),list:n??[]}),S=(t,n)=>({kind:"slot",name:m("slot",t),uuid:`$${u(t)}`,list:n??[]}),w=(t,n,s)=>({kind:"wrap",name:m("wrap",t),uuid:`$${u(t)}`,when:n,list:s??[]}),y=(t,n,s)=>({kind:"pick",name:m("pick",t),uuid:`$${u(t)}`,mode:n,list:s??[]}),x=t=>l([],f("",t)),$=(t,n)=>`/${t.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${n?`?${n}`:""}`;function l(t,n){let s=e=>e.list.some(o=>o.kind==="keep"),a=n.kind==="path"&&n.name?[...t,n.name]:t,r=i(s(n),a);for(let e of n.list){if(e.kind!=="keep"&&e.uuid in r)throw new Error(`Duplicate uuid "${String(e.uuid)}" under "${a.join("/")||"/"}"`);if(e.kind==="slot")r[e.uuid]=function(p){let d=[...a,p];return e.list.length===0?c(i(!0,d),d,[]):Object.assign(i(s(e),d),l(d,e))};else if(e.kind==="path")if(e.list.length===0){let o=[...a,e.name];r[e.uuid]=c(i(!0,o),o,[])}else r[e.uuid]=l(a,e);else e.kind==="wrap"?r[e.uuid]=function(p){let g=e.when(p)?[...a,e.name]:a,h=l(g,e);return Object.assign(i(s(e),g),h)}:e.kind==="pick"&&(r[e.uuid]=o=>{if(e.mode[o])return l([...a,...e.mode[o]],f("",e.list));throw new Error(`pick("${e.name}") got unknown value: ${String(o)}`)})}return c(r,a,n.list)}function c(t,n,s){let a=(r,e)=>{let o=r?[...n,...Array.isArray(e)?e:[e]]:n;return s.length===0&&typeof t=="function"?c(i(!0,o),o,s):l(o,f("",s))};return t.$when=a,t.$join=function(e){return a(!0,e)},t}var i=(t,n)=>t?s=>$(n,s):Object.create(null);export{N as a,f as b,S as c,w as d,y as e,x as f};
2
- //# sourceMappingURL=chunk-TB22YO7J.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\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\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 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 === '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, ...(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 (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","keep","path","list","slot","wrap","when","pick","mode","root","defs","buildNode","url","search","prefix","parent","hasKeep","pathDef","node","allPath","target","makeTarget","child","param","next","attachWhenAndJoin","leafPath","arg","wrapped","subTree","value","basePath","cond","seg","nextPath","callable","currentPath"]}