@lovrozagar/honey 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural intern for generated route-tree modules.
|
|
3
|
+
*
|
|
4
|
+
* Handler objects stay unique (`.routeTree()` patches `fn`/`mw`/`iv`/`os` onto each
|
|
5
|
+
* `H*`). Values they point at — JSON Schema subtrees, meta objects, selector strings,
|
|
6
|
+
* error-key arrays — are shared by identity when their JSON is identical.
|
|
7
|
+
*/
|
|
8
|
+
export type ForcedPrefix = "I" | "M" | "O" | "P";
|
|
9
|
+
export declare class InternPool {
|
|
10
|
+
private readonly counts;
|
|
11
|
+
private readonly firstSeen;
|
|
12
|
+
private readonly forced;
|
|
13
|
+
private readonly forcedPrefix;
|
|
14
|
+
private readonly ids;
|
|
15
|
+
private readonly prefixCounters;
|
|
16
|
+
private readonly values;
|
|
17
|
+
private sealed;
|
|
18
|
+
count(v: unknown): void;
|
|
19
|
+
force(v: unknown, prefix: ForcedPrefix): void;
|
|
20
|
+
seal(): void;
|
|
21
|
+
id(v: unknown): string | undefined;
|
|
22
|
+
expr(v: unknown): string;
|
|
23
|
+
emitConstLines(): string[];
|
|
24
|
+
private shouldIntern;
|
|
25
|
+
private prefixFor;
|
|
26
|
+
private bump;
|
|
27
|
+
private printExpanded;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=codegen-route-tree-intern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen-route-tree-intern.d.ts","sourceRoot":"","sources":["../src/codegen-route-tree-intern.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AA4BhD,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,MAAM,CAAQ;IAEtB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAsBtB;IAED,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAU5C;IAED,IAAI,IAAI,IAAI,CAWX;IAED,EAAE,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGjC;IAED,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAKvB;IAED,cAAc,IAAI,MAAM,EAAE,CAczB;IAED,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,aAAa;CAerB"}
|
package/dist/codegen.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAQA,OAAO,EACN,KAAK,qBAAqB,EAG1B,MAAM,uBAAuB,CAAA;AAY9B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,WAAW,CAAA;AAcvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACxF,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AA8NnD,KAAK,UAAU,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,KAAK,kBAAkB,GAAG;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,KAAK,aAAa,GAAG;IACpB,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAC5B,CAAA;AAED,KAAK,WAAW,GAAG;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACzB,UAAU,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACzC,CAAA;IACD,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAC9D,CAAA;AAgHD,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAyB7D,CAAA;AAmCD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AA6ClD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAO1E;AA0SD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CA6FjE;AAED,MAAM,MAAM,sBAAsB,GAAG;IACpC,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAA;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC/B,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAA;CACrC,CAAA;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,GAAG,WAAW,CAkCnG;AAwED,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CAgDpE;AAqPD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAC1C,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAC/D,aAAa,CAyDf;AAID,MAAM,MAAM,gBAAgB,CAAC,KAAK,GAAG,OAAO,IAAI;IAC/C,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACZ,CAAA;AAuHD,wBAAsB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,EAChE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAC/D,OAAO,EAAE;IACR,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,KAAK,OAAO,CAAA;IAC1D,IAAI,EAAE,WAAW,CAAA;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC,GACC,OAAO,CAAC,WAAW,CAAC,CAuVtB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EACxC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAC/D,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAoCzC;AAID,KAAK,WAAW,GAAG;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,wHAAwH;IACxH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;IAC5D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;IAC7D,IAAI,EAAE,MAAM,CAAA;CACZ,CAAA;AAwUD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAE/D;AAUD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAClD,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAC/D,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,MAAM,CAE7E;AAID,KAAK,oBAAoB,GAAG;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAC1F,CAAA;AA0KD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EACvC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EACjE,OAAO,EAAE,oBAAoB,GAC3B,MAAM,CAiNR;AAID,MAAM,MAAM,gBAAgB,GAAG;IAC9B,UAAU,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACjD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACzC,CAAA;IACD,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAC9D,CAAA;AAED,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,CAkDzE;AAED,wBAAgB,SAAS,CACxB,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE;IACP,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CACf,GACC,gBAAgB,CAwClB;AAID,KAAK,YAAY,GAAG;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,GAAG,CAAC,EAAE,OAAO,CAAA;CACb,CAAA;AAED,KAAK,iBAAiB,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAAE,CAAA;AAE3D,KAAK,YAAY,GAAG;IACnB,KAAK,EAAE;QACN,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,GAAG,EAAE,MAAM,CAAA;QACX,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;QACtB,KAAK,EAAE,MAAM,CAAA;KACb,CAAA;IACD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;CACxD,CAAA;AAED,KAAK,SAAS,GAAG;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,iBAAiB,EAAE,OAAO,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,OAAO,CAAA;IACZ,EAAE,EAAE,OAAO,CAAA;CACX,CAAA;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAQ1E;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,KAAK,SAAI,GAAG,MAAM,CAG7F;AAyID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiChH;AA4nED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG;IAC1D,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;IACxD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;IACzC,OAAO,EAAE,SAAS,EAAE,CAAA;CACpB,CAwDA;AAiDD,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAwB5G"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural intern for generated route-tree modules.
|
|
3
|
+
*
|
|
4
|
+
* Handler objects stay unique (`.routeTree()` patches `fn`/`mw`/`iv`/`os` onto each
|
|
5
|
+
* `H*`). Values they point at — JSON Schema subtrees, meta objects, selector strings,
|
|
6
|
+
* error-key arrays — are shared by identity when their JSON is identical.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type ForcedPrefix = "I" | "M" | "O" | "P"
|
|
10
|
+
|
|
11
|
+
const STRING_MIN = 8
|
|
12
|
+
const NUMBER_MIN = 8
|
|
13
|
+
|
|
14
|
+
function canonical(v: unknown): string {
|
|
15
|
+
if (v === undefined) return "__undefined__"
|
|
16
|
+
return JSON.stringify(v) as string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function valueDepth(v: unknown): number {
|
|
20
|
+
if (v === null || typeof v !== "object") return 0
|
|
21
|
+
let max = 0
|
|
22
|
+
if (Array.isArray(v)) {
|
|
23
|
+
for (const x of v) {
|
|
24
|
+
const d = valueDepth(x)
|
|
25
|
+
if (d > max) max = d
|
|
26
|
+
}
|
|
27
|
+
return max + 1
|
|
28
|
+
}
|
|
29
|
+
for (const x of Object.values(v as Record<string, unknown>)) {
|
|
30
|
+
if (x === undefined) continue
|
|
31
|
+
const d = valueDepth(x)
|
|
32
|
+
if (d > max) max = d
|
|
33
|
+
}
|
|
34
|
+
return max + 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class InternPool {
|
|
38
|
+
private readonly counts = new Map<string, number>()
|
|
39
|
+
private readonly firstSeen: string[] = []
|
|
40
|
+
private readonly forced = new Set<string>()
|
|
41
|
+
private readonly forcedPrefix = new Map<string, ForcedPrefix>()
|
|
42
|
+
private readonly ids = new Map<string, string>()
|
|
43
|
+
private readonly prefixCounters = new Map<string, number>()
|
|
44
|
+
private readonly values = new Map<string, unknown>()
|
|
45
|
+
private sealed = false
|
|
46
|
+
|
|
47
|
+
count(v: unknown): void {
|
|
48
|
+
if (v === null || v === undefined) return
|
|
49
|
+
const t = typeof v
|
|
50
|
+
if (t === "boolean") return
|
|
51
|
+
if (t === "number") {
|
|
52
|
+
if (Number.isFinite(v) && String(v).length >= NUMBER_MIN) this.bump(v)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
if (t === "string") {
|
|
56
|
+
if ((v as string).length >= STRING_MIN) this.bump(v)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
if (t === "object") {
|
|
60
|
+
this.bump(v)
|
|
61
|
+
if (Array.isArray(v)) {
|
|
62
|
+
for (const x of v) this.count(x)
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
for (const x of Object.values(v as Record<string, unknown>)) {
|
|
66
|
+
if (x !== undefined) this.count(x)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
force(v: unknown, prefix: ForcedPrefix): void {
|
|
72
|
+
if (v === null || v === undefined) return
|
|
73
|
+
const c = canonical(v)
|
|
74
|
+
if (!this.values.has(c)) {
|
|
75
|
+
this.values.set(c, v)
|
|
76
|
+
this.firstSeen.push(c)
|
|
77
|
+
this.counts.set(c, this.counts.get(c) ?? 1)
|
|
78
|
+
}
|
|
79
|
+
this.forced.add(c)
|
|
80
|
+
if (!this.forcedPrefix.has(c)) this.forcedPrefix.set(c, prefix)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
seal(): void {
|
|
84
|
+
if (this.sealed) return
|
|
85
|
+
this.sealed = true
|
|
86
|
+
for (const c of this.firstSeen) {
|
|
87
|
+
const v = this.values.get(c)
|
|
88
|
+
if (!this.shouldIntern(v)) continue
|
|
89
|
+
const prefix = this.prefixFor(c, v)
|
|
90
|
+
const n = this.prefixCounters.get(prefix) ?? 0
|
|
91
|
+
this.prefixCounters.set(prefix, n + 1)
|
|
92
|
+
this.ids.set(c, `${prefix}${n}`)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
id(v: unknown): string | undefined {
|
|
97
|
+
if (v === undefined) return undefined
|
|
98
|
+
return this.ids.get(canonical(v))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
expr(v: unknown): string {
|
|
102
|
+
if (v === undefined) return "undefined"
|
|
103
|
+
const ref = this.ids.get(canonical(v))
|
|
104
|
+
if (ref !== undefined) return ref
|
|
105
|
+
return this.printExpanded(v)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
emitConstLines(): string[] {
|
|
109
|
+
const items: Array<{ c: string; depth: number; id: string; seen: number; v: unknown }> = []
|
|
110
|
+
for (const [c, id] of this.ids) {
|
|
111
|
+
const v = this.values.get(c)
|
|
112
|
+
items.push({ c, depth: valueDepth(v), id, seen: this.firstSeen.indexOf(c), v })
|
|
113
|
+
}
|
|
114
|
+
items.sort((a, b) => a.depth - b.depth || a.seen - b.seen || a.id.localeCompare(b.id))
|
|
115
|
+
return items.map((it) => {
|
|
116
|
+
const kind = this.forcedPrefix.get(it.c)
|
|
117
|
+
let rhs = this.printExpanded(it.v)
|
|
118
|
+
if (kind === "I") rhs += ' as unknown as RouteHandler["iv"]'
|
|
119
|
+
else if (kind === "O") rhs += ' as unknown as RouteHandler["os"]'
|
|
120
|
+
return `const ${it.id} = ${rhs}`
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private shouldIntern(v: unknown): boolean {
|
|
125
|
+
if (v === null || v === undefined) return false
|
|
126
|
+
const c = canonical(v)
|
|
127
|
+
if (this.forced.has(c)) return true
|
|
128
|
+
const n = this.counts.get(c) ?? 0
|
|
129
|
+
if (n < 2) return false
|
|
130
|
+
const t = typeof v
|
|
131
|
+
if (t === "string") return (v as string).length >= STRING_MIN
|
|
132
|
+
if (t === "number") return Number.isFinite(v) && String(v).length >= NUMBER_MIN
|
|
133
|
+
if (Array.isArray(v) && v.length === 0) return false
|
|
134
|
+
return t === "object"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private prefixFor(c: string, v: unknown): string {
|
|
138
|
+
const forced = this.forcedPrefix.get(c)
|
|
139
|
+
if (forced !== undefined) return forced
|
|
140
|
+
if (typeof v === "string") return "T"
|
|
141
|
+
if (typeof v === "number") return "U"
|
|
142
|
+
if (Array.isArray(v)) return "A"
|
|
143
|
+
return "J"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private bump(v: unknown): void {
|
|
147
|
+
const c = canonical(v)
|
|
148
|
+
const n = (this.counts.get(c) ?? 0) + 1
|
|
149
|
+
this.counts.set(c, n)
|
|
150
|
+
if (n === 1) {
|
|
151
|
+
this.values.set(c, v)
|
|
152
|
+
this.firstSeen.push(c)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private printExpanded(v: unknown): string {
|
|
157
|
+
if (v === null) return "null"
|
|
158
|
+
if (v === true) return "true"
|
|
159
|
+
if (v === false) return "false"
|
|
160
|
+
const t = typeof v
|
|
161
|
+
if (t === "string") return JSON.stringify(v)
|
|
162
|
+
if (t === "number") return String(v)
|
|
163
|
+
if (Array.isArray(v)) return `[${v.map((x) => this.expr(x)).join(",")}]`
|
|
164
|
+
if (t === "object") {
|
|
165
|
+
const obj = v as Record<string, unknown>
|
|
166
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== undefined)
|
|
167
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${this.expr(obj[k])}`).join(",")}}`
|
|
168
|
+
}
|
|
169
|
+
return JSON.stringify(v) ?? "undefined"
|
|
170
|
+
}
|
|
171
|
+
}
|
package/src/codegen.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { InternPool } from "./codegen-route-tree-intern.ts"
|
|
1
2
|
import { deriveErrorEnvelopeName, deriveSchemaName, isErrorEnvelope, shortHash } from "./codegen-schema-naming.ts"
|
|
2
3
|
import type { SchemaNameContext } from "./codegen-schema-naming.ts"
|
|
3
4
|
import { effectJsonSchemaFn, loadEffectJsonSchema, loadToJSONSchema, toJSONSchemaFn } from "./codegen-loaders.ts"
|
|
@@ -2009,7 +2010,7 @@ function serializeNode(node: TreeBuild): string {
|
|
|
2009
2010
|
const staticEntries = Object.entries(node.children)
|
|
2010
2011
|
const sExpr =
|
|
2011
2012
|
staticEntries.length > 0
|
|
2012
|
-
? `
|
|
2013
|
+
? `S({ ${staticEntries.map(([k, v]) => `${JSON.stringify(k)}: ${serializeNode(v)}`).join(", ")} })`
|
|
2013
2014
|
: "E"
|
|
2014
2015
|
|
|
2015
2016
|
const dExpr = node.dynamic
|
|
@@ -2023,163 +2024,207 @@ function serializeNode(node: TreeBuild): string {
|
|
|
2023
2024
|
const mExpr =
|
|
2024
2025
|
node.handlers.length > 0 ? `{ ${node.handlers.map((h) => `${h.method}: ${h.handler}`).join(", ")} }` : "null"
|
|
2025
2026
|
|
|
2026
|
-
|
|
2027
|
+
const args = [sExpr]
|
|
2028
|
+
if (mExpr !== "null" || dExpr !== "null" || wExpr !== "null") {
|
|
2029
|
+
args.push(mExpr)
|
|
2030
|
+
if (dExpr !== "null" || wExpr !== "null") {
|
|
2031
|
+
args.push(dExpr)
|
|
2032
|
+
if (wExpr !== "null") args.push(wExpr)
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
return `N(${args.join(", ")})`
|
|
2027
2036
|
}
|
|
2028
2037
|
|
|
2029
|
-
function
|
|
2030
|
-
if (
|
|
2031
|
-
if (
|
|
2032
|
-
|
|
2033
|
-
if (Array.isArray(v)) return "unknown[]"
|
|
2034
|
-
if (typeof v === "string") return JSON.stringify(v)
|
|
2035
|
-
if (typeof v === "number") return String(v)
|
|
2036
|
-
if (typeof v === "object") return "Record<string, unknown>"
|
|
2037
|
-
return typeof v
|
|
2038
|
+
function nodeHasStatic(node: TreeBuild): boolean {
|
|
2039
|
+
if (Object.keys(node.children).length > 0) return true
|
|
2040
|
+
if (node.dynamic !== null) return nodeHasStatic(node.dynamic.child)
|
|
2041
|
+
return false
|
|
2038
2042
|
}
|
|
2039
2043
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
lines.push("")
|
|
2044
|
-
lines.push("const E = Object.create(null) as Record<string, TreeNode>")
|
|
2045
|
-
lines.push("")
|
|
2044
|
+
function selectorOf(route: RouteConfig): string {
|
|
2045
|
+
return `${route.method} ${route.path}`
|
|
2046
|
+
}
|
|
2046
2047
|
|
|
2047
|
-
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
}
|
|
2052
|
-
|
|
2053
|
-
/* emit handler configs with pre-built ek and mt */
|
|
2054
|
-
for (const { index, route } of handlerEntries) {
|
|
2055
|
-
const mwList = "[]"
|
|
2056
|
-
const bekExpr = route.boundaryErrorKey !== null ? JSON.stringify(route.boundaryErrorKey) : "null"
|
|
2057
|
-
const ekSet = route.errorKeys.length > 0 ? `new Set(${JSON.stringify(route.errorKeys)})` : "new Set()"
|
|
2058
|
-
const mtExpr = route.meta !== null ? JSON.stringify(route.meta) : "null"
|
|
2059
|
-
const ivExpr =
|
|
2060
|
-
route.inputSchemas !== null ? `${JSON.stringify(route.inputSchemas)} as unknown as RouteHandler["iv"]` : "null"
|
|
2061
|
-
const osExpr =
|
|
2062
|
-
route.outputSchemas !== null ? `${JSON.stringify(route.outputSchemas)} as unknown as RouteHandler["os"]` : "null"
|
|
2063
|
-
lines.push(
|
|
2064
|
-
`const H${index}: RouteHandler = { bek: ${bekExpr}, ef: null, fn: null as unknown as RouteHandler["fn"], mw: ${mwList}, ek: ${ekSet}, iv: ${ivExpr}, os: ${osExpr}, mt: ${mtExpr}, ov: null, rp: "" }`,
|
|
2065
|
-
)
|
|
2066
|
-
}
|
|
2048
|
+
function mapKeyExpr(intern: InternPool, selector: string): string {
|
|
2049
|
+
const id = intern.id(selector)
|
|
2050
|
+
return id !== undefined ? `[${id}]` : JSON.stringify(selector)
|
|
2051
|
+
}
|
|
2067
2052
|
|
|
2068
|
-
|
|
2053
|
+
function buildInternPool(routes: RouteConfig[]): InternPool {
|
|
2054
|
+
const intern = new InternPool()
|
|
2055
|
+
for (const route of routes) {
|
|
2056
|
+
intern.count(route.boundaryErrorKey)
|
|
2057
|
+
intern.count(route.errorKeys)
|
|
2058
|
+
intern.count(route.inputSchemas)
|
|
2059
|
+
intern.count(route.outputSchemas)
|
|
2060
|
+
intern.count(route.meta)
|
|
2061
|
+
intern.count(selectorOf(route))
|
|
2062
|
+
}
|
|
2063
|
+
for (const route of routes) {
|
|
2064
|
+
intern.force(route.inputSchemas, "I")
|
|
2065
|
+
intern.force(route.outputSchemas, "O")
|
|
2066
|
+
intern.force(route.meta, "M")
|
|
2067
|
+
intern.force(selectorOf(route), "P")
|
|
2068
|
+
}
|
|
2069
|
+
intern.seal()
|
|
2070
|
+
return intern
|
|
2071
|
+
}
|
|
2069
2072
|
|
|
2070
|
-
|
|
2071
|
-
const
|
|
2073
|
+
function insertHandler(rootBuild: TreeBuild, route: RouteConfig, hName: string): void {
|
|
2074
|
+
const segments = route.path.split("/").filter((s) => s.length > 0)
|
|
2075
|
+
let node = rootBuild
|
|
2072
2076
|
|
|
2073
|
-
for (
|
|
2074
|
-
const
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
const seg = segments[i]
|
|
2080
|
-
if (seg.startsWith("*")) {
|
|
2081
|
-
const name = seg.length > 1 ? seg.slice(1) : "*"
|
|
2082
|
-
if (node.wildcard === null) {
|
|
2083
|
-
node.wildcard = { handlers: [], name }
|
|
2084
|
-
}
|
|
2085
|
-
node.wildcard.handlers.push({ handler: hName, method: route.method })
|
|
2086
|
-
break
|
|
2087
|
-
}
|
|
2088
|
-
if (seg.startsWith(":")) {
|
|
2089
|
-
const name = seg.endsWith("?") ? seg.slice(1, -1) : seg.slice(1)
|
|
2090
|
-
if (node.dynamic === null) {
|
|
2091
|
-
node.dynamic = { child: createTreeBuild(), name }
|
|
2092
|
-
}
|
|
2093
|
-
if (i === segments.length - 1) {
|
|
2094
|
-
node.dynamic.child.handlers.push({
|
|
2095
|
-
handler: hName,
|
|
2096
|
-
method: route.method,
|
|
2097
|
-
})
|
|
2098
|
-
} else {
|
|
2099
|
-
node = node.dynamic.child
|
|
2100
|
-
}
|
|
2101
|
-
continue
|
|
2077
|
+
for (let i = 0; i < segments.length; i++) {
|
|
2078
|
+
const seg = segments[i]
|
|
2079
|
+
if (seg.startsWith("*")) {
|
|
2080
|
+
const name = seg.length > 1 ? seg.slice(1) : "*"
|
|
2081
|
+
if (node.wildcard === null) {
|
|
2082
|
+
node.wildcard = { handlers: [], name }
|
|
2102
2083
|
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2084
|
+
node.wildcard.handlers.push({ handler: hName, method: route.method })
|
|
2085
|
+
return
|
|
2086
|
+
}
|
|
2087
|
+
if (seg.startsWith(":")) {
|
|
2088
|
+
const name = seg.endsWith("?") ? seg.slice(1, -1) : seg.slice(1)
|
|
2089
|
+
if (node.dynamic === null) {
|
|
2090
|
+
node.dynamic = { child: createTreeBuild(), name }
|
|
2105
2091
|
}
|
|
2106
2092
|
if (i === segments.length - 1) {
|
|
2107
|
-
node.
|
|
2093
|
+
node.dynamic.child.handlers.push({
|
|
2108
2094
|
handler: hName,
|
|
2109
2095
|
method: route.method,
|
|
2110
2096
|
})
|
|
2111
2097
|
} else {
|
|
2112
|
-
node = node.
|
|
2098
|
+
node = node.dynamic.child
|
|
2113
2099
|
}
|
|
2100
|
+
continue
|
|
2114
2101
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2102
|
+
if (node.children[seg] === undefined) {
|
|
2103
|
+
node.children[seg] = createTreeBuild()
|
|
2104
|
+
}
|
|
2105
|
+
if (i === segments.length - 1) {
|
|
2106
|
+
node.children[seg].handlers.push({
|
|
2107
|
+
handler: hName,
|
|
2108
|
+
method: route.method,
|
|
2109
|
+
})
|
|
2110
|
+
} else {
|
|
2111
|
+
node = node.children[seg]
|
|
2118
2112
|
}
|
|
2119
2113
|
}
|
|
2120
2114
|
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
/* emit handler lookup map for .routeTree() patching */
|
|
2125
|
-
const handlerMapEntries = handlerEntries.map(
|
|
2126
|
-
({ index, route }) => `\t${JSON.stringify(`${route.method} ${route.path}`)}: H${index}`,
|
|
2127
|
-
)
|
|
2128
|
-
lines.push(`export const handlers: Record<string, RouteHandler> = {\n${handlerMapEntries.join(",\n")}\n}`)
|
|
2129
|
-
lines.push("")
|
|
2130
|
-
|
|
2131
|
-
return lines.join("\n")
|
|
2132
|
-
}
|
|
2133
|
-
|
|
2134
|
-
function generateFromTreeRoot(root: TreeNode): string {
|
|
2135
|
-
const routes: RouteConfig[] = []
|
|
2136
|
-
collectRoutesForTree(root, "", routes)
|
|
2137
|
-
|
|
2138
|
-
const collected: CollectedRoute[] = []
|
|
2139
|
-
walkTree(root, "", collected)
|
|
2140
|
-
|
|
2141
|
-
let code = generateRouteTree(routes)
|
|
2142
|
-
|
|
2143
|
-
/* emit meta export — full meta for gateway/external consumers */
|
|
2144
|
-
const metaEntries: string[] = []
|
|
2145
|
-
for (const { handler, method, path } of collected) {
|
|
2146
|
-
if (handler.mt === null || Object.keys(handler.mt).length === 0) continue
|
|
2147
|
-
metaEntries.push(`\t${JSON.stringify(`${method} ${path}`)}: ${JSON.stringify(handler.mt)}`)
|
|
2115
|
+
if (segments.length === 0) {
|
|
2116
|
+
node.handlers.push({ handler: hName, method: route.method })
|
|
2148
2117
|
}
|
|
2118
|
+
}
|
|
2149
2119
|
|
|
2150
|
-
|
|
2120
|
+
function collectMetaShape(collected: CollectedRoute[]): {
|
|
2121
|
+
allKeys: Map<string, Set<string>>
|
|
2122
|
+
keyCount: Map<string, number>
|
|
2123
|
+
metaHandlerCount: number
|
|
2124
|
+
} {
|
|
2151
2125
|
const allKeys = new Map<string, Set<string>>()
|
|
2126
|
+
const keyCount = new Map<string, number>()
|
|
2152
2127
|
let metaHandlerCount = 0
|
|
2153
2128
|
for (const { handler } of collected) {
|
|
2154
2129
|
if (handler.mt === null) continue
|
|
2155
2130
|
metaHandlerCount++
|
|
2156
2131
|
for (const [k, v] of Object.entries(handler.mt)) {
|
|
2157
2132
|
if (!allKeys.has(k)) allKeys.set(k, new Set())
|
|
2158
|
-
allKeys.get(k)?.add(
|
|
2133
|
+
allKeys.get(k)?.add(emitLiteral(v))
|
|
2134
|
+
keyCount.set(k, (keyCount.get(k) ?? 0) + 1)
|
|
2159
2135
|
}
|
|
2160
2136
|
}
|
|
2137
|
+
return { allKeys, keyCount, metaHandlerCount }
|
|
2138
|
+
}
|
|
2161
2139
|
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2140
|
+
function emitMetaShapeType(shape: ReturnType<typeof collectMetaShape>): string {
|
|
2141
|
+
if (shape.allKeys.size === 0) return ""
|
|
2142
|
+
const props = [...shape.allKeys.entries()]
|
|
2143
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
2144
|
+
.map(([key, types]) => {
|
|
2145
|
+
const optional = (shape.keyCount.get(key) ?? 0) < shape.metaHandlerCount ? "?" : ""
|
|
2146
|
+
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `"${key}"`
|
|
2147
|
+
return `\t${safeKey}${optional}: ${[...types].join(" | ")}`
|
|
2148
|
+
})
|
|
2149
|
+
return `export type MetaShape = {\n${props.join("\n")}\n} & Record<string, unknown>\n`
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
function emitRouteTree(routes: RouteConfig[], collected: CollectedRoute[] | null): string {
|
|
2153
|
+
const intern = buildInternPool(routes)
|
|
2154
|
+
const metaShape = collected !== null ? collectMetaShape(collected) : null
|
|
2155
|
+
const hasMetaShape = metaShape !== null && metaShape.allKeys.size > 0
|
|
2156
|
+
const lines: string[] = []
|
|
2157
|
+
lines.push('import type { TreeNode, RouteHandler, RouteTree } from "@lovrozagar/honey/tree"')
|
|
2158
|
+
lines.push("")
|
|
2159
|
+
lines.push("const E = Object.create(null) as Record<string, TreeNode>")
|
|
2160
|
+
lines.push(
|
|
2161
|
+
'function N(s: Record<string, TreeNode>, m: Record<string, RouteHandler> | null = null, d: TreeNode["d"] = null, w: { n: string; m: Record<string, RouteHandler> } | null = null): TreeNode {',
|
|
2162
|
+
)
|
|
2163
|
+
lines.push('\treturn { s, d, w: w as TreeNode["w"], m: m as TreeNode["m"], ws: null }')
|
|
2164
|
+
lines.push("}")
|
|
2165
|
+
|
|
2166
|
+
const rootBuild = createTreeBuild()
|
|
2167
|
+
for (let i = 0; i < routes.length; i++) {
|
|
2168
|
+
insertHandler(rootBuild, routes[i], `H${i}`)
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
if (nodeHasStatic(rootBuild)) {
|
|
2172
|
+
lines.push("function S(o: Record<string, TreeNode>): Record<string, TreeNode> {")
|
|
2173
|
+
lines.push("\treturn Object.assign(Object.create(null), o) as Record<string, TreeNode>")
|
|
2174
|
+
lines.push("}")
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
if (routes.length > 0) {
|
|
2178
|
+
lines.push('const FN = null as unknown as RouteHandler["fn"]')
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
const consts = intern.emitConstLines()
|
|
2182
|
+
if (consts.length > 0) {
|
|
2183
|
+
lines.push("")
|
|
2184
|
+
for (const line of consts) {
|
|
2185
|
+
if (hasMetaShape && /^const M\d+ = /.test(line)) lines.push(`${line} as unknown as MetaShape`)
|
|
2186
|
+
else lines.push(line)
|
|
2168
2187
|
}
|
|
2169
2188
|
}
|
|
2170
2189
|
|
|
2171
|
-
if (
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2190
|
+
if (routes.length > 0) {
|
|
2191
|
+
lines.push("")
|
|
2192
|
+
/* unique handler per route — sharing H objects would cross-wire .routeTree() patches */
|
|
2193
|
+
for (let i = 0; i < routes.length; i++) {
|
|
2194
|
+
const route = routes[i]
|
|
2195
|
+
const bekExpr = route.boundaryErrorKey !== null ? intern.expr(route.boundaryErrorKey) : "null"
|
|
2196
|
+
const ekSet = route.errorKeys.length > 0 ? `new Set(${intern.expr(route.errorKeys)})` : "new Set()"
|
|
2197
|
+
const ivExpr = route.inputSchemas !== null ? intern.expr(route.inputSchemas) : "null"
|
|
2198
|
+
const osExpr = route.outputSchemas !== null ? intern.expr(route.outputSchemas) : "null"
|
|
2199
|
+
const mtExpr = route.meta !== null ? intern.expr(route.meta) : "null"
|
|
2200
|
+
lines.push(
|
|
2201
|
+
`const H${i}: RouteHandler = { bek: ${bekExpr}, ef: null, fn: FN, mw: [], ek: ${ekSet}, iv: ${ivExpr}, os: ${osExpr}, mt: ${mtExpr}, ov: null, rp: "" }`,
|
|
2202
|
+
)
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
lines.push("")
|
|
2207
|
+
lines.push(`export const tree: TreeNode = ${serializeNode(rootBuild)}`)
|
|
2208
|
+
lines.push("")
|
|
2209
|
+
|
|
2210
|
+
const handlerMapEntries = routes.map((route, index) => `\t${mapKeyExpr(intern, selectorOf(route))}: H${index}`)
|
|
2211
|
+
lines.push(`export const handlers: Record<string, RouteHandler> = {\n${handlerMapEntries.join(",\n")}\n}`)
|
|
2212
|
+
lines.push("")
|
|
2213
|
+
|
|
2214
|
+
let code = lines.join("\n")
|
|
2215
|
+
if (collected === null) return code
|
|
2216
|
+
|
|
2217
|
+
const metaEntries: string[] = []
|
|
2218
|
+
for (const { handler, method, path } of collected) {
|
|
2219
|
+
if (handler.mt === null || Object.keys(handler.mt).length === 0) continue
|
|
2220
|
+
const selector = `${method} ${path}`
|
|
2221
|
+
metaEntries.push(`\t${mapKeyExpr(intern, selector)}: ${intern.expr(handler.mt)}`)
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
if (hasMetaShape && metaShape !== null) {
|
|
2225
|
+
code += `\n${emitMetaShapeType(metaShape)}\n`
|
|
2180
2226
|
}
|
|
2181
2227
|
|
|
2182
|
-
/* emit RouteSelector union from route graph */
|
|
2183
2228
|
const selectors = new Set<string>()
|
|
2184
2229
|
for (const { handler, method, path } of collected) {
|
|
2185
2230
|
if (handler._skip || isMetaInternal(handler)) continue
|
|
@@ -2187,21 +2232,36 @@ function generateFromTreeRoot(root: TreeNode): string {
|
|
|
2187
2232
|
}
|
|
2188
2233
|
if (selectors.size > 0) {
|
|
2189
2234
|
const sorted = [...selectors].sort()
|
|
2190
|
-
|
|
2235
|
+
const parts = sorted.map((s) => {
|
|
2236
|
+
const id = intern.id(s)
|
|
2237
|
+
return id !== undefined ? `typeof ${id}` : JSON.stringify(s)
|
|
2238
|
+
})
|
|
2239
|
+
code += `\nexport type RouteSelector = ${parts.join(" | ")}\n`
|
|
2191
2240
|
}
|
|
2192
2241
|
|
|
2193
2242
|
if (metaEntries.length > 0) {
|
|
2194
|
-
const metaType =
|
|
2243
|
+
const metaType = hasMetaShape ? "Record<string, MetaShape>" : "Record<string, Record<string, unknown>>"
|
|
2195
2244
|
code += `export const meta: ${metaType} = {\n${metaEntries.join(",\n")}\n}\n`
|
|
2196
2245
|
}
|
|
2197
2246
|
|
|
2198
|
-
/* emit routeTree convenience export for .routeTree() */
|
|
2199
2247
|
const hasMetaExport = metaEntries.length > 0
|
|
2200
2248
|
code += `export const routeTree: RouteTree = { root: tree, ${hasMetaExport ? "meta, " : "meta: {}, "}handlers }\n`
|
|
2201
2249
|
|
|
2202
2250
|
return code
|
|
2203
2251
|
}
|
|
2204
2252
|
|
|
2253
|
+
export function generateRouteTree(routes: RouteConfig[]): string {
|
|
2254
|
+
return emitRouteTree(routes, null)
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
function generateFromTreeRoot(root: TreeNode): string {
|
|
2258
|
+
const routes: RouteConfig[] = []
|
|
2259
|
+
collectRoutesForTree(root, "", routes)
|
|
2260
|
+
const collected: CollectedRoute[] = []
|
|
2261
|
+
walkTree(root, "", collected)
|
|
2262
|
+
return emitRouteTree(routes, collected)
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2205
2265
|
export function generateRouteTreeFromApp<TEnv, TCtx>(
|
|
2206
2266
|
app: Honey<TEnv, TCtx, unknown, unknown, unknown, string, string>,
|
|
2207
2267
|
): string {
|