Skip to content
Open
5 changes: 5 additions & 0 deletions .changeset/file-prefix-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"prisma-kysely": minor
---

Add `filePrefix` configuration option to allow users to prepend custom content (imports, pragmas, comments) to generated files.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,49 @@ without losing the safety of the TypeScript type system?
fileName = "types.ts"
// Optionally generate runtime enums to a separate file
enumFileName = "enums.ts"
// Optionally add content at the start of generated files (imports, pragmas, comments, etc.)
filePrefix = "import type { Decimal } from 'decimal.js';"
// For multi-line, use Prisma's triple-quoted string syntax (see below)
}
```

3. Run `prisma migrate dev` or `prisma generate` and use your freshly generated
types when instantiating Kysely!

### File Prefix Configuration

The `filePrefix` option allows you to add custom content at the start of generated files. This is particularly useful for importing custom types and libraries:

```prisma
generator kysely {
provider = "prisma-kysely"
output = "../src/db"
fileName = "types.ts"

// Add custom imports for libraries you need in generated types
filePrefix = """
import type { Decimal } from 'decimal.js';
import { Big } from 'big.js';
import * as moment from 'moment';
import { v4 as uuid } from 'uuid';
import type { SomeType } from './custom-types';
"""
}
```

This will generate a file that starts with:

```typescript
import type { Decimal } from "decimal.js";
import { Big } from "big.js";
import * as moment from "moment";
import { v4 as uuid } from "uuid";
import type { SomeType } from "./custom-types";

import type { ColumnType } from "kysely";
// ... rest of generated types
```

### Motivation

Prisma's migration and schema definition workflow is undeniably great, and the
Expand Down Expand Up @@ -81,6 +118,7 @@ hope it's just as useful for you! 😎
| `enumFileName` | The filename for the generated enums. Omitting this will generate enums and files in the same file. | |
| `camelCase` | Enable support for Kysely's camelCase plugin | `false` |
| `exportWrappedTypes` | Kysely wrapped types such as `Selectable<Model>` are also exported as described in the [Kysely documentation](https://kysely.dev/docs/getting-started#types). The exported types follow the naming conventions of the document. | `false` |
| `filePrefix` | Content to prepend to the start of generated file(s). Useful for custom imports, pragma directives (e.g., `// @ts-nocheck`), comments, or any other content. Supports single-line strings or multi-line via Prisma triple-quoted strings (`""" ... """`). The content is inserted verbatim at the top of the file(s). | |
| `readOnlyIds` | Use Kysely's `GeneratedAlways` for `@id` fields with default values, preventing insert and update. | `false` |
| `[typename]TypeOverride` | Allows you to override the resulting TypeScript type for any Prisma type. Useful when targeting a different environment than Node (e.g. WinterCG compatible runtimes that use UInt8Arrays instead of Buffers for binary types etc.) Check out the [config validator](https://github.com/valtyr/prisma-kysely/blob/main/src/utils/validateConfig.ts) for a complete list of options. | |
| `dbTypeName` | Allows you to override the exported type with all tables | `DB` |
Expand Down
1 change: 1 addition & 0 deletions src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ generatorHandler({
defaultSchema: config.defaultSchema,
importExtension: config.importExtension,
exportWrappedTypes: config.exportWrappedTypes,
filePrefix: config.filePrefix,
});

// And write it to a file!
Expand Down
34 changes: 34 additions & 0 deletions src/helpers/generateFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,37 @@ test("generates a file which imports Kysely wrapper types.", () => {
', Insertable, Selectable, Updateable } from "kysely";'
);
});

test("generates a file with custom prefix when filePrefix is specified.", () => {
const result = generateFile([], {
withEnumImport: false,
withLeader: true,
exportWrappedTypes: false,
filePrefix: "import Decimal from 'decimal.js';",
});
expect(result).toContain("import Decimal from 'decimal.js';");
});

test("generates a file with multiple imports in filePrefix.", () => {
const result = generateFile([], {
withEnumImport: false,
withLeader: true,
exportWrappedTypes: false,
filePrefix: `import Decimal from 'decimal.js';
import { Big } from 'big.js';
import * as moment from 'moment';`,
});
expect(result).toContain("import Decimal from 'decimal.js';");
expect(result).toContain("import { Big } from 'big.js';");
expect(result).toContain("import * as moment from 'moment';");
});

test("generates a file with filePrefix containing renamed imports.", () => {
const result = generateFile([], {
withEnumImport: false,
withLeader: true,
exportWrappedTypes: false,
filePrefix: "import { v4 as uuid } from 'uuid';",
});
expect(result).toContain("import { v4 as uuid } from 'uuid';");
});
5 changes: 3 additions & 2 deletions src/helpers/generateFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ type Options = {
withEnumImport: false | { importPath: string; names: string[] };
withLeader: boolean;
exportWrappedTypes: boolean;
filePrefix?: string;
};

export const generateFile = (
statements: readonly ts.Statement[],
{ withEnumImport, withLeader, exportWrappedTypes }: Options
{ withEnumImport, withLeader, exportWrappedTypes, filePrefix }: Options
) => {
const file = ts.factory.createSourceFile(
statements,
Expand All @@ -20,7 +21,7 @@ export const generateFile = (

const result = printer.printFile(file);

const leader = `import type { ColumnType${
const leader = `${filePrefix ? `${filePrefix}\n` : ""}import type { ColumnType${
result.includes("GeneratedAlways") ? ", GeneratedAlways" : ""
}${
exportWrappedTypes ? ", Insertable, Selectable, Updateable" : ""
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/generateFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function generateFiles(opts: {
defaultSchema: string;
importExtension: string;
exportWrappedTypes: boolean;
filePrefix?: string;
}) {
const models = opts.models.map(
({ definition, ...rest }: ModelType): MultiDefsModelType => ({
Expand Down Expand Up @@ -53,6 +54,7 @@ export function generateFiles(opts: {
withEnumImport: false,
withLeader: true,
exportWrappedTypes: opts.exportWrappedTypes,
filePrefix: opts.filePrefix,
}),
};

Expand All @@ -70,6 +72,7 @@ export function generateFiles(opts: {
},
withLeader: true,
exportWrappedTypes: opts.exportWrappedTypes,
filePrefix: opts.filePrefix,
}
),
};
Expand All @@ -84,6 +87,7 @@ export function generateFiles(opts: {
withEnumImport: false,
withLeader: false,
exportWrappedTypes: opts.exportWrappedTypes,
filePrefix: opts.filePrefix,
}
),
};
Expand Down
3 changes: 3 additions & 0 deletions src/utils/validateConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export const configValidator = z

// Export Kysely wrapped types such as `Selectable<Model>`
exportWrappedTypes: booleanStringLiteral.default(false),

// Content to prepend to the start of the generated file(s). Useful for custom imports, pragmas, or comments.
filePrefix: z.string().optional(),
})
.strict()
.transform((config) => {
Expand Down