route-sprout 1.0.0 → 2.0.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 +29 -21
- package/dist/api.cjs +1 -1
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +24 -15
- package/dist/api.d.ts +24 -15
- package/dist/api.js +1 -1
- package/dist/api.js.map +1 -1
- package/dist/chunk-5ZW66SPO.js +2 -0
- package/dist/chunk-5ZW66SPO.js.map +1 -0
- package/dist/dialect-node.cjs +2 -0
- package/dist/dialect-node.cjs.map +1 -0
- package/dist/dialect-node.d.cts +1 -0
- package/dist/dialect-node.d.ts +1 -0
- package/dist/dialect-node.js +2 -0
- package/dist/dialect-node.js.map +1 -0
- package/dist/dialect-path.cjs +2 -0
- package/dist/dialect-path.cjs.map +1 -0
- package/dist/dialect-path.d.cts +1 -0
- package/dist/dialect-path.d.ts +1 -0
- package/dist/dialect-path.js +2 -0
- package/dist/dialect-path.js.map +1 -0
- package/dist/dialect-step.cjs +2 -0
- package/dist/dialect-step.cjs.map +1 -0
- package/dist/dialect-step.d.cts +1 -0
- package/dist/dialect-step.d.ts +1 -0
- package/dist/dialect-step.js +2 -0
- package/dist/dialect-step.js.map +1 -0
- package/dist/dialect-tree.cjs +2 -0
- package/dist/dialect-tree.cjs.map +1 -0
- package/dist/dialect-tree.d.cts +1 -0
- package/dist/dialect-tree.d.ts +1 -0
- package/dist/dialect-tree.js +2 -0
- package/dist/dialect-tree.js.map +1 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
# route-sprout 🌱 (typed API route builder DSL)
|
|
4
4
|
|
|
@@ -10,14 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
A tiny, cute DSL that grows **type-safe, composable URL builders** from a declarative route tree.
|
|
12
12
|
|
|
13
|
-
- ✅ Strong TypeScript inference from your route definition
|
|
14
|
-
- ✅ Nested resources with `slot('id')` parameters
|
|
15
|
-
- ✅ Optional path gates with `wrap('admin', predicate, …)`
|
|
16
|
-
- ✅ Ad‑hoc conditional segments anywhere with `.when(cond, segments) and join(segments)`
|
|
17
|
-
- ✅ Search params supported (`string` or `URLSearchParams`)
|
|
18
|
-
|
|
19
|
-
> Think of it as a little route bonsai: you shape the tree once, then pluck URLs from any branch.
|
|
20
|
-
|
|
21
13
|
---
|
|
22
14
|
|
|
23
15
|
## Install
|
|
@@ -39,6 +31,7 @@ const Api = root([
|
|
|
39
31
|
path("invoices", [
|
|
40
32
|
keep(),
|
|
41
33
|
slot("id", [
|
|
34
|
+
keep(),
|
|
42
35
|
path("price"),
|
|
43
36
|
path("customers")
|
|
44
37
|
]),
|
|
@@ -54,6 +47,16 @@ Api.invoices.id("abc").customers(); // "/invoices/abc/customers"
|
|
|
54
47
|
|
|
55
48
|
---
|
|
56
49
|
|
|
50
|
+
- ✅ Strong TypeScript inference from your route definition
|
|
51
|
+
- ✅ Nested resources with `slot('id')` parameters
|
|
52
|
+
- ✅ Optional path gates with `wrap('admin', predicate, …)`
|
|
53
|
+
- ✅ Ad‑hoc conditional segments anywhere with `.$when(cond, segments) and join(segments)`
|
|
54
|
+
- ✅ Search params supported (`string` or `URLSearchParams`)
|
|
55
|
+
|
|
56
|
+
> Think of it as a little route bonsai: you shape the tree once, then pluck URLs from any branch.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
57
60
|
## Why this exists
|
|
58
61
|
|
|
59
62
|
When you have lots of endpoints, you usually end up with:
|
|
@@ -73,6 +76,10 @@ This DSL gives you:
|
|
|
73
76
|
|
|
74
77
|
## Concepts
|
|
75
78
|
|
|
79
|
+
### `root(children)`
|
|
80
|
+
|
|
81
|
+
An entry point for your root tree that naturally denotes '/' path.
|
|
82
|
+
|
|
76
83
|
### `path(name, children?)`
|
|
77
84
|
|
|
78
85
|
A **static** path segment.
|
|
@@ -142,21 +149,22 @@ Api.core.admin({ isAdmin: false }).invoices(); // "/core/invoices"
|
|
|
142
149
|
|
|
143
150
|
> `wrap` is ideal for *well-known*, reusable gates: `admin`, `v2`, `tenant`, etc.
|
|
144
151
|
|
|
145
|
-
###
|
|
152
|
+
### `.$when(cond, segment | segment[])`
|
|
146
153
|
|
|
147
154
|
Ad‑hoc conditional segment insertion at **runtime**, anywhere in the chain.
|
|
148
155
|
|
|
149
156
|
```ts
|
|
150
|
-
Api.core
|
|
151
|
-
Api.core
|
|
152
|
-
Api.invoices.id("abc")
|
|
157
|
+
Api.core.$when(isAdmin, "admin").invoices();
|
|
158
|
+
Api.core.$when(true, ["tenant", tenantId]).invoices();
|
|
159
|
+
Api.invoices.id("abc").$when(flags.preview, "preview").activities();
|
|
153
160
|
```
|
|
154
161
|
|
|
155
162
|
- `cond = false` → no-op
|
|
156
163
|
- `segment` can be a single segment or an array of segments
|
|
157
164
|
- empty segments are ignored (your `url()` filters them out)
|
|
158
165
|
|
|
159
|
-
>
|
|
166
|
+
> `.$when()` is ideal when you don’t want to bake a wrapper into the route tree.
|
|
167
|
+
> `.$join()` can be used in place of $when with condition being always true.
|
|
160
168
|
|
|
161
169
|
---
|
|
162
170
|
|
|
@@ -211,8 +219,8 @@ Api.invoices(); // "/invoices"
|
|
|
211
219
|
Api.invoices.id("123").customers(); // "/invoices/123/customers"
|
|
212
220
|
|
|
213
221
|
// runtime insert
|
|
214
|
-
Api.core
|
|
215
|
-
Api.core.admin({ isAdmin: true })
|
|
222
|
+
Api.core.$when(true, "v2").invoices(); // "/core/v2/invoices"
|
|
223
|
+
Api.core.admin({ isAdmin: true }).$when(true, "v2").invoices(); // "/core/admin/v2/invoices"
|
|
216
224
|
```
|
|
217
225
|
|
|
218
226
|
### Autocomplete-friendly patterns
|
|
@@ -234,10 +242,10 @@ Because everything is computed from the definition tree, your editor can autocom
|
|
|
234
242
|
- `wrap(name, when, rest?)`
|
|
235
243
|
- `keep()`
|
|
236
244
|
|
|
237
|
-
###
|
|
245
|
+
### Path level builders
|
|
238
246
|
|
|
239
|
-
-
|
|
240
|
-
- `
|
|
247
|
+
- `$when(predicate, segments)`
|
|
248
|
+
- `$join(segments)`
|
|
241
249
|
|
|
242
250
|
---
|
|
243
251
|
|
|
@@ -319,10 +327,10 @@ Dialects are meant to be **all-in** per codebase/file. Technically you can mix i
|
|
|
319
327
|
- `slot("id")` uses `"id"` **only as a property name**, not a URL segment.
|
|
320
328
|
- ✅ `/invoices/123`
|
|
321
329
|
- ❌ `/invoices/id/123`
|
|
322
|
-
-
|
|
330
|
+
- `.$when()` rebuilds a subtree and returns a new object/function.
|
|
323
331
|
- It does **not** mutate the original branch.
|
|
324
332
|
- Empty segments are ignored in the final URL (because `url()` does `filter()`).
|
|
325
|
-
- If you want stricter behavior (throw on empty segment), enforce it in your own
|
|
333
|
+
- If you want stricter behavior (throw on empty segment), enforce it in your own `.$when` wrapper.
|
|
326
334
|
|
|
327
335
|
---
|
|
328
336
|
|
package/dist/api.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var a in e)f(t,a,{get:e[a],enumerable:!0})},b=(t,e,a,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of N(e))!P.call(t,s)&&s!==a&&f(t,s,{get:()=>e[s],enumerable:!(r=y(e,s))||r.enumerable});return t};var D=t=>b(f({},"__esModule",{value:!0}),t);var $={};w($,{keep:()=>R,path:()=>p,root:()=>F,slot:()=>k,wrap:()=>x});module.exports=D($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),R=()=>({kind:"keep"}),p=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),k=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),x=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),K=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!K.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function F(t){return u([],p("",t))}function u(t,e){let a=n=>n.rest.some(o=>o.kind==="keep"),r=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(r,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=o=>{let l=[...r,o];return c(d=>m(l,d),l,[])}:s[n.uuid]=o=>{let l=u([...r,o],n);return Object.assign(a(n)?i=>m([...r,o],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let o=[...r,n.uuid],l=i=>m(o,i);s[n.uuid]=c(l,o,[])}else s[n.uuid]=u(r,n);else n.kind==="wrap"&&(s[n.uuid]=o=>{let i=n.when(o)?[...r,n.uuid]:r,d=u(i,n);return Object.assign(a(n)?h=>m(i,h):Object.create(null),d)});return c(s,r,e.rest)}function c(t,e,a){let r=(s,n)=>{let o=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(o,i),o,a):u(o,p("",a))};return t.$when=r,t.$join=s=>r(!0,s),t}0&&(module.exports={keep,path,root,slot,wrap});
|
|
2
2
|
//# sourceMappingURL=api.cjs.map
|
package/dist/api.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["api_exports","__export","keep","path","root","slot","wrap","__toCommonJS","toCamel","s","_","c","name","rest","assertValidName","when","IDENT","kind","url","search","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
package/dist/api.d.cts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// ---------- Helpers ----------------------
|
|
2
|
+
type KebabToCamel<S extends string> = S extends `${infer A}-${infer B}`
|
|
3
|
+
? `${A}${Capitalize<KebabToCamel<B>>}`
|
|
4
|
+
: S
|
|
5
|
+
|
|
1
6
|
// ---------- Shared public types ----------
|
|
2
7
|
type Segment = string | number
|
|
3
8
|
type SParams = string | URLSearchParams
|
|
@@ -7,19 +12,22 @@ type Keep = { kind: 'keep' }
|
|
|
7
12
|
|
|
8
13
|
type Path<
|
|
9
14
|
Name extends string = string,
|
|
15
|
+
Uuid extends string = string,
|
|
10
16
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
11
|
-
> = { kind: 'path'; name: Name; rest: Rest }
|
|
17
|
+
> = { kind: 'path'; name: Name; uuid: Uuid; rest: Rest }
|
|
12
18
|
|
|
13
19
|
type Slot<
|
|
14
20
|
Name extends string = string,
|
|
21
|
+
Uuid extends string = string,
|
|
15
22
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
16
|
-
> = { kind: 'slot'; name: Name; rest: Rest }
|
|
23
|
+
> = { kind: 'slot'; name: Name; uuid: Uuid; rest: Rest }
|
|
17
24
|
|
|
18
25
|
type Wrap<
|
|
19
26
|
Name extends string = string,
|
|
27
|
+
Uuid extends string = string,
|
|
20
28
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
21
29
|
Args = unknown,
|
|
22
|
-
> = { kind: 'wrap'; name: Name; rest: Rest; when: (args: Args) => boolean }
|
|
30
|
+
> = { kind: 'wrap'; name: Name; uuid: Uuid; rest: Rest; when: (args: Args) => boolean }
|
|
23
31
|
|
|
24
32
|
type SlotDef =
|
|
25
33
|
| Path<string, readonly PathDef[]>
|
|
@@ -29,8 +37,8 @@ type PathDef = SlotDef | Keep
|
|
|
29
37
|
|
|
30
38
|
// ---------- Type-level route builder ----------
|
|
31
39
|
interface Whenable {
|
|
32
|
-
when(cond: boolean, seg: Segment | readonly Segment[]): this
|
|
33
|
-
join(seg: Segment | readonly Segment[]): this
|
|
40
|
+
$when(cond: boolean, seg: Segment | readonly Segment[]): this
|
|
41
|
+
$join(seg: Segment | readonly Segment[]): this
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
type HasKeep<Rest extends readonly PathDef[]> =
|
|
@@ -41,11 +49,11 @@ type NonKeepChildren<Rest extends readonly PathDef[]> = Exclude<Rest[number], Ke
|
|
|
41
49
|
type PropsFromChildren<Rest extends readonly PathDef[]> = {
|
|
42
50
|
[C in NonKeepChildren<Rest> as C extends { name: infer N extends string }
|
|
43
51
|
? N
|
|
44
|
-
: never]: C extends Path<any, any>
|
|
52
|
+
: never]: C extends Path<any, any, any>
|
|
45
53
|
? RouteFromPath<C>
|
|
46
|
-
: C extends Slot<any, any>
|
|
54
|
+
: C extends Slot<any, any, any>
|
|
47
55
|
? RouteFromSlot<C>
|
|
48
|
-
: C extends Wrap<any, any, any>
|
|
56
|
+
: C extends Wrap<any, any, any, any>
|
|
49
57
|
? RouteFromWrap<C>
|
|
50
58
|
: never
|
|
51
59
|
}
|
|
@@ -53,7 +61,7 @@ type PropsFromChildren<Rest extends readonly PathDef[]> = {
|
|
|
53
61
|
type WithWhen<T> = T & Whenable
|
|
54
62
|
|
|
55
63
|
// Example: apply it to the outputs
|
|
56
|
-
type RouteFromPath<N extends Path<any, any>> = WithWhen<
|
|
64
|
+
type RouteFromPath<N extends Path<any, any, any>> = WithWhen<
|
|
57
65
|
N['rest'] extends readonly []
|
|
58
66
|
? (search?: SParams) => string
|
|
59
67
|
: HasKeep<N['rest']> extends true
|
|
@@ -69,9 +77,9 @@ type SlotResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
|
69
77
|
: PropsFromChildren<Rest>
|
|
70
78
|
>
|
|
71
79
|
|
|
72
|
-
type RouteFromSlot<I extends Slot<any, any>> = (param: Segment) => SlotResult<I['rest']>
|
|
80
|
+
type RouteFromSlot<I extends Slot<any, any, any>> = (param: Segment) => SlotResult<I['rest']>
|
|
73
81
|
|
|
74
|
-
type WrapArg<W extends Wrap<any, any, any>> = Parameters<W['when']>[0]
|
|
82
|
+
type WrapArg<W extends Wrap<any, any, any, any>> = Parameters<W['when']>[0]
|
|
75
83
|
|
|
76
84
|
type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
77
85
|
HasKeep<Rest> extends true
|
|
@@ -79,7 +87,7 @@ type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
|
79
87
|
: PropsFromChildren<Rest>
|
|
80
88
|
>
|
|
81
89
|
|
|
82
|
-
type RouteFromWrap<W extends Wrap<any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
|
|
90
|
+
type RouteFromWrap<W extends Wrap<any, any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
|
|
83
91
|
|
|
84
92
|
type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
|
|
85
93
|
HasKeep<Defs> extends true
|
|
@@ -87,10 +95,11 @@ type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
|
|
|
87
95
|
: PropsFromChildren<Defs>
|
|
88
96
|
>
|
|
89
97
|
|
|
98
|
+
type KeyFromSeg<S extends string> = KebabToCamel<S>;
|
|
90
99
|
declare const keep: () => Keep;
|
|
91
|
-
declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, Rest>;
|
|
92
|
-
declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, Rest>;
|
|
93
|
-
declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, Rest, Args>;
|
|
100
|
+
declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, KeyFromSeg<Name>, Rest>;
|
|
101
|
+
declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, KeyFromSeg<Name>, Rest>;
|
|
102
|
+
declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, KeyFromSeg<Name>, Rest, Args>;
|
|
94
103
|
declare function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs>;
|
|
95
104
|
|
|
96
105
|
export { keep, path, root, slot, wrap };
|
package/dist/api.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// ---------- Helpers ----------------------
|
|
2
|
+
type KebabToCamel<S extends string> = S extends `${infer A}-${infer B}`
|
|
3
|
+
? `${A}${Capitalize<KebabToCamel<B>>}`
|
|
4
|
+
: S
|
|
5
|
+
|
|
1
6
|
// ---------- Shared public types ----------
|
|
2
7
|
type Segment = string | number
|
|
3
8
|
type SParams = string | URLSearchParams
|
|
@@ -7,19 +12,22 @@ type Keep = { kind: 'keep' }
|
|
|
7
12
|
|
|
8
13
|
type Path<
|
|
9
14
|
Name extends string = string,
|
|
15
|
+
Uuid extends string = string,
|
|
10
16
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
11
|
-
> = { kind: 'path'; name: Name; rest: Rest }
|
|
17
|
+
> = { kind: 'path'; name: Name; uuid: Uuid; rest: Rest }
|
|
12
18
|
|
|
13
19
|
type Slot<
|
|
14
20
|
Name extends string = string,
|
|
21
|
+
Uuid extends string = string,
|
|
15
22
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
16
|
-
> = { kind: 'slot'; name: Name; rest: Rest }
|
|
23
|
+
> = { kind: 'slot'; name: Name; uuid: Uuid; rest: Rest }
|
|
17
24
|
|
|
18
25
|
type Wrap<
|
|
19
26
|
Name extends string = string,
|
|
27
|
+
Uuid extends string = string,
|
|
20
28
|
Rest extends readonly PathDef[] = readonly PathDef[],
|
|
21
29
|
Args = unknown,
|
|
22
|
-
> = { kind: 'wrap'; name: Name; rest: Rest; when: (args: Args) => boolean }
|
|
30
|
+
> = { kind: 'wrap'; name: Name; uuid: Uuid; rest: Rest; when: (args: Args) => boolean }
|
|
23
31
|
|
|
24
32
|
type SlotDef =
|
|
25
33
|
| Path<string, readonly PathDef[]>
|
|
@@ -29,8 +37,8 @@ type PathDef = SlotDef | Keep
|
|
|
29
37
|
|
|
30
38
|
// ---------- Type-level route builder ----------
|
|
31
39
|
interface Whenable {
|
|
32
|
-
when(cond: boolean, seg: Segment | readonly Segment[]): this
|
|
33
|
-
join(seg: Segment | readonly Segment[]): this
|
|
40
|
+
$when(cond: boolean, seg: Segment | readonly Segment[]): this
|
|
41
|
+
$join(seg: Segment | readonly Segment[]): this
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
type HasKeep<Rest extends readonly PathDef[]> =
|
|
@@ -41,11 +49,11 @@ type NonKeepChildren<Rest extends readonly PathDef[]> = Exclude<Rest[number], Ke
|
|
|
41
49
|
type PropsFromChildren<Rest extends readonly PathDef[]> = {
|
|
42
50
|
[C in NonKeepChildren<Rest> as C extends { name: infer N extends string }
|
|
43
51
|
? N
|
|
44
|
-
: never]: C extends Path<any, any>
|
|
52
|
+
: never]: C extends Path<any, any, any>
|
|
45
53
|
? RouteFromPath<C>
|
|
46
|
-
: C extends Slot<any, any>
|
|
54
|
+
: C extends Slot<any, any, any>
|
|
47
55
|
? RouteFromSlot<C>
|
|
48
|
-
: C extends Wrap<any, any, any>
|
|
56
|
+
: C extends Wrap<any, any, any, any>
|
|
49
57
|
? RouteFromWrap<C>
|
|
50
58
|
: never
|
|
51
59
|
}
|
|
@@ -53,7 +61,7 @@ type PropsFromChildren<Rest extends readonly PathDef[]> = {
|
|
|
53
61
|
type WithWhen<T> = T & Whenable
|
|
54
62
|
|
|
55
63
|
// Example: apply it to the outputs
|
|
56
|
-
type RouteFromPath<N extends Path<any, any>> = WithWhen<
|
|
64
|
+
type RouteFromPath<N extends Path<any, any, any>> = WithWhen<
|
|
57
65
|
N['rest'] extends readonly []
|
|
58
66
|
? (search?: SParams) => string
|
|
59
67
|
: HasKeep<N['rest']> extends true
|
|
@@ -69,9 +77,9 @@ type SlotResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
|
69
77
|
: PropsFromChildren<Rest>
|
|
70
78
|
>
|
|
71
79
|
|
|
72
|
-
type RouteFromSlot<I extends Slot<any, any>> = (param: Segment) => SlotResult<I['rest']>
|
|
80
|
+
type RouteFromSlot<I extends Slot<any, any, any>> = (param: Segment) => SlotResult<I['rest']>
|
|
73
81
|
|
|
74
|
-
type WrapArg<W extends Wrap<any, any, any>> = Parameters<W['when']>[0]
|
|
82
|
+
type WrapArg<W extends Wrap<any, any, any, any>> = Parameters<W['when']>[0]
|
|
75
83
|
|
|
76
84
|
type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
77
85
|
HasKeep<Rest> extends true
|
|
@@ -79,7 +87,7 @@ type WrapResult<Rest extends readonly PathDef[]> = WithWhen<
|
|
|
79
87
|
: PropsFromChildren<Rest>
|
|
80
88
|
>
|
|
81
89
|
|
|
82
|
-
type RouteFromWrap<W extends Wrap<any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
|
|
90
|
+
type RouteFromWrap<W extends Wrap<any, any, any, any>> = (arg: WrapArg<W>) => WrapResult<W['rest']>
|
|
83
91
|
|
|
84
92
|
type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
|
|
85
93
|
HasKeep<Defs> extends true
|
|
@@ -87,10 +95,11 @@ type RoutesFromDefs<Defs extends readonly PathDef[]> = WithWhen<
|
|
|
87
95
|
: PropsFromChildren<Defs>
|
|
88
96
|
>
|
|
89
97
|
|
|
98
|
+
type KeyFromSeg<S extends string> = KebabToCamel<S>;
|
|
90
99
|
declare const keep: () => Keep;
|
|
91
|
-
declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, Rest>;
|
|
92
|
-
declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, Rest>;
|
|
93
|
-
declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, Rest, Args>;
|
|
100
|
+
declare const path: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Path<Name, KeyFromSeg<Name>, Rest>;
|
|
101
|
+
declare const slot: <const Name extends string, const Rest extends readonly PathDef[] = readonly []>(name: Name, rest?: Rest) => Slot<Name, KeyFromSeg<Name>, Rest>;
|
|
102
|
+
declare const wrap: <const Name extends string, const Rest extends readonly PathDef[] = readonly [], Args = unknown>(name: Name, when: (args: Args) => boolean, rest?: Rest) => Wrap<Name, KeyFromSeg<Name>, Rest, Args>;
|
|
94
103
|
declare function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs>;
|
|
95
104
|
|
|
96
105
|
export { keep, path, root, slot, wrap };
|
package/dist/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import{a,b,c,d,e}from"./chunk-5ZW66SPO.js";export{a as keep,b as path,e as root,c as slot,d as wrap};
|
|
2
2
|
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var f=e=>e.replace(/-([a-zA-Z0-9])/g,(t,r)=>r.toUpperCase()),y=()=>({kind:"keep"}),p=(e,t)=>({kind:"path",name:g("path",e),uuid:f(e),rest:t??[]}),N=(e,t)=>({kind:"slot",name:g("slot",e),uuid:f(e),rest:t??[]}),P=(e,t,r)=>({kind:"wrap",name:g("wrap",e),uuid:f(e),when:t,rest:r??[]}),h=/^[A-Za-z_][A-Za-z0-9_]*$/;function g(e,t){if(e==="path"&&t==="")return t.trim();if(!t)throw new Error(`${e} name cannot be empty`);if(!h.test(t))throw new Error(`${e} name "${t}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return t.trim()}var m=(e,t)=>`/${e.filter(Boolean).join("/").replace("//{2,}/g","/")}${t?`?${t}`:""}`;function w(e){return u([],p("",e))}function u(e,t){let r=n=>n.rest.some(a=>a.kind==="keep"),s=t.kind==="slot"||t.kind==="wrap"?e:t.uuid?[...e,t.uuid]:e,o=r(t)?n=>m(s,n):Object.create(null);for(let n of t.rest)if(n.kind==="slot")n.rest.length===0?o[n.uuid]=a=>{let l=[...s,a];return c(d=>m(l,d),l,[])}:o[n.uuid]=a=>{let l=u([...s,a],n);return Object.assign(r(n)?i=>m([...s,a],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let a=[...s,n.uuid],l=i=>m(a,i);o[n.uuid]=c(l,a,[])}else o[n.uuid]=u(s,n);else n.kind==="wrap"&&(o[n.uuid]=a=>{let i=n.when(a)?[...s,n.uuid]:s,d=u(i,n);return Object.assign(r(n)?S=>m(i,S):Object.create(null),d)});return c(o,s,t.rest)}function c(e,t,r){let s=(o,n)=>{let a=o?[...t,...Array.isArray(n)?n:[n]]:t;return r.length===0&&typeof e=="function"?c(i=>m(a,i),a,r):u(a,p("",r))};return e.$when=s,e.$join=o=>s(!0,o),e}export{y as a,p as b,N as c,P as d,w as e};
|
|
2
|
+
//# sourceMappingURL=chunk-5ZW66SPO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of k(e))!D.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=w(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{base:()=>h,bind:()=>y,link:()=>P,mask:()=>N,node:()=>d});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?b=>m(i,b):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={base,bind,link,mask,node});
|
|
2
|
+
//# sourceMappingURL=dialect-node.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dialect-node.ts","../src/api.ts"],"sourcesContent":["export { root as link, path as node, slot as bind, keep as base, wrap as mask } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_node_exports","__export","keep","slot","root","wrap","path","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { keep as base, slot as bind, root as link, wrap as mask, path as node } from './api.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { keep as base, slot as bind, root as link, wrap as mask, path as node } from './api.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=b(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{keep:()=>h,path:()=>d,root:()=>P,slot:()=>y,wrap:()=>N});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?w=>m(i,w):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={keep,path,root,slot,wrap});
|
|
2
|
+
//# sourceMappingURL=dialect-path.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dialect-path.ts","../src/api.ts"],"sourcesContent":["export { root, path, slot, keep, wrap } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_path_exports","__export","keep","path","root","slot","wrap","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { keep, path, root, slot, wrap } from './api.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { keep, path, root, slot, wrap } from './api.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(o=b(e,s))||o.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{gate:()=>N,item:()=>y,make:()=>P,self:()=>h,step:()=>d});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function P(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(r=>r.kind==="keep"),o=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(o,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=r=>{let l=[...o,r];return c(f=>m(l,f),l,[])}:s[n.uuid]=r=>{let l=u([...o,r],n);return Object.assign(a(n)?i=>m([...o,r],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let r=[...o,n.uuid],l=i=>m(r,i);s[n.uuid]=c(l,r,[])}else s[n.uuid]=u(o,n);else n.kind==="wrap"&&(s[n.uuid]=r=>{let i=n.when(r)?[...o,n.uuid]:o,f=u(i,n);return Object.assign(a(n)?w=>m(i,w):Object.create(null),f)});return c(s,o,e.rest)}function c(t,e,a){let o=(s,n)=>{let r=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(r,i),r,a):u(r,d("",a))};return t.$when=o,t.$join=s=>o(!0,s),t}0&&(module.exports={gate,item,make,self,step});
|
|
2
|
+
//# sourceMappingURL=dialect-step.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dialect-step.ts","../src/api.ts"],"sourcesContent":["export { root as make, path as step, slot as item, keep as self, wrap as gate } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_step_exports","__export","wrap","slot","root","keep","path","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { wrap as gate, slot as item, root as make, keep as self, path as step } from './api.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { wrap as gate, slot as item, root as make, keep as self, path as step } from './api.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var a in e)p(t,a,{get:e[a],enumerable:!0})},x=(t,e,a,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!k.call(t,s)&&s!==a&&p(t,s,{get:()=>e[s],enumerable:!(r=b(e,s))||r.enumerable});return t};var K=t=>x(p({},"__esModule",{value:!0}),t);var $={};R($,{grow:()=>w,nest:()=>N,seed:()=>y,tree:()=>d,twig:()=>h});module.exports=K($);var g=t=>t.replace(/-([a-zA-Z0-9])/g,(e,a)=>a.toUpperCase()),h=()=>({kind:"keep"}),d=(t,e)=>({kind:"path",name:S("path",t),uuid:g(t),rest:e??[]}),y=(t,e)=>({kind:"slot",name:S("slot",t),uuid:g(t),rest:e??[]}),N=(t,e,a)=>({kind:"wrap",name:S("wrap",t),uuid:g(t),when:e,rest:a??[]}),F=/^[A-Za-z_][A-Za-z0-9_]*$/;function S(t,e){if(t==="path"&&e==="")return e.trim();if(!e)throw new Error(`${t} name cannot be empty`);if(!F.test(e))throw new Error(`${t} name "${e}" must be a valid identifier (letters/digits/_/$, not starting with a digit).`);return e.trim()}var m=(t,e)=>`/${t.filter(Boolean).join("/").replace("//{2,}/g","/")}${e?`?${e}`:""}`;function w(t){return u([],d("",t))}function u(t,e){let a=n=>n.rest.some(o=>o.kind==="keep"),r=e.kind==="slot"||e.kind==="wrap"?t:e.uuid?[...t,e.uuid]:t,s=a(e)?n=>m(r,n):Object.create(null);for(let n of e.rest)if(n.kind==="slot")n.rest.length===0?s[n.uuid]=o=>{let l=[...r,o];return c(f=>m(l,f),l,[])}:s[n.uuid]=o=>{let l=u([...r,o],n);return Object.assign(a(n)?i=>m([...r,o],i):Object.create(null),l)};else if(n.kind==="path")if(n.rest.length===0){let o=[...r,n.uuid],l=i=>m(o,i);s[n.uuid]=c(l,o,[])}else s[n.uuid]=u(r,n);else n.kind==="wrap"&&(s[n.uuid]=o=>{let i=n.when(o)?[...r,n.uuid]:r,f=u(i,n);return Object.assign(a(n)?P=>m(i,P):Object.create(null),f)});return c(s,r,e.rest)}function c(t,e,a){let r=(s,n)=>{let o=s?[...e,...Array.isArray(n)?n:[n]]:e;return a.length===0&&typeof t=="function"?c(i=>m(o,i),o,a):u(o,d("",a))};return t.$when=r,t.$join=s=>r(!0,s),t}0&&(module.exports={grow,nest,seed,tree,twig});
|
|
2
|
+
//# sourceMappingURL=dialect-tree.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dialect-tree.ts","../src/api.ts"],"sourcesContent":["export { root as grow, path as tree, slot as seed, keep as twig, wrap as nest } from './api'\n","import {\n\tKebabToCamel,\n\tKeep,\n\tPath,\n\tPathDef,\n\tRoutesFromDefs,\n\tSParams,\n\tSegment,\n\tSlot,\n\tSlotDef,\n\tWrap,\n} from './dsl'\n\n// ---------- Transform helpers ------------\nconst toCamel = (s: string) => s.replace(/-([a-zA-Z0-9])/g, (_, c) => c.toUpperCase())\ntype KeyFromSeg<S extends string> = KebabToCamel<S>\n\n// ---------- DSL helpers (typed) ----------\nexport const keep = (): Keep => ({ kind: 'keep' })\n\nexport const path = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Path<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'path',\n\tname: assertValidName('path', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const slot = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n>(\n\tname: Name,\n\trest?: Rest\n): Slot<Name, KeyFromSeg<Name>, Rest> => ({\n\tkind: 'slot',\n\tname: assertValidName('slot', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\trest: (rest ?? []) as Rest,\n})\n\nexport const wrap = <\n\tconst Name extends string,\n\tconst Rest extends readonly PathDef[] = readonly [],\n\tArgs = unknown,\n>(\n\tname: Name,\n\twhen: (args: Args) => boolean,\n\trest?: Rest\n): Wrap<Name, KeyFromSeg<Name>, Rest, Args> => ({\n\tkind: 'wrap',\n\tname: assertValidName('wrap', name),\n\tuuid: toCamel(name) as KeyFromSeg<Name>,\n\twhen,\n\trest: (rest ?? []) as Rest,\n})\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/\n\nfunction assertValidName<const Name extends string>(\n\tkind: 'path' | 'slot' | 'wrap',\n\tname: Name\n): Name {\n\t// Allow your synthetic node(\"\") only for nodes (internal)\n\tif (kind === 'path' && name === '') return name.trim() as Name\n\n\tif (!name) throw new Error(`${kind} name cannot be empty`)\n\tif (!IDENT.test(name)) {\n\t\tthrow new Error(\n\t\t\t`${kind} name \"${name}\" must be a valid identifier (letters/digits/_/$, not starting with a digit).`\n\t\t)\n\t}\n\n\treturn name.trim() as Name\n}\n\n// ---------- Runtime implementation ----------\nconst url = (path: Segment[], search?: SParams) =>\n\t`/${path.filter(Boolean).join('/').replace('/\\/{2,}/g', '/')}${search ? `?${search}` : ''}`\n\n// ---------- Typed root signature ----------\nexport function root<const Defs extends readonly PathDef[]>(defs: Defs): RoutesFromDefs<Defs> {\n\treturn buildPath([], path('', defs)) as unknown as RoutesFromDefs<Defs>\n}\n\nfunction buildPath(prefix: Segment[], def: SlotDef) {\n\tconst hasKeep = (pathDef: SlotDef) => pathDef.rest.some((c: any) => c.kind === 'keep')\n\tconst allPath =\n\t\tdef.kind === 'slot' || def.kind === 'wrap'\n\t\t\t? prefix\n\t\t\t: def.uuid\n\t\t\t\t? [...prefix, def.uuid]\n\t\t\t\t: prefix\n\n\t// If there is a keep(), the path itself is callable and acts as \"keep\"\n\tconst target: any = hasKeep(def)\n\t\t? (search?: SParams) => url(allPath, search)\n\t\t: Object.create(null)\n\n\tfor (const child of def.rest) {\n\t\tif (child.kind === 'slot') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\tconst leafPath = [...allPath, param]\n\t\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\t\treturn attachWhenAndJoin(fn, leafPath, [])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = (param: Segment) => {\n\t\t\t\t\t// Build subtree for nested parts under :id\n\t\t\t\t\t// Synthetic path with empty name so we don't add extra segment.\n\t\t\t\t\tconst subTree = buildPath([...allPath, param], child)\n\n\t\t\t\t\t// Attach children (info, activities, etc.) to that function\n\t\t\t\t\treturn Object.assign(\n\t\t\t\t\t\thasKeep(child)\n\t\t\t\t\t\t\t? (search?: SParams) => url([...allPath, param], search)\n\t\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\t\tsubTree\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (child.kind === 'path') {\n\t\t\tif (child.rest.length === 0) {\n\t\t\t\tconst leafPath = [...allPath, child.uuid]\n\t\t\t\tconst fn: any = (search?: SParams) => url(leafPath, search)\n\t\t\t\ttarget[child.uuid] = attachWhenAndJoin(fn, leafPath, [])\n\t\t\t} else {\n\t\t\t\ttarget[child.uuid] = buildPath(allPath, child)\n\t\t\t}\n\t\t} else if (child.kind === 'wrap') {\n\t\t\ttarget[child.uuid] = (arg: unknown) => {\n\t\t\t\tconst enabled = child.when(arg)\n\t\t\t\tconst wrapped = enabled ? [...allPath, child.uuid] : allPath\n\t\t\t\tconst subTree = buildPath(wrapped, child as any)\n\n\t\t\t\treturn Object.assign(\n\t\t\t\t\t// if wrap has keep(), it becomes callable at that point\n\t\t\t\t\thasKeep(child as any)\n\t\t\t\t\t\t? (search?: SParams) => url(wrapped, search)\n\t\t\t\t\t\t: Object.create(null),\n\t\t\t\t\tsubTree\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn attachWhenAndJoin(target, allPath, def.rest)\n}\n\nfunction attachWhenAndJoin(target: any, basePath: Segment[], rest: readonly PathDef[]) {\n\tconst when = (cond: boolean, seg: Segment | readonly Segment[]) => {\n\t\tconst nextPath = cond ? [...basePath, ...(Array.isArray(seg) ? seg : [seg])] : basePath\n\n\t\t// If this is a callable leaf (no children), preserve callability after .when().\n\t\tif (rest.length === 0 && typeof target === 'function') {\n\t\t\tconst leaf: any = (search?: SParams) => url(nextPath, search)\n\t\t\treturn attachWhenAndJoin(leaf, nextPath, rest)\n\t\t}\n\n\t\t// Rebuild \"same subtree\" at a new prefix:\n\t\t// Use a synthetic path '' so we don't append an extra segment name.\n\t\treturn buildPath(nextPath, path('', rest))\n\t}\n\n\ttarget.$when = when\n\ttarget.$join = (seg: Segment | readonly Segment[]) => when(true, seg)\n\n\treturn target\n}\n"],"mappings":"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","names":["dialect_tree_exports","__export","root","wrap","slot","path","keep","__toCommonJS","toCamel","s","_","c","keep","path","name","rest","assertValidName","slot","wrap","when","IDENT","kind","url","search","root","defs","buildPath","prefix","def","hasKeep","pathDef","allPath","target","child","param","leafPath","attachWhenAndJoin","subTree","fn","arg","wrapped","basePath","cond","seg","nextPath"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { root as grow, wrap as nest, slot as seed, path as tree, keep as twig } from './api.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { root as grow, wrap as nest, slot as seed, path as tree, keep as twig } from './api.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "route-sprout",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
},
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"type": "module",
|
|
27
|
-
"main": "./dist/
|
|
28
|
-
"module": "./dist/
|
|
29
|
-
"types": "./dist/
|
|
27
|
+
"main": "./dist/api.cjs",
|
|
28
|
+
"module": "./dist/api.js",
|
|
29
|
+
"types": "./dist/api.d.ts",
|
|
30
30
|
"files": [
|
|
31
31
|
"dist/**/*"
|
|
32
32
|
],
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
|
-
"build": "vitest && tsup src/api.ts --format esm,cjs --dts --clean --sourcemap --minify",
|
|
66
|
+
"build": "vitest && tsup src/api.ts src/dialect-node.ts src/dialect-path.ts src/dialect-step.ts src/dialect-tree.ts --format esm,cjs --dts --clean --sourcemap --minify",
|
|
67
67
|
"publish": "npm publish --access public",
|
|
68
68
|
"test": "vitest"
|
|
69
69
|
},
|