@danielfgray/pg-sourcerer 0.3.0 → 0.4.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/bin/pgsourcerer +2 -0
- package/dist/__tests__/fixtures/index.d.ts +15 -0
- package/dist/__tests__/fixtures/index.d.ts.map +1 -0
- package/dist/__tests__/fixtures/index.js +19 -0
- package/dist/__tests__/fixtures/index.js.map +1 -0
- package/dist/__tests__/fixtures/introspection.json +40522 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +7 -46
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +38 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -2
- package/dist/config.js.map +1 -1
- package/dist/{lib/conjure.d.ts → conjure/index.d.ts} +62 -3
- package/dist/conjure/index.d.ts.map +1 -0
- package/dist/{lib/conjure.js → conjure/index.js} +124 -3
- package/dist/conjure/index.js.map +1 -0
- package/dist/conjure/signature.d.ts +85 -0
- package/dist/conjure/signature.d.ts.map +1 -0
- package/dist/conjure/signature.js +130 -0
- package/dist/conjure/signature.js.map +1 -0
- package/dist/conjure/types.d.ts +97 -0
- package/dist/conjure/types.d.ts.map +1 -0
- package/dist/conjure/types.js +206 -0
- package/dist/conjure/types.js.map +1 -0
- package/dist/errors.d.ts +114 -139
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +82 -36
- package/dist/errors.js.map +1 -1
- package/dist/generate.d.ts +45 -46
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +86 -59
- package/dist/generate.js.map +1 -1
- package/dist/hex/builder.d.ts +12 -0
- package/dist/hex/builder.d.ts.map +1 -0
- package/dist/hex/builder.js +64 -0
- package/dist/hex/builder.js.map +1 -0
- package/dist/hex/ddl.d.ts +53 -0
- package/dist/hex/ddl.d.ts.map +1 -0
- package/dist/hex/ddl.js +306 -0
- package/dist/hex/ddl.js.map +1 -0
- package/dist/hex/index.d.ts +105 -0
- package/dist/hex/index.d.ts.map +1 -0
- package/dist/hex/index.js +81 -0
- package/dist/hex/index.js.map +1 -0
- package/dist/hex/primitives.d.ts +23 -0
- package/dist/hex/primitives.d.ts.map +1 -0
- package/dist/hex/primitives.js +38 -0
- package/dist/hex/primitives.js.map +1 -0
- package/dist/hex/query.d.ts +116 -0
- package/dist/hex/query.d.ts.map +1 -0
- package/dist/hex/query.js +219 -0
- package/dist/hex/query.js.map +1 -0
- package/dist/hex/types.d.ts +287 -0
- package/dist/hex/types.d.ts.map +1 -0
- package/dist/hex/types.js +431 -0
- package/dist/hex/types.js.map +1 -0
- package/dist/index.d.ts +17 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -44
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +76 -140
- package/dist/init.js.map +1 -1
- package/dist/ir/extensions/queries.d.ts +6 -6
- package/dist/ir/extensions/queries.d.ts.map +1 -1
- package/dist/ir/extensions/queries.js +6 -4
- package/dist/ir/extensions/queries.js.map +1 -1
- package/dist/ir/extensions/schema-builder.d.ts.map +1 -1
- package/dist/ir/extensions/schema-builder.js.map +1 -1
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js.map +1 -1
- package/dist/ir/relation-graph.d.ts.map +1 -1
- package/dist/ir/relation-graph.js +8 -8
- package/dist/ir/relation-graph.js.map +1 -1
- package/dist/ir/semantic-ir.d.ts +38 -0
- package/dist/ir/semantic-ir.d.ts.map +1 -1
- package/dist/ir/semantic-ir.js +50 -2
- package/dist/ir/semantic-ir.js.map +1 -1
- package/dist/ir/smart-tags.d.ts.map +1 -1
- package/dist/ir/smart-tags.js.map +1 -1
- package/dist/lib/field-utils.d.ts.map +1 -1
- package/dist/lib/field-utils.js +7 -7
- package/dist/lib/field-utils.js.map +1 -1
- package/dist/lib/join-graph.d.ts +95 -0
- package/dist/lib/join-graph.d.ts.map +1 -0
- package/dist/lib/join-graph.js +305 -0
- package/dist/lib/join-graph.js.map +1 -0
- package/dist/lib/picker.d.ts +60 -0
- package/dist/lib/picker.d.ts.map +1 -0
- package/dist/lib/picker.js +325 -0
- package/dist/lib/picker.js.map +1 -0
- package/dist/plugins/arktype.d.ts +20 -24
- package/dist/plugins/arktype.d.ts.map +1 -1
- package/dist/plugins/arktype.js +462 -386
- package/dist/plugins/arktype.js.map +1 -1
- package/dist/plugins/effect/http.d.ts +7 -0
- package/dist/plugins/effect/http.d.ts.map +1 -0
- package/dist/plugins/effect/http.js +460 -0
- package/dist/plugins/effect/http.js.map +1 -0
- package/dist/plugins/effect/index.d.ts +22 -0
- package/dist/plugins/effect/index.d.ts.map +1 -0
- package/dist/plugins/effect/index.js +65 -0
- package/dist/plugins/effect/index.js.map +1 -0
- package/dist/plugins/effect/models.d.ts +6 -0
- package/dist/plugins/effect/models.d.ts.map +1 -0
- package/dist/plugins/effect/models.js +116 -0
- package/dist/plugins/effect/models.js.map +1 -0
- package/dist/plugins/effect/repos.d.ts +21 -0
- package/dist/plugins/effect/repos.d.ts.map +1 -0
- package/dist/plugins/effect/repos.js +131 -0
- package/dist/plugins/effect/repos.js.map +1 -0
- package/dist/plugins/effect/schemas.d.ts +7 -0
- package/dist/plugins/effect/schemas.d.ts.map +1 -0
- package/dist/plugins/effect/schemas.js +75 -0
- package/dist/plugins/effect/schemas.js.map +1 -0
- package/dist/plugins/effect/shared.d.ts +116 -0
- package/dist/plugins/effect/shared.d.ts.map +1 -0
- package/dist/plugins/effect/shared.js +164 -0
- package/dist/plugins/effect/shared.js.map +1 -0
- package/dist/plugins/http-elysia.d.ts +20 -27
- package/dist/plugins/http-elysia.d.ts.map +1 -1
- package/dist/plugins/http-elysia.js +350 -475
- package/dist/plugins/http-elysia.js.map +1 -1
- package/dist/plugins/http-express.d.ts +20 -31
- package/dist/plugins/http-express.d.ts.map +1 -1
- package/dist/plugins/http-express.js +281 -268
- package/dist/plugins/http-express.js.map +1 -1
- package/dist/plugins/http-hono.d.ts +17 -33
- package/dist/plugins/http-hono.d.ts.map +1 -1
- package/dist/plugins/http-hono.js +317 -341
- package/dist/plugins/http-hono.js.map +1 -1
- package/dist/plugins/http-orpc.d.ts +34 -33
- package/dist/plugins/http-orpc.d.ts.map +1 -1
- package/dist/plugins/http-orpc.js +345 -257
- package/dist/plugins/http-orpc.js.map +1 -1
- package/dist/plugins/http-trpc.d.ts +33 -35
- package/dist/plugins/http-trpc.d.ts.map +1 -1
- package/dist/plugins/http-trpc.js +337 -241
- package/dist/plugins/http-trpc.js.map +1 -1
- package/dist/plugins/kysely.d.ts +54 -59
- package/dist/plugins/kysely.d.ts.map +1 -1
- package/dist/plugins/kysely.js +826 -687
- package/dist/plugins/kysely.js.map +1 -1
- package/dist/plugins/sql-queries.d.ts +38 -44
- package/dist/plugins/sql-queries.d.ts.map +1 -1
- package/dist/plugins/sql-queries.js +497 -897
- package/dist/plugins/sql-queries.js.map +1 -1
- package/dist/plugins/types.d.ts +12 -20
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/plugins/types.js +84 -227
- package/dist/plugins/types.js.map +1 -1
- package/dist/plugins/valibot.d.ts +7 -44
- package/dist/plugins/valibot.d.ts.map +1 -1
- package/dist/plugins/valibot.js +376 -382
- package/dist/plugins/valibot.js.map +1 -1
- package/dist/plugins/zod.d.ts +20 -24
- package/dist/plugins/zod.d.ts.map +1 -1
- package/dist/plugins/zod.js +370 -367
- package/dist/plugins/zod.js.map +1 -1
- package/dist/runtime/emit.d.ts +64 -0
- package/dist/runtime/emit.d.ts.map +1 -0
- package/dist/runtime/emit.js +445 -0
- package/dist/runtime/emit.js.map +1 -0
- package/dist/runtime/errors.d.ts +36 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +29 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/file-assignment.d.ts +161 -0
- package/dist/runtime/file-assignment.d.ts.map +1 -0
- package/dist/runtime/file-assignment.js +195 -0
- package/dist/runtime/file-assignment.js.map +1 -0
- package/dist/runtime/orchestrator.d.ts +62 -0
- package/dist/runtime/orchestrator.d.ts.map +1 -0
- package/dist/runtime/orchestrator.js +99 -0
- package/dist/runtime/orchestrator.js.map +1 -0
- package/dist/runtime/registry.d.ts +268 -0
- package/dist/runtime/registry.d.ts.map +1 -0
- package/dist/runtime/registry.js +436 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime/types.d.ts +182 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/validation.d.ts +41 -0
- package/dist/runtime/validation.d.ts.map +1 -0
- package/dist/runtime/validation.js +70 -0
- package/dist/runtime/validation.js.map +1 -0
- package/dist/services/config-loader.d.ts.map +1 -1
- package/dist/services/config-loader.js +15 -6
- package/dist/services/config-loader.js.map +1 -1
- package/dist/services/config.d.ts +55 -25
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +60 -34
- package/dist/services/config.js.map +1 -1
- package/dist/services/file-writer.d.ts +3 -3
- package/dist/services/file-writer.d.ts.map +1 -1
- package/dist/services/file-writer.js +6 -8
- package/dist/services/file-writer.js.map +1 -1
- package/dist/services/inflection.d.ts +126 -27
- package/dist/services/inflection.d.ts.map +1 -1
- package/dist/services/inflection.js +300 -72
- package/dist/services/inflection.js.map +1 -1
- package/dist/services/introspection.d.ts.map +1 -1
- package/dist/services/introspection.js +6 -6
- package/dist/services/introspection.js.map +1 -1
- package/dist/services/ir-builder.d.ts.map +1 -1
- package/dist/services/ir-builder.js +73 -77
- package/dist/services/ir-builder.js.map +1 -1
- package/dist/services/ir.d.ts.map +1 -1
- package/dist/services/ir.js.map +1 -1
- package/dist/services/pg-types.d.ts.map +1 -1
- package/dist/services/pg-types.js +3 -3
- package/dist/services/pg-types.js.map +1 -1
- package/dist/services/smart-tags-parser.d.ts.map +1 -1
- package/dist/services/smart-tags-parser.js +4 -4
- package/dist/services/smart-tags-parser.js.map +1 -1
- package/dist/services/type-hints.d.ts.map +1 -1
- package/dist/services/type-hints.js +1 -1
- package/dist/services/type-hints.js.map +1 -1
- package/dist/services/user-module-parser.d.ts +46 -0
- package/dist/services/user-module-parser.d.ts.map +1 -0
- package/dist/services/user-module-parser.js +181 -0
- package/dist/services/user-module-parser.js.map +1 -0
- package/dist/shared/converters.d.ts +60 -0
- package/dist/shared/converters.d.ts.map +1 -0
- package/dist/shared/converters.js +168 -0
- package/dist/shared/converters.js.map +1 -0
- package/dist/shared/query-types.d.ts +95 -0
- package/dist/shared/query-types.d.ts.map +1 -0
- package/dist/shared/query-types.js +9 -0
- package/dist/shared/query-types.js.map +1 -0
- package/dist/testing.d.ts +125 -37
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +134 -42
- package/dist/testing.js.map +1 -1
- package/dist/user-module.d.ts +86 -0
- package/dist/user-module.d.ts.map +1 -0
- package/dist/user-module.js +55 -0
- package/dist/user-module.js.map +1 -0
- package/package.json +10 -6
- package/dist/lib/conjure.d.ts.map +0 -1
- package/dist/lib/conjure.js.map +0 -1
- package/dist/lib/hex.d.ts +0 -119
- package/dist/lib/hex.d.ts.map +0 -1
- package/dist/lib/hex.js +0 -188
- package/dist/lib/hex.js.map +0 -1
- package/dist/plugins/effect.d.ts +0 -53
- package/dist/plugins/effect.d.ts.map +0 -1
- package/dist/plugins/effect.js +0 -1074
- package/dist/plugins/effect.js.map +0 -1
- package/dist/plugins/kysely/queries.d.ts +0 -92
- package/dist/plugins/kysely/queries.d.ts.map +0 -1
- package/dist/plugins/kysely/queries.js +0 -1169
- package/dist/plugins/kysely/queries.js.map +0 -1
- package/dist/plugins/kysely/shared.d.ts +0 -59
- package/dist/plugins/kysely/shared.d.ts.map +0 -1
- package/dist/plugins/kysely/shared.js +0 -247
- package/dist/plugins/kysely/shared.js.map +0 -1
- package/dist/plugins/kysely/types.d.ts +0 -22
- package/dist/plugins/kysely/types.d.ts.map +0 -1
- package/dist/plugins/kysely/types.js +0 -428
- package/dist/plugins/kysely/types.js.map +0 -1
- package/dist/services/artifact-store.d.ts +0 -65
- package/dist/services/artifact-store.d.ts.map +0 -1
- package/dist/services/artifact-store.js +0 -57
- package/dist/services/artifact-store.js.map +0 -1
- package/dist/services/core-providers.d.ts +0 -15
- package/dist/services/core-providers.d.ts.map +0 -1
- package/dist/services/core-providers.js +0 -23
- package/dist/services/core-providers.js.map +0 -1
- package/dist/services/emissions.d.ts +0 -103
- package/dist/services/emissions.d.ts.map +0 -1
- package/dist/services/emissions.js +0 -241
- package/dist/services/emissions.js.map +0 -1
- package/dist/services/execution.d.ts +0 -35
- package/dist/services/execution.d.ts.map +0 -1
- package/dist/services/execution.js +0 -86
- package/dist/services/execution.js.map +0 -1
- package/dist/services/file-builder.d.ts +0 -85
- package/dist/services/file-builder.d.ts.map +0 -1
- package/dist/services/file-builder.js +0 -112
- package/dist/services/file-builder.js.map +0 -1
- package/dist/services/plugin-meta.d.ts +0 -33
- package/dist/services/plugin-meta.d.ts.map +0 -1
- package/dist/services/plugin-meta.js +0 -24
- package/dist/services/plugin-meta.js.map +0 -1
- package/dist/services/plugin-runner.d.ts +0 -42
- package/dist/services/plugin-runner.d.ts.map +0 -1
- package/dist/services/plugin-runner.js +0 -84
- package/dist/services/plugin-runner.js.map +0 -1
- package/dist/services/plugin.d.ts +0 -421
- package/dist/services/plugin.d.ts.map +0 -1
- package/dist/services/plugin.js +0 -197
- package/dist/services/plugin.js.map +0 -1
- package/dist/services/resolution.d.ts +0 -38
- package/dist/services/resolution.d.ts.map +0 -1
- package/dist/services/resolution.js +0 -242
- package/dist/services/resolution.js.map +0 -1
- package/dist/services/service-registry.d.ts +0 -74
- package/dist/services/service-registry.d.ts.map +0 -1
- package/dist/services/service-registry.js +0 -61
- package/dist/services/service-registry.js.map +0 -1
- package/dist/services/symbols.d.ts +0 -144
- package/dist/services/symbols.d.ts.map +0 -1
- package/dist/services/symbols.js +0 -144
- package/dist/services/symbols.js.map +0 -1
package/dist/plugins/zod.js
CHANGED
|
@@ -1,401 +1,404 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Zod Plugin -
|
|
2
|
+
* Zod Plugin - Generates Zod schemas for entities
|
|
3
3
|
*
|
|
4
4
|
* Generates Zod schemas for Row, Insert, Update, and Patch shapes,
|
|
5
|
-
* with inferred TypeScript types.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import { conjure } from "../lib/conjure.js";
|
|
13
|
-
import { isUuidType, isDateType, isEnumType, getPgTypeName, resolveFieldType, } from "../lib/field-utils.js";
|
|
14
|
-
const { ts, exp, obj } = conjure;
|
|
15
|
-
const ZodConfigSchema = S.Struct({
|
|
16
|
-
outputDir: S.optionalWith(S.String, { default: () => "zod" }),
|
|
17
|
-
exportTypes: S.optionalWith(S.Boolean, { default: () => true }),
|
|
18
|
-
enumStyle: S.optionalWith(S.Union(S.Literal("strings"), S.Literal("enum")), { default: () => "strings" }),
|
|
19
|
-
typeReferences: S.optionalWith(S.Union(S.Literal("inline"), S.Literal("separate")), { default: () => "separate" }),
|
|
20
|
-
});
|
|
21
|
-
// ============================================================================
|
|
22
|
-
// Zod Schema Builders (pure functions)
|
|
23
|
-
// ============================================================================
|
|
24
|
-
/**
|
|
25
|
-
* Build z.<method>() and chain additional methods
|
|
26
|
-
*/
|
|
27
|
-
const buildZodChain = (baseMethod, chainMethods) => chainMethods
|
|
28
|
-
.reduce((chain, method) => chain.method(method), conjure.id("z").method(baseMethod))
|
|
29
|
-
.build();
|
|
30
|
-
/**
|
|
31
|
-
* Build z.enum([...values])
|
|
5
|
+
* with optional inferred TypeScript types.
|
|
6
|
+
*
|
|
7
|
+
* Capabilities provided:
|
|
8
|
+
* - `schema:zod:EntityName` for each table entity (Row schema)
|
|
9
|
+
* - `schema:zod:EntityName:insert` for Insert shape
|
|
10
|
+
* - `schema:zod:EntityName:update` for Update shape
|
|
11
|
+
* - `schema:zod:EnumName` for enum entities
|
|
32
12
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
13
|
+
import { Effect, Schema as S } from "effect";
|
|
14
|
+
import { normalizeFileNaming } from "../runtime/file-assignment.js";
|
|
15
|
+
import { SymbolRegistry } from "../runtime/registry.js";
|
|
16
|
+
import { IR } from "../services/ir.js";
|
|
17
|
+
import { isTableEntity, isEnumEntity, } from "../ir/semantic-ir.js";
|
|
18
|
+
import { conjure, cast } from "../conjure/index.js";
|
|
37
19
|
/**
|
|
38
|
-
*
|
|
20
|
+
* Creates a consume callback for Zod schemas.
|
|
21
|
+
* Generates: `SchemaName.parse(input)`
|
|
22
|
+
*
|
|
23
|
+
* @param schemaName - The name of the Zod schema
|
|
24
|
+
* @returns A function that generates parse AST for an input expression
|
|
39
25
|
*/
|
|
40
|
-
|
|
26
|
+
function createZodConsumeCallback(schemaName) {
|
|
27
|
+
return (input) => {
|
|
28
|
+
return conjure.id(schemaName).method("parse", [cast.toExpr(input)]).build();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
41
31
|
/**
|
|
42
|
-
*
|
|
32
|
+
* Zod SchemaBuilder implementation.
|
|
33
|
+
* Builds Zod schemas for path/query parameters.
|
|
43
34
|
*/
|
|
44
|
-
const
|
|
35
|
+
const zodSchemaBuilder = {
|
|
36
|
+
build(request) {
|
|
37
|
+
if (request.params.length === 0) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
// Build z.object({ field: z.type(), ... })
|
|
41
|
+
let objBuilder = conjure.obj();
|
|
42
|
+
for (const param of request.params) {
|
|
43
|
+
const zodType = paramToZodType(param);
|
|
44
|
+
objBuilder = objBuilder.prop(param.name, zodType);
|
|
45
|
+
}
|
|
46
|
+
const ast = conjure.id("z").method("object", [objBuilder.build()]).build();
|
|
47
|
+
return {
|
|
48
|
+
ast,
|
|
49
|
+
importSpec: { from: "zod", names: ["z"] },
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
45
53
|
/**
|
|
46
|
-
*
|
|
54
|
+
* Convert a QueryMethodParam to a Zod type expression.
|
|
47
55
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case
|
|
53
|
-
|
|
54
|
-
case
|
|
55
|
-
|
|
56
|
-
case
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
case
|
|
61
|
-
|
|
56
|
+
function paramToZodType(param) {
|
|
57
|
+
const baseType = param.type.replace(/\[\]$/, "").replace(/\?$/, "").toLowerCase();
|
|
58
|
+
let zodChain = conjure.id("z");
|
|
59
|
+
switch (baseType) {
|
|
60
|
+
case "number":
|
|
61
|
+
case "int":
|
|
62
|
+
case "integer":
|
|
63
|
+
case "float":
|
|
64
|
+
case "double":
|
|
65
|
+
zodChain = zodChain.prop("coerce").method("number");
|
|
66
|
+
break;
|
|
67
|
+
case "boolean":
|
|
68
|
+
case "bool":
|
|
69
|
+
zodChain = zodChain.method("boolean");
|
|
70
|
+
break;
|
|
71
|
+
case "date":
|
|
72
|
+
zodChain = zodChain.prop("coerce").method("date");
|
|
73
|
+
break;
|
|
74
|
+
case "string":
|
|
62
75
|
default:
|
|
63
|
-
|
|
76
|
+
zodChain = zodChain.method("string");
|
|
77
|
+
break;
|
|
64
78
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// Field → Zod Schema Resolution
|
|
68
|
-
// ============================================================================
|
|
69
|
-
/**
|
|
70
|
-
* Resolve a field to its Zod schema expression.
|
|
71
|
-
*
|
|
72
|
-
* Order of resolution (first match wins):
|
|
73
|
-
* 1. UUID types → z.string().uuid()
|
|
74
|
-
* 2. Date types → z.coerce.date()
|
|
75
|
-
* 3. Enum types → z.enum([...]) or reference
|
|
76
|
-
* 4. Fallback to resolved TypeScript type
|
|
77
|
-
*
|
|
78
|
-
* Then wraps with array/nullable/optional as needed.
|
|
79
|
-
*/
|
|
80
|
-
const resolveFieldZodSchema = (field, ctx) => {
|
|
81
|
-
// Get the base schema expression
|
|
82
|
-
let baseSchema;
|
|
83
|
-
// 1. UUID types get special treatment
|
|
84
|
-
if (isUuidType(field)) {
|
|
85
|
-
baseSchema = buildZodChain("string", ["uuid"]);
|
|
79
|
+
if (!param.required) {
|
|
80
|
+
zodChain = zodChain.method("optional");
|
|
86
81
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
return zodChain.build();
|
|
83
|
+
}
|
|
84
|
+
const b = conjure.b;
|
|
85
|
+
const ZodSchemaConfig = S.Struct({
|
|
86
|
+
exportTypes: S.optionalWith(S.Boolean, { default: () => true }),
|
|
87
|
+
});
|
|
88
|
+
function toExpr(node) {
|
|
89
|
+
return node;
|
|
90
|
+
}
|
|
91
|
+
function toStmt(node) {
|
|
92
|
+
return node;
|
|
93
|
+
}
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// PostgreSQL Type to Zod Schema Mapping
|
|
96
|
+
// =============================================================================
|
|
97
|
+
const PG_STRING_TYPES = new Set([
|
|
98
|
+
"uuid",
|
|
99
|
+
"text",
|
|
100
|
+
"varchar",
|
|
101
|
+
"char",
|
|
102
|
+
"character",
|
|
103
|
+
"name",
|
|
104
|
+
"bpchar",
|
|
105
|
+
"citext",
|
|
106
|
+
]);
|
|
107
|
+
const PG_NUMBER_TYPES = new Set([
|
|
108
|
+
"int2",
|
|
109
|
+
"int4",
|
|
110
|
+
"int8",
|
|
111
|
+
"integer",
|
|
112
|
+
"smallint",
|
|
113
|
+
"bigint",
|
|
114
|
+
"numeric",
|
|
115
|
+
"decimal",
|
|
116
|
+
"real",
|
|
117
|
+
"float4",
|
|
118
|
+
"float8",
|
|
119
|
+
"double",
|
|
120
|
+
]);
|
|
121
|
+
const PG_BOOLEAN_TYPES = new Set(["bool", "boolean"]);
|
|
122
|
+
const PG_DATE_TYPES = new Set(["timestamp", "timestamptz", "date", "time", "timetz"]);
|
|
123
|
+
const PG_JSON_TYPES = new Set(["json", "jsonb"]);
|
|
124
|
+
function fieldToZodMapping(field, enums) {
|
|
125
|
+
const pgType = field.pgAttribute.getType();
|
|
126
|
+
if (!pgType) {
|
|
127
|
+
return { kind: "schema", schema: conjure.id("z").method("unknown").build() };
|
|
90
128
|
}
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Reference the separate enum schema
|
|
104
|
-
baseSchema = conjure.id(enumDef.name).build();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
baseSchema = buildZodChain("unknown", []);
|
|
109
|
-
}
|
|
129
|
+
// For arrays, use element type; for domains, use base type; otherwise use pgType
|
|
130
|
+
let typeName;
|
|
131
|
+
let typeInfo;
|
|
132
|
+
if (pgType.typcategory === "A") {
|
|
133
|
+
// Array type - use element type name
|
|
134
|
+
typeName = field.elementTypeName ?? "unknown";
|
|
135
|
+
typeInfo = pgType;
|
|
136
|
+
}
|
|
137
|
+
else if (pgType.typtype === "d" && field.domainBaseType) {
|
|
138
|
+
// Domain type - resolve to underlying base type
|
|
139
|
+
typeName = field.domainBaseType.typeName;
|
|
140
|
+
typeInfo = { typcategory: field.domainBaseType.category };
|
|
110
141
|
}
|
|
111
|
-
// 4. Fallback to resolved TypeScript type
|
|
112
142
|
else {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
typeName = pgType.typname;
|
|
144
|
+
typeInfo = pgType;
|
|
145
|
+
}
|
|
146
|
+
const baseResult = baseTypeToZodMapping(typeName, typeInfo, enums);
|
|
147
|
+
// For enum references, return as-is (modifiers applied in shapeToZodObject)
|
|
148
|
+
if (baseResult.kind === "enumRef") {
|
|
149
|
+
return baseResult;
|
|
116
150
|
}
|
|
117
|
-
|
|
151
|
+
let schema = baseResult.schema;
|
|
118
152
|
if (field.isArray) {
|
|
119
|
-
|
|
153
|
+
schema = conjure.chain(schema).method("array").build();
|
|
120
154
|
}
|
|
121
|
-
|
|
122
|
-
const modifiers = [];
|
|
155
|
+
const methods = [];
|
|
123
156
|
if (field.nullable)
|
|
124
|
-
|
|
157
|
+
methods.push("nullable");
|
|
125
158
|
if (field.optional)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
};
|
|
130
|
-
// ============================================================================
|
|
131
|
-
// Statement Generators
|
|
132
|
-
// ============================================================================
|
|
133
|
-
/**
|
|
134
|
-
* Build z.object({...}) expression from shape fields
|
|
135
|
-
*/
|
|
136
|
-
const buildShapeZodObject = (shape, ctx) => {
|
|
137
|
-
const objBuilder = shape.fields.reduce((builder, field) => builder.prop(field.name, resolveFieldZodSchema(field, ctx)), obj());
|
|
138
|
-
return conjure.id("z").method("object", [objBuilder.build()]).build();
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Generate schema const + optional inferred type for a shape
|
|
142
|
-
*/
|
|
143
|
-
const generateShapeStatements = (shape, entityName, shapeKind, ctx, exportTypes) => {
|
|
144
|
-
const schemaSymbolCtx = { capability: "schemas", entity: entityName, shape: shapeKind };
|
|
145
|
-
const schemaExpr = buildShapeZodObject(shape, ctx);
|
|
146
|
-
const schemaStatement = exp.const(shape.name, schemaSymbolCtx, schemaExpr);
|
|
147
|
-
if (!exportTypes) {
|
|
148
|
-
return [schemaStatement];
|
|
159
|
+
methods.push("optional");
|
|
160
|
+
for (const method of methods) {
|
|
161
|
+
schema = conjure.chain(schema).method(method).build();
|
|
149
162
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
["row", entity.shapes.row],
|
|
162
|
-
["insert", entity.shapes.insert],
|
|
163
|
-
["update", entity.shapes.update],
|
|
164
|
-
].filter((entry) => entry[1] != null);
|
|
165
|
-
/**
|
|
166
|
-
* Generate all statements for an entity's shapes
|
|
167
|
-
*/
|
|
168
|
-
const generateEntityStatements = (entity, ctx, exportTypes) => collectShapes(entity).flatMap(([kind, shape]) => generateShapeStatements(shape, entity.name, kind, ctx, exportTypes));
|
|
169
|
-
// ============================================================================
|
|
170
|
-
// Composite Type Generation
|
|
171
|
-
// ============================================================================
|
|
172
|
-
/**
|
|
173
|
-
* Build z.object({...}) expression from composite fields
|
|
174
|
-
*/
|
|
175
|
-
const buildCompositeZodObject = (composite, ctx) => {
|
|
176
|
-
const objBuilder = composite.fields.reduce((builder, field) => builder.prop(field.name, resolveFieldZodSchema(field, ctx)), obj());
|
|
177
|
-
return conjure.id("z").method("object", [objBuilder.build()]).build();
|
|
178
|
-
};
|
|
179
|
-
/**
|
|
180
|
-
* Generate schema const + optional inferred type for a composite type
|
|
181
|
-
*/
|
|
182
|
-
const generateCompositeStatements = (composite, ctx, exportTypes) => {
|
|
183
|
-
const schemaSymbolCtx = { capability: "schemas", entity: composite.name };
|
|
184
|
-
const schemaExpr = buildCompositeZodObject(composite, ctx);
|
|
185
|
-
const schemaStatement = exp.const(composite.name, schemaSymbolCtx, schemaExpr);
|
|
186
|
-
if (!exportTypes) {
|
|
187
|
-
return [schemaStatement];
|
|
163
|
+
return { kind: "schema", schema };
|
|
164
|
+
}
|
|
165
|
+
function baseTypeToZodMapping(typeName, pgType, enums) {
|
|
166
|
+
const normalized = typeName.toLowerCase();
|
|
167
|
+
if (PG_STRING_TYPES.has(normalized)) {
|
|
168
|
+
if (normalized === "uuid") {
|
|
169
|
+
return { kind: "schema", schema: conjure.id("z").method("uuid").build() };
|
|
170
|
+
}
|
|
171
|
+
// citext is case-insensitive text - just treat as regular string
|
|
172
|
+
// (Zod doesn't have a built-in case-insensitive string validator)
|
|
173
|
+
return { kind: "schema", schema: conjure.id("z").method("string").build() };
|
|
188
174
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const typeSymbolCtx = { capability: "types", entity: composite.name };
|
|
192
|
-
const inferType = ts.qualifiedRef("z", "infer", [ts.typeof(composite.name)]);
|
|
193
|
-
const typeStatement = exp.type(composite.name, typeSymbolCtx, inferType);
|
|
194
|
-
return [schemaStatement, typeStatement];
|
|
195
|
-
};
|
|
196
|
-
// ============================================================================
|
|
197
|
-
// Enum Generation
|
|
198
|
-
// ============================================================================
|
|
199
|
-
/**
|
|
200
|
-
* Generate enum schema statement: export const EnumName = z.enum(['a', 'b', ...])
|
|
201
|
-
* or for native enums: export enum EnumName { A = 'a', ... } + schema
|
|
202
|
-
*/
|
|
203
|
-
const generateEnumStatement = (enumEntity, enumStyle, exportTypes) => {
|
|
204
|
-
const schemaSymbolCtx = { capability: "schemas", entity: enumEntity.name };
|
|
205
|
-
if (enumStyle === "enum") {
|
|
206
|
-
// Generate: export enum EnumName { A = 'a', B = 'b', ... }
|
|
207
|
-
// Then: export const EnumNameSchema = z.nativeEnum(EnumName)
|
|
208
|
-
const enumStatement = exp.tsEnum(enumEntity.name, { capability: "types", entity: enumEntity.name }, enumEntity.values);
|
|
209
|
-
const schemaName = `${enumEntity.name}Schema`;
|
|
210
|
-
const schemaExpr = conjure
|
|
211
|
-
.id("z")
|
|
212
|
-
.method("nativeEnum", [conjure.id(enumEntity.name).build()])
|
|
213
|
-
.build();
|
|
214
|
-
const schemaStatement = exp.const(schemaName, schemaSymbolCtx, schemaExpr);
|
|
215
|
-
return [enumStatement, schemaStatement];
|
|
175
|
+
if (PG_NUMBER_TYPES.has(normalized)) {
|
|
176
|
+
return { kind: "schema", schema: conjure.id("z").method("number").build() };
|
|
216
177
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const schemaStatement = exp.const(enumEntity.name, schemaSymbolCtx, schemaExpr);
|
|
220
|
-
if (!exportTypes) {
|
|
221
|
-
return [schemaStatement];
|
|
178
|
+
if (PG_BOOLEAN_TYPES.has(normalized)) {
|
|
179
|
+
return { kind: "schema", schema: conjure.id("z").method("boolean").build() };
|
|
222
180
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const typeSymbolCtx = { capability: "types", entity: enumEntity.name };
|
|
226
|
-
const inferType = ts.qualifiedRef("z", "infer", [ts.typeof(enumEntity.name)]);
|
|
227
|
-
const typeStatement = exp.type(enumEntity.name, typeSymbolCtx, inferType);
|
|
228
|
-
return [schemaStatement, typeStatement];
|
|
229
|
-
};
|
|
230
|
-
/** Collect enum names used by fields */
|
|
231
|
-
const collectUsedEnums = (fields, enums) => {
|
|
232
|
-
const enumNames = fields.filter(isEnumType).flatMap(field => {
|
|
233
|
-
const pgTypeName = getPgTypeName(field);
|
|
234
|
-
if (!pgTypeName)
|
|
235
|
-
return [];
|
|
236
|
-
return pipe(findEnumByPgName(enums, pgTypeName), Option.map(e => e.name), Option.toArray);
|
|
237
|
-
});
|
|
238
|
-
return new Set(enumNames);
|
|
239
|
-
};
|
|
240
|
-
/** Build import refs for used enums */
|
|
241
|
-
const buildEnumImports = (usedEnums) => Arr.fromIterable(usedEnums).map(enumName => ({
|
|
242
|
-
kind: "symbol",
|
|
243
|
-
ref: { capability: "schemas", entity: enumName },
|
|
244
|
-
}));
|
|
245
|
-
// ============================================================================
|
|
246
|
-
// Schema Builder Service
|
|
247
|
-
// ============================================================================
|
|
248
|
-
/**
|
|
249
|
-
* Build Zod schema expression for a single param.
|
|
250
|
-
* Uses z.coerce for numeric types since URL params are always strings.
|
|
251
|
-
*/
|
|
252
|
-
const buildParamFieldSchema = (param) => {
|
|
253
|
-
const tsType = param.type.toLowerCase();
|
|
254
|
-
let fieldSchema;
|
|
255
|
-
switch (tsType) {
|
|
256
|
-
case "number":
|
|
257
|
-
// z.coerce.number() - converts string "10" to number 10
|
|
258
|
-
fieldSchema = conjure.id("z").prop("coerce").method("number").build();
|
|
259
|
-
break;
|
|
260
|
-
case "boolean":
|
|
261
|
-
// z.coerce.boolean() - converts "true"/"false" strings
|
|
262
|
-
fieldSchema = conjure.id("z").prop("coerce").method("boolean").build();
|
|
263
|
-
break;
|
|
264
|
-
case "bigint":
|
|
265
|
-
// z.coerce.bigint()
|
|
266
|
-
fieldSchema = conjure.id("z").prop("coerce").method("bigint").build();
|
|
267
|
-
break;
|
|
268
|
-
case "date":
|
|
269
|
-
// z.coerce.date() - converts ISO strings to Date objects
|
|
270
|
-
fieldSchema = conjure.id("z").prop("coerce").method("date").build();
|
|
271
|
-
break;
|
|
272
|
-
case "string":
|
|
273
|
-
default:
|
|
274
|
-
// z.string() - no coercion needed
|
|
275
|
-
fieldSchema = buildZodChain("string", []);
|
|
276
|
-
break;
|
|
181
|
+
if (PG_DATE_TYPES.has(normalized)) {
|
|
182
|
+
return { kind: "schema", schema: conjure.id("z").method("coerce").method("date").build() };
|
|
277
183
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
fieldSchema = chainZodMethods(fieldSchema, ["optional"]);
|
|
184
|
+
if (PG_JSON_TYPES.has(normalized)) {
|
|
185
|
+
return { kind: "schema", schema: conjure.id("z").method("unknown").build() };
|
|
281
186
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
*/
|
|
288
|
-
const buildParamZodObject = (params) => {
|
|
289
|
-
const objBuilder = params.reduce((builder, param) => builder.prop(param.name, buildParamFieldSchema(param)), obj());
|
|
290
|
-
return conjure.id("z").method("object", [objBuilder.build()]).build();
|
|
291
|
-
};
|
|
292
|
-
/**
|
|
293
|
-
* Create a SchemaBuilder implementation for Zod.
|
|
294
|
-
*/
|
|
295
|
-
const createZodSchemaBuilder = () => ({
|
|
296
|
-
build: (request) => {
|
|
297
|
-
if (request.params.length === 0) {
|
|
298
|
-
return undefined;
|
|
187
|
+
if (pgType.typtype === "e" || pgType.typcategory === "E") {
|
|
188
|
+
const enumEntity = enums.find(e => e.pgType.typname === typeName);
|
|
189
|
+
if (enumEntity) {
|
|
190
|
+
// Return reference to the enum schema instead of inlining
|
|
191
|
+
return { kind: "enumRef", enumRef: enumEntity.name };
|
|
299
192
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
193
|
+
return { kind: "schema", schema: conjure.id("z").method("unknown").build() };
|
|
194
|
+
}
|
|
195
|
+
return { kind: "schema", schema: conjure.id("z").method("unknown").build() };
|
|
196
|
+
}
|
|
197
|
+
// =============================================================================
|
|
198
|
+
// Shape to Zod Object
|
|
199
|
+
// =============================================================================
|
|
200
|
+
function shapeToZodObject(shape, enums, registry) {
|
|
201
|
+
const properties = shape.fields.map(field => {
|
|
202
|
+
const mapping = fieldToZodMapping(field, enums);
|
|
203
|
+
let value;
|
|
204
|
+
if (mapping.kind === "enumRef") {
|
|
205
|
+
// Get handle and track cross-reference
|
|
206
|
+
const enumHandle = registry.import(`schema:zod:${mapping.enumRef}`);
|
|
207
|
+
value = enumHandle.ref();
|
|
208
|
+
// Apply modifiers for enum references
|
|
209
|
+
if (field.isArray) {
|
|
210
|
+
value = conjure.chain(value).method("array").build();
|
|
211
|
+
}
|
|
212
|
+
if (field.nullable) {
|
|
213
|
+
value = conjure.chain(value).method("nullable").build();
|
|
214
|
+
}
|
|
215
|
+
if (field.optional) {
|
|
216
|
+
value = conjure.chain(value).method("optional").build();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
value = mapping.schema;
|
|
221
|
+
}
|
|
222
|
+
return b.objectProperty(b.identifier(field.name), toExpr(value));
|
|
223
|
+
});
|
|
224
|
+
const objExpr = b.objectExpression(properties);
|
|
225
|
+
const zObject = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("object")), [
|
|
226
|
+
objExpr,
|
|
227
|
+
]);
|
|
228
|
+
return zObject;
|
|
229
|
+
}
|
|
230
|
+
// =============================================================================
|
|
231
|
+
// Zod Plugin Definition
|
|
232
|
+
// =============================================================================
|
|
233
|
+
function getShapeDeclarations(entity) {
|
|
234
|
+
const declarations = [];
|
|
235
|
+
const baseEntityName = entity.name;
|
|
236
|
+
// Row shape uses the entity name directly
|
|
237
|
+
declarations.push({
|
|
238
|
+
name: entity.shapes.row.name,
|
|
239
|
+
capability: `schema:zod:${entity.shapes.row.name}`,
|
|
240
|
+
baseEntityName,
|
|
241
|
+
});
|
|
242
|
+
if (entity.shapes.insert) {
|
|
243
|
+
const insertName = entity.shapes.insert.name;
|
|
244
|
+
declarations.push({
|
|
245
|
+
name: insertName,
|
|
246
|
+
capability: `schema:zod:${insertName}`,
|
|
247
|
+
baseEntityName,
|
|
248
|
+
});
|
|
249
|
+
declarations.push({
|
|
250
|
+
name: insertName,
|
|
251
|
+
capability: `schema:zod:${insertName}:type`,
|
|
252
|
+
baseEntityName,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (entity.shapes.update) {
|
|
256
|
+
const updateName = entity.shapes.update.name;
|
|
257
|
+
declarations.push({
|
|
258
|
+
name: updateName,
|
|
259
|
+
capability: `schema:zod:${updateName}`,
|
|
260
|
+
baseEntityName,
|
|
261
|
+
});
|
|
262
|
+
declarations.push({
|
|
263
|
+
name: updateName,
|
|
264
|
+
capability: `schema:zod:${updateName}:type`,
|
|
265
|
+
baseEntityName,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return declarations;
|
|
269
|
+
}
|
|
270
|
+
export function zod(config) {
|
|
271
|
+
// Parse schema-validated options
|
|
272
|
+
const schemaConfig = S.decodeSync(ZodSchemaConfig)(config ?? {});
|
|
273
|
+
// Resolve file naming
|
|
274
|
+
const resolvedConfig = {
|
|
275
|
+
...schemaConfig,
|
|
276
|
+
schemasFile: normalizeFileNaming(config?.schemasFile, "schemas.ts"),
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
331
279
|
name: "zod",
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
.
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
});
|
|
280
|
+
provides: ["schema"],
|
|
281
|
+
fileDefaults: [
|
|
282
|
+
{
|
|
283
|
+
pattern: "schema:",
|
|
284
|
+
fileNaming: resolvedConfig.schemasFile,
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
declare: Effect.gen(function* () {
|
|
288
|
+
const ir = yield* IR;
|
|
289
|
+
const declarations = [];
|
|
290
|
+
for (const entity of ir.entities.values()) {
|
|
291
|
+
if (isTableEntity(entity)) {
|
|
292
|
+
// Push declarations directly - they already include baseEntityName
|
|
293
|
+
declarations.push(...getShapeDeclarations(entity));
|
|
294
|
+
}
|
|
295
|
+
else if (isEnumEntity(entity)) {
|
|
296
|
+
declarations.push({
|
|
297
|
+
name: entity.name,
|
|
298
|
+
capability: `schema:zod:${entity.name}`,
|
|
299
|
+
baseEntityName: entity.name,
|
|
300
|
+
});
|
|
301
|
+
declarations.push({
|
|
302
|
+
name: entity.name,
|
|
303
|
+
capability: `schema:zod:${entity.name}:type`,
|
|
304
|
+
baseEntityName: entity.name,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
360
307
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const entityName = inflection.entityName(entity.pgClass, entity.tags);
|
|
366
|
-
// Collect all fields for enum detection
|
|
367
|
-
const allFields = [
|
|
368
|
-
...entity.shapes.row.fields,
|
|
369
|
-
...(entity.shapes.insert?.fields ?? []),
|
|
370
|
-
...(entity.shapes.update?.fields ?? []),
|
|
371
|
-
];
|
|
372
|
-
const usedEnums = parsed.typeReferences === "separate"
|
|
373
|
-
? collectUsedEnums(allFields, Arr.fromIterable(fieldCtx.enums))
|
|
374
|
-
: new Set();
|
|
375
|
-
const fileBuilder = ctx
|
|
376
|
-
.file(buildFilePath(entityName))
|
|
377
|
-
.import({ kind: "package", names: ["z"], from: "zod" });
|
|
378
|
-
// Add enum imports when using separate files
|
|
379
|
-
buildEnumImports(usedEnums).forEach(ref => fileBuilder.import(ref));
|
|
380
|
-
fileBuilder.ast(conjure.symbolProgram(...statements)).emit();
|
|
308
|
+
// Declare the schema builder capability
|
|
309
|
+
declarations.push({
|
|
310
|
+
name: "zodSchemaBuilder",
|
|
311
|
+
capability: "schema:zod:builder",
|
|
381
312
|
});
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
313
|
+
return declarations;
|
|
314
|
+
}),
|
|
315
|
+
render: Effect.gen(function* () {
|
|
316
|
+
const ir = yield* IR;
|
|
317
|
+
const registry = yield* SymbolRegistry;
|
|
318
|
+
const enums = [...ir.entities.values()].filter(isEnumEntity);
|
|
319
|
+
const rendered = [];
|
|
320
|
+
for (const entity of ir.entities.values()) {
|
|
321
|
+
if (isTableEntity(entity)) {
|
|
322
|
+
const shapes = [
|
|
323
|
+
entity.shapes.row,
|
|
324
|
+
];
|
|
325
|
+
if (entity.shapes.insert)
|
|
326
|
+
shapes.push(entity.shapes.insert);
|
|
327
|
+
if (entity.shapes.update)
|
|
328
|
+
shapes.push(entity.shapes.update);
|
|
329
|
+
for (const shape of shapes) {
|
|
330
|
+
const isRow = shape.kind === "row";
|
|
331
|
+
const capability = `schema:zod:${shape.name}`;
|
|
332
|
+
// Scope cross-references to this specific capability
|
|
333
|
+
const schemaNode = registry.forSymbol(capability, () => shapeToZodObject(shape, enums, registry));
|
|
334
|
+
const schemaDecl = conjure.export.const(shape.name, schemaNode);
|
|
335
|
+
rendered.push({
|
|
336
|
+
name: shape.name,
|
|
337
|
+
capability,
|
|
338
|
+
node: schemaDecl,
|
|
339
|
+
exports: "named",
|
|
340
|
+
externalImports: [{ from: "zod", names: ["z"] }],
|
|
341
|
+
metadata: {
|
|
342
|
+
consume: createZodConsumeCallback(shape.name),
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
if (resolvedConfig.exportTypes && !isRow) {
|
|
346
|
+
const inferType = conjure.ts.qualifiedRef("z", "infer", [
|
|
347
|
+
conjure.ts.typeof(shape.name),
|
|
348
|
+
]);
|
|
349
|
+
const typeDecl = conjure.export.type(shape.name, inferType);
|
|
350
|
+
rendered.push({
|
|
351
|
+
name: shape.name,
|
|
352
|
+
capability: `schema:zod:${shape.name}:type`,
|
|
353
|
+
node: typeDecl,
|
|
354
|
+
exports: "named",
|
|
355
|
+
externalImports: [{ from: "zod", names: ["z"] }],
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else if (isEnumEntity(entity)) {
|
|
361
|
+
const schemaNode = conjure
|
|
362
|
+
.id("z")
|
|
363
|
+
.method("enum", [conjure.arr(...entity.values.map(v => conjure.str(v))).build()])
|
|
364
|
+
.build();
|
|
365
|
+
const schemaDecl = conjure.export.const(entity.name, schemaNode);
|
|
366
|
+
const inferType = conjure.ts.qualifiedRef("z", "infer", [conjure.ts.typeof(entity.name)]);
|
|
367
|
+
const typeDecl = conjure.export.type(entity.name, inferType);
|
|
368
|
+
rendered.push({
|
|
369
|
+
name: entity.name,
|
|
370
|
+
capability: `schema:zod:${entity.name}`,
|
|
371
|
+
node: schemaDecl,
|
|
372
|
+
exports: "named",
|
|
373
|
+
externalImports: [{ from: "zod", names: ["z"] }],
|
|
374
|
+
metadata: {
|
|
375
|
+
consume: createZodConsumeCallback(entity.name),
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
if (resolvedConfig.exportTypes) {
|
|
379
|
+
rendered.push({
|
|
380
|
+
name: entity.name,
|
|
381
|
+
capability: `schema:zod:${entity.name}:type`,
|
|
382
|
+
node: typeDecl,
|
|
383
|
+
exports: "named",
|
|
384
|
+
externalImports: [{ from: "zod", names: ["z"] }],
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// Render the schema builder (virtual symbol - no node, just metadata)
|
|
390
|
+
// The builder is used by HTTP plugins to generate inline param schemas
|
|
391
|
+
rendered.push({
|
|
392
|
+
name: "zodSchemaBuilder",
|
|
393
|
+
capability: "schema:zod:builder",
|
|
394
|
+
node: null, // Virtual symbol - no emitted code
|
|
395
|
+
exports: false, // Not exported
|
|
396
|
+
metadata: {
|
|
397
|
+
builder: zodSchemaBuilder,
|
|
398
|
+
},
|
|
396
399
|
});
|
|
397
|
-
return
|
|
398
|
-
},
|
|
399
|
-
}
|
|
400
|
+
return rendered;
|
|
401
|
+
}),
|
|
402
|
+
};
|
|
400
403
|
}
|
|
401
404
|
//# sourceMappingURL=zod.js.map
|