Skip to content

Commit

Permalink
Export enums and related types like Prisma does (#38)
Browse files Browse the repository at this point in the history
* Export enums and related types like Prisma does

* Update test name to better reflect the test

* Add changeset

* Append `as const` to enum objects

* Fix tests after adding `as const`

* Update changeset

---------

Co-authored-by: Valtýr Örn Kjartansson <valtyr@gmail.com>
  • Loading branch information
jvandenaardweg and valtyr authored May 15, 2023
1 parent 49a110b commit 2659cc3
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/ten-fans-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"prisma-kysely": patch
---

Now using narrower types for enum objects bringing `prisma-kysely`'s enums in line with `prisma-client-js` (Thank you @jvandenaardweg 🎉)
6 changes: 3 additions & 3 deletions src/__test__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ test(
const enumFile = await fs.readFile("./prisma/generated/enums.ts", {
encoding: "utf-8",
});
expect(enumFile).toEqual(`export type TestEnum = "A" | "B" | "C";
export const TestEnum = {
expect(enumFile).toEqual(`export const TestEnum = {
A: "A",
B: "B",
C: "C",
};
} as const;
export type TestEnum = (typeof TestEnum)[keyof typeof TestEnum];
`);
},
{ timeout: 20000 }
Expand Down
25 changes: 25 additions & 0 deletions src/helpers/generateEnumType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ts, { createPrinter } from "typescript";
import { expect, test } from "vitest";

import { generateEnumType } from "./generateEnumType";

test("it generates the enum type", () => {
const [objectDeclaration, typeDeclaration] = generateEnumType("Name", [
{ name: "FOO", dbName: "FOO" },
{ name: "BAR", dbName: "BAR" },
]);

const printer = createPrinter();

const result = printer.printList(
ts.ListFormat.MultiLine,
ts.factory.createNodeArray([objectDeclaration, typeDeclaration]),
ts.createSourceFile("", "", ts.ScriptTarget.Latest)
);

expect(result).toEqual(`export const Name = {
FOO: "FOO",
BAR: "BAR"
} as const;
export type Name = (typeof Name)[keyof typeof Name];\n`);
});
37 changes: 22 additions & 15 deletions src/helpers/generateEnumType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ts from "typescript";
import isValidTSIdentifier from "~/utils/isValidTSIdentifier";

import { generateStringLiteralUnion } from "./generateStringLiteralUnion";
import { generateTypedAliasDeclaration } from "./generateTypedAliasDeclaration";
import { generateTypedReferenceNode } from "./generateTypedReferenceNode";

export const generateEnumType = (name: string, values: DMMF.EnumValue[]) => {
const type = generateStringLiteralUnion(values.map((v) => v.name));
Expand All @@ -19,26 +19,33 @@ export const generateEnumType = (name: string, values: DMMF.EnumValue[]) => {
name,
undefined,
undefined,
ts.factory.createObjectLiteralExpression(
values.map((v) => {
const identifier = isValidTSIdentifier(v.name)
? ts.factory.createIdentifier(v.name)
: ts.factory.createStringLiteral(v.name);

return ts.factory.createPropertyAssignment(
identifier,
ts.factory.createStringLiteral(v.name)
);
}),
true

ts.factory.createAsExpression(
ts.factory.createObjectLiteralExpression(
values.map((v) => {
const identifier = isValidTSIdentifier(v.name)
? ts.factory.createIdentifier(v.name)
: ts.factory.createStringLiteral(v.name);

return ts.factory.createPropertyAssignment(
identifier,
ts.factory.createStringLiteral(v.name)
);
}),
true
),
ts.factory.createTypeReferenceNode(
ts.factory.createIdentifier("const"),
undefined
)
)
),
],
ts.NodeFlags.Const
)
);

const typeDeclaration = generateTypedAliasDeclaration(name, type);
const typeDeclaration = generateTypedReferenceNode(name);

return [typeDeclaration, objectDeclaration];
return [objectDeclaration, typeDeclaration];
};
15 changes: 15 additions & 0 deletions src/helpers/generateTypedReferenceNode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect, test } from "vitest";

import { stringifyTsNode } from "~/utils/testUtils";

import { generateTypedReferenceNode } from "./generateTypedReferenceNode";

test("it generated the typed reference node", () => {
const node = generateTypedReferenceNode("Name");

const result = stringifyTsNode(node);

expect(result).toEqual(
"export type Name = (typeof Name)[keyof typeof Name];"
);
});
14 changes: 14 additions & 0 deletions src/helpers/generateTypedReferenceNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import ts from "typescript";

export const generateTypedReferenceNode = (name: string) => {
return ts.factory.createTypeAliasDeclaration(
undefined,
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
name,
undefined,
ts.factory.createTypeReferenceNode(
`(typeof ${name})[keyof typeof ${name}]`,
undefined
)
);
};

0 comments on commit 2659cc3

Please # to comment.