sfdx-hardis 5.10.2-beta202412231619.0 → 5.10.2-beta202412292224.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/defaults/mkdocs/docs/stylesheets/extra.css +25 -0
  2. package/defaults/mkdocs/mkdocs.yml +10 -2
  3. package/defaults/mkdocs-project-doc/docs/javascripts/gtag.js +27 -0
  4. package/defaults/mkdocs-project-doc/docs/javascripts/tables.js +6 -0
  5. package/defaults/mkdocs-project-doc/docs/overrides/main.html +4 -0
  6. package/defaults/mkdocs-project-doc/docs/stylesheets/extra.css +33 -0
  7. package/defaults/mkdocs-project-doc/mkdocs.yml +49 -0
  8. package/lib/commands/hardis/doc/flow2markdown.d.ts +1 -0
  9. package/lib/commands/hardis/doc/flow2markdown.js +18 -3
  10. package/lib/commands/hardis/doc/flow2markdown.js.map +1 -1
  11. package/lib/commands/hardis/doc/project2markdown.d.ts +7 -2
  12. package/lib/commands/hardis/doc/project2markdown.js +173 -45
  13. package/lib/commands/hardis/doc/project2markdown.js.map +1 -1
  14. package/lib/commands/hardis/project/generate/flow-git-diff.js +28 -16
  15. package/lib/commands/hardis/project/generate/flow-git-diff.js.map +1 -1
  16. package/lib/common/gitProvider/utilsMarkdown.js +5 -5
  17. package/lib/common/gitProvider/utilsMarkdown.js.map +1 -1
  18. package/lib/common/metadata-utils/index.js +3 -2
  19. package/lib/common/metadata-utils/index.js.map +1 -1
  20. package/lib/common/utils/flowVisualiser/flowParser.d.ts +0 -7
  21. package/lib/common/utils/flowVisualiser/flowParser.js +150 -167
  22. package/lib/common/utils/flowVisualiser/flowParser.js.map +1 -1
  23. package/lib/common/utils/flowVisualiser/nodeFormatUtils.d.ts +14 -0
  24. package/lib/common/utils/flowVisualiser/nodeFormatUtils.js +341 -0
  25. package/lib/common/utils/flowVisualiser/nodeFormatUtils.js.map +1 -0
  26. package/lib/common/utils/flowVisualiser/renderConfig.d.ts +9 -3
  27. package/lib/common/utils/flowVisualiser/renderConfig.js +62 -56
  28. package/lib/common/utils/flowVisualiser/renderConfig.js.map +1 -1
  29. package/lib/common/utils/index.d.ts +1 -0
  30. package/lib/common/utils/index.js +10 -0
  31. package/lib/common/utils/index.js.map +1 -1
  32. package/lib/common/utils/mermaidUtils.d.ts +5 -2
  33. package/lib/common/utils/mermaidUtils.js +278 -92
  34. package/lib/common/utils/mermaidUtils.js.map +1 -1
  35. package/lib/common/utils/projectUtils.js +1 -1
  36. package/lib/common/utils/projectUtils.js.map +1 -1
  37. package/oclif.lock +938 -1263
  38. package/oclif.manifest.json +373 -358
  39. package/package.json +6 -5
@@ -3,7 +3,7 @@ import fs from 'fs-extra';
3
3
  import * as Diff from "diff";
4
4
  import * as path from "path";
5
5
  import which from "which";
6
- import { execCommand, git, uxLog } from "./index.js";
6
+ import { execCommand, git, isDockerRunning, uxLog } from "./index.js";
7
7
  import { parseFlow } from "./flowVisualiser/flowParser.js";
8
8
  import { getReportDirectory } from "../../config/index.js";
9
9
  import moment from "moment";
@@ -26,13 +26,15 @@ export async function isDockerAvailable() {
26
26
  if (IS_DOCKER_AVAILABLE !== null) {
27
27
  return IS_DOCKER_AVAILABLE;
28
28
  }
29
- const isDockerAvailable1 = await which("docker", { nothrow: true });
30
- IS_DOCKER_AVAILABLE = isDockerAvailable1 !== null;
29
+ IS_DOCKER_AVAILABLE = await isDockerRunning();
30
+ if (!IS_DOCKER_AVAILABLE) {
31
+ uxLog(this, c.yellow("Docker daemon is not available. If you have issues running npm package @mermaid-js/mermaid-cli, please install Docker and start it"));
32
+ }
31
33
  return IS_DOCKER_AVAILABLE;
32
34
  }
33
- export async function generateFlowMarkdownFile(flowName, flowXml, outputFlowMdFile) {
35
+ export async function generateFlowMarkdownFile(flowName, flowXml, outputFlowMdFile, options = { collapsedDetails: true }) {
34
36
  try {
35
- const flowDocGenResult = await parseFlow(flowXml, 'mermaid', { outputAsMarkdown: true });
37
+ const flowDocGenResult = await parseFlow(flowXml, 'mermaid', { outputAsMarkdown: true, collapsedDetails: options.collapsedDetails });
36
38
  const flowMarkdownDoc = flowDocGenResult.uml;
37
39
  await fs.writeFile(outputFlowMdFile, flowMarkdownDoc);
38
40
  uxLog(this, c.grey(`Written ${flowName} documentation in ${outputFlowMdFile}`));
@@ -99,59 +101,80 @@ export async function generateMarkdownFileWithMermaidCli(outputFlowMdFile) {
99
101
  }
100
102
  }
101
103
  export function getMermaidExtraClasses() {
102
- return `classDef actionCallsAdded fill:#344568,color:white,stroke:#00ff00,stroke-width:12px;
103
- classDef assignmentsAdded fill:#F97924,color:white,stroke:#00ff00,stroke-width:12px;
104
- classDef collectionProcessorsAdded fill:#DD7A00,color:white,stroke:#00ff00,stroke-width:12px;
105
- classDef customErrorsAdded fill:#032D60,color:white,stroke:#00ff00,stroke-width:12px;
106
- classDef decisionsAdded fill:#DD7A00,color:white,stroke:#00ff00,stroke-width:12px;
107
- classDef loopsAdded fill:#E07D1C,color:undefined,stroke:#00ff00,stroke-width:12px;
108
- classDef recordCreatesAdded fill:#F9548A,color:white,stroke:#00ff00,stroke-width:12px;
109
- classDef recordDeletesAdded fill:#F9548A,color:white,stroke:#00ff00,stroke-width:12px;
110
- classDef recordLookupsAdded fill:#F9548A,color:white,stroke:#00ff00,stroke-width:12px;
111
- classDef recordUpdatesAdded fill:#F9548A,color:white,stroke:#00ff00,stroke-width:12px;
112
- classDef screensAdded fill:#1B96FF,color:white,stroke:#00ff00,stroke-width:12px;
113
- classDef subflowsAdded fill:#032D60,color:white,stroke:#00ff00,stroke-width:12px;
114
-
115
- classDef actionCallsRemoved fill:#344568,color:white,stroke:#ff0000,stroke-width:12px;
116
- classDef assignmentsRemoved fill:#F97924,color:white,stroke:#ff0000,stroke-width:12px;
117
- classDef collectionProcessorsRemoved fill:#DD7A00,color:white,stroke:#ff0000,stroke-width:12px;
118
- classDef customErrorsRemoved fill:#032D60,color:white,stroke:#ff0000,stroke-width:12px;
119
- classDef decisionsRemoved fill:#DD7A00,color:white,stroke:#ff0000,stroke-width:12px;
120
- classDef loopsRemoved fill:#E07D1C,color:undefined,stroke:#ff0000,stroke-width:12px;
121
- classDef recordCreatesRemoved fill:#F9548A,color:white,stroke:#ff0000,stroke-width:12px;
122
- classDef recordDeletesRemoved fill:#F9548A,color:white,stroke:#ff0000,stroke-width:12px;
123
- classDef recordLookupsRemoved fill:#F9548A,color:white,stroke:#ff0000,stroke-width:12px;
124
- classDef recordUpdatesRemoved fill:#F9548A,color:white,stroke:#ff0000,stroke-width:12px;
125
- classDef screensRemoved fill:#1B96FF,color:white,stroke:#ff0000,stroke-width:12px;
126
- classDef subflowsRemoved fill:#032D60,color:white,stroke:#ff0000,stroke-width:12px;
104
+ const added = 'fill:green,color:white,stroke-width:4px,max-height:100px';
105
+ const removed = 'fill:red,color:white,stroke-width:4px,max-height:100px';
106
+ const changed = 'fill:orange,color:white,stroke-width:4px,max-height:100px';
107
+ const addedClasses = [
108
+ 'actionCallsAdded',
109
+ 'assignmentsAdded',
110
+ 'collectionProcessorsAdded',
111
+ 'customErrorsAdded',
112
+ 'decisionsAdded',
113
+ 'loopsAdded',
114
+ 'recordCreatesAdded',
115
+ 'recordDeletesAdded',
116
+ 'recordLookupsAdded',
117
+ 'recordUpdatesAdded',
118
+ 'screensAdded',
119
+ 'subflowsAdded',
120
+ 'startClassAdded'
121
+ ];
122
+ const removedClasses = [
123
+ 'actionCallsRemoved',
124
+ 'assignmentsRemoved',
125
+ 'collectionProcessorsRemoved',
126
+ 'customErrorsRemoved',
127
+ 'decisionsRemoved',
128
+ 'loopsRemoved',
129
+ 'recordCreatesRemoved',
130
+ 'recordDeletesRemoved',
131
+ 'recordLookupsRemoved',
132
+ 'recordUpdatesRemoved',
133
+ 'screensRemoved',
134
+ 'subflowsRemoved',
135
+ 'startClassRemoved'
136
+ ];
137
+ const changedClasses = [
138
+ 'actionCallsChanged',
139
+ 'assignmentsChanged',
140
+ 'collectionProcessorsChanged',
141
+ 'customErrorsChanged',
142
+ 'decisionsChanged',
143
+ 'loopsChanged',
144
+ 'recordCreatesChanged',
145
+ 'recordDeletesChanged',
146
+ 'recordLookupsChanged',
147
+ 'recordUpdatesChanged',
148
+ 'screensChanged',
149
+ 'subflowsChanged',
150
+ 'startClassChanged'
151
+ ];
152
+ const formatClasses = (classList, style) => classList.map(className => `classDef ${className} ${style}`).join('\n');
153
+ return `
154
+ ${formatClasses(addedClasses, added)}
127
155
 
128
- classDef actionCallsChanged fill:#344568,color:white,stroke:#edaa18,stroke-width:12px;
129
- classDef assignmentsChanged fill:#F97924,color:white,stroke:#edaa18,stroke-width:12px;
130
- classDef collectionProcessorsChanged fill:#DD7A00,color:white,stroke:#edaa18,stroke-width:12px;
131
- classDef customErrorsChanged fill:#032D60,color:white,stroke:#edaa18,stroke-width:12px;
132
- classDef decisionsChanged fill:#DD7A00,color:white,stroke:#edaa18,stroke-width:12px;
133
- classDef loopsChanged fill:#E07D1C,color:undefined,stroke:#edaa18,stroke-width:12px;
134
- classDef recordCreatesChanged fill:#F9548A,color:white,stroke:#edaa18,stroke-width:12px;
135
- classDef recordDeletesChanged fill:#F9548A,color:white,stroke:#edaa18,stroke-width:12px;
136
- classDef recordLookupsChanged fill:#F9548A,color:white,stroke:#edaa18,stroke-width:12px;
137
- classDef recordUpdatesChanged fill:#F9548A,color:white,stroke:#edaa18,stroke-width:12px;
138
- classDef screensChanged fill:#1B96FF,color:white,stroke:#edaa18,stroke-width:12px;
139
- classDef subflowsChanged fill:#032D60,color:white,stroke:#edaa18,stroke-width:12px;
156
+ ${formatClasses(removedClasses, removed)}
140
157
 
141
- classDef addedLink stroke:#00ff00,stroke-width:3px;
142
- classDef removedLink stroke:#ff0000,stroke-width:3px;
143
- `;
158
+ ${formatClasses(changedClasses, changed)}
159
+ `;
144
160
  }
145
161
  export async function generateFlowVisualGitDiff(flowFile, commitBefore, commitAfter, options = { mermaidMd: false, svgMd: true, debug: false }) {
162
+ const result = { outputDiffMdFile: "", hasFlowDiffs: false };
146
163
  const mermaidMdBefore = await buildMermaidMarkdown(commitBefore, flowFile);
147
164
  const mermaidMdAfter = await buildMermaidMarkdown(commitAfter, flowFile);
148
165
  const flowLabel = path.basename(flowFile, ".flow-meta.xml");
166
+ const reportDir = await getReportDirectory();
167
+ await fs.ensureDir(path.join(reportDir, "flow-diff"));
168
+ const diffMdFile = path.join(reportDir, 'flow-diff', `${flowLabel}_${moment().format("YYYYMMDD-hhmmss")}.md`);
149
169
  if (options.debug) {
150
170
  uxLog(this, c.grey("FLOW DOC BEFORE:\n" + mermaidMdBefore) + "\n");
171
+ await fs.writeFile(diffMdFile.replace(".md", ".mermaid-before.md"), mermaidMdBefore);
151
172
  uxLog(this, c.grey("FLOW DOC AFTER:\n" + mermaidMdAfter) + "\n");
173
+ await fs.writeFile(diffMdFile.replace(".md", ".mermaid-after.md"), mermaidMdAfter);
152
174
  }
153
175
  const flowDiffs = Diff.diffLines(mermaidMdBefore, mermaidMdAfter);
154
- // uxLog(this, JSON.stringify(flowDiffs, null, 2));
176
+ result.hasFlowDiffs = flowDiffs.some(line => line.added || line.removed);
177
+ result.diffLines = flowDiffs.filter(line => line.added || line.removed);
155
178
  const mixedLines = [];
156
179
  for (const line of flowDiffs) {
157
180
  if (line.added) {
@@ -166,26 +189,26 @@ export async function generateFlowVisualGitDiff(flowFile, commitBefore, commitAf
166
189
  }
167
190
  // uxLog(this, JSON.stringify(mixedLines, null, 2));
168
191
  const compareMdLines = [];
169
- buildFinalCompareMarkdown(mixedLines, compareMdLines, false, false);
192
+ const linkLines = [];
193
+ buildFinalCompareMarkdown(mixedLines, compareMdLines, false, false, linkLines);
170
194
  // Write markdown with diff in a file
171
- const reportDir = await getReportDirectory();
172
- await fs.ensureDir(path.join(reportDir, "flow-diff"));
173
- const diffMdFile = path.join(reportDir, 'flow-diff', `${flowLabel}_${moment().format("YYYYMMDD-hhmmss")}.md`);
174
195
  await fs.writeFile(diffMdFile, compareMdLines.join("\n"));
175
196
  if (options.mermaidMd) {
176
- await fs.copyFile(diffMdFile, diffMdFile + ".mermaid.md");
197
+ await fs.copyFile(diffMdFile, diffMdFile.replace(".md", ".mermaid.md"));
177
198
  }
178
199
  if (!options.svgMd) {
179
- return diffMdFile;
200
+ result.outputDiffMdFile = diffMdFile;
201
+ return result;
180
202
  }
181
203
  // Generate final markdown with mermaid SVG
182
204
  const finalRes = await generateMarkdownFileWithMermaid(diffMdFile);
183
205
  if (finalRes) {
184
206
  uxLog(this, c.green(`Successfully generated visual git diff for flow: ${diffMdFile}`));
185
207
  }
186
- return diffMdFile;
208
+ result.outputDiffMdFile = diffMdFile;
209
+ return result;
187
210
  }
188
- function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTableStarted) {
211
+ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTableStarted, linkLines) {
189
212
  if (mixedLines.length === 0) {
190
213
  return;
191
214
  }
@@ -197,19 +220,37 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
197
220
  }
198
221
  else if (isMermaid === true && currentLine.includes("```")) {
199
222
  compareMdLines.push(...getMermaidExtraClasses().split("\n"));
223
+ // Build link positions
224
+ let pos = 0;
225
+ const positions = {
226
+ added: [],
227
+ removed: [],
228
+ unchanged: []
229
+ };
230
+ for (const linkType of linkLines) {
231
+ positions[linkType].push(pos);
232
+ pos++;
233
+ }
234
+ // Build added and removed links styles
235
+ if (positions.added.length > 0) {
236
+ compareMdLines.push("linkStyle " + positions.added.join(",") + " stroke:#00ff00,stroke-width:4px,color:green;");
237
+ }
238
+ if (positions.removed.length > 0) {
239
+ compareMdLines.push("linkStyle " + positions.removed.join(",") + " stroke:#ff0000,stroke-width:4px,color:red;");
240
+ }
200
241
  isMermaid = false;
201
242
  }
202
243
  let styledLine = currentLine;
203
244
  // Remove next diff line if not relevant
204
- if (styledLine.startsWith("|") && mixedLines.length > 1 && mixedLines[0][1] === '' && mixedLines[1][1].startsWith("|")) {
245
+ if (styledLine.startsWith("|") && mixedLines.length > 1 && mixedLines[0][1] === '' && mixedLines[1][1].startsWith("|") && !mixedLines[1][1].startsWith("|Condition Id|") && !mixedLines[1][1].startsWith("|Filter Id|")) {
205
246
  mixedLines.shift();
206
247
  }
207
248
  // Skip table block if there are no updated lines within
208
- if (styledLine.startsWith("## ") && !styledLine.startsWith("## Flow")) {
249
+ if (styledLine.startsWith("## ") && !styledLine.startsWith("## Flow Diagram")) {
209
250
  let updatedInBlock = false;
210
251
  let nextBlockPos = 0;
211
252
  for (const nextLine of mixedLines) {
212
- if (nextLine[1].startsWith("## ") || nextLine[1].startsWith("_Documentation")) {
253
+ if (nextLine[1].startsWith("## ") || nextLine[1].includes("_Documentation") || nextLine[1].startsWith("___")) {
213
254
  break;
214
255
  }
215
256
  if (nextLine[0] === "removed" || nextLine[0] === "added") {
@@ -220,7 +261,7 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
220
261
  if (!updatedInBlock) {
221
262
  const mixedLinesStartingFromNextBlock = mixedLines.slice(nextBlockPos);
222
263
  // Continue processing next lines
223
- buildFinalCompareMarkdown(mixedLinesStartingFromNextBlock, compareMdLines, isMermaid, isTableStarted);
264
+ buildFinalCompareMarkdown(mixedLinesStartingFromNextBlock, compareMdLines, isMermaid, false, linkLines);
224
265
  return;
225
266
  }
226
267
  }
@@ -230,7 +271,26 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
230
271
  let updatedInBlock = false;
231
272
  let nextBlockPos = 0;
232
273
  for (const nextLine of mixedLines) {
233
- if (nextLine[1].startsWith("### ") || nextLine[1].startsWith("_Documentation")) {
274
+ if (nextLine[1].startsWith("### ") || nextLine[1].startsWith("## ") || nextLine[1].includes("_Documentation") || nextLine[1].startsWith("___")) {
275
+ break;
276
+ }
277
+ if (nextLine[0] === "removed" || nextLine[0] === "added") {
278
+ updatedInBlock = true;
279
+ }
280
+ nextBlockPos++;
281
+ }
282
+ if (!updatedInBlock) {
283
+ const mixedLinesStartingFromNextBlock = mixedLines.slice(nextBlockPos);
284
+ // Continue processing next lines
285
+ buildFinalCompareMarkdown(mixedLinesStartingFromNextBlock, compareMdLines, isMermaid, false, linkLines);
286
+ return;
287
+ }
288
+ }
289
+ else if (styledLine.startsWith("#### ")) {
290
+ let updatedInBlock = false;
291
+ let nextBlockPos = 0;
292
+ for (const nextLine of mixedLines) {
293
+ if (nextLine[1].startsWith("#### ") || nextLine[1].startsWith("### ") || nextLine[1].startsWith("## ") || nextLine[1].includes("_Documentation") || nextLine[1].startsWith("___")) {
234
294
  break;
235
295
  }
236
296
  if (nextLine[0] === "removed" || nextLine[0] === "added") {
@@ -241,7 +301,7 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
241
301
  if (!updatedInBlock) {
242
302
  const mixedLinesStartingFromNextBlock = mixedLines.slice(nextBlockPos);
243
303
  // Continue processing next lines
244
- buildFinalCompareMarkdown(mixedLinesStartingFromNextBlock, compareMdLines, isMermaid, isTableStarted);
304
+ buildFinalCompareMarkdown(mixedLinesStartingFromNextBlock, compareMdLines, isMermaid, false, linkLines);
245
305
  return;
246
306
  }
247
307
  }
@@ -252,62 +312,76 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
252
312
  const tableFilteredLines = [];
253
313
  let endTablePos = 0;
254
314
  for (const nextLine of mixedLines) {
255
- if (!nextLine[1].startsWith("|") && nextLine[1] !== "") {
315
+ if ((!nextLine[1].startsWith("|") || nextLine[1].includes("Condition Id") || nextLine[1].includes("Filter Id")) && nextLine[1] !== "") {
256
316
  break;
257
317
  }
258
- if (nextLine[0] === "removed" || nextLine[0] === "added" || endTablePos === 0) {
318
+ if ((nextLine[0] === "removed" || nextLine[0] === "added" || endTablePos === 0) && nextLine[1] !== "") {
259
319
  tableFilteredLines.push(nextLine);
260
320
  }
261
321
  endTablePos++;
262
322
  }
263
- compareMdLines.push(styledLine);
264
- const mixedLinesStartingFromEndOfTable = mixedLines.slice(endTablePos);
265
- const newMixedLines = [...tableFilteredLines, ...mixedLinesStartingFromEndOfTable];
266
- // Continue processing next lines
267
- buildFinalCompareMarkdown(newMixedLines, compareMdLines, isMermaid, true);
323
+ if (tableFilteredLines.length < 2) {
324
+ // Empty table
325
+ const mixedLinesStartingFromEndOfTable = mixedLines.slice(endTablePos);
326
+ buildFinalCompareMarkdown(mixedLinesStartingFromEndOfTable, compareMdLines, isMermaid, false, linkLines);
327
+ }
328
+ else {
329
+ compareMdLines.push(styledLine);
330
+ const mixedLinesStartingFromEndOfTable = mixedLines.slice(endTablePos);
331
+ const newMixedLines = [...tableFilteredLines, ...[["unchanged", ""]], ...mixedLinesStartingFromEndOfTable];
332
+ // Continue processing next lines
333
+ buildFinalCompareMarkdown(newMixedLines, compareMdLines, isMermaid, true, linkLines);
334
+ }
268
335
  return;
269
336
  }
270
337
  // Tables lines
271
338
  if (!isMermaid && status === "removed" && styledLine.startsWith("|") && !styledLine.startsWith("|:-")) {
272
- styledLine = "|🟥" + styledLine.split("|").filter(e => e !== "").map((col) => `<span style="background-color: red;"><i>${col}</i></span>`).join("|") + "|";
339
+ styledLine = "|🟥" + styledLine.split("|").filter(e => e !== "").map((col) => `<span style="background-color: #ff7f7f;"><i>${col}</i></span>`).join("|") + "|";
273
340
  }
274
341
  else if (!isMermaid && status === "added" && styledLine.startsWith("|") && !styledLine.startsWith("|:-")) {
275
- styledLine = "|🟩" + styledLine.split("|").filter(e => e !== "").map((col) => `<span style="background-color: green;"><b>${col}</b></span>`).join("|") + "|";
342
+ styledLine = "|🟩" + styledLine.split("|").filter(e => e !== "").map((col) => `<span style="background-color: #a6e22e;"><b>${col}</b></span>`).join("|") + "|";
343
+ }
344
+ // Normal lines header 3
345
+ else if (!isMermaid && status === "removed" && styledLine.startsWith("#### ")) {
346
+ styledLine = `#### 🟥${styledLine.replace("#### ", "")}`;
347
+ }
348
+ else if (!isMermaid && status === "added" && styledLine.startsWith("#### ")) {
349
+ styledLine = `#### 🟩${styledLine.replace("#### ", "")}`;
276
350
  }
277
351
  // Normal lines header 2
278
- else if (!isMermaid && status === "removed" && styledLine.startsWith("###")) {
352
+ else if (!isMermaid && status === "removed" && styledLine.startsWith("### ")) {
279
353
  styledLine = `### 🟥${styledLine.replace("### ", "")}`;
280
354
  }
281
- else if (!isMermaid && status === "added" && styledLine.startsWith("###")) {
355
+ else if (!isMermaid && status === "added" && styledLine.startsWith("### ")) {
282
356
  styledLine = `### 🟩${styledLine.replace("### ", "")}`;
283
357
  }
284
358
  // Normal lines header 3
285
- else if (!isMermaid && status === "removed" && styledLine.startsWith("##")) {
359
+ else if (!isMermaid && status === "removed" && styledLine.startsWith("## ")) {
286
360
  styledLine = `## 🟥${styledLine.replace("## ", "")}`;
287
361
  }
288
- else if (!isMermaid && status === "added" && styledLine.startsWith("##")) {
362
+ else if (!isMermaid && status === "added" && styledLine.startsWith("## ")) {
289
363
  styledLine = `## 🟩${styledLine.replace("## ", "")}`;
290
364
  }
291
365
  // Normal lines
292
- else if (!isMermaid && status === "removed" && styledLine !== "" && !styledLine.startsWith("|:-")) {
293
- styledLine = `<span style="background-color: red;"><i>🟥${styledLine}</i></span>`;
366
+ else if (!isMermaid && status === "removed" && styledLine !== "" && !styledLine.startsWith("|:-") && !styledLine.startsWith("___")) {
367
+ styledLine = `<span style="background-color: #ff7f7f;"><i>🟥${styledLine}</i></span>`;
294
368
  }
295
- else if (!isMermaid && status === "added" && styledLine !== "" && !styledLine.startsWith("|:-")) {
296
- styledLine = `<span style="background-color: green;"><b>🟩${styledLine}</b></span>`;
369
+ else if (!isMermaid && status === "added" && styledLine !== "" && !styledLine.startsWith("|:-") && !styledLine.startsWith("___")) {
370
+ styledLine = `<span style="background-color: #a6e22e;"><b>🟩${styledLine}</b></span>`;
297
371
  }
298
372
  // Boxes lines
299
373
  else if (isMermaid === true && status === "removed" && currentLine.split(":::").length === 2) {
300
374
  styledLine = styledLine + "Removed";
301
375
  if (styledLine.split('"').length === 3) {
302
376
  const splits = styledLine.split('"');
303
- styledLine = splits[0] + '"🟥<i>' + splits[1] + '</i>"' + splits[2];
377
+ styledLine = splits[0] + '"<i>' + splits[1] + '</i>"' + splits[2];
304
378
  }
305
379
  }
306
380
  else if (isMermaid === true && status === "added" && currentLine.split(":::").length === 2) {
307
381
  styledLine = styledLine + "Added";
308
382
  if (styledLine.split('"').length === 3) {
309
383
  const splits = styledLine.split('"');
310
- styledLine = splits[0] + '"🟩<b>' + splits[1] + '</b>"' + splits[2];
384
+ styledLine = splits[0] + '"<b>' + splits[1] + '</b>"' + splits[2];
311
385
  }
312
386
  }
313
387
  else if (isMermaid === true && currentLine.includes(":::")) {
@@ -315,58 +389,73 @@ function buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, isTabl
315
389
  const splits = currentLine.split(/[[({]/);
316
390
  if (splits.length > 1) {
317
391
  const boxName = splits[0];
318
- const changed = mixedLines.filter(([lineStatus, line]) => { return line.startsWith(`click ${boxName}`) && ["added", "changed"].includes(lineStatus); }).length;
392
+ const changed = mixedLines.filter(([lineStatus, line]) => { return line.startsWith(`click ${boxName}`) && ["added", "removed"].includes(lineStatus); }).length;
319
393
  if (changed > 0) {
320
394
  styledLine = styledLine + "Changed";
321
395
  if (styledLine.split('"').length === 3) {
322
396
  const splits = styledLine.split('"');
323
- styledLine = splits[0] + '"🟧<b>' + splits[1] + '</b>"' + splits[2];
397
+ styledLine = splits[0] + '"<b>' + splits[1] + '</b>"' + splits[2];
398
+ }
399
+ // Remove "removed" line from mixedLines
400
+ const removedNodePos = mixedLines.findIndex(([lineStatus, line]) => { return line.startsWith(`click ${boxName}`) && lineStatus === "removed"; });
401
+ if (removedNodePos !== -1) {
402
+ mixedLines.splice(removedNodePos, 1);
324
403
  }
325
404
  }
326
405
  }
327
406
  }
328
407
  // Long Link lines
329
408
  else if (isMermaid === true && status === "removed" && currentLine.includes('-. Fault .->')) {
330
- styledLine = styledLine.replace('-. Fault .->', '-. 🟥Fault .->') + ":::removedLink";
409
+ styledLine = styledLine.replace('-. Fault .->', '-. 🟥Fault .->'); //+ ":::removedLink"
410
+ linkLines.push("removed");
331
411
  }
332
412
  else if (isMermaid === true && status === "added" && currentLine.includes('-. Fault .->')) {
333
- styledLine = styledLine.replace('-. Fault .->', '-. 🟩Fault .->') + ":::addedLink";
413
+ styledLine = styledLine.replace('-. Fault .->', '-. 🟩Fault .->'); // + ":::addedLink"
414
+ linkLines.push("added");
334
415
  }
335
416
  /* jscpd:ignore-start */
336
417
  // Long Link lines
337
418
  else if (isMermaid === true && status === "removed" && currentLine.includes('--->')) {
338
- styledLine = styledLine.replace("--->", "--.->") + ":::removedLink";
419
+ styledLine = styledLine.replace("--->", "--.->"); //+ ":::removedLink"
420
+ linkLines.push("removed");
339
421
  if (styledLine.split("|").length === 3) {
340
422
  const splits = styledLine.split("|");
341
- styledLine = splits[0] + "|🟥<i>" + splits[1] + "</i>|" + splits[2];
423
+ styledLine = splits[0] + '|"🟥<i>' + removeQuotes(splits[1]) + '</i>"|' + splits[2];
342
424
  }
343
425
  }
344
426
  else if (isMermaid === true && status === "added" && currentLine.includes('--->')) {
345
- styledLine = styledLine.replace("--->", "===>") + ":::addedLink";
427
+ styledLine = styledLine.replace("--->", "===>"); // + ":::addedLink"
428
+ linkLines.push("added");
346
429
  if (styledLine.split("|").length === 3) {
347
430
  const splits = styledLine.split("|");
348
- styledLine = splits[0] + "|🟩<b>" + splits[1] + "</b>|" + splits[2];
431
+ styledLine = splits[0] + '|"🟩<b>' + removeQuotes(splits[1]) + '</b>"|' + splits[2];
349
432
  }
350
433
  }
351
434
  // Link lines
352
435
  else if (isMermaid === true && status === "removed" && currentLine.includes('-->')) {
353
- styledLine = styledLine.replace("-->", "-.->") + ":::removedLink";
436
+ styledLine = styledLine.replace("-->", "-.->"); // + ":::removedLink"
437
+ linkLines.push("removed");
354
438
  if (styledLine.split("|").length === 3) {
355
439
  const splits = styledLine.split("|");
356
- styledLine = splits[0] + "|🟥<i>" + splits[1] + "</i>|" + splits[2];
440
+ styledLine = splits[0] + '|"🟥<i>' + removeQuotes(splits[1]) + '</i>"|' + splits[2];
357
441
  }
358
442
  }
359
443
  else if (isMermaid === true && status === "added" && currentLine.includes('-->')) {
360
- styledLine = styledLine.replace("-->", "==>") + ":::addedLink";
444
+ styledLine = styledLine.replace("-->", "==>"); // + ":::addedLink"
445
+ linkLines.push("added");
361
446
  if (styledLine.split("|").length === 3) {
362
447
  const splits = styledLine.split("|");
363
- styledLine = splits[0] + "|🟩<b>" + splits[1] + "</b>|" + splits[2];
448
+ styledLine = splits[0] + '|"🟩<b>' + removeQuotes(splits[1]) + '</b>"|' + splits[2];
364
449
  }
365
450
  }
451
+ else if (isMermaid === true && !["added", "removed"].includes(status) &&
452
+ (currentLine.includes('-->') || currentLine.includes('-. Fault .->'))) {
453
+ linkLines.push("unchanged");
454
+ }
366
455
  /* jscpd:ignore-end */
367
456
  compareMdLines.push(styledLine);
368
457
  // Continue processing next lines
369
- buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, (styledLine.startsWith("|") && isTableStarted));
458
+ buildFinalCompareMarkdown(mixedLines, compareMdLines, isMermaid, (styledLine.startsWith("|") && isTableStarted), linkLines);
370
459
  }
371
460
  async function buildMermaidMarkdown(commit, flowFile) {
372
461
  const flowXml = await git().show([`${commit}:${flowFile}`]);
@@ -378,4 +467,101 @@ async function buildMermaidMarkdown(commit, flowFile) {
378
467
  throw new SfError(`Unable to build Graph for flow ${flowFile}: ${err.message}`);
379
468
  }
380
469
  }
470
+ function removeQuotes(str) {
471
+ if (str.startsWith('"')) {
472
+ str = str.slice(1);
473
+ }
474
+ if (str.endsWith('"')) {
475
+ str = str.slice(0, -1);
476
+ }
477
+ return str;
478
+ }
479
+ export async function generateHistoryDiffMarkdown(flowFile, debugMode) {
480
+ await fs.ensureDir(path.join("docs", "flows"));
481
+ const diffMdFile = path.join("docs", "flows", path.basename(flowFile).replace(".flow-meta.xml", "-history.md"));
482
+ // Compute for all states
483
+ const fileHistory = await git().log({ file: flowFile });
484
+ const flowLabel = path.basename(flowFile, ".flow-meta.xml");
485
+ uxLog(this, c.cyan(`Generating ${flowLabel} markdown diff between ${fileHistory.all.length} Flow states...`));
486
+ const diffMdFiles = [];
487
+ for (let i = 0; i < fileHistory.all.length; i++) {
488
+ const commitAfter = fileHistory.all[i];
489
+ // Initial state
490
+ if (i === fileHistory.all.length - 1) {
491
+ const flowXml = await git().show([`${fileHistory.all[i].hash}:${flowFile}`]);
492
+ const reportDir = await getReportDirectory();
493
+ await fs.ensureDir(path.join(reportDir, "flow-diff"));
494
+ const diffMdFileTmp = path.join(reportDir, 'flow-diff', `${flowLabel}_${moment().format("YYYYMMDD-hhmmss")}.md`);
495
+ const genRes = await generateFlowMarkdownFile(flowFile, flowXml, diffMdFileTmp, { collapsedDetails: false });
496
+ if (!genRes) {
497
+ throw new Error(`Error generating markdown file for flow ${flowFile}`);
498
+ }
499
+ diffMdFiles.push({
500
+ initialVersion: true,
501
+ commitAfter: commitAfter,
502
+ markdown: fs.readFileSync(diffMdFileTmp, "utf8")
503
+ });
504
+ }
505
+ else {
506
+ const commitBefore = fileHistory.all[i + 1];
507
+ const genDiffRes = await generateFlowVisualGitDiff(flowFile, commitBefore.hash, commitAfter.hash, { svgMd: false, mermaidMd: true, debug: debugMode });
508
+ if (genDiffRes.hasFlowDiffs && fs.existsSync(genDiffRes.outputDiffMdFile)) {
509
+ diffMdFiles.push({
510
+ commitBefore: commitBefore,
511
+ commitAfter: commitAfter,
512
+ markdown: fs.readFileSync(genDiffRes.outputDiffMdFile, "utf8")
513
+ });
514
+ }
515
+ else {
516
+ uxLog(this, c.yellow(`No real flow diff has been found between ${commitBefore.hash} and ${commitAfter.hash}`));
517
+ }
518
+ }
519
+ }
520
+ // Set all the results in a single tabbed markdown
521
+ uxLog(this, c.cyan(`Aggregating results in summary tabbed file ${diffMdFile}...`));
522
+ let finalMd = `# ${flowLabel} history\n\n`;
523
+ for (const diffMdFile of diffMdFiles) {
524
+ finalMd += `=== "${moment(diffMdFile.commitAfter.date).format("ll")}` + (diffMdFile.initialVersion ? " (Initial)" : "") + `"\n\n`;
525
+ finalMd += ` _${moment(diffMdFile.commitAfter.date).format("ll")}, by ${diffMdFile.commitAfter.author_name} in commit ${diffMdFile.commitAfter.message}_\n\n`;
526
+ // Remove title and add indentation for tabs to be displayed
527
+ finalMd += diffMdFile.markdown.split("\n").filter(line => !line.startsWith("# ")).map(line => ` ${line}`).join("\n");
528
+ finalMd += "\n\n";
529
+ }
530
+ await fs.writeFile(diffMdFile, finalMd);
531
+ if (debugMode) {
532
+ await fs.copyFile(diffMdFile, diffMdFile.replace(".md", ".mermaid.md"));
533
+ }
534
+ const genSvgRes = await generateMarkdownFileWithMermaid(diffMdFile);
535
+ if (!genSvgRes) {
536
+ throw new Error("Error generating mermaid markdown file");
537
+ }
538
+ // Fix indentation for mermaid SVG links
539
+ const diffMarkdown = await fs.readFile(diffMdFile, "utf8");
540
+ const diffMarkdownFixed = diffMarkdown.split("\n").map(line => {
541
+ if (line.startsWith("![diagram]")) {
542
+ return ` ${line}`;
543
+ }
544
+ return line;
545
+ }).join("\n");
546
+ await fs.writeFile(diffMdFile, diffMarkdownFixed);
547
+ // Add link to main flow doc
548
+ const mainFlowDoc = path.join("docs", "flows", path.basename(flowFile).replace(".flow-meta.xml", ".md"));
549
+ if (fs.existsSync(mainFlowDoc)) {
550
+ const mainFlowDocContent = await fs.readFile(mainFlowDoc, "utf8");
551
+ const mainFlowDocLink = `[_View History_](${path.basename(flowFile).replace(".flow-meta.xml", "-history.md")})`;
552
+ if (!mainFlowDocContent.includes(mainFlowDocLink)) {
553
+ let replaced = false;
554
+ const updatedFlowDocContent = mainFlowDocContent.split("\n").map(line => {
555
+ if (line.startsWith("![") && replaced === false) {
556
+ replaced = true;
557
+ return `${line}\n\n ${mainFlowDocLink}\n`;
558
+ }
559
+ return line;
560
+ }).join("\n");
561
+ await fs.writeFile(mainFlowDoc, updatedFlowDocContent);
562
+ }
563
+ }
564
+ uxLog(this, c.green(`Markdown diff between ${fileHistory.all.length} Flow states generated in ${diffMdFile}`));
565
+ return diffMdFile;
566
+ }
381
567
  //# sourceMappingURL=mermaidUtils.js.map