UNPKG

prisma-grapher

Version:
246 lines 11.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generate = generate; const wasm_1 = require("@hpcc-js/wasm"); const promises_1 = require("fs/promises"); const identifier = (...parts) => parts .filter(Boolean) .map((part) => JSON.stringify(part)) .join(":"); function generate(options) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const config = options.generator.config; const output = ((_a = options.generator.output) === null || _a === void 0 ? void 0 : _a.value) || "./prisma/ERD.svg"; const disabled = config.disabled === "true" || process.env.DISABLE_PRISMA_GRAPHER === "true"; const title = (_b = config.title) !== null && _b !== void 0 ? _b : ""; const ignoreEnums = config.ignoreEnums === "true"; const lineColor = (_c = config.lineColor) !== null && _c !== void 0 ? _c : "#004cff"; const headerBackgroundColor = (_d = config.headerBackgroundColor) !== null && _d !== void 0 ? _d : "#bacefc"; const headerForegroundColor = (_e = config.headerForegroundColor) !== null && _e !== void 0 ? _e : "black"; const bodyBackgroundColor = (_f = config.bodyBackgroundColor) !== null && _f !== void 0 ? _f : "white"; const bodyBackgroundColor2 = (_g = config.bodyBackgroundColor2) !== null && _g !== void 0 ? _g : "#e8efff"; const bodyForegroundColor = (_h = config.bodyForegroundColor) !== null && _h !== void 0 ? _h : "black"; const typeForegroundColor = (_j = config.typeForegroundColor) !== null && _j !== void 0 ? _j : "#4f83ff"; if (disabled) { return console.log("prisma grapher is disabled"); } const enums = options.dmmf.datamodel.enums; const models = [...options.dmmf.datamodel.models, ...options.dmmf.datamodel.types]; const enumByName = !ignoreEnums ? enums.reduce((acc, _enum) => ((acc[_enum.name] = _enum), acc), {}) : {}; const modelByName = models.reduce((acc, model, index) => ((acc[model.name] = Object.assign(Object.assign({}, model), { index })), acc), {}); const verticesLeft = []; const verticesRight = []; const relations = Object.values(modelByName) .flatMap((aModel) => aModel.fields .filter((aField) => enumByName[aField.type] || modelByName[aField.type]) .filter((aField) => aField.type !== aModel.name) .map((aField) => { var _a; const a = [aModel.name, aField.name]; if (enumByName[aField.type]) { const bModel = enumByName[aField.type]; const b = [bModel.name, ""]; const t = !aField.isList ? "1-m" : "m-m"; return [b, a, t]; } else { const bModel = modelByName[aField.type]; const bField = bModel.fields.find((it) => it.type === aModel.name); const b = [bModel.name, (_a = bField === null || bField === void 0 ? void 0 : bField.name) !== null && _a !== void 0 ? _a : ""]; return !aField.isList && (bField === null || bField === void 0 ? void 0 : bField.isList) ? [b, a, "1-m"] : aField.isList && !(bField === null || bField === void 0 ? void 0 : bField.isList) ? [a, b, "1-m"] : aModel.index < bModel.index ? [a, b, !aField.isList ? "1-1" : "m-m"] : [b, a, !aField.isList ? "1-1" : "m-m"]; } })) .map((edge) => JSON.stringify(edge)) .filter((it, i, arr) => arr.indexOf(it) === i) .map((it) => JSON.parse(it)) .map((edge) => (verticesLeft.push(edge[0]), verticesRight.push(edge[1]), edge)); const relationDotDefinitions = relations.map((edge) => ` edge [ dir=both arrowtail=${edge[2].startsWith("1-") ? "tee" : "crow"} arrowhead=${edge[2].endsWith("-1") ? "tee" : "crow"} ] ${identifier(...edge[0])}:e -> ${identifier(...edge[1])}:w `); const nodeTableAttributes = ` bgcolor="${bodyBackgroundColor}" color="${lineColor}" border="0" cellborder="0" cellspacing="0" cellpadding="0"`; const headerTdAttributes = ` bgcolor="${headerBackgroundColor}" color="${lineColor}" border="1" cellpadding="8"`; const fieldsTableAttributes = ` bgcolor="${bodyBackgroundColor}" color="${lineColor}" border="0" cellborder="0" cellspacing="0" cellpadding="4"`; const enumDotDefinitions = !ignoreEnums ? enums.map((_enum) => ` ${identifier(_enum.name)} [ shape=plain label=<<table ${nodeTableAttributes}> <tr> <td ${headerTdAttributes}><font color="${headerForegroundColor}">${_enum.name}</font></td> </tr> <tr> <td> <table ${fieldsTableAttributes}> ${_enum.values .map((value, i, values) => { const bgcolor = i % 2 === 0 ? bodyBackgroundColor : bodyBackgroundColor2; const bottomBorder = i === values.length - 1 ? "B" : ""; return `<tr> <td bgcolor="${bgcolor}" color="${lineColor}" border="1" sides="L${bottomBorder}" ></td> <td bgcolor="${bgcolor}" color="${lineColor}" ${bottomBorder ? `border="1" sides="${bottomBorder}"` : ""} ><font color="${bodyForegroundColor}">${value.name}</font></td> <td bgcolor="${bgcolor}" color="${lineColor}" border="1" sides="R${bottomBorder}" ></td> </tr>`; }) .join("\n")} </table> </td> </tr> </table>> ] `) : []; const modelDotDefinitions = models.map((model) => ` ${identifier(model.name)} [ shape=plain label=<<table ${nodeTableAttributes}> <tr> <td ${headerTdAttributes}><font color="${headerForegroundColor}">${model.name}</font></td> </tr> <tr> <td> <table ${fieldsTableAttributes}> ${model.fields .filter((field, i, fields) => !fields.some((otherField) => { var _a; return (_a = otherField.relationFromFields) === null || _a === void 0 ? void 0 : _a.includes(field.name); })) .map((field, i, fields) => { const bgcolor = i % 2 === 0 ? bodyBackgroundColor : bodyBackgroundColor2; const portLeft = field.kind === "enum" || verticesRight.find((vertex) => vertex[0] === model.name && vertex[1] === field.name) ? field.name : ""; const portRight = verticesLeft.find((vertex) => vertex[0] === model.name && vertex[1] === field.name) ? field.name : ""; const bottomBorder = i === fields.length - 1 ? "B" : ""; return `<tr> <td bgcolor="${bgcolor}" color="${lineColor}" border="1" sides="L${bottomBorder}" port="${portLeft}" >${field.isId ? `<font color="${bodyForegroundColor}">&#9670;</font>` : field.relationFromFields !== undefined || field.kind === "enum" ? `<font color="${bodyForegroundColor}">&#9671;</font>` : ""}</td> <td bgcolor="${bgcolor}" color="${lineColor}" ${bottomBorder ? `border="1" sides="${bottomBorder}"` : ""} align="left" ><font color="${bodyForegroundColor}">${field.name}&nbsp;&nbsp;</font></td> <td bgcolor="${bgcolor}" color="${lineColor}" ${bottomBorder ? `border="1" sides="${bottomBorder}"` : ""} align="left" ><font color="${typeForegroundColor}">${[ field.type, field.isList ? "&nbsp;[&nbsp;]" : "", !field.isRequired ? "&nbsp;?" : "", ].join("")}&nbsp;&nbsp;</font></td> <td bgcolor="${bgcolor}" color="${lineColor}" border="1" sides="R${bottomBorder}" align="left" port="${portRight}" ></td> </tr>`; }) .join("\n")} </table> </td> </tr> </table>> ] `); const dotSource = ` digraph ERD { graph [ ${title ? `label=${identifier(title)}` : ""} pad=0.4 labelloc="t" fontname="Arial,sans-serif" rankdir="LR" ] node [ fontname="Arial,sans-serif" shape=record style=filled color="${lineColor}" fillcolor="${headerBackgroundColor}" fontcolor="${headerForegroundColor}" ] edge [ fontname="Arial,sans-serif" color="${lineColor}" minlen=5 arrowsize=1.2 ] ${relationDotDefinitions.join("\n")} ${enumDotDefinitions.join("\n")} ${modelDotDefinitions.join("\n")} } `; const graphviz = yield wasm_1.Graphviz.load(); const svg = graphviz.dot(dotSource, "svg"); yield (0, promises_1.writeFile)(output, svg); return console.log(`prisma grapher generated erd at "${output}"`); }); } //# sourceMappingURL=generate.js.map