@lovrozagar/honey 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +1596 -6
  2. package/dist/accepts.d.ts +6 -0
  3. package/dist/accepts.d.ts.map +1 -0
  4. package/dist/body-limit.d.ts +22 -0
  5. package/dist/body-limit.d.ts.map +1 -0
  6. package/dist/build/index.d.ts +42 -0
  7. package/dist/build/index.d.ts.map +1 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/client/error.d.ts +14 -0
  11. package/dist/client/error.d.ts.map +1 -0
  12. package/dist/client/http.d.ts +88 -0
  13. package/dist/client/http.d.ts.map +1 -0
  14. package/dist/client/index.d.ts +22 -0
  15. package/dist/client/index.d.ts.map +1 -0
  16. package/dist/client/sdk.d.ts +34 -0
  17. package/dist/client/sdk.d.ts.map +1 -0
  18. package/dist/client/sse.d.ts +10 -0
  19. package/dist/client/sse.d.ts.map +1 -0
  20. package/dist/client/types.d.ts +124 -0
  21. package/dist/client/types.d.ts.map +1 -0
  22. package/dist/client/ws.d.ts +15 -0
  23. package/dist/client/ws.d.ts.map +1 -0
  24. package/dist/client-mcp/server.d.ts +10 -0
  25. package/dist/client-mcp/server.d.ts.map +1 -0
  26. package/dist/client-mcp/types.d.ts +16 -0
  27. package/dist/client-mcp/types.d.ts.map +1 -0
  28. package/dist/cloudflare/realtime.d.ts +30 -0
  29. package/dist/cloudflare/realtime.d.ts.map +1 -0
  30. package/dist/codegen-go-cli.d.ts +22 -0
  31. package/dist/codegen-go-cli.d.ts.map +1 -0
  32. package/dist/codegen-go.d.ts +29 -0
  33. package/dist/codegen-go.d.ts.map +1 -0
  34. package/dist/codegen-hash.d.ts +3 -0
  35. package/dist/codegen-hash.d.ts.map +1 -0
  36. package/dist/codegen-ir.d.ts +123 -0
  37. package/dist/codegen-ir.d.ts.map +1 -0
  38. package/dist/codegen-loaders.d.ts +12 -0
  39. package/dist/codegen-loaders.d.ts.map +1 -0
  40. package/dist/codegen-mcp.d.ts +13 -0
  41. package/dist/codegen-mcp.d.ts.map +1 -0
  42. package/dist/codegen-python.d.ts +21 -0
  43. package/dist/codegen-python.d.ts.map +1 -0
  44. package/dist/codegen-rust.d.ts +18 -0
  45. package/dist/codegen-rust.d.ts.map +1 -0
  46. package/dist/codegen-sanitize.d.ts +3 -0
  47. package/dist/codegen-sanitize.d.ts.map +1 -0
  48. package/dist/codegen-schema-naming.d.ts +22 -0
  49. package/dist/codegen-schema-naming.d.ts.map +1 -0
  50. package/dist/codegen.d.ts +178 -0
  51. package/dist/codegen.d.ts.map +1 -0
  52. package/dist/context.d.ts +56 -0
  53. package/dist/context.d.ts.map +1 -0
  54. package/dist/cookie-sign.d.ts +3 -0
  55. package/dist/cookie-sign.d.ts.map +1 -0
  56. package/dist/cookie.d.ts +12 -0
  57. package/dist/cookie.d.ts.map +1 -0
  58. package/dist/cors.d.ts +13 -0
  59. package/dist/cors.d.ts.map +1 -0
  60. package/dist/crypto.d.ts +2 -0
  61. package/dist/crypto.d.ts.map +1 -0
  62. package/dist/csrf.d.ts +9 -0
  63. package/dist/csrf.d.ts.map +1 -0
  64. package/dist/curl-logger.d.ts +33 -0
  65. package/dist/curl-logger.d.ts.map +1 -0
  66. package/dist/detect-runtime.d.ts +16 -0
  67. package/dist/detect-runtime.d.ts.map +1 -0
  68. package/dist/error.d.ts +21 -0
  69. package/dist/error.d.ts.map +1 -0
  70. package/dist/errors.d.ts +40 -0
  71. package/dist/errors.d.ts.map +1 -0
  72. package/dist/etag.d.ts +9 -0
  73. package/dist/etag.d.ts.map +1 -0
  74. package/dist/feature-load.d.ts +3 -0
  75. package/dist/feature-load.d.ts.map +1 -0
  76. package/dist/go-type-emitter.d.ts +33 -0
  77. package/dist/go-type-emitter.d.ts.map +1 -0
  78. package/dist/honey-response.d.ts +82 -0
  79. package/dist/honey-response.d.ts.map +1 -0
  80. package/dist/i18n-slot.d.ts +7 -0
  81. package/dist/i18n-slot.d.ts.map +1 -0
  82. package/dist/i18n.d.ts +26 -0
  83. package/dist/i18n.d.ts.map +1 -0
  84. package/dist/index.d.ts +470 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/init.d.ts +7 -0
  87. package/dist/init.d.ts.map +1 -0
  88. package/dist/input.d.ts +6 -0
  89. package/dist/input.d.ts.map +1 -0
  90. package/dist/ip-restrict.d.ts +12 -0
  91. package/dist/ip-restrict.d.ts.map +1 -0
  92. package/dist/logger.d.ts +45 -0
  93. package/dist/logger.d.ts.map +1 -0
  94. package/dist/meta-spec.d.ts +81 -0
  95. package/dist/meta-spec.d.ts.map +1 -0
  96. package/dist/middleware.d.ts +60 -0
  97. package/dist/middleware.d.ts.map +1 -0
  98. package/dist/node-request.d.ts +59 -0
  99. package/dist/node-request.d.ts.map +1 -0
  100. package/dist/node.d.ts +13 -0
  101. package/dist/node.d.ts.map +1 -0
  102. package/dist/openapi/register.d.ts +3 -0
  103. package/dist/openapi/register.d.ts.map +1 -0
  104. package/dist/openapi/scalar.d.ts +12 -0
  105. package/dist/openapi/scalar.d.ts.map +1 -0
  106. package/dist/openapi/spec-factory.d.ts +31 -0
  107. package/dist/openapi/spec-factory.d.ts.map +1 -0
  108. package/dist/openapi/spec.d.ts +19 -0
  109. package/dist/openapi/spec.d.ts.map +1 -0
  110. package/dist/openapi/swagger.d.ts +12 -0
  111. package/dist/openapi/swagger.d.ts.map +1 -0
  112. package/dist/plugin.d.ts +167 -0
  113. package/dist/plugin.d.ts.map +1 -0
  114. package/dist/powered-by.d.ts +7 -0
  115. package/dist/powered-by.d.ts.map +1 -0
  116. package/dist/pretty-json.d.ts +10 -0
  117. package/dist/pretty-json.d.ts.map +1 -0
  118. package/dist/proxy.d.ts +51 -0
  119. package/dist/proxy.d.ts.map +1 -0
  120. package/dist/python-type-emitter.d.ts +11 -0
  121. package/dist/python-type-emitter.d.ts.map +1 -0
  122. package/dist/realtime/buffer.d.ts +18 -0
  123. package/dist/realtime/buffer.d.ts.map +1 -0
  124. package/dist/realtime/bus.d.ts +11 -0
  125. package/dist/realtime/bus.d.ts.map +1 -0
  126. package/dist/realtime/longpoll.d.ts +23 -0
  127. package/dist/realtime/longpoll.d.ts.map +1 -0
  128. package/dist/realtime/protocol.d.ts +50 -0
  129. package/dist/realtime/protocol.d.ts.map +1 -0
  130. package/dist/realtime/route.d.ts +42 -0
  131. package/dist/realtime/route.d.ts.map +1 -0
  132. package/dist/realtime/runtime.d.ts +74 -0
  133. package/dist/realtime/runtime.d.ts.map +1 -0
  134. package/dist/request-id.d.ts +12 -0
  135. package/dist/request-id.d.ts.map +1 -0
  136. package/dist/request-to-curl.d.ts +9 -0
  137. package/dist/request-to-curl.d.ts.map +1 -0
  138. package/dist/response.d.ts +57 -0
  139. package/dist/response.d.ts.map +1 -0
  140. package/dist/rust-type-emitter.d.ts +32 -0
  141. package/dist/rust-type-emitter.d.ts.map +1 -0
  142. package/dist/secure-headers.d.ts +16 -0
  143. package/dist/secure-headers.d.ts.map +1 -0
  144. package/dist/serve-register.d.ts +2 -0
  145. package/dist/serve-register.d.ts.map +1 -0
  146. package/dist/serve-slot.d.ts +6 -0
  147. package/dist/serve-slot.d.ts.map +1 -0
  148. package/dist/serve.d.ts +21 -0
  149. package/dist/serve.d.ts.map +1 -0
  150. package/dist/server-timing.d.ts +9 -0
  151. package/dist/server-timing.d.ts.map +1 -0
  152. package/dist/static.d.ts +12 -0
  153. package/dist/static.d.ts.map +1 -0
  154. package/dist/telemetry/otel.d.ts +59 -0
  155. package/dist/telemetry/otel.d.ts.map +1 -0
  156. package/dist/testing.d.ts +24 -0
  157. package/dist/testing.d.ts.map +1 -0
  158. package/dist/timeout.d.ts +7 -0
  159. package/dist/timeout.d.ts.map +1 -0
  160. package/dist/tree.d.ts +90 -0
  161. package/dist/tree.d.ts.map +1 -0
  162. package/dist/ts-type-emitter.d.ts +4 -0
  163. package/dist/ts-type-emitter.d.ts.map +1 -0
  164. package/dist/type-emitter.d.ts +8 -0
  165. package/dist/type-emitter.d.ts.map +1 -0
  166. package/dist/type-extractor.d.ts +39 -0
  167. package/dist/type-extractor.d.ts.map +1 -0
  168. package/dist/types.d.ts +451 -0
  169. package/dist/types.d.ts.map +1 -0
  170. package/dist/validation.d.ts +18 -0
  171. package/dist/validation.d.ts.map +1 -0
  172. package/dist/ws/bun.d.ts +28 -0
  173. package/dist/ws/bun.d.ts.map +1 -0
  174. package/dist/ws/cloudflare.d.ts +55 -0
  175. package/dist/ws/cloudflare.d.ts.map +1 -0
  176. package/dist/ws/deno.d.ts +13 -0
  177. package/dist/ws/deno.d.ts.map +1 -0
  178. package/dist/ws/node.d.ts +10 -0
  179. package/dist/ws/node.d.ts.map +1 -0
  180. package/dist/yaml.d.ts +4 -0
  181. package/dist/yaml.d.ts.map +1 -0
  182. package/docs/api-ref/go.md +82 -82
  183. package/docs/api-ref/python.md +82 -82
  184. package/docs/api-ref/rust.md +82 -82
  185. package/docs/api-ref/typescript.md +82 -82
  186. package/docs/invalidate-spec.md +13 -13
  187. package/docs/meta-spec.md +513 -0
  188. package/docs/packaging.md +85 -0
  189. package/docs/sdk.md +87 -73
  190. package/package.json +195 -51
  191. package/src/body-limit.ts +2 -1
  192. package/src/build/index.ts +2 -9
  193. package/src/cli.ts +2 -3
  194. package/src/client/http.ts +204 -223
  195. package/src/client/index.ts +6 -14
  196. package/src/client/sdk.ts +24 -17
  197. package/src/client/types.ts +4 -9
  198. package/src/client/ws.ts +3 -5
  199. package/src/client-mcp/server.ts +1 -4
  200. package/src/cloudflare/realtime.ts +8 -10
  201. package/src/codegen-go-cli.ts +74 -67
  202. package/src/codegen-go.ts +71 -51
  203. package/src/codegen-ir.ts +16 -27
  204. package/src/codegen-loaders.ts +5 -8
  205. package/src/codegen-mcp.ts +9 -27
  206. package/src/codegen-python.ts +47 -27
  207. package/src/codegen-rust.ts +110 -66
  208. package/src/codegen-sanitize.ts +1 -7
  209. package/src/codegen-schema-naming.ts +8 -2
  210. package/src/codegen.ts +299 -196
  211. package/src/context.ts +91 -95
  212. package/src/cookie-sign.ts +5 -13
  213. package/src/cookie.ts +1 -2
  214. package/src/cors.ts +4 -6
  215. package/src/crypto.ts +1 -4
  216. package/src/csrf.ts +3 -3
  217. package/src/curl-logger.ts +14 -32
  218. package/src/detect-runtime.ts +1 -3
  219. package/src/errors.ts +1 -3
  220. package/src/etag.ts +3 -4
  221. package/src/go-type-emitter.ts +45 -40
  222. package/src/honey-response.ts +1 -3
  223. package/src/i18n.ts +3 -12
  224. package/src/index.ts +1168 -1412
  225. package/src/ip-restrict.ts +2 -1
  226. package/src/logger.ts +13 -13
  227. package/src/meta-spec.ts +0 -0
  228. package/src/middleware.ts +111 -79
  229. package/src/node-request.ts +2 -1
  230. package/src/node.ts +9 -10
  231. package/src/openapi/register.ts +1 -2
  232. package/src/openapi/scalar.ts +9 -9
  233. package/src/openapi/spec-factory.ts +2 -2
  234. package/src/openapi/spec.ts +26 -19
  235. package/src/openapi/swagger.ts +9 -9
  236. package/src/plugin.ts +226 -256
  237. package/src/powered-by.ts +2 -1
  238. package/src/pretty-json.ts +2 -1
  239. package/src/proxy.ts +1 -3
  240. package/src/python-type-emitter.ts +37 -12
  241. package/src/realtime/route.ts +1 -1
  242. package/src/realtime/runtime.ts +9 -12
  243. package/src/request-id.ts +3 -4
  244. package/src/request-to-curl.ts +1 -4
  245. package/src/response.ts +150 -199
  246. package/src/rust-type-emitter.ts +66 -25
  247. package/src/secure-headers.ts +2 -1
  248. package/src/serve.ts +3 -12
  249. package/src/server-timing.ts +2 -1
  250. package/src/static.ts +3 -4
  251. package/src/telemetry/otel.ts +1 -6
  252. package/src/testing.ts +2 -11
  253. package/src/timeout.ts +2 -1
  254. package/src/tree.ts +12 -27
  255. package/src/ts-type-emitter.ts +71 -15
  256. package/src/type-emitter.ts +226 -237
  257. package/src/type-extractor.ts +260 -334
  258. package/src/types.ts +168 -68
  259. package/src/validation.ts +7 -30
  260. package/src/ws/bun.ts +2 -9
  261. package/src/ws/cloudflare.ts +13 -16
  262. package/src/ws/deno.ts +31 -40
  263. package/src/ws/node.ts +4 -19
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import type { MiddlewareFn } from "./middleware.ts"
2
3
 
3
4
  type SecureHeadersOptions = {
@@ -65,5 +66,5 @@ export function secureHeaders(options?: SecureHeadersOptions): MiddlewareFn<{},
65
66
  return response
66
67
  }
67
68
 
68
- return mw
69
+ return namedMiddleware("secureHeaders", mw)
69
70
  }
package/src/serve.ts CHANGED
@@ -87,25 +87,16 @@ export async function startHoneyServer(
87
87
  }
88
88
  ).Deno
89
89
  const ac = new AbortController()
90
- const server = DenoNs.serve(
91
- { hostname, port, signal: ac.signal },
92
- (req) => listening.fetch(req, env),
93
- )
90
+ const server = DenoNs.serve({ hostname, port, signal: ac.signal }, (req) => listening.fetch(req, env))
94
91
  const bound = server.addr?.port ?? port
95
92
  return {
96
93
  async close() {
97
94
  ac.abort()
98
95
  if (server.shutdown) {
99
- await Promise.race([
100
- server.shutdown(),
101
- new Promise<void>((r) => setTimeout(r, 1_000)),
102
- ])
96
+ await Promise.race([server.shutdown(), new Promise<void>((r) => setTimeout(r, 1_000))])
103
97
  return
104
98
  }
105
- await Promise.race([
106
- server.finished ?? Promise.resolve(),
107
- new Promise<void>((r) => setTimeout(r, 1_000)),
108
- ])
99
+ await Promise.race([server.finished ?? Promise.resolve(), new Promise<void>((r) => setTimeout(r, 1_000))])
109
100
  },
110
101
  hostname,
111
102
  port: bound,
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import type { MiddlewareFn } from "./middleware.ts"
2
3
 
3
4
  export type Timing = {
@@ -62,5 +63,5 @@ export function serverTiming(): MiddlewareFn<{}, { timing: Timing }> {
62
63
  return response
63
64
  }
64
65
 
65
- return mw
66
+ return namedMiddleware("serverTiming", mw)
66
67
  }
package/src/static.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import type { MiddlewareFn } from "./middleware.ts"
2
3
 
3
4
  type StaticConfig<TCtx> = {
@@ -9,9 +10,7 @@ type StaticConfig<TCtx> = {
9
10
 
10
11
  const TRAVERSAL = /(?:^|\/)\.\.\//
11
12
 
12
- export function staticFiles<TCtx extends { req: Request }>(
13
- config: StaticConfig<TCtx>,
14
- ): MiddlewareFn<TCtx, {}> {
13
+ export function staticFiles<TCtx extends { req: Request }>(config: StaticConfig<TCtx>): MiddlewareFn<TCtx, {}> {
15
14
  const prefix = config.prefix ?? "/"
16
15
 
17
16
  const mw: MiddlewareFn<TCtx, {}> = async (ctx, next) => {
@@ -56,5 +55,5 @@ export function staticFiles<TCtx extends { req: Request }>(
56
55
  return response
57
56
  }
58
57
 
59
- return mw
58
+ return namedMiddleware("staticFiles", mw)
60
59
  }
@@ -18,12 +18,7 @@ type TelemetryAdapter = {
18
18
  onNotFound?(ctx: { method: string; path: string; req: Request }): void
19
19
  onRequest?(ctx: { env: unknown; req: Request }): void
20
20
  onResponse?(ctx: { duration: number; req: Request; status: number }): void
21
- onRoute?(ctx: {
22
- method: string
23
- params: Record<string, string>
24
- path: string
25
- req: Request
26
- }): void
21
+ onRoute?(ctx: { method: string; params: Record<string, string>; path: string; req: Request }): void
27
22
  }
28
23
 
29
24
  export function otelAdapter(options: { tracer: Tracer }): TelemetryAdapter {
package/src/testing.ts CHANGED
@@ -18,12 +18,7 @@ type TestClient = {
18
18
  request(method: string, path: string, opts?: TestRequestOptions): Promise<Response>
19
19
  }
20
20
 
21
- function buildRequest(
22
- method: string,
23
- path: string,
24
- baseUrl: string,
25
- opts?: TestRequestOptions,
26
- ): Request {
21
+ function buildRequest(method: string, path: string, baseUrl: string, opts?: TestRequestOptions): Request {
27
22
  const url = new URL(path, baseUrl)
28
23
 
29
24
  if (opts?.search) {
@@ -70,11 +65,7 @@ export function testClient<TEnv>(
70
65
  const baseUrl = "http://localhost"
71
66
  const jar = new Map<string, string>()
72
67
 
73
- async function doRequest(
74
- method: string,
75
- path: string,
76
- opts?: TestRequestOptions,
77
- ): Promise<Response> {
68
+ async function doRequest(method: string, path: string, opts?: TestRequestOptions): Promise<Response> {
78
69
  const mergedHeaders = { ...opts?.headers }
79
70
 
80
71
  if (options.cookies && jar.size > 0) {
package/src/timeout.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { namedMiddleware } from "./middleware.ts"
1
2
  import { HoneyError } from "./error.ts"
2
3
  import type { MiddlewareFn } from "./middleware.ts"
3
4
  import { EK, SK } from "./types.ts"
@@ -32,5 +33,5 @@ export function timeout(opts: TimeoutOptions): MiddlewareFn<{}, {}> {
32
33
  })
33
34
  }
34
35
 
35
- return mw
36
+ return namedMiddleware("timeout", mw)
36
37
  }
package/src/tree.ts CHANGED
@@ -112,18 +112,12 @@ function splitSegments(path: string): string[] {
112
112
  return path.split("/").filter((s) => s.length > 0)
113
113
  }
114
114
 
115
- export function insertRoute(
116
- root: TreeNode,
117
- method: HttpMethod | "ALL",
118
- path: string,
119
- handler: RouteHandler,
120
- ): void {
115
+ export function insertRoute(root: TreeNode, method: HttpMethod | "ALL", path: string, handler: RouteHandler): void {
121
116
  bumpGeneration(root)
122
117
  const segments = splitSegments(path)
123
118
  let node = root
124
119
 
125
120
  for (const seg of segments) {
126
-
127
121
  if (seg.startsWith("*")) {
128
122
  const name = seg.length > 1 ? seg.slice(1) : "*"
129
123
  if (node.w !== null && node.w.n !== name) {
@@ -145,9 +139,7 @@ export function insertRoute(
145
139
  if (seg.startsWith(":")) {
146
140
  const name = seg.endsWith("?") ? seg.slice(1, -1) : seg.slice(1)
147
141
  if (node.d !== null && node.d.n !== name) {
148
- throw new Error(
149
- `Route "${path}": param name conflict — expected ":${node.d.n}" but got ":${name}"`,
150
- )
142
+ throw new Error(`Route "${path}": param name conflict — expected ":${node.d.n}" but got ":${name}"`)
151
143
  }
152
144
  if (node.d === null) {
153
145
  node.d = { c: createNode(), n: name }
@@ -270,7 +262,6 @@ export function insertWsRoute(root: TreeNode, path: string, handler: WSRouteHand
270
262
  let node = root
271
263
 
272
264
  for (const seg of segments) {
273
-
274
265
  if (seg.startsWith("*")) {
275
266
  throw new Error("Wildcard segments not supported for WebSocket routes")
276
267
  }
@@ -278,9 +269,7 @@ export function insertWsRoute(root: TreeNode, path: string, handler: WSRouteHand
278
269
  if (seg.startsWith(":")) {
279
270
  const name = seg.slice(1)
280
271
  if (node.d !== null && node.d.n !== name) {
281
- throw new Error(
282
- `Route "${path}": param name conflict — expected ":${node.d.n}" but got ":${name}"`,
283
- )
272
+ throw new Error(`Route "${path}": param name conflict — expected ":${node.d.n}" but got ":${name}"`)
284
273
  }
285
274
  if (node.d === null) {
286
275
  node.d = { c: createNode(), n: name }
@@ -364,13 +353,13 @@ function mergeNodes(target: TreeNode, source: TreeNode, path: string): void {
364
353
  }
365
354
 
366
355
  /* merge static children — shallow-copy s to avoid mutating shared empty objects */
367
- if (source.s && Object.keys(source.s).length > 0) {
368
- let detached = false
369
- for (const [seg, child] of Object.entries(source.s)) {
370
- const targetChild = target.s[seg]
371
- if (targetChild !== undefined) {
372
- mergeNodes(targetChild, child, `${path}/${seg}`)
373
- } else {
356
+ if (source.s && Object.keys(source.s).length > 0) {
357
+ let detached = false
358
+ for (const [seg, child] of Object.entries(source.s)) {
359
+ const targetChild = target.s[seg]
360
+ if (targetChild !== undefined) {
361
+ mergeNodes(targetChild, child, `${path}/${seg}`)
362
+ } else {
374
363
  if (!detached) {
375
364
  target.s = Object.assign(Object.create(null) as Record<string, TreeNode>, target.s)
376
365
  detached = true
@@ -384,9 +373,7 @@ function mergeNodes(target: TreeNode, source: TreeNode, path: string): void {
384
373
  if (source.d !== null && source.d !== undefined) {
385
374
  if (target.d !== null && target.d !== undefined) {
386
375
  if (target.d.n !== source.d.n) {
387
- throw new Error(
388
- `Merge conflict: param name mismatch at ${path}: "${target.d.n}" vs "${source.d.n}"`,
389
- )
376
+ throw new Error(`Merge conflict: param name mismatch at ${path}: "${target.d.n}" vs "${source.d.n}"`)
390
377
  }
391
378
  mergeNodes(target.d.c, source.d.c, `${path}/:${target.d.n}`)
392
379
  } else {
@@ -398,9 +385,7 @@ function mergeNodes(target: TreeNode, source: TreeNode, path: string): void {
398
385
  if (source.w !== null && source.w !== undefined) {
399
386
  if (target.w !== null && target.w !== undefined) {
400
387
  if (target.w.n !== source.w.n) {
401
- throw new Error(
402
- `Merge conflict: wildcard name mismatch at ${path}: "${target.w.n}" vs "${source.w.n}"`,
403
- )
388
+ throw new Error(`Merge conflict: wildcard name mismatch at ${path}: "${target.w.n}" vs "${source.w.n}"`)
404
389
  }
405
390
  for (const [method, handler] of Object.entries(source.w.m)) {
406
391
  if (method in target.w.m) {
@@ -4,16 +4,75 @@ import type { IRSchema } from "./codegen-ir.ts"
4
4
 
5
5
  /* TS keywords that are valid identifiers but require quoting as object property keys */
6
6
  const TS_RESERVED = new Set([
7
- "break", "case", "catch", "class", "const", "continue", "debugger",
8
- "default", "delete", "do", "else", "enum", "export", "extends", "false",
9
- "finally", "for", "function", "if", "import", "in", "instanceof", "new",
10
- "null", "return", "super", "switch", "this", "throw", "true", "try",
11
- "typeof", "var", "void", "while", "with", "yield", "let", "static",
12
- "implements", "interface", "package", "private", "protected", "public",
13
- "abstract", "as", "async", "await", "constructor", "declare", "from",
14
- "get", "infer", "is", "keyof", "module", "namespace", "never", "of",
15
- "readonly", "require", "set", "satisfies", "symbol", "type", "unique",
16
- "unknown", "override",
7
+ "break",
8
+ "case",
9
+ "catch",
10
+ "class",
11
+ "const",
12
+ "continue",
13
+ "debugger",
14
+ "default",
15
+ "delete",
16
+ "do",
17
+ "else",
18
+ "enum",
19
+ "export",
20
+ "extends",
21
+ "false",
22
+ "finally",
23
+ "for",
24
+ "function",
25
+ "if",
26
+ "import",
27
+ "in",
28
+ "instanceof",
29
+ "new",
30
+ "null",
31
+ "return",
32
+ "super",
33
+ "switch",
34
+ "this",
35
+ "throw",
36
+ "true",
37
+ "try",
38
+ "typeof",
39
+ "var",
40
+ "void",
41
+ "while",
42
+ "with",
43
+ "yield",
44
+ "let",
45
+ "static",
46
+ "implements",
47
+ "interface",
48
+ "package",
49
+ "private",
50
+ "protected",
51
+ "public",
52
+ "abstract",
53
+ "as",
54
+ "async",
55
+ "await",
56
+ "constructor",
57
+ "declare",
58
+ "from",
59
+ "get",
60
+ "infer",
61
+ "is",
62
+ "keyof",
63
+ "module",
64
+ "namespace",
65
+ "never",
66
+ "of",
67
+ "readonly",
68
+ "require",
69
+ "set",
70
+ "satisfies",
71
+ "symbol",
72
+ "type",
73
+ "unique",
74
+ "unknown",
75
+ "override",
17
76
  ])
18
77
 
19
78
  export function irToTs(ir: IRSchema, depth = 0): string {
@@ -66,9 +125,7 @@ export function irToTs(ir: IRSchema, depth = 0): string {
66
125
 
67
126
  function emitScalar(ir: Extract<IRSchema, { kind: "scalar" }>): string {
68
127
  if (ir.enum) {
69
- return ir.enum
70
- .map((v) => (typeof v === "string" ? JSON.stringify(v) : String(v)))
71
- .join(" | ")
128
+ return ir.enum.map((v) => (typeof v === "string" ? JSON.stringify(v) : String(v))).join(" | ")
72
129
  }
73
130
 
74
131
  if (ir.type === "string") return "string"
@@ -92,8 +149,7 @@ function emitObject(ir: Extract<IRSchema, { kind: "object" }>, depth: number): s
92
149
 
93
150
  const entries = sortedFields.map((field) => {
94
151
  const opt = field.required ? "" : "?"
95
- const needsQuote =
96
- !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(field.name) || TS_RESERVED.has(field.name)
152
+ const needsQuote = !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(field.name) || TS_RESERVED.has(field.name)
97
153
  const key = needsQuote ? JSON.stringify(field.name) : field.name
98
154
  return `${key}${opt}: ${irToTs(field.schema, depth + 1)}`
99
155
  })