sfdx-hardis
Version:
Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards
130 lines • 6.2 kB
JavaScript
import * as fs from "fs";
import { sortCrossPlatform } from "../utils/index.js";
import { DocBuilderRoot } from "./docBuilderRoot.js";
export class DocBuilderApex extends DocBuilderRoot {
docType = "APEX";
promptKey = "PROMPT_DESCRIBE_APEX";
placeholder = "<!-- Apex description -->";
static buildIndexTable(prefix, apexDescriptions, filterObject = null) {
const filteredApex = filterObject ? apexDescriptions.filter(apex => apex.impactedObjects.includes(filterObject)) : apexDescriptions;
if (filteredApex.length === 0) {
return [];
}
const lines = [];
lines.push(...[
filterObject ? "## Related Apex Classes" : "## Apex Classes",
"",
"| Apex Class | Type |",
"| :---- | :--: | "
]);
for (const apex of filteredApex) {
const flowNameCell = `[${apex.name}](${prefix}${apex.name}.md)`;
lines.push(...[
`| ${flowNameCell} | ${apex.type} |`
]);
}
lines.push("");
return lines;
}
// Build Mermaid class diagram with all direct and reverse relationships with className
static buildMermaidClassDiagram(className, apexDescriptions) {
const classNameDescription = apexDescriptions.find(apex => apex.name === className);
if (!classNameDescription) {
return "";
}
const relatedClasses = sortCrossPlatform(classNameDescription.relatedClasses || []);
const reverseRelatedClasses = sortCrossPlatform(apexDescriptions.map(apex => ({
name: apex.name,
relatedClasses: apex.relatedClasses || []
})).filter(apex => apex.relatedClasses.includes(className)).map(apex => apex.name));
const allRelatedClasses = [...new Set([...relatedClasses, ...reverseRelatedClasses])];
const lines = ["## Class Diagram"];
lines.push("");
lines.push("```mermaid");
lines.push("graph TD");
lines.push(` ${className}["${className}"]:::mainApexClass`);
if (fs.existsSync(`docs/apex/${className}.md`)) {
lines.push(` click ${className} "/objects/${className}/"`);
}
// Declare all classes related to the className
for (const relatedClassName of allRelatedClasses) {
const relatedClassDescription = apexDescriptions.find(apex => apex.name === relatedClassName);
if (relatedClassDescription?.type.includes("Test")) {
lines.push(` ${relatedClassName}["${relatedClassName}"]:::apexTestClass`);
}
else {
lines.push(` ${relatedClassName}["${relatedClassName}"]:::apexClass`);
}
if (fs.existsSync(`docs/apex/${relatedClassName}.md`)) {
lines.push(` click ${relatedClassName} "/apex/${relatedClassName}/"`);
}
}
lines.push("");
let pos = 0;
const directLinksPos = [];
const reverseLinksPos = [];
const transverseLinksPos = [];
// Add relationships
for (const relatedClassName of relatedClasses) {
if (relatedClassName !== className) {
lines.push(` ${className} --> ${relatedClassName}`);
directLinksPos.push(pos);
pos++;
}
}
lines.push("");
// Add reverse relationships
for (const relatedClassName of reverseRelatedClasses) {
if (relatedClassName !== className) {
lines.push(` ${relatedClassName} --> ${className}`);
reverseLinksPos.push(pos);
pos++;
}
}
lines.push("");
// If the number of lines is not too big, calculate relations between related classes using allRelatedClasses and apexDescriptions
// This is to avoid too many links in the diagram
if (allRelatedClasses.length > 10) {
lines.push(" %% Too many related classes, skipping transverse links");
lines.push("");
}
else {
for (const relatedClassName of allRelatedClasses) {
const relatedClassDescription = apexDescriptions.find(apex => apex.name === relatedClassName);
if (relatedClassDescription) {
const relatedRelatedClasses = relatedClassDescription.relatedClasses || [];
for (const otherRelatedClassName of relatedRelatedClasses) {
if (otherRelatedClassName !== className && allRelatedClasses.includes(otherRelatedClassName) && otherRelatedClassName !== relatedClassName) {
lines.push(` ${relatedClassName} --> ${otherRelatedClassName}`);
transverseLinksPos.push(pos);
pos++;
}
}
}
}
}
// Add styles for classes
lines.push("");
lines.push(`classDef apexClass fill:#FFF4C2,stroke:#CCAA00,stroke-width:3px,rx:12px,ry:12px,shadow:drop,color:#333;`);
lines.push(`classDef apexTestClass fill:#F5F5F5,stroke:#999999,stroke-width:3px,rx:12px,ry:12px,shadow:drop,color:#333;`);
lines.push(`classDef mainApexClass fill:#FFB3B3,stroke:#A94442,stroke-width:4px,rx:14px,ry:14px,shadow:drop,color:#333,font-weight:bold;`);
lines.push("");
// Add classes to links
if (directLinksPos.length > 0) {
lines.push("linkStyle " + directLinksPos.join(",") + " stroke:#4C9F70,stroke-width:4px;");
}
if (reverseLinksPos.length > 0) {
lines.push("linkStyle " + reverseLinksPos.join(",") + " stroke:#FF8C00,stroke-width:2px;");
}
if (transverseLinksPos.length > 0) {
lines.push("linkStyle " + transverseLinksPos.join(",") + " stroke:#A6A6A6,stroke-width:2px;");
}
lines.push("```");
// Use Graph LR if there are too many lines for a nice mermaid display
if (lines.length > 50) {
lines[3] = "graph LR";
}
return lines.join("\n");
}
}
//# sourceMappingURL=docBuilderApex.js.map