route-sprout 3.2.0 → 3.3.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
@@ -15,11 +15,7 @@ A tiny, cute DSL that grows **type-safe, composable URL builders** from a declar
15
15
  ## Install
16
16
 
17
17
  ```bash
18
- npm i route-sprout
19
- # or
20
- pnpm add route-sprout
21
- # or
22
- yarn add route-sprout
18
+ npm install route-sprout
23
19
  ```
24
20
 
25
21
  ## Quick start
@@ -221,6 +217,35 @@ Api.invoices.$id("abc").$when(flags.preview, "preview").activities();
221
217
  > `.$when()` is ideal when you don’t want to bake a wrapper into the route tree.
222
218
  > `.$join()` can be used in place of $when with condition being always true.
223
219
 
220
+ ### `$tail(tail)` (end the URL anywhere)
221
+
222
+ `$tail()` always returns a **string URL** for the current point in the chain, and then appends `tail` verbatim.
223
+
224
+ This is especially useful for “dot paths” that are **not callable** (no `keep()`), where you still want to produce a URL without restructuring your route tree.
225
+
226
+ ```ts
227
+ import { keep, path, root, slot } from 'route-sprout'
228
+
229
+ const Api = root([
230
+ path('jobs', [
231
+ // NOTE: no keep() here, so `jobs` is NOT callable
232
+ slot('id', [
233
+ path('activities'), // also not callable
234
+ ]),
235
+ ]),
236
+ ])
237
+
238
+ // Not callable (no keep):
239
+ // Api.jobs() // ❌
240
+ // Api.jobs.$id(1)() // ❌
241
+ // Api.jobs.$id(1).activities() // ❌
242
+
243
+ // But you can still end the URL anywhere:
244
+ Api.jobs.$tail('?page=1') // "/jobs?page=1"
245
+ Api.jobs.$id(1).$tail('#details') // "/jobs/1#details"
246
+ Api.jobs.$id(1).activities.$tail('?q=abc') // "/jobs/1/activities?q=abc"
247
+ ```
248
+
224
249
  ---
225
250
 
226
251
  ## Search params
@@ -303,6 +328,7 @@ Because everything is computed from the definition tree, your editor can autocom
303
328
 
304
329
  - `$when(predicate, segments)`
305
330
  - `$join(segments)`
331
+ - `$tail(string)`
306
332
 
307
333
  ---
308
334
 
package/dist/api.cjs CHANGED
@@ -1,2 +1,2 @@
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});
1
+ "use strict";var S=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var N=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},P=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of w(t))!x.call(e,i)&&i!==s&&S(e,i,{get:()=>t[i],enumerable:!(o=k(t,i))||o.enumerable});return e};var L=e=>P(S({},"__esModule",{value:!0}),e);var O={};N(O,{base:()=>T,keep:()=>b,path:()=>m,pick:()=>A,root:()=>_,slot:()=>C,wrap:()=>j});module.exports=L(O);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()),D=/^[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(!D.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var $=e=>Array.isArray(e)?e:[e],b=()=>({kind:"keep"}),m=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),C=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),j=(e,t,s)=>({kind:"wrap",name:g("wrap",e),uuid:`$${p(e)}`,when:t,list:s??[]}),A=(e,t,s)=>({kind:"pick",name:g("pick",e),uuid:`$${p(e)}`,mode:t,list:s??[]}),T=(e,t)=>({kind:"base",segs:e,list:t??[]}),_=e=>l([],m("",e)),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()},y=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${E(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,i=c(s(t),o);for(let n of t.list){if(n.kind!=="keep"&&n.uuid in i)throw new Error(`Duplicate uuid "${String(n.uuid)}" under "${o.join("/")||"/"}"`);if(n.kind==="base"){let r=[...o,...$(n.segs)],d=l(r,m("",n.list));for(let a of Reflect.ownKeys(d)){if(a==="$when"||a==="$join")continue;let u=Object.getOwnPropertyDescriptor(d,a);if(u?.enumerable){if(a in i)throw new Error(`base() merge collision on key "${String(a)}" under "${o.join("/")||"/"}"`);Object.defineProperty(i,a,u)}}}else if(n.kind==="slot")i[n.uuid]=function(d){let a=[...o,d];return n.list.length===0?f(c(!0,a),a,[]):Object.assign(c(s(n),a),l(a,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...o,n.name];i[n.uuid]=f(c(!0,r),r,[])}else i[n.uuid]=l(o,n);else n.kind==="wrap"?i[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"&&(i[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(i,o,t.list)}function f(e,t,s){let o=(i,n)=>{let r=i?[...t,...$(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.$tail=function(i){return`${y(t)}${i}`},e}var c=(e,t)=>e?s=>y(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\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"]}
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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"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","tail","callable","currentPath"]}
package/dist/api.d.cts CHANGED
@@ -10,6 +10,7 @@ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}
10
10
  type Segment = string | number
11
11
  type SParams =
12
12
  | string
13
+ | null
13
14
  | URLSearchParams
14
15
  | Record<string, string | number | boolean | null | undefined>
15
16
 
@@ -56,6 +57,7 @@ type CallIfKeep<U, Props> =
56
57
  type WithWhen<T> = T & {
57
58
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
58
59
  $join(seg: Segment | readonly Segment[]): this
60
+ $tail(tail: string): string
59
61
  }
60
62
  type ExpandBase<U> =
61
63
  U extends Base<any, infer L extends readonly PathDef[]>
package/dist/api.d.ts CHANGED
@@ -10,6 +10,7 @@ type ToCamelCase<S extends string> = S extends `${infer A}${Delimiter}${infer B}
10
10
  type Segment = string | number
11
11
  type SParams =
12
12
  | string
13
+ | null
13
14
  | URLSearchParams
14
15
  | Record<string, string | number | boolean | null | undefined>
15
16
 
@@ -56,6 +57,7 @@ type CallIfKeep<U, Props> =
56
57
  type WithWhen<T> = T & {
57
58
  $when(cond: boolean, seg: Segment | readonly Segment[]): this
58
59
  $join(seg: Segment | readonly Segment[]): this
60
+ $tail(tail: string): string
59
61
  }
60
62
  type ExpandBase<U> =
61
63
  U extends Base<any, infer L extends readonly PathDef[]>
package/dist/api.js CHANGED
@@ -1,2 +1,2 @@
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};
1
+ import{a,b,c,d,e,f,g}from"./chunk-DDS6DC5E.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()),h=/^[A-Za-z_-][A-Za-z0-9_-]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!h.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var 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??[]}),D=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(i=>i.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 i=[...o,...S(n.segs)],d=l(i,f("",n.list));for(let a of Reflect.ownKeys(d)){if(a==="$when"||a==="$join")continue;let u=Object.getOwnPropertyDescriptor(d,a);if(u?.enumerable){if(a in r)throw new Error(`base() merge collision on key "${String(a)}" under "${o.join("/")||"/"}"`);Object.defineProperty(r,a,u)}}}else if(n.kind==="slot")r[n.uuid]=function(d){let a=[...o,d];return n.list.length===0?m(c(!0,a),a,[]):Object.assign(c(s(n),a),l(a,n))};else if(n.kind==="path")if(n.list.length===0){let i=[...o,n.name];r[n.uuid]=m(c(!0,i),i,[])}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,y=l(u,n);return Object.assign(c(s(n),u),y)}:n.kind==="pick"&&(r[n.uuid]=i=>{if(n.mode[i])return l([...o,...n.mode[i]],f("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(i)}`)})}return m(r,o,t.list)}function m(e,t,s){let o=(r,n)=>{let i=r?[...t,...S(n)]:t;return s.length===0&&typeof e=="function"?m(c(!0,i),i,s):l(i,f("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e.$tail=function(r){return`${$(t)}${r}`},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,D as g};
2
+ //# sourceMappingURL=chunk-DDS6DC5E.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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"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","tail","callable","currentPath"]}
@@ -1,2 +1,2 @@
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});
1
+ "use strict";var S=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},A=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of D(t))!C.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=L(t,a))||o.enumerable});return e};var T=e=>A(S({},"__esModule",{value:!0}),e);var O={};j(O,{base:()=>x,bind:()=>h,call:()=>$,link:()=>N,mask:()=>y,node:()=>u,pick:()=>w});module.exports=T(O);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()),_=/^[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(!_.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],$=()=>({kind:"keep"}),u=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),h=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),y=(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=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()},P=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${E(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,b=l(m,n);return Object.assign(c(s(n),m),b)}: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.$tail=function(a){return`${P(t)}${a}`},e}var c=(e,t)=>e?s=>P(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 {\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
+ {"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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"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","tail","callable","currentPath"]}
@@ -1,2 +1,2 @@
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};
1
+ import{a,b as s,c as o,d as e,e as p,f as k,g as l}from"./chunk-DDS6DC5E.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 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});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},A=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of D(t))!C.call(e,r)&&r!==s&&S(e,r,{get:()=>t[r],enumerable:!(o=b(t,r))||o.enumerable});return e};var T=e=>A(S({},"__esModule",{value:!0}),e);var O={};j(O,{base:()=>x,keep:()=>$,path:()=>u,pick:()=>w,root:()=>N,slot:()=>h,wrap:()=>y});module.exports=T(O);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()),_=/^[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(!_.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],$=()=>({kind:"keep"}),u=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),h=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),y=(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=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()},P=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${E(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=d(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,...k(n.segs)],c=l(a,u("",n.list));for(let i of Reflect.ownKeys(c)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(c,i);if(m?.enumerable){if(i in r)throw new Error(`base() merge collision on key "${String(i)}" under "${o.join("/")||"/"}"`);Object.defineProperty(r,i,m)}}}else if(n.kind==="slot")r[n.uuid]=function(c){let i=[...o,c];return n.list.length===0?f(d(!0,i),i,[]):Object.assign(d(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let a=[...o,n.name];r[n.uuid]=f(d(!0,a),a,[])}else r[n.uuid]=l(o,n);else n.kind==="wrap"?r[n.uuid]=function(c){let m=n.when(c)?[...o,n.name]:o,L=l(m,n);return Object.assign(d(s(n),m),L)}:n.kind==="pick"&&(r[n.uuid]=a=>{if(n.mode[a])return l([...o,...n.mode[a]],u("",n.list));throw new Error(`pick("${n.name}") got unknown value: ${String(a)}`)})}return f(r,o,t.list)}function f(e,t,s){let o=(r,n)=>{let a=r?[...t,...k(n)]:t;return s.length===0&&typeof e=="function"?f(d(!0,a),a,s):l(a,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e.$tail=function(r){return`${P(t)}${r}`},e}var d=(e,t)=>e?s=>P(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, 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
+ {"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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"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","tail","callable","currentPath"]}
@@ -1,2 +1,2 @@
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};
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-DDS6DC5E.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 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});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},A=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of D(t))!C.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var T=e=>A(S({},"__esModule",{value:!0}),e);var O={};j(O,{base:()=>x,gate:()=>y,item:()=>h,make:()=>N,pick:()=>w,self:()=>$,step:()=>u});module.exports=T(O);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()),_=/^[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(!_.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],$=()=>({kind:"keep"}),u=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),h=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),y=(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=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()},P=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${E(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=d(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)],c=l(r,u("",n.list));for(let i of Reflect.ownKeys(c)){if(i==="$when"||i==="$join")continue;let m=Object.getOwnPropertyDescriptor(c,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(c){let i=[...o,c];return n.list.length===0?f(d(!0,i),i,[]):Object.assign(d(s(n),i),l(i,n))};else if(n.kind==="path")if(n.list.length===0){let r=[...o,n.name];a[n.uuid]=f(d(!0,r),r,[])}else a[n.uuid]=l(o,n);else n.kind==="wrap"?a[n.uuid]=function(c){let m=n.when(c)?[...o,n.name]:o,L=l(m,n);return Object.assign(d(s(n),m),L)}: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(d(!0,r),r,s):l(r,u("",s))};return e.$when=o,e.$join=function(n){return o(!0,n)},e.$tail=function(a){return`${P(t)}${a}`},e}var d=(e,t)=>e?s=>P(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 {\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
+ {"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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAT,GCgBA,IAAMU,EAAiCC,GACtCA,EACE,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,MAAO,EAAE,EACjB,QAAQ,kBAAmB,CAACC,EAAGC,IAAMA,EAAE,YAAY,CAAC,EACpD,QAAQ,kBAAmB,CAACD,EAAGC,IAAMA,EAAE,YAAY,CAAC,EAEjDC,EAAQ,6BAEd,SAASC,EACRC,EACAC,EACO,CAEP,GAAID,IAAS,QAAUC,IAAS,GAAI,OAAOA,EAAK,KAAK,EAErD,GAAI,CAACA,EAAM,MAAM,IAAI,MAAM,GAAGD,CAAI,uBAAuB,EACzD,GAAI,CAACF,EAAM,KAAKG,CAAI,EACnB,MAAM,IAAI,MACT,GAAGD,CAAI,UAAUC,CAAI,+EACtB,EAGD,OAAOA,EAAK,KAAK,CAClB,CAEA,IAAMC,EAAUC,GAAuC,MAAM,QAAQA,CAAG,EAAIA,EAAM,CAACA,CAAG,EAGzEC,EAAO,KAAa,CAAE,KAAM,MAAO,GAEnCC,EAAO,CAInBJ,EACAK,KAC0C,CAC1C,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAMP,EAAYO,CAAI,EACtB,KAAOK,GAAQ,CAAC,CACjB,GAEaC,EAAO,CAInBN,EACAK,KACgD,CAChD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAOK,GAAQ,CAAC,CACjB,GAEaE,EAAO,CAKnBP,EACAQ,EACAH,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAQ,EACA,KAAOH,GAAQ,CAAC,CACjB,GAEaI,EAAO,CAKnBT,EACAU,EACAL,KACsD,CACtD,KAAM,OACN,KAAMP,EAAgB,OAAQE,CAAI,EAClC,KAAM,IAAIP,EAAYO,CAAI,CAAC,GAC3B,KAAAU,EACA,KAAOL,GAAQ,CAAC,CACjB,GAEaM,EAAO,CAInBC,EACAP,KACuB,CAAE,KAAM,OAAQ,KAAAO,EAAM,KAAOP,GAAQ,CAAC,CAAW,GAE5DQ,EAA+CC,GAC3DC,EAAU,CAAC,EAAGX,EAAK,GAAIU,CAAI,CAAC,EAGvBE,EAAmBC,GAA2C,CACnE,GAAIA,aAAkB,gBACrB,OAAOA,EAAO,SAAS,EAGxB,GAAI,OAAOA,GAAW,SACrB,OAAOA,EAIR,IAAMC,EAAS,IAAI,gBACnB,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAM,EAC3CG,GAAU,MACdF,EAAO,OAAOC,EAAK,OAAOC,CAAK,CAAC,EAGjC,OAAOF,EAAO,SAAS,CACxB,EAEMG,EAAM,CAACjB,EAAiBa,IAC7B,IAAIb,EACF,OAAO,OAAO,EACd,KAAK,GAAG,EACR,QAAQ,UAAW,GAAG,CAAC,GAAGa,EAAS,IAAID,EAAgBC,CAAM,CAAC,GAAK,EAAE,GAExE,SAASF,EAAUO,EAAmBC,EAAiB,CACtD,IAAMC,EAAWC,GAAqBA,EAAQ,KAAK,KAAMC,GAAcA,EAAK,OAAS,MAAM,EACrFC,EAAUJ,EAAO,OAAS,QAAUA,EAAO,KAAO,CAAC,GAAGD,EAAQC,EAAO,IAAI,EAAID,EAG7EM,EAAcC,EAAWL,EAAQD,CAAM,EAAGI,CAAO,EAEvD,QAAWG,KAASP,EAAO,KAAM,CAChC,GAAIO,EAAM,OAAS,QACdA,EAAM,QAAQF,EACjB,MAAM,IAAI,MACT,mBAAmB,OAAOE,EAAM,IAAI,CAAC,YAAYH,EAAQ,KAAK,GAAG,GAAK,GAAG,GAC1E,EAIF,GAAIG,EAAM,OAAS,OAAQ,CAC1B,IAAMC,EAAa,CAAC,GAAGJ,EAAS,GAAG1B,EAAO6B,EAAM,IAAI,CAAC,EAC/CE,EAAWjB,EAAUgB,EAAY3B,EAAK,GAAI0B,EAAM,IAAI,CAAC,EAE3D,QAAWX,KAAO,QAAQ,QAAQa,CAAG,EAAG,CACvC,GAAIb,IAAQ,SAAWA,IAAQ,QAAS,SACxC,IAAMc,EAAO,OAAO,yBAAyBD,EAAKb,CAAG,EACrD,GAAKc,GAAM,WAEX,IAAId,KAAOS,EACV,MAAM,IAAI,MACT,kCAAkC,OAAOT,CAAG,CAAC,YAAYQ,EAAQ,KAAK,GAAG,GAAK,GAAG,GAClF,EAED,OAAO,eAAeC,EAAQT,EAAKc,CAAI,EACxC,CACD,SAAWH,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcI,EAAgB,CAClD,IAAMC,EAAO,CAAC,GAAGR,EAASO,CAAK,EAG/B,OAAIJ,EAAM,KAAK,SAAW,EAClBM,EAAkBP,EAAW,GAAMM,CAAI,EAAGA,EAAM,CAAC,CAAC,EAInD,OAAO,OAAON,EAAWL,EAAQM,CAAK,EAAGK,CAAI,EAAGpB,EAAUoB,EAAML,CAAK,CAAC,CAC9E,UACUA,EAAM,OAAS,OACzB,GAAIA,EAAM,KAAK,SAAW,EAAG,CAC5B,IAAMO,EAAW,CAAC,GAAGV,EAASG,EAAM,IAAI,EACxCF,EAAOE,EAAM,IAAI,EAAIM,EAAkBP,EAAW,GAAMQ,CAAQ,EAAGA,EAAU,CAAC,CAAC,CAChF,MACCT,EAAOE,EAAM,IAAI,EAAIf,EAAUY,EAASG,CAAK,OAEpCA,EAAM,OAAS,OACzBF,EAAOE,EAAM,IAAI,EAAI,SAAcQ,EAAc,CAEhD,IAAMC,EADUT,EAAM,KAAKQ,CAAG,EACJ,CAAC,GAAGX,EAASG,EAAM,IAAI,EAAIH,EAC/Ca,EAAUzB,EAAUwB,EAAST,CAAK,EAExC,OAAO,OAAO,OAAOD,EAAWL,EAAQM,CAAK,EAAGS,CAAO,EAAGC,CAAO,CAClE,EACUV,EAAM,OAAS,SACzBF,EAAOE,EAAM,IAAI,EAAKV,GAAmC,CACxD,GAAIU,EAAM,KAAKV,CAAK,EACnB,OAAOL,EAAU,CAAC,GAAGY,EAAS,GAAGG,EAAM,KAAKV,CAAK,CAAC,EAAGhB,EAAK,GAAI0B,EAAM,IAAI,CAAC,EAEzE,MAAM,IAAI,MAAM,SAASA,EAAM,IAAI,yBAAyB,OAAOV,CAAK,CAAC,EAAE,CAE7E,EAEF,CAEA,OAAOgB,EAAkBR,EAAQD,EAASJ,EAAO,IAAI,CACtD,CAEA,SAASa,EAAkBR,EAAaa,EAAqBpC,EAA0B,CACtF,IAAMG,EAAO,CAACkC,EAAexC,IAAsC,CAClE,IAAMyC,EAAWD,EAAO,CAAC,GAAGD,EAAU,GAAGxC,EAAOC,CAAG,CAAC,EAAIuC,EAGxD,OAAIpC,EAAK,SAAW,GAAK,OAAOuB,GAAW,WACnCQ,EAAkBP,EAAW,GAAMc,CAAQ,EAAGA,EAAUtC,CAAI,EAK7DU,EAAU4B,EAAUvC,EAAK,GAAIC,CAAI,CAAC,CAC1C,EAEA,OAAAuB,EAAO,MAAQpB,EACfoB,EAAO,MAAQ,SAAc1B,EAAmC,CAC/D,OAAOM,EAAK,GAAMN,CAAG,CACtB,EAEA0B,EAAO,MAAQ,SAAcgB,EAAc,CAC1C,MAAO,GAAGvB,EAAIoB,CAAQ,CAAC,GAAGG,CAAI,EAC/B,EAEOhB,CACR,CAEA,IAAMC,EAAa,CAACgB,EAAmBC,IAC/BD,EAAY5B,GAAqBI,EAAIyB,EAAa7B,CAAM,EAAI,OAAO,OAAO,IAAI","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","tail","callable","currentPath"]}
@@ -1,2 +1,2 @@
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};
1
+ import{a,b as e,c as s,d as t,e as p,f as o,g as r}from"./chunk-DDS6DC5E.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 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});
1
+ "use strict";var S=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},A=(e,t,s,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of D(t))!C.call(e,a)&&a!==s&&S(e,a,{get:()=>t[a],enumerable:!(o=b(t,a))||o.enumerable});return e};var T=e=>A(S({},"__esModule",{value:!0}),e);var O={};j(O,{base:()=>x,grow:()=>N,nest:()=>y,pick:()=>w,seed:()=>h,tree:()=>u,twig:()=>$});module.exports=T(O);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()),_=/^[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(!_.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],$=()=>({kind:"keep"}),u=(e,t)=>({kind:"path",name:g("path",e),uuid:p(e),list:t??[]}),h=(e,t)=>({kind:"slot",name:g("slot",e),uuid:`$${p(e)}`,list:t??[]}),y=(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=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()},P=(e,t)=>`/${e.filter(Boolean).join("/").replace(/\/{2,}/g,"/")}${t?`?${E(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,L=l(m,n);return Object.assign(c(s(n),m),L)}: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.$tail=function(a){return`${P(t)}${a}`},e}var c=(e,t)=>e?s=>P(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 {\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
+ {"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: Exclude<SParams, null>): 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\ttarget.$tail = function tail(tail: string) {\n\t\treturn `${url(basePath)}${tail}`\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}"],"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","tail","callable","currentPath"]}
@@ -1,2 +1,2 @@
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};
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-DDS6DC5E.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.2.0",
3
+ "version": "3.3.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 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
@@ -1 +0,0 @@
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"]}