@prismakit/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runCodegen,
4
+ runGenerate,
5
+ runValidate
6
+ } from "./chunk-36ZM4UZV.js";
7
+
8
+ // src/bin.ts
9
+ function printHelp() {
10
+ console.log(`prismakit \u2014 PrismaKit CLI
11
+
12
+ Usage:
13
+ prismakit generate <name> [--cache] [--full] [--route <path>] [--prisma-import <path>] [--dry-run]
14
+ prismakit codegen [--schema <path>] [--write] [--out <file>]
15
+ prismakit validate [--no-assert]
16
+ prismakit help
17
+
18
+ By default, generate writes only the repository file.
19
+ Pass --full for a Nest module (controller, service, types).
20
+
21
+ Examples:
22
+ prismakit generate product --cache
23
+ prismakit generate product --cache --full --route products
24
+ prismakit codegen --write
25
+ prismakit validate
26
+ `);
27
+ }
28
+ function parseArgs(argv) {
29
+ const [command = "help", ...rest] = argv;
30
+ const positional = [];
31
+ const flags = {};
32
+ for (let i = 0; i < rest.length; i++) {
33
+ const arg = rest[i];
34
+ if (arg.startsWith("--")) {
35
+ const key = arg.slice(2);
36
+ const next = rest[i + 1];
37
+ if (next && !next.startsWith("--")) {
38
+ flags[key] = next;
39
+ i++;
40
+ } else {
41
+ flags[key] = true;
42
+ }
43
+ } else {
44
+ positional.push(arg);
45
+ }
46
+ }
47
+ return { command, positional, flags };
48
+ }
49
+ function main() {
50
+ const { command, positional, flags } = parseArgs(process.argv.slice(2));
51
+ try {
52
+ switch (command) {
53
+ case "generate":
54
+ case "gen": {
55
+ const name = positional[0];
56
+ if (!name) {
57
+ console.error("Missing module name. Usage: prismakit generate <name>");
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ runGenerate({
62
+ name,
63
+ cache: !!flags.cache,
64
+ full: !!flags.full,
65
+ route: typeof flags.route === "string" ? flags.route : void 0,
66
+ prismaImport: typeof flags["prisma-import"] === "string" ? flags["prisma-import"] : void 0,
67
+ dryRun: !!flags["dry-run"]
68
+ });
69
+ break;
70
+ }
71
+ case "codegen": {
72
+ runCodegen({
73
+ schemaPath: typeof flags.schema === "string" ? flags.schema : void 0,
74
+ write: !!flags.write,
75
+ outFile: typeof flags.out === "string" ? flags.out : void 0
76
+ });
77
+ break;
78
+ }
79
+ case "validate": {
80
+ runValidate({
81
+ assert: !flags["no-assert"]
82
+ });
83
+ break;
84
+ }
85
+ case "help":
86
+ case "--help":
87
+ case "-h":
88
+ printHelp();
89
+ break;
90
+ default:
91
+ console.error(`Unknown command: ${command}`);
92
+ printHelp();
93
+ process.exitCode = 1;
94
+ }
95
+ } catch (err) {
96
+ console.error(err.message);
97
+ process.exitCode = 1;
98
+ }
99
+ }
100
+ main();
101
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["import { runGenerate } from './commands/generate';\nimport { runCodegen } from './commands/codegen';\nimport { runValidate } from './commands/validate';\n\nfunction printHelp(): void {\n console.log(`prismakit — PrismaKit CLI\n\nUsage:\n prismakit generate <name> [--cache] [--full] [--route <path>] [--prisma-import <path>] [--dry-run]\n prismakit codegen [--schema <path>] [--write] [--out <file>]\n prismakit validate [--no-assert]\n prismakit help\n\nBy default, generate writes only the repository file.\nPass --full for a Nest module (controller, service, types).\n\nExamples:\n prismakit generate product --cache\n prismakit generate product --cache --full --route products\n prismakit codegen --write\n prismakit validate\n`);\n}\n\nfunction parseArgs(argv: string[]): {\n command: string;\n positional: string[];\n flags: Record<string, string | boolean>;\n} {\n const [command = 'help', ...rest] = argv;\n const positional: string[] = [];\n const flags: Record<string, string | boolean> = {};\n\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i];\n if (arg.startsWith('--')) {\n const key = arg.slice(2);\n const next = rest[i + 1];\n if (next && !next.startsWith('--')) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n } else {\n positional.push(arg);\n }\n }\n\n return { command, positional, flags };\n}\n\nfunction main(): void {\n const { command, positional, flags } = parseArgs(process.argv.slice(2));\n\n try {\n switch (command) {\n case 'generate':\n case 'gen': {\n const name = positional[0];\n if (!name) {\n console.error('Missing module name. Usage: prismakit generate <name>');\n process.exitCode = 1;\n return;\n }\n runGenerate({\n name,\n cache: !!flags.cache,\n full: !!flags.full,\n route:\n typeof flags.route === 'string' ? flags.route : undefined,\n prismaImport:\n typeof flags['prisma-import'] === 'string'\n ? flags['prisma-import']\n : undefined,\n dryRun: !!flags['dry-run'],\n });\n break;\n }\n case 'codegen': {\n runCodegen({\n schemaPath:\n typeof flags.schema === 'string' ? flags.schema : undefined,\n write: !!flags.write,\n outFile: typeof flags.out === 'string' ? flags.out : undefined,\n });\n break;\n }\n case 'validate': {\n runValidate({\n assert: !flags['no-assert'],\n });\n break;\n }\n case 'help':\n case '--help':\n case '-h':\n printHelp();\n break;\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exitCode = 1;\n }\n } catch (err) {\n console.error((err as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":";;;;;;;AAIA,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAgBb;AACD;AAEA,SAAS,UAAU,MAIjB;AACA,QAAM,CAAC,UAAU,QAAQ,GAAG,IAAI,IAAI;AACpC,QAAM,aAAuB,CAAC;AAC9B,QAAM,QAA0C,CAAC;AAEjD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,IAAI,WAAW,IAAI,GAAG;AACxB,YAAM,MAAM,IAAI,MAAM,CAAC;AACvB,YAAM,OAAO,KAAK,IAAI,CAAC;AACvB,UAAI,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG;AAClC,cAAM,GAAG,IAAI;AACb;AAAA,MACF,OAAO;AACL,cAAM,GAAG,IAAI;AAAA,MACf;AAAA,IACF,OAAO;AACL,iBAAW,KAAK,GAAG;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,YAAY,MAAM;AACtC;AAEA,SAAS,OAAa;AACpB,QAAM,EAAE,SAAS,YAAY,MAAM,IAAI,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAEtE,MAAI;AACF,YAAQ,SAAS;AAAA,MACf,KAAK;AAAA,MACL,KAAK,OAAO;AACV,cAAM,OAAO,WAAW,CAAC;AACzB,YAAI,CAAC,MAAM;AACT,kBAAQ,MAAM,uDAAuD;AACrE,kBAAQ,WAAW;AACnB;AAAA,QACF;AACA,oBAAY;AAAA,UACV;AAAA,UACA,OAAO,CAAC,CAAC,MAAM;AAAA,UACf,MAAM,CAAC,CAAC,MAAM;AAAA,UACd,OACE,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,UAClD,cACE,OAAO,MAAM,eAAe,MAAM,WAC9B,MAAM,eAAe,IACrB;AAAA,UACN,QAAQ,CAAC,CAAC,MAAM,SAAS;AAAA,QAC3B,CAAC;AACD;AAAA,MACF;AAAA,MACA,KAAK,WAAW;AACd,mBAAW;AAAA,UACT,YACE,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAAA,UACpD,OAAO,CAAC,CAAC,MAAM;AAAA,UACf,SAAS,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM;AAAA,QACvD,CAAC;AACD;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,oBAAY;AAAA,UACV,QAAQ,CAAC,MAAM,WAAW;AAAA,QAC5B,CAAC;AACD;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,kBAAU;AACV;AAAA,MACF;AACE,gBAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,kBAAU;AACV,gBAAQ,WAAW;AAAA,IACvB;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,MAAO,IAAc,OAAO;AACpC,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,KAAK;","names":[]}
@@ -0,0 +1,325 @@
1
+ // src/naming.ts
2
+ var KEBAB_NAME_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
3
+ function assertKebabName(name) {
4
+ if (!KEBAB_NAME_RE.test(name)) {
5
+ throw new Error(
6
+ `Invalid module name "${name}". Use kebab-case (e.g. product, blog-post).`
7
+ );
8
+ }
9
+ }
10
+ function kebabToPascal(kebab) {
11
+ return kebab.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
12
+ }
13
+ function kebabToCamel(kebab) {
14
+ const pascal = kebabToPascal(kebab);
15
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
16
+ }
17
+ function resolveNames(kebab, route) {
18
+ assertKebabName(kebab);
19
+ const pascal = kebabToPascal(kebab);
20
+ const camel = kebabToCamel(kebab);
21
+ return {
22
+ kebab,
23
+ camel,
24
+ pascal,
25
+ repoModel: camel,
26
+ route: route ?? kebab
27
+ };
28
+ }
29
+
30
+ // src/templates.ts
31
+ function apply(template, names, extras) {
32
+ const replacements = {
33
+ "{{pascal}}": names.pascal,
34
+ "{{camel}}": names.camel,
35
+ "{{kebab}}": names.kebab,
36
+ "{{route}}": names.route,
37
+ "{{repoModel}}": names.repoModel,
38
+ ...extras
39
+ };
40
+ let result = template;
41
+ for (const [key, value] of Object.entries(replacements)) {
42
+ result = result.split(key).join(value);
43
+ }
44
+ return result;
45
+ }
46
+ function renderRepository(names, cacheEnabled, prismaImport, base) {
47
+ const cacheBlock = cacheEnabled ? ` cache: {
48
+ ttl: 86400,
49
+ sensitiveFields: ['password'],
50
+ },
51
+ ` : "";
52
+ const content = apply(
53
+ `import { Prisma } from '{{prismaImport}}';
54
+ import { createInjectableRepository } from '@prismakit/nestjs';
55
+
56
+ export const {{pascal}}Repository = createInjectableRepository({
57
+ model: '{{repoModel}}',
58
+ scalarFields: Prisma.{{pascal}}ScalarFieldEnum,
59
+ {{cacheBlock}}});
60
+
61
+ export type {{pascal}}Repository = InstanceType<typeof {{pascal}}Repository>;
62
+ `,
63
+ names,
64
+ {
65
+ "{{cacheBlock}}": cacheBlock,
66
+ "{{prismaImport}}": prismaImport
67
+ }
68
+ );
69
+ return {
70
+ relativePath: `${base}/repositories/${names.kebab}.repository.ts`,
71
+ content
72
+ };
73
+ }
74
+ function renderModuleFiles(options) {
75
+ const { names, cacheEnabled, full = false } = options;
76
+ const prismaImport = options.prismaImport ?? "@prisma/client";
77
+ const base = `src/modules/${names.kebab}`;
78
+ const repository = renderRepository(names, cacheEnabled, prismaImport, base);
79
+ if (!full) {
80
+ return [repository];
81
+ }
82
+ const service = apply(
83
+ `import { Injectable } from '@nestjs/common';
84
+
85
+ import { {{pascal}}Repository } from '../repositories/{{kebab}}.repository';
86
+ import { get{{pascal}}Select } from '../types/select-{{kebab}}.type';
87
+
88
+ @Injectable()
89
+ export class {{pascal}}Service {
90
+ constructor(private readonly {{camel}}Repository: {{pascal}}Repository) {}
91
+
92
+ async handleGetById(id: string) {
93
+ return await this.{{camel}}Repository.getThrowById({
94
+ id,
95
+ select: get{{pascal}}Select('general'),
96
+ setCache: true,
97
+ });
98
+ }
99
+ }
100
+ `,
101
+ names,
102
+ {}
103
+ );
104
+ const controller = apply(
105
+ `import { Controller, Get, Param } from '@nestjs/common';
106
+
107
+ import { {{pascal}}Service } from '../services/{{kebab}}.service';
108
+
109
+ @Controller('{{route}}')
110
+ export class {{pascal}}Controller {
111
+ constructor(private readonly {{camel}}Service: {{pascal}}Service) {}
112
+
113
+ @Get(':id')
114
+ async getById(@Param('id') id: string) {
115
+ return this.{{camel}}Service.handleGetById(id);
116
+ }
117
+ }
118
+ `,
119
+ names,
120
+ {}
121
+ );
122
+ const moduleFile = apply(
123
+ `import { Module } from '@nestjs/common';
124
+
125
+ import { {{pascal}}Controller } from './controllers/{{kebab}}.controller';
126
+ import { {{pascal}}Service } from './services/{{kebab}}.service';
127
+ import { {{pascal}}Repository } from './repositories/{{kebab}}.repository';
128
+
129
+ @Module({
130
+ controllers: [{{pascal}}Controller],
131
+ providers: [{{pascal}}Service, {{pascal}}Repository],
132
+ exports: [{{pascal}}Service, {{pascal}}Repository],
133
+ })
134
+ export class {{pascal}}Module {}
135
+ `,
136
+ names,
137
+ {}
138
+ );
139
+ const select = apply(
140
+ `import { Prisma } from '{{prismaImport}}';
141
+
142
+ type {{pascal}}SelectPresetKey = keyof typeof {{camel}}SelectPresets;
143
+
144
+ export function get{{pascal}}Select<K extends {{pascal}}SelectPresetKey>(key: K) {
145
+ return {{camel}}SelectPresets[key];
146
+ }
147
+
148
+ export const {{camel}}SelectPresets = {
149
+ minimal: {
150
+ id: true,
151
+ } satisfies Prisma.{{pascal}}Select,
152
+
153
+ general: {
154
+ id: true,
155
+ } satisfies Prisma.{{pascal}}Select,
156
+ };
157
+ `,
158
+ names,
159
+ { "{{prismaImport}}": prismaImport }
160
+ );
161
+ const where = apply(
162
+ `import { Prisma } from '{{prismaImport}}';
163
+
164
+ export function where{{pascal}}GetManyPaginate(_filter: {
165
+ q?: string;
166
+ }): {
167
+ where: Prisma.{{pascal}}WhereInput;
168
+ } {
169
+ return { where: {} };
170
+ }
171
+ `,
172
+ names,
173
+ { "{{prismaImport}}": prismaImport }
174
+ );
175
+ return [
176
+ { relativePath: `${base}/${names.kebab}.module.ts`, content: moduleFile },
177
+ {
178
+ relativePath: `${base}/controllers/${names.kebab}.controller.ts`,
179
+ content: controller
180
+ },
181
+ {
182
+ relativePath: `${base}/services/${names.kebab}.service.ts`,
183
+ content: service
184
+ },
185
+ repository,
186
+ {
187
+ relativePath: `${base}/types/select-${names.kebab}.type.ts`,
188
+ content: select
189
+ },
190
+ {
191
+ relativePath: `${base}/types/where-${names.kebab}.type.ts`,
192
+ content: where
193
+ }
194
+ ];
195
+ }
196
+
197
+ // src/commands/generate.ts
198
+ import * as fs from "fs";
199
+ import * as path from "path";
200
+ function runGenerate(options) {
201
+ const cwd = options.cwd ?? process.cwd();
202
+ const names = resolveNames(options.name, options.route);
203
+ const full = !!options.full;
204
+ const files = renderModuleFiles({
205
+ names,
206
+ cacheEnabled: !!options.cache,
207
+ full,
208
+ prismaImport: options.prismaImport
209
+ });
210
+ for (const file of files) {
211
+ const fullPath = path.join(cwd, file.relativePath);
212
+ if (options.dryRun) {
213
+ console.log(`[dry-run] would write ${file.relativePath}`);
214
+ continue;
215
+ }
216
+ if (fs.existsSync(fullPath)) {
217
+ console.warn(`skip (exists): ${file.relativePath}`);
218
+ continue;
219
+ }
220
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
221
+ const content = file.content.endsWith("\n") ? file.content : `${file.content}
222
+ `;
223
+ fs.writeFileSync(fullPath, content, "utf-8");
224
+ console.log(`created ${file.relativePath}`);
225
+ }
226
+ if (full) {
227
+ console.log(
228
+ `
229
+ Scaffolded module "${names.kebab}". Register ${names.pascal}Module in app.module.ts.`
230
+ );
231
+ } else {
232
+ console.log(
233
+ `
234
+ Scaffolded repository "${names.pascal}Repository". Register it in your feature module providers.`
235
+ );
236
+ }
237
+ }
238
+
239
+ // src/commands/codegen.ts
240
+ import * as fs2 from "fs";
241
+ import * as path2 from "path";
242
+ import {
243
+ computeRelationAliasesFromSchema,
244
+ getSchemaModels
245
+ } from "@prismakit/core";
246
+ function runCodegen(options = {}) {
247
+ const cwd = options.cwd ?? process.cwd();
248
+ const schemaPath = options.schemaPath ?? path2.join(cwd, "prisma", "schema.prisma");
249
+ if (!fs2.existsSync(schemaPath)) {
250
+ throw new Error(`Prisma schema not found at ${schemaPath}`);
251
+ }
252
+ const models = getSchemaModels(schemaPath);
253
+ const aliases = computeRelationAliasesFromSchema(models);
254
+ const entries = Object.entries(aliases).sort(
255
+ ([a], [b]) => a.localeCompare(b)
256
+ );
257
+ if (entries.length === 0) {
258
+ console.log(
259
+ "No additional relation aliases suggested (suffix rules cover all)."
260
+ );
261
+ return;
262
+ }
263
+ const lines = [
264
+ "// Suggested RELATION_MODEL_ALIASES entries (merge into your resolver config)",
265
+ "export const SUGGESTED_RELATION_MODEL_ALIASES = {",
266
+ ...entries.map(([k, v]) => ` ${k}: '${v}',`),
267
+ "} as const;",
268
+ ""
269
+ ];
270
+ const output = lines.join("\n");
271
+ if (options.write) {
272
+ const out = options.outFile ?? path2.join(
273
+ cwd,
274
+ "src",
275
+ "infrastructure",
276
+ "prisma",
277
+ "suggested-relation-aliases.ts"
278
+ );
279
+ fs2.mkdirSync(path2.dirname(out), { recursive: true });
280
+ fs2.writeFileSync(out, output, "utf-8");
281
+ console.log(`wrote ${path2.relative(cwd, out)}`);
282
+ } else {
283
+ console.log(output);
284
+ }
285
+ console.log(`
286
+ ${entries.length} alias suggestion(s).`);
287
+ }
288
+
289
+ // src/commands/validate.ts
290
+ import {
291
+ assertSelectComposeValid,
292
+ validateSelectCompose
293
+ } from "@prismakit/core";
294
+ function runValidate(options = {}) {
295
+ const cwd = options.cwd ?? process.cwd();
296
+ if (options.assert !== false) {
297
+ try {
298
+ assertSelectComposeValid(cwd);
299
+ console.log("Select compose validation passed.");
300
+ } catch (err) {
301
+ console.error(err.message);
302
+ process.exitCode = 1;
303
+ }
304
+ return;
305
+ }
306
+ const issues = validateSelectCompose(cwd);
307
+ if (issues.length === 0) {
308
+ console.log("Select compose validation passed.");
309
+ return;
310
+ }
311
+ for (const issue of issues) {
312
+ console.error(` - ${issue.file}: ${issue.message}`);
313
+ }
314
+ process.exitCode = 1;
315
+ }
316
+
317
+ export {
318
+ assertKebabName,
319
+ resolveNames,
320
+ renderModuleFiles,
321
+ runGenerate,
322
+ runCodegen,
323
+ runValidate
324
+ };
325
+ //# sourceMappingURL=chunk-36ZM4UZV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/naming.ts","../src/templates.ts","../src/commands/generate.ts","../src/commands/codegen.ts","../src/commands/validate.ts"],"sourcesContent":["export interface ModuleNames {\n kebab: string;\n camel: string;\n pascal: string;\n repoModel: string;\n route: string;\n}\n\nconst KEBAB_NAME_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\n\nexport function assertKebabName(name: string): void {\n if (!KEBAB_NAME_RE.test(name)) {\n throw new Error(\n `Invalid module name \"${name}\". Use kebab-case (e.g. product, blog-post).`,\n );\n }\n}\n\nfunction kebabToPascal(kebab: string): string {\n return kebab\n .split('-')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction kebabToCamel(kebab: string): string {\n const pascal = kebabToPascal(kebab);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\nexport function resolveNames(kebab: string, route?: string): ModuleNames {\n assertKebabName(kebab);\n const pascal = kebabToPascal(kebab);\n const camel = kebabToCamel(kebab);\n return {\n kebab,\n camel,\n pascal,\n repoModel: camel,\n route: route ?? kebab,\n };\n}\n","import type { ModuleNames } from './naming';\n\nexport type GenerateOptions = {\n names: ModuleNames;\n cacheEnabled: boolean;\n /** When false (default), only emit the repository file. */\n full?: boolean;\n /** Prisma client import path (default `@prisma/client`). */\n prismaImport?: string;\n};\n\nfunction apply(template: string, names: ModuleNames, extras: Record<string, string>): string {\n const replacements: Record<string, string> = {\n '{{pascal}}': names.pascal,\n '{{camel}}': names.camel,\n '{{kebab}}': names.kebab,\n '{{route}}': names.route,\n '{{repoModel}}': names.repoModel,\n ...extras,\n };\n let result = template;\n for (const [key, value] of Object.entries(replacements)) {\n result = result.split(key).join(value);\n }\n return result;\n}\n\nexport type GeneratedFile = {\n relativePath: string;\n content: string;\n};\n\nfunction renderRepository(\n names: ModuleNames,\n cacheEnabled: boolean,\n prismaImport: string,\n base: string,\n): GeneratedFile {\n const cacheBlock = cacheEnabled\n ? ` cache: {\n ttl: 86400,\n sensitiveFields: ['password'],\n },\n`\n : '';\n\n const content = apply(\n `import { Prisma } from '{{prismaImport}}';\nimport { createInjectableRepository } from '@prismakit/nestjs';\n\nexport const {{pascal}}Repository = createInjectableRepository({\n model: '{{repoModel}}',\n scalarFields: Prisma.{{pascal}}ScalarFieldEnum,\n{{cacheBlock}}});\n\nexport type {{pascal}}Repository = InstanceType<typeof {{pascal}}Repository>;\n`,\n names,\n {\n '{{cacheBlock}}': cacheBlock,\n '{{prismaImport}}': prismaImport,\n },\n );\n\n return {\n relativePath: `${base}/repositories/${names.kebab}.repository.ts`,\n content,\n };\n}\n\nexport function renderModuleFiles(options: GenerateOptions): GeneratedFile[] {\n const { names, cacheEnabled, full = false } = options;\n const prismaImport = options.prismaImport ?? '@prisma/client';\n const base = `src/modules/${names.kebab}`;\n\n const repository = renderRepository(names, cacheEnabled, prismaImport, base);\n\n if (!full) {\n return [repository];\n }\n\n const service = apply(\n `import { Injectable } from '@nestjs/common';\n\nimport { {{pascal}}Repository } from '../repositories/{{kebab}}.repository';\nimport { get{{pascal}}Select } from '../types/select-{{kebab}}.type';\n\n@Injectable()\nexport class {{pascal}}Service {\n constructor(private readonly {{camel}}Repository: {{pascal}}Repository) {}\n\n async handleGetById(id: string) {\n return await this.{{camel}}Repository.getThrowById({\n id,\n select: get{{pascal}}Select('general'),\n setCache: true,\n });\n }\n}\n`,\n names,\n {},\n );\n\n const controller = apply(\n `import { Controller, Get, Param } from '@nestjs/common';\n\nimport { {{pascal}}Service } from '../services/{{kebab}}.service';\n\n@Controller('{{route}}')\nexport class {{pascal}}Controller {\n constructor(private readonly {{camel}}Service: {{pascal}}Service) {}\n\n @Get(':id')\n async getById(@Param('id') id: string) {\n return this.{{camel}}Service.handleGetById(id);\n }\n}\n`,\n names,\n {},\n );\n\n const moduleFile = apply(\n `import { Module } from '@nestjs/common';\n\nimport { {{pascal}}Controller } from './controllers/{{kebab}}.controller';\nimport { {{pascal}}Service } from './services/{{kebab}}.service';\nimport { {{pascal}}Repository } from './repositories/{{kebab}}.repository';\n\n@Module({\n controllers: [{{pascal}}Controller],\n providers: [{{pascal}}Service, {{pascal}}Repository],\n exports: [{{pascal}}Service, {{pascal}}Repository],\n})\nexport class {{pascal}}Module {}\n`,\n names,\n {},\n );\n\n const select = apply(\n `import { Prisma } from '{{prismaImport}}';\n\ntype {{pascal}}SelectPresetKey = keyof typeof {{camel}}SelectPresets;\n\nexport function get{{pascal}}Select<K extends {{pascal}}SelectPresetKey>(key: K) {\n return {{camel}}SelectPresets[key];\n}\n\nexport const {{camel}}SelectPresets = {\n minimal: {\n id: true,\n } satisfies Prisma.{{pascal}}Select,\n\n general: {\n id: true,\n } satisfies Prisma.{{pascal}}Select,\n};\n`,\n names,\n { '{{prismaImport}}': prismaImport },\n );\n\n const where = apply(\n `import { Prisma } from '{{prismaImport}}';\n\nexport function where{{pascal}}GetManyPaginate(_filter: {\n q?: string;\n}): {\n where: Prisma.{{pascal}}WhereInput;\n} {\n return { where: {} };\n}\n`,\n names,\n { '{{prismaImport}}': prismaImport },\n );\n\n return [\n { relativePath: `${base}/${names.kebab}.module.ts`, content: moduleFile },\n {\n relativePath: `${base}/controllers/${names.kebab}.controller.ts`,\n content: controller,\n },\n {\n relativePath: `${base}/services/${names.kebab}.service.ts`,\n content: service,\n },\n repository,\n {\n relativePath: `${base}/types/select-${names.kebab}.type.ts`,\n content: select,\n },\n {\n relativePath: `${base}/types/where-${names.kebab}.type.ts`,\n content: where,\n },\n ];\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { resolveNames } from '../naming';\nimport { renderModuleFiles } from '../templates';\n\nexport type GenerateCommandOptions = {\n name: string;\n cache?: boolean;\n route?: string;\n cwd?: string;\n dryRun?: boolean;\n /** Emit full Nest module (controller/service/types). Default: repo-only. */\n full?: boolean;\n /** Prisma client import path (default `@prisma/client`). */\n prismaImport?: string;\n};\n\nexport function runGenerate(options: GenerateCommandOptions): void {\n const cwd = options.cwd ?? process.cwd();\n const names = resolveNames(options.name, options.route);\n const full = !!options.full;\n const files = renderModuleFiles({\n names,\n cacheEnabled: !!options.cache,\n full,\n prismaImport: options.prismaImport,\n });\n\n for (const file of files) {\n const fullPath = path.join(cwd, file.relativePath);\n if (options.dryRun) {\n console.log(`[dry-run] would write ${file.relativePath}`);\n continue;\n }\n if (fs.existsSync(fullPath)) {\n console.warn(`skip (exists): ${file.relativePath}`);\n continue;\n }\n fs.mkdirSync(path.dirname(fullPath), { recursive: true });\n const content = file.content.endsWith('\\n')\n ? file.content\n : `${file.content}\\n`;\n fs.writeFileSync(fullPath, content, 'utf-8');\n console.log(`created ${file.relativePath}`);\n }\n\n if (full) {\n console.log(\n `\\nScaffolded module \"${names.kebab}\". Register ${names.pascal}Module in app.module.ts.`,\n );\n } else {\n console.log(\n `\\nScaffolded repository \"${names.pascal}Repository\". Register it in your feature module providers.`,\n );\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport {\n computeRelationAliasesFromSchema,\n getSchemaModels,\n} from '@prismakit/core';\n\nexport type CodegenCommandOptions = {\n cwd?: string;\n schemaPath?: string;\n write?: boolean;\n outFile?: string;\n};\n\n/**\n * Parse prisma/schema.prisma and print (or write) suggested relation aliases.\n */\nexport function runCodegen(options: CodegenCommandOptions = {}): void {\n const cwd = options.cwd ?? process.cwd();\n const schemaPath =\n options.schemaPath ?? path.join(cwd, 'prisma', 'schema.prisma');\n\n if (!fs.existsSync(schemaPath)) {\n throw new Error(`Prisma schema not found at ${schemaPath}`);\n }\n\n const models = getSchemaModels(schemaPath);\n const aliases = computeRelationAliasesFromSchema(models);\n\n const entries = Object.entries(aliases).sort(([a], [b]) =>\n a.localeCompare(b),\n );\n\n if (entries.length === 0) {\n console.log(\n 'No additional relation aliases suggested (suffix rules cover all).',\n );\n return;\n }\n\n const lines = [\n '// Suggested RELATION_MODEL_ALIASES entries (merge into your resolver config)',\n 'export const SUGGESTED_RELATION_MODEL_ALIASES = {',\n ...entries.map(([k, v]) => ` ${k}: '${v}',`),\n '} as const;',\n '',\n ];\n const output = lines.join('\\n');\n\n if (options.write) {\n const out =\n options.outFile ??\n path.join(\n cwd,\n 'src',\n 'infrastructure',\n 'prisma',\n 'suggested-relation-aliases.ts',\n );\n fs.mkdirSync(path.dirname(out), { recursive: true });\n fs.writeFileSync(out, output, 'utf-8');\n console.log(`wrote ${path.relative(cwd, out)}`);\n } else {\n console.log(output);\n }\n\n console.log(`\\n${entries.length} alias suggestion(s).`);\n}\n","import {\n assertSelectComposeValid,\n validateSelectCompose,\n} from '@prismakit/core';\n\nexport type ValidateCommandOptions = {\n cwd?: string;\n assert?: boolean;\n};\n\n/**\n * Run select-compose validation from @prismakit/core.\n */\nexport function runValidate(options: ValidateCommandOptions = {}): void {\n const cwd = options.cwd ?? process.cwd();\n\n if (options.assert !== false) {\n try {\n assertSelectComposeValid(cwd);\n console.log('Select compose validation passed.');\n } catch (err) {\n console.error((err as Error).message);\n process.exitCode = 1;\n }\n return;\n }\n\n const issues = validateSelectCompose(cwd);\n if (issues.length === 0) {\n console.log('Select compose validation passed.');\n return;\n }\n\n for (const issue of issues) {\n console.error(` - ${issue.file}: ${issue.message}`);\n }\n process.exitCode = 1;\n}\n"],"mappings":"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","names":["fs","path"]}