prisma-kysely 3.0.0 → 3.1.1

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.
@@ -0,0 +1,861 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/generator.ts
5
+ import generatorHelper from "@prisma/generator-helper";
6
+ import path3 from "node:path";
7
+ // package.json
8
+ var package_default = {
9
+ name: "prisma-kysely",
10
+ version: "3.1.1",
11
+ description: "Generate Kysely database types from a Prisma schema",
12
+ repository: {
13
+ url: "git+https://github.com/valtyr/prisma-kysely.git"
14
+ },
15
+ type: "module",
16
+ license: "MIT",
17
+ keywords: [
18
+ "prisma",
19
+ "kysely",
20
+ "generator",
21
+ "typescript",
22
+ "codegen",
23
+ "sql"
24
+ ],
25
+ author: {
26
+ name: "Valtyr Orn Kjartansson",
27
+ url: "http://valtyr.is"
28
+ },
29
+ contributors: [
30
+ {
31
+ name: "Alistair Smith",
32
+ url: "https://alistair.sh"
33
+ },
34
+ {
35
+ name: "Arthur Fiorette",
36
+ url: "https://arthur.place"
37
+ }
38
+ ],
39
+ exports: {
40
+ ".": "./dist/generator.js",
41
+ "./generator": "./dist/generator.js",
42
+ "./bin": "./dist/bin.js"
43
+ },
44
+ bin: {
45
+ "prisma-kysely": "dist/bin.js"
46
+ },
47
+ files: [
48
+ "dist",
49
+ "README.md",
50
+ "LICENSE",
51
+ "package.json"
52
+ ],
53
+ scripts: {
54
+ build: "bunup src/bin.ts src/generator.ts --packages external --format esm --splitting",
55
+ dev: "bun run build --watch",
56
+ fix: "prettier --write .",
57
+ lint: "eslint ./src",
58
+ prepack: "bun run build",
59
+ release: "bun run build && bun changeset publish",
60
+ start: "node dist/bin.js",
61
+ test: "bun run build && bun test",
62
+ typecheck: "tsc --noEmit"
63
+ },
64
+ dependencies: {
65
+ "@mrleebo/prisma-ast": "^0.14.0",
66
+ "@prisma/generator-helper": "^7.0.0",
67
+ "@prisma/internals": "^7.0.0",
68
+ typescript: "^5.9.3",
69
+ zod: "^4.4.3"
70
+ },
71
+ devDependencies: {
72
+ "@changesets/cli": "^2.31.0",
73
+ "@types/bun": "^1.3.14",
74
+ "@types/node": "25.3.3",
75
+ "@types/pg": "^8.20.0",
76
+ "@types/prettier": "3.0.0",
77
+ bunup: "^0.16.31",
78
+ eslint: "^10.4.0",
79
+ kysely: "^0.28.17",
80
+ mysql2: "^3.22.3",
81
+ pg: "^8.21.0",
82
+ prettier: "^3.8.3",
83
+ prisma: "^7.8.0",
84
+ "typescript-eslint": "^8.59.4"
85
+ },
86
+ peerDependencies: {
87
+ prisma: ">=7.0.0"
88
+ },
89
+ packageManager: "bun@1.3.14"
90
+ };
91
+
92
+ // src/constants.ts
93
+ var GENERATOR_NAME = "Kysely types";
94
+
95
+ // src/helpers/generateDatabaseType.ts
96
+ import ts2 from "typescript";
97
+
98
+ // src/utils/isValidTSIdentifier.ts
99
+ var isValidTSIdentifier = (ident) => !!ident && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(ident);
100
+ var isValidTSIdentifier_default = isValidTSIdentifier;
101
+
102
+ // src/utils/words.ts
103
+ function createCamelCaseMapper({
104
+ upperCase = false
105
+ } = {}) {
106
+ return memoize((str) => {
107
+ if (str.length === 0) {
108
+ return str;
109
+ }
110
+ if (upperCase && isAllUpperCaseSnakeCase(str)) {
111
+ str = str.toLowerCase();
112
+ }
113
+ let out = str[0];
114
+ for (let i = 1, l = str.length;i < l; ++i) {
115
+ const char = str[i];
116
+ const prevChar = str[i - 1];
117
+ if (char !== "_") {
118
+ if (prevChar === "_") {
119
+ out += char.toUpperCase();
120
+ } else {
121
+ out += char;
122
+ }
123
+ }
124
+ }
125
+ return out;
126
+ });
127
+ }
128
+ function isAllUpperCaseSnakeCase(str) {
129
+ for (let i = 1, l = str.length;i < l; ++i) {
130
+ const char = str[i];
131
+ if (char !== "_" && char !== char.toUpperCase()) {
132
+ return false;
133
+ }
134
+ }
135
+ return true;
136
+ }
137
+ function memoize(func) {
138
+ const cache = new Map;
139
+ return (str) => {
140
+ let mapped = cache.get(str);
141
+ if (!mapped) {
142
+ mapped = func(str);
143
+ cache.set(str, mapped);
144
+ }
145
+ return mapped;
146
+ };
147
+ }
148
+ function capitalize(str) {
149
+ return str.charAt(0).toUpperCase() + str.slice(1);
150
+ }
151
+
152
+ // src/utils/normalizeCase.ts
153
+ var snakeToCamel = createCamelCaseMapper();
154
+ var normalizeCase = (name, config) => {
155
+ if (!config.camelCase)
156
+ return name;
157
+ return snakeToCamel(name);
158
+ };
159
+
160
+ // src/utils/sorted.ts
161
+ var sorted = (list, sortFunction) => {
162
+ const newList = [...list];
163
+ newList.sort(sortFunction);
164
+ return newList;
165
+ };
166
+
167
+ // src/helpers/wrappedTypeHelpers.ts
168
+ import ts from "typescript";
169
+ var toTableTypeName = (modelName) => `${modelName}Table`;
170
+ var convertToWrappedTypes = (modelDefinition) => {
171
+ const modelName = modelDefinition.name.text;
172
+ const tableTypeName = toTableTypeName(modelName);
173
+ return [
174
+ { ...modelDefinition, name: ts.factory.createIdentifier(tableTypeName) },
175
+ ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(modelName), undefined, ts.factory.createTypeReferenceNode("Selectable", [
176
+ ts.factory.createTypeReferenceNode(tableTypeName, undefined)
177
+ ])),
178
+ ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`New${modelName}`), undefined, ts.factory.createTypeReferenceNode("Insertable", [
179
+ ts.factory.createTypeReferenceNode(tableTypeName, undefined)
180
+ ])),
181
+ ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${modelName}Update`), undefined, ts.factory.createTypeReferenceNode("Updateable", [
182
+ ts.factory.createTypeReferenceNode(tableTypeName, undefined)
183
+ ]))
184
+ ];
185
+ };
186
+
187
+ // src/helpers/generateDatabaseType.ts
188
+ var generateDatabaseType = (models, config) => {
189
+ const sortedModels = sorted(models, (a, b) => a.tableName.localeCompare(b.tableName));
190
+ const properties = sortedModels.map((field) => {
191
+ const caseNormalizedTableName = normalizeCase(field.tableName, config);
192
+ const nameIdentifier = isValidTSIdentifier_default(caseNormalizedTableName) ? ts2.factory.createIdentifier(caseNormalizedTableName) : ts2.factory.createStringLiteral(caseNormalizedTableName);
193
+ const typeName = config.exportWrappedTypes ? toTableTypeName(field.typeName) : field.typeName;
194
+ return ts2.factory.createPropertySignature(undefined, nameIdentifier, undefined, ts2.factory.createTypeReferenceNode(ts2.factory.createIdentifier(typeName), undefined));
195
+ });
196
+ return ts2.factory.createTypeAliasDeclaration([ts2.factory.createModifier(ts2.SyntaxKind.ExportKeyword)], ts2.factory.createIdentifier(config.dbTypeName), undefined, ts2.factory.createTypeLiteralNode(properties));
197
+ };
198
+
199
+ // src/helpers/generateEnumType.ts
200
+ import ts5 from "typescript";
201
+
202
+ // src/helpers/generateStringLiteralUnion.ts
203
+ import ts3 from "typescript";
204
+ var generateStringLiteralUnion = (stringLiterals) => {
205
+ if (stringLiterals.length === 0)
206
+ return null;
207
+ if (stringLiterals.length === 1)
208
+ return ts3.factory.createLiteralTypeNode(ts3.factory.createStringLiteral(stringLiterals[0]));
209
+ return ts3.factory.createUnionTypeNode(stringLiterals.map((literal) => ts3.factory.createLiteralTypeNode(ts3.factory.createStringLiteral(literal))));
210
+ };
211
+
212
+ // src/helpers/generateTypedReferenceNode.ts
213
+ import ts4 from "typescript";
214
+ var generateTypedReferenceNode = (name) => {
215
+ return ts4.factory.createTypeAliasDeclaration([ts4.factory.createModifier(ts4.SyntaxKind.ExportKeyword)], name, undefined, ts4.factory.createTypeReferenceNode(`(typeof ${name})[keyof typeof ${name}]`, undefined));
216
+ };
217
+
218
+ // src/helpers/generateEnumType.ts
219
+ var generateEnumType = (name, values) => {
220
+ const type = generateStringLiteralUnion(values.map((v) => v.name));
221
+ if (!type) {
222
+ return;
223
+ }
224
+ const objectDeclaration = ts5.factory.createVariableStatement([ts5.factory.createModifier(ts5.SyntaxKind.ExportKeyword)], ts5.factory.createVariableDeclarationList([
225
+ ts5.factory.createVariableDeclaration(name, undefined, undefined, ts5.factory.createAsExpression(ts5.factory.createObjectLiteralExpression(values.map((v) => {
226
+ const identifier = isValidTSIdentifier_default(v.name) ? ts5.factory.createIdentifier(v.name) : ts5.factory.createStringLiteral(v.name);
227
+ return ts5.factory.createPropertyAssignment(identifier, ts5.factory.createStringLiteral(v.dbName || v.name));
228
+ }), true), ts5.factory.createTypeReferenceNode(ts5.factory.createIdentifier("const"), undefined)))
229
+ ], ts5.NodeFlags.Const));
230
+ const typeDeclaration = generateTypedReferenceNode(name);
231
+ return {
232
+ typeName: name,
233
+ objectDeclaration,
234
+ typeDeclaration
235
+ };
236
+ };
237
+
238
+ // src/helpers/generateFiles.ts
239
+ import path from "node:path";
240
+ import ts7 from "typescript";
241
+
242
+ // src/helpers/generateFile.ts
243
+ import ts6 from "typescript";
244
+ var printer = ts6.createPrinter({ newLine: ts6.NewLineKind.LineFeed });
245
+ var generateFile = (statements, { withEnumImport, withLeader, exportWrappedTypes, banner }) => {
246
+ const file = ts6.factory.createSourceFile(statements, ts6.factory.createToken(ts6.SyntaxKind.EndOfFileToken), ts6.NodeFlags.None);
247
+ const result = printer.printFile(file);
248
+ const leader = `${banner ? `${banner}
249
+ ` : ""}import type { ColumnType${result.includes("GeneratedAlways") ? ", GeneratedAlways" : ""}${exportWrappedTypes ? ", Insertable, Selectable, Updateable" : ""} } from "kysely";
250
+ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
251
+ ? ColumnType<S, I | undefined, U>
252
+ : ColumnType<T, T | undefined, T>;
253
+ export type Timestamp = ColumnType<Date, Date | string, Date | string>;`;
254
+ if (withEnumImport) {
255
+ const enumImportStatement = `import type { ${withEnumImport.names.join(", ")} } from "${withEnumImport.importPath}";`;
256
+ return withLeader ? `${leader}
257
+
258
+ ${enumImportStatement}
259
+
260
+ ${result}` : `${enumImportStatement}
261
+
262
+ ${result}`;
263
+ }
264
+ return withLeader ? `${leader}
265
+
266
+ ${result}` : result;
267
+ };
268
+
269
+ // src/helpers/generateFiles.ts
270
+ function generateFiles(opts) {
271
+ const models = opts.models.map(({ definition, ...rest }) => ({
272
+ ...rest,
273
+ definitions: opts.exportWrappedTypes ? convertToWrappedTypes(definition) : [definition]
274
+ }));
275
+ if (opts.enumsOutfile === opts.typesOutfile || opts.enums.length === 0) {
276
+ let statements;
277
+ if (!opts.groupBySchema) {
278
+ statements = [
279
+ ...opts.enums.flatMap((e) => [e.objectDeclaration, e.typeDeclaration]),
280
+ ...models.flatMap((m) => m.definitions)
281
+ ];
282
+ } else {
283
+ statements = groupModelsAndEnum(opts.enums, models, opts.defaultSchema);
284
+ }
285
+ const typesFileWithEnums = {
286
+ filepath: opts.typesOutfile,
287
+ content: generateFile([...statements, opts.databaseType], {
288
+ withEnumImport: false,
289
+ withLeader: true,
290
+ exportWrappedTypes: opts.exportWrappedTypes,
291
+ banner: opts.banner
292
+ })
293
+ };
294
+ return [typesFileWithEnums];
295
+ }
296
+ const typesFileWithoutEnums = {
297
+ filepath: opts.typesOutfile,
298
+ content: generateFile([...models.flatMap((m) => m.definitions), opts.databaseType], {
299
+ withEnumImport: {
300
+ importPath: `./${path.parse(opts.enumsOutfile).name}${opts.importExtension}`,
301
+ names: opts.enumNames
302
+ },
303
+ withLeader: true,
304
+ exportWrappedTypes: opts.exportWrappedTypes,
305
+ banner: opts.banner
306
+ })
307
+ };
308
+ if (opts.enums.length === 0)
309
+ return [typesFileWithoutEnums];
310
+ const enumFile = {
311
+ filepath: opts.enumsOutfile,
312
+ content: generateFile(opts.enums.flatMap((e) => [e.objectDeclaration, e.typeDeclaration]), {
313
+ withEnumImport: false,
314
+ withLeader: false,
315
+ exportWrappedTypes: opts.exportWrappedTypes,
316
+ banner: opts.banner
317
+ })
318
+ };
319
+ return [typesFileWithoutEnums, enumFile];
320
+ }
321
+ function* groupModelsAndEnum(enums, models, defaultSchema) {
322
+ const groupsMap = new Map;
323
+ for (const enumType of enums) {
324
+ if (!enumType.schema || enumType.schema === defaultSchema) {
325
+ yield enumType.objectDeclaration;
326
+ yield enumType.typeDeclaration;
327
+ continue;
328
+ }
329
+ const group = groupsMap.get(enumType.schema);
330
+ if (!group) {
331
+ groupsMap.set(enumType.schema, [
332
+ enumType.objectDeclaration,
333
+ enumType.typeDeclaration
334
+ ]);
335
+ } else {
336
+ group.push(enumType.objectDeclaration, enumType.typeDeclaration);
337
+ }
338
+ }
339
+ for (const model of models) {
340
+ if (!model.schema || model.schema === defaultSchema) {
341
+ yield* model.definitions;
342
+ continue;
343
+ }
344
+ const group = groupsMap.get(model.schema);
345
+ if (!group) {
346
+ groupsMap.set(model.schema, model.definitions);
347
+ } else {
348
+ group.push(...model.definitions);
349
+ }
350
+ }
351
+ for (const [schema, group] of groupsMap) {
352
+ yield ts7.factory.createModuleDeclaration([ts7.factory.createModifier(ts7.SyntaxKind.ExportKeyword)], ts7.factory.createIdentifier(capitalize(schema)), ts7.factory.createModuleBlock(group), ts7.NodeFlags.Namespace);
353
+ }
354
+ }
355
+
356
+ // src/helpers/generateImplicitManyToManyModels.ts
357
+ function generateImplicitManyToManyModels(models) {
358
+ const manyToManyFields = filterManyToManyRelationFields(models);
359
+ if (!manyToManyFields.length) {
360
+ return [];
361
+ }
362
+ return generateModels(manyToManyFields, models, []);
363
+ }
364
+ function generateModels(manyToManyFields, models, manyToManyTables = []) {
365
+ const manyFirst = manyToManyFields.shift();
366
+ if (!manyFirst) {
367
+ return manyToManyTables;
368
+ }
369
+ const manySecond = manyToManyFields.find((field) => field.relationName === manyFirst.relationName);
370
+ if (!manySecond) {
371
+ return manyToManyTables;
372
+ }
373
+ manyToManyTables.push({
374
+ dbName: `_${manyFirst.relationName}`,
375
+ name: manyFirst.relationName || "",
376
+ primaryKey: null,
377
+ schema: null,
378
+ uniqueFields: [],
379
+ uniqueIndexes: [],
380
+ fields: generateJoinFields([manyFirst, manySecond], models)
381
+ });
382
+ return generateModels(manyToManyFields.filter((field) => field.relationName !== manyFirst.relationName), models, manyToManyTables);
383
+ }
384
+ function generateJoinFields(fields, models) {
385
+ if (fields.length !== 2)
386
+ throw new Error("Huh?");
387
+ const sortedFields = sorted(fields, (a, b) => a.type.localeCompare(b.type));
388
+ const joinedA = getJoinIdField(sortedFields[0], models);
389
+ const joinedB = getJoinIdField(sortedFields[1], models);
390
+ return [
391
+ {
392
+ name: "A",
393
+ type: joinedA.type,
394
+ kind: joinedA.kind,
395
+ isRequired: true,
396
+ isList: false,
397
+ isUnique: false,
398
+ isId: false,
399
+ isReadOnly: true,
400
+ hasDefaultValue: false
401
+ },
402
+ {
403
+ name: "B",
404
+ type: joinedB.type,
405
+ kind: joinedB.kind,
406
+ isRequired: true,
407
+ isList: false,
408
+ isUnique: false,
409
+ isId: false,
410
+ isReadOnly: true,
411
+ hasDefaultValue: false
412
+ }
413
+ ];
414
+ }
415
+ function getJoinIdField(joinField, models) {
416
+ const joinedModel = models.find((m) => m.name === joinField.type);
417
+ if (!joinedModel)
418
+ throw new Error("Could not find referenced model");
419
+ const idField = joinedModel.fields.find((f) => f.isId);
420
+ if (!idField)
421
+ throw new Error("No ID field on referenced model");
422
+ return idField;
423
+ }
424
+ function filterManyToManyRelationFields(models) {
425
+ const fields = models.flatMap((model) => model.fields);
426
+ const relationFields = fields.filter((field) => !!field.relationName);
427
+ const nonManyToManyRelationNames = relationFields.filter((field) => !field.isList).map((field) => field.relationName);
428
+ const notManyToMany = new Set(nonManyToManyRelationNames);
429
+ return relationFields.filter((field) => !notManyToMany.has(field.relationName));
430
+ }
431
+
432
+ // src/helpers/generateModel.ts
433
+ import ts9 from "typescript";
434
+
435
+ // src/helpers/generateField.ts
436
+ import ts8 from "typescript";
437
+
438
+ // src/utils/applyJSDocWorkaround.ts
439
+ var applyJSDocWorkaround = (comment) => {
440
+ return `*
441
+ * ${comment.split(`
442
+ `).join(`
443
+ * `)}
444
+ `;
445
+ };
446
+
447
+ // src/helpers/generateField.ts
448
+ var generateField = (args) => {
449
+ const { name, type, nullable, generated, list, documentation, isId, config } = args;
450
+ let fieldType = type;
451
+ if (nullable)
452
+ fieldType = ts8.factory.createUnionTypeNode([
453
+ fieldType,
454
+ ts8.factory.createLiteralTypeNode(ts8.factory.createToken(ts8.SyntaxKind.NullKeyword))
455
+ ]);
456
+ if (list)
457
+ fieldType = ts8.factory.createArrayTypeNode(fieldType);
458
+ if (generated) {
459
+ if (isId && config.readOnlyIds) {
460
+ fieldType = ts8.factory.createTypeReferenceNode(ts8.factory.createIdentifier("GeneratedAlways"), [fieldType]);
461
+ } else {
462
+ fieldType = ts8.factory.createTypeReferenceNode(ts8.factory.createIdentifier("Generated"), [fieldType]);
463
+ }
464
+ }
465
+ const nameIdentifier = isValidTSIdentifier_default(name) ? ts8.factory.createIdentifier(name) : ts8.factory.createStringLiteral(name);
466
+ const propertySignature = ts8.factory.createPropertySignature(undefined, nameIdentifier, undefined, fieldType);
467
+ if (documentation) {
468
+ return ts8.addSyntheticLeadingComment(propertySignature, ts8.SyntaxKind.MultiLineCommentTrivia, applyJSDocWorkaround(documentation), true);
469
+ }
470
+ return propertySignature;
471
+ };
472
+
473
+ // src/helpers/generateFieldType.ts
474
+ var sqliteTypeMap = {
475
+ BigInt: "number",
476
+ Boolean: "number",
477
+ Bytes: "Buffer",
478
+ DateTime: "string",
479
+ Decimal: "number",
480
+ Float: "number",
481
+ Int: "number",
482
+ Json: "unknown",
483
+ String: "string",
484
+ Unsupported: "unknown"
485
+ };
486
+ var mysqlTypeMap = {
487
+ BigInt: "number",
488
+ Boolean: "number",
489
+ Bytes: "Buffer",
490
+ DateTime: "Timestamp",
491
+ Decimal: "string",
492
+ Float: "number",
493
+ Int: "number",
494
+ Json: "unknown",
495
+ String: "string",
496
+ Unsupported: "unknown"
497
+ };
498
+ var postgresqlTypeMap = {
499
+ BigInt: "string",
500
+ Boolean: "boolean",
501
+ Bytes: "Buffer",
502
+ DateTime: "Timestamp",
503
+ Decimal: "string",
504
+ Float: "number",
505
+ Int: "number",
506
+ Json: "unknown",
507
+ String: "string",
508
+ Unsupported: "unknown"
509
+ };
510
+ var sqlServerTypeMap = {
511
+ BigInt: "number",
512
+ Boolean: "boolean",
513
+ Bytes: "Buffer",
514
+ DateTime: "Timestamp",
515
+ Decimal: "string",
516
+ Float: "number",
517
+ Int: "number",
518
+ Json: "unknown",
519
+ String: "string",
520
+ Unsupported: "unknown"
521
+ };
522
+ var overrideType = (type, config) => {
523
+ switch (type) {
524
+ case "String":
525
+ return config.stringTypeOverride;
526
+ case "DateTime":
527
+ return config.dateTimeTypeOverride;
528
+ case "Boolean":
529
+ return config.booleanTypeOverride;
530
+ case "BigInt":
531
+ return config.bigIntTypeOverride;
532
+ case "Int":
533
+ return config.intTypeOverride;
534
+ case "Float":
535
+ return config.floatTypeOverride;
536
+ case "Decimal":
537
+ return config.decimalTypeOverride;
538
+ case "Bytes":
539
+ return config.bytesTypeOverride;
540
+ case "Json":
541
+ return config.jsonTypeOverride;
542
+ case "Unsupported":
543
+ return config.unsupportedTypeOverride;
544
+ }
545
+ };
546
+ var generateFieldTypeInner = (type, config, typeOverride) => {
547
+ switch (config.databaseProvider) {
548
+ case "sqlite":
549
+ return typeOverride || overrideType(type, config) || sqliteTypeMap[type];
550
+ case "mysql":
551
+ return typeOverride || overrideType(type, config) || mysqlTypeMap[type];
552
+ case "postgresql":
553
+ return typeOverride || overrideType(type, config) || postgresqlTypeMap[type];
554
+ case "cockroachdb":
555
+ return typeOverride || overrideType(type, config) || postgresqlTypeMap[type];
556
+ case "sqlserver":
557
+ return typeOverride || overrideType(type, config) || sqlServerTypeMap[type];
558
+ }
559
+ };
560
+ var generateFieldType = (type, config, typeOverride) => {
561
+ const fieldType = generateFieldTypeInner(type, config, typeOverride || null);
562
+ if (!fieldType)
563
+ throw new Error(`Unsupported type ${type} for database ${config.databaseProvider}`);
564
+ return fieldType;
565
+ };
566
+
567
+ // src/helpers/generateTypeOverrideFromDocumentation.ts
568
+ var START_LEXEME = "@kyselyType(";
569
+ var generateTypeOverrideFromDocumentation = (documentation) => {
570
+ const tokens = documentation.split("");
571
+ let matchState = null;
572
+ let parentheses = 0;
573
+ let i = 0;
574
+ while (i < documentation.length) {
575
+ const currentToken = tokens[i];
576
+ if (matchState) {
577
+ if (currentToken === ")" && parentheses === 0)
578
+ return matchState.tokens.join("");
579
+ if (currentToken === ")")
580
+ parentheses--;
581
+ if (currentToken === "(")
582
+ parentheses++;
583
+ matchState.tokens.push(currentToken);
584
+ i++;
585
+ if (i === documentation.length) {
586
+ i = matchState.startLocation + 1;
587
+ matchState = null;
588
+ continue;
589
+ }
590
+ continue;
591
+ }
592
+ if (currentToken === "@") {
593
+ const isMatch = tokens.slice(i, i + START_LEXEME.length).join("") === START_LEXEME;
594
+ if (!isMatch) {
595
+ i++;
596
+ continue;
597
+ }
598
+ matchState = { tokens: [], startLocation: i };
599
+ i += START_LEXEME.length;
600
+ continue;
601
+ }
602
+ i++;
603
+ }
604
+ return null;
605
+ };
606
+
607
+ // src/helpers/generateModel.ts
608
+ var defaultTypesImplementedInJS = ["cuid", "uuid"];
609
+ var generateModel = (model, config, { defaultSchema, groupBySchema, multiSchemaMap }) => {
610
+ const properties = model.fields.flatMap((field) => {
611
+ const isGenerated = field.hasDefaultValue && !(typeof field.default === "object" && ("name" in field.default) && defaultTypesImplementedInJS.includes(field.default.name));
612
+ const typeOverride = field.documentation ? generateTypeOverrideFromDocumentation(field.documentation) : null;
613
+ if (field.kind === "object" || field.kind === "unsupported")
614
+ return [];
615
+ const dbName = typeof field.dbName === "string" ? field.dbName : null;
616
+ const schemaPrefix = groupBySchema && multiSchemaMap?.get(field.type);
617
+ if (field.kind === "enum") {
618
+ const isEnumArray = field.isList;
619
+ return generateField({
620
+ isId: field.isId,
621
+ name: normalizeCase(dbName || field.name, config),
622
+ type: isEnumArray ? ts9.factory.createKeywordTypeNode(ts9.SyntaxKind.StringKeyword) : ts9.factory.createTypeReferenceNode(ts9.factory.createIdentifier(schemaPrefix && defaultSchema !== schemaPrefix ? `${capitalize(schemaPrefix)}.${field.type}` : field.type), undefined),
623
+ nullable: !field.isRequired,
624
+ generated: isGenerated,
625
+ list: false,
626
+ documentation: field.documentation,
627
+ config
628
+ });
629
+ }
630
+ return generateField({
631
+ name: normalizeCase(dbName || field.name, config),
632
+ type: ts9.factory.createTypeReferenceNode(ts9.factory.createIdentifier(generateFieldType(field.type, config, typeOverride)), undefined),
633
+ nullable: !field.isRequired,
634
+ generated: isGenerated,
635
+ list: field.isList,
636
+ documentation: field.documentation,
637
+ isId: field.isId,
638
+ config
639
+ });
640
+ });
641
+ return {
642
+ typeName: model.name,
643
+ tableName: model.dbName || model.name,
644
+ definition: ts9.factory.createTypeAliasDeclaration([ts9.factory.createModifier(ts9.SyntaxKind.ExportKeyword)], ts9.factory.createIdentifier(model.name), undefined, ts9.factory.createTypeLiteralNode(properties))
645
+ };
646
+ };
647
+
648
+ // src/helpers/multiSchemaHelpers.ts
649
+ import { getSchema } from "@mrleebo/prisma-ast";
650
+ import ts10 from "typescript";
651
+ var convertToMultiSchemaModels = ({
652
+ defaultSchema,
653
+ filterBySchema,
654
+ groupBySchema,
655
+ models,
656
+ multiSchemaMap
657
+ }) => {
658
+ return models.flatMap((model) => {
659
+ const schemaName = multiSchemaMap?.get(model.typeName);
660
+ if (!schemaName) {
661
+ return model;
662
+ }
663
+ if (filterBySchema && !filterBySchema.has(schemaName)) {
664
+ return [];
665
+ }
666
+ if (schemaName === defaultSchema) {
667
+ return model;
668
+ }
669
+ return [
670
+ {
671
+ ...model,
672
+ typeName: groupBySchema ? `${capitalize(schemaName)}.${model.typeName}` : model.typeName,
673
+ tableName: model.tableName ? `${schemaName}.${model.tableName}` : undefined,
674
+ schema: groupBySchema ? schemaName : undefined
675
+ }
676
+ ];
677
+ });
678
+ };
679
+ var isIdentifierText = ts10.isIdentifierText;
680
+ function parseMultiSchemaMap(dataModelStr) {
681
+ const parsedSchema = getSchema(dataModelStr);
682
+ const multiSchemaMap = new Map;
683
+ for (const block of parsedSchema.list) {
684
+ if (block.type !== "model" && block.type !== "view" && block.type !== "type" && block.type !== "enum") {
685
+ continue;
686
+ }
687
+ const properties = block.type === "enum" ? block.enumerators : block.properties;
688
+ const schemaProperty = properties.find((prop) => prop.type === "attribute" && prop.name === "schema");
689
+ const schemaName = schemaProperty?.args?.[0].value;
690
+ if (typeof schemaName !== "string") {
691
+ multiSchemaMap.set(block.name, "");
692
+ } else {
693
+ const schema = JSON.parse(schemaName).toString();
694
+ if (isIdentifierText && !isIdentifierText(schema)) {
695
+ throw new Error(`Cannot generate identifier for schema "${schema}" in model "${block.name}" because it is not a valid Identifier, please disable \`groupBySchema\` or rename it.`);
696
+ }
697
+ multiSchemaMap.set(block.name, schema);
698
+ }
699
+ }
700
+ return multiSchemaMap;
701
+ }
702
+
703
+ // src/utils/validateConfig.ts
704
+ import prismaInternals from "@prisma/internals";
705
+ import z from "zod";
706
+ var { logger } = prismaInternals;
707
+ var booleanStringLiteral = z.union([z.boolean(), z.literal("true"), z.literal("false")]).transform((arg) => {
708
+ if (typeof arg === "boolean")
709
+ return arg;
710
+ return arg === "true";
711
+ });
712
+ var configValidator = z.object({
713
+ databaseProvider: z.union([
714
+ z.literal("postgresql"),
715
+ z.literal("cockroachdb"),
716
+ z.literal("mysql"),
717
+ z.literal("sqlite"),
718
+ z.literal("sqlserver")
719
+ ]),
720
+ fileName: z.string().optional().default("types.ts"),
721
+ importExtension: z.string().default(""),
722
+ enumFileName: z.string().optional(),
723
+ stringTypeOverride: z.string().optional(),
724
+ booleanTypeOverride: z.string().optional(),
725
+ intTypeOverride: z.string().optional(),
726
+ bigIntTypeOverride: z.string().optional(),
727
+ floatTypeOverride: z.string().optional(),
728
+ decimalTypeOverride: z.string().optional(),
729
+ dateTimeTypeOverride: z.string().optional(),
730
+ jsonTypeOverride: z.string().optional(),
731
+ bytesTypeOverride: z.string().optional(),
732
+ unsupportedTypeOverride: z.string().optional(),
733
+ dbTypeName: z.string().default("DB"),
734
+ camelCase: booleanStringLiteral.default(false),
735
+ readOnlyIds: booleanStringLiteral.default(false),
736
+ groupBySchema: booleanStringLiteral.default(false),
737
+ defaultSchema: z.string().default("public"),
738
+ filterBySchema: z.array(z.string()).optional(),
739
+ exportWrappedTypes: booleanStringLiteral.default(false),
740
+ banner: z.string().optional()
741
+ }).strict().transform((config) => {
742
+ if (!config.enumFileName) {
743
+ config.enumFileName = config.fileName;
744
+ }
745
+ if (config.groupBySchema && config.enumFileName !== config.fileName) {
746
+ throw new Error("groupBySchema is not compatible with enumFileName");
747
+ }
748
+ return config;
749
+ });
750
+ var validateConfig = (config) => {
751
+ const parsed = configValidator.safeParse(config);
752
+ if (!parsed.success) {
753
+ logger.error("Invalid prisma-kysely config");
754
+ Object.entries(parsed.error.flatten().fieldErrors).forEach(([key, value]) => {
755
+ logger.error(`${key}: ${value.join(", ")}`);
756
+ });
757
+ Object.values(parsed.error.flatten().formErrors).forEach((value) => {
758
+ logger.error(`${value}`);
759
+ });
760
+ process.exit(1);
761
+ }
762
+ return parsed.data;
763
+ };
764
+
765
+ // src/utils/writeFileSafely.ts
766
+ import fs from "fs";
767
+ import path2 from "path";
768
+
769
+ // src/utils/formatFile.ts
770
+ var formatFile = async (content) => {
771
+ try {
772
+ const { default: prettier } = await import("prettier");
773
+ const config = await prettier.resolveConfig(process.cwd());
774
+ if (!config)
775
+ return content;
776
+ const formatted = prettier.format(content, {
777
+ ...config,
778
+ parser: "typescript"
779
+ });
780
+ return formatted;
781
+ } catch {}
782
+ return content;
783
+ };
784
+
785
+ // src/utils/writeFileSafely.ts
786
+ var writeFileSafely = async (writeLocation, content) => {
787
+ fs.mkdirSync(path2.dirname(writeLocation), {
788
+ recursive: true
789
+ });
790
+ fs.writeFileSync(writeLocation, await formatFile(content));
791
+ };
792
+
793
+ // src/generator.ts
794
+ var { version } = package_default;
795
+ var { generatorHandler } = generatorHelper;
796
+ generatorHandler({
797
+ onManifest() {
798
+ return {
799
+ version,
800
+ defaultOutput: "./generated",
801
+ prettyName: GENERATOR_NAME
802
+ };
803
+ },
804
+ onGenerate: async (options) => {
805
+ if (!options.version) {
806
+ throw new Error(`Could not determine Prisma version. ` + `Make sure you are using a recent version of Prisma.`);
807
+ }
808
+ const semverMatch = options.version.match(/^(\d+)\./);
809
+ if (semverMatch && parseInt(semverMatch[1], 10) < 7) {
810
+ throw new Error(`prisma-kysely v${version} requires Prisma 7 or later. ` + `You are using Prisma ${options.version}. ` + `Please upgrade Prisma or use prisma-kysely v2.x for Prisma 6.`);
811
+ }
812
+ const config = validateConfig({
813
+ ...options.generator.config,
814
+ databaseProvider: options.datasources[0].provider
815
+ });
816
+ let enums = options.dmmf.datamodel.enums.map(({ name, values }) => generateEnumType(name, values)).filter((e) => !!e);
817
+ const implicitManyToManyModels = generateImplicitManyToManyModels(options.dmmf.datamodel.models);
818
+ const hasMultiSchema = options.datasources.some((d) => d.schemas.length > 0);
819
+ const multiSchemaMap = config.groupBySchema || hasMultiSchema ? parseMultiSchemaMap(options.datamodel) : undefined;
820
+ let models = sorted([...options.dmmf.datamodel.models, ...implicitManyToManyModels], (a, b) => a.name.localeCompare(b.name)).map((m) => generateModel(m, config, {
821
+ groupBySchema: config.groupBySchema,
822
+ defaultSchema: config.defaultSchema,
823
+ multiSchemaMap
824
+ }));
825
+ if (hasMultiSchema) {
826
+ const filterBySchema = config.filterBySchema ? new Set(config.filterBySchema) : null;
827
+ models = convertToMultiSchemaModels({
828
+ models,
829
+ groupBySchema: config.groupBySchema,
830
+ defaultSchema: config.defaultSchema,
831
+ filterBySchema,
832
+ multiSchemaMap
833
+ });
834
+ enums = convertToMultiSchemaModels({
835
+ models: enums,
836
+ groupBySchema: config.groupBySchema,
837
+ defaultSchema: config.defaultSchema,
838
+ filterBySchema,
839
+ multiSchemaMap
840
+ });
841
+ }
842
+ const databaseType = generateDatabaseType(models, config);
843
+ const files = generateFiles({
844
+ databaseType,
845
+ enumNames: options.dmmf.datamodel.enums.map((e) => e.name),
846
+ models,
847
+ enums,
848
+ enumsOutfile: config.enumFileName,
849
+ typesOutfile: config.fileName,
850
+ groupBySchema: config.groupBySchema,
851
+ defaultSchema: config.defaultSchema,
852
+ importExtension: config.importExtension,
853
+ exportWrappedTypes: config.exportWrappedTypes,
854
+ banner: config.banner
855
+ });
856
+ await Promise.allSettled(files.map(({ filepath, content }) => {
857
+ const writeLocation = path3.join(options.generator.output?.value || "", filepath);
858
+ return writeFileSafely(writeLocation, content);
859
+ }));
860
+ }
861
+ });