diff --git a/.changeset/file-prefix-feature.md b/.changeset/file-prefix-feature.md new file mode 100644 index 0000000..0ec5eaf --- /dev/null +++ b/.changeset/file-prefix-feature.md @@ -0,0 +1,5 @@ +--- +"prisma-kysely": minor +--- + +Add `filePrefix` configuration option to allow users to prepend custom content (imports, pragmas, comments) to generated files. diff --git a/README.md b/README.md index 00e4dad..8ba1ec8 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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` 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` | diff --git a/src/generator.ts b/src/generator.ts index 80d89a4..cb03597 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -123,6 +123,7 @@ generatorHandler({ defaultSchema: config.defaultSchema, importExtension: config.importExtension, exportWrappedTypes: config.exportWrappedTypes, + filePrefix: config.filePrefix, }); // And write it to a file! diff --git a/src/helpers/generateFile.test.ts b/src/helpers/generateFile.test.ts index c3955c0..cb93bad 100644 --- a/src/helpers/generateFile.test.ts +++ b/src/helpers/generateFile.test.ts @@ -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';"); +}); diff --git a/src/helpers/generateFile.ts b/src/helpers/generateFile.ts index 28aca8e..e331d5c 100644 --- a/src/helpers/generateFile.ts +++ b/src/helpers/generateFile.ts @@ -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, @@ -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" : "" diff --git a/src/helpers/generateFiles.ts b/src/helpers/generateFiles.ts index 42d5af4..4dc3775 100644 --- a/src/helpers/generateFiles.ts +++ b/src/helpers/generateFiles.ts @@ -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 => ({ @@ -53,6 +54,7 @@ export function generateFiles(opts: { withEnumImport: false, withLeader: true, exportWrappedTypes: opts.exportWrappedTypes, + filePrefix: opts.filePrefix, }), }; @@ -70,6 +72,7 @@ export function generateFiles(opts: { }, withLeader: true, exportWrappedTypes: opts.exportWrappedTypes, + filePrefix: opts.filePrefix, } ), }; @@ -84,6 +87,7 @@ export function generateFiles(opts: { withEnumImport: false, withLeader: false, exportWrappedTypes: opts.exportWrappedTypes, + filePrefix: opts.filePrefix, } ), }; diff --git a/src/utils/validateConfig.ts b/src/utils/validateConfig.ts index 6068527..9462fe9 100644 --- a/src/utils/validateConfig.ts +++ b/src/utils/validateConfig.ts @@ -58,6 +58,9 @@ export const configValidator = z // Export Kysely wrapped types such as `Selectable` 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) => {