UNPKG

esm-prisma-typebox-generator

Version:

Typebox generator for prisma schema, hotfixed for ESM

156 lines (155 loc) 5.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformDMMF = exports.transformEnum = void 0; const transformField = (field) => { const tokens = [field.name + ':']; let inputTokens = []; const deps = new Set(); if (['Int', 'Float', 'Decimal'].includes(field.type)) { tokens.push('Type.Number()'); } else if (['BigInt'].includes(field.type)) { tokens.push('Type.Integer()'); } else if (['String', 'Json'].includes(field.type)) { tokens.push('Type.String()'); } else if (['DateTime', 'Date'].includes(field.type)) { tokens.push("Type.Unsafe<Date>({ type: 'string', format: 'date' })"); } else if (field.type === 'Boolean') { tokens.push('Type.Boolean()'); } else { tokens.push(`::${field.type}::`); deps.add(field.type); } if (field.isList) { tokens.splice(1, 0, 'Type.Array('); tokens.splice(tokens.length, 0, ')'); } inputTokens = [...tokens]; // @id cannot be optional except for input if it's auto increment if (field.isId && field?.default?.name === 'autoincrement') { inputTokens.splice(1, 0, 'Type.Optional('); inputTokens.splice(inputTokens.length, 0, ')'); } if ((!field.isRequired || field.hasDefaultValue) && !field.isId) { // Prismas inputs are undefined (Type.Optional) but responses are nullable tokens.splice(1, 0, 'Type.Union(['); tokens.splice(tokens.length, 0, ', Type.Null()])'); inputTokens.splice(1, 0, 'Type.Optional('); inputTokens.splice(inputTokens.length, 0, ')'); } return { str: tokens.join(' ').concat('\n'), strInput: inputTokens.join(' ').concat('\n'), deps, }; }; const transformFields = (fields) => { let dependencies = new Set(); const _fields = []; const _inputFields = []; fields.map(transformField).forEach((field) => { _fields.push(field.str); _inputFields.push(field.strInput); [...field.deps].forEach((d) => { dependencies.add(d); }); }); return { dependencies, rawString: _fields.filter((f) => !!f).join(','), rawInputString: _inputFields.filter((f) => !!f).join(','), }; }; const transformModel = (model, models) => { const fields = transformFields(model.fields); let raw = [ `${models ? '' : `export const ${model.name} = `}Type.Object({\n\t`, fields.rawString, '})', ].join('\n'); let inputRaw = [ `${models ? '' : `export const ${model.name}Input = `}Type.Object({\n\t`, fields.rawInputString, '})', ].join('\n'); if (Array.isArray(models)) { models.forEach((md) => { const re = new RegExp(`.+::${md.name}.+\n`, 'gm'); const inputRe = new RegExp(`.+::${md.name}.+\n`, 'gm'); raw = raw.replace(re, ''); inputRaw = inputRaw.replace(inputRe, ''); }); } return { raw, inputRaw, deps: fields.dependencies, }; }; const transformEnum = (enm) => { const values = enm.values .map((v) => `${v.name}: Type.Literal('${v.name}'),\n`) .join(''); return [ `export const ${enm.name}Const = {`, values, '}\n', `export const ${enm.name} = Type.KeyOf(Type.Object(${enm.name}Const))\n`, `export type ${enm.name}Type = Static<typeof ${enm.name}>`, ].join('\n'); }; exports.transformEnum = transformEnum; function transformDMMF(dmmf, config) { const { models, enums } = dmmf.datamodel; const importStatements = new Set([ 'import {Type, Static} from "@sinclair/typebox"', ]); return [ ...models.map((model) => { let { raw, inputRaw, deps } = transformModel(model); [...deps].forEach((d) => { const depsModel = models.find((m) => m.name === d); if (depsModel) { const replacer = transformModel(depsModel, models); const re = new RegExp(`::${d}::`, 'gm'); raw = raw.replace(re, replacer.raw); inputRaw = inputRaw.replace(re, replacer.inputRaw); } }); enums.forEach((enm) => { const re = new RegExp(`::${enm.name}::`, 'gm'); if (raw.match(re)) { raw = raw.replace(re, enm.name); inputRaw = inputRaw.replace(re, enm.name); importStatements.add(`import { ${enm.name} } from './${enm.name}${config?.esmImports ? '.js' : ''}'`); } }); return { name: model.name, rawString: [ [...importStatements].join('\n'), raw, `export type ${model.name}Type = Static<typeof ${model.name}>`, ].join('\n\n'), inputRawString: [ [...importStatements].join('\n'), inputRaw, `export type ${model.name}InputType = Static<typeof ${model.name}Input>`, ].join('\n\n'), }; }), ...enums.map((enm) => { return { name: enm.name, inputRawString: null, rawString: 'import {Type, Static} from "@sinclair/typebox"\n\n' + (0, exports.transformEnum)(enm), }; }), ]; } exports.transformDMMF = transformDMMF;