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

188 lines • 8.41 kB
import c from 'chalk'; import fs from 'fs-extra'; import * as path from 'path'; import { execCommand, sortCrossPlatform, uxLog } from './index.js'; import { glob } from 'glob'; import { parseXmlFile } from './xmlUtils.js'; import { getApiVersion } from '../../config/index.js'; export const GLOB_IGNORE_PATTERNS = [ '**/node_modules/**', '**/.git/**', '**/cache/**', '**/.npm/**', '**/logs/**', '**/.sfdx/**', '**/.sf/**', '**/.vscode/**', ]; export function isSfdxProject(cwd = process.cwd()) { return fs.existsSync(path.join(cwd, 'sfdx-project.json')); } export async function createBlankSfdxProject(cwd = process.cwd(), debug = false) { uxLog(this, c.cyan('Creating blank SFDX project...')); const projectCreateCommand = 'sf project generate --name "sfdx-hardis-blank-project"'; await execCommand(projectCreateCommand, this, { cwd: cwd, fail: true, debug: debug, output: true, }); return path.join(cwd, "sfdx-hardis-blank-project"); } export async function listFlowFiles(packageDirs) { const flowFiles = []; const skippedFlows = []; for (const packageDir of packageDirs || []) { const flowMetadatas = await glob("**/*.flow-meta.xml", { cwd: packageDir.path, ignore: GLOB_IGNORE_PATTERNS }); for (const flowMetadata of flowMetadatas) { const flowFile = path.join(packageDir.path, flowMetadata).replace(/\\/g, '/'); if (await isManagedFlow(flowFile)) { skippedFlows.push(flowFile); } else { flowFiles.push(flowFile); } } } if (skippedFlows.length > 0) { uxLog(this, c.yellow(`Skipped ${skippedFlows.length} managed flows:`)); for (const skippedFlow of sortCrossPlatform(skippedFlows)) { uxLog(this, c.yellow(` ${skippedFlow}`)); } } return sortCrossPlatform(flowFiles); } export async function isManagedFlow(flowFile) { const flowXml = await parseXmlFile(flowFile); for (const flowNodeType of [ 'start', 'actionCalls', 'assignments', 'customErrors', 'collectionProcessors', 'decisions', 'loops', 'recordCreates', 'recordDeletes', 'recordLookups', 'recordUpdates', 'transforms', 'screens', 'subflows', 'variables', 'constants', 'formulas' ]) { if (flowXml?.Flow?.[flowNodeType] && flowXml?.Flow?.[flowNodeType]?.length > 0) { return false; } } return true; } export async function listApexFiles(packageDirs) { const apexFiles = []; const skippedApex = []; for (const packageDir of packageDirs || []) { const apexMetadatas = await glob("**/*.{cls,trigger}", { cwd: packageDir.path, ignore: GLOB_IGNORE_PATTERNS }); for (const apexMetadata of apexMetadatas) { const apexFile = path.join(packageDir.path, apexMetadata).replace(/\\/g, '/'); if (apexFile.includes('__')) { skippedApex.push(apexFile); } else { apexFiles.push(apexFile); } } } if (skippedApex.length > 0) { uxLog(this, c.yellow(`Skipped ${skippedApex.length} managed Apex:`)); for (const skippedApexItem of sortCrossPlatform(skippedApex)) { uxLog(this, c.yellow(` ${skippedApexItem}`)); } } return apexFiles.sort(); } export async function listPageFiles(packageDirs) { const pageFiles = []; const skippedPages = []; for (const packageDir of packageDirs || []) { const pageMetadatas = await glob("**/*.flexipage-meta.xml", { cwd: packageDir.path, ignore: GLOB_IGNORE_PATTERNS }); for (const pageMetadata of pageMetadatas) { const pageFile = path.join(packageDir.path, pageMetadata).replace(/\\/g, '/'); if (pageFile.includes('__')) { skippedPages.push(pageFile); } else { pageFiles.push(pageFile); } } } if (skippedPages.length > 0) { uxLog(this, c.yellow(`Skipped ${skippedPages.length} managed Lightning Pages:`)); for (const skippedPage of sortCrossPlatform(skippedPages)) { uxLog(this, c.yellow(` ${skippedPage}`)); } } return pageFiles.sort(); } export function returnApexType(apexCode) { const apexContentlower = apexCode.toLowerCase(); return apexContentlower.includes("@istest(seealldata=true)") ? "Test (See All Data)" : apexContentlower.includes("@istest") ? "Test" : apexContentlower.includes("@invocablemethod") ? "Invocable" : apexContentlower.includes("@restresource") ? "REST" : apexContentlower.includes("implements database.batchable") ? "Batch" : apexContentlower.includes("implements batchable") ? "Batch" : apexContentlower.includes("implements database.schedulable") ? "Schedulable" : apexContentlower.includes("implements schedulable") ? "Schedulable" : apexContentlower.includes("@auraenabled") ? "Lightning Controller" : apexContentlower.includes("apexpages.standardcontroller") ? "Visualforce Controller" : apexContentlower.includes("pagereference") ? "Visualforce Controller" : apexContentlower.includes("triggerhandler") ? "Trigger Handler" : apexContentlower.includes("new httprequest") ? "Callout" : apexContentlower.includes("jsonparser parser") ? "JSON" : apexContentlower.includes("public class soaprequest") ? "SOAP" : "Class"; } // Update only if found API version is inferior to the candidate API version (convert to number) export async function updateSfdxProjectApiVersion() { const candidateApiVersion = getApiVersion(); // Handle sfdx-project.json file const sfdxProjectFile = path.join(process.cwd(), 'sfdx-project.json'); if (await fs.pathExists(sfdxProjectFile)) { const sfdxProject = await fs.readJson(sfdxProjectFile); if (sfdxProject?.sourceApiVersion) { const currentApiVersionStr = sfdxProject.sourceApiVersion; const currentApiVersion = parseFloat(currentApiVersionStr); if (currentApiVersion < parseFloat(candidateApiVersion)) { sfdxProject.sourceApiVersion = candidateApiVersion; await fs.writeJson(sfdxProjectFile, sfdxProject, { spaces: 2 }); uxLog(this, c.cyan(`Updated API version in sfdx-project.json from ${currentApiVersionStr} to ${candidateApiVersion}`)); } } } // Handle all .xml files found in manifest folder const manifestDir = path.join(process.cwd(), 'manifest'); if (fs.existsSync(manifestDir)) { const manifestFiles = await glob('**/*.xml', { cwd: manifestDir }); for (const manifestFile of manifestFiles) { const fullPath = path.join(manifestDir, manifestFile); if (fs.existsSync(fullPath)) { const xmlContent = await fs.readFile(fullPath, 'utf-8'); if (xmlContent.includes('version')) { const regex = /<version>(\d+\.\d+)<\/version>/; const match = xmlContent.match(regex); if (match && match[1]) { const currentApiVersion = parseFloat(match[1]); if (currentApiVersion < parseFloat(candidateApiVersion)) { const updatedXmlContent = xmlContent.replace(regex, `<version>${candidateApiVersion}</version>`); await fs.writeFile(fullPath, updatedXmlContent, 'utf-8'); uxLog(this, c.cyan(`Updated API version in ${manifestFile} from ${match[1]} to ${candidateApiVersion}`)); } } } } } } } //# sourceMappingURL=projectUtils.js.map