on-zero 0.4.1 → 0.4.3

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 (41) hide show
  1. package/dist/cjs/generate-helpers.cjs +309 -0
  2. package/dist/cjs/generate-helpers.native.js +451 -0
  3. package/dist/cjs/generate-helpers.native.js.map +1 -0
  4. package/dist/cjs/generate-lite.cjs +150 -0
  5. package/dist/cjs/generate-lite.native.js +269 -0
  6. package/dist/cjs/generate-lite.native.js.map +1 -0
  7. package/dist/cjs/generate-lite.test.cjs +229 -0
  8. package/dist/cjs/generate-lite.test.native.js +234 -0
  9. package/dist/cjs/generate-lite.test.native.js.map +1 -0
  10. package/dist/cjs/generate.cjs +16 -285
  11. package/dist/cjs/generate.native.js +18 -432
  12. package/dist/cjs/generate.native.js.map +1 -1
  13. package/dist/esm/generate-helpers.mjs +272 -0
  14. package/dist/esm/generate-helpers.mjs.map +1 -0
  15. package/dist/esm/generate-helpers.native.js +411 -0
  16. package/dist/esm/generate-helpers.native.js.map +1 -0
  17. package/dist/esm/generate-lite.mjs +127 -0
  18. package/dist/esm/generate-lite.mjs.map +1 -0
  19. package/dist/esm/generate-lite.native.js +243 -0
  20. package/dist/esm/generate-lite.native.js.map +1 -0
  21. package/dist/esm/generate-lite.test.mjs +230 -0
  22. package/dist/esm/generate-lite.test.mjs.map +1 -0
  23. package/dist/esm/generate-lite.test.native.js +232 -0
  24. package/dist/esm/generate-lite.test.native.js.map +1 -0
  25. package/dist/esm/generate.mjs +6 -275
  26. package/dist/esm/generate.mjs.map +1 -1
  27. package/dist/esm/generate.native.js +9 -423
  28. package/dist/esm/generate.native.js.map +1 -1
  29. package/package.json +7 -2
  30. package/src/generate-helpers.ts +440 -0
  31. package/src/generate-lite.test.ts +310 -0
  32. package/src/generate-lite.ts +333 -0
  33. package/src/generate.ts +23 -415
  34. package/types/generate-helpers.d.ts +42 -0
  35. package/types/generate-helpers.d.ts.map +1 -0
  36. package/types/generate-lite.d.ts +40 -0
  37. package/types/generate-lite.d.ts.map +1 -0
  38. package/types/generate-lite.test.d.ts +2 -0
  39. package/types/generate-lite.test.d.ts.map +1 -0
  40. package/types/generate.d.ts +1 -6
  41. package/types/generate.d.ts.map +1 -1
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+
3
+ var import_vitest = require("vitest"),
4
+ import_generate_lite = require("./generate-lite.native.js");
5
+ function makeParse(table) {
6
+ return function (_src, path) {
7
+ var entry = table[path];
8
+ if (!entry) throw new Error(`no lite ast fixture for ${path}`);
9
+ return entry;
10
+ };
11
+ }
12
+ var DIR = "/proj/src/data";
13
+ (0, import_vitest.describe)("generateLite", function () {
14
+ (0, import_vitest.test)("emits models.ts, syncedMutations.ts, and README.md from inline types", function () {
15
+ var files = {
16
+ [`${DIR}/models/todo.ts`]: "// fake source, parser returns fixture",
17
+ [`${DIR}/models/user.ts`]: "// fake source, parser returns fixture"
18
+ },
19
+ fixtures = {
20
+ [`${DIR}/models/todo.ts`]: {
21
+ mutations: [{
22
+ modelName: "todo",
23
+ handlers: [{
24
+ name: "toggle",
25
+ paramTypeText: "{ id: string; isActive: boolean }"
26
+ }, {
27
+ name: "rename",
28
+ paramTypeText: "{ id: string; title: string }"
29
+ }],
30
+ schema: null
31
+ }],
32
+ queries: []
33
+ },
34
+ [`${DIR}/models/user.ts`]: {
35
+ mutations: [{
36
+ modelName: "user",
37
+ handlers: [{
38
+ name: "finishOnboarding",
39
+ // null = no second param / void
40
+ paramTypeText: null
41
+ }],
42
+ schema: null
43
+ }],
44
+ queries: []
45
+ }
46
+ },
47
+ result = (0, import_generate_lite.generateLite)({
48
+ files,
49
+ dir: DIR,
50
+ parse: makeParse(fixtures)
51
+ });
52
+ (0, import_vitest.expect)(Object.keys(result.files).sort()).toEqual(["README.md", "models.ts", "syncedMutations.ts"]);
53
+ var models = result.files["models.ts"];
54
+ (0, import_vitest.expect)(models).toContain("import * as todo from '../models/todo'"), (0, import_vitest.expect)(models).toContain("import * as userPublic from '../models/user'"), (0, import_vitest.expect)(models).toContain("export const models = {");
55
+ var syncedMutations = result.files["syncedMutations.ts"];
56
+ (0, import_vitest.expect)(syncedMutations).toContain("toggle:"), (0, import_vitest.expect)(syncedMutations).toContain("v.object({"), (0, import_vitest.expect)(syncedMutations).toContain("id: v.string()"), (0, import_vitest.expect)(syncedMutations).toContain("isActive: v.boolean()"), (0, import_vitest.expect)(syncedMutations).toContain("rename:"), (0, import_vitest.expect)(syncedMutations).toContain("title: v.string()"), (0, import_vitest.expect)(syncedMutations).toContain("finishOnboarding: v.void_()"), (0, import_vitest.expect)(result.modelCount).toBe(2), (0, import_vitest.expect)(result.schemaCount).toBe(0), (0, import_vitest.expect)(result.mutationCount).toBe(3);
57
+ }), (0, import_vitest.test)("falls back to v.unknown() for type references", function () {
58
+ var files = {
59
+ [`${DIR}/models/post.ts`]: "// fake"
60
+ },
61
+ fixtures = {
62
+ [`${DIR}/models/post.ts`]: {
63
+ mutations: [{
64
+ modelName: "post",
65
+ handlers: [{
66
+ name: "archive",
67
+ // bare type reference — parseTypeString returns null, so
68
+ // generate-lite should fall back to v.unknown() rather than
69
+ // attempting cross-file type resolution.
70
+ paramTypeText: "ArchiveParams"
71
+ }, {
72
+ name: "publish",
73
+ // primitive, should resolve
74
+ paramTypeText: "string"
75
+ }],
76
+ schema: null
77
+ }],
78
+ queries: []
79
+ }
80
+ },
81
+ result = (0, import_generate_lite.generateLite)({
82
+ files,
83
+ dir: DIR,
84
+ parse: makeParse(fixtures)
85
+ }),
86
+ synced = result.files["syncedMutations.ts"];
87
+ (0, import_vitest.expect)(synced).toContain("archive: v.unknown()"), (0, import_vitest.expect)(synced).toContain("publish: v.string()");
88
+ }), (0, import_vitest.test)("emits query files with v.unknown() fallback for references", function () {
89
+ var files = {
90
+ [`${DIR}/models/post.ts`]: "// fake",
91
+ [`${DIR}/queries/post.ts`]: "// fake"
92
+ },
93
+ fixtures = {
94
+ [`${DIR}/models/post.ts`]: {
95
+ mutations: [],
96
+ queries: []
97
+ },
98
+ [`${DIR}/queries/post.ts`]: {
99
+ mutations: [],
100
+ queries: [
101
+ // no-arg query → void
102
+ {
103
+ name: "allPosts",
104
+ paramTypeText: null
105
+ },
106
+ // inline object → real validator
107
+ {
108
+ name: "postById",
109
+ paramTypeText: "{ id: string }"
110
+ },
111
+ // primitive
112
+ {
113
+ name: "byAuthorId",
114
+ paramTypeText: "string"
115
+ },
116
+ // type reference → fallback
117
+ {
118
+ name: "filtered",
119
+ paramTypeText: "PostFilter"
120
+ },
121
+ // permission should be skipped
122
+ {
123
+ name: "permission",
124
+ paramTypeText: null
125
+ }]
126
+ }
127
+ },
128
+ result = (0, import_generate_lite.generateLite)({
129
+ files,
130
+ dir: DIR,
131
+ parse: makeParse(fixtures)
132
+ });
133
+ (0, import_vitest.expect)(result.files["groupedQueries.ts"]).toBeDefined(), (0, import_vitest.expect)(result.files["syncedQueries.ts"]).toBeDefined();
134
+ var grouped = result.files["groupedQueries.ts"];
135
+ (0, import_vitest.expect)(grouped).toContain("export * as post from '../queries/post'");
136
+ var synced = result.files["syncedQueries.ts"];
137
+ (0, import_vitest.expect)(synced).toContain("allPosts: defineQuery(() => Queries.post.allPosts())"), (0, import_vitest.expect)(synced).toContain("postById: defineQuery("), (0, import_vitest.expect)(synced).toContain("id: v.string()"), (0, import_vitest.expect)(synced).toContain("byAuthorId: defineQuery("), (0, import_vitest.expect)(synced).toMatch(/byAuthorId: defineQuery\(\s*v\.string\(\)/), (0, import_vitest.expect)(synced).toContain("filtered: defineQuery("), (0, import_vitest.expect)(synced).toMatch(/filtered: defineQuery\(\s*v\.unknown\(\)/), (0, import_vitest.expect)(synced).not.toContain("permission: defineQuery"), (0, import_vitest.expect)(result.queryCount).toBe(4);
138
+ }), (0, import_vitest.test)("emits types.ts and tables.ts when a model declares a schema inline", function () {
139
+ var files = {
140
+ [`${DIR}/models/task.ts`]: "// fake"
141
+ },
142
+ fixtures = {
143
+ [`${DIR}/models/task.ts`]: {
144
+ mutations: [{
145
+ modelName: "task",
146
+ handlers: [],
147
+ schema: {
148
+ tableName: "task",
149
+ primaryKeys: ["id"],
150
+ columns: [{
151
+ name: "id",
152
+ builderText: "string()"
153
+ }, {
154
+ name: "title",
155
+ builderText: "string()"
156
+ }, {
157
+ name: "priority",
158
+ builderText: "number()"
159
+ }, {
160
+ name: "done",
161
+ builderText: "boolean()"
162
+ }, {
163
+ name: "note",
164
+ builderText: "string().optional()"
165
+ }]
166
+ }
167
+ }],
168
+ queries: []
169
+ }
170
+ },
171
+ result = (0, import_generate_lite.generateLite)({
172
+ files,
173
+ dir: DIR,
174
+ parse: makeParse(fixtures)
175
+ });
176
+ (0, import_vitest.expect)(result.schemaCount).toBe(1), (0, import_vitest.expect)(result.files["types.ts"]).toBeDefined(), (0, import_vitest.expect)(result.files["tables.ts"]).toBeDefined();
177
+ var types = result.files["types.ts"];
178
+ (0, import_vitest.expect)(types).toContain("export type Task = TableInsertRow<typeof schema.task>");
179
+ var tables = result.files["tables.ts"];
180
+ (0, import_vitest.expect)(tables).toContain("export { schema as task } from '../models/task'");
181
+ var synced = result.files["syncedMutations.ts"];
182
+ (0, import_vitest.expect)(synced).toContain("insert:"), (0, import_vitest.expect)(synced).toContain("update:"), (0, import_vitest.expect)(synced).toContain("delete:"), (0, import_vitest.expect)(result.mutationCount).toBe(3);
183
+ }), (0, import_vitest.test)("ignores nested files and non-ts files inside the models directory", function () {
184
+ var files = {
185
+ [`${DIR}/models/post.ts`]: "// fake",
186
+ [`${DIR}/models/README.md`]: "not a model",
187
+ [`${DIR}/models/helpers/util.ts`]: "nested should be ignored",
188
+ [`${DIR}/models/post.d.ts`]: "declaration file, ignored"
189
+ },
190
+ fixtures = {
191
+ [`${DIR}/models/post.ts`]: {
192
+ mutations: [{
193
+ modelName: "post",
194
+ handlers: [],
195
+ schema: null
196
+ }],
197
+ queries: []
198
+ }
199
+ },
200
+ result = (0, import_generate_lite.generateLite)({
201
+ files,
202
+ dir: DIR,
203
+ parse: makeParse(fixtures)
204
+ });
205
+ (0, import_vitest.expect)(result.modelCount).toBe(1);
206
+ var models = result.files["models.ts"];
207
+ (0, import_vitest.expect)(models).toContain("import * as post from '../models/post'"), (0, import_vitest.expect)(models).not.toContain("util"), (0, import_vitest.expect)(models).not.toContain("README");
208
+ }), (0, import_vitest.test)("infers mutations/ directory when present", function () {
209
+ var files = {
210
+ [`${DIR}/mutations/post.ts`]: "// fake"
211
+ },
212
+ fixtures = {
213
+ [`${DIR}/mutations/post.ts`]: {
214
+ mutations: [{
215
+ modelName: "post",
216
+ handlers: [{
217
+ name: "publish",
218
+ paramTypeText: "{ id: string }"
219
+ }],
220
+ schema: null
221
+ }],
222
+ queries: []
223
+ }
224
+ },
225
+ result = (0, import_generate_lite.generateLite)({
226
+ files,
227
+ dir: DIR,
228
+ parse: makeParse(fixtures)
229
+ }),
230
+ models = result.files["models.ts"];
231
+ (0, import_vitest.expect)(models).toContain("from '../mutations/post'");
232
+ });
233
+ });
234
+ //# sourceMappingURL=generate-lite.test.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["import_vitest","require","import_generate_lite","makeParse","table","_src","path","entry","Error","DIR","describe","test","files","fixtures","mutations","modelName","handlers","name","paramTypeText","schema","queries","result","generateLite","dir","parse","expect","Object","keys","sort","toEqual","models","toContain","syncedMutations","modelCount","toBe","schemaCount","mutationCount","synced","toBeDefined","grouped","toMatch","not","queryCount","tableName","primaryKeys","columns","builderText","types","tables"],"sources":["../../src/generate-lite.test.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -38,7 +38,8 @@ __export(generate_exports, {
38
38
  module.exports = __toCommonJS(generate_exports);
39
39
  var import_node_crypto = require("node:crypto"),
40
40
  import_node_fs = require("node:fs"),
41
- import_node_path = require("node:path");
41
+ import_node_path = require("node:path"),
42
+ import_generate_helpers = require("./generate-helpers.cjs");
42
43
  const hash = s => (0, import_node_crypto.createHash)("sha256").update(s).digest("hex");
43
44
  let generateCache = {},
44
45
  generateCachePath = "";
@@ -75,157 +76,6 @@ function writeFileIfChanged(filePath, content) {
75
76
  const contentHash = hash(content);
76
77
  return generateCache[filePath] === contentHash && (0, import_node_fs.existsSync)(filePath) ? !1 : ((0, import_node_fs.writeFileSync)(filePath, content, "utf-8"), generateCache[filePath] = contentHash, !0);
77
78
  }
78
- function generateModelsFile(modelFiles, modelsDirName) {
79
- const modelNames = modelFiles.map(f => (0, import_node_path.basename)(f, ".ts")).sort(),
80
- getImportName = name => name === "user" ? "userPublic" : name,
81
- imports = modelNames.map(name => `import * as ${getImportName(name)} from '../${modelsDirName}/${name}'`).join(`
82
- `),
83
- modelsObj = `export const models = {
84
- ${[...modelNames].sort((a, b) => getImportName(a).localeCompare(getImportName(b))).map(name => ` ${getImportName(name)},`).join(`
85
- `)}
86
- }`;
87
- return `// auto-generated by: on-zero generate
88
- ${imports}
89
-
90
- ${modelsObj}
91
- `;
92
- }
93
- function generateTypesFile(modelFiles) {
94
- const modelNames = modelFiles.map(f => (0, import_node_path.basename)(f, ".ts")).sort(),
95
- getSchemaName = name => name === "user" ? "userPublic" : name;
96
- return `import type { TableInsertRow, TableUpdateRow } from 'on-zero'
97
- import type * as schema from './tables'
98
-
99
- ${modelNames.map(name => {
100
- const pascalName = name.charAt(0).toUpperCase() + name.slice(1),
101
- schemaName = getSchemaName(name);
102
- return `export type ${pascalName} = TableInsertRow<typeof schema.${schemaName}>
103
- export type ${pascalName}Update = TableUpdateRow<typeof schema.${schemaName}>`;
104
- }).join(`
105
-
106
- `)}
107
- `;
108
- }
109
- function generateTablesFile(modelFiles, modelsDirName) {
110
- const modelNames = modelFiles.map(f => (0, import_node_path.basename)(f, ".ts")).sort(),
111
- getExportName = name => name === "user" ? "userPublic" : name;
112
- return `// auto-generated by: on-zero generate
113
-
114
- ${modelNames.map(name => `export { schema as ${getExportName(name)} } from '../${modelsDirName}/${name}'`).join(`
115
- `)}
116
- `;
117
- }
118
- function generateReadmeFile() {
119
- return `# generated
120
-
121
- this folder is auto-generated by on-zero. do not edit files here directly.
122
-
123
- ## what's generated
124
-
125
- - \`models.ts\` - exports all models from ../models
126
- - \`types.ts\` - typescript types derived from table schemas
127
- - \`tables.ts\` - exports table schemas for type inference
128
- - \`groupedQueries.ts\` - namespaced query re-exports for client setup
129
- - \`syncedQueries.ts\` - namespaced syncedQuery wrappers for server setup
130
- - \`syncedMutations.ts\` - valibot validators for mutation args (server auto-validation)
131
-
132
- ## usage guidelines
133
-
134
- **do not import generated files outside of the data folder.**
135
-
136
- ### queries
137
-
138
- write your queries as plain functions in \`../queries/\` and import them directly:
139
-
140
- \`\`\`ts
141
- // \u2705 good - import from queries
142
- import { channelMessages } from '~/data/queries/message'
143
- \`\`\`
144
-
145
- the generated query files are only used internally by zero client/server setup.
146
-
147
- ### types
148
-
149
- you can import types from this folder, but prefer re-exporting from \`../types.ts\`:
150
-
151
- \`\`\`ts
152
- // \u274C okay but not preferred
153
- import type { Message } from '~/data/generated/types'
154
-
155
- // \u2705 better - re-export from types.ts
156
- import type { Message } from '~/data/types'
157
- \`\`\`
158
-
159
- ## regeneration
160
-
161
- files are regenerated when you run:
162
-
163
- \`\`\`bash
164
- bun on-zero generate
165
- \`\`\`
166
-
167
- or in watch mode:
168
-
169
- \`\`\`bash
170
- bun on-zero generate --watch
171
- \`\`\`
172
-
173
- ## more info
174
-
175
- see the [on-zero readme](./node_modules/on-zero/README.md) for full documentation.
176
- `;
177
- }
178
- function generateGroupedQueriesFile(queries) {
179
- return `/**
180
- * auto-generated by: on-zero generate
181
- *
182
- * grouped query re-exports for minification-safe query identity.
183
- * this file re-exports all query modules - while this breaks tree-shaking,
184
- * queries are typically small and few in number even in larger apps.
185
- */
186
- ${[...new Set(queries.map(q => q.sourceFile))].sort().map(file => `export * as ${file} from '../queries/${file}'`).join(`
187
- `)}
188
- `;
189
- }
190
- function generateSyncedQueriesFile(queries) {
191
- const queryByFile = /* @__PURE__ */new Map();
192
- for (const q of queries) queryByFile.has(q.sourceFile) || queryByFile.set(q.sourceFile, []), queryByFile.get(q.sourceFile).push(q);
193
- const sortedFiles = Array.from(queryByFile.keys()).sort(),
194
- imports = `// auto-generated by: on-zero generate
195
- // server-side query definitions with validators
196
- import { defineQuery, defineQueries } from '@rocicorp/zero'
197
- import * as v from 'valibot'
198
- import * as Queries from './groupedQueries'
199
- `,
200
- namespaceDefs = sortedFiles.map(file => {
201
- const queryDefs = queryByFile.get(file).sort((a, b) => a.name.localeCompare(b.name)).map(q => {
202
- const validatorDef = q.valibotCode.trim();
203
- if (q.params === "void" || !validatorDef) return ` ${q.name}: defineQuery(() => Queries.${file}.${q.name}()),`;
204
- const indentedValidator = validatorDef.split(`
205
- `).map((line, i) => i === 0 ? line : ` ${line}`).join(`
206
- `);
207
- return ` ${q.name}: defineQuery(
208
- ${indentedValidator},
209
- ({ args }) => Queries.${file}.${q.name}(args)
210
- ),`;
211
- }).join(`
212
- `);
213
- return `const ${file} = {
214
- ${queryDefs}
215
- }`;
216
- }).join(`
217
-
218
- `),
219
- queriesObject = sortedFiles.map(file => ` ${file},`).join(`
220
- `);
221
- return `${imports}
222
- ${namespaceDefs}
223
-
224
- export const queries = defineQueries({
225
- ${queriesObject}
226
- })
227
- `;
228
- }
229
79
  function createTypeResolver(ts, files, dir) {
230
80
  const configPath = ts.findConfigFile(dir, ts.sys.fileExists, "tsconfig.json");
231
81
  let compilerOptions = {
@@ -392,7 +242,7 @@ function extractSchemaColumns(ts, sourceFile, columns, primaryKeys) {
392
242
  const colName = prop.name?.getText(sourceFile);
393
243
  if (!colName) continue;
394
244
  const initText = prop.initializer.getText(sourceFile),
395
- colType = parseColumnType(initText);
245
+ colType = (0, import_generate_helpers.parseColumnType)(initText);
396
246
  columns[colName] = colType;
397
247
  }
398
248
  }
@@ -401,127 +251,6 @@ function extractSchemaColumns(ts, sourceFile, columns, primaryKeys) {
401
251
  }
402
252
  visit(sourceFile);
403
253
  }
404
- function parseColumnType(initText) {
405
- const optional = initText.includes(".optional()");
406
- let type = "string";
407
- return initText.startsWith("number(") ? type = "number" : initText.startsWith("boolean(") ? type = "boolean" : initText.startsWith("json(") || initText.startsWith("json<") ? type = "json" : initText.startsWith("enumeration(") && (type = "enum"), {
408
- type,
409
- optional,
410
- customType: void 0
411
- };
412
- }
413
- function columnTypeToValibot(col) {
414
- let base = "v.string()";
415
- switch (col.type) {
416
- case "string":
417
- base = "v.string()";
418
- break;
419
- case "number":
420
- base = "v.number()";
421
- break;
422
- case "boolean":
423
- base = "v.boolean()";
424
- break;
425
- case "json":
426
- base = "v.unknown()";
427
- break;
428
- case "enum":
429
- base = "v.string()";
430
- break;
431
- }
432
- return col.optional ? `v.optional(v.nullable(${base}))` : base;
433
- }
434
- function shouldSkipObjectKey(name) {
435
- return name.startsWith("__@");
436
- }
437
- function formatObjectKey(name) {
438
- return /^[$A-Z_a-z][$\w]*$/.test(name) ? name : JSON.stringify(name);
439
- }
440
- function schemaColumnsToValibot(columns, primaryKeys, mode) {
441
- const entries = [];
442
- if (mode === "delete") for (const pk of primaryKeys) {
443
- const col = columns[pk];
444
- col && entries.push(`${formatObjectKey(pk)}: ${columnTypeToValibot({
445
- ...col,
446
- optional: !1
447
- })}`);
448
- } else if (mode === "update") for (const [name, col] of Object.entries(columns)) primaryKeys.includes(name) ? entries.push(`${formatObjectKey(name)}: ${columnTypeToValibot({
449
- ...col,
450
- optional: !1
451
- })}`) : entries.push(`${formatObjectKey(name)}: ${columnTypeToValibot({
452
- ...col,
453
- optional: !0
454
- })}`);else for (const [name, col] of Object.entries(columns)) entries.push(`${formatObjectKey(name)}: ${columnTypeToValibot(col)}`);
455
- return `v.object({
456
- ${entries.join(`,
457
- `)},
458
- })`;
459
- }
460
- function generateSyncedMutationsFile(modelMutations) {
461
- return `// auto-generated by: on-zero generate
462
- // mutation validators derived from model schemas and handler types
463
- import * as v from 'valibot'
464
-
465
- export const mutationValidators = {
466
- ${[...modelMutations].sort((a, b) => a.modelName.localeCompare(b.modelName)).map(model => {
467
- const entries = [];
468
- if (model.hasCRUD && Object.keys(model.columns).length > 0) for (const mode of ["insert", "update", "delete"]) if (model.custom.some(m => m.name === mode)) {
469
- const customMut = model.custom.find(m => m.name === mode);
470
- customMut.valibotCode ? entries.push(` ${mode}: ${extractValibotExpression(customMut.valibotCode)},`) : entries.push(` ${mode}: ${schemaColumnsToValibot(model.columns, model.primaryKeys, mode)},`);
471
- } else entries.push(` ${mode}: ${schemaColumnsToValibot(model.columns, model.primaryKeys, mode)},`);
472
- for (const mut of model.custom) if (!(model.hasCRUD && ["insert", "update", "delete", "upsert"].includes(mut.name))) {
473
- if (mut.paramType === "void" || !mut.valibotCode) {
474
- entries.push(` ${mut.name}: v.void_(),`);
475
- continue;
476
- }
477
- entries.push(` ${mut.name}: ${extractValibotExpression(mut.valibotCode)},`);
478
- }
479
- return ` ${model.modelName}: {
480
- ${entries.join(`
481
- `)}
482
- },`;
483
- }).join(`
484
- `)}
485
- }
486
- `;
487
- }
488
- function extractValibotExpression(valibotCode) {
489
- return valibotCode.trim() || "v.unknown()";
490
- }
491
- function parseTypeString(type) {
492
- if (type = type.trim(), type === "string") return "v.string()";
493
- if (type === "number") return "v.number()";
494
- if (type === "boolean") return "v.boolean()";
495
- if (type === "void" || type === "undefined") return "v.void_()";
496
- if (type === "null") return "v.null_()";
497
- if (type === "any" || type === "unknown") return "v.unknown()";
498
- if (type.startsWith("{") && type.endsWith("}")) {
499
- const inner = type.slice(1, -1).trim();
500
- if (!inner) return "v.object({})";
501
- const normalized = inner.replace(/\n/g, "; ").replace(/;\s*;/g, ";"),
502
- entries = [];
503
- for (const part of normalized.split(";")) {
504
- const trimmed = part.trim().replace(/,\s*$/, "");
505
- if (!trimmed) continue;
506
- const match = trimmed.match(/^(?:readonly\s+)?(\w+)(\?)?:\s*(.+)$/);
507
- if (!match) continue;
508
- const [, name, opt, typeStr] = match,
509
- parsed = parseTypeString(typeStr.trim());
510
- if (!parsed) return null;
511
- let val = parsed;
512
- opt && (val = `v.optional(${val})`), entries.push(`${formatObjectKey(name)}: ${val}`);
513
- }
514
- return entries.length === 0 ? "v.object({})" : `v.object({
515
- ${entries.join(`,
516
- `)},
517
- })`;
518
- }
519
- if (type.endsWith("[]")) {
520
- const inner = parseTypeString(type.slice(0, -2).trim());
521
- return inner ? `v.array(${inner})` : null;
522
- }
523
- return null;
524
- }
525
254
  function tsTypeToValibot(ts, checker, type, seen) {
526
255
  seen || (seen = /* @__PURE__ */new Set());
527
256
  const flags = type.getFlags();
@@ -560,11 +289,11 @@ function tsTypeToValibot(ts, checker, type, seen) {
560
289
  const entries = [];
561
290
  for (const prop of props2) {
562
291
  const name = prop.getName();
563
- if (shouldSkipObjectKey(name)) continue;
292
+ if ((0, import_generate_helpers.shouldSkipObjectKey)(name)) continue;
564
293
  const propType = resolveSymbolType(prop),
565
294
  isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
566
295
  let val = recurse(propType);
567
- isOptional && !val.startsWith("v.optional(") && (val = `v.optional(${val})`), entries.push(`${formatObjectKey(name)}: ${val}`);
296
+ isOptional && !val.startsWith("v.optional(") && (val = `v.optional(${val})`), entries.push(`${(0, import_generate_helpers.formatObjectKey)(name)}: ${val}`);
568
297
  }
569
298
  return entries.length === 0 ? "v.object({})" : `v.object({
570
299
  ${entries.join(`,
@@ -583,11 +312,11 @@ function tsTypeToValibot(ts, checker, type, seen) {
583
312
  const entries = [];
584
313
  for (const prop of props) {
585
314
  const name = prop.getName();
586
- if (shouldSkipObjectKey(name)) continue;
315
+ if ((0, import_generate_helpers.shouldSkipObjectKey)(name)) continue;
587
316
  const propType = resolveSymbolType(prop),
588
317
  isOptional = !!(prop.getFlags() & ts.SymbolFlags.Optional);
589
318
  let val = recurse(propType);
590
- isOptional && !val.startsWith("v.optional(") && (val = `v.optional(${val})`), entries.push(`${formatObjectKey(name)}: ${val}`);
319
+ isOptional && !val.startsWith("v.optional(") && (val = `v.optional(${val})`), entries.push(`${(0, import_generate_helpers.formatObjectKey)(name)}: ${val}`);
591
320
  }
592
321
  return entries.length === 0 ? "v.object({})" : `v.object({
593
322
  ${entries.join(`,
@@ -665,18 +394,20 @@ async function generate(options) {
665
394
  recursive: !0
666
395
  }), loadCache();
667
396
  const allModelFiles = (0, import_node_fs.readdirSync)(modelsDir).filter(f => f.endsWith(".ts")).sort(),
668
- filesWithSchema = allModelFiles.filter(f => (0, import_node_fs.readFileSync)((0, import_node_path.resolve)(modelsDir, f), "utf-8").includes("export const schema = table("));
669
- let filesChanged = [writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "models.ts"), generateModelsFile(allModelFiles, modelsDirName)),
397
+ filesWithSchema = allModelFiles.filter(f => (0, import_node_fs.readFileSync)((0, import_node_path.resolve)(modelsDir, f), "utf-8").includes("export const schema = table(")),
398
+ allModelNames = allModelFiles.map(f => (0, import_node_path.basename)(f, ".ts")),
399
+ schemaModelNames = filesWithSchema.map(f => (0, import_node_path.basename)(f, ".ts"));
400
+ let filesChanged = [writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "models.ts"), (0, import_generate_helpers.generateModelsFile)(allModelNames, modelsDirName)),
670
401
  // only generate types.ts and tables.ts when model files define schemas.
671
402
  // when using drizzle-zero CLI for schema generation, these files are
672
403
  // managed externally and should not be overwritten.
673
- ...(filesWithSchema.length > 0 ? [writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "types.ts"), generateTypesFile(filesWithSchema)), writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "tables.ts"), generateTablesFile(filesWithSchema, modelsDirName))] : []), writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "README.md"), generateReadmeFile())].filter(Boolean).length,
404
+ ...(filesWithSchema.length > 0 ? [writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "types.ts"), (0, import_generate_helpers.generateTypesFile)(schemaModelNames)), writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "tables.ts"), (0, import_generate_helpers.generateTablesFile)(schemaModelNames, modelsDirName))] : []), writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "README.md"), (0, import_generate_helpers.generateReadmeFile)())].filter(Boolean).length,
674
405
  queryCount = 0,
675
406
  mutationCount = 0;
676
407
  const ts = await import("typescript"),
677
408
  typeToValibot = paramType => {
678
409
  try {
679
- return parseTypeString(paramType.trim());
410
+ return (0, import_generate_helpers.parseTypeString)(paramType.trim());
680
411
  } catch {
681
412
  return null;
682
413
  }
@@ -735,8 +466,8 @@ async function generate(options) {
735
466
  }
736
467
  }
737
468
  queryCount = allQueries.length;
738
- const groupedChanged = writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "groupedQueries.ts"), generateGroupedQueriesFile(allQueries)),
739
- syncedChanged = writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "syncedQueries.ts"), generateSyncedQueriesFile(allQueries));
469
+ const groupedChanged = writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "groupedQueries.ts"), (0, import_generate_helpers.generateGroupedQueriesFile)(allQueries)),
470
+ syncedChanged = writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "syncedQueries.ts"), (0, import_generate_helpers.generateSyncedQueriesFile)(allQueries));
740
471
  groupedChanged && filesChanged++, syncedChanged && filesChanged++;
741
472
  }
742
473
  const allModelMutations = [],
@@ -797,7 +528,7 @@ async function generate(options) {
797
528
  }
798
529
  }
799
530
  for (const model of allModelMutations) model.hasCRUD && (mutationCount += 3), mutationCount += model.custom.filter(m => !model.hasCRUD || !["insert", "update", "delete", "upsert"].includes(m.name)).length;
800
- if (allModelMutations.length > 0 && writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "syncedMutations.ts"), generateSyncedMutationsFile(allModelMutations)) && filesChanged++, filesChanged > 0 && !silent && console.info(`\u2713 ${allModelFiles.length} models (${filesWithSchema.length} schemas)${queryCount ? `, ${queryCount} queries` : ""}${mutationCount ? `, ${mutationCount} mutations` : ""}`), filesChanged > 0 && after) {
531
+ if (allModelMutations.length > 0 && writeFileIfChanged((0, import_node_path.resolve)(generatedDir, "syncedMutations.ts"), (0, import_generate_helpers.generateSyncedMutationsFile)(allModelMutations)) && filesChanged++, filesChanged > 0 && !silent && console.info(`\u2713 ${allModelFiles.length} models (${filesWithSchema.length} schemas)${queryCount ? `, ${queryCount} queries` : ""}${mutationCount ? `, ${mutationCount} mutations` : ""}`), filesChanged > 0 && after) {
801
532
  const {
802
533
  execSync
803
534
  } = await import("node:child_process");