@danielfgray/pg-sourcerer 0.1.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 (145) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +104 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config.d.ts +133 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +47 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/errors.d.ts +129 -0
  10. package/dist/errors.d.ts.map +1 -0
  11. package/dist/errors.js +41 -0
  12. package/dist/errors.js.map +1 -0
  13. package/dist/generate.d.ts +75 -0
  14. package/dist/generate.d.ts.map +1 -0
  15. package/dist/generate.js +183 -0
  16. package/dist/generate.js.map +1 -0
  17. package/dist/index.d.ts +35 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +62 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/init.d.ts +4 -0
  22. package/dist/init.d.ts.map +1 -0
  23. package/dist/init.js +229 -0
  24. package/dist/init.js.map +1 -0
  25. package/dist/ir/index.d.ts +7 -0
  26. package/dist/ir/index.d.ts.map +1 -0
  27. package/dist/ir/index.js +7 -0
  28. package/dist/ir/index.js.map +1 -0
  29. package/dist/ir/relation-graph.d.ts +113 -0
  30. package/dist/ir/relation-graph.d.ts.map +1 -0
  31. package/dist/ir/relation-graph.js +232 -0
  32. package/dist/ir/relation-graph.js.map +1 -0
  33. package/dist/ir/semantic-ir.d.ts +448 -0
  34. package/dist/ir/semantic-ir.d.ts.map +1 -0
  35. package/dist/ir/semantic-ir.js +138 -0
  36. package/dist/ir/semantic-ir.js.map +1 -0
  37. package/dist/ir/smart-tags.d.ts +24 -0
  38. package/dist/ir/smart-tags.d.ts.map +1 -0
  39. package/dist/ir/smart-tags.js +30 -0
  40. package/dist/ir/smart-tags.js.map +1 -0
  41. package/dist/lib/conjure.d.ts +431 -0
  42. package/dist/lib/conjure.d.ts.map +1 -0
  43. package/dist/lib/conjure.js +697 -0
  44. package/dist/lib/conjure.js.map +1 -0
  45. package/dist/lib/field-utils.d.ts +61 -0
  46. package/dist/lib/field-utils.d.ts.map +1 -0
  47. package/dist/lib/field-utils.js +132 -0
  48. package/dist/lib/field-utils.js.map +1 -0
  49. package/dist/lib/hex.d.ts +117 -0
  50. package/dist/lib/hex.d.ts.map +1 -0
  51. package/dist/lib/hex.js +185 -0
  52. package/dist/lib/hex.js.map +1 -0
  53. package/dist/plugins/arktype.d.ts +11 -0
  54. package/dist/plugins/arktype.d.ts.map +1 -0
  55. package/dist/plugins/arktype.js +207 -0
  56. package/dist/plugins/arktype.js.map +1 -0
  57. package/dist/plugins/effect-model.d.ts +10 -0
  58. package/dist/plugins/effect-model.d.ts.map +1 -0
  59. package/dist/plugins/effect-model.js +261 -0
  60. package/dist/plugins/effect-model.js.map +1 -0
  61. package/dist/plugins/kysely-queries.d.ts +7 -0
  62. package/dist/plugins/kysely-queries.d.ts.map +1 -0
  63. package/dist/plugins/kysely-queries.js +380 -0
  64. package/dist/plugins/kysely-queries.js.map +1 -0
  65. package/dist/plugins/sql-queries.d.ts +6 -0
  66. package/dist/plugins/sql-queries.d.ts.map +1 -0
  67. package/dist/plugins/sql-queries.js +249 -0
  68. package/dist/plugins/sql-queries.js.map +1 -0
  69. package/dist/plugins/types.d.ts +18 -0
  70. package/dist/plugins/types.d.ts.map +1 -0
  71. package/dist/plugins/types.js +263 -0
  72. package/dist/plugins/types.js.map +1 -0
  73. package/dist/plugins/zod.d.ts +11 -0
  74. package/dist/plugins/zod.d.ts.map +1 -0
  75. package/dist/plugins/zod.js +180 -0
  76. package/dist/plugins/zod.js.map +1 -0
  77. package/dist/services/artifact-store.d.ts +55 -0
  78. package/dist/services/artifact-store.d.ts.map +1 -0
  79. package/dist/services/artifact-store.js +51 -0
  80. package/dist/services/artifact-store.js.map +1 -0
  81. package/dist/services/config-loader.d.ts +45 -0
  82. package/dist/services/config-loader.d.ts.map +1 -0
  83. package/dist/services/config-loader.js +113 -0
  84. package/dist/services/config-loader.js.map +1 -0
  85. package/dist/services/emissions.d.ts +89 -0
  86. package/dist/services/emissions.d.ts.map +1 -0
  87. package/dist/services/emissions.js +194 -0
  88. package/dist/services/emissions.js.map +1 -0
  89. package/dist/services/file-builder.d.ts +81 -0
  90. package/dist/services/file-builder.d.ts.map +1 -0
  91. package/dist/services/file-builder.js +112 -0
  92. package/dist/services/file-builder.js.map +1 -0
  93. package/dist/services/file-writer.d.ts +57 -0
  94. package/dist/services/file-writer.d.ts.map +1 -0
  95. package/dist/services/file-writer.js +76 -0
  96. package/dist/services/file-writer.js.map +1 -0
  97. package/dist/services/inflection.d.ts +227 -0
  98. package/dist/services/inflection.d.ts.map +1 -0
  99. package/dist/services/inflection.js +350 -0
  100. package/dist/services/inflection.js.map +1 -0
  101. package/dist/services/introspection.d.ts +46 -0
  102. package/dist/services/introspection.d.ts.map +1 -0
  103. package/dist/services/introspection.js +99 -0
  104. package/dist/services/introspection.js.map +1 -0
  105. package/dist/services/ir-builder.d.ts +46 -0
  106. package/dist/services/ir-builder.d.ts.map +1 -0
  107. package/dist/services/ir-builder.js +923 -0
  108. package/dist/services/ir-builder.js.map +1 -0
  109. package/dist/services/ir.d.ts +28 -0
  110. package/dist/services/ir.d.ts.map +1 -0
  111. package/dist/services/ir.js +25 -0
  112. package/dist/services/ir.js.map +1 -0
  113. package/dist/services/pg-types.d.ts +197 -0
  114. package/dist/services/pg-types.d.ts.map +1 -0
  115. package/dist/services/pg-types.js +274 -0
  116. package/dist/services/pg-types.js.map +1 -0
  117. package/dist/services/plugin-meta.d.ts +33 -0
  118. package/dist/services/plugin-meta.d.ts.map +1 -0
  119. package/dist/services/plugin-meta.js +24 -0
  120. package/dist/services/plugin-meta.js.map +1 -0
  121. package/dist/services/plugin-runner.d.ts +52 -0
  122. package/dist/services/plugin-runner.d.ts.map +1 -0
  123. package/dist/services/plugin-runner.js +182 -0
  124. package/dist/services/plugin-runner.js.map +1 -0
  125. package/dist/services/plugin.d.ts +286 -0
  126. package/dist/services/plugin.d.ts.map +1 -0
  127. package/dist/services/plugin.js +132 -0
  128. package/dist/services/plugin.js.map +1 -0
  129. package/dist/services/smart-tags-parser.d.ts +37 -0
  130. package/dist/services/smart-tags-parser.d.ts.map +1 -0
  131. package/dist/services/smart-tags-parser.js +79 -0
  132. package/dist/services/smart-tags-parser.js.map +1 -0
  133. package/dist/services/symbols.d.ts +85 -0
  134. package/dist/services/symbols.d.ts.map +1 -0
  135. package/dist/services/symbols.js +128 -0
  136. package/dist/services/symbols.js.map +1 -0
  137. package/dist/services/type-hints.d.ts +62 -0
  138. package/dist/services/type-hints.d.ts.map +1 -0
  139. package/dist/services/type-hints.js +117 -0
  140. package/dist/services/type-hints.js.map +1 -0
  141. package/dist/testing.d.ts +77 -0
  142. package/dist/testing.d.ts.map +1 -0
  143. package/dist/testing.js +84 -0
  144. package/dist/testing.js.map +1 -0
  145. package/package.json +74 -0
@@ -0,0 +1,697 @@
1
+ /**
2
+ * Conjure - AST Builder DSL for recast
3
+ *
4
+ * A fluent, immutable API for constructing JavaScript/TypeScript AST nodes.
5
+ * Wraps recast builders with ergonomic patterns for common code generation tasks.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { conjure, cast } from "../lib/conjure.js"
10
+ *
11
+ * // Method chains
12
+ * const schema = conjure.id("z")
13
+ * .method("string")
14
+ * .method("uuid")
15
+ * .method("nullable")
16
+ * .build()
17
+ *
18
+ * // Object literals
19
+ * const config = conjure.obj()
20
+ * .prop("path", conjure.str("/users"))
21
+ * .prop("method", conjure.str("GET"))
22
+ * .build()
23
+ *
24
+ * // Functions
25
+ * const handler = conjure.fn()
26
+ * .async()
27
+ * .arrow()
28
+ * .param("req", conjure.ts.ref("Request"))
29
+ * .param("res", conjure.ts.ref("Response"))
30
+ * .body(
31
+ * conjure.stmt.return(conjure.id("res").method("json", [data]).build())
32
+ * )
33
+ * .build()
34
+ * ```
35
+ */
36
+ import recast from "recast";
37
+ const b = recast.types.builders;
38
+ // =============================================================================
39
+ // Recast Interop Types
40
+ // =============================================================================
41
+ /**
42
+ * The ast-types library uses "Kind" union types that are incompatible with
43
+ * exactOptionalPropertyTypes. We define explicit cast functions that convert
44
+ * from the namedTypes interfaces (n.Expression, n.Statement, etc.) to the
45
+ * Kind types that recast builders expect.
46
+ *
47
+ * This is safe because every member of n.Expression is a member of ExpressionKind.
48
+ */
49
+ /** Cast n.Expression to ExpressionKind for recast builder compatibility */
50
+ function toExpr(node) {
51
+ return node;
52
+ }
53
+ /** Cast n.Statement to StatementKind for recast builder compatibility */
54
+ function toStmt(node) {
55
+ return node;
56
+ }
57
+ /** Cast n.TSType to TSTypeKind for recast builder compatibility */
58
+ function toTSType(node) {
59
+ return node;
60
+ }
61
+ // =============================================================================
62
+ // Type Casts (Public API)
63
+ // =============================================================================
64
+ /**
65
+ * Type cast helpers for raw recast interop.
66
+ *
67
+ * Use these when mixing conjure with direct recast builder calls.
68
+ * These provide the same functionality as the internal cast functions
69
+ * but are exported for external use.
70
+ */
71
+ export const cast = {
72
+ /** Cast n.Expression to ExpressionKind */
73
+ toExpr,
74
+ /** Cast array element (expression or spread) */
75
+ asArrayElem: (node) => node,
76
+ /** Cast n.Statement to StatementKind */
77
+ toStmt,
78
+ /** Cast n.TSType to TSTypeKind */
79
+ toTSType,
80
+ };
81
+ function createChain(start) {
82
+ return {
83
+ node: start,
84
+ prop(name) {
85
+ return createChain(b.memberExpression(toExpr(this.node), b.identifier(name)));
86
+ },
87
+ method(name, args = []) {
88
+ return createChain(b.callExpression(b.memberExpression(toExpr(this.node), b.identifier(name)), args.map(toExpr)));
89
+ },
90
+ call(args = []) {
91
+ return createChain(b.callExpression(toExpr(this.node), args.map(toExpr)));
92
+ },
93
+ index(expr) {
94
+ return createChain(b.memberExpression(toExpr(this.node), toExpr(expr), true));
95
+ },
96
+ build() {
97
+ return this.node;
98
+ },
99
+ };
100
+ }
101
+ // Internal: properly typed for recast builder compatibility
102
+ function createObj(props = []) {
103
+ return {
104
+ prop(key, value) {
105
+ const newProp = b.objectProperty(b.identifier(key), toExpr(value));
106
+ return createObj([...props, newProp]);
107
+ },
108
+ stringProp(key, value) {
109
+ const newProp = b.objectProperty(b.stringLiteral(key), toExpr(value));
110
+ return createObj([...props, newProp]);
111
+ },
112
+ computed(key, value) {
113
+ const prop = b.objectProperty(toExpr(key), toExpr(value));
114
+ prop.computed = true;
115
+ return createObj([...props, prop]);
116
+ },
117
+ spread(expr) {
118
+ const spreadElem = b.spreadElement(toExpr(expr));
119
+ return createObj([...props, spreadElem]);
120
+ },
121
+ shorthand(key) {
122
+ const prop = b.objectProperty(b.identifier(key), b.identifier(key));
123
+ prop.shorthand = true;
124
+ return createObj([...props, prop]);
125
+ },
126
+ build() {
127
+ return b.objectExpression(props);
128
+ },
129
+ };
130
+ }
131
+ // Internal: properly typed for recast builder compatibility
132
+ function createArr(elems = []) {
133
+ return {
134
+ add(...exprs) {
135
+ const newElems = exprs.map((e) => toExpr(e));
136
+ return createArr([...elems, ...newElems]);
137
+ },
138
+ spread(expr) {
139
+ const spreadElem = b.spreadElement(toExpr(expr));
140
+ return createArr([...elems, spreadElem]);
141
+ },
142
+ build() {
143
+ return b.arrayExpression(elems);
144
+ },
145
+ };
146
+ }
147
+ const defaultParam = (name, type) => ({
148
+ name,
149
+ type,
150
+ optional: false,
151
+ rest: false,
152
+ defaultValue: undefined,
153
+ });
154
+ function createFn(config) {
155
+ const buildParams = () => config.params.map((p) => {
156
+ if (p.rest) {
157
+ const restId = b.identifier(p.name);
158
+ if (p.type) {
159
+ restId.typeAnnotation = b.tsTypeAnnotation(toTSType(p.type));
160
+ }
161
+ return b.restElement(restId);
162
+ }
163
+ else if (p.defaultValue) {
164
+ // For default params, type annotation goes on the identifier
165
+ const id = b.identifier(p.name);
166
+ if (p.type) {
167
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(p.type));
168
+ }
169
+ return b.assignmentPattern(id, toExpr(p.defaultValue));
170
+ }
171
+ else {
172
+ const param = b.identifier(p.name);
173
+ if (p.type) {
174
+ param.typeAnnotation = b.tsTypeAnnotation(toTSType(p.type));
175
+ }
176
+ if (p.optional) {
177
+ param.optional = true;
178
+ }
179
+ return param;
180
+ }
181
+ });
182
+ return {
183
+ param(name, type) {
184
+ return createFn({
185
+ ...config,
186
+ params: [...config.params, defaultParam(name, type)],
187
+ });
188
+ },
189
+ optionalParam(name, type) {
190
+ return createFn({
191
+ ...config,
192
+ params: [...config.params, { ...defaultParam(name, type), optional: true }],
193
+ });
194
+ },
195
+ restParam(name, type) {
196
+ return createFn({
197
+ ...config,
198
+ params: [...config.params, { ...defaultParam(name, type), rest: true }],
199
+ });
200
+ },
201
+ defaultParam(name, defaultValue, type) {
202
+ return createFn({
203
+ ...config,
204
+ params: [...config.params, { ...defaultParam(name, type), defaultValue }],
205
+ });
206
+ },
207
+ returns(type) {
208
+ return createFn({ ...config, returnType: type });
209
+ },
210
+ body(...statements) {
211
+ return createFn({ ...config, body: statements });
212
+ },
213
+ async() {
214
+ return createFn({ ...config, isAsync: true });
215
+ },
216
+ arrow() {
217
+ return createFn({ ...config, isArrow: true });
218
+ },
219
+ generator() {
220
+ return createFn({ ...config, isGenerator: true });
221
+ },
222
+ build() {
223
+ const params = buildParams();
224
+ const block = b.blockStatement(config.body.map(toStmt));
225
+ if (config.isArrow) {
226
+ const fn = b.arrowFunctionExpression(params, block, false);
227
+ fn.async = config.isAsync;
228
+ if (config.returnType) {
229
+ fn.returnType = b.tsTypeAnnotation(toTSType(config.returnType));
230
+ }
231
+ return fn;
232
+ }
233
+ else {
234
+ const fn = b.functionExpression(null, params, block, config.isGenerator);
235
+ fn.async = config.isAsync;
236
+ if (config.returnType) {
237
+ fn.returnType = b.tsTypeAnnotation(toTSType(config.returnType));
238
+ }
239
+ return fn;
240
+ }
241
+ },
242
+ toDeclaration(name) {
243
+ const params = buildParams();
244
+ const block = b.blockStatement(config.body.map(toStmt));
245
+ const fn = b.functionDeclaration(b.identifier(name), params, block, config.isGenerator);
246
+ fn.async = config.isAsync;
247
+ if (config.returnType) {
248
+ fn.returnType = b.tsTypeAnnotation(toTSType(config.returnType));
249
+ }
250
+ return fn;
251
+ },
252
+ };
253
+ }
254
+ /**
255
+ * Operator helpers for building expressions.
256
+ */
257
+ const op = {
258
+ /** Generic binary expression */
259
+ binary: (left, operator, right) => b.binaryExpression(operator, toExpr(left), toExpr(right)),
260
+ /** Logical expression (&&, ||, ??) */
261
+ logical: (left, operator, right) => b.logicalExpression(operator, toExpr(left), toExpr(right)),
262
+ /** Unary expression */
263
+ unary: (operator, argument) => b.unaryExpression(operator, toExpr(argument)),
264
+ /** Assignment expression */
265
+ assign: (left, operator, right) => b.assignmentExpression(operator, left, toExpr(right)),
266
+ /** Ternary/conditional expression */
267
+ ternary: (test, consequent, alternate) => b.conditionalExpression(toExpr(test), toExpr(consequent), toExpr(alternate)),
268
+ /** New expression */
269
+ new: (callee, args = []) => b.newExpression(toExpr(callee), args.map(toExpr)),
270
+ // Common shortcuts
271
+ /** Strict equality: `===` */
272
+ eq: (left, right) => b.binaryExpression("===", toExpr(left), toExpr(right)),
273
+ /** Strict inequality: `!==` */
274
+ neq: (left, right) => b.binaryExpression("!==", toExpr(left), toExpr(right)),
275
+ /** Logical not: `!` */
276
+ not: (expr) => b.unaryExpression("!", toExpr(expr)),
277
+ /** Logical and: `&&` */
278
+ and: (left, right) => b.logicalExpression("&&", toExpr(left), toExpr(right)),
279
+ /** Logical or: `||` */
280
+ or: (left, right) => b.logicalExpression("||", toExpr(left), toExpr(right)),
281
+ /** Nullish coalescing: `??` */
282
+ nullish: (left, right) => b.logicalExpression("??", toExpr(left), toExpr(right)),
283
+ };
284
+ // =============================================================================
285
+ // Statement Helpers
286
+ // =============================================================================
287
+ /**
288
+ * Statement builders.
289
+ */
290
+ const stmt = {
291
+ /** `const name = init` */
292
+ const: (name, init, type) => {
293
+ const id = b.identifier(name);
294
+ if (type) {
295
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(type));
296
+ }
297
+ return b.variableDeclaration("const", [b.variableDeclarator(id, toExpr(init))]);
298
+ },
299
+ /** `let name = init` */
300
+ let: (name, init, type) => {
301
+ const id = b.identifier(name);
302
+ if (type) {
303
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(type));
304
+ }
305
+ return b.variableDeclaration("let", [
306
+ b.variableDeclarator(id, init ? toExpr(init) : null),
307
+ ]);
308
+ },
309
+ /** `return expr` */
310
+ return: (expr) => expr ? b.returnStatement(toExpr(expr)) : b.returnStatement(null),
311
+ /** Expression statement: `expr;` */
312
+ expr: (expr) => b.expressionStatement(toExpr(expr)),
313
+ /** If statement */
314
+ if: (test, consequent, alternate) => b.ifStatement(toExpr(test), b.blockStatement(consequent.map(toStmt)), alternate ? b.blockStatement(alternate.map(toStmt)) : null),
315
+ /** Throw statement */
316
+ throw: (expr) => b.throwStatement(toExpr(expr)),
317
+ /** Try-catch statement */
318
+ try: (block, catchParam, catchBlock, finallyBlock) => b.tryStatement(b.blockStatement(block.map(toStmt)), b.catchClause(b.identifier(catchParam), null, b.blockStatement(catchBlock.map(toStmt))), finallyBlock ? b.blockStatement(finallyBlock.map(toStmt)) : null),
319
+ /** For...of statement */
320
+ forOf: (varKind, varName, iterable, body) => b.forOfStatement(b.variableDeclaration(varKind, [
321
+ b.variableDeclarator(b.identifier(varName)),
322
+ ]), toExpr(iterable), b.blockStatement(body.map(toStmt))),
323
+ /** Block statement */
324
+ block: (...statements) => b.blockStatement(statements.map(toStmt)),
325
+ };
326
+ // =============================================================================
327
+ // TypeScript Type Helpers
328
+ // =============================================================================
329
+ /**
330
+ * TypeScript type node builders.
331
+ */
332
+ const ts = {
333
+ // Keyword types
334
+ string: () => b.tsStringKeyword(),
335
+ number: () => b.tsNumberKeyword(),
336
+ boolean: () => b.tsBooleanKeyword(),
337
+ bigint: () => b.tsBigIntKeyword(),
338
+ any: () => b.tsAnyKeyword(),
339
+ unknown: () => b.tsUnknownKeyword(),
340
+ never: () => b.tsNeverKeyword(),
341
+ void: () => b.tsVoidKeyword(),
342
+ null: () => b.tsNullKeyword(),
343
+ undefined: () => b.tsUndefinedKeyword(),
344
+ /** Type reference: `TypeName` or `TypeName<T>` */
345
+ ref: (name, typeParams) => {
346
+ const ref = b.tsTypeReference(b.identifier(name));
347
+ if (typeParams && typeParams.length > 0) {
348
+ ref.typeParameters = b.tsTypeParameterInstantiation(typeParams.map(toTSType));
349
+ }
350
+ return ref;
351
+ },
352
+ /** Qualified name reference: `Namespace.Type` */
353
+ qualifiedRef: (qualifier, name, typeParams) => {
354
+ const ref = b.tsTypeReference(b.tsQualifiedName(b.identifier(qualifier), b.identifier(name)));
355
+ if (typeParams && typeParams.length > 0) {
356
+ ref.typeParameters = b.tsTypeParameterInstantiation(typeParams.map(toTSType));
357
+ }
358
+ return ref;
359
+ },
360
+ /** Array type: `T[]` */
361
+ array: (elementType) => b.tsArrayType(toTSType(elementType)),
362
+ /** Union type: `A | B | C` */
363
+ union: (...types) => b.tsUnionType(types.map(toTSType)),
364
+ /** Intersection type: `A & B` */
365
+ intersection: (...types) => b.tsIntersectionType(types.map(toTSType)),
366
+ /** Literal type: `"value"` or `42` */
367
+ literal: (value) => {
368
+ if (typeof value === "string") {
369
+ return b.tsLiteralType(b.stringLiteral(value));
370
+ }
371
+ else if (typeof value === "number") {
372
+ return b.tsLiteralType(b.numericLiteral(value));
373
+ }
374
+ else {
375
+ return b.tsLiteralType(b.booleanLiteral(value));
376
+ }
377
+ },
378
+ /** Tuple type: `[A, B, C]` */
379
+ tuple: (...types) => b.tsTupleType(types.map(toTSType)),
380
+ /** Function type: `(a: A, b: B) => R` */
381
+ fn: (params, returnType) => {
382
+ const fnParams = params.map((p) => {
383
+ const param = b.identifier(p.name);
384
+ param.typeAnnotation = b.tsTypeAnnotation(toTSType(p.type));
385
+ if (p.optional) {
386
+ param.optional = true;
387
+ }
388
+ return param;
389
+ });
390
+ const fnType = b.tsFunctionType(fnParams);
391
+ fnType.typeAnnotation = b.tsTypeAnnotation(toTSType(returnType));
392
+ return fnType;
393
+ },
394
+ /** Typeof type: `typeof x` */
395
+ typeof: (expr) => b.tsTypeQuery(b.identifier(expr)),
396
+ /** Keyof type: `keyof T` */
397
+ keyof: (type) => ({
398
+ type: "TSTypeOperator",
399
+ operator: "keyof",
400
+ typeAnnotation: toTSType(type),
401
+ }),
402
+ /** Readonly type: `readonly T` */
403
+ readonly: (type) => ({
404
+ type: "TSTypeOperator",
405
+ operator: "readonly",
406
+ typeAnnotation: toTSType(type),
407
+ }),
408
+ /** Promise type: `Promise<T>` */
409
+ promise: (inner) => b.tsTypeReference(b.identifier("Promise"), b.tsTypeParameterInstantiation([toTSType(inner)])),
410
+ /**
411
+ * Object type literal: `{ name: string; age?: number }`
412
+ * @example
413
+ * ts.objectType([
414
+ * { name: "id", type: ts.string() },
415
+ * { name: "count", type: ts.number(), optional: true },
416
+ * ])
417
+ */
418
+ objectType: (props) => b.tsTypeLiteral(props.map(p => {
419
+ const sig = b.tsPropertySignature(b.identifier(p.name), b.tsTypeAnnotation(toTSType(p.type)));
420
+ if (p.optional)
421
+ sig.optional = true;
422
+ if (p.readonly)
423
+ sig.readonly = true;
424
+ return sig;
425
+ })),
426
+ };
427
+ /**
428
+ * Parameter builders for function signatures.
429
+ */
430
+ const param = {
431
+ /**
432
+ * Create a typed parameter: `name: Type`
433
+ */
434
+ typed: (name, type) => {
435
+ const id = b.identifier(name);
436
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(type));
437
+ return id;
438
+ },
439
+ /**
440
+ * Create an optional typed parameter: `name?: Type`
441
+ */
442
+ optional: (name, type) => {
443
+ const id = b.identifier(name);
444
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(type));
445
+ id.optional = true;
446
+ return id;
447
+ },
448
+ /**
449
+ * Create a parameter with default value: `name: Type = defaultValue`
450
+ */
451
+ withDefault: (name, defaultValue, type) => {
452
+ const id = b.identifier(name);
453
+ if (type) {
454
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(type));
455
+ }
456
+ return b.assignmentPattern(id, toExpr(defaultValue));
457
+ },
458
+ /**
459
+ * Create a destructured parameter with Pick type: `{ field }: Pick<Entity, 'field'>`
460
+ *
461
+ * @example
462
+ * param.pick(["id", "name"], "UserRow")
463
+ * // { id, name }: Pick<UserRow, "id" | "name">
464
+ */
465
+ pick: (fields, entityType) => {
466
+ const pattern = b.objectPattern(fields.map((f) => {
467
+ const prop = b.objectProperty(b.identifier(f), b.identifier(f));
468
+ prop.shorthand = true;
469
+ return prop;
470
+ }));
471
+ // Pick<Entity, 'field1' | 'field2'>
472
+ const pickType = ts.ref("Pick", [
473
+ ts.ref(entityType),
474
+ fields.length === 1
475
+ ? ts.literal(fields[0])
476
+ : ts.union(...fields.map((f) => ts.literal(f))),
477
+ ]);
478
+ pattern.typeAnnotation = b.tsTypeAnnotation(toTSType(pickType));
479
+ return pattern;
480
+ },
481
+ /**
482
+ * Create a destructured parameter with explicit types and optional defaults.
483
+ *
484
+ * @example
485
+ * param.destructured([
486
+ * { name: "limit", type: ts.number(), optional: true, defaultValue: conjure.num(50) },
487
+ * { name: "offset", type: ts.number(), optional: true, defaultValue: conjure.num(0) },
488
+ * ])
489
+ * // { limit = 50, offset = 0 }: { limit?: number; offset?: number }
490
+ */
491
+ destructured: (fields) => {
492
+ const pattern = b.objectPattern(fields.map((f) => {
493
+ const id = b.identifier(f.name);
494
+ // Use AssignmentPattern for default values: { limit = 50 }
495
+ const value = f.defaultValue
496
+ ? b.assignmentPattern(id, toExpr(f.defaultValue))
497
+ : id;
498
+ const prop = b.objectProperty(b.identifier(f.name), value);
499
+ prop.shorthand = true;
500
+ return prop;
501
+ }));
502
+ // Build the type annotation: { name: type; name?: type; }
503
+ const typeAnnotation = ts.objectType(fields.map((f) => ({ name: f.name, type: f.type, optional: f.optional })));
504
+ pattern.typeAnnotation = b.tsTypeAnnotation(toTSType(typeAnnotation));
505
+ return pattern;
506
+ },
507
+ };
508
+ // =============================================================================
509
+ // Export Helpers (exp.*)
510
+ // =============================================================================
511
+ /**
512
+ * Helper to create a SymbolStatement wrapper
513
+ */
514
+ function symbolStatement(node, symbol) {
515
+ return { _tag: "SymbolStatement", node, symbol };
516
+ }
517
+ /**
518
+ * Helper to create SymbolMeta with proper handling of optional shape
519
+ */
520
+ function createSymbolMeta(name, ctx, isType) {
521
+ const base = {
522
+ name,
523
+ capability: ctx.capability,
524
+ entity: ctx.entity,
525
+ isType,
526
+ };
527
+ return ctx.shape !== undefined ? { ...base, shape: ctx.shape } : base;
528
+ }
529
+ /**
530
+ * Build interface properties from property signature objects
531
+ */
532
+ function buildInterfaceProperties(props) {
533
+ return props.map((p) => {
534
+ const sig = b.tsPropertySignature(b.identifier(p.name), b.tsTypeAnnotation(toTSType(p.type)));
535
+ if (p.optional)
536
+ sig.optional = true;
537
+ if (p.readonly)
538
+ sig.readonly = true;
539
+ return sig;
540
+ });
541
+ }
542
+ /**
543
+ * Export helpers that produce statements with symbol metadata.
544
+ * These are used for tracking exports across files for import resolution.
545
+ */
546
+ export const exp = {
547
+ /**
548
+ * Export interface declaration: `export interface Name { ... }`
549
+ */
550
+ interface: (name, ctx, properties) => {
551
+ const decl = b.tsInterfaceDeclaration(b.identifier(name), b.tsInterfaceBody(buildInterfaceProperties(properties)));
552
+ const exportDecl = b.exportNamedDeclaration(decl, []);
553
+ return symbolStatement(exportDecl, createSymbolMeta(name, ctx, true));
554
+ },
555
+ /**
556
+ * Export type alias: `export type Name = Type`
557
+ */
558
+ typeAlias: (name, ctx, type) => {
559
+ const decl = b.tsTypeAliasDeclaration(b.identifier(name), toTSType(type));
560
+ const exportDecl = b.exportNamedDeclaration(decl, []);
561
+ return symbolStatement(exportDecl, createSymbolMeta(name, ctx, true));
562
+ },
563
+ /**
564
+ * Export const declaration: `export const name = init`
565
+ */
566
+ const: (name, ctx, init, typeAnnotation) => {
567
+ const id = b.identifier(name);
568
+ if (typeAnnotation) {
569
+ id.typeAnnotation = b.tsTypeAnnotation(toTSType(typeAnnotation));
570
+ }
571
+ const decl = b.variableDeclaration("const", [
572
+ b.variableDeclarator(id, toExpr(init)),
573
+ ]);
574
+ const exportDecl = b.exportNamedDeclaration(decl, []);
575
+ return symbolStatement(exportDecl, createSymbolMeta(name, ctx, false));
576
+ },
577
+ /**
578
+ * Export type alias for inferred types: `export type Name = typeof schema`
579
+ * Useful for exporting the inferred type alongside a schema constant.
580
+ */
581
+ type: (name, ctx, type) => {
582
+ // This is the same as typeAlias but semantically distinct -
583
+ // used for inferred types like `z.infer<typeof Schema>`
584
+ const decl = b.tsTypeAliasDeclaration(b.identifier(name), toTSType(type));
585
+ const exportDecl = b.exportNamedDeclaration(decl, []);
586
+ return symbolStatement(exportDecl, createSymbolMeta(name, ctx, true));
587
+ },
588
+ };
589
+ // =============================================================================
590
+ // Program Builder
591
+ // =============================================================================
592
+ /**
593
+ * Type guard for SymbolStatement
594
+ */
595
+ function isSymbolStatement(stmt) {
596
+ return (typeof stmt === "object" &&
597
+ stmt !== null &&
598
+ "_tag" in stmt &&
599
+ stmt._tag === "SymbolStatement");
600
+ }
601
+ /**
602
+ * Create a SymbolProgram from statements, extracting symbol metadata.
603
+ * Accepts both regular statements and SymbolStatements.
604
+ */
605
+ function createSymbolProgram(...statements) {
606
+ const nodes = [];
607
+ const symbols = [];
608
+ for (const stmt of statements) {
609
+ if (isSymbolStatement(stmt)) {
610
+ nodes.push(stmt.node);
611
+ symbols.push(stmt.symbol);
612
+ }
613
+ else {
614
+ nodes.push(stmt);
615
+ }
616
+ }
617
+ return {
618
+ _tag: "SymbolProgram",
619
+ node: b.program(nodes.map(toStmt)),
620
+ symbols,
621
+ };
622
+ }
623
+ // =============================================================================
624
+ // Main API
625
+ // =============================================================================
626
+ /**
627
+ * Conjure - AST Builder DSL
628
+ *
629
+ * A fluent, immutable API for constructing JavaScript/TypeScript AST nodes.
630
+ */
631
+ export const conjure = {
632
+ // === Chain builders ===
633
+ /** Start a chain from an identifier */
634
+ id: (name) => createChain(b.identifier(name)),
635
+ /** Start a chain from any expression */
636
+ chain: (expr) => createChain(expr),
637
+ // === Compound builders ===
638
+ /** Start an object literal builder */
639
+ obj: () => createObj(),
640
+ /** Start an array literal builder */
641
+ arr: (...elements) => createArr(elements.map((e) => toExpr(e))),
642
+ /** Start a function builder */
643
+ fn: () => createFn({
644
+ params: [],
645
+ body: [],
646
+ returnType: null,
647
+ isAsync: false,
648
+ isArrow: false,
649
+ isGenerator: false,
650
+ }),
651
+ // === Literals ===
652
+ /** String literal */
653
+ str: (value) => b.stringLiteral(value),
654
+ /** Numeric literal */
655
+ num: (value) => b.numericLiteral(value),
656
+ /** Boolean literal */
657
+ bool: (value) => b.booleanLiteral(value),
658
+ /** null */
659
+ null: () => b.nullLiteral(),
660
+ /** undefined */
661
+ undefined: () => b.identifier("undefined"),
662
+ /** Template literal */
663
+ template: (quasis, ...expressions) => {
664
+ const templateElements = quasis.map((raw, i) => b.templateElement({ raw, cooked: raw }, i === quasis.length - 1));
665
+ return b.templateLiteral(templateElements, expressions.map(toExpr));
666
+ },
667
+ // === Operators ===
668
+ op,
669
+ // === Statements ===
670
+ stmt,
671
+ // === TypeScript types ===
672
+ ts,
673
+ // === Parameter helpers ===
674
+ param,
675
+ // === Export helpers ===
676
+ exp,
677
+ // === Helpers ===
678
+ /** Await expression */
679
+ await: (expr) => b.awaitExpression(toExpr(expr)),
680
+ /** Spread expression (for use in arrays/calls) */
681
+ spread: (expr) => b.spreadElement(toExpr(expr)),
682
+ /** Print AST node to code string */
683
+ print: (node) => recast.print(node).code,
684
+ /** Create a program from statements (backwards compatible) */
685
+ program: (...statements) => b.program(statements.map(toStmt)),
686
+ /**
687
+ * Create a SymbolProgram from statements, extracting symbol metadata.
688
+ * Accepts both regular statements and SymbolStatements.
689
+ * Returns a SymbolProgram with the AST node and extracted symbols.
690
+ */
691
+ symbolProgram: createSymbolProgram,
692
+ // === Raw builders (escape hatch) ===
693
+ /** Raw recast builders for advanced use cases */
694
+ b,
695
+ };
696
+ export default conjure;
697
+ //# sourceMappingURL=conjure.js.map