UNPKG

prisma-supabase

Version:

Prisma generator for creating types for supabase-js/postgrest-js, without requiring a database, for faster generation times. Ideal for PostgREST-only projects.

307 lines (306 loc) 18.2 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateTypes = generateTypes; var defaultGeneratorConfig = { enableDocumentation: 'true', }; /** * Generates TypeScript types based on the Prisma DMMF document. * @param dmmf The Prisma DMMF document * @returns A string containing the generated TypeScript types */ function generateTypes(dmmf, options) { var _a; var datamodel = dmmf.datamodel; var generatorConfig = (((_a = options === null || options === void 0 ? void 0 : options.generator) === null || _a === void 0 ? void 0 : _a.config) || {}); var schemas = createSchemaObjects(datamodel, __assign(__assign({}, defaultGeneratorConfig), generatorConfig)); return generateTypeDefinitions(schemas, generatorConfig); } /** * Creates schema objects from the Prisma datamodel. * @param datamodel The Prisma datamodel * @returns An array of schema objects */ function createSchemaObjects(datamodel, generatorConfig) { return [ { compositeTypes: datamodel.types, enums: datamodel.enums.map(stringifyName), functions: [], name: 'public', tables: datamodel.models.map(stringifyName), views: [], }, ]; } /** * Generates the full TypeScript type definitions. * @param schemas An array of schema objects * @returns A string containing the generated TypeScript types */ function generateTypeDefinitions(schemas, generatorConfig) { var sortedSchemas = schemas.sort(function (a, b) { return a.name.localeCompare(b.name); }); return "\nexport type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]\n\nexport type Database = {\n".concat(sortedSchemas.map(function (schema) { return generateSchemaDefinition(schema, generatorConfig); }).join(''), "\n}\n\n").concat(generateHelperTypes(), "\n"); } /** * Generates the TypeScript definition for a single schema. * @param schema The schema object * @returns A string containing the schema definition */ function generateSchemaDefinition(schema, generatorConfig) { var schemaTables = __spreadArray([], schema.tables, true).sort(alphaSort); var schemaEnums = schema.enums.filter(function (type) { return type.values.length > 0; }).sort(alphaSort); var schemaCompositeTypes = schema.compositeTypes.filter(function (type) { return type.fields.length > 0; }).sort(alphaSort); return "\n ".concat(schema.name, ": {\n Tables: {\n ").concat(generateTablesDefinition(schemaTables, schemaEnums, generatorConfig), "\n }\n Views: {\n ").concat(generateViewsDefinition(), "\n }\n Functions: {\n ").concat(generateFunctionsDefinition(), "\n }\n Enums: {\n ").concat(generateEnumsDefinition(schemaEnums, generatorConfig), "\n }\n CompositeTypes: {\n ").concat(generateCompositeTypesDefinition(schemaCompositeTypes, generatorConfig), "\n }\n }"); } /** * Generates the TypeScript definition for tables. * @param schemaTables An array of DMMF Model objects representing tables * @returns A string containing the tables definition */ function generateTablesDefinition(schemaTables, schemaEnums, generatorConfig) { if (!schemaTables.length) return '[_ in never]: never'; return schemaTables .map(function (table) { return "\n ".concat(renderDoc(table.documentation, generatorConfig)).concat(table.name, ": {\n Row: {\n ").concat(generateTableRowDefinition(table, schemaEnums, generatorConfig), "\n }\n Insert: {\n ").concat(generateTableInsertDefinition(table, schemaEnums, generatorConfig), "\n }\n Update: {\n ").concat(generateTableUpdateDefinition(table, schemaEnums, generatorConfig), "\n }\n Relationships: [\n ").concat(generateTableRelationshipsDefinition(table, schemaEnums, generatorConfig), "\n ]\n }"); }) .join(';'); } function generateColEnumDocs(col, schemaEnums, generatorConfig) { var enumModel = col.kind === 'enum' ? schemaEnums.find(function (e) { return e.name === col.type; }) : null; if (!enumModel) return ''; // TODO: Append enumModel.documentation to col.documentation as well enumModel = __assign(__assign({}, enumModel), { documentation: col.documentation }); return enumModel ? generateEnumMemberDocs(enumModel, generatorConfig) : ''; } /** * Generates the TypeScript definition for a table's row. * @param table The DMMF Model object representing a table * @returns A string containing the row definition */ function generateTableRowDefinition(table, schemaEnums, generatorConfig) { return table.fields .filter(filterField) .sort(alphaSort) .map(function (col) { var type = "".concat(prismaTypeToTsType(col)).concat(col.isRequired ? '' : ' | null'); var enumDoc = generateColEnumDocs(col, schemaEnums, generatorConfig); var colDoc = renderDoc(col.documentation, generatorConfig, { noEndingStar: !!enumDoc }); return colDoc + enumDoc + "".concat(col.name, ": ").concat(type); }) .join('\n'); } /** * Generates the TypeScript definition for a table's insert operation. * @param table The DMMF Model object representing a table * @returns A string containing the insert definition */ function generateTableInsertDefinition(table, schemaEnums, generatorConfig) { return table.fields .filter(filterField) .sort(alphaSort) .map(function (col) { var type = "".concat(prismaTypeToTsType(col)).concat(col.isRequired ? '' : ' | null'); var isOptional = !col.isRequired || col.hasDefaultValue; var fieldName = "".concat(col.name).concat(isOptional ? '?' : ''); if (col.isGenerated) return "".concat(fieldName, ": never"); var enumDoc = generateColEnumDocs(col, schemaEnums, generatorConfig); var colDoc = renderDoc(col.documentation, generatorConfig, { noEndingStar: !!enumDoc }); return colDoc + enumDoc + "".concat(fieldName, ": ").concat(type); }) .join('\n'); } /** * Generates the TypeScript definition for a table's update operation. * @param table The DMMF Model object representing a table * @returns A string containing the update definition */ function generateTableUpdateDefinition(table, schemaEnums, generatorConfig) { return table.fields .filter(filterField) .sort(alphaSort) .map(function (col) { if (col.isGenerated) return "".concat(col.name, "?: never"); var type = "".concat(prismaTypeToTsType(col)).concat(!col.isRequired ? ' | null' : ''); var enumDoc = generateColEnumDocs(col, schemaEnums, generatorConfig); var colDoc = renderDoc(col.documentation, generatorConfig, { noEndingStar: !!enumDoc }); return colDoc + enumDoc + "".concat(col.name, "?: ").concat(type); }) .join('\n'); } /** * Generates the TypeScript definition for a table's relationships. * @param table The DMMF Model object representing a table * @returns A string containing the relationships definition */ function generateTableRelationshipsDefinition(table, schemaEnums, generatorConfig) { return table.fields .filter(function (field) { var _a, _b; return field.relationName && ((_a = field === null || field === void 0 ? void 0 : field.relationFromFields) === null || _a === void 0 ? void 0 : _a.length) && ((_b = field === null || field === void 0 ? void 0 : field.relationToFields) === null || _b === void 0 ? void 0 : _b.length); }) .sort(alphaSort) .map(function (relationship) { var relationshipDeclaration = "\n {\n foreignKeyName: \"".concat(relationship.relationName, "\"\n columns: ").concat(JSON.stringify(relationship.relationFromFields), "\n isOneToOne: ").concat(relationship.isList, "\n referencedRelation: \"").concat(relationship.type, "\"\n referencedColumns: ").concat(JSON.stringify(relationship.relationToFields), "\n }"); return relationshipDeclaration; }) .join(','); } /** * Generates the TypeScript definition for views (currently not supported). * @returns A string indicating that views are not supported */ function generateViewsDefinition() { return '/* Views are within tables */'; } /** * Generates the TypeScript definition for functions (currently not supported). * @returns A string indicating that functions are not supported */ function generateFunctionsDefinition() { return '/* No support for functions */'; } /** * Generates the TypeScript definition for enums. * @param schemaEnums An array of DMMF DatamodelEnum objects * @returns A string containing the enums definition */ function generateEnumsDefinition(schemaEnums, generatorConfig) { if (!schemaEnums.length) return '[_ in never]: never'; return schemaEnums .map(function (enm) { var enumMemberDocs = generateEnumMemberDocs(enm, generatorConfig); var enumRootDoc = renderDoc(enm.documentation, generatorConfig, { noEndingStar: !!enumMemberDocs }); var finalEnumDoc = "".concat(enumRootDoc).concat(enumMemberDocs); return "".concat(finalEnumDoc).concat(enm.name, ": ").concat(enm.values.map(function (member) { return "\"".concat(member.name, "\""); }).join(' | ')); }) .join('\n'); } function generateEnumMemberDocs(enm, generatorConfig) { return renderDoc(enm.values.map(function (member) { var _a, _b; // @ts-expect-error: documentation is not typed var doc = (_b = (_a = member.documentation) === null || _a === void 0 ? void 0 : _a.trim()) === null || _b === void 0 ? void 0 : _b.split('\n').join(' '); return "\n- ".concat(member.name).concat(doc ? ": ".concat(doc) : ''); }), generatorConfig, { noStartingStar: !!enm.documentation, }); } /** * Generates the TypeScript definition for composite types. * @param schemaCompositeTypes An array of DMMF Model objects representing composite types * @returns A string containing the composite types definition */ function generateCompositeTypesDefinition(schemaCompositeTypes, generatorConfig) { if (!schemaCompositeTypes.length) return '[_ in never]: never'; return schemaCompositeTypes .map(function (_a) { var name = _a.name, fields = _a.fields, documentation = _a.documentation; return "\n ".concat(renderDoc(documentation, generatorConfig)).concat(name, ": {\n ").concat(fields .map(function (field) { var tsType = field.type ? "".concat(prismaTypeToTsType(field), " | null") : 'unknown'; return "".concat(renderDoc(field.documentation, generatorConfig)).concat(field.name, ": ").concat(tsType); }) .join(',\n'), "\n }"); }) .join(',\n\n'); } /** * Generates helper types for the generated TypeScript definitions. * @returns A string containing the helper types */ function generateHelperTypes() { return "\ntype PublicSchema = Database[Extract<keyof Database, \"public\">]\n\nexport type Tables<\n PublicTableNameOrOptions extends\n | keyof (PublicSchema[\"Tables\"] & PublicSchema[\"Views\"])\n | { schema: keyof Database },\n TableName extends PublicTableNameOrOptions extends { schema: keyof Database }\n ? keyof (Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"] &\n Database[PublicTableNameOrOptions[\"schema\"]][\"Views\"])\n : never = never\n> = PublicTableNameOrOptions extends { schema: keyof Database }\n ? (Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"] &\n Database[PublicTableNameOrOptions[\"schema\"]][\"Views\"])[TableName] extends {\n Row: infer R\n }\n ? R\n : never\n : PublicTableNameOrOptions extends keyof (PublicSchema[\"Tables\"] & PublicSchema[\"Views\"])\n ? (PublicSchema[\"Tables\"] & PublicSchema[\"Views\"])[PublicTableNameOrOptions] extends {\n Row: infer R\n }\n ? R\n : never\n : never\n\nexport type TablesInsert<\n PublicTableNameOrOptions extends\n | keyof PublicSchema[\"Tables\"]\n | { schema: keyof Database },\n TableName extends PublicTableNameOrOptions extends { schema: keyof Database }\n ? keyof Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"]\n : never = never\n> = PublicTableNameOrOptions extends { schema: keyof Database }\n ? Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"][TableName] extends {\n Insert: infer I\n }\n ? I\n : never\n : PublicTableNameOrOptions extends keyof PublicSchema[\"Tables\"]\n ? PublicSchema[\"Tables\"][PublicTableNameOrOptions] extends {\n Insert: infer I\n }\n ? I\n : never\n : never\n\nexport type TablesUpdate<\n PublicTableNameOrOptions extends\n | keyof PublicSchema[\"Tables\"]\n | { schema: keyof Database },\n TableName extends PublicTableNameOrOptions extends { schema: keyof Database }\n ? keyof Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"]\n : never = never\n> = PublicTableNameOrOptions extends { schema: keyof Database }\n ? Database[PublicTableNameOrOptions[\"schema\"]][\"Tables\"][TableName] extends {\n Update: infer U\n }\n ? U\n : never\n : PublicTableNameOrOptions extends keyof PublicSchema[\"Tables\"]\n ? PublicSchema[\"Tables\"][PublicTableNameOrOptions] extends {\n Update: infer U\n }\n ? U\n : never\n : never\n\nexport type Enums<\n PublicEnumNameOrOptions extends\n | keyof PublicSchema[\"Enums\"]\n | { schema: keyof Database },\n EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }\n ? keyof Database[PublicEnumNameOrOptions[\"schema\"]][\"Enums\"]\n : never = never\n> = PublicEnumNameOrOptions extends { schema: keyof Database }\n ? Database[PublicEnumNameOrOptions[\"schema\"]][\"Enums\"][EnumName]\n : PublicEnumNameOrOptions extends keyof PublicSchema[\"Enums\"]\n ? PublicSchema[\"Enums\"][PublicEnumNameOrOptions]\n : never\n\nexport type CompositeTypes<\n PublicCompositeTypeNameOrOptions extends\n | keyof PublicSchema['CompositeTypes']\n | { schema: keyof Database },\n CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { schema: keyof Database }\n ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes']\n : never = never\n> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }\n ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName]\n : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes']\n ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions]\n : never\n"; } /** * Converts a Prisma type to its corresponding TypeScript type. * @param field The DMMF Field object * @returns The corresponding TypeScript type as a string */ function prismaTypeToTsType(field) { if (field.kind === 'scalar') { return PRISMA_TO_TS_TYPE[field.type]; } if (field.kind === 'enum') { return "Database['public']['Enums']['".concat(field.type, "']"); } return field.type; } var PRISMA_TO_TS_TYPE = { BigInt: 'number', Boolean: 'boolean', Bytes: 'string', DateTime: 'string', Decimal: 'number', Float: 'number', Int: 'number', Json: 'Json', String: 'string', }; /** * Sorts two objects alphabetically by their 'name' property. * @param a The first object * @param b The second object * @returns A number indicating the sort order */ function alphaSort(a, b) { return a.name.localeCompare(b.name); } /** * Filters out fields that have a relation name. * @param field The DMMF Field object to filter * @returns A boolean indicating whether the field should be included */ function filterField(field) { return !field.relationName; } /** * Stringifies the name of an entity if it's not a valid JavaScript identifier. * @param entity An object with a 'name' property * @returns The entity with a potentially stringified name */ function stringifyName(entity) { var isValidJsKey = entity.name.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/); if (isValidJsKey) return entity; return __assign(__assign({}, entity), { name: JSON.stringify(entity.name) }); } /** * Renders a documentation string as a multi-line JSDoc comment. * @param doc The documentation string to render * @returns A formatted multi-line JSDoc comment */ function renderDoc(doc, generatorConfig, options) { if (!doc || generatorConfig.enableDocumentation === 'false') return ''; var lines = Array.isArray(doc) ? doc.map(function (line) { return line.trim(); }) : doc.split('\n').map(function (line) { return line.trim(); }); if (lines.length === 0) return ''; var startLine = (options === null || options === void 0 ? void 0 : options.noStartingStar) ? '' : '/**'; var endLine = (options === null || options === void 0 ? void 0 : options.noEndingStar) ? '' : ' */'; if (lines.length === 1) return "".concat(startLine, " ").concat(lines[0]).concat(endLine, "\n"); var contentLines = lines.map(function (line) { return " * ".concat(line); }); return __spreadArray(__spreadArray([startLine], contentLines, true), [endLine, ''], false).filter(Boolean).join('\n') + '\n'; }