sfdx-hardis 5.24.3 → 5.25.1

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 (50) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/commands/hardis/doc/packagexml2markdown.js +2 -2
  3. package/lib/commands/hardis/doc/packagexml2markdown.js.map +1 -1
  4. package/lib/commands/hardis/doc/project2markdown.d.ts +2 -8
  5. package/lib/commands/hardis/doc/project2markdown.js +69 -206
  6. package/lib/commands/hardis/doc/project2markdown.js.map +1 -1
  7. package/lib/common/aiProvider/promptTemplates.d.ts +7 -1
  8. package/lib/common/aiProvider/promptTemplates.js +30 -0
  9. package/lib/common/aiProvider/promptTemplates.js.map +1 -1
  10. package/lib/common/aiProvider/utils.d.ts +0 -1
  11. package/lib/common/aiProvider/utils.js +1 -41
  12. package/lib/common/aiProvider/utils.js.map +1 -1
  13. package/lib/common/docBuilder/docBuilderApex.d.ts +8 -0
  14. package/lib/common/docBuilder/docBuilderApex.js +28 -0
  15. package/lib/common/docBuilder/docBuilderApex.js.map +1 -0
  16. package/lib/common/docBuilder/docBuilderFlow.d.ts +10 -0
  17. package/lib/common/docBuilder/docBuilderFlow.js +43 -0
  18. package/lib/common/docBuilder/docBuilderFlow.js.map +1 -0
  19. package/lib/common/docBuilder/docBuilderObject.d.ts +13 -0
  20. package/lib/common/docBuilder/docBuilderObject.js +116 -0
  21. package/lib/common/docBuilder/docBuilderObject.js.map +1 -0
  22. package/lib/common/docBuilder/docBuilderPackageXml.d.ts +8 -0
  23. package/lib/common/docBuilder/docBuilderPackageXml.js +136 -0
  24. package/lib/common/docBuilder/docBuilderPackageXml.js.map +1 -0
  25. package/lib/common/docBuilder/docBuilderPage.d.ts +10 -0
  26. package/lib/common/docBuilder/docBuilderPage.js +40 -0
  27. package/lib/common/docBuilder/docBuilderPage.js.map +1 -0
  28. package/lib/common/docBuilder/docBuilderProfile.d.ts +11 -0
  29. package/lib/common/docBuilder/docBuilderProfile.js +86 -0
  30. package/lib/common/docBuilder/docBuilderProfile.js.map +1 -0
  31. package/lib/common/docBuilder/docBuilderRoot.d.ts +18 -0
  32. package/lib/common/docBuilder/docBuilderRoot.js +79 -0
  33. package/lib/common/docBuilder/docBuilderRoot.js.map +1 -0
  34. package/lib/common/docBuilder/docUtils.d.ts +0 -4
  35. package/lib/common/docBuilder/docUtils.js +0 -206
  36. package/lib/common/docBuilder/docUtils.js.map +1 -1
  37. package/lib/common/gitProvider/azureDevops.js +3 -0
  38. package/lib/common/gitProvider/azureDevops.js.map +1 -1
  39. package/lib/common/gitProvider/bitbucket.js +3 -0
  40. package/lib/common/gitProvider/bitbucket.js.map +1 -1
  41. package/lib/common/gitProvider/github.d.ts +4 -0
  42. package/lib/common/gitProvider/github.js +31 -31
  43. package/lib/common/gitProvider/github.js.map +1 -1
  44. package/lib/common/gitProvider/gitlab.js +3 -0
  45. package/lib/common/gitProvider/gitlab.js.map +1 -1
  46. package/lib/common/utils/mermaidUtils.js +6 -29
  47. package/lib/common/utils/mermaidUtils.js.map +1 -1
  48. package/oclif.lock +33 -33
  49. package/oclif.manifest.json +513 -513
  50. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image `hardisgroupcom/sfdx-hardis@beta`
6
6
 
7
+ ## [5.25.1] 2025-04-08
8
+
9
+ - [hardis:doc:project2markdown](https://sfdx-hardis.cloudity.com/hardis/doc/project2markdown/): Fix typo for Object description prompt
10
+
11
+ ## [5.25.0] 2025-04-06
12
+
13
+ - [hardis:doc:project2markdown](https://sfdx-hardis.cloudity.com/hardis/doc/project2markdown/): Add profile documentation generated by AI
14
+ - Refactor document generation code
15
+ - GitHub Integration: Use ENV variables as fallback [in case the job runner is not GitHub Actions](https://sfdx-hardis.cloudity.com/salesforce-ci-cd-setup-integration-github/#using-github-integration-without-github-actions), like Codefresh
16
+
7
17
  ## [5.24.3] 2025-04-04
8
18
 
9
19
  - Fix visualization of [Azure DevOps](https://sfdx-hardis.cloudity.com/salesforce-ci-cd-setup-integration-azure/#azure-pull-request-notes) images by linking attachments to a generic work item.
@@ -2,7 +2,7 @@
2
2
  import { SfCommand, Flags, optionalOrgFlagWithDeprecations } from '@salesforce/sf-plugins-core';
3
3
  import { Messages } from '@salesforce/core';
4
4
  import { WebSocketClient } from '../../../common/websocketClient.js';
5
- import { generatePackageXmlMarkdown } from '../../../common/docBuilder/docUtils.js';
5
+ import { DocBuilderPackageXML } from '../../../common/docBuilder/docBuilderPackageXml.js';
6
6
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
7
  const messages = Messages.loadMessages('sfdx-hardis', 'org');
8
8
  export default class PackageXml2Markdown extends SfCommand {
@@ -47,7 +47,7 @@ export default class PackageXml2Markdown extends SfCommand {
47
47
  this.debugMode = flags.debug || false;
48
48
  // Generate markdown for package.xml
49
49
  const instanceUrl = flags?.['target-org']?.getConnection()?.instanceUrl;
50
- this.outputFile = await generatePackageXmlMarkdown(this.inputFile, this.outputFile, null, instanceUrl);
50
+ this.outputFile = await DocBuilderPackageXML.generatePackageXmlMarkdown(this.inputFile, this.outputFile, null, instanceUrl);
51
51
  // Open file in a new VsCode tab if available
52
52
  WebSocketClient.requestOpenFile(this.outputFile);
53
53
  // Return an object to be displayed with --json
@@ -1 +1 @@
1
- {"version":3,"file":"packagexml2markdown.js","sourceRoot":"","sources":["../../../../src/commands/hardis/doc/packagexml2markdown.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AAEpF,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AAE7D,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,SAAc;IACtD,MAAM,CAAC,KAAK,GAAG,wBAAwB,CAAC;IAExC,MAAM,CAAC,WAAW,GAAG,4DAA4D,CAAC;IAElF,MAAM,CAAC,QAAQ,GAAG;QACvB,qCAAqC;QACrC,0EAA0E;KAC3E,CAAC;IAEK,MAAM,CAAC,KAAK,GAAQ;QACzB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,sFAAsF;SACpG,CAAC;QACF,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,kEAAkE;SAChF,CAAC;QACF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,GAAG;YACT,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;SAC9C,CAAC;QACF,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;YACtB,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;SAC9C,CAAC;QACF,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;YACtB,WAAW,EAAE,+DAA+D;SAC7E,CAAC;QACF,YAAY,EAAE,+BAA+B;KAC9C,CAAC;IAEF,uGAAuG;IAChG,MAAM,CAAC,eAAe,GAAG,KAAK,CAAC;IAE5B,SAAS,CAAC;IACV,UAAU,CAAC;IACX,SAAS,GAAG,KAAK,CAAC;IAC5B,sBAAsB;IAEf,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACxD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC;QAC3C,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;QAEtC,oCAAoC;QACpC,MAAM,WAAW,GAAG,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,aAAa,EAAE,EAAE,WAAW,CAAC;QACxE,IAAI,CAAC,UAAU,GAAG,MAAM,0BAA0B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAEvG,6CAA6C;QAC7C,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEjD,+CAA+C;QAC/C,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IACzC,CAAC"}
1
+ {"version":3,"file":"packagexml2markdown.js","sourceRoot":"","sources":["../../../../src/commands/hardis/doc/packagexml2markdown.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oDAAoD,CAAC;AAE1F,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AAE7D,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,SAAc;IACtD,MAAM,CAAC,KAAK,GAAG,wBAAwB,CAAC;IAExC,MAAM,CAAC,WAAW,GAAG,4DAA4D,CAAC;IAElF,MAAM,CAAC,QAAQ,GAAG;QACvB,qCAAqC;QACrC,0EAA0E;KAC3E,CAAC;IAEK,MAAM,CAAC,KAAK,GAAQ;QACzB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,sFAAsF;SACpG,CAAC;QACF,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,kEAAkE;SAChF,CAAC;QACF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,GAAG;YACT,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;SAC9C,CAAC;QACF,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;YACtB,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;SAC9C,CAAC;QACF,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;YACtB,WAAW,EAAE,+DAA+D;SAC7E,CAAC;QACF,YAAY,EAAE,+BAA+B;KAC9C,CAAC;IAEF,uGAAuG;IAChG,MAAM,CAAC,eAAe,GAAG,KAAK,CAAC;IAE5B,SAAS,CAAC;IACV,UAAU,CAAC;IACX,SAAS,GAAG,KAAK,CAAC;IAC5B,sBAAsB;IAEf,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACxD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;QACzC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC;QAC3C,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;QAEtC,oCAAoC;QACpC,MAAM,WAAW,GAAG,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,aAAa,EAAE,EAAE,WAAW,CAAC;QACxE,IAAI,CAAC,UAAU,GAAG,MAAM,oBAAoB,CAAC,0BAA0B,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAE5H,6CAA6C;QAC7C,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEjD,+CAA+C;QAC/C,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IACzC,CAAC"}
@@ -22,6 +22,7 @@ export default class Project2Markdown extends SfCommand<any> {
22
22
  protected apexDescriptions: any[];
23
23
  protected flowDescriptions: any[];
24
24
  protected pageDescriptions: any[];
25
+ protected profileDescriptions: any[];
25
26
  protected objectDescriptions: any[];
26
27
  protected objectFiles: string[];
27
28
  protected allObjectsNames: string[];
@@ -29,24 +30,17 @@ export default class Project2Markdown extends SfCommand<any> {
29
30
  run(): Promise<AnyJson>;
30
31
  private generateApexDocumentation;
31
32
  private generatePagesDocumentation;
33
+ private generateAuthorizationsDocumentation;
32
34
  private buildMkDocsYml;
33
35
  private generateObjectsDocumentation;
34
36
  private buildAttributesTables;
35
37
  private generateLinksInfo;
36
38
  private generateFlowsDocumentation;
37
39
  private humanDisplay;
38
- private buildFlowsTable;
39
- private buildObjectsTable;
40
- private buildApexTable;
41
- private buildPagesTable;
42
- private buildCustomFieldsTable;
43
- private buildValidationRulesTable;
44
40
  private buildInstalledPackages;
45
41
  private buildSfdxHardisParams;
46
42
  private buildMajorBranchesAndOrgs;
47
43
  private manageLocalPackages;
48
- private buildPackagesIndex;
49
44
  private addNavNode;
50
45
  private generatePackageXmlMarkdown;
51
- private listPackageXmlCandidates;
52
46
  }
@@ -8,8 +8,8 @@ import { XMLParser } from "fast-xml-parser";
8
8
  import sortArray from 'sort-array';
9
9
  import { Messages } from '@salesforce/core';
10
10
  import { WebSocketClient } from '../../../common/websocketClient.js';
11
- import { completeApexDocWithAiDescription, completeAttributesDescriptionWithAi, generateLightningPageMarkdown, generateObjectMarkdown, generatePackageXmlMarkdown, getMetaHideLines, readMkDocsFile, replaceInFile, writeMkDocsFile } from '../../../common/docBuilder/docUtils.js';
12
- import { countPackageXmlItems, parseXmlFile } from '../../../common/utils/xmlUtils.js';
11
+ import { completeAttributesDescriptionWithAi, getMetaHideLines, readMkDocsFile, replaceInFile, writeMkDocsFile } from '../../../common/docBuilder/docUtils.js';
12
+ import { parseXmlFile } from '../../../common/utils/xmlUtils.js';
13
13
  import { bool2emoji, createTempDir, execCommand, execSfdxJson, getCurrentGitBranch, uxLog } from '../../../common/utils/index.js';
14
14
  import { CONSTANTS, getConfig } from '../../../config/index.js';
15
15
  import { listMajorOrgs } from '../../../common/utils/orgConfigUtils.js';
@@ -19,10 +19,15 @@ import { generateFlowMarkdownFile, generateHistoryDiffMarkdown, generateMarkdown
19
19
  import { MetadataUtils } from '../../../common/metadata-utils/index.js';
20
20
  import { PACKAGE_ROOT_DIR } from '../../../settings.js';
21
21
  import { BranchStrategyMermaidBuilder } from '../../../common/utils/branchStrategyMermaidBuilder.js';
22
- import { mdTableCell } from '../../../common/gitProvider/utilsMarkdown.js';
23
22
  import { prettifyFieldName } from '../../../common/utils/flowVisualiser/nodeFormatUtils.js';
24
23
  import { ObjectModelBuilder } from '../../../common/docBuilder/objectModelBuilder.js';
25
24
  import { generatePdfFileFromMarkdown } from '../../../common/utils/markdownUtils.js';
25
+ import { DocBuilderPage } from '../../../common/docBuilder/docBuilderPage.js';
26
+ import { DocBuilderProfile } from '../../../common/docBuilder/docBuilderProfile.js';
27
+ import { DocBuilderObject } from '../../../common/docBuilder/docBuilderObject.js';
28
+ import { DocBuilderApex } from '../../../common/docBuilder/docBuilderApex.js';
29
+ import { DocBuilderFlow } from '../../../common/docBuilder/docBuilderFlow.js';
30
+ import { DocBuilderPackageXML } from '../../../common/docBuilder/docBuilderPackageXml.js';
26
31
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
27
32
  const messages = Messages.loadMessages('sfdx-hardis', 'org');
28
33
  export default class Project2Markdown extends SfCommand {
@@ -139,6 +144,7 @@ ${this.htmlInstructions}
139
144
  apexDescriptions = [];
140
145
  flowDescriptions = [];
141
146
  pageDescriptions = [];
147
+ profileDescriptions = [];
142
148
  objectDescriptions = [];
143
149
  objectFiles;
144
150
  allObjectsNames;
@@ -161,6 +167,7 @@ ${this.htmlInstructions}
161
167
  "- [Objects](objects/index.md)",
162
168
  "- [Flows](flows/index.md)",
163
169
  "- [Apex](apex/index.md)",
170
+ "- [Profiles](profiles/index.md)",
164
171
  "- [Lightning Pages](pages/index.md)",
165
172
  "- [SFDX-Hardis Config](sfdx-hardis-params.md)",
166
173
  "- [Branches & Orgs](sfdx-hardis-branches-and-orgs.md)",
@@ -189,11 +196,12 @@ ${this.htmlInstructions}
189
196
  this.addNavNode("Object Model", "object-model.md");
190
197
  */
191
198
  // List SFDX packages and generate a manifest for each of them, except if there is only force-app with a package.xml
192
- this.packageXmlCandidates = this.listPackageXmlCandidates();
199
+ this.packageXmlCandidates = DocBuilderPackageXML.listPackageXmlCandidates();
193
200
  await this.manageLocalPackages();
194
201
  const instanceUrl = flags?.['target-org']?.getConnection()?.instanceUrl;
195
202
  await this.generatePackageXmlMarkdown(this.packageXmlCandidates, instanceUrl);
196
- const packageLines = await this.buildPackagesIndex();
203
+ const { packageLines, packagesForMenu } = await DocBuilderPackageXML.buildIndexTable(this.outputPackageXmlMarkdownFiles);
204
+ this.addNavNode("Manifests", packagesForMenu);
197
205
  await fs.writeFile(path.join(this.outputMarkdownRoot, "manifests.md"), getMetaHideLines() + packageLines.join("\n") + `\n${this.footer}\n`);
198
206
  // List managed packages
199
207
  const installedPackages = await this.buildInstalledPackages();
@@ -212,14 +220,18 @@ ${this.htmlInstructions}
212
220
  if (!(process?.env?.GENERATE_FLOW_DOC === 'false')) {
213
221
  await this.generateFlowsDocumentation();
214
222
  }
215
- // List flows & generate doc
223
+ // List pages & generate doc
216
224
  if (!(process?.env?.GENERATE_PAGES_DOC === 'false')) {
217
225
  await this.generatePagesDocumentation();
218
226
  }
219
- // List flows & generate doc
227
+ // List objects & generate doc
220
228
  if (!(process?.env?.GENERATE_OBJECTS_DOC === 'false')) {
221
229
  await this.generateObjectsDocumentation();
222
230
  }
231
+ // List profiles & generate doc
232
+ if (!(process?.env?.GENERATE_PROFILES_DOC === 'false')) {
233
+ await this.generateAuthorizationsDocumentation();
234
+ }
223
235
  // Write output index file
224
236
  await fs.ensureDir(path.dirname(this.outputMarkdownIndexFile));
225
237
  await fs.writeFile(this.outputMarkdownIndexFile, getMetaHideLines() + this.mdLines.join("\n") + `\n\n${this.footer}\n`);
@@ -296,10 +308,15 @@ ${Project2Markdown.htmlInstructions}
296
308
  apexMdContent = apexMdContent.replaceAll("..\\custom-objects\\", "../objects/").replaceAll("../custom-objects/", "../objects/");
297
309
  // Add text before the first ##
298
310
  if (!["MetadataService"].includes(apexName)) {
299
- const insertion = `## AI-Generated description\n\n<!-- Apex description -->\n\n## Apex Code\n\n\`\`\`java\n${apexContent}\n\`\`\`\n\n`;
311
+ const insertion = `<!-- Apex description -->\n\n## Apex Code\n\n\`\`\`java\n${apexContent}\n\`\`\`\n\n`;
300
312
  const firstHeading = apexMdContent.indexOf("## ");
301
313
  apexMdContent = apexMdContent.substring(0, firstHeading) + insertion + apexMdContent.substring(firstHeading);
302
- apexMdContent = await completeApexDocWithAiDescription(apexMdContent, apexName, apexContent);
314
+ const apexDocBuilder = new DocBuilderApex(apexName, apexContent, "", {
315
+ "CLASS_NAME": apexName,
316
+ "APEX_CODE": apexContent
317
+ });
318
+ apexDocBuilder.markdownDoc = apexMdContent;
319
+ apexMdContent = await apexDocBuilder.completeDocWithAiDescription();
303
320
  await fs.writeFile(mdFile, getMetaHideLines() + apexMdContent);
304
321
  }
305
322
  uxLog(this, c.grey(`Generated markdown for Apex class ${apexName}`));
@@ -312,7 +329,7 @@ ${Project2Markdown.htmlInstructions}
312
329
  // Write index file for apex folder
313
330
  await fs.ensureDir(path.join(this.outputMarkdownRoot, "apex"));
314
331
  const apexIndexFile = path.join(this.outputMarkdownRoot, "apex", "index.md");
315
- await fs.writeFile(apexIndexFile, getMetaHideLines() + this.buildApexTable('').join("\n") + `\n\n${this.footer}\n`);
332
+ await fs.writeFile(apexIndexFile, getMetaHideLines() + DocBuilderApex.buildIndexTable('', this.apexDescriptions).join("\n") + `\n\n${this.footer}\n`);
316
333
  }
317
334
  async generatePagesDocumentation() {
318
335
  const packageDirs = this.project?.getPackageDirectories() || [];
@@ -330,7 +347,7 @@ ${Project2Markdown.htmlInstructions}
330
347
  type: prettifyFieldName(pageXmlParsed?.FlexiPage?.type || "Unknown"),
331
348
  impactedObjects: this.allObjectsNames.filter(objectName => pageXml.includes(`${objectName}`)).join(", ")
332
349
  });
333
- await generateLightningPageMarkdown(pageName, pageXml, mdFile);
350
+ await new DocBuilderPage(pageName, pageXml, mdFile).generateMarkdownFileFromXml();
334
351
  if (this.withPdf) {
335
352
  await generatePdfFileFromMarkdown(mdFile);
336
353
  }
@@ -339,7 +356,34 @@ ${Project2Markdown.htmlInstructions}
339
356
  // Write index file for apex folder
340
357
  await fs.ensureDir(path.join(this.outputMarkdownRoot, "pages"));
341
358
  const pagesIndexFile = path.join(this.outputMarkdownRoot, "pages", "index.md");
342
- await fs.writeFile(pagesIndexFile, getMetaHideLines() + this.buildPagesTable('').join("\n") + `\n\n${this.footer}\n`);
359
+ await fs.writeFile(pagesIndexFile, getMetaHideLines() + DocBuilderPage.buildIndexTable('', this.pageDescriptions).join("\n") + `\n\n${this.footer}\n`);
360
+ }
361
+ async generateAuthorizationsDocumentation() {
362
+ uxLog(this, c.cyan("Generating Authorizations documentation... (if you don't want it, define GENERATE_PROFILES_DOC=false in your environment variables)"));
363
+ const profilesForMenu = { "All Profiles": "profiles/index.md" };
364
+ const profilesFiles = (await glob("**/profiles/**.profile-meta.xml", { cwd: process.cwd(), ignore: GLOB_IGNORE_PATTERNS })).sort();
365
+ for (const profileFile of profilesFiles) {
366
+ const profileName = path.basename(profileFile, ".profile-meta.xml");
367
+ const mdFile = path.join(this.outputMarkdownRoot, "profiles", profileName + ".md");
368
+ profilesForMenu[profileName] = "profiles/" + profileName + ".md";
369
+ const profileXml = await fs.readFile(profileFile, "utf8");
370
+ const profileXmlParsed = new XMLParser().parse(profileXml);
371
+ this.profileDescriptions.push({
372
+ name: profileName,
373
+ userLicense: prettifyFieldName(profileXmlParsed?.Profile?.userLicense || "Unknown"),
374
+ impactedObjects: this.allObjectsNames.filter(objectName => profileXml.includes(`${objectName}`)).join(", ")
375
+ });
376
+ // Add apex code in documentation
377
+ await new DocBuilderProfile(profileName, profileXml, mdFile).generateMarkdownFileFromXml();
378
+ if (this.withPdf) {
379
+ await generatePdfFileFromMarkdown(mdFile);
380
+ }
381
+ }
382
+ this.addNavNode("Profiles", profilesForMenu);
383
+ // Write index file for profiles folder
384
+ await fs.ensureDir(path.join(this.outputMarkdownRoot, "profiles"));
385
+ const profilesIndexFile = path.join(this.outputMarkdownRoot, "profiles", "index.md");
386
+ await fs.writeFile(profilesIndexFile, getMetaHideLines() + DocBuilderProfile.buildIndexTable('', this.profileDescriptions).join("\n") + `\n\n${this.footer}\n`);
343
387
  }
344
388
  async buildMkDocsYml() {
345
389
  // Copy default files (mkdocs.yml and other files can be updated by the SF Cli plugin developer later)
@@ -388,7 +432,7 @@ ${Project2Markdown.htmlInstructions}
388
432
  // Remove deprecated Flows History if found
389
433
  mkdocsYml.nav = mkdocsYml.nav.filter(navItem => !navItem["Flows History"]);
390
434
  // Order nav items with this elements in first
391
- const firstItemsInOrder = ["Home", "Object Model", "Objects", "Flows", "Apex", "Lightning Pages", "SFDX-Hardis Config", "Branches & Orgs", "Installed Packages", "Manifests"];
435
+ const firstItemsInOrder = ["Home", "Object Model", "Objects", "Flows", "Apex", "Profiles", "Lightning Pages", "SFDX-Hardis Config", "Branches & Orgs", "Installed Packages", "Manifests"];
392
436
  mkdocsYml.nav = firstItemsInOrder.map(item => mkdocsYml.nav.find(navItem => Object.keys(navItem)[0] === item)).filter(item => item).concat(mkdocsYml.nav.filter(navItem => !firstItemsInOrder.includes(Object.keys(navItem)[0])));
393
437
  // Update mkdocs file
394
438
  await writeMkDocsFile(mkdocsYmlFile, mkdocsYml);
@@ -411,7 +455,10 @@ ${Project2Markdown.htmlInstructions}
411
455
  // Build filtered XML
412
456
  const objectXmlParsed = new XMLParser().parse(objectXml);
413
457
  // Main AI markdown
414
- await generateObjectMarkdown(objectName, objectXml, this.allObjectsNames.join(","), objectLinksInfo, objectMdFile);
458
+ await new DocBuilderObject(objectName, objectXml, objectMdFile, {
459
+ "ALL_OBJECTS_LIST": this.allObjectsNames.join(","),
460
+ "ALL_OBJECT_LINKS": objectLinksInfo
461
+ }).generateMarkdownFileFromXml();
415
462
  // Fields table
416
463
  await this.buildAttributesTables(objectName, objectXmlParsed, objectMdFile);
417
464
  // Mermaid schema
@@ -422,11 +469,11 @@ ${Project2Markdown.htmlInstructions}
422
469
  await generateMarkdownFileWithMermaid(objectMdFile, objectMdFile, null, true);
423
470
  }
424
471
  // Flows Tables
425
- const relatedObjectFlowsTable = await this.buildFlowsTable('../flows/', objectName);
472
+ const relatedObjectFlowsTable = DocBuilderFlow.buildIndexTable('../flows/', this.flowDescriptions, this.outputMarkdownRoot, objectName);
426
473
  await replaceInFile(objectMdFile, '<!-- Flows table -->', relatedObjectFlowsTable.join("\n"));
427
- const relatedApexTable = this.buildApexTable('../apex/', objectName);
474
+ const relatedApexTable = DocBuilderApex.buildIndexTable('../apex/', this.apexDescriptions, objectName);
428
475
  await replaceInFile(objectMdFile, '<!-- Apex table -->', relatedApexTable.join("\n"));
429
- const relatedPages = this.buildPagesTable('../pages/', objectName);
476
+ const relatedPages = DocBuilderPage.buildIndexTable('../pages/', this.pageDescriptions, objectName);
430
477
  await replaceInFile(objectMdFile, '<!-- Pages table -->', relatedPages.join("\n"));
431
478
  this.objectDescriptions.push({
432
479
  name: objectName,
@@ -441,13 +488,13 @@ ${Project2Markdown.htmlInstructions}
441
488
  this.addNavNode("Objects", objectsForMenu);
442
489
  // Write index file for objects folder
443
490
  await fs.ensureDir(path.join(this.outputMarkdownRoot, "objects"));
444
- const objectsTableLinesForIndex = await this.buildObjectsTable('');
491
+ const objectsTableLinesForIndex = DocBuilderObject.buildIndexTable('', this.objectDescriptions);
445
492
  const objectsIndexFile = path.join(this.outputMarkdownRoot, "objects", "index.md");
446
493
  await fs.writeFile(objectsIndexFile, getMetaHideLines() + objectsTableLinesForIndex.join("\n") + `\n${this.footer}\n`);
447
494
  }
448
495
  async buildAttributesTables(objectName, objectXmlParsed, objectMdFile) {
449
- const fieldsTable = await this.buildCustomFieldsTable(objectXmlParsed?.CustomObject?.fields || []);
450
- const validationRulesTable = await this.buildValidationRulesTable(objectXmlParsed?.CustomObject?.validationRules || []);
496
+ const fieldsTable = DocBuilderObject.buildCustomFieldsTable(objectXmlParsed?.CustomObject?.fields || []);
497
+ const validationRulesTable = DocBuilderObject.buildValidationRulesTable(objectXmlParsed?.CustomObject?.validationRules || []);
451
498
  const attributesLines = [...fieldsTable, ...validationRulesTable];
452
499
  const attributesMarkdown = await completeAttributesDescriptionWithAi(attributesLines.join("\n"), objectName);
453
500
  await replaceInFile(objectMdFile, '<!-- Attributes tables -->', attributesMarkdown);
@@ -555,7 +602,7 @@ ${Project2Markdown.htmlInstructions}
555
602
  }
556
603
  // Write index file for flow folder
557
604
  await fs.ensureDir(path.join(this.outputMarkdownRoot, "flows"));
558
- const flowTableLinesForIndex = await this.buildFlowsTable('');
605
+ const flowTableLinesForIndex = DocBuilderFlow.buildIndexTable('', this.flowDescriptions, this.outputMarkdownRoot);
559
606
  const flowIndexFile = path.join(this.outputMarkdownRoot, "flows", "index.md");
560
607
  await fs.writeFile(flowIndexFile, getMetaHideLines() + flowTableLinesForIndex.join("\n") + `\n${this.footer}\n`);
561
608
  this.addNavNode("Flows", flowsForMenu);
@@ -564,133 +611,6 @@ ${Project2Markdown.htmlInstructions}
564
611
  humanDisplay(flows) {
565
612
  return flows.map(flow => path.basename(flow, ".flow-meta.xml")).join(", ");
566
613
  }
567
- async buildFlowsTable(prefix, filterObject = null) {
568
- const filteredFlows = filterObject ? this.flowDescriptions.filter(flow => flow.object === filterObject || flow.impactedObjects.includes(filterObject)) : this.flowDescriptions;
569
- if (filteredFlows.length === 0) {
570
- return [];
571
- }
572
- const lines = [];
573
- lines.push(...[
574
- filterObject ? "## Related Flows" : "## Flows",
575
- "",
576
- "| Object | Name | Type | Description |",
577
- "| :---- | :-------- | :--: | :---------- | "
578
- ]);
579
- for (const flow of filteredFlows) {
580
- const outputFlowHistoryMdFile = path.join(this.outputMarkdownRoot, "flows", flow.name + "-history.md");
581
- const flowNameCell = fs.existsSync(outputFlowHistoryMdFile) ?
582
- `[${flow.name}](${prefix}${flow.name}.md) [🕒](${prefix}${flow.name}-history.md)` :
583
- `[${flow.name}](${prefix}${flow.name}.md)`;
584
- lines.push(...[
585
- `| ${flow.object || "💻"} | ${flowNameCell} | ${prettifyFieldName(flow.type)} | ${mdTableCell(flow.description)} |`
586
- ]);
587
- }
588
- lines.push("");
589
- return lines;
590
- }
591
- async buildObjectsTable(prefix) {
592
- const lines = [];
593
- lines.push(...[
594
- "## Objects",
595
- "",
596
- "| Name | Label | Description |",
597
- "| :-------- | :---- | :---------- | "
598
- ]);
599
- for (const objectDescription of this.objectDescriptions) {
600
- const objectNameCell = `[${objectDescription.name}](${prefix}${objectDescription.name}.md)`;
601
- lines.push(...[
602
- `| ${objectNameCell} | ${objectDescription.label || ""} | ${mdTableCell(objectDescription.description)} |`
603
- ]);
604
- }
605
- lines.push("");
606
- return lines;
607
- }
608
- buildApexTable(prefix, filterObject = null) {
609
- const filteredApex = filterObject ? this.apexDescriptions.filter(apex => apex.impactedObjects.includes(filterObject)) : this.apexDescriptions;
610
- if (filteredApex.length === 0) {
611
- return [];
612
- }
613
- const lines = [];
614
- lines.push(...[
615
- filterObject ? "## Related Apex Classes" : "## Apex Classes",
616
- "",
617
- "| Apex Class | Type |",
618
- "| :---- | :--: | "
619
- ]);
620
- for (const apex of filteredApex) {
621
- const flowNameCell = `[${apex.name}](${prefix}${apex.name}.md)`;
622
- lines.push(...[
623
- `| ${flowNameCell} | ${apex.type} |`
624
- ]);
625
- }
626
- lines.push("");
627
- return lines;
628
- }
629
- buildPagesTable(prefix, filterObject = null) {
630
- const filteredPages = filterObject ? this.pageDescriptions.filter(page => page.impactedObjects.includes(filterObject)) : this.pageDescriptions;
631
- if (filteredPages.length === 0) {
632
- return [];
633
- }
634
- const lines = [];
635
- lines.push(...[
636
- filterObject ? "## Related Lightning Pages" : "## Lightning Pages",
637
- "",
638
- "| Lightning Page | Type |",
639
- "| :---- | :--: | "
640
- ]);
641
- for (const page of filteredPages) {
642
- const pageNameCell = `[${page.name}](${prefix}${page.name}.md)`;
643
- lines.push(...[
644
- `| ${pageNameCell} | ${page.type} |`
645
- ]);
646
- }
647
- lines.push("");
648
- return lines;
649
- }
650
- async buildCustomFieldsTable(fields) {
651
- if (!Array.isArray(fields)) {
652
- fields = [fields];
653
- }
654
- if (fields.length === 0) {
655
- return [];
656
- }
657
- const lines = [];
658
- lines.push(...[
659
- "## Fields",
660
- "",
661
- "| Name | Label | Type | Description |",
662
- "| :-------- | :---- | :--: | :---------- | "
663
- ]);
664
- for (const field of fields) {
665
- lines.push(...[
666
- `| ${field.fullName} | ${field.label || ""} | ${field.type || ""} | ${mdTableCell(field.description)} |`
667
- ]);
668
- }
669
- lines.push("");
670
- return lines;
671
- }
672
- async buildValidationRulesTable(validationRules) {
673
- if (!Array.isArray(validationRules)) {
674
- validationRules = [validationRules];
675
- }
676
- if (validationRules.length === 0) {
677
- return [];
678
- }
679
- const lines = [];
680
- lines.push(...[
681
- "## Validation Rules",
682
- "",
683
- "| Rule | Active | Description | Formula |",
684
- "| :-------- | :---- | :---------- | :------ |"
685
- ]);
686
- for (const rule of validationRules) {
687
- lines.push(...[
688
- `| ${rule.fullName} | ${rule.active ? "Yes" : "No ⚠️"} | ${rule.description || ""} | \`${rule.errorConditionFormula}\` |`
689
- ]);
690
- }
691
- lines.push("");
692
- return lines;
693
- }
694
614
  async buildInstalledPackages() {
695
615
  // CI/CD context
696
616
  const packages = this.sfdxHardisConfig.installedPackages || [];
@@ -802,29 +722,6 @@ ${Project2Markdown.htmlInstructions}
802
722
  }
803
723
  }
804
724
  }
805
- async buildPackagesIndex() {
806
- const packageLines = [];
807
- const packagesForMenu = { "All manifests": "manifests.md" };
808
- packageLines.push(...[
809
- "## Package XML files",
810
- "",
811
- "| Package name | Description |",
812
- "| :----------- | :---------- |"
813
- ]);
814
- for (const outputPackageXmlDef of this.outputPackageXmlMarkdownFiles) {
815
- const metadataNb = await countPackageXmlItems(outputPackageXmlDef.path);
816
- const packageMdFile = path.basename(outputPackageXmlDef.path) + ".md";
817
- const label = outputPackageXmlDef.name ? `Package folder: ${outputPackageXmlDef.name}` : path.basename(outputPackageXmlDef.path);
818
- const packageTableLine = `| [${label}](${packageMdFile}) (${metadataNb}) | ${outputPackageXmlDef.description} |`;
819
- packageLines.push(packageTableLine);
820
- packagesForMenu[label] = packageMdFile;
821
- }
822
- packageLines.push("");
823
- packageLines.push("___");
824
- packageLines.push("");
825
- this.addNavNode("Manifests", packagesForMenu);
826
- return packageLines;
827
- }
828
725
  addNavNode(nodeName, nodeValue) {
829
726
  const nodeIndex = this.mkDocsNavNodes.findIndex(navNode => Object.keys(navNode)[0] === nodeName);
830
727
  if (nodeIndex > -1) {
@@ -841,7 +738,7 @@ ${Project2Markdown.htmlInstructions}
841
738
  for (const packageXmlCandidate of packageXmlCandidates) {
842
739
  if (fs.existsSync(packageXmlCandidate.path)) {
843
740
  // Generate markdown for package.xml
844
- const packageMarkdownFile = await generatePackageXmlMarkdown(packageXmlCandidate.path, null, packageXmlCandidate, instanceUrl);
741
+ const packageMarkdownFile = await DocBuilderPackageXML.generatePackageXmlMarkdown(packageXmlCandidate.path, null, packageXmlCandidate, instanceUrl);
845
742
  // Open file in a new VsCode tab if available
846
743
  WebSocketClient.requestOpenFile(packageMarkdownFile);
847
744
  packageXmlCandidate.markdownFile = packageMarkdownFile;
@@ -849,39 +746,5 @@ ${Project2Markdown.htmlInstructions}
849
746
  }
850
747
  }
851
748
  }
852
- listPackageXmlCandidates() {
853
- return [
854
- // CI/CD package files
855
- {
856
- path: "manifest/package.xml",
857
- description: "Contains all deployable metadatas of the SFDX project"
858
- },
859
- {
860
- path: "manifest/packageDeployOnce.xml",
861
- description: "Contains all metadatas that will never be overwritten during deployment if they are already existing in the target org"
862
- },
863
- {
864
- path: "manifest/package-no-overwrite.xml",
865
- description: "Contains all metadatas that will never be overwritten during deployment if they are already existing in the target org"
866
- },
867
- {
868
- path: "manifest/destructiveChanges.xml",
869
- description: "Contains all metadatas that will be deleted during deployment, in case they are existing in the target org"
870
- },
871
- // Monitoring package files
872
- {
873
- path: "manifest/package-all-org-items.xml",
874
- description: "Contains the entire list of metadatas that are present in the monitored org (not all of them are in the git backup)"
875
- },
876
- {
877
- path: "manifest/package-backup-items.xml",
878
- description: "Contains the list of metadatas that are in the git backup"
879
- },
880
- {
881
- path: "manifest/package-skip-items.xml",
882
- description: "Contains the list of metadatas that are excluded from the backup.<br/>Other metadata types might be skipped using environment variable MONITORING_BACKUP_SKIP_METADATA_TYPES"
883
- },
884
- ];
885
- }
886
749
  }
887
750
  //# sourceMappingURL=project2markdown.js.map