@danielfgray/pg-sourcerer 0.2.2 → 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.
Files changed (307) hide show
  1. package/bin/pgsourcerer +2 -0
  2. package/dist/__tests__/fixtures/index.d.ts +15 -0
  3. package/dist/__tests__/fixtures/index.d.ts.map +1 -0
  4. package/dist/__tests__/fixtures/index.js +19 -0
  5. package/dist/__tests__/fixtures/index.js.map +1 -0
  6. package/dist/__tests__/fixtures/introspection.json +40522 -0
  7. package/dist/cli.d.ts +0 -1
  8. package/dist/cli.js +7 -46
  9. package/dist/cli.js.map +1 -1
  10. package/dist/config.d.ts +38 -5
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +13 -2
  13. package/dist/config.js.map +1 -1
  14. package/dist/{lib/conjure.d.ts → conjure/index.d.ts} +62 -3
  15. package/dist/conjure/index.d.ts.map +1 -0
  16. package/dist/{lib/conjure.js → conjure/index.js} +124 -3
  17. package/dist/conjure/index.js.map +1 -0
  18. package/dist/conjure/signature.d.ts +85 -0
  19. package/dist/conjure/signature.d.ts.map +1 -0
  20. package/dist/conjure/signature.js +130 -0
  21. package/dist/conjure/signature.js.map +1 -0
  22. package/dist/conjure/types.d.ts +97 -0
  23. package/dist/conjure/types.d.ts.map +1 -0
  24. package/dist/conjure/types.js +206 -0
  25. package/dist/conjure/types.js.map +1 -0
  26. package/dist/errors.d.ts +114 -139
  27. package/dist/errors.d.ts.map +1 -1
  28. package/dist/errors.js +82 -36
  29. package/dist/errors.js.map +1 -1
  30. package/dist/generate.d.ts +45 -46
  31. package/dist/generate.d.ts.map +1 -1
  32. package/dist/generate.js +86 -59
  33. package/dist/generate.js.map +1 -1
  34. package/dist/hex/builder.d.ts +12 -0
  35. package/dist/hex/builder.d.ts.map +1 -0
  36. package/dist/hex/builder.js +64 -0
  37. package/dist/hex/builder.js.map +1 -0
  38. package/dist/hex/ddl.d.ts +53 -0
  39. package/dist/hex/ddl.d.ts.map +1 -0
  40. package/dist/hex/ddl.js +306 -0
  41. package/dist/hex/ddl.js.map +1 -0
  42. package/dist/hex/index.d.ts +105 -0
  43. package/dist/hex/index.d.ts.map +1 -0
  44. package/dist/hex/index.js +81 -0
  45. package/dist/hex/index.js.map +1 -0
  46. package/dist/hex/primitives.d.ts +23 -0
  47. package/dist/hex/primitives.d.ts.map +1 -0
  48. package/dist/hex/primitives.js +38 -0
  49. package/dist/hex/primitives.js.map +1 -0
  50. package/dist/hex/query.d.ts +116 -0
  51. package/dist/hex/query.d.ts.map +1 -0
  52. package/dist/hex/query.js +219 -0
  53. package/dist/hex/query.js.map +1 -0
  54. package/dist/hex/types.d.ts +287 -0
  55. package/dist/hex/types.d.ts.map +1 -0
  56. package/dist/hex/types.js +431 -0
  57. package/dist/hex/types.js.map +1 -0
  58. package/dist/index.d.ts +17 -25
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +33 -44
  61. package/dist/index.js.map +1 -1
  62. package/dist/init.d.ts.map +1 -1
  63. package/dist/init.js +76 -140
  64. package/dist/init.js.map +1 -1
  65. package/dist/ir/extensions/queries.d.ts +6 -6
  66. package/dist/ir/extensions/queries.d.ts.map +1 -1
  67. package/dist/ir/extensions/queries.js +6 -4
  68. package/dist/ir/extensions/queries.js.map +1 -1
  69. package/dist/ir/extensions/schema-builder.d.ts.map +1 -1
  70. package/dist/ir/extensions/schema-builder.js.map +1 -1
  71. package/dist/ir/index.d.ts.map +1 -1
  72. package/dist/ir/index.js.map +1 -1
  73. package/dist/ir/relation-graph.d.ts.map +1 -1
  74. package/dist/ir/relation-graph.js +8 -8
  75. package/dist/ir/relation-graph.js.map +1 -1
  76. package/dist/ir/semantic-ir.d.ts +38 -0
  77. package/dist/ir/semantic-ir.d.ts.map +1 -1
  78. package/dist/ir/semantic-ir.js +50 -2
  79. package/dist/ir/semantic-ir.js.map +1 -1
  80. package/dist/ir/smart-tags.d.ts.map +1 -1
  81. package/dist/ir/smart-tags.js.map +1 -1
  82. package/dist/lib/field-utils.d.ts.map +1 -1
  83. package/dist/lib/field-utils.js +7 -7
  84. package/dist/lib/field-utils.js.map +1 -1
  85. package/dist/lib/join-graph.d.ts +95 -0
  86. package/dist/lib/join-graph.d.ts.map +1 -0
  87. package/dist/lib/join-graph.js +305 -0
  88. package/dist/lib/join-graph.js.map +1 -0
  89. package/dist/lib/picker.d.ts +60 -0
  90. package/dist/lib/picker.d.ts.map +1 -0
  91. package/dist/lib/picker.js +325 -0
  92. package/dist/lib/picker.js.map +1 -0
  93. package/dist/plugins/arktype.d.ts +20 -24
  94. package/dist/plugins/arktype.d.ts.map +1 -1
  95. package/dist/plugins/arktype.js +462 -386
  96. package/dist/plugins/arktype.js.map +1 -1
  97. package/dist/plugins/effect/http.d.ts +7 -0
  98. package/dist/plugins/effect/http.d.ts.map +1 -0
  99. package/dist/plugins/effect/http.js +460 -0
  100. package/dist/plugins/effect/http.js.map +1 -0
  101. package/dist/plugins/effect/index.d.ts +22 -0
  102. package/dist/plugins/effect/index.d.ts.map +1 -0
  103. package/dist/plugins/effect/index.js +65 -0
  104. package/dist/plugins/effect/index.js.map +1 -0
  105. package/dist/plugins/effect/models.d.ts +6 -0
  106. package/dist/plugins/effect/models.d.ts.map +1 -0
  107. package/dist/plugins/effect/models.js +116 -0
  108. package/dist/plugins/effect/models.js.map +1 -0
  109. package/dist/plugins/effect/repos.d.ts +21 -0
  110. package/dist/plugins/effect/repos.d.ts.map +1 -0
  111. package/dist/plugins/effect/repos.js +131 -0
  112. package/dist/plugins/effect/repos.js.map +1 -0
  113. package/dist/plugins/effect/schemas.d.ts +7 -0
  114. package/dist/plugins/effect/schemas.d.ts.map +1 -0
  115. package/dist/plugins/effect/schemas.js +75 -0
  116. package/dist/plugins/effect/schemas.js.map +1 -0
  117. package/dist/plugins/effect/shared.d.ts +116 -0
  118. package/dist/plugins/effect/shared.d.ts.map +1 -0
  119. package/dist/plugins/effect/shared.js +164 -0
  120. package/dist/plugins/effect/shared.js.map +1 -0
  121. package/dist/plugins/http-elysia.d.ts +20 -27
  122. package/dist/plugins/http-elysia.d.ts.map +1 -1
  123. package/dist/plugins/http-elysia.js +350 -475
  124. package/dist/plugins/http-elysia.js.map +1 -1
  125. package/dist/plugins/http-express.d.ts +20 -31
  126. package/dist/plugins/http-express.d.ts.map +1 -1
  127. package/dist/plugins/http-express.js +281 -268
  128. package/dist/plugins/http-express.js.map +1 -1
  129. package/dist/plugins/http-hono.d.ts +17 -33
  130. package/dist/plugins/http-hono.d.ts.map +1 -1
  131. package/dist/plugins/http-hono.js +317 -341
  132. package/dist/plugins/http-hono.js.map +1 -1
  133. package/dist/plugins/http-orpc.d.ts +34 -33
  134. package/dist/plugins/http-orpc.d.ts.map +1 -1
  135. package/dist/plugins/http-orpc.js +345 -257
  136. package/dist/plugins/http-orpc.js.map +1 -1
  137. package/dist/plugins/http-trpc.d.ts +33 -35
  138. package/dist/plugins/http-trpc.d.ts.map +1 -1
  139. package/dist/plugins/http-trpc.js +337 -241
  140. package/dist/plugins/http-trpc.js.map +1 -1
  141. package/dist/plugins/kysely.d.ts +54 -59
  142. package/dist/plugins/kysely.d.ts.map +1 -1
  143. package/dist/plugins/kysely.js +826 -687
  144. package/dist/plugins/kysely.js.map +1 -1
  145. package/dist/plugins/sql-queries.d.ts +38 -44
  146. package/dist/plugins/sql-queries.d.ts.map +1 -1
  147. package/dist/plugins/sql-queries.js +497 -897
  148. package/dist/plugins/sql-queries.js.map +1 -1
  149. package/dist/plugins/types.d.ts +12 -20
  150. package/dist/plugins/types.d.ts.map +1 -1
  151. package/dist/plugins/types.js +84 -227
  152. package/dist/plugins/types.js.map +1 -1
  153. package/dist/plugins/valibot.d.ts +7 -44
  154. package/dist/plugins/valibot.d.ts.map +1 -1
  155. package/dist/plugins/valibot.js +376 -382
  156. package/dist/plugins/valibot.js.map +1 -1
  157. package/dist/plugins/zod.d.ts +20 -24
  158. package/dist/plugins/zod.d.ts.map +1 -1
  159. package/dist/plugins/zod.js +370 -367
  160. package/dist/plugins/zod.js.map +1 -1
  161. package/dist/runtime/emit.d.ts +64 -0
  162. package/dist/runtime/emit.d.ts.map +1 -0
  163. package/dist/runtime/emit.js +445 -0
  164. package/dist/runtime/emit.js.map +1 -0
  165. package/dist/runtime/errors.d.ts +36 -0
  166. package/dist/runtime/errors.d.ts.map +1 -0
  167. package/dist/runtime/errors.js +29 -0
  168. package/dist/runtime/errors.js.map +1 -0
  169. package/dist/runtime/file-assignment.d.ts +161 -0
  170. package/dist/runtime/file-assignment.d.ts.map +1 -0
  171. package/dist/runtime/file-assignment.js +195 -0
  172. package/dist/runtime/file-assignment.js.map +1 -0
  173. package/dist/runtime/orchestrator.d.ts +62 -0
  174. package/dist/runtime/orchestrator.d.ts.map +1 -0
  175. package/dist/runtime/orchestrator.js +99 -0
  176. package/dist/runtime/orchestrator.js.map +1 -0
  177. package/dist/runtime/registry.d.ts +268 -0
  178. package/dist/runtime/registry.d.ts.map +1 -0
  179. package/dist/runtime/registry.js +436 -0
  180. package/dist/runtime/registry.js.map +1 -0
  181. package/dist/runtime/types.d.ts +182 -0
  182. package/dist/runtime/types.d.ts.map +1 -0
  183. package/dist/runtime/types.js +2 -0
  184. package/dist/runtime/types.js.map +1 -0
  185. package/dist/runtime/validation.d.ts +41 -0
  186. package/dist/runtime/validation.d.ts.map +1 -0
  187. package/dist/runtime/validation.js +70 -0
  188. package/dist/runtime/validation.js.map +1 -0
  189. package/dist/services/config-loader.d.ts.map +1 -1
  190. package/dist/services/config-loader.js +15 -6
  191. package/dist/services/config-loader.js.map +1 -1
  192. package/dist/services/config.d.ts +55 -25
  193. package/dist/services/config.d.ts.map +1 -1
  194. package/dist/services/config.js +60 -34
  195. package/dist/services/config.js.map +1 -1
  196. package/dist/services/file-writer.d.ts +3 -3
  197. package/dist/services/file-writer.d.ts.map +1 -1
  198. package/dist/services/file-writer.js +6 -8
  199. package/dist/services/file-writer.js.map +1 -1
  200. package/dist/services/inflection.d.ts +126 -27
  201. package/dist/services/inflection.d.ts.map +1 -1
  202. package/dist/services/inflection.js +300 -72
  203. package/dist/services/inflection.js.map +1 -1
  204. package/dist/services/introspection.d.ts.map +1 -1
  205. package/dist/services/introspection.js +6 -6
  206. package/dist/services/introspection.js.map +1 -1
  207. package/dist/services/ir-builder.d.ts.map +1 -1
  208. package/dist/services/ir-builder.js +73 -77
  209. package/dist/services/ir-builder.js.map +1 -1
  210. package/dist/services/ir.d.ts.map +1 -1
  211. package/dist/services/ir.js.map +1 -1
  212. package/dist/services/pg-types.d.ts.map +1 -1
  213. package/dist/services/pg-types.js +3 -3
  214. package/dist/services/pg-types.js.map +1 -1
  215. package/dist/services/smart-tags-parser.d.ts.map +1 -1
  216. package/dist/services/smart-tags-parser.js +4 -4
  217. package/dist/services/smart-tags-parser.js.map +1 -1
  218. package/dist/services/type-hints.d.ts.map +1 -1
  219. package/dist/services/type-hints.js +1 -1
  220. package/dist/services/type-hints.js.map +1 -1
  221. package/dist/services/user-module-parser.d.ts +46 -0
  222. package/dist/services/user-module-parser.d.ts.map +1 -0
  223. package/dist/services/user-module-parser.js +181 -0
  224. package/dist/services/user-module-parser.js.map +1 -0
  225. package/dist/shared/converters.d.ts +60 -0
  226. package/dist/shared/converters.d.ts.map +1 -0
  227. package/dist/shared/converters.js +168 -0
  228. package/dist/shared/converters.js.map +1 -0
  229. package/dist/shared/query-types.d.ts +95 -0
  230. package/dist/shared/query-types.d.ts.map +1 -0
  231. package/dist/shared/query-types.js +9 -0
  232. package/dist/shared/query-types.js.map +1 -0
  233. package/dist/testing.d.ts +125 -37
  234. package/dist/testing.d.ts.map +1 -1
  235. package/dist/testing.js +134 -42
  236. package/dist/testing.js.map +1 -1
  237. package/dist/user-module.d.ts +86 -0
  238. package/dist/user-module.d.ts.map +1 -0
  239. package/dist/user-module.js +55 -0
  240. package/dist/user-module.js.map +1 -0
  241. package/package.json +10 -6
  242. package/dist/lib/conjure.d.ts.map +0 -1
  243. package/dist/lib/conjure.js.map +0 -1
  244. package/dist/lib/hex.d.ts +0 -119
  245. package/dist/lib/hex.d.ts.map +0 -1
  246. package/dist/lib/hex.js +0 -188
  247. package/dist/lib/hex.js.map +0 -1
  248. package/dist/plugins/effect.d.ts +0 -53
  249. package/dist/plugins/effect.d.ts.map +0 -1
  250. package/dist/plugins/effect.js +0 -1074
  251. package/dist/plugins/effect.js.map +0 -1
  252. package/dist/plugins/kysely/queries.d.ts +0 -92
  253. package/dist/plugins/kysely/queries.d.ts.map +0 -1
  254. package/dist/plugins/kysely/queries.js +0 -1169
  255. package/dist/plugins/kysely/queries.js.map +0 -1
  256. package/dist/plugins/kysely/shared.d.ts +0 -59
  257. package/dist/plugins/kysely/shared.d.ts.map +0 -1
  258. package/dist/plugins/kysely/shared.js +0 -247
  259. package/dist/plugins/kysely/shared.js.map +0 -1
  260. package/dist/plugins/kysely/types.d.ts +0 -22
  261. package/dist/plugins/kysely/types.d.ts.map +0 -1
  262. package/dist/plugins/kysely/types.js +0 -428
  263. package/dist/plugins/kysely/types.js.map +0 -1
  264. package/dist/services/artifact-store.d.ts +0 -65
  265. package/dist/services/artifact-store.d.ts.map +0 -1
  266. package/dist/services/artifact-store.js +0 -57
  267. package/dist/services/artifact-store.js.map +0 -1
  268. package/dist/services/core-providers.d.ts +0 -15
  269. package/dist/services/core-providers.d.ts.map +0 -1
  270. package/dist/services/core-providers.js +0 -23
  271. package/dist/services/core-providers.js.map +0 -1
  272. package/dist/services/emissions.d.ts +0 -103
  273. package/dist/services/emissions.d.ts.map +0 -1
  274. package/dist/services/emissions.js +0 -241
  275. package/dist/services/emissions.js.map +0 -1
  276. package/dist/services/execution.d.ts +0 -35
  277. package/dist/services/execution.d.ts.map +0 -1
  278. package/dist/services/execution.js +0 -86
  279. package/dist/services/execution.js.map +0 -1
  280. package/dist/services/file-builder.d.ts +0 -85
  281. package/dist/services/file-builder.d.ts.map +0 -1
  282. package/dist/services/file-builder.js +0 -112
  283. package/dist/services/file-builder.js.map +0 -1
  284. package/dist/services/plugin-meta.d.ts +0 -33
  285. package/dist/services/plugin-meta.d.ts.map +0 -1
  286. package/dist/services/plugin-meta.js +0 -24
  287. package/dist/services/plugin-meta.js.map +0 -1
  288. package/dist/services/plugin-runner.d.ts +0 -42
  289. package/dist/services/plugin-runner.d.ts.map +0 -1
  290. package/dist/services/plugin-runner.js +0 -84
  291. package/dist/services/plugin-runner.js.map +0 -1
  292. package/dist/services/plugin.d.ts +0 -421
  293. package/dist/services/plugin.d.ts.map +0 -1
  294. package/dist/services/plugin.js +0 -197
  295. package/dist/services/plugin.js.map +0 -1
  296. package/dist/services/resolution.d.ts +0 -38
  297. package/dist/services/resolution.d.ts.map +0 -1
  298. package/dist/services/resolution.js +0 -242
  299. package/dist/services/resolution.js.map +0 -1
  300. package/dist/services/service-registry.d.ts +0 -74
  301. package/dist/services/service-registry.d.ts.map +0 -1
  302. package/dist/services/service-registry.js +0 -61
  303. package/dist/services/service-registry.js.map +0 -1
  304. package/dist/services/symbols.d.ts +0 -144
  305. package/dist/services/symbols.d.ts.map +0 -1
  306. package/dist/services/symbols.js +0 -144
  307. package/dist/services/symbols.js.map +0 -1
@@ -1,422 +1,498 @@
1
1
  /**
2
- * ArkType Plugin - Generate ArkType schemas for entities
2
+ * ArkType Plugin - Generates ArkType schemas for entities
3
3
  *
4
- * Generates ArkType type definitions for Row, Insert, Update, and Patch shapes,
5
- * with inferred TypeScript types.
4
+ * Generates ArkType schemas for Row, Insert, Update, and Patch shapes,
5
+ * with optional inferred TypeScript types.
6
6
  *
7
- * ArkType uses string-based syntax for type definitions:
8
- * - `type({ foo: "string", bar: "number?" })` for objects
9
- * - `"string | null"` for nullable
10
- * - `"string[]"` for arrays
11
- * - Union syntax `"'a' | 'b' | 'c'"` for enums
7
+ * Capabilities provided:
8
+ * - `schema:arktype:EntityName` for each table entity (Row schema)
9
+ * - `schema:arktype:EntityName:insert` for Insert shape
10
+ * - `schema:arktype:EntityName:update` for Update shape
11
+ * - `schema:arktype:EnumName` for enum entities
12
12
  */
13
- import { Array as Arr, Option, pipe, Schema as S } from "effect";
14
- import { definePlugin } from "../services/plugin.js";
15
- import { findEnumByPgName, TsType } from "../services/pg-types.js";
16
- import { getTableEntities, getEnumEntities, getCompositeEntities } from "../ir/semantic-ir.js";
17
- import { conjure } from "../lib/conjure.js";
18
- import { isUuidType, isDateType, isEnumType, getPgTypeName, resolveFieldType, } from "../lib/field-utils.js";
19
- import { SCHEMA_BUILDER_KIND, } from "../ir/extensions/schema-builder.js";
20
- const { ts, exp, obj } = conjure;
21
- const ArkTypeConfigSchema = S.Struct({
22
- outputDir: S.optionalWith(S.String, { default: () => "arktype" }),
23
- exportTypes: S.optionalWith(S.Boolean, { default: () => true }),
24
- enumStyle: S.optionalWith(S.Union(S.Literal("strings"), S.Literal("enum")), {
25
- default: () => "strings",
26
- }),
27
- typeReferences: S.optionalWith(S.Union(S.Literal("inline"), S.Literal("separate")), {
28
- default: () => "separate",
29
- }),
30
- });
31
- // ============================================================================
32
- // ArkType Schema Builders (pure functions)
33
- // ============================================================================
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";
34
19
  /**
35
- * Build ArkType string-based type expression.
20
+ * Creates a consume callback for ArkType schemas.
21
+ * Generates: `SchemaName.assert(input)` (throws on validation error)
36
22
  *
37
- * ArkType uses string syntax for most types:
38
- * - `"string"`, `"number"`, `"boolean"`, `"bigint"`
39
- * - `"Date"` for Date objects
40
- * - `"string?"` for optional
41
- * - `"string | null"` for nullable
42
- * - `"string[]"` for arrays
43
- */
44
- const buildArkTypeString = (baseType, modifiers) => {
45
- let result = baseType;
46
- // Apply array first (before nullable/optional)
47
- if (modifiers.isArray) {
48
- result = `${result}[]`;
49
- }
50
- // For nullable, use union with null
51
- if (modifiers.nullable) {
52
- result = `${result} | null`;
53
- }
54
- // Optional uses ? suffix in object keys, not in the type string itself
55
- // We handle this at the property level
56
- return result;
57
- };
58
- /**
59
- * Build ArkType enum as union of string literals: `"'a' | 'b' | 'c'"`
23
+ * @param schemaName - The name of the ArkType schema
24
+ * @returns A function that generates assert AST for an input expression
60
25
  */
61
- const buildArkTypeEnumString = (values) => values.map(v => `'${v}'`).join(" | ");
26
+ function createArkTypeConsumeCallback(schemaName) {
27
+ return (input) => {
28
+ return conjure.id(schemaName).method("assert", [cast.toExpr(input)]).build();
29
+ };
30
+ }
62
31
  /**
63
- * Map TypeScript type to ArkType string type
32
+ * Convert a param type to an ArkType type string.
64
33
  */
65
- const tsTypeToArkTypeString = (tsType) => {
66
- switch (tsType) {
67
- case TsType.String:
68
- return "string";
69
- case TsType.Number:
70
- return "number";
71
- case TsType.Boolean:
72
- return "boolean";
73
- case TsType.BigInt:
74
- return "bigint";
75
- case TsType.Date:
76
- return "Date";
77
- case TsType.Buffer:
78
- case TsType.Unknown:
34
+ function paramToArkTypeString(param) {
35
+ const baseType = param.type.replace(/\[\]$/, "").replace(/\?$/, "").toLowerCase();
36
+ let arkType;
37
+ switch (baseType) {
38
+ case "number":
39
+ case "int":
40
+ case "integer":
41
+ case "float":
42
+ case "double":
43
+ arkType = "number";
44
+ break;
45
+ case "boolean":
46
+ case "bool":
47
+ arkType = "boolean";
48
+ break;
49
+ case "date":
50
+ arkType = "Date";
51
+ break;
52
+ case "string":
79
53
  default:
80
- return "unknown";
54
+ arkType = "string";
55
+ break;
81
56
  }
82
- };
83
- const resolveFieldArkType = (field, ctx) => {
84
- const resolved = resolveFieldType(field, ctx.enums, ctx.extensions);
85
- // Enum handling
86
- if (resolved.enumDef) {
87
- if (ctx.typeReferences === "separate") {
88
- // Reference by name - will be imported
89
- const baseRef = resolved.enumDef.name;
90
- const withMods = buildArkTypeString(baseRef, {
91
- nullable: field.nullable,
92
- isArray: field.isArray,
93
- });
94
- return { typeString: withMods, isReference: true };
57
+ if (!param.required) {
58
+ arkType = `${arkType}?`;
59
+ }
60
+ return arkType;
61
+ }
62
+ /**
63
+ * ArkType SchemaBuilder implementation.
64
+ * Builds ArkType schemas for path/query parameters.
65
+ */
66
+ const arkTypeSchemaBuilder = {
67
+ build(request) {
68
+ if (request.params.length === 0) {
69
+ return undefined;
95
70
  }
96
- // Inline: union of string literals
97
- const baseType = buildArkTypeEnumString(resolved.enumDef.values);
98
- const needsParens = field.nullable || field.isArray;
99
- const wrapped = needsParens ? `(${baseType})` : baseType;
71
+ // Build type({ field: "string", ... })
72
+ const typeObj = {};
73
+ for (const param of request.params) {
74
+ typeObj[param.name] = paramToArkTypeString(param);
75
+ }
76
+ // Generate: type({ id: "number", email: "string" })
77
+ let objBuilder = conjure.obj();
78
+ for (const [name, arkType] of Object.entries(typeObj)) {
79
+ objBuilder = objBuilder.prop(name, conjure.str(arkType));
80
+ }
81
+ const ast = conjure.id("type").call([objBuilder.build()]).build();
100
82
  return {
101
- typeString: buildArkTypeString(wrapped, {
102
- nullable: field.nullable,
103
- isArray: field.isArray,
104
- }),
105
- isReference: false,
83
+ ast,
84
+ importSpec: { from: "arktype", names: ["type"] },
106
85
  };
86
+ },
87
+ };
88
+ const ArkTypeSchemaConfig = S.Struct({
89
+ exportTypes: S.optionalWith(S.Boolean, { default: () => true }),
90
+ });
91
+ function toExpr(node) {
92
+ return node;
93
+ }
94
+ // =============================================================================
95
+ // PostgreSQL Type to ArkType String 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 fieldToArkType(field, enums) {
125
+ const pgType = field.pgAttribute.getType();
126
+ if (!pgType) {
127
+ return { kind: "string", typeString: "unknown" };
107
128
  }
108
- // UUID string.uuid
109
- if (isUuidType(field)) {
110
- return {
111
- typeString: buildArkTypeString("string.uuid", {
112
- nullable: field.nullable,
113
- isArray: field.isArray,
114
- }),
115
- isReference: false,
116
- };
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;
117
136
  }
118
- // Date/timestamp Date
119
- if (isDateType(field)) {
120
- return {
121
- typeString: buildArkTypeString("Date", {
122
- nullable: field.nullable,
123
- isArray: field.isArray,
124
- }),
125
- isReference: false,
126
- };
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 };
127
141
  }
128
- // Standard type mapping
129
- return {
130
- typeString: buildArkTypeString(tsTypeToArkTypeString(resolved.tsType), {
131
- nullable: field.nullable,
132
- isArray: field.isArray,
133
- }),
134
- isReference: false,
135
- };
136
- };
137
- // ============================================================================
138
- // Shape Statement Generation
139
- // ============================================================================
140
- /**
141
- * Build type({ ... }) expression from shape fields
142
- *
143
- * ArkType uses string keys for optionality: `"key?": "type"`
144
- */
145
- const buildShapeArkTypeObject = (shape, ctx) => {
146
- const objBuilder = shape.fields.reduce((builder, field) => {
147
- const result = resolveFieldArkType(field, ctx);
148
- const value = result.isReference
149
- ? conjure.id(result.typeString).build()
150
- : conjure.str(result.typeString);
151
- // Use "key?" syntax for optional fields - must use stringProp for valid JS
152
- if (field.optional) {
153
- return builder.stringProp(`${field.name}?`, value);
142
+ else {
143
+ typeName = pgType.typname;
144
+ typeInfo = pgType;
145
+ }
146
+ const baseResult = baseTypeToArkType(typeName, typeInfo, enums);
147
+ // For enum references, we can't easily add modifiers in string form,
148
+ // so we handle them specially in shapeToArkTypeObject
149
+ if (baseResult.kind === "enumRef") {
150
+ return baseResult;
151
+ }
152
+ let typeStr = baseResult.typeString;
153
+ if (field.isArray) {
154
+ typeStr = `${typeStr}[]`;
155
+ }
156
+ if (field.nullable) {
157
+ typeStr = `${typeStr} | null`;
158
+ }
159
+ if (field.optional) {
160
+ typeStr = `${typeStr}?`;
161
+ }
162
+ return { kind: "string", typeString: typeStr };
163
+ }
164
+ function baseTypeToArkType(typeName, pgType, enums) {
165
+ const normalized = typeName.toLowerCase();
166
+ if (PG_STRING_TYPES.has(normalized)) {
167
+ if (normalized === "uuid") {
168
+ return { kind: "string", typeString: "string.uuid" };
154
169
  }
155
- return builder.prop(field.name, value);
156
- }, obj());
157
- // Build: type({ ... })
158
- return conjure.id("type").call([objBuilder.build()]).build();
159
- };
160
- /**
161
- * Generate schema const + optional inferred type for a shape
162
- */
163
- const generateShapeStatements = (shape, entityName, shapeKind, ctx, exportTypes) => {
164
- const schemaSymbolCtx = { capability: "schemas", entity: entityName, shape: shapeKind };
165
- const schemaExpr = buildShapeArkTypeObject(shape, ctx);
166
- const schemaStatement = exp.const(shape.name, schemaSymbolCtx, schemaExpr);
167
- if (!exportTypes) {
168
- return [schemaStatement];
170
+ // citext is case-insensitive text, but ArkType doesn't have a specific validator
171
+ // Just treat it as a regular string
172
+ return { kind: "string", typeString: "string" };
169
173
  }
170
- // Generate: export type ShapeName = typeof ShapeName.infer
171
- // ArkType uses Schema.infer for the inferred type
172
- const typeSymbolCtx = { capability: "types", entity: entityName, shape: shapeKind };
173
- const inferType = ts.typeof(`${shape.name}.infer`);
174
- const typeStatement = exp.type(shape.name, typeSymbolCtx, inferType);
175
- return [schemaStatement, typeStatement];
176
- };
177
- /**
178
- * Collect all defined shapes from an entity as [kind, shape] pairs
179
- */
180
- const collectShapes = (entity) => [
181
- ["row", entity.shapes.row],
182
- ["insert", entity.shapes.insert],
183
- ["update", entity.shapes.update],
184
- ].filter((entry) => entry[1] != null);
185
- /**
186
- * Generate all statements for an entity's shapes
187
- */
188
- const generateEntityStatements = (entity, ctx, exportTypes) => collectShapes(entity).flatMap(([kind, shape]) => generateShapeStatements(shape, entity.name, kind, ctx, exportTypes));
189
- // ============================================================================
190
- // Composite Type Generation
191
- // ============================================================================
192
- /**
193
- * Build type({ ... }) expression from composite fields
194
- */
195
- const buildCompositeArkTypeObject = (composite, ctx) => {
196
- const objBuilder = composite.fields.reduce((builder, field) => {
197
- const result = resolveFieldArkType(field, ctx);
198
- const value = result.isReference
199
- ? conjure.id(result.typeString).build()
200
- : conjure.str(result.typeString);
201
- // Use "key?" syntax for optional fields
202
- if (field.optional) {
203
- return builder.stringProp(`${field.name}?`, value);
174
+ if (PG_NUMBER_TYPES.has(normalized)) {
175
+ return { kind: "string", typeString: "number" };
176
+ }
177
+ if (PG_BOOLEAN_TYPES.has(normalized)) {
178
+ return { kind: "string", typeString: "boolean" };
179
+ }
180
+ if (PG_DATE_TYPES.has(normalized)) {
181
+ return { kind: "string", typeString: "Date" };
182
+ }
183
+ if (PG_JSON_TYPES.has(normalized)) {
184
+ return { kind: "string", typeString: "unknown" };
185
+ }
186
+ if (pgType.typtype === "e" || pgType.typcategory === "E") {
187
+ const enumEntity = enums.find(e => e.pgType.typname === typeName);
188
+ if (enumEntity) {
189
+ // Return reference to the enum schema instead of inlining
190
+ return { kind: "enumRef", enumRef: enumEntity.name };
204
191
  }
205
- return builder.prop(field.name, value);
206
- }, obj());
207
- return conjure.id("type").call([objBuilder.build()]).build();
208
- };
209
- /**
210
- * Generate schema const + optional inferred type for a composite type
211
- */
212
- const generateCompositeStatements = (composite, ctx, exportTypes) => {
213
- const schemaSymbolCtx = { capability: "schemas", entity: composite.name };
214
- const schemaExpr = buildCompositeArkTypeObject(composite, ctx);
215
- const schemaStatement = exp.const(composite.name, schemaSymbolCtx, schemaExpr);
216
- if (!exportTypes) {
217
- return [schemaStatement];
192
+ return { kind: "string", typeString: "unknown" };
218
193
  }
219
- // Generate: export type CompositeName = typeof CompositeName.infer
220
- const typeSymbolCtx = { capability: "types", entity: composite.name };
221
- const inferType = ts.typeof(`${composite.name}.infer`);
222
- const typeStatement = exp.type(composite.name, typeSymbolCtx, inferType);
223
- return [schemaStatement, typeStatement];
224
- };
225
- // ============================================================================
226
- // Enum Generation
227
- // ============================================================================
194
+ return { kind: "string", typeString: "unknown" };
195
+ }
196
+ // =============================================================================
197
+ // Shape to ArkType Object
198
+ // =============================================================================
199
+ function shapeToArkTypeObject(shape, enums, registry) {
200
+ let objBuilder = conjure.obj();
201
+ for (const field of shape.fields) {
202
+ const mapping = fieldToArkType(field, enums);
203
+ if (mapping.kind === "enumRef") {
204
+ // Get handle and track cross-reference
205
+ const enumHandle = registry.import(`schema:arktype:${mapping.enumRef}`);
206
+ let enumExpr = enumHandle.ref();
207
+ if (field.isArray) {
208
+ enumExpr = conjure.chain(enumExpr).method("array").build();
209
+ }
210
+ if (field.nullable) {
211
+ enumExpr = conjure.chain(enumExpr).method("or", [conjure.id("type").call([conjure.str("null")]).build()]).build();
212
+ }
213
+ // Note: ArkType doesn't have a direct .optional() method like Zod
214
+ // Optional is typically handled at the object level with "key?" syntax
215
+ // For now, we'll treat optional enum fields the same as required
216
+ // This is a limitation - may need scope() for full support
217
+ objBuilder = objBuilder.prop(field.name, enumExpr);
218
+ }
219
+ else {
220
+ objBuilder = objBuilder.prop(field.name, conjure.str(mapping.typeString));
221
+ }
222
+ }
223
+ return conjure.id("type").call([objBuilder.build()]).build();
224
+ }
228
225
  /**
229
- * Generate enum type for ArkType.
230
- * - For 'strings': export const EnumName = type("'a' | 'b' | 'c'")
231
- * - For 'enum': export enum EnumName { ... } + const EnumNameType = type("keyof", typeof EnumName)
226
+ * Build an UpdateInput schema: PK fields required, non-PK update fields optional.
227
+ * This is used for update operations where we need to identify the row (PK) and
228
+ * specify which fields to change (non-PK).
232
229
  */
233
- const generateEnumStatement = (enumEntity, enumStyle, exportTypes) => {
234
- const schemaSymbolCtx = { capability: "schemas", entity: enumEntity.name };
235
- if (enumStyle === "enum") {
236
- // Generate: export enum EnumName { A = 'a', B = 'b', ... }
237
- const enumStatement = exp.tsEnum(enumEntity.name, { capability: "types", entity: enumEntity.name }, enumEntity.values);
238
- // For arktype with native enums: type("keyof", typeof EnumName)
239
- const schemaName = `${enumEntity.name}Type`;
240
- const typeofExpr = conjure.b.unaryExpression("typeof", conjure.id(enumEntity.name).build(), true);
241
- const schemaExpr = conjure
242
- .id("type")
243
- .call([conjure.str("keyof"), typeofExpr])
244
- .build();
245
- const schemaStatement = exp.const(schemaName, schemaSymbolCtx, schemaExpr);
246
- return [enumStatement, schemaStatement];
230
+ function buildUpdateInputSchema(entity, enums, registry) {
231
+ const updateShape = entity.shapes.update;
232
+ const primaryKey = entity.primaryKey;
233
+ if (!updateShape || !primaryKey) {
234
+ return null;
247
235
  }
248
- // strings style: export const EnumName = type("'a' | 'b' | 'c'")
249
- const enumString = buildArkTypeEnumString(enumEntity.values);
250
- const schemaExpr = conjure
251
- .id("type")
252
- .call([conjure.str(enumString)])
253
- .build();
254
- const schemaStatement = exp.const(enumEntity.name, schemaSymbolCtx, schemaExpr);
255
- if (!exportTypes) {
256
- return [schemaStatement];
236
+ const pkColumnSet = new Set(primaryKey.columns);
237
+ let objBuilder = conjure.obj();
238
+ // First, add PK fields as REQUIRED (from row shape to get correct types)
239
+ for (const pkColName of primaryKey.columns) {
240
+ // Find the field in the row shape (PK fields always exist in row)
241
+ const pkField = entity.shapes.row.fields.find(f => f.name === pkColName);
242
+ if (!pkField)
243
+ continue;
244
+ // Get the base type without optional/nullable modifiers for PK
245
+ const mapping = fieldToArkType({ ...pkField, optional: false, nullable: false }, enums);
246
+ if (mapping.kind === "enumRef") {
247
+ const enumHandle = registry.import(`schema:arktype:${mapping.enumRef}`);
248
+ objBuilder = objBuilder.prop(pkField.name, enumHandle.ref());
249
+ }
250
+ else {
251
+ objBuilder = objBuilder.prop(pkField.name, conjure.str(mapping.typeString));
252
+ }
257
253
  }
258
- // Generate: export type EnumName = typeof EnumName.infer
259
- const typeSymbolCtx = { capability: "types", entity: enumEntity.name };
260
- const inferType = ts.typeof(`${enumEntity.name}.infer`);
261
- const typeStatement = exp.type(enumEntity.name, typeSymbolCtx, inferType);
262
- return [schemaStatement, typeStatement];
263
- };
264
- /** Collect enum names used by fields */
265
- const collectUsedEnums = (fields, enums) => {
266
- const enumNames = fields.filter(isEnumType).flatMap(field => {
267
- const pgTypeName = getPgTypeName(field);
268
- if (!pgTypeName)
269
- return [];
270
- return pipe(findEnumByPgName(enums, pgTypeName), Option.map(e => e.name), Option.toArray);
271
- });
272
- return new Set(enumNames);
273
- };
274
- /** Build import refs for used enums */
275
- const buildEnumImports = (usedEnums) => Arr.fromIterable(usedEnums).map(enumName => ({
276
- kind: "symbol",
277
- ref: { capability: "schemas", entity: enumName },
278
- }));
279
- // ============================================================================
280
- // Schema Builder Service
281
- // ============================================================================
282
- /**
283
- * Map TypeScript type string to ArkType string for params.
284
- * URL params are strings, so we use string.integer for numbers (coerces).
285
- */
286
- const paramTypeToArkTypeString = (tsType) => {
287
- switch (tsType.toLowerCase()) {
288
- case "number":
289
- // string.integer parses string to integer
290
- return "string.integer.parse";
291
- case "boolean":
292
- return "string"; // ArkType doesn't have built-in boolean coercion from string
293
- case "bigint":
294
- return "string"; // Handle as string, parse manually
295
- case "string":
296
- default:
297
- return "string";
254
+ // Then add non-PK fields from update shape as OPTIONAL
255
+ for (const field of updateShape.fields) {
256
+ if (pkColumnSet.has(field.name)) {
257
+ continue; // Skip PK fields, already added above
258
+ }
259
+ // Force optional for non-PK fields (partial updates)
260
+ const mapping = fieldToArkType({ ...field, optional: true }, enums);
261
+ if (mapping.kind === "enumRef") {
262
+ const enumHandle = registry.import(`schema:arktype:${mapping.enumRef}`);
263
+ let enumExpr = enumHandle.ref();
264
+ if (field.isArray) {
265
+ enumExpr = conjure.chain(enumExpr).method("array").build();
266
+ }
267
+ if (field.nullable) {
268
+ enumExpr = conjure.chain(enumExpr).method("or", [conjure.id("type").call([conjure.str("null")]).build()]).build();
269
+ }
270
+ // For optional enum fields, we need to use .optional() method
271
+ enumExpr = conjure.chain(enumExpr).method("optional").build();
272
+ objBuilder = objBuilder.prop(field.name, enumExpr);
273
+ }
274
+ else {
275
+ objBuilder = objBuilder.prop(field.name, conjure.str(mapping.typeString));
276
+ }
298
277
  }
299
- };
300
- /**
301
- * Build type({ ... }) expression from QueryMethodParam[].
302
- * For path/query parameter validation in HTTP handlers.
303
- */
304
- const buildParamArkTypeObject = (params) => {
305
- const objBuilder = params.reduce((builder, param) => {
306
- const arkType = paramTypeToArkTypeString(param.type);
307
- // Use "key?" syntax for optional params
308
- const key = param.required ? param.name : `${param.name}?`;
309
- return builder.stringProp(key, conjure.str(arkType));
310
- }, obj());
311
278
  return conjure.id("type").call([objBuilder.build()]).build();
312
- };
279
+ }
280
+ // =============================================================================
281
+ // ArkType Plugin Definition
282
+ // =============================================================================
313
283
  /**
314
- * Create a SchemaBuilder implementation for ArkType.
284
+ * Get the UpdateInput schema name for an entity.
285
+ * Convention: EntityNameUpdateInput (e.g., CommentUpdateInput)
315
286
  */
316
- const createArkTypeSchemaBuilder = () => ({
317
- build: (request) => {
318
- if (request.params.length === 0) {
319
- return undefined;
287
+ function getUpdateInputName(entity) {
288
+ return `${entity.name}UpdateInput`;
289
+ }
290
+ function getShapeDeclarations(entity) {
291
+ const declarations = [];
292
+ const baseEntityName = entity.name;
293
+ declarations.push({
294
+ name: entity.shapes.row.name,
295
+ capability: `schema:arktype:${entity.shapes.row.name}`,
296
+ baseEntityName,
297
+ });
298
+ if (entity.shapes.insert) {
299
+ const insertName = entity.shapes.insert.name;
300
+ declarations.push({
301
+ name: insertName,
302
+ capability: `schema:arktype:${insertName}`,
303
+ baseEntityName,
304
+ });
305
+ declarations.push({
306
+ name: insertName,
307
+ capability: `schema:arktype:${insertName}:type`,
308
+ baseEntityName,
309
+ });
310
+ }
311
+ if (entity.shapes.update) {
312
+ const updateName = entity.shapes.update.name;
313
+ declarations.push({
314
+ name: updateName,
315
+ capability: `schema:arktype:${updateName}`,
316
+ baseEntityName,
317
+ });
318
+ declarations.push({
319
+ name: updateName,
320
+ capability: `schema:arktype:${updateName}:type`,
321
+ baseEntityName,
322
+ });
323
+ // UpdateInput schema: required PK + optional non-PK fields
324
+ // Only declare if entity has both update shape AND primary key
325
+ if (entity.primaryKey) {
326
+ const updateInputName = getUpdateInputName(entity);
327
+ declarations.push({
328
+ name: updateInputName,
329
+ capability: `schema:arktype:${updateInputName}`,
330
+ baseEntityName,
331
+ });
332
+ declarations.push({
333
+ name: updateInputName,
334
+ capability: `schema:arktype:${updateInputName}:type`,
335
+ baseEntityName,
336
+ });
320
337
  }
321
- const ast = buildParamArkTypeObject(request.params);
322
- return {
323
- ast,
324
- importSpec: {
325
- names: ["type"],
326
- from: "arktype",
327
- },
328
- };
329
- },
330
- });
331
- // ============================================================================
332
- // Provider Definition
333
- // ============================================================================
334
- /**
335
- * Create an arktype provider that generates ArkType schemas.
336
- *
337
- * @example
338
- * ```typescript
339
- * import { arktype } from "pg-sourcerer"
340
- *
341
- * export default defineConfig({
342
- * plugins: [
343
- * arktype(),
344
- * arktype({ outputDir: "schemas", exportTypes: false }),
345
- * ],
346
- * })
347
- * ```
348
- */
349
- export function arktype(config = {}) {
350
- const parsed = S.decodeUnknownSync(ArkTypeConfigSchema)(config);
351
- return definePlugin({
338
+ }
339
+ return declarations;
340
+ }
341
+ export function arktype(config) {
342
+ const schemaConfig = S.decodeSync(ArkTypeSchemaConfig)(config ?? {});
343
+ const resolvedConfig = {
344
+ ...schemaConfig,
345
+ schemasFile: normalizeFileNaming(config?.schemasFile, "schemas.ts"),
346
+ };
347
+ return {
352
348
  name: "arktype",
353
- kind: "schemas",
354
- singleton: true,
355
- canProvide: () => true,
356
- provide: (_params, _deps, ctx) => {
357
- const { ir, inflection } = ctx;
358
- const enumEntities = getEnumEntities(ir);
359
- // Register schema-builder service for on-demand param/query schema generation
360
- ctx.registerHandler(SCHEMA_BUILDER_KIND, createArkTypeSchemaBuilder().build);
361
- const fieldCtx = {
362
- enums: enumEntities,
363
- extensions: ir.extensions,
364
- enumStyle: parsed.enumStyle,
365
- typeReferences: parsed.typeReferences,
366
- };
367
- // Helper to build file path
368
- const buildFilePath = (entityName) => `${parsed.outputDir}/${entityName}.ts`;
369
- // Generate separate enum files if configured
370
- if (parsed.typeReferences === "separate") {
371
- enumEntities
372
- .filter(e => e.tags.omit !== true)
373
- .forEach(enumEntity => {
374
- const statements = generateEnumStatement(enumEntity, parsed.enumStyle, parsed.exportTypes);
375
- ctx
376
- .file(buildFilePath(enumEntity.name))
377
- .import({ kind: "package", names: ["type"], from: "arktype" })
378
- .ast(conjure.symbolProgram(...statements))
379
- .emit();
380
- });
349
+ provides: ["schema"],
350
+ fileDefaults: [
351
+ {
352
+ pattern: "schema:",
353
+ fileNaming: resolvedConfig.schemasFile,
354
+ },
355
+ ],
356
+ declare: Effect.gen(function* () {
357
+ const ir = yield* IR;
358
+ const declarations = [];
359
+ for (const entity of ir.entities.values()) {
360
+ if (isTableEntity(entity)) {
361
+ declarations.push(...getShapeDeclarations(entity));
362
+ }
363
+ else if (isEnumEntity(entity)) {
364
+ declarations.push({
365
+ name: entity.name,
366
+ capability: `schema:arktype:${entity.name}`,
367
+ baseEntityName: entity.name,
368
+ });
369
+ declarations.push({
370
+ name: entity.name,
371
+ capability: `schema:arktype:${entity.name}:type`,
372
+ baseEntityName: entity.name,
373
+ });
374
+ }
381
375
  }
382
- getTableEntities(ir)
383
- .filter(entity => entity.tags.omit !== true)
384
- .forEach(entity => {
385
- const statements = generateEntityStatements(entity, fieldCtx, parsed.exportTypes);
386
- const entityName = inflection.entityName(entity.pgClass, entity.tags);
387
- // Collect all fields for enum detection
388
- const allFields = [
389
- ...entity.shapes.row.fields,
390
- ...(entity.shapes.insert?.fields ?? []),
391
- ...(entity.shapes.update?.fields ?? []),
392
- ];
393
- const usedEnums = parsed.typeReferences === "separate"
394
- ? collectUsedEnums(allFields, Arr.fromIterable(fieldCtx.enums))
395
- : new Set();
396
- const fileBuilder = ctx
397
- .file(buildFilePath(entityName))
398
- .import({ kind: "package", names: ["type"], from: "arktype" });
399
- // Add enum imports when using separate files
400
- buildEnumImports(usedEnums).forEach(ref => fileBuilder.import(ref));
401
- fileBuilder.ast(conjure.symbolProgram(...statements)).emit();
376
+ // Declare the schema builder capability
377
+ declarations.push({
378
+ name: "arkTypeSchemaBuilder",
379
+ capability: "schema:arktype:builder",
402
380
  });
403
- // Generate composite type schemas
404
- getCompositeEntities(ir)
405
- .filter(composite => composite.tags.omit !== true)
406
- .forEach(composite => {
407
- const statements = generateCompositeStatements(composite, fieldCtx, parsed.exportTypes);
408
- // Collect enum usage for imports
409
- const usedEnums = parsed.typeReferences === "separate"
410
- ? collectUsedEnums(composite.fields, Arr.fromIterable(fieldCtx.enums))
411
- : new Set();
412
- const fileBuilder = ctx
413
- .file(buildFilePath(composite.name))
414
- .import({ kind: "package", names: ["type"], from: "arktype" });
415
- buildEnumImports(usedEnums).forEach(ref => fileBuilder.import(ref));
416
- fileBuilder.ast(conjure.symbolProgram(...statements)).emit();
381
+ return declarations;
382
+ }),
383
+ render: Effect.gen(function* () {
384
+ const ir = yield* IR;
385
+ const registry = yield* SymbolRegistry;
386
+ const enums = [...ir.entities.values()].filter(isEnumEntity);
387
+ const rendered = [];
388
+ for (const entity of ir.entities.values()) {
389
+ if (isTableEntity(entity)) {
390
+ const shapes = [
391
+ entity.shapes.row,
392
+ ];
393
+ if (entity.shapes.insert)
394
+ shapes.push(entity.shapes.insert);
395
+ if (entity.shapes.update)
396
+ shapes.push(entity.shapes.update);
397
+ for (const shape of shapes) {
398
+ const isRow = shape.kind === "row";
399
+ const capability = `schema:arktype:${shape.name}`;
400
+ // Scope cross-references to this specific capability
401
+ const schemaNode = registry.forSymbol(capability, () => shapeToArkTypeObject(shape, enums, registry));
402
+ const schemaDecl = conjure.export.const(shape.name, schemaNode);
403
+ rendered.push({
404
+ name: shape.name,
405
+ capability,
406
+ node: schemaDecl,
407
+ exports: "named",
408
+ externalImports: [{ from: "arktype", names: ["type"] }],
409
+ metadata: {
410
+ consume: createArkTypeConsumeCallback(shape.name),
411
+ },
412
+ });
413
+ if (resolvedConfig.exportTypes && !isRow) {
414
+ const inferType = conjure.ts.typeof(`${shape.name}.infer`);
415
+ const typeDecl = conjure.export.type(shape.name, inferType);
416
+ rendered.push({
417
+ name: shape.name,
418
+ capability: `schema:arktype:${shape.name}:type`,
419
+ node: typeDecl,
420
+ exports: "named",
421
+ externalImports: [{ from: "arktype", names: ["type"] }],
422
+ });
423
+ }
424
+ }
425
+ // Render UpdateInput schema if entity has update shape AND primary key
426
+ if (entity.shapes.update && entity.primaryKey) {
427
+ const updateInputName = getUpdateInputName(entity);
428
+ const capability = `schema:arktype:${updateInputName}`;
429
+ const schemaNode = registry.forSymbol(capability, () => buildUpdateInputSchema(entity, enums, registry));
430
+ if (schemaNode) {
431
+ const schemaDecl = conjure.export.const(updateInputName, schemaNode);
432
+ rendered.push({
433
+ name: updateInputName,
434
+ capability,
435
+ node: schemaDecl,
436
+ exports: "named",
437
+ externalImports: [{ from: "arktype", names: ["type"] }],
438
+ metadata: {
439
+ consume: createArkTypeConsumeCallback(updateInputName),
440
+ },
441
+ });
442
+ if (resolvedConfig.exportTypes) {
443
+ const inferType = conjure.ts.typeof(`${updateInputName}.infer`);
444
+ const typeDecl = conjure.export.type(updateInputName, inferType);
445
+ rendered.push({
446
+ name: updateInputName,
447
+ capability: `schema:arktype:${updateInputName}:type`,
448
+ node: typeDecl,
449
+ exports: "named",
450
+ externalImports: [{ from: "arktype", names: ["type"] }],
451
+ });
452
+ }
453
+ }
454
+ }
455
+ }
456
+ else if (isEnumEntity(entity)) {
457
+ const enumString = entity.values.map(v => `'${v}'`).join(" | ");
458
+ const schemaNode = conjure.id("type").call([conjure.str(enumString)]).build();
459
+ const schemaDecl = conjure.export.const(entity.name, schemaNode);
460
+ const inferType = conjure.ts.typeof(`${entity.name}.infer`);
461
+ const typeDecl = conjure.export.type(entity.name, inferType);
462
+ rendered.push({
463
+ name: entity.name,
464
+ capability: `schema:arktype:${entity.name}`,
465
+ node: schemaDecl,
466
+ exports: "named",
467
+ externalImports: [{ from: "arktype", names: ["type"] }],
468
+ metadata: {
469
+ consume: createArkTypeConsumeCallback(entity.name),
470
+ },
471
+ });
472
+ if (resolvedConfig.exportTypes) {
473
+ rendered.push({
474
+ name: entity.name,
475
+ capability: `schema:arktype:${entity.name}:type`,
476
+ node: typeDecl,
477
+ exports: "named",
478
+ externalImports: [{ from: "arktype", names: ["type"] }],
479
+ });
480
+ }
481
+ }
482
+ }
483
+ // Render the schema builder (virtual symbol - no node, just metadata)
484
+ // The builder is used by HTTP plugins to generate inline param schemas
485
+ rendered.push({
486
+ name: "arkTypeSchemaBuilder",
487
+ capability: "schema:arktype:builder",
488
+ node: null, // Virtual symbol - no emitted code
489
+ exports: false, // Not exported
490
+ metadata: {
491
+ builder: arkTypeSchemaBuilder,
492
+ },
417
493
  });
418
- return undefined;
419
- },
420
- });
494
+ return rendered;
495
+ }),
496
+ };
421
497
  }
422
498
  //# sourceMappingURL=arktype.js.map