Power Platform QA Solution
Power Platform QA
Home
Solutions
Reports
Settings
User Guide
Back to Analyzers
Configure Analyzer —
OnStart Overload
CUSTOM
Metadata
ID
onstart-overload
Result Key
onStartOverload
File
onstart-overload.js
Built-in
No
Analyzer Classification
Category
— This determines the type of Analyzer you are building. Categories can be set up under settings.
Uncategorized
Performance
Data Operations
Variables & Scoping
Maintenance
Test sets
— Include this analyzer in predefined runs. Select one or more test sets this analyzer should belong to.
Dataverse test set
Some tests
Description
Detects overloaded OnStart handlers with too many statements, collection operations, or improper patterns
Prompt
Provider
Anthropic (Claude) — no key
OpenAI (GPT) — no key
Google (Gemini) — no key
Re-run AI builder
Check the OnStart event of the application for any of the following OnStart Overload situations and for the following: 1. when there are more than 15 statements. Severity = high 2. when there are more than more than 3 ClearCollect or Collect calls. Severity = medium or when there are more than more than 9 ClearCollect or Collect calls. Severity = high. 3. where the Concurrent function is not used despite containing ≥ 2 independent connector calls 4. where these is a Navigate function call inside the OnStart. severity = high. Suggest moving the code to to Screen.OnVisible or migrate to named formulas.
Source Code
onstart-overload.js ·
Input data reference ↗
Checking…
Save JavaScript
export default { name: "OnStart Overload", description: "Detects overloaded OnStart handlers with too many statements, collection operations, or improper patterns", resultKey: "onStartOverload", resultSchema: { keys: [ { key: "name", label: "Location", suggestedFormat: "text" }, { key: "type", label: "Issue Type", suggestedFormat: "badge-info" }, { key: "message", label: "Description", suggestedFormat: "text" }, { key: "confidence", label: "Confidence", suggestedFormat: "badge-confidence" }, { key: "locations", label: "Locations", suggestedFormat: "locations" } ] }, analyze(controlTree, refGraph, extraction) { const results = []; // Get the App node and OnStart formula const appNode = controlTree.appNode; if (!appNode || !appNode.formulas.has('OnStart')) { return results; } const onStartFormula = appNode.formulas.get('OnStart'); if (!onStartFormula || onStartFormula.trim() === '') { return results; } const location = { control: 'App', property: 'OnStart', file: appNode.filePath || 'App.pa.yaml' }; // 1. Check for too many statements (>15 = high severity) const statements = this.countStatements(onStartFormula); if (statements > 15) { results.push({ name: 'App.OnStart', type: 'too-many-statements', message: `OnStart contains ${statements} statements (>15). Consider moving logic to Screen.OnVisible or named formulas.`, confidence: 'high', locations: [location] }); } // 2. Check for too many collection operations const collectionCalls = this.countCollectionCalls(onStartFormula); if (collectionCalls > 9) { results.push({ name: 'App.OnStart', type: 'too-many-collections', message: `OnStart contains ${collectionCalls} ClearCollect/Collect calls (>9). Consider moving to Screen.OnVisible or named formulas.`, confidence: 'high', locations: [location] }); } else if (collectionCalls > 3) { results.push({ name: 'App.OnStart', type: 'many-collections', message: `OnStart contains ${collectionCalls} ClearCollect/Collect calls (>3). Consider optimizing or moving to Screen.OnVisible.`, confidence: 'medium', locations: [location] }); } // 3. Check for missing Concurrent with multiple connector calls const connectorCalls = this.findConnectorCalls(onStartFormula); const hasConcurrent = this.hasConcurrentFunction(onStartFormula); if (connectorCalls.length >= 2 && !hasConcurrent) { const independentCalls = this.areCallsIndependent(connectorCalls); if (independentCalls) { results.push({ name: 'App.OnStart', type: 'missing-concurrent', message: `OnStart has ${connectorCalls.length} independent connector calls without Concurrent function. Consider using Concurrent() for better performance.`, confidence: 'medium', locations: [location] }); } } // 4. Check for Navigate calls (high severity) if (this.hasNavigateCall(onStartFormula)) { results.push({ name: 'App.OnStart', type: 'navigate-in-onstart', message: 'OnStart contains Navigate function call. Navigation should be handled in Screen.OnVisible instead.', confidence: 'high', locations: [location] }); } return results; }, countStatements(formula) { // Count statements by looking for semicolons and line breaks // Remove comments and strings to avoid false positives const cleanFormula = this.removeCommentsAndStrings(formula); // Split by semicolons and filter out empty statements const statements = cleanFormula .split(/;|\r?\n/) .map(s => s.trim()) .filter(s => s.length > 0 && !s.match(/^\s*\/\//)); return statements.length; }, countCollectionCalls(formula) { // Remove comments and strings const cleanFormula = this.removeCommentsAndStrings(formula); // Look for ClearCollect and Collect function calls const collectionPattern = /\b(ClearCollect|Collect)\s*\(/gi; const matches = cleanFormula.match(collectionPattern) || []; return matches.length; }, findConnectorCalls(formula) { // Remove comments and strings const cleanFormula = this.removeCommentsAndStrings(formula); // Common connector functions that typically involve external calls const connectorPatterns = [ /\bOffice365Users\./gi, /\bOffice365Outlook\./gi, /\bSharePoint\./gi, /\bSQL\./gi, /\bHTTP\s*\(/gi, /\bPower(?:BI|Automate)\./gi, /\bDataverse\./gi, /\bExcel\./gi, /\bOneDrive\./gi, /\bTeams\./gi, /\bOutlook\./gi ]; const calls = []; connectorPatterns.forEach(pattern => { const matches = cleanFormula.match(pattern) || []; calls.push(...matches); }); return calls; }, hasConcurrentFunction(formula) { const cleanFormula = this.removeCommentsAndStrings(formula); return /\bConcurrent\s*\(/i.test(cleanFormula); }, areCallsIndependent(calls) { // Simple heuristic: if we have multiple different connector types, // they're likely independent const uniqueConnectors = new Set(); calls.forEach(call => { const connector = call.toLowerCase().replace(/[.\s(].*/g, ''); uniqueConnectors.add(connector); }); return uniqueConnectors.size >= 2; }, hasNavigateCall(formula) { const cleanFormula = this.removeCommentsAndStrings(formula); return /\bNavigate\s*\(/i.test(cleanFormula); }, removeCommentsAndStrings(formula) { // Remove single-line comments let cleaned = formula.replace(/\/\/.*$/gm, ''); // Remove multi-line comments cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove string literals (both single and double quotes) // This is a simplified approach - doesn't handle escaped quotes perfectly cleaned = cleaned.replace(/"[^"]*"/g, '""'); cleaned = cleaned.replace(/'[^']*'/g, "''"); return cleaned; } };
Report Output Columns
Columns shown in the generated report. Toggle off to hide; pick a declared key or use "Custom…" for dot-paths like
locations.0.file
.
+ Add column
Enabled
Key
Label
Format
Width
name
Plain text
Small text
Muted grey text
Code snippet
Number (right-aligned)
Percentage (%)
Truncate at 80 chars
Truncate at 120 chars
Info pill (blue)
Confidence pill (red/yellow/grey)
Dead-code type pill
Bold name + copy button
Locations list
×
type
Plain text
Small text
Muted grey text
Code snippet
Number (right-aligned)
Percentage (%)
Truncate at 80 chars
Truncate at 120 chars
Info pill (blue)
Confidence pill (red/yellow/grey)
Dead-code type pill
Bold name + copy button
Locations list
×
message
Plain text
Small text
Muted grey text
Code snippet
Number (right-aligned)
Percentage (%)
Truncate at 80 chars
Truncate at 120 chars
Info pill (blue)
Confidence pill (red/yellow/grey)
Dead-code type pill
Bold name + copy button
Locations list
×
confidence
Plain text
Small text
Muted grey text
Code snippet
Number (right-aligned)
Percentage (%)
Truncate at 80 chars
Truncate at 120 chars
Info pill (blue)
Confidence pill (red/yellow/grey)
Dead-code type pill
Bold name + copy button
Locations list
×
locations
Plain text
Small text
Muted grey text
Code snippet
Number (right-aligned)
Percentage (%)
Truncate at 80 chars
Truncate at 120 chars
Info pill (blue)
Confidence pill (red/yellow/grey)
Dead-code type pill
Bold name + copy button
Locations list
×
Cancel
Test analyzer
Save Columns
Running analyzer against solution…
This can take up to a minute for large solutions.
Test OnStart Overload
×
Runs this analyzer in isolation against the chosen solution. Nothing is saved — the result is shown here only.
Use an existing solution
No solutions uploaded yet
Upload a solution file
Cancel
Run test
Test results
×