const { makeKyselyHook } = require("kanel-kysely"); const { makePgTsGenerator } = require("kanel"); const { generateZodSchemas, makeGenerateZodSchemas, defaultZodTypeMap } = require("kanel-zod"); const ignoredTables = ["schema_migrations"]; /** * Allows for injection of custom types from the mapping of `table.field` * @param {import("kanel").TypeMap} mappings * @returns {import("kanel").PreRenderHook} */ const specificTypes = (mappings) => { /** @type {import("kanel").PreRenderHook} */ return async (outputAcc, instantiatedConfig) => { const output = { ...outputAcc }; for (const path of Object.keys(output)) { const file = outputAcc[path]; const declarations = file.declarations.map((decl) => { const declaration = { ...decl }; if (declaration.declarationType === "interface") { for (const field of declaration.properties) { const key = `${declaration.name}.${field.name}`; if (mappings[key]) { field.typeName = mappings[key].name; declaration.typeImports = [ ...(declaration.typeImports || []), ...mappings[key].typeImports, ]; } } } return declaration; }); output[path] = { ...file, declarations, }; } return output; }; } const kanelZodCastRegex = /as unknown as z.Schema<(.*?)(Mutator|Initializer)>/; const zodItemInitializer = /^export const \w+ = z\.object/ /** * @type {import("kanel").PostRenderHook} * * Renames the type of the `as unknown as z.Schema` casts from `kanel-zod` to * to be compatible with `kanel-kysely`, turning * 1. `as unknown as z.Schema` into `as unknown as z.Schema` * 2. `as unknown as z.Schema` into `as unknown as z.Schema` */ function kanelKyselyZodCompatibilityHook(path, lines) { return lines.map((line) => { if (zodItemInitializer.test(line)) { const parts = line.split(" "); if (parts[2].includes("Initializer")) { const nome = parts[2].replace("Initializer", ""); parts[2] = "New" + nome[0].toUpperCase() + nome.slice(1) + "Schema"; return parts.join(" "); } if (parts[2].includes("Mutator")) { const nome = parts[2].replace("Mutator", ""); parts[2] = nome[0].toUpperCase() + nome.slice(1) + "UpdateSchema"; return parts.join(" "); } const nome = parts[2]; parts[2] = nome[0].toUpperCase() + nome.slice(1) + "Schema"; return parts.join(" "); } if (line.includes("as unknown as z.Schema")) { const replacedLine = line.replace( kanelZodCastRegex, (_, typeName, mutatorOrInitializer) => { if (!mutatorOrInitializer) { return `as unknown as z.Schema<${typeName}>`; } if (mutatorOrInitializer === "Mutator") { return `as unknown as z.Schema<${typeName}Update>`; } return `as unknown as z.Schema`; } ); return replacedLine; } return line; }); } /**@type {import("kanel").PostRenderHook} */ function zodCaratteristicheHook(path, lines) { if (path.includes("src\\schemas\\public\\Annunci.ts")) { return lines.map(line => { if (line.includes("kanel-types")) { return "import { CaratteristicheSchema, type Caratteristiche } from '../../utils/kanel-types';" } if (line.includes("caratteristiche: z.unknown().optional().nullable()")) { return line.replace("caratteristiche: z.unknown().optional().nullable()", "caratteristiche: CaratteristicheSchema.optional().nullable()") } if (line.includes("caratteristiche: z.unknown().nullable()")) { return line.replace("caratteristiche: z.unknown().nullable()", "caratteristiche: CaratteristicheSchema.nullable()") } return line; }) } return lines } /**@type {import("kanel").PostRenderHook} */ function zodUpdateInsertionDatesFix(path, lines) { //z.date() -> z.union([z.date(), z.string()]).pipe(z.coerce.date()) let insideUpdateOrInsert = false; return lines.map(line => { if (line.includes("export const") && line.includes("UpdateSchema")) { insideUpdateOrInsert = true; } if (line.includes("export const") && line.includes("New")) { insideUpdateOrInsert = true; } if (insideUpdateOrInsert && line.includes("z.date()")) { return line.replace("z.date()", "z.union([z.date(), z.string()]).pipe(z.coerce.date())"); } if (line.includes("import")) { insideUpdateOrInsert = false; } return line; }) } /** @type {import('kanel').Config} */ module.exports = { connection: { host: "localhost", user: "postgres", database: "postgres", password: "rootpost", port: 5433, }, filter: (pgTable) => !ignoredTables.includes(pgTable.name), outputPath: "./src/schemas", generators: [ makePgTsGenerator({ customTypeMap: { "pg_catalog.tsvector": "string", "pg_catalog.bpchar": "string", 'pg_catalog.numeric': 'number', //"pg_catalog.json": "string", 'pg_catalog.bytea': "Buffer" }, preRenderHooks: [ specificTypes({ "Annunci.caratteristiche": { name: "Caratteristiche", typeImports: [{ name: "Caratteristiche", path: "src/utils/kanel-types.ts", importAsType: true, isAbsolute: false, isDefault: false }], }, }), makeKyselyHook(), makeGenerateZodSchemas({ castToSchema: false, zodTypeMap: { ...defaultZodTypeMap, "pg_catalog.numeric": "z.number()", "pg_catalog.bytea": "z.instanceof(Buffer)" } }), ], }), ], postRenderHooks: [kanelKyselyZodCompatibilityHook, zodCaratteristicheHook, zodUpdateInsertionDatesFix], preDeleteOutputFolder: true, };