@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.
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +104 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +133 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +129 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/generate.d.ts +75 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +183 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +4 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +229 -0
- package/dist/init.js.map +1 -0
- package/dist/ir/index.d.ts +7 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +7 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/relation-graph.d.ts +113 -0
- package/dist/ir/relation-graph.d.ts.map +1 -0
- package/dist/ir/relation-graph.js +232 -0
- package/dist/ir/relation-graph.js.map +1 -0
- package/dist/ir/semantic-ir.d.ts +448 -0
- package/dist/ir/semantic-ir.d.ts.map +1 -0
- package/dist/ir/semantic-ir.js +138 -0
- package/dist/ir/semantic-ir.js.map +1 -0
- package/dist/ir/smart-tags.d.ts +24 -0
- package/dist/ir/smart-tags.d.ts.map +1 -0
- package/dist/ir/smart-tags.js +30 -0
- package/dist/ir/smart-tags.js.map +1 -0
- package/dist/lib/conjure.d.ts +431 -0
- package/dist/lib/conjure.d.ts.map +1 -0
- package/dist/lib/conjure.js +697 -0
- package/dist/lib/conjure.js.map +1 -0
- package/dist/lib/field-utils.d.ts +61 -0
- package/dist/lib/field-utils.d.ts.map +1 -0
- package/dist/lib/field-utils.js +132 -0
- package/dist/lib/field-utils.js.map +1 -0
- package/dist/lib/hex.d.ts +117 -0
- package/dist/lib/hex.d.ts.map +1 -0
- package/dist/lib/hex.js +185 -0
- package/dist/lib/hex.js.map +1 -0
- package/dist/plugins/arktype.d.ts +11 -0
- package/dist/plugins/arktype.d.ts.map +1 -0
- package/dist/plugins/arktype.js +207 -0
- package/dist/plugins/arktype.js.map +1 -0
- package/dist/plugins/effect-model.d.ts +10 -0
- package/dist/plugins/effect-model.d.ts.map +1 -0
- package/dist/plugins/effect-model.js +261 -0
- package/dist/plugins/effect-model.js.map +1 -0
- package/dist/plugins/kysely-queries.d.ts +7 -0
- package/dist/plugins/kysely-queries.d.ts.map +1 -0
- package/dist/plugins/kysely-queries.js +380 -0
- package/dist/plugins/kysely-queries.js.map +1 -0
- package/dist/plugins/sql-queries.d.ts +6 -0
- package/dist/plugins/sql-queries.d.ts.map +1 -0
- package/dist/plugins/sql-queries.js +249 -0
- package/dist/plugins/sql-queries.js.map +1 -0
- package/dist/plugins/types.d.ts +18 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +263 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/plugins/zod.d.ts +11 -0
- package/dist/plugins/zod.d.ts.map +1 -0
- package/dist/plugins/zod.js +180 -0
- package/dist/plugins/zod.js.map +1 -0
- package/dist/services/artifact-store.d.ts +55 -0
- package/dist/services/artifact-store.d.ts.map +1 -0
- package/dist/services/artifact-store.js +51 -0
- package/dist/services/artifact-store.js.map +1 -0
- package/dist/services/config-loader.d.ts +45 -0
- package/dist/services/config-loader.d.ts.map +1 -0
- package/dist/services/config-loader.js +113 -0
- package/dist/services/config-loader.js.map +1 -0
- package/dist/services/emissions.d.ts +89 -0
- package/dist/services/emissions.d.ts.map +1 -0
- package/dist/services/emissions.js +194 -0
- package/dist/services/emissions.js.map +1 -0
- package/dist/services/file-builder.d.ts +81 -0
- package/dist/services/file-builder.d.ts.map +1 -0
- package/dist/services/file-builder.js +112 -0
- package/dist/services/file-builder.js.map +1 -0
- package/dist/services/file-writer.d.ts +57 -0
- package/dist/services/file-writer.d.ts.map +1 -0
- package/dist/services/file-writer.js +76 -0
- package/dist/services/file-writer.js.map +1 -0
- package/dist/services/inflection.d.ts +227 -0
- package/dist/services/inflection.d.ts.map +1 -0
- package/dist/services/inflection.js +350 -0
- package/dist/services/inflection.js.map +1 -0
- package/dist/services/introspection.d.ts +46 -0
- package/dist/services/introspection.d.ts.map +1 -0
- package/dist/services/introspection.js +99 -0
- package/dist/services/introspection.js.map +1 -0
- package/dist/services/ir-builder.d.ts +46 -0
- package/dist/services/ir-builder.d.ts.map +1 -0
- package/dist/services/ir-builder.js +923 -0
- package/dist/services/ir-builder.js.map +1 -0
- package/dist/services/ir.d.ts +28 -0
- package/dist/services/ir.d.ts.map +1 -0
- package/dist/services/ir.js +25 -0
- package/dist/services/ir.js.map +1 -0
- package/dist/services/pg-types.d.ts +197 -0
- package/dist/services/pg-types.d.ts.map +1 -0
- package/dist/services/pg-types.js +274 -0
- package/dist/services/pg-types.js.map +1 -0
- package/dist/services/plugin-meta.d.ts +33 -0
- package/dist/services/plugin-meta.d.ts.map +1 -0
- package/dist/services/plugin-meta.js +24 -0
- package/dist/services/plugin-meta.js.map +1 -0
- package/dist/services/plugin-runner.d.ts +52 -0
- package/dist/services/plugin-runner.d.ts.map +1 -0
- package/dist/services/plugin-runner.js +182 -0
- package/dist/services/plugin-runner.js.map +1 -0
- package/dist/services/plugin.d.ts +286 -0
- package/dist/services/plugin.d.ts.map +1 -0
- package/dist/services/plugin.js +132 -0
- package/dist/services/plugin.js.map +1 -0
- package/dist/services/smart-tags-parser.d.ts +37 -0
- package/dist/services/smart-tags-parser.d.ts.map +1 -0
- package/dist/services/smart-tags-parser.js +79 -0
- package/dist/services/smart-tags-parser.js.map +1 -0
- package/dist/services/symbols.d.ts +85 -0
- package/dist/services/symbols.d.ts.map +1 -0
- package/dist/services/symbols.js +128 -0
- package/dist/services/symbols.js.map +1 -0
- package/dist/services/type-hints.d.ts +62 -0
- package/dist/services/type-hints.d.ts.map +1 -0
- package/dist/services/type-hints.js +117 -0
- package/dist/services/type-hints.js.map +1 -0
- package/dist/testing.d.ts +77 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +84 -0
- package/dist/testing.js.map +1 -0
- 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
|