Skip to content

Commit

Permalink
Merge pull request #33 from TomasHubelbauer/main
Browse files Browse the repository at this point in the history
  • Loading branch information
psteinroe authored Jun 26, 2024
2 parents 896b752 + 95214e2 commit 2426e75
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/lib/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
temp.ts
temp
5 changes: 5 additions & 0 deletions src/lib/get-node-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export const getNodeName = (n: ts.Node) => {
if (ts.isIdentifier(n)) {
name = n.text;
}

// Handle quoted identifiers in case they contain special characters
if (ts.isStringLiteral(n)) {
name = n.text;
}
});
if (!name) throw new Error('Cannot get name of node');
return name;
Expand Down
74 changes: 71 additions & 3 deletions src/lib/transform-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { z } from 'zod';
import { getNodeName } from './get-node-name';

const enumFormatterSchema = z.function().args(z.string()).returns(z.string());
const compositeTypeFormatterSchema = z
.function()
.args(z.string())
.returns(z.string());

const functionFormatterSchema = z
.function()
Expand All @@ -18,6 +22,9 @@ export const transformTypesOptionsSchema = z.object({
sourceText: z.string(),
schema: z.string().default('public'),
enumFormatter: enumFormatterSchema.default(() => (name: string) => name),
compositeTypeFormatter: compositeTypeFormatterSchema.default(
() => (name: string) => name
),
functionFormatter: functionFormatterSchema.default(
() => (name: string, type: string) => `${name}${type}`
),
Expand All @@ -33,8 +40,13 @@ export const transformTypes = z
.args(transformTypesOptionsSchema)
.returns(z.string())
.implement((opts) => {
const { schema, tableOrViewFormatter, enumFormatter, functionFormatter } =
opts;
const {
schema,
tableOrViewFormatter,
enumFormatter,
compositeTypeFormatter,
functionFormatter,
} = opts;
const sourceFile = ts.createSourceFile(
'index.ts',
opts.sourceText,
Expand All @@ -43,6 +55,7 @@ export const transformTypes = z

const typeStrings: string[] = [];
const enumNames: { name: string; formattedName: string }[] = [];
const compositeTypeNames: { name: string; formattedName: string }[] = [];

sourceFile.forEachChild((n) => {
const processDatabase = (n: ts.Node | ts.TypeNode) => {
Expand All @@ -68,7 +81,11 @@ export const transformTypes = z
const operation = getNodeName(n);
if (operation) {
n.forEachChild((n) => {
if (ts.isTypeLiteralNode(n)) {
if (
ts.isTypeLiteralNode(n) ||
// Handle `Relationships` operation which is an array
ts.isTupleTypeNode(n)
) {
typeStrings.push(
`export type ${tableOrViewFormatter(
tableOrViewName,
Expand Down Expand Up @@ -106,6 +123,46 @@ export const transformTypes = z
name: enumName,
});
}

// Handle single-member enums
if (ts.isIdentifier(n)) {
const formattedName = enumFormatter(enumName);
typeStrings.push(
`export type ${formattedName} = '${n.getText(
sourceFile,
)}'`,
);
enumNames.push({
formattedName,
name: enumName,
});
}
});
}
});
}
});
}
if ('CompositeTypes' === n.name.text) {
n.forEachChild((n) => {
if (ts.isTypeLiteralNode(n)) {
n.forEachChild((n) => {
const enumName = getNodeName(n);
if (ts.isPropertySignature(n)) {
n.forEachChild((n) => {
if (ts.isTypeLiteralNode(n)) {
const formattedName =
compositeTypeFormatter(enumName);
typeStrings.push(
`export type ${formattedName} = ${n.getText(
sourceFile,
)}`,
);
compositeTypeNames.push({
formattedName,
name: enumName,
});
}
});
}
});
Expand Down Expand Up @@ -181,5 +238,16 @@ export const transformTypes = z
);
}

for (const { name, formattedName } of compositeTypeNames) {
parsedTypes = parsedTypes.replaceAll(
`Database["${schema}"]["CompositeTypes"]["${name}"]`,
formattedName,
);
parsedTypes = parsedTypes.replaceAll(
`Database['${schema}']['CompositeTypes']['${name}']`,
formattedName,
);
}

return parsedTypes;
});
6 changes: 5 additions & 1 deletion src/supabase-to-zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ export default async function supabaseToZod(opts: SupabaseToZodOptions) {

const parsedTypes = transformTypes({ sourceText, ...opts });

const { getZodSchemasFile } = generate({
const { getZodSchemasFile, errors } = generate({
sourceText: parsedTypes,
...opts,
});

if (errors.length > 0) {
throw new Error(errors.join('\n'));
}

const zodSchemasFile = getZodSchemasFile(
getImportPath(outputPath, inputPath)
);
Expand Down

0 comments on commit 2426e75

Please sign in to comment.