sizuku 0.3.1 → 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 (204) hide show
  1. package/README.md +104 -1
  2. package/dist/config/index.d.mts +58 -0
  3. package/dist/config/index.mjs +95 -0
  4. package/dist/index.d.mts +10 -0
  5. package/dist/index.mjs +1615 -0
  6. package/package.json +31 -17
  7. package/dist/cli/main.d.ts +0 -10
  8. package/dist/cli/main.js +0 -61
  9. package/dist/cli.d.ts +0 -2
  10. package/dist/cli.js +0 -51
  11. package/dist/config/index.d.ts +0 -27
  12. package/dist/config/index.js +0 -85
  13. package/dist/config/loader.d.ts +0 -19
  14. package/dist/config/loader.js +0 -30
  15. package/dist/generator/engine.d.ts +0 -3
  16. package/dist/generator/engine.js +0 -63
  17. package/dist/generator/mermaid-er/config/index.d.ts +0 -10
  18. package/dist/generator/mermaid-er/config/index.js +0 -12
  19. package/dist/generator/mermaid-er/core/extract-relations.d.ts +0 -8
  20. package/dist/generator/mermaid-er/core/extract-relations.js +0 -17
  21. package/dist/generator/mermaid-er/core.d.ts +0 -6
  22. package/dist/generator/mermaid-er/core.js +0 -54
  23. package/dist/generator/mermaid-er/generator/er-content.d.ts +0 -20
  24. package/dist/generator/mermaid-er/generator/er-content.js +0 -23
  25. package/dist/generator/mermaid-er/generator/index.d.ts +0 -2
  26. package/dist/generator/mermaid-er/generator/index.js +0 -2
  27. package/dist/generator/mermaid-er/generator/relation-line.d.ts +0 -12
  28. package/dist/generator/mermaid-er/generator/relation-line.js +0 -13
  29. package/dist/generator/mermaid-er/generator.d.ts +0 -3
  30. package/dist/generator/mermaid-er/generator.js +0 -14
  31. package/dist/generator/mermaid-er/index.d.ts +0 -12
  32. package/dist/generator/mermaid-er/index.js +0 -33
  33. package/dist/generator/mermaid-er/relationship/build-relation-line.d.ts +0 -14
  34. package/dist/generator/mermaid-er/relationship/build-relation-line.js +0 -34
  35. package/dist/generator/mermaid-er/types.d.ts +0 -21
  36. package/dist/generator/mermaid-er/types.js +0 -1
  37. package/dist/generator/mermaid-er/validator/index.d.ts +0 -8
  38. package/dist/generator/mermaid-er/validator/index.js +0 -74
  39. package/dist/generator/mermaid-er/validator/is-relationship.d.ts +0 -7
  40. package/dist/generator/mermaid-er/validator/is-relationship.js +0 -8
  41. package/dist/generator/mermaid-er/validator/parse-relation-line.d.ts +0 -12
  42. package/dist/generator/mermaid-er/validator/parse-relation-line.js +0 -20
  43. package/dist/generator/mermaid-er/validator/parse-table-info.d.ts +0 -2
  44. package/dist/generator/mermaid-er/validator/parse-table-info.js +0 -71
  45. package/dist/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +0 -7
  46. package/dist/generator/mermaid-er/validator/remove-duplicate-relations.js +0 -9
  47. package/dist/generator/valibot/config/index.d.ts +0 -7
  48. package/dist/generator/valibot/config/index.js +0 -13
  49. package/dist/generator/valibot/core/extract-schema.d.ts +0 -5
  50. package/dist/generator/valibot/core/extract-schema.js +0 -173
  51. package/dist/generator/valibot/core.d.ts +0 -5
  52. package/dist/generator/valibot/core.js +0 -39
  53. package/dist/generator/valibot/generator/infer-input.d.ts +0 -5
  54. package/dist/generator/valibot/generator/infer-input.js +0 -8
  55. package/dist/generator/valibot/generator/relation-valibot-code.d.ts +0 -13
  56. package/dist/generator/valibot/generator/relation-valibot-code.js +0 -19
  57. package/dist/generator/valibot/generator/valibot-code.d.ts +0 -15
  58. package/dist/generator/valibot/generator/valibot-code.js +0 -16
  59. package/dist/generator/valibot/generator/valibot.d.ts +0 -14
  60. package/dist/generator/valibot/generator/valibot.js +0 -15
  61. package/dist/generator/valibot/generator.d.ts +0 -3
  62. package/dist/generator/valibot/generator.js +0 -14
  63. package/dist/generator/valibot/index.d.ts +0 -14
  64. package/dist/generator/valibot/index.js +0 -50
  65. package/dist/generator/zod/config/index.d.ts +0 -8
  66. package/dist/generator/zod/config/index.js +0 -14
  67. package/dist/generator/zod/core/extract-schema.d.ts +0 -7
  68. package/dist/generator/zod/core/extract-schema.js +0 -243
  69. package/dist/generator/zod/core.d.ts +0 -5
  70. package/dist/generator/zod/core.js +0 -39
  71. package/dist/generator/zod/generator/infer.d.ts +0 -5
  72. package/dist/generator/zod/generator/infer.js +0 -8
  73. package/dist/generator/zod/generator/relation-zod-code.d.ts +0 -13
  74. package/dist/generator/zod/generator/relation-zod-code.js +0 -19
  75. package/dist/generator/zod/generator/zod-code.d.ts +0 -17
  76. package/dist/generator/zod/generator/zod-code.js +0 -18
  77. package/dist/generator/zod/generator/zod.d.ts +0 -16
  78. package/dist/generator/zod/generator/zod.js +0 -16
  79. package/dist/generator/zod/generator.d.ts +0 -3
  80. package/dist/generator/zod/generator.js +0 -14
  81. package/dist/generator/zod/index.d.ts +0 -15
  82. package/dist/generator/zod/index.js +0 -54
  83. package/dist/index.d.ts +0 -7
  84. package/dist/index.js +0 -73
  85. package/dist/shared/config/index.d.ts +0 -13
  86. package/dist/shared/config/index.js +0 -10
  87. package/dist/shared/format/index.d.ts +0 -13
  88. package/dist/shared/format/index.js +0 -24
  89. package/dist/shared/fs/index.d.ts +0 -7
  90. package/dist/shared/fs/index.js +0 -16
  91. package/dist/shared/fsp/index.d.ts +0 -27
  92. package/dist/shared/fsp/index.js +0 -38
  93. package/dist/shared/generator/field-definitions.d.ts +0 -12
  94. package/dist/shared/generator/field-definitions.js +0 -12
  95. package/dist/shared/helper/ast-parser.d.ts +0 -3
  96. package/dist/shared/helper/ast-parser.js +0 -202
  97. package/dist/shared/helper/build-schema-extractor.d.ts +0 -25
  98. package/dist/shared/helper/build-schema-extractor.js +0 -33
  99. package/dist/shared/helper/create-extract-field-from-property.d.ts +0 -15
  100. package/dist/shared/helper/create-extract-field-from-property.js +0 -20
  101. package/dist/shared/helper/create-extract-fields-from-call-expression.d.ts +0 -14
  102. package/dist/shared/helper/create-extract-fields-from-call-expression.js +0 -14
  103. package/dist/shared/helper/create-extract-relation-field-from-property.d.ts +0 -12
  104. package/dist/shared/helper/create-extract-relation-field-from-property.js +0 -27
  105. package/dist/shared/helper/extract-schemas.d.ts +0 -133
  106. package/dist/shared/helper/extract-schemas.js +0 -445
  107. package/dist/shared/helper/file-writer.d.ts +0 -3
  108. package/dist/shared/helper/file-writer.js +0 -25
  109. package/dist/shared/helper/find-object-literal-expression.d.ts +0 -12
  110. package/dist/shared/helper/find-object-literal-expression.js +0 -31
  111. package/dist/shared/helper/find-object-literalIn-args.d.ts +0 -2
  112. package/dist/shared/helper/find-object-literalIn-args.js +0 -8
  113. package/dist/shared/helper/is-relation-function.d.ts +0 -10
  114. package/dist/shared/helper/is-relation-function.js +0 -16
  115. package/dist/shared/types.d.ts +0 -9
  116. package/dist/shared/types.js +0 -1
  117. package/dist/shared/utils/capitalize.d.ts +0 -18
  118. package/dist/shared/utils/capitalize.js +0 -20
  119. package/dist/shared/utils/compose.d.ts +0 -101
  120. package/dist/shared/utils/compose.js +0 -124
  121. package/dist/shared/utils/file.d.ts +0 -92
  122. package/dist/shared/utils/file.js +0 -177
  123. package/dist/shared/utils/functional.d.ts +0 -118
  124. package/dist/shared/utils/functional.js +0 -96
  125. package/dist/shared/utils/index.d.ts +0 -20
  126. package/dist/shared/utils/index.js +0 -48
  127. package/dist/shared/utils/string-utils.d.ts +0 -8
  128. package/dist/shared/utils/string-utils.js +0 -28
  129. package/dist/shared/utils/types.d.ts +0 -32
  130. package/dist/shared/utils/types.js +0 -2
  131. package/dist/shared/utils/validation-utils.d.ts +0 -8
  132. package/dist/shared/utils/validation-utils.js +0 -25
  133. package/dist/src/config/index.d.ts +0 -18
  134. package/dist/src/config/index.js +0 -13
  135. package/dist/src/generator/mermaid-er/core/extract-relations.d.ts +0 -8
  136. package/dist/src/generator/mermaid-er/core/extract-relations.js +0 -12
  137. package/dist/src/generator/mermaid-er/generator/er-content.d.ts +0 -9
  138. package/dist/src/generator/mermaid-er/generator/er-content.js +0 -25
  139. package/dist/src/generator/mermaid-er/generator/index.d.ts +0 -2
  140. package/dist/src/generator/mermaid-er/generator/index.js +0 -2
  141. package/dist/src/generator/mermaid-er/generator/relation-line.d.ts +0 -8
  142. package/dist/src/generator/mermaid-er/generator/relation-line.js +0 -14
  143. package/dist/src/generator/mermaid-er/index.d.ts +0 -6
  144. package/dist/src/generator/mermaid-er/index.js +0 -16
  145. package/dist/src/generator/mermaid-er/relationship/build-relation-line.d.ts +0 -15
  146. package/dist/src/generator/mermaid-er/relationship/build-relation-line.js +0 -35
  147. package/dist/src/generator/mermaid-er/types.d.ts +0 -21
  148. package/dist/src/generator/mermaid-er/types.js +0 -1
  149. package/dist/src/generator/mermaid-er/validator/index.d.ts +0 -4
  150. package/dist/src/generator/mermaid-er/validator/index.js +0 -4
  151. package/dist/src/generator/mermaid-er/validator/is-relationship.d.ts +0 -8
  152. package/dist/src/generator/mermaid-er/validator/is-relationship.js +0 -9
  153. package/dist/src/generator/mermaid-er/validator/parse-relation-line.d.ts +0 -13
  154. package/dist/src/generator/mermaid-er/validator/parse-relation-line.js +0 -21
  155. package/dist/src/generator/mermaid-er/validator/parse-table-info.d.ts +0 -8
  156. package/dist/src/generator/mermaid-er/validator/parse-table-info.js +0 -91
  157. package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +0 -7
  158. package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.js +0 -9
  159. package/dist/src/generator/valibot/generator/infer-input.d.ts +0 -5
  160. package/dist/src/generator/valibot/generator/infer-input.js +0 -8
  161. package/dist/src/generator/valibot/generator/valibot-code.d.ts +0 -14
  162. package/dist/src/generator/valibot/generator/valibot-code.js +0 -16
  163. package/dist/src/generator/valibot/generator/valibot.d.ts +0 -13
  164. package/dist/src/generator/valibot/generator/valibot.js +0 -11
  165. package/dist/src/generator/valibot/index.d.ts +0 -9
  166. package/dist/src/generator/valibot/index.js +0 -34
  167. package/dist/src/generator/zod/generator/infer.d.ts +0 -5
  168. package/dist/src/generator/zod/generator/infer.js +0 -8
  169. package/dist/src/generator/zod/generator/zod-code.d.ts +0 -16
  170. package/dist/src/generator/zod/generator/zod-code.js +0 -18
  171. package/dist/src/generator/zod/generator/zod.d.ts +0 -15
  172. package/dist/src/generator/zod/generator/zod.js +0 -12
  173. package/dist/src/generator/zod/index.d.ts +0 -10
  174. package/dist/src/generator/zod/index.js +0 -40
  175. package/dist/src/index.d.ts +0 -10
  176. package/dist/src/index.js +0 -35
  177. package/dist/src/shared/format/index.d.ts +0 -2
  178. package/dist/src/shared/format/index.js +0 -10
  179. package/dist/src/shared/fs/index.d.ts +0 -2
  180. package/dist/src/shared/fs/index.js +0 -10
  181. package/dist/src/shared/fsp/index.d.ts +0 -3
  182. package/dist/src/shared/fsp/index.js +0 -8
  183. package/dist/src/shared/generator/field-definitions.d.ts +0 -12
  184. package/dist/src/shared/generator/field-definitions.js +0 -12
  185. package/dist/src/shared/helper/build-schema-extractor.d.ts +0 -25
  186. package/dist/src/shared/helper/build-schema-extractor.js +0 -33
  187. package/dist/src/shared/helper/create-extract-field-from-property.d.ts +0 -15
  188. package/dist/src/shared/helper/create-extract-field-from-property.js +0 -20
  189. package/dist/src/shared/helper/create-extract-fields-from-call-expression.d.ts +0 -14
  190. package/dist/src/shared/helper/create-extract-fields-from-call-expression.js +0 -14
  191. package/dist/src/shared/helper/create-extract-relation-field-from-property.d.ts +0 -12
  192. package/dist/src/shared/helper/create-extract-relation-field-from-property.js +0 -27
  193. package/dist/src/shared/helper/extract-schemas.d.ts +0 -16
  194. package/dist/src/shared/helper/extract-schemas.js +0 -19
  195. package/dist/src/shared/helper/find-object-literal-expression.d.ts +0 -12
  196. package/dist/src/shared/helper/find-object-literal-expression.js +0 -31
  197. package/dist/src/shared/helper/find-object-literalIn-args.d.ts +0 -2
  198. package/dist/src/shared/helper/find-object-literalIn-args.js +0 -8
  199. package/dist/src/shared/helper/is-relation-function.d.ts +0 -10
  200. package/dist/src/shared/helper/is-relation-function.js +0 -16
  201. package/dist/src/shared/utils/index.d.ts +0 -33
  202. package/dist/src/shared/utils/index.js +0 -61
  203. package/dist/utils/index.d.ts +0 -144
  204. package/dist/utils/index.js +0 -250
package/dist/index.mjs ADDED
@@ -0,0 +1,1615 @@
1
+ import { config } from "./config/index.mjs";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { format } from "prettier";
5
+ import fsp from "node:fs/promises";
6
+ import { Node, Project } from "ts-morph";
7
+ import { generateDBMLContent, makeCapitalized, makeCapitalized as makeCapitalized$1, makeCleanedCommentLines, makeValibotInfer, makeValibotObject, makeZodInfer, makeZodObject, mapDrizzleType } from "utils-lab";
8
+ import { Resvg } from "@resvg/resvg-js";
9
+ import { run } from "@softwaretechnik/dbml-renderer";
10
+
11
+ //#region src/shared/format/index.ts
12
+ /**
13
+ * Formats TypeScript source with Prettier.
14
+ *
15
+ * @param code - Source code to format.
16
+ * @returns A `Result` containing the formatted code or an error message.
17
+ */
18
+ async function fmt(code) {
19
+ try {
20
+ return {
21
+ ok: true,
22
+ value: await format(code, {
23
+ parser: "typescript",
24
+ printWidth: 100,
25
+ singleQuote: true,
26
+ semi: false
27
+ })
28
+ };
29
+ } catch (e) {
30
+ return {
31
+ ok: false,
32
+ error: e instanceof Error ? e.message : String(e)
33
+ };
34
+ }
35
+ }
36
+
37
+ //#endregion
38
+ //#region src/shared/fsp/index.ts
39
+ /**
40
+ * Creates a directory if it does not already exist.
41
+ *
42
+ * @param dir - Directory path to create.
43
+ * @returns A `Result` that is `ok` on success, otherwise an error message.
44
+ */
45
+ async function mkdir(dir) {
46
+ try {
47
+ await fsp.mkdir(dir, { recursive: true });
48
+ return {
49
+ ok: true,
50
+ value: void 0
51
+ };
52
+ } catch (e) {
53
+ return {
54
+ ok: false,
55
+ error: e instanceof Error ? e.message : String(e)
56
+ };
57
+ }
58
+ }
59
+ /**
60
+ * Writes UTF-8 text to a file, creating it if necessary.
61
+ *
62
+ * @param path - File path to write.
63
+ * @param data - Text data to write.
64
+ * @returns A `Result` that is `ok` on success, otherwise an error message.
65
+ */
66
+ async function writeFile(path, data) {
67
+ try {
68
+ await fsp.writeFile(path, data, "utf-8");
69
+ return {
70
+ ok: true,
71
+ value: void 0
72
+ };
73
+ } catch (e) {
74
+ return {
75
+ ok: false,
76
+ error: e instanceof Error ? e.message : String(e)
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * Writes binary data to a file, creating it if necessary.
82
+ *
83
+ * @param path - File path to write.
84
+ * @param data - Binary data to write.
85
+ * @returns A `Result` that is `ok` on success, otherwise an error message.
86
+ */
87
+ async function writeFileBinary(path, data) {
88
+ try {
89
+ await fsp.writeFile(path, data);
90
+ return {
91
+ ok: true,
92
+ value: void 0
93
+ };
94
+ } catch (e) {
95
+ return {
96
+ ok: false,
97
+ error: e instanceof Error ? e.message : String(e)
98
+ };
99
+ }
100
+ }
101
+
102
+ //#endregion
103
+ //#region src/utils/index.ts
104
+ /**
105
+ * Check if a string starts with a prefix.
106
+ *
107
+ * @param str - The input string.
108
+ * @param prefix - The prefix to check.
109
+ * @returns True if string starts with prefix.
110
+ */
111
+ function startsWith(str, prefix) {
112
+ return str.indexOf(prefix) === 0;
113
+ }
114
+ /**
115
+ * Trim whitespace from string.
116
+ *
117
+ * @param str - The input string.
118
+ * @returns Trimmed string.
119
+ */
120
+ function trimString(str) {
121
+ return str.trim();
122
+ }
123
+ /**
124
+ * Clean comment lines by removing triple slash prefix and trimming.
125
+ * Uses makeCleanedCommentLines from utils-lab.
126
+ *
127
+ * @param commentLines - Raw comment lines
128
+ * @returns Cleaned comment lines
129
+ */
130
+ function cleanCommentLines(commentLines) {
131
+ return makeCleanedCommentLines(commentLines);
132
+ }
133
+ /**
134
+ * Extract object type from comment lines.
135
+ *
136
+ * @param cleaned - Cleaned comment lines
137
+ * @param tag - The tag to look for
138
+ * @returns The object type if found
139
+ */
140
+ function extractObjectType(cleaned, tag) {
141
+ const tagWithoutAt = tag.slice(1);
142
+ const objectTypeLine = cleaned.find((line) => line.includes(`${tagWithoutAt}strictObject`) || line.includes(`${tagWithoutAt}looseObject`));
143
+ if (!objectTypeLine) return void 0;
144
+ if (objectTypeLine.includes("strictObject")) return "strict";
145
+ if (objectTypeLine.includes("looseObject")) return "loose";
146
+ }
147
+ /**
148
+ * Extract definition from comment lines.
149
+ *
150
+ * @param cleaned - Cleaned comment lines
151
+ * @param tag - The tag to look for
152
+ * @returns The definition string
153
+ */
154
+ function extractDefinition(cleaned, tag) {
155
+ const definitionLine = cleaned.find((line) => line.startsWith(tag) && !line.includes("strictObject") && !line.includes("looseObject"));
156
+ if (!definitionLine) return "";
157
+ const withoutAt = definitionLine.startsWith("@") ? definitionLine.substring(1) : definitionLine;
158
+ if (tag === "@a." || tag === "@e.") {
159
+ const prefix = tag.substring(1);
160
+ return withoutAt.startsWith(prefix) ? withoutAt.substring(prefix.length) : withoutAt;
161
+ }
162
+ return withoutAt;
163
+ }
164
+ /**
165
+ * Extract description from comment lines.
166
+ *
167
+ * @param cleaned - Cleaned comment lines
168
+ * @returns The description if found
169
+ */
170
+ function extractDescription(cleaned) {
171
+ const descriptionLines = cleaned.filter((line) => !(line.includes("@z.") || line.includes("@v.") || line.includes("@a.") || line.includes("@e.") || line.includes("@relation.")));
172
+ return descriptionLines.length > 0 ? descriptionLines.join(" ") : void 0;
173
+ }
174
+ /**
175
+ * Parse field comments and extract definition line and description.
176
+ *
177
+ * @param commentLines - Raw comment lines (e.g., from source text)
178
+ * @param tag - The tag to look for (e.g., '@v.', '@z.', '@a.', or '@e.')
179
+ * @returns Parsed definition and description
180
+ */
181
+ function parseFieldComments(commentLines, tag) {
182
+ const cleaned = cleanCommentLines(commentLines);
183
+ const objectType = extractObjectType(cleaned, tag);
184
+ return {
185
+ definition: extractDefinition(cleaned, tag),
186
+ description: extractDescription(cleaned),
187
+ objectType
188
+ };
189
+ }
190
+ /**
191
+ * Process a single line during comment extraction.
192
+ *
193
+ * @param acc - The accumulator
194
+ * @param line - The line to process
195
+ * @returns Updated accumulator
196
+ */
197
+ function processCommentLine(acc, line) {
198
+ if (acc.shouldStop) return acc;
199
+ if (line.startsWith("///")) return {
200
+ commentLines: [line, ...acc.commentLines],
201
+ shouldStop: false
202
+ };
203
+ if (line === "") return acc;
204
+ return {
205
+ commentLines: acc.commentLines,
206
+ shouldStop: true
207
+ };
208
+ }
209
+ /**
210
+ * Extract field comments from source text.
211
+ *
212
+ * @param sourceText - The source text to extract comments from.
213
+ * @param fieldStartPos - The position of the field in the source text.
214
+ * @returns An array of comment lines.
215
+ */
216
+ function extractFieldComments(sourceText, fieldStartPos) {
217
+ return sourceText.substring(0, fieldStartPos).split("\n").map((line, index) => ({
218
+ line: line.trim(),
219
+ index
220
+ })).reverse().reduce((acc, { line }) => processCommentLine(acc, line), {
221
+ commentLines: [],
222
+ shouldStop: false
223
+ }).commentLines;
224
+ }
225
+ /**
226
+ * Creates `z.infer` type for the specified model.
227
+ * Uses makeZodInfer from utils-lab with capitalized model name.
228
+ *
229
+ * @param name - The model name
230
+ * @returns The generated TypeScript type definition line using Zod.
231
+ */
232
+ function infer(name) {
233
+ return makeZodInfer(makeCapitalized(name));
234
+ }
235
+ /**
236
+ * Creates `v.InferInput` type for the specified model.
237
+ * Uses makeValibotInfer from utils-lab with capitalized model name.
238
+ *
239
+ * @param name - The model name
240
+ * @returns The generated TypeScript type definition line using Valibot.
241
+ */
242
+ function inferInput(name) {
243
+ return makeValibotInfer(makeCapitalized(name));
244
+ }
245
+ /**
246
+ * @param schema
247
+ * @returns
248
+ */
249
+ function fieldDefinitions(schema, comment) {
250
+ return schema.fields.map(({ name, definition, description }) => {
251
+ return `${description && comment ? `/**\n* ${description}\n*/\n` : ""}${name}:${definition}`;
252
+ }).join(",\n");
253
+ }
254
+ /**
255
+ * Creates ArkType infer type for the specified model.
256
+ *
257
+ * @param name - The model name
258
+ * @returns The generated TypeScript type definition line using ArkType.
259
+ */
260
+ function inferArktype(name) {
261
+ const capitalized = makeCapitalized(name);
262
+ return `export type ${capitalized} = typeof ${capitalized}Schema.infer`;
263
+ }
264
+ /**
265
+ * Creates Effect Schema infer type for the specified model.
266
+ *
267
+ * @param name - The model name
268
+ * @returns The generated TypeScript type definition line using Effect Schema.
269
+ */
270
+ function inferEffect(name) {
271
+ const capitalized = makeCapitalized(name);
272
+ return `export type ${capitalized} = Schema.Schema.Type<typeof ${capitalized}Schema>`;
273
+ }
274
+
275
+ //#endregion
276
+ //#region src/shared/helper/extract-schemas.ts
277
+ /**
278
+ * Generates relation definition based on function name and reference table.
279
+ *
280
+ * @param fnName - The relation function name ('many' or 'one')
281
+ * @param refTable - The referenced table name
282
+ * @param prefix - Schema prefix for validation library
283
+ * @returns The generated relation definition string
284
+ */
285
+ function generateRelationDefinition(fnName, refTable, prefix) {
286
+ const schema = `${makeCapitalized$1(refTable)}Schema`;
287
+ if (fnName === "many") {
288
+ if (prefix === "type") return `${schema}.array()`;
289
+ if (prefix === "Schema") return `Schema.Array(${schema})`;
290
+ return `${prefix}.array(${schema})`;
291
+ }
292
+ if (fnName === "one") return schema;
293
+ return "";
294
+ }
295
+ /**
296
+ * Processes arrow function body to find object literal expression.
297
+ *
298
+ * @param body - The arrow function body node
299
+ * @returns The found object literal expression, or null if not found
300
+ */
301
+ function processArrowFunctionBody(body) {
302
+ if (Node.isObjectLiteralExpression(body)) return body;
303
+ if (Node.isParenthesizedExpression(body)) return findObjectLiteralExpression(body.getExpression());
304
+ if (Node.isBlock(body)) {
305
+ const ret = body.getStatements().find(Node.isReturnStatement);
306
+ if (ret && Node.isReturnStatement(ret)) {
307
+ const re = ret.getExpression();
308
+ return re && Node.isObjectLiteralExpression(re) ? re : null;
309
+ }
310
+ }
311
+ return null;
312
+ }
313
+ /**
314
+ * Recursively extracts an `ObjectLiteralExpression` from a given AST node.
315
+ *
316
+ * @param expr - The root `Node` to search for object literals
317
+ * @returns The found `ObjectLiteralExpression`, or `null` if not found
318
+ */
319
+ function findObjectLiteralExpression(expr) {
320
+ if (Node.isObjectLiteralExpression(expr)) return expr;
321
+ if (Node.isParenthesizedExpression(expr)) return findObjectLiteralExpression(expr.getExpression());
322
+ if (Node.isArrowFunction(expr)) return processArrowFunctionBody(expr.getBody());
323
+ return null;
324
+ }
325
+ /**
326
+ * Finds an object literal expression in call expression arguments.
327
+ *
328
+ * @param call - The call expression to search for object literals in its arguments
329
+ * @param finder - Function to find object literal in a node
330
+ * @returns The found object literal, or `null` if not found in any argument
331
+ */
332
+ function findObjectLiteralInArgs(call, finder) {
333
+ for (const arg of call.getArguments()) {
334
+ const obj = finder(arg);
335
+ if (obj) return obj;
336
+ }
337
+ return null;
338
+ }
339
+ /**
340
+ * Determines whether a given `CallExpression` is a relation-related function call.
341
+ *
342
+ * @param callExpr - The call expression node to check for relation functions
343
+ * @returns `true` if the function is a relation function; otherwise, `false`
344
+ */
345
+ function isRelationFunctionCall(callExpr) {
346
+ const expression = callExpr.getExpression();
347
+ if (!Node.isIdentifier(expression)) return false;
348
+ const functionName = expression.getText();
349
+ return functionName === "relations" || functionName.includes("relation");
350
+ }
351
+ /**
352
+ * Creates a field extractor function using a custom parseFieldComments implementation.
353
+ *
354
+ * @param parseFieldComments - A function that parses comment lines into { definition, description, objectType }
355
+ * @returns A property node extractor function
356
+ */
357
+ function createExtractFieldFromProperty(parseFieldComments) {
358
+ return (property, sourceText) => {
359
+ if (!Node.isPropertyAssignment(property)) return null;
360
+ const name = property.getName();
361
+ if (!name) return null;
362
+ const { definition, description } = parseFieldComments(extractFieldComments(sourceText, property.getStart()));
363
+ return {
364
+ name,
365
+ definition,
366
+ description
367
+ };
368
+ };
369
+ }
370
+ /**
371
+ * Creates a relation field extractor function.
372
+ *
373
+ * @param parseFieldComments - Function to parse field comments
374
+ * @param prefix - Schema prefix for validation library
375
+ * @returns Function that extracts relation fields from property
376
+ */
377
+ function createExtractRelationFieldFromProperty(parseFieldComments, prefix) {
378
+ return (property, sourceText) => {
379
+ if (!Node.isPropertyAssignment(property)) return null;
380
+ const name = property.getName();
381
+ if (!name) return null;
382
+ const init = property.getInitializer();
383
+ if (!Node.isCallExpression(init)) return {
384
+ name,
385
+ definition: "",
386
+ description: void 0
387
+ };
388
+ const expr = init.getExpression();
389
+ if (!Node.isIdentifier(expr)) return {
390
+ name,
391
+ definition: "",
392
+ description: void 0
393
+ };
394
+ const fnName = expr.getText();
395
+ const args = init.getArguments();
396
+ if (!(args.length && Node.isIdentifier(args[0]))) return {
397
+ name,
398
+ definition: "",
399
+ description: void 0
400
+ };
401
+ const definition = generateRelationDefinition(fnName, args[0].getText(), prefix);
402
+ const { description } = parseFieldComments(extractFieldComments(sourceText, property.getStart()));
403
+ return {
404
+ name,
405
+ definition,
406
+ description
407
+ };
408
+ };
409
+ }
410
+ /**
411
+ * Extracts fields from object literal properties using appropriate extractor.
412
+ *
413
+ * @param properties - Array of object literal properties
414
+ * @param isRelation - Whether this is a relation function call
415
+ * @param extractFieldFromProperty - Function to extract regular fields
416
+ * @param extractRelationFieldFromProperty - Function to extract relation fields
417
+ * @param sourceText - The source text for comment extraction
418
+ * @returns Array of extracted field results
419
+ */
420
+ function extractFieldsFromProperties(properties, isRelation, extractFieldFromProperty, extractRelationFieldFromProperty, sourceText) {
421
+ return properties.map((prop) => isRelation ? extractRelationFieldFromProperty(prop, sourceText) : extractFieldFromProperty(prop, sourceText)).filter((field) => field !== null);
422
+ }
423
+ /**
424
+ * Creates a field extractor for call expressions with customizable strategies.
425
+ *
426
+ * @param extractFieldFromProperty - Function to extract field from property
427
+ * @param extractRelationFieldFromProperty - Function to extract relation field from property
428
+ * @param findObjectLiteralExpression - Function to find object literal expression
429
+ * @param findObjectLiteralInArgs - Function to find object literal in call arguments
430
+ * @param isRelationFunctionCall - Function to check if call is relation function
431
+ * @returns Function that extracts fields from call expression
432
+ */
433
+ function createExtractFieldsFromCallExpression(extractFieldFromProperty, extractRelationFieldFromProperty, findObjectLiteralExpression, findObjectLiteralInArgs, isRelationFunctionCall) {
434
+ return (callExpr, sourceText) => {
435
+ const objectLiteral = findObjectLiteralInArgs(callExpr, findObjectLiteralExpression);
436
+ if (!objectLiteral) return [];
437
+ const isRelation = isRelationFunctionCall(callExpr);
438
+ return extractFieldsFromProperties(objectLiteral.getProperties(), isRelation, extractFieldFromProperty, extractRelationFieldFromProperty, sourceText);
439
+ };
440
+ }
441
+ /**
442
+ * Creates a schema extractor from customizable strategies.
443
+ *
444
+ * @param extractFieldsFromCall - Function to extract fields from a call expression
445
+ * @param extractFieldFromProperty - Function to extract a single field from an object literal property
446
+ * @param parseFieldComments - Function to parse field comments with object type support
447
+ * @param commentPrefix - The comment prefix to use for parsing
448
+ * @returns A function that extracts a schema from a variable declaration node
449
+ */
450
+ function buildSchemaExtractor(extractFieldsFromCall, extractFieldFromProperty, parseFieldComments, commentPrefix) {
451
+ return (variableStatement, sourceText, originalSourceCode) => {
452
+ if (!Node.isVariableStatement(variableStatement)) return null;
453
+ const declarations = variableStatement.getDeclarations();
454
+ if (declarations.length === 0) return null;
455
+ const declaration = declarations[0];
456
+ const name = declaration.getName();
457
+ if (!name) return null;
458
+ const statementStart = variableStatement.getStart();
459
+ const originalSourceLines = originalSourceCode.split("\n");
460
+ const commentLines = [];
461
+ let lineNumber = 0;
462
+ let charCount = 0;
463
+ for (let i = 0; i < originalSourceLines.length; i++) {
464
+ if (charCount >= statementStart) {
465
+ lineNumber = i;
466
+ break;
467
+ }
468
+ charCount += originalSourceLines[i].length + 1;
469
+ }
470
+ for (let i = lineNumber - 1; i >= 0; i--) {
471
+ const line = originalSourceLines[i];
472
+ const trimmedLine = trimString(line);
473
+ if (trimmedLine === "") continue;
474
+ if (startsWith(trimmedLine, "///")) commentLines.unshift(line);
475
+ else break;
476
+ }
477
+ const { objectType } = parseFieldComments(commentLines, commentPrefix);
478
+ const initializer = declaration.getInitializer();
479
+ if (Node.isCallExpression(initializer)) {
480
+ if (isRelationFunctionCall(initializer)) return null;
481
+ return {
482
+ name,
483
+ fields: extractFieldsFromCall(initializer, sourceText),
484
+ objectType
485
+ };
486
+ }
487
+ if (Node.isObjectLiteralExpression(initializer)) return {
488
+ name,
489
+ fields: initializer.getProperties().map((prop) => extractFieldFromProperty(prop, sourceText)).filter((field) => field !== null),
490
+ objectType
491
+ };
492
+ return {
493
+ name,
494
+ fields: [],
495
+ objectType
496
+ };
497
+ };
498
+ }
499
+ /**
500
+ * Extracts schemas from TypeScript source code using AST analysis.
501
+ *
502
+ * This function processes exported variable declarations to extract table schemas
503
+ * with their field definitions and comments. It supports both Zod and Valibot schema extraction.
504
+ *
505
+ * @param lines - Array of source code lines to process
506
+ * @param library - The validation library to extract schemas for ('zod' or 'valibot')
507
+ * @returns Array of extracted schemas with field definitions
508
+ *
509
+ * @example
510
+ * ```typescript
511
+ * // For Zod schemas
512
+ * const zodSchemas = extractSchemas(sourceLines, 'zod')
513
+ *
514
+ * // For Valibot schemas
515
+ * const valibotSchemas = extractSchemas(sourceLines, 'valibot')
516
+ * ```
517
+ */
518
+ function extractSchemas(lines, library) {
519
+ const sourceCode = lines.join("\n");
520
+ const sourceFile = new Project({
521
+ useInMemoryFileSystem: true,
522
+ compilerOptions: {
523
+ allowJs: true,
524
+ skipLibCheck: true
525
+ }
526
+ }).createSourceFile("temp.ts", sourceCode);
527
+ const sourceText = sourceFile.getFullText();
528
+ const commentPrefix = library === "zod" ? "@z." : library === "valibot" ? "@v." : library === "arktype" ? "@a." : "@e.";
529
+ const schemaPrefix = library === "zod" ? "z" : library === "valibot" ? "v" : library === "arktype" ? "type" : "Schema";
530
+ const extractField = createExtractFieldFromProperty((lines) => parseFieldComments(lines, commentPrefix));
531
+ const extractSchema = buildSchemaExtractor(createExtractFieldsFromCallExpression(extractField, createExtractRelationFieldFromProperty((lines) => parseFieldComments(lines, commentPrefix), schemaPrefix), findObjectLiteralExpression, findObjectLiteralInArgs, isRelationFunctionCall), extractField, parseFieldComments, commentPrefix);
532
+ return sourceFile.getVariableStatements().filter((stmt) => stmt.hasExportKeyword()).map((stmt) => extractSchema(stmt, sourceText, sourceCode)).filter((schema) => schema !== null);
533
+ }
534
+ /**
535
+ * Extracts relation schemas from `relations(...)` declarations using AST analysis.
536
+ *
537
+ * This returns entries like `userRelations` and `postRelations` with fields
538
+ * resolved to either `z.array(OtherSchema)` / `v.array(OtherSchema)` or direct
539
+ * `OtherSchema` based on `many`/`one`.
540
+ *
541
+ * Note: Base table schemas are not included here; use `extractSchemas` for those.
542
+ */
543
+ function extractRelationSchemas(lines, library) {
544
+ const sourceCode = lines.join("\n");
545
+ const sourceFile = new Project({
546
+ useInMemoryFileSystem: true,
547
+ compilerOptions: {
548
+ allowJs: true,
549
+ skipLibCheck: true
550
+ }
551
+ }).createSourceFile("temp.ts", sourceCode);
552
+ const sourceText = sourceFile.getFullText();
553
+ const commentPrefix = library === "zod" ? "@z." : library === "valibot" ? "@v." : library === "arktype" ? "@a." : "@e.";
554
+ const schemaPrefix = library === "zod" ? "z" : library === "valibot" ? "v" : library === "arktype" ? "type" : "Schema";
555
+ const baseSchemas = extractSchemas(lines, library);
556
+ const baseSchemaMap = new Map(baseSchemas.map((schema) => [schema.name, schema.objectType]));
557
+ const extractFieldsFromCall = createExtractFieldsFromCallExpression(createExtractFieldFromProperty((lines) => parseFieldComments(lines, commentPrefix)), createExtractRelationFieldFromProperty((lines) => parseFieldComments(lines, commentPrefix), schemaPrefix), findObjectLiteralExpression, findObjectLiteralInArgs, isRelationFunctionCall);
558
+ function extract(declaration) {
559
+ if (!Node.isVariableDeclaration(declaration)) return null;
560
+ const name = declaration.getName();
561
+ if (!name) return null;
562
+ const initializer = declaration.getInitializer();
563
+ if (!Node.isCallExpression(initializer)) return null;
564
+ if (!isRelationFunctionCall(initializer)) return null;
565
+ const relArgs = initializer.getArguments();
566
+ const baseIdentifier = relArgs.length && Node.isIdentifier(relArgs[0]) ? relArgs[0] : void 0;
567
+ if (!baseIdentifier) return null;
568
+ const baseName = baseIdentifier.getText();
569
+ return {
570
+ name,
571
+ baseName,
572
+ fields: extractFieldsFromCall(initializer, sourceText),
573
+ objectType: baseSchemaMap.get(baseName)
574
+ };
575
+ }
576
+ return sourceFile.getVariableStatements().filter((stmt) => stmt.hasExportKeyword()).flatMap((stmt) => stmt.getDeclarations()).map((decl) => extract(decl)).filter((schema) => schema !== null);
577
+ }
578
+
579
+ //#endregion
580
+ //#region src/generator/arktype/generator/arktype.ts
581
+ /**
582
+ * Generates an ArkType schema for a given schema and config.
583
+ *
584
+ * @param schema - The schema to generate code for.
585
+ * @param comment - Whether to include comments in the generated code.
586
+ * @returns The generated ArkType schema.
587
+ */
588
+ function arktype(schema, comment) {
589
+ const inner = fieldDefinitions(schema, comment);
590
+ return `export const ${makeCapitalized(schema.name)}Schema = type({${inner}})`;
591
+ }
592
+
593
+ //#endregion
594
+ //#region src/generator/arktype/generator/arktype-code.ts
595
+ /**
596
+ * Generates ArkType code for a given schema and config.
597
+ *
598
+ * @param schema - The schema to generate code for.
599
+ * @param comment - Whether to include comments in the generated code.
600
+ * @param type - Whether to include type information in the generated code.
601
+ * @returns The generated ArkType code.
602
+ */
603
+ function arktypeCode(schema, comment, type) {
604
+ const arktypeSchema = arktype(schema, comment);
605
+ if (type) return `${arktypeSchema}\n\n${inferArktype(schema.name)}\n`;
606
+ return `${arktypeSchema}\n`;
607
+ }
608
+
609
+ //#endregion
610
+ //#region src/generator/arktype/index.ts
611
+ /**
612
+ * Generate ArkType schema
613
+ * @param code - The code to generate ArkType schema from
614
+ * @param output - The output file path
615
+ * @param comment - Whether to include comments in the generated code
616
+ * @param type - Whether to include type information in the generated code
617
+ */
618
+ async function sizukuArktype(code, output, comment, type) {
619
+ const arktypeGeneratedCode = [
620
+ `import { type } from 'arktype'`,
621
+ "",
622
+ ...extractSchemas(code, "arktype").map((schema) => arktypeCode(schema, comment ?? false, type ?? false))
623
+ ].join("\n");
624
+ const mkdirResult = await mkdir(path.dirname(output));
625
+ if (!mkdirResult.ok) return {
626
+ ok: false,
627
+ error: mkdirResult.error
628
+ };
629
+ const fmtResult = await fmt(arktypeGeneratedCode);
630
+ if (!fmtResult.ok) return {
631
+ ok: false,
632
+ error: fmtResult.error
633
+ };
634
+ const writeFileResult = await writeFile(output, fmtResult.value);
635
+ if (!writeFileResult.ok) return {
636
+ ok: false,
637
+ error: writeFileResult.error
638
+ };
639
+ return {
640
+ ok: true,
641
+ value: void 0
642
+ };
643
+ }
644
+
645
+ //#endregion
646
+ //#region src/generator/mermaid-er/validator/index.ts
647
+ /**
648
+ * Create a unique key for relation deduplication.
649
+ */
650
+ function relationKey(r) {
651
+ return `${r.fromModel}.${r.fromField}->${r.toModel}.${r.toField}`;
652
+ }
653
+ /**
654
+ * Extract base builder name from expression.
655
+ *
656
+ * @param expr - The expression to extract name from
657
+ * @returns The base builder name
658
+ */
659
+ function baseBuilderName(expr) {
660
+ if (Node.isIdentifier(expr)) return expr.getText();
661
+ if (Node.isCallExpression(expr) || Node.isPropertyAccessExpression(expr)) return baseBuilderName(expr.getExpression());
662
+ return "";
663
+ }
664
+ /**
665
+ * Type guard for FieldInfo.
666
+ *
667
+ * @param v - The value to check
668
+ * @returns True if value is FieldInfo
669
+ */
670
+ function isFieldInfo(v) {
671
+ return v !== null;
672
+ }
673
+ /**
674
+ * Extract key type based on field definition.
675
+ *
676
+ * @param initText - The initializer text
677
+ * @returns The key type (PK, FK, or null)
678
+ */
679
+ function extractKeyType(initText) {
680
+ if (initText.includes(".primaryKey()")) return "PK";
681
+ if (initText.includes(".references(")) return "FK";
682
+ return null;
683
+ }
684
+ /**
685
+ * Find immediate comment for a field.
686
+ *
687
+ * @param code - The source code lines
688
+ * @param lineIdx - The line index of the field
689
+ * @returns The immediate comment or empty string
690
+ */
691
+ function findImmediateComment(code, lineIdx) {
692
+ return code.slice(0, lineIdx).reverse().find((line) => {
693
+ const t = line.trim();
694
+ return t.startsWith("///") && !t.includes("@z.") && !t.includes("@v.") && !t.includes("@a.") && !t.includes("@e.") && !t.includes("@relation");
695
+ })?.replace(/^\s*\/\/\/\s*/, "") ?? "";
696
+ }
697
+ /**
698
+ * Extract reference info from a .references() call.
699
+ *
700
+ * @param initExpr - The call expression to analyze
701
+ * @returns The reference info or null
702
+ */
703
+ function extractReferenceInfo(initExpr) {
704
+ const match = initExpr.getText().match(/\.references\(\s*\(\)\s*=>\s*(\w+)\.(\w+)\s*\)/);
705
+ if (match) return {
706
+ referencedTable: match[1],
707
+ referencedField: match[2]
708
+ };
709
+ return null;
710
+ }
711
+ /**
712
+ * Check if field is required (notNull).
713
+ *
714
+ * @param initText - The initializer text
715
+ * @returns True if field is required
716
+ */
717
+ function isFieldRequired(initText) {
718
+ return initText.includes(".notNull()");
719
+ }
720
+ /**
721
+ * Extract field info from property assignment.
722
+ *
723
+ * @param prop - The property assignment node
724
+ * @param code - The source code lines
725
+ * @returns Field info or null
726
+ */
727
+ function extractFieldInfo(prop, code) {
728
+ const keyNode = prop.getNameNode();
729
+ if (!Node.isIdentifier(keyNode)) return null;
730
+ const fieldName = keyNode.getText();
731
+ const initExpr = prop.getInitializer();
732
+ if (!(initExpr && Node.isCallExpression(initExpr))) return null;
733
+ const fieldType = baseBuilderName(initExpr);
734
+ const initText = initExpr.getText();
735
+ const immediateComment = findImmediateComment(code, prop.getStartLineNumber() - 1);
736
+ return {
737
+ name: fieldName,
738
+ type: fieldType,
739
+ keyType: extractKeyType(initText),
740
+ description: immediateComment || null
741
+ };
742
+ }
743
+ /**
744
+ * Extract relation info from a property assignment with .references().
745
+ *
746
+ * @param prop - The property assignment node
747
+ * @param tableName - The name of the current table
748
+ * @returns Relation info or null
749
+ */
750
+ function extractRelationFromField(prop, tableName) {
751
+ const keyNode = prop.getNameNode();
752
+ if (!Node.isIdentifier(keyNode)) return null;
753
+ const fieldName = keyNode.getText();
754
+ const initExpr = prop.getInitializer();
755
+ if (!(initExpr && Node.isCallExpression(initExpr))) return null;
756
+ const initText = initExpr.getText();
757
+ if (!initText.includes(".references(")) return null;
758
+ const refInfo = extractReferenceInfo(initExpr);
759
+ if (!refInfo) return null;
760
+ const isRequired = isFieldRequired(initText);
761
+ return {
762
+ fromModel: refInfo.referencedTable,
763
+ toModel: tableName,
764
+ fromField: refInfo.referencedField,
765
+ toField: fieldName,
766
+ isRequired
767
+ };
768
+ }
769
+ /**
770
+ * Extract relations from foreignKey() constraints in the third argument.
771
+ *
772
+ * Pattern:
773
+ * foreignKey({
774
+ * columns: [TableName.fieldName],
775
+ * foreignColumns: [OtherTable.fieldName],
776
+ * })
777
+ *
778
+ * @param tableName - The name of the current table
779
+ * @param constraintArg - The third argument (arrow function returning constraints object)
780
+ * @returns Array of relation info
781
+ */
782
+ function extractRelationsFromForeignKeyConstraints(tableName, constraintArg) {
783
+ const relations = [];
784
+ if (!Node.isArrowFunction(constraintArg)) return relations;
785
+ const body = constraintArg.getBody();
786
+ if (!body) return relations;
787
+ let objExpr = body;
788
+ if (Node.isParenthesizedExpression(objExpr)) objExpr = objExpr.getExpression();
789
+ if (!Node.isObjectLiteralExpression(objExpr)) return relations;
790
+ objExpr.getProperties().forEach((prop) => {
791
+ if (!Node.isPropertyAssignment(prop)) return;
792
+ const initExpr = prop.getInitializer();
793
+ if (!initExpr) return;
794
+ const text = initExpr.getText();
795
+ if (!text.includes("foreignKey(")) return;
796
+ const columnsMatch = text.match(/columns:\s*\[\s*(\w+)\.(\w+)\s*\]/);
797
+ const foreignColumnsMatch = text.match(/foreignColumns:\s*\[\s*(\w+)\.(\w+)\s*\]/);
798
+ if (columnsMatch && foreignColumnsMatch) {
799
+ const toField = columnsMatch[2];
800
+ const fromModel = foreignColumnsMatch[1];
801
+ const fromField = foreignColumnsMatch[2];
802
+ const isRequired = !text.includes(".nullable()");
803
+ relations.push({
804
+ fromModel,
805
+ toModel: tableName,
806
+ fromField,
807
+ toField,
808
+ isRequired
809
+ });
810
+ }
811
+ });
812
+ return relations;
813
+ }
814
+ /**
815
+ * Extract relations from relations() helper blocks.
816
+ *
817
+ * Pattern:
818
+ * relations(TableRef, ({ one, many }) => ({
819
+ * user: one(User, {
820
+ * fields: [Post.userId],
821
+ * references: [User.id],
822
+ * }),
823
+ * posts: many(Post),
824
+ * }))
825
+ *
826
+ * @param file - The source file
827
+ * @returns Array of relation info
828
+ */
829
+ function extractRelationsFromRelationBlocks(file) {
830
+ const relations = [];
831
+ file.getVariableStatements().filter((stmt) => stmt.isExported()).forEach((stmt) => {
832
+ const decl = stmt.getDeclarations()[0];
833
+ if (!Node.isVariableDeclaration(decl)) return;
834
+ if (!decl.getName().toLowerCase().includes("relation")) return;
835
+ const init = decl.getInitializer();
836
+ if (!(init && Node.isCallExpression(init))) return;
837
+ if (init.getExpression().getText() !== "relations") return;
838
+ const args = init.getArguments();
839
+ if (args.length < 2) return;
840
+ const tableRef = args[0];
841
+ if (!Node.isIdentifier(tableRef)) return;
842
+ const tableName = tableRef.getText();
843
+ const arrowFn = args[1];
844
+ if (!Node.isArrowFunction(arrowFn)) return;
845
+ const body = arrowFn.getBody();
846
+ if (!body) return;
847
+ let objExpr = body;
848
+ if (Node.isParenthesizedExpression(objExpr)) objExpr = objExpr.getExpression();
849
+ if (!Node.isObjectLiteralExpression(objExpr)) return;
850
+ objExpr.getProperties().forEach((prop) => {
851
+ if (!Node.isPropertyAssignment(prop)) return;
852
+ const initExpr = prop.getInitializer();
853
+ if (!(initExpr && Node.isCallExpression(initExpr))) return;
854
+ if (initExpr.getExpression().getText() !== "one") return;
855
+ const relArgs = initExpr.getArguments();
856
+ if (relArgs.length < 2) return;
857
+ const refTableArg = relArgs[0];
858
+ if (!Node.isIdentifier(refTableArg)) return;
859
+ const refTable = refTableArg.getText();
860
+ const configArg = relArgs[1];
861
+ if (!Node.isObjectLiteralExpression(configArg)) return;
862
+ const configText = configArg.getText();
863
+ const fieldsMatch = configText.match(/fields:\s*\[\s*(\w+)\.(\w+)\s*\]/);
864
+ const referencesMatch = configText.match(/references:\s*\[\s*(\w+)\.(\w+)\s*\]/);
865
+ if (fieldsMatch && referencesMatch) {
866
+ const currentField = fieldsMatch[2];
867
+ const refField = referencesMatch[2];
868
+ const currentFieldLower = currentField.toLowerCase();
869
+ const refFieldLower = refField.toLowerCase();
870
+ const isCurrentFieldFk = currentFieldLower.endsWith("id") && currentFieldLower !== "id" || currentFieldLower.endsWith("_id");
871
+ const isRefFieldFk = refFieldLower.endsWith("id") && refFieldLower !== "id" || refFieldLower.endsWith("_id");
872
+ if (isCurrentFieldFk && !isRefFieldFk) relations.push({
873
+ fromModel: refTable,
874
+ toModel: tableName,
875
+ fromField: refField,
876
+ toField: currentField,
877
+ isRequired: true
878
+ });
879
+ else if (!isCurrentFieldFk && isRefFieldFk) relations.push({
880
+ fromModel: tableName,
881
+ toModel: refTable,
882
+ fromField: currentField,
883
+ toField: refField,
884
+ isRequired: true
885
+ });
886
+ else relations.push({
887
+ fromModel: refTable,
888
+ toModel: tableName,
889
+ fromField: refField,
890
+ toField: currentField,
891
+ isRequired: true
892
+ });
893
+ }
894
+ });
895
+ });
896
+ return relations;
897
+ }
898
+ /**
899
+ * Parse table information from Drizzle schema code.
900
+ *
901
+ * @param code - Array of source code lines
902
+ * @returns Array of table information
903
+ */
904
+ function parseTableInfo(code) {
905
+ const source = code.join("\n");
906
+ return new Project({ useInMemoryFileSystem: true }).createSourceFile("temp.ts", source).getVariableStatements().filter((stmt) => stmt.isExported()).flatMap((stmt) => {
907
+ const decl = stmt.getDeclarations()[0];
908
+ if (!Node.isVariableDeclaration(decl)) return [];
909
+ const varName = decl.getName();
910
+ if (varName.toLowerCase().includes("relation")) return [];
911
+ const init = decl.getInitializer();
912
+ if (!(init && Node.isCallExpression(init))) return [];
913
+ const callee = init.getExpression().getText();
914
+ if (!callee.endsWith("Table") || callee === "relations") return [];
915
+ const objLit = init.getArguments()[1];
916
+ if (!(objLit && Node.isObjectLiteralExpression(objLit))) return [];
917
+ return [{
918
+ name: varName,
919
+ fields: objLit.getProperties().filter(Node.isPropertyAssignment).map((prop) => extractFieldInfo(prop, code)).filter(isFieldInfo)
920
+ }];
921
+ });
922
+ }
923
+ /**
924
+ * Extract relations from Drizzle schema code by analyzing:
925
+ * 1. .references() calls on fields
926
+ * 2. foreignKey() constraints in table definition
927
+ * 3. relations() helper blocks
928
+ *
929
+ * @param code - Array of source code lines
930
+ * @returns Array of relation information (deduplicated)
931
+ */
932
+ function extractRelationsFromSchema(code) {
933
+ const source = code.join("\n");
934
+ const file = new Project({ useInMemoryFileSystem: true }).createSourceFile("temp.ts", source);
935
+ const relations = [];
936
+ file.getVariableStatements().filter((stmt) => stmt.isExported()).forEach((stmt) => {
937
+ const decl = stmt.getDeclarations()[0];
938
+ if (!Node.isVariableDeclaration(decl)) return;
939
+ const varName = decl.getName();
940
+ if (varName.toLowerCase().includes("relation")) return;
941
+ const init = decl.getInitializer();
942
+ if (!(init && Node.isCallExpression(init))) return;
943
+ const callee = init.getExpression().getText();
944
+ if (!callee.endsWith("Table") || callee === "relations") return;
945
+ const args = init.getArguments();
946
+ const objLit = args[1];
947
+ if (objLit && Node.isObjectLiteralExpression(objLit)) objLit.getProperties().filter(Node.isPropertyAssignment).forEach((prop) => {
948
+ const relation = extractRelationFromField(prop, varName);
949
+ if (relation) relations.push(relation);
950
+ });
951
+ const constraintArg = args[2];
952
+ if (constraintArg && Node.isExpression(constraintArg)) {
953
+ const fkRelations = extractRelationsFromForeignKeyConstraints(varName, constraintArg);
954
+ relations.push(...fkRelations);
955
+ }
956
+ });
957
+ const relationBlockRelations = extractRelationsFromRelationBlocks(file);
958
+ relations.push(...relationBlockRelations);
959
+ const seen = /* @__PURE__ */ new Set();
960
+ return relations.filter((r) => {
961
+ const key = relationKey(r);
962
+ if (seen.has(key)) return false;
963
+ seen.add(key);
964
+ return true;
965
+ });
966
+ }
967
+
968
+ //#endregion
969
+ //#region src/generator/dbml/generator/dbml-content.ts
970
+ /**
971
+ * DBML content generator for Drizzle schemas
972
+ *
973
+ * Generates DBML (Database Markup Language) format from parsed table and relation info.
974
+ * Uses utils-lab for common DBML generation functions.
975
+ */
976
+ /**
977
+ * Convert internal FieldInfo to DBMLColumn
978
+ */
979
+ function toDBMLColumn(field) {
980
+ return {
981
+ name: field.name,
982
+ type: mapDrizzleType(field.type),
983
+ isPrimaryKey: field.keyType === "PK",
984
+ isIncrement: field.type.includes("serial"),
985
+ note: field.description ?? void 0
986
+ };
987
+ }
988
+ /**
989
+ * Convert internal TableInfo to DBMLTable
990
+ */
991
+ function toDBMLTable(table) {
992
+ return {
993
+ name: table.name,
994
+ columns: table.fields.map(toDBMLColumn)
995
+ };
996
+ }
997
+ /**
998
+ * Convert internal RelationInfo to DBMLRef
999
+ */
1000
+ function toDBMLRef(relation) {
1001
+ return {
1002
+ fromTable: relation.toModel,
1003
+ fromColumn: relation.toField,
1004
+ toTable: relation.fromModel,
1005
+ toColumn: relation.fromField
1006
+ };
1007
+ }
1008
+ /**
1009
+ * Generate complete DBML content
1010
+ *
1011
+ * @param relations - The relations extracted from the schema
1012
+ * @param tables - The tables to generate DBML from
1013
+ * @returns The generated DBML content
1014
+ */
1015
+ function dbmlContent(relations, tables) {
1016
+ return generateDBMLContent({
1017
+ tables: tables.map(toDBMLTable),
1018
+ refs: relations.map(toDBMLRef)
1019
+ });
1020
+ }
1021
+
1022
+ //#endregion
1023
+ //#region src/generator/dbml/index.ts
1024
+ /**
1025
+ * Generate DBML schema from Drizzle schema code
1026
+ *
1027
+ * @param code - The code to generate DBML from
1028
+ * @param output - The output file path
1029
+ */
1030
+ async function sizukuDBML(code, output) {
1031
+ const tables = parseTableInfo(code);
1032
+ const content = dbmlContent(extractRelationsFromSchema(code), tables);
1033
+ const mkdirResult = await mkdir(path.dirname(output));
1034
+ if (!mkdirResult.ok) return {
1035
+ ok: false,
1036
+ error: mkdirResult.error
1037
+ };
1038
+ const writeFileResult = await writeFile(output, content);
1039
+ if (!writeFileResult.ok) return {
1040
+ ok: false,
1041
+ error: writeFileResult.error
1042
+ };
1043
+ return {
1044
+ ok: true,
1045
+ value: void 0
1046
+ };
1047
+ }
1048
+
1049
+ //#endregion
1050
+ //#region src/generator/effect/generator/effect.ts
1051
+ /**
1052
+ * Generates an Effect schema for a given schema and config.
1053
+ *
1054
+ * @param schema - The schema to generate code for.
1055
+ * @param comment - Whether to include comments in the generated code.
1056
+ * @returns The generated Effect schema.
1057
+ */
1058
+ function effect(schema, comment) {
1059
+ const inner = fieldDefinitions(schema, comment);
1060
+ return `export const ${makeCapitalized(schema.name)}Schema = Schema.Struct({${inner}})`;
1061
+ }
1062
+
1063
+ //#endregion
1064
+ //#region src/generator/effect/generator/effect-code.ts
1065
+ /**
1066
+ * Generates Effect code for a given schema and config.
1067
+ *
1068
+ * @param schema - The schema to generate code for.
1069
+ * @param comment - Whether to include comments in the generated code.
1070
+ * @param type - Whether to include type information in the generated code.
1071
+ * @returns The generated Effect code.
1072
+ */
1073
+ function effectCode(schema, comment, type) {
1074
+ const effectSchema = effect(schema, comment);
1075
+ if (type) return `${effectSchema}\n\n${inferEffect(schema.name)}\n`;
1076
+ return `${effectSchema}\n`;
1077
+ }
1078
+
1079
+ //#endregion
1080
+ //#region src/generator/effect/index.ts
1081
+ /**
1082
+ * Generate Effect schema
1083
+ * @param code - The code to generate Effect schema from
1084
+ * @param output - The output file path
1085
+ * @param comment - Whether to include comments in the generated code
1086
+ * @param type - Whether to include type information in the generated code
1087
+ */
1088
+ async function sizukuEffect(code, output, comment, type) {
1089
+ const effectGeneratedCode = [
1090
+ `import { Schema } from 'effect'`,
1091
+ "",
1092
+ ...extractSchemas(code, "effect").map((schema) => effectCode(schema, comment ?? false, type ?? false))
1093
+ ].join("\n");
1094
+ const mkdirResult = await mkdir(path.dirname(output));
1095
+ if (!mkdirResult.ok) return {
1096
+ ok: false,
1097
+ error: mkdirResult.error
1098
+ };
1099
+ const fmtResult = await fmt(effectGeneratedCode);
1100
+ if (!fmtResult.ok) return {
1101
+ ok: false,
1102
+ error: fmtResult.error
1103
+ };
1104
+ const writeFileResult = await writeFile(output, fmtResult.value);
1105
+ if (!writeFileResult.ok) return {
1106
+ ok: false,
1107
+ error: writeFileResult.error
1108
+ };
1109
+ return {
1110
+ ok: true,
1111
+ value: void 0
1112
+ };
1113
+ }
1114
+
1115
+ //#endregion
1116
+ //#region src/generator/mermaid-er/generator/er-content.ts
1117
+ const ER_HEADER = ["```mermaid", "erDiagram"];
1118
+ const ER_FOOTER = ["```"];
1119
+ const RELATIONSHIPS = {
1120
+ "zero-one": "|o",
1121
+ one: "||",
1122
+ "zero-many": "}o",
1123
+ many: "}|"
1124
+ };
1125
+ /**
1126
+ * Generate relation line from relation info.
1127
+ *
1128
+ * @param relation - The relation info
1129
+ * @returns The Mermaid ER relation line
1130
+ */
1131
+ function generateRelationLine(relation) {
1132
+ const fromSymbol = RELATIONSHIPS.one;
1133
+ const toSymbol = relation.isRequired ? RELATIONSHIPS.many : RELATIONSHIPS["zero-many"];
1134
+ return ` ${relation.fromModel} ${fromSymbol}--${toSymbol} ${relation.toModel} : "(${relation.fromField}) - (${relation.toField})"`;
1135
+ }
1136
+ /**
1137
+ * Remove duplicate relations.
1138
+ *
1139
+ * @param relations - The relations to deduplicate
1140
+ * @returns The deduplicated relations
1141
+ */
1142
+ function removeDuplicateRelations(relations) {
1143
+ return [...new Set(relations)];
1144
+ }
1145
+ /**
1146
+ * Generate ER content
1147
+ * @param relations - The relations extracted from .references() calls
1148
+ * @param tables - The tables to generate the ER content from
1149
+ * @returns The generated ER content
1150
+ */
1151
+ function erContent(relations, tables) {
1152
+ const relationLines = removeDuplicateRelations(relations.map(generateRelationLine));
1153
+ const tableDefinitions = tables.flatMap((table) => [
1154
+ ` ${table.name} {`,
1155
+ ...table.fields.map((field) => {
1156
+ const keyPart = field.keyType ? ` ${field.keyType}` : "";
1157
+ const descPart = field.description ? ` "${field.description}"` : "";
1158
+ return ` ${field.type} ${field.name}${keyPart}${descPart}`;
1159
+ }),
1160
+ " }"
1161
+ ]);
1162
+ return [
1163
+ ...ER_HEADER,
1164
+ ...relationLines,
1165
+ ...tableDefinitions,
1166
+ ...ER_FOOTER
1167
+ ].join("\n");
1168
+ }
1169
+
1170
+ //#endregion
1171
+ //#region src/generator/mermaid-er/index.ts
1172
+ /**
1173
+ * Generate Mermaid ER diagram
1174
+ * @param code - The code to generate Mermaid ER diagram from
1175
+ * @param output - The output file path
1176
+ */
1177
+ async function sizukuMermaidER(code, output) {
1178
+ const tables = parseTableInfo(code);
1179
+ const ERContent = erContent(extractRelationsFromSchema(code), tables);
1180
+ const mkdirResult = await mkdir(path.dirname(output));
1181
+ if (!mkdirResult.ok) return {
1182
+ ok: false,
1183
+ error: mkdirResult.error
1184
+ };
1185
+ const writeFileResult = await writeFile(output, ERContent);
1186
+ if (!writeFileResult.ok) return {
1187
+ ok: false,
1188
+ error: writeFileResult.error
1189
+ };
1190
+ return {
1191
+ ok: true,
1192
+ value: void 0
1193
+ };
1194
+ }
1195
+
1196
+ //#endregion
1197
+ //#region src/generator/svg/index.ts
1198
+ /**
1199
+ * Generate diagram from Drizzle schema code
1200
+ *
1201
+ * @param code - The code to generate diagram from
1202
+ * @param output - The output file path
1203
+ * @param format - Output format ('svg', 'png', or 'dot')
1204
+ */
1205
+ async function sizukuSVG(code, output, format = "png") {
1206
+ const tables = parseTableInfo(code);
1207
+ const dbml = dbmlContent(extractRelationsFromSchema(code), tables);
1208
+ const mkdirResult = await mkdir(path.dirname(output));
1209
+ if (!mkdirResult.ok) return {
1210
+ ok: false,
1211
+ error: mkdirResult.error
1212
+ };
1213
+ if (format === "dot") {
1214
+ const writeResult = await writeFile(output, run(dbml, "dot"));
1215
+ if (!writeResult.ok) return {
1216
+ ok: false,
1217
+ error: writeResult.error
1218
+ };
1219
+ } else {
1220
+ const svg = run(dbml, "svg");
1221
+ if (format === "png") {
1222
+ const writeResult = await writeFileBinary(output, new Resvg(svg, { font: { loadSystemFonts: true } }).render().asPng());
1223
+ if (!writeResult.ok) return {
1224
+ ok: false,
1225
+ error: writeResult.error
1226
+ };
1227
+ } else {
1228
+ const writeResult = await writeFile(output, svg);
1229
+ if (!writeResult.ok) return {
1230
+ ok: false,
1231
+ error: writeResult.error
1232
+ };
1233
+ }
1234
+ }
1235
+ return {
1236
+ ok: true,
1237
+ value: void 0
1238
+ };
1239
+ }
1240
+
1241
+ //#endregion
1242
+ //#region src/generator/valibot/generator/relation-valibot-code.ts
1243
+ /**
1244
+ * Generates Valibot relation schema code from a relation schema AST extraction.
1245
+ *
1246
+ * @param schema - The relation schema to generate code for.
1247
+ * @param withType - Whether to include type definition.
1248
+ * @returns The generated Valibot relation schema code.
1249
+ */
1250
+ function relationValibotCode(schema, withType) {
1251
+ const base = schema.baseName;
1252
+ const relName = `${schema.name}Schema`;
1253
+ const baseSchema = `${makeCapitalized$1(base)}Schema`;
1254
+ const fields = schema.fields.map((f) => `${f.name}:${f.definition}`).join(",");
1255
+ const objectType = schema.objectType === "strict" ? "strictObject" : schema.objectType === "loose" ? "looseObject" : "object";
1256
+ const obj = `\nexport const ${makeCapitalized$1(relName)} = v.${objectType}({...${baseSchema}.entries,${fields}})`;
1257
+ if (withType) return `${obj}\n\n${inferInput(schema.name)}\n`;
1258
+ return `${obj}`;
1259
+ }
1260
+
1261
+ //#endregion
1262
+ //#region src/generator/valibot/generator/valibot.ts
1263
+ /**
1264
+ * Generates a Valibot schema for a given schema and config.
1265
+ *
1266
+ * @param schema - The schema to generate code for.
1267
+ * @param comment - Whether to include comments in the generated code.
1268
+ * @returns The generated Valibot schema.
1269
+ */
1270
+ function valibot(schema, comment) {
1271
+ const wrapperType = schema.objectType === "strict" ? "strictObject" : schema.objectType === "loose" ? "looseObject" : "object";
1272
+ const objectCode = makeValibotObject(fieldDefinitions(schema, comment), wrapperType);
1273
+ return `export const ${makeCapitalized(schema.name)}Schema = ${objectCode}`;
1274
+ }
1275
+
1276
+ //#endregion
1277
+ //#region src/generator/valibot/generator/valibot-code.ts
1278
+ /**
1279
+ * Generates Valibot code for a given schema and config.
1280
+ *
1281
+ * @param schema - The schema to generate code for.
1282
+ * @param comment - Whether to include comments in the generated code.
1283
+ * @param type - Whether to include type information in the generated code.
1284
+ * @returns The generated Valibot code.
1285
+ */
1286
+ function valibotCode(schema, comment, type) {
1287
+ const valibotSchema = valibot(schema, comment);
1288
+ if (type) return `${valibotSchema}\n\n${inferInput(schema.name)}\n`;
1289
+ return `${valibotSchema}\n`;
1290
+ }
1291
+
1292
+ //#endregion
1293
+ //#region src/generator/valibot/index.ts
1294
+ /**
1295
+ * Generate Valibot schema
1296
+ * @param code - The code to generate Valibot schema from
1297
+ * @param output - The output file path
1298
+ * @param comment - Whether to include comments in the generated code
1299
+ * @param type - Whether to include type information in the generated code
1300
+ */
1301
+ async function sizukuValibot(code, output, comment, type, relation) {
1302
+ const baseSchemas = extractSchemas(code, "valibot");
1303
+ const relationSchemas = extractRelationSchemas(code, "valibot");
1304
+ const valibotGeneratedCode = [
1305
+ "import * as v from 'valibot'",
1306
+ "",
1307
+ ...baseSchemas.map((schema) => valibotCode(schema, comment ?? false, type ?? false)),
1308
+ ...relation ? relationSchemas.map((schema) => relationValibotCode(schema, type ?? false)) : []
1309
+ ].join("\n");
1310
+ const mkdirResult = await mkdir(path.dirname(output));
1311
+ if (!mkdirResult.ok) return {
1312
+ ok: false,
1313
+ error: mkdirResult.error
1314
+ };
1315
+ const fmtResult = await fmt(valibotGeneratedCode);
1316
+ if (!fmtResult.ok) return {
1317
+ ok: false,
1318
+ error: fmtResult.error
1319
+ };
1320
+ const writeFileResult = await writeFile(output, fmtResult.value);
1321
+ if (!writeFileResult.ok) return {
1322
+ ok: false,
1323
+ error: writeFileResult.error
1324
+ };
1325
+ return {
1326
+ ok: true,
1327
+ value: void 0
1328
+ };
1329
+ }
1330
+
1331
+ //#endregion
1332
+ //#region src/generator/zod/generator/relation-zod-code.ts
1333
+ /**
1334
+ * Generates Zod relation schema code from a relation schema AST extraction.
1335
+ *
1336
+ * @param schema - The relation schema to generate code for.
1337
+ * @param withType - Whether to include type definition.
1338
+ * @returns The generated Zod relation schema code.
1339
+ */
1340
+ function relationZodCode(schema, withType) {
1341
+ const base = schema.baseName;
1342
+ const relName = `${schema.name}Schema`;
1343
+ const baseSchema = `${makeCapitalized$1(base)}Schema`;
1344
+ const fields = schema.fields.map((f) => `${f.name}:${f.definition}`).join(",");
1345
+ const objectType = schema.objectType === "strict" ? "strictObject" : schema.objectType === "loose" ? "looseObject" : "object";
1346
+ const obj = `\nexport const ${makeCapitalized$1(relName)} = z.${objectType}({...${baseSchema}.shape,${fields}})`;
1347
+ if (withType) return `${obj}\n\n${infer(schema.name)}\n`;
1348
+ return `${obj}`;
1349
+ }
1350
+
1351
+ //#endregion
1352
+ //#region src/generator/zod/generator/zod.ts
1353
+ /**
1354
+ * Generates a Zod schema for a given schema and config.
1355
+ *
1356
+ * @param schema - The schema to generate code for.
1357
+ * @param comment - Whether to include comments in the generated code.
1358
+ * @returns The generated Zod schema.
1359
+ */
1360
+ function zod(schema, comment) {
1361
+ const wrapperType = schema.objectType === "strict" ? "strictObject" : schema.objectType === "loose" ? "looseObject" : "object";
1362
+ const objectCode = makeZodObject(fieldDefinitions(schema, comment), wrapperType);
1363
+ return `export const ${makeCapitalized(schema.name)}Schema = ${objectCode}`;
1364
+ }
1365
+
1366
+ //#endregion
1367
+ //#region src/generator/zod/generator/zod-code.ts
1368
+ /**
1369
+ * Generates Zod code for a given schema and config.
1370
+ *
1371
+ * @param schema - The schema to generate code for.
1372
+ * @param comment - Whether to include comments in the generated code.
1373
+ * @param type - Whether to include type information in the generated code.
1374
+ * @returns The generated Zod code.
1375
+ */
1376
+ function zodCode(schema, comment, type) {
1377
+ const zodSchema = zod(schema, comment);
1378
+ if (type) return `${zodSchema}\n\n${infer(schema.name)}\n`;
1379
+ return `${zodSchema}\n`;
1380
+ }
1381
+
1382
+ //#endregion
1383
+ //#region src/generator/zod/index.ts
1384
+ /**
1385
+ * Generate Zod schema
1386
+ * @param code - The code to generate Zod schema from
1387
+ * @param output - The output file path
1388
+ * @param comment - Whether to include comments in the generated code
1389
+ * @param type - Whether to include type information in the generated code
1390
+ * @param zod - The Zod version to use
1391
+ */
1392
+ async function sizukuZod(code, output, comment, type, zod, relation) {
1393
+ const importLine = zod === "mini" ? `import * as z from 'zod/mini'` : zod === "@hono/zod-openapi" ? `import { z } from '@hono/zod-openapi'` : `import * as z from 'zod'`;
1394
+ const baseSchemas = extractSchemas(code, "zod");
1395
+ const relationSchemas = extractRelationSchemas(code, "zod");
1396
+ const zodGeneratedCode = [
1397
+ importLine,
1398
+ "",
1399
+ ...baseSchemas.map((schema) => zodCode(schema, comment ?? false, type ?? false)),
1400
+ ...relation ? relationSchemas.map((schema) => relationZodCode(schema, type ?? false)) : []
1401
+ ].join("\n");
1402
+ const mkdirResult = await mkdir(path.dirname(output));
1403
+ if (!mkdirResult.ok) return {
1404
+ ok: false,
1405
+ error: mkdirResult.error
1406
+ };
1407
+ const fmtResult = await fmt(zodGeneratedCode);
1408
+ if (!fmtResult.ok) return {
1409
+ ok: false,
1410
+ error: fmtResult.error
1411
+ };
1412
+ const writeFileResult = await writeFile(output, fmtResult.value);
1413
+ if (!writeFileResult.ok) return {
1414
+ ok: false,
1415
+ error: writeFileResult.error
1416
+ };
1417
+ return {
1418
+ ok: true,
1419
+ value: void 0
1420
+ };
1421
+ }
1422
+
1423
+ //#endregion
1424
+ //#region src/shared/fs/index.ts
1425
+ function readFileSync(path) {
1426
+ try {
1427
+ return {
1428
+ ok: true,
1429
+ value: fs.readFileSync(path, "utf-8")
1430
+ };
1431
+ } catch (e) {
1432
+ return {
1433
+ ok: false,
1434
+ error: e instanceof Error ? e.message : String(e)
1435
+ };
1436
+ }
1437
+ }
1438
+
1439
+ //#endregion
1440
+ //#region src/index.ts
1441
+ async function main() {
1442
+ const configResult = await config();
1443
+ if (!configResult.ok) return {
1444
+ ok: false,
1445
+ error: configResult.error
1446
+ };
1447
+ const c = configResult.value;
1448
+ const contentResult = readFileSync(c.input);
1449
+ if (!contentResult.ok) return {
1450
+ ok: false,
1451
+ error: contentResult.error
1452
+ };
1453
+ const lines = contentResult.value.split("\n");
1454
+ const codeStart = lines.findIndex((line) => !line.trim().startsWith("import") && line.trim() !== "");
1455
+ const code = lines.slice(codeStart);
1456
+ const zodMessage = c.zod?.output ? await (async () => {
1457
+ const zodConfig = c.zod;
1458
+ if (!zodConfig?.output) return {
1459
+ ok: false,
1460
+ error: "Zod config is missing"
1461
+ };
1462
+ const zodResult = await sizukuZod(code, zodConfig.output, zodConfig.comment, zodConfig.type, zodConfig.zod, zodConfig.relation);
1463
+ if (!zodResult.ok) return {
1464
+ ok: false,
1465
+ error: zodResult.error
1466
+ };
1467
+ return {
1468
+ ok: true,
1469
+ value: `Generated Zod schema at: ${zodConfig.output}`
1470
+ };
1471
+ })() : null;
1472
+ if (zodMessage && !zodMessage.ok) return {
1473
+ ok: false,
1474
+ error: zodMessage.error
1475
+ };
1476
+ const valibotMessage = c.valibot?.output ? await (async () => {
1477
+ const valibotConfig = c.valibot;
1478
+ if (!valibotConfig?.output) return {
1479
+ ok: false,
1480
+ error: "Valibot config is missing"
1481
+ };
1482
+ const valibotResult = await sizukuValibot(code, valibotConfig.output, valibotConfig.comment, valibotConfig.type, valibotConfig.relation);
1483
+ if (!valibotResult.ok) return {
1484
+ ok: false,
1485
+ error: valibotResult.error
1486
+ };
1487
+ return {
1488
+ ok: true,
1489
+ value: `Generated Valibot schema at: ${valibotConfig.output}`
1490
+ };
1491
+ })() : null;
1492
+ if (valibotMessage && !valibotMessage.ok) return {
1493
+ ok: false,
1494
+ error: valibotMessage.error
1495
+ };
1496
+ const arktypeMessage = c.arktype?.output ? await (async () => {
1497
+ const arktypeConfig = c.arktype;
1498
+ if (!arktypeConfig?.output) return {
1499
+ ok: false,
1500
+ error: "ArkType config is missing"
1501
+ };
1502
+ const arktypeResult = await sizukuArktype(code, arktypeConfig.output, arktypeConfig.comment, arktypeConfig.type);
1503
+ if (!arktypeResult.ok) return {
1504
+ ok: false,
1505
+ error: arktypeResult.error
1506
+ };
1507
+ return {
1508
+ ok: true,
1509
+ value: `Generated ArkType schema at: ${arktypeConfig.output}`
1510
+ };
1511
+ })() : null;
1512
+ if (arktypeMessage && !arktypeMessage.ok) return {
1513
+ ok: false,
1514
+ error: arktypeMessage.error
1515
+ };
1516
+ const effectMessage = c.effect?.output ? await (async () => {
1517
+ const effectConfig = c.effect;
1518
+ if (!effectConfig?.output) return {
1519
+ ok: false,
1520
+ error: "Effect config is missing"
1521
+ };
1522
+ const effectResult = await sizukuEffect(code, effectConfig.output, effectConfig.comment, effectConfig.type);
1523
+ if (!effectResult.ok) return {
1524
+ ok: false,
1525
+ error: effectResult.error
1526
+ };
1527
+ return {
1528
+ ok: true,
1529
+ value: `Generated Effect schema at: ${effectConfig.output}`
1530
+ };
1531
+ })() : null;
1532
+ if (effectMessage && !effectMessage.ok) return {
1533
+ ok: false,
1534
+ error: effectMessage.error
1535
+ };
1536
+ const mermaidMessage = c.mermaid?.output ? await (async () => {
1537
+ const mermaidConfig = c.mermaid;
1538
+ if (!mermaidConfig?.output) return {
1539
+ ok: false,
1540
+ error: "Mermaid config is missing"
1541
+ };
1542
+ const mermaidResult = await sizukuMermaidER(code, mermaidConfig.output);
1543
+ if (!mermaidResult.ok) return {
1544
+ ok: false,
1545
+ error: mermaidResult.error
1546
+ };
1547
+ return {
1548
+ ok: true,
1549
+ value: `Generated Mermaid ER at: ${mermaidConfig.output}`
1550
+ };
1551
+ })() : null;
1552
+ if (mermaidMessage && !mermaidMessage.ok) return {
1553
+ ok: false,
1554
+ error: mermaidMessage.error
1555
+ };
1556
+ const dbmlMessage = c.dbml?.output ? await (async () => {
1557
+ const dbmlConfig = c.dbml;
1558
+ if (!dbmlConfig?.output) return {
1559
+ ok: false,
1560
+ error: "DBML config is missing"
1561
+ };
1562
+ const dbmlResult = await sizukuDBML(code, dbmlConfig.output);
1563
+ if (!dbmlResult.ok) return {
1564
+ ok: false,
1565
+ error: dbmlResult.error
1566
+ };
1567
+ return {
1568
+ ok: true,
1569
+ value: `Generated DBML schema at: ${dbmlConfig.output}`
1570
+ };
1571
+ })() : null;
1572
+ if (dbmlMessage && !dbmlMessage.ok) return {
1573
+ ok: false,
1574
+ error: dbmlMessage.error
1575
+ };
1576
+ const svgMessage = c.svg?.output ? await (async () => {
1577
+ const svgConfig = c.svg;
1578
+ if (!svgConfig?.output) return {
1579
+ ok: false,
1580
+ error: "SVG config is missing"
1581
+ };
1582
+ const svgResult = await sizukuSVG(code, svgConfig.output, svgConfig.format);
1583
+ if (!svgResult.ok) return {
1584
+ ok: false,
1585
+ error: svgResult.error
1586
+ };
1587
+ return {
1588
+ ok: true,
1589
+ value: `Generated SVG diagram at: ${svgConfig.output}`
1590
+ };
1591
+ })() : null;
1592
+ if (svgMessage && !svgMessage.ok) return {
1593
+ ok: false,
1594
+ error: svgMessage.error
1595
+ };
1596
+ return {
1597
+ ok: true,
1598
+ value: [
1599
+ zodMessage?.ok ? zodMessage.value : null,
1600
+ valibotMessage?.ok ? valibotMessage.value : null,
1601
+ arktypeMessage?.ok ? arktypeMessage.value : null,
1602
+ effectMessage?.ok ? effectMessage.value : null,
1603
+ mermaidMessage?.ok ? mermaidMessage.value : null,
1604
+ dbmlMessage?.ok ? dbmlMessage.value : null,
1605
+ svgMessage?.ok ? svgMessage.value : null
1606
+ ].filter((msg) => msg !== null).join("\n")
1607
+ };
1608
+ }
1609
+ main().then((result) => {
1610
+ if (result?.ok) console.log(result.value);
1611
+ else console.error(result?.error);
1612
+ });
1613
+
1614
+ //#endregion
1615
+ export { main };