Skip to content

Instantly share code, notes, and snippets.

@serhii-levchenko
Last active May 6, 2024 05:10
Show Gist options
  • Save serhii-levchenko/3e40f987e9195541a11c759ed26c5cc2 to your computer and use it in GitHub Desktop.
Save serhii-levchenko/3e40f987e9195541a11c759ed26c5cc2 to your computer and use it in GitHub Desktop.
Generate enums based on Supabase types

Currently Supabase generates only types by default but it can be useful to have enums. That's how you can do it:

  1. Add your own script in package.json e.g. "generate:enums": "node ./scripts/generate-enums.js"

  2. Create ./scripts/generate-enums.js file

const fs = require('fs');
const ts = require('typescript');

// Read the types.ts file
const fileContent = fs.readFileSync('./types.ts', 'utf8');

// Function to transform enum names to PascalCase and remove '_enum' suffix
function transformEnumName(name) {
    return name
        .replace(/_enum$/, '') // Remove '_enum' suffix
        .split('_')
        .map(part => part.charAt(0).toUpperCase() + part.slice(1))
        .join('');
}

// Function to parse and extract enums from Database['public']['Enums']
function extractEnums(content) {
    const sourceFile = ts.createSourceFile('types.ts', content, ts.ScriptTarget.Latest, true);
    const enums = {};

    function visit(node) {
        if (ts.isPropertySignature(node) &&
            node.name.escapedText === 'Enums' &&
            node.type &&
            ts.isTypeLiteralNode(node.type)) {

            node.type.members.forEach(member => {
                if (ts.isPropertySignature(member) &&
                    member.type &&
                    ts.isUnionTypeNode(member.type)) {

                    const enumName = transformEnumName(member.name.escapedText);
                    const enumValues = member.type.types.map(type => {
                        if (ts.isLiteralTypeNode(type) && type.literal && ts.isStringLiteral(type.literal)) {
                            return type.literal.text;
                        }
                        return null;
                    }).filter(Boolean);

                    enums[enumName] = enumValues;
                }
            });
        }

        ts.forEachChild(node, visit);
    }

    visit(sourceFile);

    return enums;
}

// Function to create enum strings
function createEnumStrings(enums) {
    return Object.entries(enums).map(([enumName, enumValues]) => {
        const enumMembers = enumValues.map(value => `${value} = "${value}"`).join(',\n  ');
        return `export enum ${enumName} {\n  ${enumMembers}\n}`;
    }).join('\n\n');
}

// Extract enums
const extractedEnums = extractEnums(fileContent);

// Create enum strings
const enumStrings = createEnumStrings(extractedEnums);

// Write enums to a new file
fs.writeFileSync('./enums.ts', enumStrings);
  1. Enjoy enums.ts file with all your enums (PascalCase, without enum suffix`) - e.g.
export enum LogLevel {
  debug = "debug",
  info = "info",
  warning = "warning",
  error = "error"
}
@govi218
Copy link

govi218 commented May 6, 2024

I modified this to make sure names are valid in JS (in case they include special chars): https://gist.github.com/govi218/683c0cb7121adce1e4adffc8a89239e2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment