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
JavaScript
"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';
}