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.
- package/CHANGELOG.md +10 -0
- package/lib/commands/hardis/doc/packagexml2markdown.js +2 -2
- package/lib/commands/hardis/doc/packagexml2markdown.js.map +1 -1
- package/lib/commands/hardis/doc/project2markdown.d.ts +2 -8
- package/lib/commands/hardis/doc/project2markdown.js +69 -206
- package/lib/commands/hardis/doc/project2markdown.js.map +1 -1
- package/lib/common/aiProvider/promptTemplates.d.ts +7 -1
- package/lib/common/aiProvider/promptTemplates.js +30 -0
- package/lib/common/aiProvider/promptTemplates.js.map +1 -1
- package/lib/common/aiProvider/utils.d.ts +0 -1
- package/lib/common/aiProvider/utils.js +1 -41
- package/lib/common/aiProvider/utils.js.map +1 -1
- package/lib/common/docBuilder/docBuilderApex.d.ts +8 -0
- package/lib/common/docBuilder/docBuilderApex.js +28 -0
- package/lib/common/docBuilder/docBuilderApex.js.map +1 -0
- package/lib/common/docBuilder/docBuilderFlow.d.ts +10 -0
- package/lib/common/docBuilder/docBuilderFlow.js +43 -0
- package/lib/common/docBuilder/docBuilderFlow.js.map +1 -0
- package/lib/common/docBuilder/docBuilderObject.d.ts +13 -0
- package/lib/common/docBuilder/docBuilderObject.js +116 -0
- package/lib/common/docBuilder/docBuilderObject.js.map +1 -0
- package/lib/common/docBuilder/docBuilderPackageXml.d.ts +8 -0
- package/lib/common/docBuilder/docBuilderPackageXml.js +136 -0
- package/lib/common/docBuilder/docBuilderPackageXml.js.map +1 -0
- package/lib/common/docBuilder/docBuilderPage.d.ts +10 -0
- package/lib/common/docBuilder/docBuilderPage.js +40 -0
- package/lib/common/docBuilder/docBuilderPage.js.map +1 -0
- package/lib/common/docBuilder/docBuilderProfile.d.ts +11 -0
- package/lib/common/docBuilder/docBuilderProfile.js +86 -0
- package/lib/common/docBuilder/docBuilderProfile.js.map +1 -0
- package/lib/common/docBuilder/docBuilderRoot.d.ts +18 -0
- package/lib/common/docBuilder/docBuilderRoot.js +79 -0
- package/lib/common/docBuilder/docBuilderRoot.js.map +1 -0
- package/lib/common/docBuilder/docUtils.d.ts +0 -4
- package/lib/common/docBuilder/docUtils.js +0 -206
- package/lib/common/docBuilder/docUtils.js.map +1 -1
- package/lib/common/gitProvider/azureDevops.js +3 -0
- package/lib/common/gitProvider/azureDevops.js.map +1 -1
- package/lib/common/gitProvider/bitbucket.js +3 -0
- package/lib/common/gitProvider/bitbucket.js.map +1 -1
- package/lib/common/gitProvider/github.d.ts +4 -0
- package/lib/common/gitProvider/github.js +31 -31
- package/lib/common/gitProvider/github.js.map +1 -1
- package/lib/common/gitProvider/gitlab.js +3 -0
- package/lib/common/gitProvider/gitlab.js.map +1 -1
- package/lib/common/utils/mermaidUtils.js +6 -29
- package/lib/common/utils/mermaidUtils.js.map +1 -1
- package/oclif.lock +33 -33
- package/oclif.manifest.json +513 -513
- 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 {
|
|
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,
|
|
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 {
|
|
12
|
-
import {
|
|
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 =
|
|
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.
|
|
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
|
|
223
|
+
// List pages & generate doc
|
|
216
224
|
if (!(process?.env?.GENERATE_PAGES_DOC === 'false')) {
|
|
217
225
|
await this.generatePagesDocumentation();
|
|
218
226
|
}
|
|
219
|
-
// List
|
|
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 =
|
|
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
|
-
|
|
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() +
|
|
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
|
|
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() +
|
|
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
|
|
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 =
|
|
472
|
+
const relatedObjectFlowsTable = DocBuilderFlow.buildIndexTable('../flows/', this.flowDescriptions, this.outputMarkdownRoot, objectName);
|
|
426
473
|
await replaceInFile(objectMdFile, '<!-- Flows table -->', relatedObjectFlowsTable.join("\n"));
|
|
427
|
-
const relatedApexTable =
|
|
474
|
+
const relatedApexTable = DocBuilderApex.buildIndexTable('../apex/', this.apexDescriptions, objectName);
|
|
428
475
|
await replaceInFile(objectMdFile, '<!-- Apex table -->', relatedApexTable.join("\n"));
|
|
429
|
-
const relatedPages =
|
|
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 =
|
|
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 =
|
|
450
|
-
const validationRulesTable =
|
|
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 =
|
|
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
|