@veloxts/cli 0.4.0 → 0.4.2

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 (140) hide show
  1. package/README.md +23 -144
  2. package/dist/cli.js +2 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/generate.d.ts +17 -0
  5. package/dist/commands/generate.d.ts.map +1 -0
  6. package/dist/commands/generate.js +219 -0
  7. package/dist/commands/generate.js.map +1 -0
  8. package/dist/commands/migrate.d.ts +8 -3
  9. package/dist/commands/migrate.d.ts.map +1 -1
  10. package/dist/commands/migrate.js +17 -123
  11. package/dist/commands/migrate.js.map +1 -1
  12. package/dist/generators/base.d.ts +76 -0
  13. package/dist/generators/base.d.ts.map +1 -0
  14. package/dist/generators/base.js +271 -0
  15. package/dist/generators/base.js.map +1 -0
  16. package/dist/generators/generators/index.d.ts +17 -0
  17. package/dist/generators/generators/index.d.ts.map +1 -0
  18. package/dist/generators/generators/index.js +43 -0
  19. package/dist/generators/generators/index.js.map +1 -0
  20. package/dist/generators/generators/migration.d.ts +43 -0
  21. package/dist/generators/generators/migration.d.ts.map +1 -0
  22. package/dist/generators/generators/migration.js +121 -0
  23. package/dist/generators/generators/migration.js.map +1 -0
  24. package/dist/generators/generators/model.d.ts +38 -0
  25. package/dist/generators/generators/model.d.ts.map +1 -0
  26. package/dist/generators/generators/model.js +108 -0
  27. package/dist/generators/generators/model.js.map +1 -0
  28. package/dist/generators/generators/procedure.d.ts +37 -0
  29. package/dist/generators/generators/procedure.d.ts.map +1 -0
  30. package/dist/generators/generators/procedure.js +99 -0
  31. package/dist/generators/generators/procedure.js.map +1 -0
  32. package/dist/generators/generators/resource.d.ts +29 -0
  33. package/dist/generators/generators/resource.d.ts.map +1 -0
  34. package/dist/generators/generators/resource.js +124 -0
  35. package/dist/generators/generators/resource.js.map +1 -0
  36. package/dist/generators/generators/schema.d.ts +28 -0
  37. package/dist/generators/generators/schema.d.ts.map +1 -0
  38. package/dist/generators/generators/schema.js +83 -0
  39. package/dist/generators/generators/schema.js.map +1 -0
  40. package/dist/generators/generators/test.d.ts +28 -0
  41. package/dist/generators/generators/test.d.ts.map +1 -0
  42. package/dist/generators/generators/test.js +96 -0
  43. package/dist/generators/generators/test.js.map +1 -0
  44. package/dist/generators/index.d.ts +16 -0
  45. package/dist/generators/index.d.ts.map +1 -0
  46. package/dist/generators/index.js +16 -0
  47. package/dist/generators/index.js.map +1 -0
  48. package/dist/generators/registry.d.ts +97 -0
  49. package/dist/generators/registry.d.ts.map +1 -0
  50. package/dist/generators/registry.js +253 -0
  51. package/dist/generators/registry.js.map +1 -0
  52. package/dist/generators/templates/migration.d.ts +23 -0
  53. package/dist/generators/templates/migration.d.ts.map +1 -0
  54. package/dist/generators/templates/migration.js +389 -0
  55. package/dist/generators/templates/migration.js.map +1 -0
  56. package/dist/generators/templates/model.d.ts +37 -0
  57. package/dist/generators/templates/model.d.ts.map +1 -0
  58. package/dist/generators/templates/model.js +374 -0
  59. package/dist/generators/templates/model.js.map +1 -0
  60. package/dist/generators/templates/procedure.d.ts +25 -0
  61. package/dist/generators/templates/procedure.d.ts.map +1 -0
  62. package/dist/generators/templates/procedure.js +274 -0
  63. package/dist/generators/templates/procedure.js.map +1 -0
  64. package/dist/generators/templates/resource.d.ts +34 -0
  65. package/dist/generators/templates/resource.d.ts.map +1 -0
  66. package/dist/generators/templates/resource.js +550 -0
  67. package/dist/generators/templates/resource.js.map +1 -0
  68. package/dist/generators/templates/schema.d.ts +33 -0
  69. package/dist/generators/templates/schema.d.ts.map +1 -0
  70. package/dist/generators/templates/schema.js +248 -0
  71. package/dist/generators/templates/schema.js.map +1 -0
  72. package/dist/generators/templates/test.d.ts +31 -0
  73. package/dist/generators/templates/test.d.ts.map +1 -0
  74. package/dist/generators/templates/test.js +882 -0
  75. package/dist/generators/templates/test.js.map +1 -0
  76. package/dist/generators/types.d.ts +211 -0
  77. package/dist/generators/types.d.ts.map +1 -0
  78. package/dist/generators/types.js +54 -0
  79. package/dist/generators/types.js.map +1 -0
  80. package/dist/generators/utils/filesystem.d.ts +68 -0
  81. package/dist/generators/utils/filesystem.d.ts.map +1 -0
  82. package/dist/generators/utils/filesystem.js +217 -0
  83. package/dist/generators/utils/filesystem.js.map +1 -0
  84. package/dist/generators/utils/naming.d.ts +122 -0
  85. package/dist/generators/utils/naming.d.ts.map +1 -0
  86. package/dist/generators/utils/naming.js +198 -0
  87. package/dist/generators/utils/naming.js.map +1 -0
  88. package/dist/index.d.ts +4 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +4 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/migrations/commands/fresh.d.ts +11 -0
  93. package/dist/migrations/commands/fresh.d.ts.map +1 -0
  94. package/dist/migrations/commands/fresh.js +164 -0
  95. package/dist/migrations/commands/fresh.js.map +1 -0
  96. package/dist/migrations/commands/index.d.ts +11 -0
  97. package/dist/migrations/commands/index.d.ts.map +1 -0
  98. package/dist/migrations/commands/index.js +11 -0
  99. package/dist/migrations/commands/index.js.map +1 -0
  100. package/dist/migrations/commands/reset.d.ts +11 -0
  101. package/dist/migrations/commands/reset.d.ts.map +1 -0
  102. package/dist/migrations/commands/reset.js +258 -0
  103. package/dist/migrations/commands/reset.js.map +1 -0
  104. package/dist/migrations/commands/rollback.d.ts +11 -0
  105. package/dist/migrations/commands/rollback.d.ts.map +1 -0
  106. package/dist/migrations/commands/rollback.js +241 -0
  107. package/dist/migrations/commands/rollback.js.map +1 -0
  108. package/dist/migrations/commands/run.d.ts +11 -0
  109. package/dist/migrations/commands/run.d.ts.map +1 -0
  110. package/dist/migrations/commands/run.js +183 -0
  111. package/dist/migrations/commands/run.js.map +1 -0
  112. package/dist/migrations/commands/status.d.ts +11 -0
  113. package/dist/migrations/commands/status.d.ts.map +1 -0
  114. package/dist/migrations/commands/status.js +154 -0
  115. package/dist/migrations/commands/status.js.map +1 -0
  116. package/dist/migrations/errors.d.ts +74 -0
  117. package/dist/migrations/errors.d.ts.map +1 -0
  118. package/dist/migrations/errors.js +155 -0
  119. package/dist/migrations/errors.js.map +1 -0
  120. package/dist/migrations/index.d.ts +13 -0
  121. package/dist/migrations/index.d.ts.map +1 -0
  122. package/dist/migrations/index.js +17 -0
  123. package/dist/migrations/index.js.map +1 -0
  124. package/dist/migrations/loader.d.ts +44 -0
  125. package/dist/migrations/loader.d.ts.map +1 -0
  126. package/dist/migrations/loader.js +181 -0
  127. package/dist/migrations/loader.js.map +1 -0
  128. package/dist/migrations/prisma-wrapper.d.ts +60 -0
  129. package/dist/migrations/prisma-wrapper.d.ts.map +1 -0
  130. package/dist/migrations/prisma-wrapper.js +184 -0
  131. package/dist/migrations/prisma-wrapper.js.map +1 -0
  132. package/dist/migrations/rollback-runner.d.ts +40 -0
  133. package/dist/migrations/rollback-runner.d.ts.map +1 -0
  134. package/dist/migrations/rollback-runner.js +203 -0
  135. package/dist/migrations/rollback-runner.js.map +1 -0
  136. package/dist/migrations/types.d.ts +214 -0
  137. package/dist/migrations/types.d.ts.map +1 -0
  138. package/dist/migrations/types.js +19 -0
  139. package/dist/migrations/types.js.map +1 -0
  140. package/package.json +29 -8
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Resource Template
3
+ *
4
+ * Generates a complete resource with model, schema, procedures, and tests.
5
+ * This is the "full stack" generator for quickly scaffolding new entities.
6
+ */
7
+ import type { GeneratedFile, TemplateContext } from '../types.js';
8
+ export interface ResourceOptions {
9
+ /** Include CRUD operations */
10
+ crud: boolean;
11
+ /** Include pagination for list operations */
12
+ paginated: boolean;
13
+ /** Include soft delete support */
14
+ softDelete: boolean;
15
+ /** Include timestamp fields */
16
+ timestamps: boolean;
17
+ /** Generate test files */
18
+ withTests: boolean;
19
+ /** Skip Prisma model generation */
20
+ skipModel: boolean;
21
+ /** Skip schema generation */
22
+ skipSchema: boolean;
23
+ /** Skip procedure generation */
24
+ skipProcedure: boolean;
25
+ }
26
+ /**
27
+ * Generate all files for a resource
28
+ */
29
+ export declare function generateResourceFiles(ctx: TemplateContext<ResourceOptions>): GeneratedFile[];
30
+ /**
31
+ * Generate post-generation instructions
32
+ */
33
+ export declare function getResourceInstructions(entityName: string, options: ResourceOptions): string;
34
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../../src/generators/templates/resource.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAMlE,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,kCAAkC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,+BAA+B;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,0BAA0B;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,gCAAgC;IAChC,aAAa,EAAE,OAAO,CAAC;CACxB;AA2eD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,CAAC,eAAe,CAAC,GAAG,aAAa,EAAE,CAqC5F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAsD5F"}
@@ -0,0 +1,550 @@
1
+ /**
2
+ * Resource Template
3
+ *
4
+ * Generates a complete resource with model, schema, procedures, and tests.
5
+ * This is the "full stack" generator for quickly scaffolding new entities.
6
+ */
7
+ // ============================================================================
8
+ // Prisma Model Template
9
+ // ============================================================================
10
+ function generatePrismaModel(entity, options) {
11
+ const { pascal, camel } = entity;
12
+ const { softDelete, timestamps } = options;
13
+ const timestampFields = timestamps
14
+ ? `
15
+ createdAt DateTime @default(now())
16
+ updatedAt DateTime @updatedAt`
17
+ : '';
18
+ const softDeleteField = softDelete
19
+ ? `
20
+ deletedAt DateTime?`
21
+ : '';
22
+ return `// Add this model to your prisma/schema.prisma file
23
+
24
+ model ${pascal} {
25
+ id String @id @default(uuid())
26
+
27
+ // TODO: Add your fields here
28
+ // name String
29
+ // email String @unique
30
+ // status Status @default(ACTIVE)
31
+ ${timestampFields}${softDeleteField}
32
+
33
+ // Relations
34
+ // posts Post[]
35
+
36
+ @@map("${camel}s")
37
+ }
38
+
39
+ // Optional: Add enum if needed
40
+ // enum Status {
41
+ // ACTIVE
42
+ // INACTIVE
43
+ // PENDING
44
+ // }
45
+ `;
46
+ }
47
+ // ============================================================================
48
+ // Zod Schema Template
49
+ // ============================================================================
50
+ function generateZodSchema(entity, options) {
51
+ const { pascal, camel } = entity;
52
+ const { softDelete, timestamps, crud } = options;
53
+ const timestampFields = timestamps
54
+ ? `
55
+ createdAt: z.date(),
56
+ updatedAt: z.date(),`
57
+ : '';
58
+ const softDeleteField = softDelete
59
+ ? `
60
+ deletedAt: z.date().nullable(),`
61
+ : '';
62
+ // Fields to omit for create/update
63
+ const omitFields = ['id'];
64
+ if (timestamps)
65
+ omitFields.push('createdAt', 'updatedAt');
66
+ if (softDelete)
67
+ omitFields.push('deletedAt');
68
+ const crudSchemas = crud
69
+ ? `
70
+
71
+ // ============================================================================
72
+ // Input Schemas
73
+ // ============================================================================
74
+
75
+ /**
76
+ * Create${pascal}Input - For creating new ${camel}s
77
+ */
78
+ export const create${pascal}InputSchema = ${camel}Schema.omit({
79
+ ${omitFields.map((f) => `${f}: true`).join(',\n ')},
80
+ });
81
+
82
+ export type Create${pascal}Input = z.infer<typeof create${pascal}InputSchema>;
83
+
84
+ /**
85
+ * Update${pascal}Input - For full updates (PUT)
86
+ */
87
+ export const update${pascal}InputSchema = ${camel}Schema.omit({
88
+ ${omitFields.map((f) => `${f}: true`).join(',\n ')},
89
+ });
90
+
91
+ export type Update${pascal}Input = z.infer<typeof update${pascal}InputSchema>;
92
+
93
+ /**
94
+ * Patch${pascal}Input - For partial updates (PATCH)
95
+ */
96
+ export const patch${pascal}InputSchema = update${pascal}InputSchema.partial();
97
+
98
+ export type Patch${pascal}Input = z.infer<typeof patch${pascal}InputSchema>;
99
+
100
+ // ============================================================================
101
+ // Query Schemas
102
+ // ============================================================================
103
+
104
+ /**
105
+ * ${pascal}IdParam - ID parameter validation
106
+ */
107
+ export const ${camel}IdParamSchema = z.object({
108
+ id: z.string().uuid(),
109
+ });
110
+
111
+ export type ${pascal}IdParam = z.infer<typeof ${camel}IdParamSchema>;
112
+
113
+ /**
114
+ * ${pascal}ListQuery - List/search parameters
115
+ */
116
+ export const ${camel}ListQuerySchema = z.object({
117
+ page: z.coerce.number().int().positive().default(1),
118
+ limit: z.coerce.number().int().positive().max(100).default(20),
119
+ sortBy: z.string().optional(),
120
+ sortOrder: z.enum(['asc', 'desc']).default('desc'),
121
+ search: z.string().optional(),
122
+ });
123
+
124
+ export type ${pascal}ListQuery = z.infer<typeof ${camel}ListQuerySchema>;
125
+
126
+ // ============================================================================
127
+ // Response Schemas
128
+ // ============================================================================
129
+
130
+ /**
131
+ * ${pascal}ListResponse - Paginated response
132
+ */
133
+ export const ${camel}ListResponseSchema = z.object({
134
+ data: z.array(${camel}Schema),
135
+ meta: z.object({
136
+ total: z.number(),
137
+ page: z.number(),
138
+ limit: z.number(),
139
+ totalPages: z.number(),
140
+ }),
141
+ });
142
+
143
+ export type ${pascal}ListResponse = z.infer<typeof ${camel}ListResponseSchema>;`
144
+ : '';
145
+ return `/**
146
+ * ${pascal} Schema
147
+ *
148
+ * Zod validation schemas for ${pascal} entity.
149
+ */
150
+
151
+ import { z } from 'zod';
152
+
153
+ // ============================================================================
154
+ // Base Schema
155
+ // ============================================================================
156
+
157
+ /**
158
+ * ${pascal} - Full entity schema
159
+ */
160
+ export const ${camel}Schema = z.object({
161
+ id: z.string().uuid(),
162
+ // TODO: Add your fields here
163
+ // name: z.string().min(1).max(255),
164
+ // email: z.string().email(),
165
+ // status: z.enum(['ACTIVE', 'INACTIVE', 'PENDING']),${timestampFields}${softDeleteField}
166
+ });
167
+
168
+ export type ${pascal} = z.infer<typeof ${camel}Schema>;
169
+ ${crudSchemas}
170
+ `;
171
+ }
172
+ // ============================================================================
173
+ // Procedure Template
174
+ // ============================================================================
175
+ function generateProcedure(entity, options) {
176
+ const { pascal, camel, kebab } = entity;
177
+ const { crud, paginated, softDelete } = options;
178
+ if (!crud) {
179
+ // Simple procedure without CRUD
180
+ return `/**
181
+ * ${pascal} Procedures
182
+ *
183
+ * API procedures for ${pascal} operations.
184
+ */
185
+
186
+ import { procedure, defineProcedures } from '@veloxts/router';
187
+ import { ${camel}Schema, ${camel}IdParamSchema } from '../schemas/${kebab}.schema.js';
188
+
189
+ export const ${camel}Procedures = defineProcedures('${kebab}s', {
190
+ /**
191
+ * Get a single ${camel} by ID
192
+ * GET /api/${kebab}s/:id
193
+ */
194
+ get${pascal}: procedure
195
+ .input(${camel}IdParamSchema)
196
+ .output(${camel}Schema.nullable())
197
+ .query(async ({ input, ctx }) => {
198
+ return ctx.db.${camel}.findUnique({
199
+ where: { id: input.id },
200
+ });
201
+ }),
202
+ });
203
+ `;
204
+ }
205
+ // CRUD procedures
206
+ const softDeleteWhere = softDelete ? ', deletedAt: null' : '';
207
+ const paginationCode = paginated
208
+ ? `
209
+ const total = await ctx.db.${camel}.count({ where: { ${softDelete ? 'deletedAt: null' : ''} } });
210
+ const totalPages = Math.ceil(total / input.limit);
211
+
212
+ return {
213
+ data: ${camel}s,
214
+ meta: {
215
+ total,
216
+ page: input.page,
217
+ limit: input.limit,
218
+ totalPages,
219
+ },
220
+ };`
221
+ : `
222
+ return ${camel}s;`;
223
+ const listOutput = paginated ? `${camel}ListResponseSchema` : `z.array(${camel}Schema)`;
224
+ const deleteOperation = softDelete
225
+ ? `// Soft delete
226
+ return ctx.db.${camel}.update({
227
+ where: { id: input.id },
228
+ data: { deletedAt: new Date() },
229
+ });`
230
+ : `return ctx.db.${camel}.delete({
231
+ where: { id: input.id },
232
+ });`;
233
+ return `/**
234
+ * ${pascal} Procedures
235
+ *
236
+ * CRUD procedures for ${pascal} entity.
237
+ */
238
+
239
+ import { z } from 'zod';
240
+ import { procedure, defineProcedures } from '@veloxts/router';
241
+ import {
242
+ ${camel}Schema,
243
+ ${camel}IdParamSchema,
244
+ ${camel}ListQuerySchema,
245
+ ${paginated ? `${camel}ListResponseSchema,\n ` : ''}create${pascal}InputSchema,
246
+ update${pascal}InputSchema,
247
+ patch${pascal}InputSchema,
248
+ } from '../schemas/${kebab}.schema.js';
249
+
250
+ export const ${camel}Procedures = defineProcedures('${kebab}s', {
251
+ /**
252
+ * Get a single ${camel} by ID
253
+ * GET /api/${kebab}s/:id
254
+ */
255
+ get${pascal}: procedure
256
+ .input(${camel}IdParamSchema)
257
+ .output(${camel}Schema.nullable())
258
+ .query(async ({ input, ctx }) => {
259
+ return ctx.db.${camel}.findUnique({
260
+ where: { id: input.id${softDeleteWhere} },
261
+ });
262
+ }),
263
+
264
+ /**
265
+ * List all ${camel}s with pagination
266
+ * GET /api/${kebab}s
267
+ */
268
+ list${pascal}s: procedure
269
+ .input(${camel}ListQuerySchema)
270
+ .output(${listOutput})
271
+ .query(async ({ input, ctx }) => {
272
+ const ${camel}s = await ctx.db.${camel}.findMany({
273
+ where: { ${softDelete ? 'deletedAt: null' : ''} },
274
+ skip: (input.page - 1) * input.limit,
275
+ take: input.limit,
276
+ orderBy: input.sortBy
277
+ ? { [input.sortBy]: input.sortOrder }
278
+ : { createdAt: 'desc' },
279
+ });
280
+ ${paginationCode}
281
+ }),
282
+
283
+ /**
284
+ * Create a new ${camel}
285
+ * POST /api/${kebab}s
286
+ */
287
+ create${pascal}: procedure
288
+ .input(create${pascal}InputSchema)
289
+ .output(${camel}Schema)
290
+ .mutation(async ({ input, ctx }) => {
291
+ return ctx.db.${camel}.create({
292
+ data: input,
293
+ });
294
+ }),
295
+
296
+ /**
297
+ * Update a ${camel} (full replacement)
298
+ * PUT /api/${kebab}s/:id
299
+ */
300
+ update${pascal}: procedure
301
+ .input(${camel}IdParamSchema.merge(update${pascal}InputSchema))
302
+ .output(${camel}Schema)
303
+ .mutation(async ({ input, ctx }) => {
304
+ const { id, ...data } = input;
305
+ return ctx.db.${camel}.update({
306
+ where: { id },
307
+ data,
308
+ });
309
+ }),
310
+
311
+ /**
312
+ * Patch a ${camel} (partial update)
313
+ * PATCH /api/${kebab}s/:id
314
+ */
315
+ patch${pascal}: procedure
316
+ .input(${camel}IdParamSchema.merge(patch${pascal}InputSchema))
317
+ .output(${camel}Schema)
318
+ .mutation(async ({ input, ctx }) => {
319
+ const { id, ...data } = input;
320
+ return ctx.db.${camel}.update({
321
+ where: { id },
322
+ data,
323
+ });
324
+ }),
325
+
326
+ /**
327
+ * Delete a ${camel}
328
+ * DELETE /api/${kebab}s/:id
329
+ */
330
+ delete${pascal}: procedure
331
+ .input(${camel}IdParamSchema)
332
+ .output(${camel}Schema)
333
+ .mutation(async ({ input, ctx }) => {
334
+ ${deleteOperation}
335
+ }),
336
+ });
337
+ `;
338
+ }
339
+ // ============================================================================
340
+ // Test Template
341
+ // ============================================================================
342
+ function generateTest(entity, options) {
343
+ const { pascal, camel, kebab } = entity;
344
+ const { crud } = options;
345
+ if (!crud) {
346
+ return `/**
347
+ * ${pascal} Procedures - Tests
348
+ */
349
+
350
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
351
+ // import { ${camel}Procedures } from '../procedures/${kebab}.js';
352
+
353
+ describe('${pascal} Procedures', () => {
354
+ const mockCtx = {
355
+ db: {
356
+ ${camel}: {
357
+ findUnique: vi.fn(),
358
+ },
359
+ },
360
+ };
361
+
362
+ beforeEach(() => {
363
+ vi.clearAllMocks();
364
+ });
365
+
366
+ describe('get${pascal}', () => {
367
+ it('should return a ${camel} by id', async () => {
368
+ const mock${pascal} = { id: 'test-uuid' };
369
+ mockCtx.db.${camel}.findUnique.mockResolvedValue(mock${pascal});
370
+
371
+ // TODO: Implement test
372
+ });
373
+ });
374
+ });
375
+ `;
376
+ }
377
+ return `/**
378
+ * ${pascal} Procedures - Tests
379
+ */
380
+
381
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
382
+ // import { ${camel}Procedures } from '../procedures/${kebab}.js';
383
+
384
+ describe('${pascal} Procedures', () => {
385
+ const mockCtx = {
386
+ db: {
387
+ ${camel}: {
388
+ findUnique: vi.fn(),
389
+ findMany: vi.fn(),
390
+ count: vi.fn(),
391
+ create: vi.fn(),
392
+ update: vi.fn(),
393
+ delete: vi.fn(),
394
+ },
395
+ },
396
+ };
397
+
398
+ beforeEach(() => {
399
+ vi.clearAllMocks();
400
+ });
401
+
402
+ describe('get${pascal}', () => {
403
+ it('should return a ${camel} by id', async () => {
404
+ const mock${pascal} = { id: 'test-uuid', createdAt: new Date(), updatedAt: new Date() };
405
+ mockCtx.db.${camel}.findUnique.mockResolvedValue(mock${pascal});
406
+
407
+ // TODO: Call procedure and assert
408
+ });
409
+
410
+ it('should return null for non-existent ${camel}', async () => {
411
+ mockCtx.db.${camel}.findUnique.mockResolvedValue(null);
412
+
413
+ // TODO: Call procedure and assert
414
+ });
415
+ });
416
+
417
+ describe('list${pascal}s', () => {
418
+ it('should return paginated ${camel}s', async () => {
419
+ const mock${pascal}s = [
420
+ { id: 'uuid-1', createdAt: new Date(), updatedAt: new Date() },
421
+ { id: 'uuid-2', createdAt: new Date(), updatedAt: new Date() },
422
+ ];
423
+ mockCtx.db.${camel}.findMany.mockResolvedValue(mock${pascal}s);
424
+ mockCtx.db.${camel}.count.mockResolvedValue(2);
425
+
426
+ // TODO: Call procedure and assert
427
+ });
428
+ });
429
+
430
+ describe('create${pascal}', () => {
431
+ it('should create a new ${camel}', async () => {
432
+ const input = { /* TODO: Add fields */ };
433
+ const created = { id: 'new-uuid', ...input, createdAt: new Date(), updatedAt: new Date() };
434
+ mockCtx.db.${camel}.create.mockResolvedValue(created);
435
+
436
+ // TODO: Call procedure and assert
437
+ });
438
+ });
439
+
440
+ describe('update${pascal}', () => {
441
+ it('should update an existing ${camel}', async () => {
442
+ const updated = { id: 'test-uuid', createdAt: new Date(), updatedAt: new Date() };
443
+ mockCtx.db.${camel}.update.mockResolvedValue(updated);
444
+
445
+ // TODO: Call procedure and assert
446
+ });
447
+ });
448
+
449
+ describe('delete${pascal}', () => {
450
+ it('should delete a ${camel}', async () => {
451
+ mockCtx.db.${camel}.delete.mockResolvedValue({ id: 'test-uuid' });
452
+
453
+ // TODO: Call procedure and assert
454
+ });
455
+ });
456
+ });
457
+ `;
458
+ }
459
+ // ============================================================================
460
+ // Template Export
461
+ // ============================================================================
462
+ /**
463
+ * Generate all files for a resource
464
+ */
465
+ export function generateResourceFiles(ctx) {
466
+ const files = [];
467
+ const { entity, options } = ctx;
468
+ // Prisma model (added to models folder for reference)
469
+ if (!options.skipModel) {
470
+ files.push({
471
+ path: `src/models/${entity.kebab}.prisma`,
472
+ content: generatePrismaModel(entity, options),
473
+ });
474
+ }
475
+ // Zod schema
476
+ if (!options.skipSchema) {
477
+ files.push({
478
+ path: `src/schemas/${entity.kebab}.schema.ts`,
479
+ content: generateZodSchema(entity, options),
480
+ });
481
+ }
482
+ // Procedures
483
+ if (!options.skipProcedure) {
484
+ files.push({
485
+ path: `src/procedures/${entity.kebab}.ts`,
486
+ content: generateProcedure(entity, options),
487
+ });
488
+ }
489
+ // Tests
490
+ if (options.withTests && !options.skipProcedure) {
491
+ files.push({
492
+ path: `src/procedures/__tests__/${entity.kebab}.test.ts`,
493
+ content: generateTest(entity, options),
494
+ });
495
+ }
496
+ return files;
497
+ }
498
+ /**
499
+ * Generate post-generation instructions
500
+ */
501
+ export function getResourceInstructions(entityName, options) {
502
+ const steps = [];
503
+ let stepNum = 1;
504
+ if (!options.skipModel) {
505
+ steps.push(`${stepNum}. Add the Prisma model to your schema:
506
+
507
+ Copy the contents of src/models/${entityName.toLowerCase()}.prisma
508
+ into your prisma/schema.prisma file.
509
+
510
+ Then run:
511
+ npx prisma db push
512
+ # or
513
+ npx prisma migrate dev --name add_${entityName.toLowerCase()}`);
514
+ stepNum++;
515
+ }
516
+ if (!options.skipSchema) {
517
+ steps.push(`${stepNum}. Customize the Zod schema:
518
+
519
+ Edit src/schemas/${entityName.toLowerCase()}.schema.ts
520
+ to match your Prisma model fields.`);
521
+ stepNum++;
522
+ }
523
+ if (!options.skipProcedure) {
524
+ steps.push(`${stepNum}. Register the procedures in your router:
525
+
526
+ import { ${entityName.charAt(0).toLowerCase() + entityName.slice(1)}Procedures } from './procedures/${entityName.toLowerCase()}.js';
527
+
528
+ // Add to your router
529
+ const router = createRouter({
530
+ ${entityName.charAt(0).toLowerCase() + entityName.slice(1)}: ${entityName.charAt(0).toLowerCase() + entityName.slice(1)}Procedures,
531
+ });`);
532
+ stepNum++;
533
+ }
534
+ if (options.withTests) {
535
+ steps.push(`${stepNum}. Run the tests:
536
+
537
+ pnpm test src/procedures/__tests__/${entityName.toLowerCase()}.test.ts`);
538
+ stepNum++;
539
+ }
540
+ steps.push(`${stepNum}. Your ${entityName} API is ready:
541
+
542
+ GET /api/${entityName.toLowerCase()}s - List all
543
+ GET /api/${entityName.toLowerCase()}s/:id - Get by ID
544
+ POST /api/${entityName.toLowerCase()}s - Create new
545
+ PUT /api/${entityName.toLowerCase()}s/:id - Full update
546
+ PATCH /api/${entityName.toLowerCase()}s/:id - Partial update
547
+ DELETE /api/${entityName.toLowerCase()}s/:id - Delete`);
548
+ return `\n ${steps.join('\n\n ')}`;
549
+ }
550
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../../src/generators/templates/resource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Schema Template
3
+ *
4
+ * Generates Zod validation schemas for VeloxTS applications.
5
+ */
6
+ import type { GeneratedFile, TemplateContext, TemplateFunction } from '../types.js';
7
+ export interface SchemaOptions {
8
+ /** Include soft delete fields (deletedAt) */
9
+ softDelete: boolean;
10
+ /** Include timestamp fields (createdAt, updatedAt) */
11
+ timestamps: boolean;
12
+ /** Generate CRUD-related schemas (create, update, patch) */
13
+ crud: boolean;
14
+ }
15
+ /**
16
+ * Schema template function
17
+ */
18
+ export declare const schemaTemplate: TemplateFunction<SchemaOptions>;
19
+ /**
20
+ * Get output path for schema file
21
+ */
22
+ export declare function getSchemaPath(entity: {
23
+ kebab: string;
24
+ }): string;
25
+ /**
26
+ * Generate all files for a schema
27
+ */
28
+ export declare function generateSchemaFiles(ctx: TemplateContext<SchemaOptions>): GeneratedFile[];
29
+ /**
30
+ * Generate post-generation instructions
31
+ */
32
+ export declare function getSchemaInstructions(entityName: string, options: SchemaOptions): string;
33
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/generators/templates/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpF,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,UAAU,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,UAAU,EAAE,OAAO,CAAC;IACpB,4DAA4D;IAC5D,IAAI,EAAE,OAAO,CAAC;CACf;AAsMD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,gBAAgB,CAAC,aAAa,CAQ1D,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE/D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,CAAC,aAAa,CAAC,GAAG,aAAa,EAAE,CASxF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAgCxF"}