UNPKG

prisma-class-validator

Version:

Automatically generator class-validator schema from Prisma client

113 lines (107 loc) 4.22 kB
/** * @copyright Koj <https://koj.co> * @link https://github.com/koj-co/prisma-class-validator */ import { format } from "prettier"; import { readFile } from "fs/promises"; import { join } from "path"; export const readAndGenerateClassValidator = async () => { const generatedTypes = await readFile( join(".", "node_modules", ".prisma", "client", "index.d.ts"), "utf8" ); return generateClassValidatorFromPrismaClient(generatedTypes); }; export const generateClassValidatorFromPrismaClient = (generatedTypes: string) => { const enums = new Set<string>(); const enumValues: Record<string, string[]> = {}; generatedTypes.split("\n").forEach((line) => { if (line.includes("[keyof typeof ")) enums.add(line.split("[keyof typeof ")[1].split("]")[0]); }); enums.forEach((val) => { const started = generatedTypes.split(`export const ${val}: {`)[1]; if (started) enumValues[val] = started .split("}")[0] .split("\n") .map((i) => i.split(":")[0].trim()) .filter((i) => i.length > 0); }); return format( `/** * DO NOT EDIT THIS FILE MANUALLY * ============================== * * This file is automatically generated by Prisma Class Validator using @prisma/client * Source: https://github.com/koj-co/prisma-class-validator/blob/HEAD/scripts/generate-types.ts */ import { IsOptional, IsString, IsNumber, IsNotEmpty, IsBoolean, IsObject, IsDateString, IsIn, } from 'class-validator'; ` + generatedTypes .split("@prisma/client/runtime';")[1] .split("export class PrismaClient")[0] .split("/**\n * ## Prisma Client")[0] .replace(new RegExp("Prisma.JsonValue", "g"), "any") .replace(new RegExp("Prisma.Decimal", "g"), "string") .replace(new RegExp("export const", "g"), "export let") .split("\n") .map((line) => { if (line.match(/export type ([A-Z])\w+ = {/g)) line = line.replace("export type ", "export class ").replace("= {", "{"); else if (line.endsWith(": string")) return `\n@IsString()\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(": string | null")) return `\n@IsString()\n@IsOptional()\n${line.replace(":", "?:")}`; else if (line.endsWith(": Date | null")) return `\n@IsDateString()\n@IsOptional()\n${line.replace(":", "?:")}`; else if (line.endsWith(": Date")) return `\n@IsDateString()\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(": number")) return `\n@IsNumber()\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(": number | null")) return `\n@IsNumber()\n@IsOptional()\n${line.replace(":", "?:")}`; else if (line.endsWith(": any")) return `\n@IsObject()\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(": any | null")) return `\n@IsObject()\n@IsOptional()\n${line.replace(":", "?:")}`; else if (line.endsWith(": boolean")) return `\n@IsBoolean()\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(": boolean | null")) return `\n@IsBoolean()\n@IsOptional()\n${line.replace(":", "?:")}`; else { let result = ""; enums.forEach((val) => { let options = enumValues[val]; let prefix = ""; if (options) prefix = `@IsIn([${options.map((i) => `'${i}'`).join(", ")}])\n`; if (line.endsWith(`: ${val}`)) result = `\n@IsString()${prefix}\n@IsNotEmpty()\n${line.replace(":", "!:")}`; else if (line.endsWith(`: ${val} | null`)) result = `\n@IsString()${prefix}\n@IsOptional()\n${line.replace(":", "?:")}`; }); if (result) return result; } return line; }) .map((i) => i.includes("?!:") ? i.replace("?!:", "!:") : i.includes("??:") ? i.replace("??:", "?:") : i ) .join("\n") .trim() + "\n", { parser: "typescript" } ); };