UNPKG

@webda/shell

Version:

Deploy a Webda app or configure it

150 lines (148 loc) 4.85 kB
/* StorageDiagram <!-- WEBDA:StorageDiagram --> ```mermaid flowchart BT CoreModel User --> CoreModel Task --> CoreModel CustomUser --> User subgraph MyStore User CustomUser end ``` <!-- /WEBDA:StorageDiagram --> */ import { Service } from "@webda/core"; import { existsSync, readFileSync, writeFileSync } from "fs"; /** * Abstract diagram with the common replacement methods */ export class Diagram { constructor(name) { this.name = name; } update(file, webda) { this.file = file; if (existsSync(file)) { this.content = readFileSync(file, "utf8").toString(); } else { this.content = ""; } let diagram = this.generate(webda); diagram = `<!-- WEBDA:${this.name} -->\n${diagram}\n<!-- /WEBDA:${this.name} -->`; if (this.content.includes(`<!-- WEBDA:${this.name} -->`)) { const regexp = new RegExp(`<!-- WEBDA:${this.name} -->[\\s\\S]*?<!-- \\/WEBDA:${this.name} -->`, "gm"); this.content = this.content.replace(regexp, diagram); } else { this.content += `\n${diagram}\n`; } writeFileSync(this.file, this.content); } } /** * Export each CoreModel and their Store */ export class StorageDiagram extends Diagram { constructor() { super("StorageDiagram"); } generate(webda) { let diagram = "```mermaid\nflowchart BT\n"; const tree = webda.getApplication().getModelHierarchy("CoreModel"); const stores = {}; const recursive = (name, children) => { let storeName = webda.getModelStore(webda.getModel(name)).getName(); stores[storeName] ?? (stores[storeName] = []); stores[storeName].push(name); for (let child in children) { diagram += `\t${child} --> ${name}\n`; recursive(child, children[child]); } }; recursive("CoreModel", tree.children); // Add subgraph for Stores for (let store in stores) { diagram += `\n\tsubgraph ${store}\n`; for (let model of stores[store]) { diagram += `\t\t${model}\n`; } diagram += `\tend\n`; } return diagram + "```"; } } /** * Export each CoreModel, their properties and actions */ export class ModelDiagram extends Diagram { constructor() { super("ClassDiagram"); } generateClassDefinition(schema, actions) { let definition = ""; if (schema.description) { definition += `\t\t${schema.title}: ${schema.description}\n`; } const properties = schema.properties; // Display properties for (const propertyName in properties) { const property = properties[propertyName]; const isRequired = schema.required && schema.required.includes(propertyName); const propertyType = property.type; definition += `\t\t${isRequired ? "+" : "-"}${propertyName}: ${propertyType}\n`; } // Display actions for (const actionName in actions) { definition += `\t\t+${actionName}()\n`; } return definition; } generate(webda) { const models = webda.getApplication().getModels(); let diagram = "```mermaid\nclassDiagram\n"; Object.values(models).forEach(model => { diagram += `\tclass ${model.getIdentifier()}{\n`; diagram += this.generateClassDefinition(model.getSchema() || { properties: {} }, model.getActions()); diagram += `\t}\n`; }); return diagram + "```"; } } /** * Export each Service and their dependencies * * It detect dependencies by looking at the attributes of the service * So dynamic dependencies are not detected */ export class ServiceDiagram extends Diagram { constructor() { super("ServiceDiagram"); } generate(webda) { const services = Object.values(webda.getServices()).filter(service => service.getName); let diagram = "```mermaid\nflowchart TD\n"; let ids = {}; services.forEach((service, i) => { diagram += `\tS${i}(${service.getName()}<br /><i>${service.getParameters().type}</i>)\n`; ids[service.getName()] = i; }); services.forEach((service, i) => { for (let attr in service) { if (service[attr] instanceof Service) { diagram += `\tS${i} -->|${attr}| S${ids[service[attr].getName()]}\n`; } } }); return diagram + "```"; } } export const DiagramTypes = { storage: StorageDiagram, models: ModelDiagram, services: ServiceDiagram }; //# sourceMappingURL=diagrams.js.map