UNPKG

powerplatform-review-tool

Version:

Evaluate Power Platform solution zip files based on best practice patterns

144 lines (143 loc) 8.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.reviewPowerAutomateComponents = reviewPowerAutomateComponents; const powerautomatePatterns_1 = require("./powerautomatePatterns"); const ManifestConstant_1 = require("../ManifestConstant"); // eslint-disable-next-line sonarjs/cognitive-complexity async function reviewPowerAutomateComponents(zipContent, patternDetails) { const workflowsFolder = zipContent.folder("Workflows"); const powerAutomateResults = []; const flowPatternCount = Object.keys(ManifestConstant_1.FlowPatternInfo).length; const errorSummary = []; let totalScore = 0; if (!workflowsFolder) { console.error("No Workflows folder found in the solution."); return { items: [], totalFlows: 0, totalScore: "0%" }; } const processingPromises = []; workflowsFolder.forEach((relativePath, file) => { if (relativePath.endsWith(".json")) { processingPromises.push(file .async("string") .then((jsonContent) => { const parsedJson = JSON.parse(jsonContent); const powerAutomateName = relativePath.split("/").pop()?.replace(".json", ""); // We collect all results in patternResults const patternResults = []; let flowScore = 0; // Prepare to track which patternIDs have been processed, so we don't double-process them. // Track processed pattern IDs const processedPatternIDs = new Set(); // List of all patterns to check const patternsToCheck = [ { fn: powerautomatePatterns_1.patternCheckDataRetrievalParameters, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.DataRetrievalParameters].patternName, }, { fn: powerautomatePatterns_1.patternCheckScopeUsage, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.ScopeUsage].patternName, }, { fn: powerautomatePatterns_1.patternCheckNestedLoops, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.NestedLoops].patternName, }, { fn: powerautomatePatterns_1.patternCheckConcurrencySettings, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.Concurrency].patternName, }, { fn: powerautomatePatterns_1.patternCheckConsistentNaming, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.NamingConventions].patternName, }, { fn: powerautomatePatterns_1.patternCheckTriggerCondition, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.TriggerCondition].patternName, }, { fn: powerautomatePatterns_1.patternCheckPowerAppResponse, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.PowerAppResponse].patternName, }, { fn: powerautomatePatterns_1.patternCheckStaticVariables, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.StaticVariables].patternName, }, { fn: powerautomatePatterns_1.patternCheckMultipleInitializeVariable, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.MultipleInitializeVariableActions].patternName, }, { fn: powerautomatePatterns_1.patternCheckUnusedVariables, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.UnusedVariables].patternName, }, { fn: powerautomatePatterns_1.patternOptimizeActionCounts, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.ActionCount].patternName, }, { fn: powerautomatePatterns_1.patternCheckForActionNote, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.ActionNote].patternName, }, { fn: powerautomatePatterns_1.patternCheckCreateUpdateInsideLoop, name: ManifestConstant_1.FlowPatternDetails[ManifestConstant_1.FlowPatternInfo.CreateUpdateInsideLoop].patternName, }, ]; // Execute each pattern check in a try/catch block for (const patternDefinition of patternsToCheck) { const { fn, name } = patternDefinition; try { const result = fn(parsedJson); if (patternDetails && patternDetails.length > 0 && !processedPatternIDs.has(result.patternID)) { // Merge extra pattern details from patternDetails if it matches the same patternID const matchingPatternDetail = patternDetails.find((detail) => detail.data.patternID === result.patternID); if (matchingPatternDetail) { const data = matchingPatternDetail.data; result.patternName = data.patternName || result.patternName; result.description = data.description || result.description; result.docLinks = data.docLinks || result.docLinks; result.recommendation = data.recommendation || result.recommendation; result.severity = data.severity || result.severity; result.category = data.category || result.category; } } patternResults.push(result); processedPatternIDs.add(result.patternID); if (result.status === "Pass" /* ManifestPropertyStatusNames.Pass */) { flowScore += 1; } if (result.status === "Warning" /* ManifestPropertyStatusNames.Warning */) { flowScore += 0.5; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); errorSummary.push({ pattern: name, error: errorMessage }); } } totalScore += flowScore; powerAutomateResults.push({ name: powerAutomateName, displayName: powerAutomateName?.split(/-[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}/)[0], result: patternResults, score: flowScore > 0 ? Math.round((flowScore / flowPatternCount) * 100) + "%" : "0%", }); }) .catch((error) => { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Failed to process file ${relativePath}:`, errorMessage); errorSummary.push({ file: relativePath, error: errorMessage }); })); } }); console.log(errorSummary); await Promise.all(processingPromises); // Return the final results return { items: powerAutomateResults, totalFlows: powerAutomateResults.length, totalScore: powerAutomateResults.length > 0 ? Math.round((totalScore / (powerAutomateResults.length * flowPatternCount)) * 100).toString() + "%" : "0%", }; }