UNPKG

sfdx-hardis

Version:

Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards

123 lines 5.1 kB
/* jscpd:ignore-start */ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; import fs from 'fs-extra'; import { glob } from 'glob'; import sortArray from 'sort-array'; import { catchMatches, generateReports, uxLog } from '../../../../common/utils/index.js'; import { GLOB_IGNORE_PATTERNS } from '../../../../common/utils/projectUtils.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('sfdx-hardis', 'org'); export default class CallInCallOut extends SfCommand { static title = 'Audit CallIns and CallOuts'; static description = messages.getMessage('auditCallInCallOut'); static examples = ['$ sf hardis:project:audit:callouts']; // public static args = [{name: 'file'}]; static flags = { // flag with a value (-n, --name=VALUE) debug: Flags.boolean({ char: 'd', default: false, description: messages.getMessage('debugMode'), }), websocket: Flags.string({ description: messages.getMessage('websocket'), }), skipauth: Flags.boolean({ description: 'Skip authentication check when a default username is required', }), }; // Set this to true if your command requires a project workspace; 'requiresProject' is false by default static requiresProject = true; /* jscpd:ignore-end */ matchResults = []; async run() { const pattern = '**/*.{cls,trigger}'; const catchers = [ { type: 'INBOUND', subType: 'SOAP', regex: /webservice static/gim, detail: [{ name: 'webServiceName', regex: /webservice static (.*?){/gims }], }, { type: 'INBOUND', subType: 'REST', regex: /@RestResource/gim, detail: [{ name: 'restResource', regex: /@RestResource\((.*?)\)/gims }], }, { type: 'OUTBOUND', subType: 'HTTP', regex: /new HttpRequest/gim, detail: [ { name: 'endPoint', regex: /setEndpoint\((.*?);/gims }, { name: 'action', regex: /<soapenv:Body><[A-Za-z0-9_-]*:(.*?)>/gims }, ], }, ]; const apexFiles = await glob(pattern, { ignore: GLOB_IGNORE_PATTERNS }); this.matchResults = []; uxLog(this, `Browsing ${apexFiles.length} files`); // Loop in files for (const file of apexFiles) { const fileText = await fs.readFile(file, 'utf8'); if (fileText.startsWith('hidden') || fileText.includes('@isTest')) { continue; } // Loop on criteria to find matches in this file for (const catcher of catchers) { const catcherMatchResults = await catchMatches(catcher, file, fileText, this); this.matchResults.push(...catcherMatchResults); } } // Format result const result = this.matchResults.map((item) => { return { type: item.type, subType: item.subType, fileName: item.fileName, nameSpace: item.fileName.includes('__') ? item.fileName.split('__')[0] : 'Custom', matches: item.matches, detail: Object.keys(item.detail) .map((key) => key + ': ' + item.detail[key] .map((extractedText) => extractedText .replace(/(\r\n|\n|\r)/gm, '') // Remove new lines from result .replace(/\s+/g, ' ') // Replace multiple whitespaces by single whitespaces ) .join(' | ')) .join(' || ') || '', }; }); // Sort array const resultSorted = sortArray(result, { by: ['type', 'subType', 'fileName', 'matches'], order: ['asc', 'asc', 'asc', 'desc'], }); // Display as table const resultsLight = JSON.parse(JSON.stringify(resultSorted)); console.table(resultsLight.map((item) => { delete item.detail; return item; })); // Generate output files const columns = [ { key: 'type', header: 'IN/OUT' }, { key: 'subType', header: 'Protocol' }, { key: 'fileName', header: 'Apex' }, { key: 'nameSpace', header: 'Namespace' }, { key: 'matches', header: 'Number' }, { key: 'detail', header: 'Detail' }, ]; const reportFiles = await generateReports(resultSorted, columns, this); // Return an object to be displayed with --json return { outputString: 'Processed callIns and callOuts audit', result: resultSorted, reportFiles, }; } } //# sourceMappingURL=callincallout.js.map