@sabrish/power-platform-solution-blueprint 0.5.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.
Files changed (129) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/LICENSE +21 -0
  3. package/README.md +331 -0
  4. package/dist/assets/BusinessProcessFlowDiscovery-BSDgBoIA.js +2 -0
  5. package/dist/assets/BusinessProcessFlowDiscovery-BSDgBoIA.js.map +1 -0
  6. package/dist/assets/ColumnSecurityDiscovery-B3yVn0LZ.js +2 -0
  7. package/dist/assets/ColumnSecurityDiscovery-B3yVn0LZ.js.map +1 -0
  8. package/dist/assets/ConnectionReferenceDiscovery-DFTQuo-S.js +2 -0
  9. package/dist/assets/ConnectionReferenceDiscovery-DFTQuo-S.js.map +1 -0
  10. package/dist/assets/CustomAPIDiscovery-BiQS_ENt.js +2 -0
  11. package/dist/assets/CustomAPIDiscovery-BiQS_ENt.js.map +1 -0
  12. package/dist/assets/CustomConnectorDiscovery-TvNjElP3.js +2 -0
  13. package/dist/assets/CustomConnectorDiscovery-TvNjElP3.js.map +1 -0
  14. package/dist/assets/EnvironmentVariableDiscovery-DG_tXCcQ.js +2 -0
  15. package/dist/assets/EnvironmentVariableDiscovery-DG_tXCcQ.js.map +1 -0
  16. package/dist/assets/GlobalChoiceDiscovery-nivz9yGs.js +2 -0
  17. package/dist/assets/GlobalChoiceDiscovery-nivz9yGs.js.map +1 -0
  18. package/dist/assets/HtmlReporter-Cu9NwA6b.js +1894 -0
  19. package/dist/assets/HtmlReporter-Cu9NwA6b.js.map +1 -0
  20. package/dist/assets/JsonReporter-BqDJorX-.js +2 -0
  21. package/dist/assets/JsonReporter-BqDJorX-.js.map +1 -0
  22. package/dist/assets/MarkdownReporter-B1FEpc6-.js +53 -0
  23. package/dist/assets/MarkdownReporter-B1FEpc6-.js.map +1 -0
  24. package/dist/assets/ZipPackager-B4xx8LbF.js +3 -0
  25. package/dist/assets/ZipPackager-B4xx8LbF.js.map +1 -0
  26. package/dist/assets/_baseUniq-Nm59UrQz.js +2 -0
  27. package/dist/assets/_baseUniq-Nm59UrQz.js.map +1 -0
  28. package/dist/assets/arc-BVr5R-xB.js +2 -0
  29. package/dist/assets/arc-BVr5R-xB.js.map +1 -0
  30. package/dist/assets/architectureDiagram-VXUJARFQ-C-olLUHb.js +37 -0
  31. package/dist/assets/architectureDiagram-VXUJARFQ-C-olLUHb.js.map +1 -0
  32. package/dist/assets/blockDiagram-VD42YOAC-B4incSX8.js +123 -0
  33. package/dist/assets/blockDiagram-VD42YOAC-B4incSX8.js.map +1 -0
  34. package/dist/assets/c4Diagram-YG6GDRKO-BJxhcb17.js +11 -0
  35. package/dist/assets/c4Diagram-YG6GDRKO-BJxhcb17.js.map +1 -0
  36. package/dist/assets/channel-CjhOgOS9.js +2 -0
  37. package/dist/assets/channel-CjhOgOS9.js.map +1 -0
  38. package/dist/assets/chunk-4BX2VUAB-BIe6iK-b.js +2 -0
  39. package/dist/assets/chunk-4BX2VUAB-BIe6iK-b.js.map +1 -0
  40. package/dist/assets/chunk-55IACEB6-CA6P5Ey6.js +2 -0
  41. package/dist/assets/chunk-55IACEB6-CA6P5Ey6.js.map +1 -0
  42. package/dist/assets/chunk-B4BG7PRW-licIQLj-.js +166 -0
  43. package/dist/assets/chunk-B4BG7PRW-licIQLj-.js.map +1 -0
  44. package/dist/assets/chunk-DI55MBZ5-CxFpzZDS.js +221 -0
  45. package/dist/assets/chunk-DI55MBZ5-CxFpzZDS.js.map +1 -0
  46. package/dist/assets/chunk-FMBD7UC4-VjnBPAq9.js +16 -0
  47. package/dist/assets/chunk-FMBD7UC4-VjnBPAq9.js.map +1 -0
  48. package/dist/assets/chunk-QN33PNHL-BcMwEixv.js +2 -0
  49. package/dist/assets/chunk-QN33PNHL-BcMwEixv.js.map +1 -0
  50. package/dist/assets/chunk-QZHKN3VN-6eOG0UZ6.js +2 -0
  51. package/dist/assets/chunk-QZHKN3VN-6eOG0UZ6.js.map +1 -0
  52. package/dist/assets/chunk-TZMSLE5B-B38vDpWG.js +2 -0
  53. package/dist/assets/chunk-TZMSLE5B-B38vDpWG.js.map +1 -0
  54. package/dist/assets/classDiagram-2ON5EDUG-CEjpoRuI.js +2 -0
  55. package/dist/assets/classDiagram-2ON5EDUG-CEjpoRuI.js.map +1 -0
  56. package/dist/assets/classDiagram-v2-WZHVMYZB-CEjpoRuI.js +2 -0
  57. package/dist/assets/classDiagram-v2-WZHVMYZB-CEjpoRuI.js.map +1 -0
  58. package/dist/assets/clone-FgHYDKfb.js +2 -0
  59. package/dist/assets/clone-FgHYDKfb.js.map +1 -0
  60. package/dist/assets/cose-bilkent-S5V4N54A-BFz6nI_Q.js +2 -0
  61. package/dist/assets/cose-bilkent-S5V4N54A-BFz6nI_Q.js.map +1 -0
  62. package/dist/assets/cytoscape.esm-CyJtwmzi.js +332 -0
  63. package/dist/assets/cytoscape.esm-CyJtwmzi.js.map +1 -0
  64. package/dist/assets/dagre-6UL2VRFP-B9xCTGce.js +5 -0
  65. package/dist/assets/dagre-6UL2VRFP-B9xCTGce.js.map +1 -0
  66. package/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  67. package/dist/assets/defaultLocale-DX6XiGOO.js.map +1 -0
  68. package/dist/assets/diagram-PSM6KHXK-BG-mPBdn.js +25 -0
  69. package/dist/assets/diagram-PSM6KHXK-BG-mPBdn.js.map +1 -0
  70. package/dist/assets/diagram-QEK2KX5R-BAd41szY.js +44 -0
  71. package/dist/assets/diagram-QEK2KX5R-BAd41szY.js.map +1 -0
  72. package/dist/assets/diagram-S2PKOQOG-Qhy7nrMX.js +25 -0
  73. package/dist/assets/diagram-S2PKOQOG-Qhy7nrMX.js.map +1 -0
  74. package/dist/assets/erDiagram-Q2GNP2WA-HJD-sygr.js +61 -0
  75. package/dist/assets/erDiagram-Q2GNP2WA-HJD-sygr.js.map +1 -0
  76. package/dist/assets/flowDiagram-NV44I4VS-DcFzPV5l.js +163 -0
  77. package/dist/assets/flowDiagram-NV44I4VS-DcFzPV5l.js.map +1 -0
  78. package/dist/assets/ganttDiagram-JELNMOA3-5hzmn_YM.js +268 -0
  79. package/dist/assets/ganttDiagram-JELNMOA3-5hzmn_YM.js.map +1 -0
  80. package/dist/assets/gitGraphDiagram-NY62KEGX-BJoaRoQP.js +66 -0
  81. package/dist/assets/gitGraphDiagram-NY62KEGX-BJoaRoQP.js.map +1 -0
  82. package/dist/assets/graph-iTkoc_Qp.js +2 -0
  83. package/dist/assets/graph-iTkoc_Qp.js.map +1 -0
  84. package/dist/assets/index-C0N3Q-wf.js +404 -0
  85. package/dist/assets/index-C0N3Q-wf.js.map +1 -0
  86. package/dist/assets/index-Dau71uup.css +1 -0
  87. package/dist/assets/infoDiagram-WHAUD3N6-Dm-9Locf.js +3 -0
  88. package/dist/assets/infoDiagram-WHAUD3N6-Dm-9Locf.js.map +1 -0
  89. package/dist/assets/init-Gi6I4Gst.js +2 -0
  90. package/dist/assets/init-Gi6I4Gst.js.map +1 -0
  91. package/dist/assets/journeyDiagram-XKPGCS4Q-Cn4q49x5.js +140 -0
  92. package/dist/assets/journeyDiagram-XKPGCS4Q-Cn4q49x5.js.map +1 -0
  93. package/dist/assets/kanban-definition-3W4ZIXB7-lUx8-faE.js +90 -0
  94. package/dist/assets/kanban-definition-3W4ZIXB7-lUx8-faE.js.map +1 -0
  95. package/dist/assets/katex-CBSAILhF.js +262 -0
  96. package/dist/assets/katex-CBSAILhF.js.map +1 -0
  97. package/dist/assets/layout-BNMvCxLN.js +2 -0
  98. package/dist/assets/layout-BNMvCxLN.js.map +1 -0
  99. package/dist/assets/linear-OqJg3PPm.js +2 -0
  100. package/dist/assets/linear-OqJg3PPm.js.map +1 -0
  101. package/dist/assets/min-N_DZlU1c.js +2 -0
  102. package/dist/assets/min-N_DZlU1c.js.map +1 -0
  103. package/dist/assets/mindmap-definition-VGOIOE7T-C43AGCOz.js +69 -0
  104. package/dist/assets/mindmap-definition-VGOIOE7T-C43AGCOz.js.map +1 -0
  105. package/dist/assets/ordinal-Cboi1Yqb.js +2 -0
  106. package/dist/assets/ordinal-Cboi1Yqb.js.map +1 -0
  107. package/dist/assets/pieDiagram-ADFJNKIX-COl1BPcc.js +31 -0
  108. package/dist/assets/pieDiagram-ADFJNKIX-COl1BPcc.js.map +1 -0
  109. package/dist/assets/quadrantDiagram-AYHSOK5B-C-fSINkS.js +8 -0
  110. package/dist/assets/quadrantDiagram-AYHSOK5B-C-fSINkS.js.map +1 -0
  111. package/dist/assets/requirementDiagram-UZGBJVZJ-DSag9Z4m.js +65 -0
  112. package/dist/assets/requirementDiagram-UZGBJVZJ-DSag9Z4m.js.map +1 -0
  113. package/dist/assets/sankeyDiagram-TZEHDZUN-JyvYJ7BV.js +11 -0
  114. package/dist/assets/sankeyDiagram-TZEHDZUN-JyvYJ7BV.js.map +1 -0
  115. package/dist/assets/sequenceDiagram-WL72ISMW-GkUPZQOc.js +146 -0
  116. package/dist/assets/sequenceDiagram-WL72ISMW-GkUPZQOc.js.map +1 -0
  117. package/dist/assets/stateDiagram-FKZM4ZOC-DiJHFrza.js +2 -0
  118. package/dist/assets/stateDiagram-FKZM4ZOC-DiJHFrza.js.map +1 -0
  119. package/dist/assets/stateDiagram-v2-4FDKWEC3-BgdSYitm.js +2 -0
  120. package/dist/assets/stateDiagram-v2-4FDKWEC3-BgdSYitm.js.map +1 -0
  121. package/dist/assets/timeline-definition-IT6M3QCI-BIeoFfU5.js +62 -0
  122. package/dist/assets/timeline-definition-IT6M3QCI-BIeoFfU5.js.map +1 -0
  123. package/dist/assets/treemap-KMMF4GRG-BDDqLxLB.js +129 -0
  124. package/dist/assets/treemap-KMMF4GRG-BDDqLxLB.js.map +1 -0
  125. package/dist/assets/xychartDiagram-PRI3JC2R-CUzWjNyv.js +8 -0
  126. package/dist/assets/xychartDiagram-PRI3JC2R-CUzWjNyv.js.map +1 -0
  127. package/dist/index.html +13 -0
  128. package/index.html +12 -0
  129. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HtmlReporter-Cu9NwA6b.js","sources":["../../src/core/reporters/html/HtmlTemplates.ts","../../src/core/reporters/HtmlReporter.ts"],"sourcesContent":["/**\n * HTML Templates for Blueprint Report\n * Generates each section of the HTML report with embedded CSS and JavaScript\n */\nimport type {\n BlueprintResult,\n BlueprintMetadata,\n BlueprintSummary,\n ERDDefinition,\n EntityBlueprint,\n PluginStep,\n Flow,\n BusinessRule,\n WebResource,\n CrossEntityLink,\n ExternalEndpoint,\n} from '../../types/blueprint.js';\nimport type { ClassicWorkflow } from '../../types/classicWorkflow.js';\nimport type { CustomAPI } from '../../types/customApi.js';\nimport type { EnvironmentVariable } from '../../types/environmentVariable.js';\nimport type { ConnectionReference } from '../../types/connectionReference.js';\nimport type { BusinessProcessFlow } from '../../types/businessProcessFlow.js';\n\n/**\n * Main HTML Templates class\n */\nexport class HtmlTemplates {\n /**\n * Generate complete HTML head section\n */\n htmlHead(result: BlueprintResult): string {\n const title = `Blueprint - ${result.metadata.environment || 'Power Platform'}`;\n return `<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"generator\" content=\"Power Platform Solution Blueprint (PPSB)\">\n <meta name=\"description\" content=\"Complete architectural blueprint for Power Platform solutions\">\n <title>${this.escapeHtml(title)}</title>\n <script src=\"https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js\"></script>\n <style>\n${this.embeddedCSS()}\n </style>\n</head>`;\n }\n\n /**\n * Generate sidebar navigation\n */\n htmlNavigation(): string {\n return `<nav class=\"sidebar\" id=\"sidebar\" role=\"navigation\" aria-label=\"Main navigation\">\n <div class=\"sidebar-header\">\n <h3>Blueprint</h3>\n <button class=\"nav-toggle\" id=\"navToggle\" aria-label=\"Toggle navigation\">☰</button>\n </div>\n <ul class=\"nav-links\">\n <li><a href=\"#summary\">📊 Summary</a></li>\n <li><a href=\"#erd\">🔗 Entity Relationship Diagram</a></li>\n <li><a href=\"#entities\">đŸ“Ļ Entities</a></li>\n <li><a href=\"#plugins\">🔌 Plugins</a></li>\n <li><a href=\"#flows\">⚡ Flows</a></li>\n <li><a href=\"#business-rules\">📋 Business Rules</a></li>\n <li><a href=\"#classic-workflows\">âąī¸ Classic Workflows</a></li>\n <li><a href=\"#business-process-flows\">🔄 Business Process Flows</a></li>\n <li><a href=\"#web-resources\">🌐 Web Resources</a></li>\n <li><a href=\"#custom-apis\">🔧 Custom APIs</a></li>\n <li><a href=\"#environment-variables\">âš™ī¸ Environment Variables</a></li>\n <li><a href=\"#connection-references\">🔗 Connection References</a></li>\n <li><a href=\"#security\">🔒 Security</a></li>\n <li><a href=\"#external-dependencies\">🌍 External Dependencies</a></li>\n <li><a href=\"#cross-entity\">🔀 Cross-Entity Automation</a></li>\n </ul>\n <div class=\"nav-footer\">\n <button class=\"btn-print\" onclick=\"window.print()\" aria-label=\"Print blueprint\">đŸ–¨ī¸ Print</button>\n </div>\n</nav>`;\n }\n\n /**\n * Generate header section\n */\n htmlHeader(metadata: BlueprintMetadata): string {\n const generatedDate = metadata.generatedAt.toLocaleString();\n return `<header class=\"report-header\" role=\"banner\">\n <h1>Power Platform Solution Blueprint</h1>\n <div class=\"metadata-grid\">\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Environment:</span>\n <span class=\"metadata-value\">${this.escapeHtml(metadata.environment)}</span>\n </div>\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Generated:</span>\n <span class=\"metadata-value\">${this.escapeHtml(generatedDate)}</span>\n </div>\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Scope:</span>\n <span class=\"metadata-value\">${this.escapeHtml(metadata.scope.description)}</span>\n </div>\n <div class=\"metadata-item\">\n <span class=\"metadata-label\">Entities:</span>\n <span class=\"metadata-value\">${metadata.entityCount}</span>\n </div>\n </div>\n</header>`;\n }\n\n /**\n * Generate ERD section\n * Note: Only includes the first diagram (comprehensive view) to match the tool UI behavior\n */\n htmlErdSection(erd: ERDDefinition | undefined): string {\n if (!erd || erd.diagrams.length === 0) {\n return `<section id=\"erd\" class=\"content-section\">\n <h2>Entity Relationship Diagram</h2>\n <div class=\"empty-state\">No ERD available</div>\n</section>`;\n }\n\n const legendHtml = this.generateLegendHtml(erd.legend);\n\n // Use only the first diagram (comprehensive view with all entities) - matches UI behavior\n const diagram = erd.diagrams[0];\n const diagramHtml = `<div class=\"erd-diagram\">\n <h3>${this.escapeHtml(diagram.title)}</h3>\n <p class=\"diagram-description\">${this.escapeHtml(diagram.description)}</p>\n <div class=\"mermaid\" id=\"diagram-0\">\n${diagram.mermaidDiagram}\n </div>\n <p class=\"diagram-stats\">Entities: ${diagram.entityCount} | Relationships: ${diagram.relationshipCount}</p>\n</div>`;\n\n return `<section id=\"erd\" class=\"content-section\">\n <h2>Entity Relationship Diagram</h2>\n ${legendHtml}\n ${diagramHtml}\n</section>`;\n }\n\n /**\n * Generate legend HTML for ERD\n */\n private generateLegendHtml(legend: any[]): string {\n if (!legend || legend.length === 0) return '';\n\n const items = legend.map(item => {\n return `<div class=\"legend-item\">\n <span class=\"legend-color\" style=\"background-color: ${item.color}\"></span>\n <span class=\"legend-label\">${this.escapeHtml(item.publisherName)} (${item.entityCount})</span>\n</div>`;\n }).join('\\n');\n\n return `<div class=\"erd-legend\">\n <h4>Publishers</h4>\n <div class=\"legend-items\">\n${items}\n </div>\n</div>`;\n }\n\n /**\n * Generate summary section\n */\n htmlSummary(summary: BlueprintSummary): string {\n return `<section id=\"summary\" class=\"content-section\">\n <h2>Summary</h2>\n <div class=\"summary-grid\">\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalEntities}</div>\n <div class=\"card-label\">Entities</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalAttributes}</div>\n <div class=\"card-label\">Attributes</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalPlugins}</div>\n <div class=\"card-label\">Plugins</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalFlows}</div>\n <div class=\"card-label\">Flows</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalBusinessRules}</div>\n <div class=\"card-label\">Business Rules</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalWebResources}</div>\n <div class=\"card-label\">Web Resources</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalCustomAPIs}</div>\n <div class=\"card-label\">Custom APIs</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalSecurityRoles}</div>\n <div class=\"card-label\">Security Roles</div>\n </div>\n <div class=\"summary-card\">\n <div class=\"card-number\">${summary.totalFieldSecurityProfiles}</div>\n <div class=\"card-label\">Field Security Profiles</div>\n </div>\n <div class=\"summary-card ${summary.totalClassicWorkflows > 0 ? 'card-warning' : ''}\">\n <div class=\"card-number\">${summary.totalClassicWorkflows}</div>\n <div class=\"card-label\">Classic Workflows</div>\n </div>\n </div>\n</section>`;\n }\n\n /**\n * Generate entities accordion section\n */\n htmlEntitiesAccordion(entities: EntityBlueprint[]): string {\n if (entities.length === 0) {\n return `<section id=\"entities\" class=\"content-section\">\n <h2>Entities</h2>\n <div class=\"empty-state\">No entities found</div>\n</section>`;\n }\n\n const accordionItems = entities.map((entityBp, index) => {\n const entity = entityBp.entity;\n const displayName = entity.DisplayName?.UserLocalizedLabel?.Label || entity.LogicalName;\n const attributeCount = entity.Attributes?.length || 0;\n const pluginCount = entityBp.plugins?.length || 0;\n const flowCount = entityBp.flows?.length || 0;\n const brCount = entityBp.businessRules?.length || 0;\n\n // Check if entity has server-side automation for execution pipeline\n const hasExecutionPipeline = this.hasEntityExecutionPipeline(entityBp);\n\n return `<div class=\"accordion-item\">\n <div class=\"accordion-header\" onclick=\"toggleAccordion('entity-${index}')\">\n <span class=\"accordion-icon\" id=\"icon-entity-${index}\">+</span>\n <h3>${this.escapeHtml(displayName)}</h3>\n <span class=\"entity-badges\">\n ${attributeCount > 0 ? `<span class=\"badge badge-info\">${attributeCount} fields</span>` : ''}\n ${pluginCount > 0 ? `<span class=\"badge badge-success\">${pluginCount} plugins</span>` : ''}\n ${flowCount > 0 ? `<span class=\"badge badge-primary\">${flowCount} flows</span>` : ''}\n ${brCount > 0 ? `<span class=\"badge badge-warning\">${brCount} rules</span>` : ''}\n </span>\n </div>\n <div class=\"accordion-content\" id=\"entity-${index}\" style=\"display: none;\">\n <!-- Entity Tabs -->\n <div class=\"entity-tabs\">\n <div class=\"tabs-header\">\n <button class=\"tab-button active\" onclick=\"switchEntityTab('entity-${index}', 'overview')\">Overview</button>\n <button class=\"tab-button\" onclick=\"switchEntityTab('entity-${index}', 'schema')\">Schema</button>\n ${this.hasEntityAutomation(entityBp) ? `<button class=\"tab-button\" onclick=\"switchEntityTab('entity-${index}', 'automation')\">Automation</button>` : ''}\n ${hasExecutionPipeline ? `<button class=\"tab-button\" onclick=\"switchEntityTab('entity-${index}', 'pipeline')\">Execution Pipeline</button>` : ''}\n </div>\n\n <!-- Overview Tab -->\n <div class=\"tab-content active\" id=\"entity-${index}-overview\">\n ${this.generateEntityOverviewTab(entityBp)}\n </div>\n\n <!-- Schema Tab -->\n <div class=\"tab-content\" id=\"entity-${index}-schema\">\n ${this.generateEntitySchemaTab(entityBp)}\n </div>\n\n ${this.hasEntityAutomation(entityBp) ? `<!-- Automation Tab -->\n <div class=\"tab-content\" id=\"entity-${index}-automation\">\n ${this.generateEntityAutomationTab(entityBp)}\n </div>` : ''}\n\n ${hasExecutionPipeline ? `<!-- Execution Pipeline Tab -->\n <div class=\"tab-content\" id=\"entity-${index}-pipeline\">\n ${this.generateEntityPipelineTab(entityBp)}\n </div>` : ''}\n </div>\n </div>\n</div>`;\n }).join('\\n');\n\n return `<section id=\"entities\" class=\"content-section\">\n <h2>Entities (${entities.length})</h2>\n <div class=\"accordion\">\n${accordionItems}\n </div>\n</section>`;\n }\n\n /**\n * Generate attributes table for entity detail\n */\n private generateAttributesTable(attributes: any[]): string {\n if (attributes.length === 0) return '';\n\n const rows = attributes.slice(0, 50).map(attr => {\n const displayName = attr.DisplayName?.UserLocalizedLabel?.Label || attr.LogicalName;\n const description = attr.Description?.UserLocalizedLabel?.Label || '';\n const required = attr.RequiredLevel?.Value || 'None';\n const type = attr.AttributeType || 'Unknown';\n\n return `<tr>\n <td>${this.escapeHtml(attr.LogicalName)}</td>\n <td>${this.escapeHtml(displayName)}</td>\n <td>${this.escapeHtml(type)}</td>\n <td><span class=\"badge badge-${required === 'SystemRequired' ? 'error' : required === 'ApplicationRequired' ? 'warning' : 'info'}\">${required}</span></td>\n <td style=\"word-break: break-word;\">${this.escapeHtml(description)}</td>\n</tr>`;\n }).join('\\n');\n\n const moreText = attributes.length > 50 ? `<p class=\"table-note\">Showing 50 of ${attributes.length} attributes</p>` : '';\n\n return `<div class=\"entity-subsection\">\n <h4>Attributes (${attributes.length})</h4>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Logical Name</th>\n <th>Display Name</th>\n <th>Type</th>\n <th>Required</th>\n <th>Description</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n ${moreText}\n</div>`;\n }\n\n /**\n * Generate plugins table for entity detail\n */\n private generateEntityPluginsTable(plugins: PluginStep[]): string {\n if (plugins.length === 0) return '';\n\n const rows = plugins.map(plugin => {\n return `<tr>\n <td>${this.escapeHtml(plugin.name)}</td>\n <td>${this.escapeHtml(plugin.message || '')}</td>\n <td>${this.escapeHtml(plugin.stageName || '')}</td>\n <td>${this.escapeHtml(plugin.modeName || '')}</td>\n <td style=\"word-break: break-word;\">${this.escapeHtml(plugin.description || '')}</td>\n</tr>`;\n }).join('\\n');\n\n return `<div class=\"entity-subsection\">\n <h4>Plugins (${plugins.length})</h4>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Message</th>\n <th>Stage</th>\n <th>Mode</th>\n <th>Description</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n</div>`;\n }\n\n /**\n * Generate flows table for entity detail\n */\n private generateEntityFlowsTable(flows: Flow[]): string {\n if (flows.length === 0) return '';\n\n const rows = flows.map(flow => {\n return `<tr>\n <td>${this.escapeHtml(flow.name)}</td>\n <td><span class=\"badge badge-${flow.state === 'Active' ? 'success' : flow.state === 'Draft' ? 'warning' : 'error'}\">${flow.state}</span></td>\n <td>${this.escapeHtml(flow.definition.triggerEvent)}</td>\n <td style=\"word-break: break-word;\">${this.escapeHtml(flow.description || '')}</td>\n</tr>`;\n }).join('\\n');\n\n return `<div class=\"entity-subsection\">\n <h4>Flows (${flows.length})</h4>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>State</th>\n <th>Trigger</th>\n <th>Description</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n</div>`;\n }\n\n /**\n * Check if entity has any automation\n */\n private hasEntityAutomation(entityBp: EntityBlueprint): boolean {\n return entityBp.plugins.length > 0 ||\n entityBp.flows.length > 0 ||\n entityBp.businessRules.length > 0;\n }\n\n /**\n * Check if entity has server-side execution pipeline\n */\n private hasEntityExecutionPipeline(entityBp: EntityBlueprint): boolean {\n // Has plugins\n if (entityBp.plugins.length > 0) return true;\n\n // Has entity-scoped business rules (they run server-side)\n const hasEntityScopedBRs = entityBp.businessRules.some(br => br.scopeName === 'Entity');\n if (hasEntityScopedBRs) return true;\n\n // Has Dataverse flows (they run server-side)\n const hasDataverseFlows = entityBp.flows.some(flow => flow.definition.triggerType === 'Dataverse');\n if (hasDataverseFlows) return true;\n\n return false;\n }\n\n /**\n * Generate Overview tab content for entity\n */\n private generateEntityOverviewTab(entityBp: EntityBlueprint): string {\n const entity = entityBp.entity;\n const description = entity.Description?.UserLocalizedLabel?.Label || '';\n\n const metadata = [\n ['Logical Name', entity.LogicalName],\n ['Schema Name', entity.SchemaName],\n ['Primary Field', entity.PrimaryNameAttribute || 'N/A'],\n ['Ownership', entity.OwnershipTypeName || 'N/A'],\n ['Is Activity', entity.IsActivity ? 'Yes' : 'No'],\n ['Is Custom', entity.IsCustomEntity ? 'Yes' : 'No'],\n ];\n\n const automationSummary = `\n <div class=\"automation-summary\">\n <div class=\"summary-row\">\n <span class=\"summary-label\">Plugins:</span>\n <span class=\"summary-value\">${entityBp.plugins.length}</span>\n </div>\n <div class=\"summary-row\">\n <span class=\"summary-label\">Cloud Flows:</span>\n <span class=\"summary-value\">${entityBp.flows.length}</span>\n </div>\n <div class=\"summary-row\">\n <span class=\"summary-label\">Business Rules:</span>\n <span class=\"summary-value\">${entityBp.businessRules.length}</span>\n </div>\n <div class=\"summary-row\">\n <span class=\"summary-label\">Attributes:</span>\n <span class=\"summary-value\">${entity.Attributes?.length || 0}</span>\n </div>\n </div>\n `;\n\n return `\n ${description ? `<div class=\"entity-description\">${this.escapeHtml(description)}</div>` : ''}\n <div class=\"entity-metadata\">\n <h4>Entity Information</h4>\n <table class=\"metadata-table\">\n ${metadata.map(([key, value]) => `<tr><th>${key}</th><td>${this.escapeHtml(value)}</td></tr>`).join('\\n')}\n </table>\n </div>\n ${automationSummary}\n `;\n }\n\n /**\n * Generate Schema tab content for entity\n */\n private generateEntitySchemaTab(entityBp: EntityBlueprint): string {\n const entity = entityBp.entity;\n const attributes = entity.Attributes || [];\n const oneToMany = entity.OneToManyRelationships || [];\n const manyToOne = entity.ManyToOneRelationships || [];\n const manyToMany = entity.ManyToManyRelationships || [];\n\n let content = '';\n\n // Attributes section\n if (attributes.length > 0) {\n content += this.generateAttributesTable(attributes);\n } else {\n content += '<div class=\"empty-state\">No attributes found</div>';\n }\n\n // Relationships section\n const totalRelationships = oneToMany.length + manyToOne.length + manyToMany.length;\n if (totalRelationships > 0) {\n content += `<div class=\"entity-subsection\">\n <h4>Relationships (${totalRelationships})</h4>\n ${oneToMany.length > 0 ? this.generateRelationshipsSection('One-to-Many', oneToMany) : ''}\n ${manyToOne.length > 0 ? this.generateRelationshipsSection('Many-to-One', manyToOne) : ''}\n ${manyToMany.length > 0 ? this.generateRelationshipsSection('Many-to-Many', manyToMany) : ''}\n </div>`;\n }\n\n // Field Security section\n if (entityBp.fieldSecurity && entityBp.fieldSecurity.securedFields.length > 0) {\n content += this.generateFieldSecuritySection(entityBp.fieldSecurity);\n }\n\n return content;\n }\n\n /**\n * Generate Automation tab content for entity\n */\n private generateEntityAutomationTab(entityBp: EntityBlueprint): string {\n let content = '';\n\n const hasAutomation = entityBp.plugins.length > 0 || entityBp.flows.length > 0 || entityBp.businessRules.length > 0;\n\n if (!hasAutomation) {\n return '<div class=\"empty-state\">No automation configured for this entity</div>';\n }\n\n // Plugins\n if (entityBp.plugins.length > 0) {\n content += this.generateEntityPluginsTable(entityBp.plugins);\n }\n\n // Flows\n if (entityBp.flows.length > 0) {\n content += this.generateEntityFlowsTable(entityBp.flows);\n }\n\n // Business Rules\n if (entityBp.businessRules.length > 0) {\n content += this.generateEntityBusinessRulesTable(entityBp.businessRules);\n }\n\n return content;\n }\n\n /**\n * Generate Execution Pipeline tab content for entity\n */\n private generateEntityPipelineTab(entityBp: EntityBlueprint): string {\n const entity = entityBp.entity;\n const displayName = entity.DisplayName?.UserLocalizedLabel?.Label || entity.LogicalName;\n\n let content = `<div class=\"pipeline-intro\">\n <p>This shows the execution order of server-side automation on <strong>${this.escapeHtml(displayName)}</strong>.</p>\n </div>`;\n\n // Group plugins by message\n const pluginsByMessage = new Map<string, PluginStep[]>();\n for (const plugin of entityBp.plugins) {\n const key = plugin.message;\n if (!pluginsByMessage.has(key)) {\n pluginsByMessage.set(key, []);\n }\n pluginsByMessage.get(key)!.push(plugin);\n }\n\n // Get entity-scoped business rules (they run server-side)\n const entityScopedBRs = entityBp.businessRules.filter(br => br.scopeName === 'Entity');\n\n // If no plugins, show business rules and flows\n if (entityBp.plugins.length === 0) {\n content += '<p><strong>No plugins registered on this entity.</strong></p>';\n\n if (entityScopedBRs.length > 0) {\n content += `<div class=\"entity-subsection\">\n <h4>Business Rules (Server-side)</h4>\n ${this.generateEntityBusinessRulesTable(entityScopedBRs)}\n </div>`;\n }\n\n const dataverseFlows = entityBp.flows.filter(f => f.definition.triggerType === 'Dataverse');\n if (dataverseFlows.length > 0) {\n content += `<div class=\"entity-subsection\">\n <h4>Dataverse Flows</h4>\n ${this.generateEntityFlowsTable(dataverseFlows)}\n </div>`;\n }\n\n return content;\n }\n\n // Generate execution order for each message\n for (const [message, plugins] of pluginsByMessage) {\n content += `<div class=\"pipeline-message\">\n <h4>${this.escapeHtml(message)} Event</h4>`;\n\n // Sort plugins by stage then rank\n const sortedPlugins = [...plugins].sort((a, b) => {\n if (a.stage !== b.stage) return a.stage - b.stage;\n return a.rank - b.rank;\n });\n\n // Group by stage\n const byStage = new Map<number, PluginStep[]>();\n for (const plugin of sortedPlugins) {\n if (!byStage.has(plugin.stage)) {\n byStage.set(plugin.stage, []);\n }\n byStage.get(plugin.stage)!.push(plugin);\n }\n\n // Generate visual pipeline\n content += this.generatePipelineVisualization(byStage, entityScopedBRs);\n\n // Execution details table\n content += `<h5>Execution Details</h5>`;\n content += this.generatePipelineDetailsTable(sortedPlugins, entityScopedBRs);\n\n // Check for sync plugins (potential performance impact)\n const syncPlugins = sortedPlugins.filter(p => p.mode === 0);\n if (syncPlugins.length > 0) {\n content += `<div class=\"info-box\">\n <strong>â„šī¸ Synchronous Plugins</strong>\n <p>${syncPlugins.length} synchronous plugin(s) execute in this pipeline. Synchronous plugins block the transaction and should complete quickly.</p>\n </div>`;\n }\n\n content += `</div>`;\n }\n\n // Show all business rules\n if (entityBp.businessRules.length > 0) {\n content += `<div class=\"entity-subsection\">\n <h4>All Business Rules</h4>\n <p>Business rules execute on the client (form) or server depending on their scope.</p>\n ${this.generateEntityBusinessRulesTable(entityBp.businessRules)}\n </div>`;\n }\n\n return content;\n }\n\n /**\n * Generate visual pipeline representation\n */\n private generatePipelineVisualization(byStage: Map<number, PluginStep[]>, businessRules: BusinessRule[]): string {\n let html = '<div class=\"pipeline-visual\">';\n\n // Add business rules first\n if (businessRules.length > 0) {\n html += `<div class=\"pipeline-stage stage-business-rules\">\n <div class=\"stage-header\">Business Rules (Server-side, Entity-scoped)</div>\n <div class=\"stage-steps\">`;\n\n businessRules.forEach((br, idx) => {\n const state = br.state === 'Active' ? 'active' : 'draft';\n html += `<div class=\"pipeline-step step-${state}\">\n ${idx + 1}. ${this.escapeHtml(br.name)} <span class=\"step-badge badge-${state}\">[${state.toUpperCase()}]</span>\n </div>`;\n });\n\n html += `</div></div>`;\n }\n\n // Add plugin stages\n for (const [stage, plugins] of byStage) {\n const stageName = plugins[0].stageName;\n const stageClass = this.getStageClass(stage);\n\n html += `<div class=\"pipeline-stage ${stageClass}\">\n <div class=\"stage-header\">Stage ${stage}: ${this.escapeHtml(stageName)}</div>\n <div class=\"stage-steps\">`;\n\n plugins.forEach((plugin, idx) => {\n const mode = plugin.mode === 0 ? 'sync' : 'async';\n html += `<div class=\"pipeline-step step-${mode}\">\n ${idx + 1}. ${this.escapeHtml(plugin.name)} <span class=\"step-badge badge-${mode}\">[${mode.toUpperCase()}]</span>\n <span class=\"step-rank\">Rank: ${plugin.rank}</span>\n </div>`;\n });\n\n html += `</div></div>`;\n }\n\n html += '</div>';\n return html;\n }\n\n /**\n * Get CSS class for plugin stage\n */\n private getStageClass(stage: number): string {\n switch (stage) {\n case 10: return 'stage-prevalidation';\n case 20: return 'stage-preoperation';\n case 30: return 'stage-mainoperation';\n case 40: return 'stage-postoperation';\n default: return 'stage-unknown';\n }\n }\n\n /**\n * Generate pipeline details table\n */\n private generatePipelineDetailsTable(plugins: PluginStep[], businessRules: BusinessRule[]): string {\n const rows: string[] = [];\n\n // Add business rules first\n businessRules.forEach((br, idx) => {\n const stateBadge = br.state === 'Active'\n ? '<span class=\"badge badge-success\">Active</span>'\n : '<span class=\"badge badge-warning\">Draft</span>';\n rows.push(`<tr>\n <td>${idx + 1}</td>\n <td>Business Rule</td>\n <td>${this.escapeHtml(br.name)}</td>\n <td>Server-side (Entity scope)</td>\n <td>${stateBadge}</td>\n <td>-</td>\n </tr>`);\n });\n\n // Add plugins\n plugins.forEach((plugin, idx) => {\n const modeBadge = plugin.mode === 0\n ? '<span class=\"badge badge-sync\">Synchronous</span>'\n : '<span class=\"badge badge-async\">Asynchronous</span>';\n rows.push(`<tr>\n <td>${businessRules.length + idx + 1}</td>\n <td>Plugin</td>\n <td>${this.escapeHtml(plugin.name)}</td>\n <td>${this.escapeHtml(plugin.stageName)}</td>\n <td>${modeBadge}</td>\n <td>${plugin.rank}</td>\n </tr>`);\n });\n\n return `<table class=\"data-table pipeline-table\">\n <thead>\n <tr>\n <th>Order</th>\n <th>Type</th>\n <th>Name</th>\n <th>Stage/Details</th>\n <th>Mode</th>\n <th>Rank</th>\n </tr>\n </thead>\n <tbody>\n ${rows.join('\\n')}\n </tbody>\n </table>`;\n }\n\n /**\n * Generate business rules table for entity\n */\n private generateEntityBusinessRulesTable(businessRules: BusinessRule[]): string {\n if (businessRules.length === 0) return '';\n\n const rows = businessRules.map(br => {\n const stateBadge = br.state === 'Active'\n ? '<span class=\"badge badge-success\">Active</span>'\n : '<span class=\"badge badge-warning\">Draft</span>';\n return `<tr>\n <td>${this.escapeHtml(br.name)}</td>\n <td>${this.escapeHtml(br.scopeName)}</td>\n <td>${this.escapeHtml(br.definition.executionContext)}</td>\n <td>${stateBadge}</td>\n <td>${br.definition.conditions.length}</td>\n <td>${br.definition.actions.length}</td>\n </tr>`;\n }).join('\\n');\n\n return `<div class=\"entity-subsection\">\n <h4>Business Rules (${businessRules.length})</h4>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Scope</th>\n <th>Context</th>\n <th>State</th>\n <th>Conditions</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n ${rows}\n </tbody>\n </table>\n </div>`;\n }\n\n /**\n * Generate relationships section\n */\n private generateRelationshipsSection(type: string, relationships: any[]): string {\n if (relationships.length === 0) return '';\n\n const rows = relationships.slice(0, 20).map(rel => {\n const schemaName = rel.SchemaName || 'N/A';\n const referencingEntity = rel.ReferencingEntity || rel.ReferencedEntity || 'N/A';\n const referencedAttribute = rel.ReferencedAttribute || rel.ReferencingAttribute || 'N/A';\n\n return `<tr>\n <td>${this.escapeHtml(schemaName)}</td>\n <td>${this.escapeHtml(referencingEntity)}</td>\n <td>${this.escapeHtml(referencedAttribute)}</td>\n </tr>`;\n }).join('\\n');\n\n const moreText = relationships.length > 20 ? `<p class=\"table-note\">Showing 20 of ${relationships.length} relationships</p>` : '';\n\n return `<div class=\"relationship-section\">\n <h5>${type} (${relationships.length})</h5>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Schema Name</th>\n <th>Related Entity</th>\n <th>Related Attribute</th>\n </tr>\n </thead>\n <tbody>\n ${rows}\n </tbody>\n </table>\n ${moreText}\n </div>`;\n }\n\n /**\n * Generate plugins table section\n */\n htmlPluginsTable(plugins: PluginStep[]): string {\n if (plugins.length === 0) {\n return `<section id=\"plugins\" class=\"content-section\">\n <h2>Plugins</h2>\n <div class=\"empty-state\">No plugins found</div>\n</section>`;\n }\n\n const rows = plugins.map(plugin => {\n const images: string[] = [];\n if (plugin.preImage) images.push(plugin.preImage.imageType);\n if (plugin.postImage) images.push(plugin.postImage.imageType);\n const imagesText = images.length > 0 ? images.join(', ') : 'None';\n\n return `<tr>\n <td>${this.escapeHtml(plugin.name)}</td>\n <td>${this.escapeHtml(plugin.entity || 'N/A')}</td>\n <td>${this.escapeHtml(plugin.message || 'N/A')}</td>\n <td>${this.escapeHtml(plugin.stageName || 'N/A')}</td>\n <td>${this.escapeHtml(plugin.modeName || 'N/A')}</td>\n <td>${String(plugin.rank || 0)}</td>\n <td>${this.escapeHtml(imagesText)}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"plugins\" class=\"content-section\">\n <h2>Plugins (${plugins.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"plugins-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('plugins-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('plugins-table', 1)\">Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('plugins-table', 2)\">Message <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('plugins-table', 3)\">Stage <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('plugins-table', 4)\">Mode <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('plugins-table', 5)\">Rank <span class=\"sort-indicator\"></span></th>\n <th>Images</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate flows table section\n */\n htmlFlowsTable(flows: Flow[]): string {\n if (flows.length === 0) {\n return `<section id=\"flows\" class=\"content-section\">\n <h2>Flows</h2>\n <div class=\"empty-state\">No flows found</div>\n</section>`;\n }\n\n const rows = flows.map(flow => {\n const entityDisplay = flow.entityDisplayName || flow.entity || 'N/A';\n const hasExternal = flow.hasExternalCalls;\n\n return `<tr>\n <td>${this.escapeHtml(flow.name)}</td>\n <td>${this.escapeHtml(entityDisplay)}</td>\n <td><span class=\"badge badge-${flow.state === 'Active' ? 'success' : flow.state === 'Draft' ? 'warning' : 'error'}\">${flow.state}</span></td>\n <td>${this.escapeHtml(flow.definition.triggerEvent)}</td>\n <td>${this.escapeHtml(flow.definition.scopeType)}</td>\n <td>${flow.definition.actionsCount}</td>\n <td>${hasExternal ? '<span class=\"badge badge-warning\">Yes</span>' : '<span class=\"badge badge-info\">No</span>'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"flows\" class=\"content-section\">\n <h2>Flows (${flows.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"flows-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('flows-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('flows-table', 1)\">Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('flows-table', 2)\">State <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('flows-table', 3)\">Trigger <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('flows-table', 4)\">Scope <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('flows-table', 5)\">Actions <span class=\"sort-indicator\"></span></th>\n <th>External Calls</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate business rules table section\n */\n htmlBusinessRulesTable(businessRules: BusinessRule[]): string {\n if (businessRules.length === 0) {\n return `<section id=\"business-rules\" class=\"content-section\">\n <h2>Business Rules</h2>\n <div class=\"empty-state\">No business rules found</div>\n</section>`;\n }\n\n const rows = businessRules.map(rule => {\n const entityDisplay = rule.entityDisplayName || rule.entity;\n const conditions = rule.definition.conditions?.length || 0;\n const actions = rule.definition.actions?.length || 0;\n\n return `<tr>\n <td>${this.escapeHtml(rule.name)}</td>\n <td>${this.escapeHtml(entityDisplay)}</td>\n <td><span class=\"badge badge-${rule.state === 'Active' ? 'success' : 'warning'}\">${rule.state}</span></td>\n <td>${this.escapeHtml(rule.scope)}</td>\n <td>${conditions}</td>\n <td>${actions}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"business-rules\" class=\"content-section\">\n <h2>Business Rules (${businessRules.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"business-rules-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('business-rules-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('business-rules-table', 1)\">Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('business-rules-table', 2)\">State <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('business-rules-table', 3)\">Scope <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('business-rules-table', 4)\">Conditions <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('business-rules-table', 5)\">Actions <span class=\"sort-indicator\"></span></th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate classic workflows table section\n */\n htmlClassicWorkflowsTable(workflows: ClassicWorkflow[]): string {\n if (workflows.length === 0) {\n return `<section id=\"classic-workflows\" class=\"content-section\">\n <h2>Classic Workflows (Deprecated)</h2>\n <div class=\"empty-state\">No classic workflows found</div>\n</section>`;\n }\n\n const rows = workflows.map(workflow => {\n const entityDisplay = workflow.entityDisplayName || workflow.entity;\n const complexity = workflow.migrationRecommendation?.complexity || 'Unknown';\n const effort = workflow.migrationRecommendation?.effort || 'Unknown';\n\n return `<tr>\n <td>${this.escapeHtml(workflow.name)}</td>\n <td>${this.escapeHtml(entityDisplay)}</td>\n <td><span class=\"badge badge-${workflow.state === 'Active' ? 'success' : workflow.state === 'Draft' ? 'warning' : 'error'}\">${workflow.state}</span></td>\n <td>${this.escapeHtml(workflow.modeName)}</td>\n <td><span class=\"badge badge-${complexity === 'Critical' ? 'error' : complexity === 'High' ? 'warning' : 'info'}\">${complexity}</span></td>\n <td>${this.escapeHtml(effort)}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"classic-workflows\" class=\"content-section\">\n <h2>Classic Workflows - Migration Required (${workflows.length})</h2>\n <div class=\"alert alert-warning\">\n <strong>âš ī¸ Migration Required:</strong> Classic workflows are deprecated and will be removed. Please migrate to Power Automate cloud flows.\n </div>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"classic-workflows-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('classic-workflows-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('classic-workflows-table', 1)\">Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('classic-workflows-table', 2)\">State <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('classic-workflows-table', 3)\">Mode <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('classic-workflows-table', 4)\">Complexity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('classic-workflows-table', 5)\">Effort <span class=\"sort-indicator\"></span></th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate business process flows table section\n */\n htmlBusinessProcessFlowsTable(bpfs: BusinessProcessFlow[]): string {\n if (bpfs.length === 0) {\n return `<section id=\"business-process-flows\" class=\"content-section\">\n <h2>Business Process Flows</h2>\n <div class=\"empty-state\">No business process flows found</div>\n</section>`;\n }\n\n const rows = bpfs.map(bpf => {\n const entityDisplay = bpf.primaryEntityDisplayName || bpf.primaryEntity;\n const stages = bpf.definition.stages?.length || 0;\n const crossEntity = bpf.definition.crossEntityFlow;\n\n return `<tr>\n <td>${this.escapeHtml(bpf.name)}</td>\n <td>${this.escapeHtml(entityDisplay)}</td>\n <td><span class=\"badge badge-${bpf.state === 'Active' ? 'success' : 'warning'}\">${bpf.state}</span></td>\n <td>${stages}</td>\n <td>${bpf.definition.totalSteps}</td>\n <td>${crossEntity ? '<span class=\"badge badge-info\">Yes</span>' : 'No'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"business-process-flows\" class=\"content-section\">\n <h2>Business Process Flows (${bpfs.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"bpfs-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('bpfs-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('bpfs-table', 1)\">Primary Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('bpfs-table', 2)\">State <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('bpfs-table', 3)\">Stages <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('bpfs-table', 4)\">Steps <span class=\"sort-indicator\"></span></th>\n <th>Cross-Entity</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate web resources table section\n */\n htmlWebResourcesTable(webResources: WebResource[]): string {\n if (webResources.length === 0) {\n return `<section id=\"web-resources\" class=\"content-section\">\n <h2>Web Resources</h2>\n <div class=\"empty-state\">No web resources found</div>\n</section>`;\n }\n\n const rows = webResources.map(wr => {\n const sizeKB = (wr.contentSize / 1024).toFixed(2);\n const hasExternal = wr.hasExternalCalls;\n const deprecated = wr.isDeprecated;\n\n return `<tr>\n <td>${this.escapeHtml(wr.name)}</td>\n <td>${this.escapeHtml(wr.displayName)}</td>\n <td>${this.escapeHtml(wr.typeName)}</td>\n <td>${sizeKB} KB</td>\n <td>${hasExternal ? '<span class=\"badge badge-warning\">Yes</span>' : 'No'}</td>\n <td>${deprecated ? '<span class=\"badge badge-error\">Yes</span>' : 'No'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"web-resources\" class=\"content-section\">\n <h2>Web Resources (${webResources.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"web-resources-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('web-resources-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('web-resources-table', 1)\">Display Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('web-resources-table', 2)\">Type <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('web-resources-table', 3)\">Size <span class=\"sort-indicator\"></span></th>\n <th>External Calls</th>\n <th>Deprecated</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate custom APIs table section\n */\n htmlCustomAPIsTable(customAPIs: CustomAPI[]): string {\n if (customAPIs.length === 0) {\n return `<section id=\"custom-apis\" class=\"content-section\">\n <h2>Custom APIs</h2>\n <div class=\"empty-state\">No custom APIs found</div>\n</section>`;\n }\n\n const rows = customAPIs.map(api => {\n const type = api.isFunction ? 'Function' : 'Action';\n const binding = api.bindingType;\n const params = api.requestParameters?.length || 0;\n const responses = api.responseProperties?.length || 0;\n\n return `<tr>\n <td>${this.escapeHtml(api.uniqueName)}</td>\n <td>${this.escapeHtml(api.displayName)}</td>\n <td><span class=\"badge badge-${api.isFunction ? 'info' : 'primary'}\">${type}</span></td>\n <td>${this.escapeHtml(binding)}</td>\n <td>${params}</td>\n <td>${responses}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"custom-apis\" class=\"content-section\">\n <h2>Custom APIs (${customAPIs.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"custom-apis-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('custom-apis-table', 0)\">Unique Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('custom-apis-table', 1)\">Display Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('custom-apis-table', 2)\">Type <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('custom-apis-table', 3)\">Binding <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('custom-apis-table', 4)\">Parameters <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('custom-apis-table', 5)\">Responses <span class=\"sort-indicator\"></span></th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate environment variables table section\n */\n htmlEnvironmentVariablesTable(envVars: EnvironmentVariable[]): string {\n if (envVars.length === 0) {\n return `<section id=\"environment-variables\" class=\"content-section\">\n <h2>Environment Variables</h2>\n <div class=\"empty-state\">No environment variables found</div>\n</section>`;\n }\n\n const rows = envVars.map(envVar => {\n const hasValue = !!envVar.currentValue;\n const required = envVar.isRequired;\n\n return `<tr>\n <td>${this.escapeHtml(envVar.schemaName)}</td>\n <td>${this.escapeHtml(envVar.displayName)}</td>\n <td>${this.escapeHtml(envVar.typeName)}</td>\n <td>${required ? '<span class=\"badge badge-error\">Required</span>' : 'Optional'}</td>\n <td>${hasValue ? '<span class=\"badge badge-success\">Set</span>' : '<span class=\"badge badge-warning\">Not Set</span>'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"environment-variables\" class=\"content-section\">\n <h2>Environment Variables (${envVars.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"env-vars-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('env-vars-table', 0)\">Schema Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('env-vars-table', 1)\">Display Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('env-vars-table', 2)\">Type <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('env-vars-table', 3)\">Required <span class=\"sort-indicator\"></span></th>\n <th>Value Status</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate connection references table section\n */\n htmlConnectionReferencesTable(connRefs: ConnectionReference[]): string {\n if (connRefs.length === 0) {\n return `<section id=\"connection-references\" class=\"content-section\">\n <h2>Connection References</h2>\n <div class=\"empty-state\">No connection references found</div>\n</section>`;\n }\n\n const rows = connRefs.map(connRef => {\n const connector = connRef.connectorDisplayName || 'Unknown';\n const connected = !!connRef.connectionId;\n\n return `<tr>\n <td>${this.escapeHtml(connRef.name)}</td>\n <td>${this.escapeHtml(connRef.displayName)}</td>\n <td>${this.escapeHtml(connector)}</td>\n <td>${connected ? '<span class=\"badge badge-success\">Connected</span>' : '<span class=\"badge badge-error\">Not Connected</span>'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"connection-references\" class=\"content-section\">\n <h2>Connection References (${connRefs.length})</h2>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"conn-refs-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('conn-refs-table', 0)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('conn-refs-table', 1)\">Display Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('conn-refs-table', 2)\">Connector <span class=\"sort-indicator\"></span></th>\n <th>Status</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate external dependencies section\n */\n htmlExternalDependenciesSection(endpoints: ExternalEndpoint[] | undefined): string {\n if (!endpoints || endpoints.length === 0) {\n return `<section id=\"external-dependencies\" class=\"content-section\">\n <h2>External Dependencies</h2>\n <div class=\"empty-state\">No external dependencies detected</div>\n</section>`;\n }\n\n const rows = endpoints.map(endpoint => {\n const riskColor = endpoint.riskLevel === 'Trusted' ? 'success' : endpoint.riskLevel === 'Known' ? 'warning' : 'error';\n const riskFactorsText = endpoint.riskFactors.map(rf => rf.factor).join(', ') || 'None';\n\n return `<tr>\n <td>${this.escapeHtml(endpoint.domain)}</td>\n <td>${this.escapeHtml(endpoint.protocol.toUpperCase())}</td>\n <td><span class=\"badge badge-${riskColor}\">${endpoint.riskLevel}</span></td>\n <td>${endpoint.callCount}</td>\n <td>${this.escapeHtml(riskFactorsText)}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"external-dependencies\" class=\"content-section\">\n <h2>External Dependencies (${endpoints.length})</h2>\n <div class=\"alert alert-info\">\n <strong>â„šī¸ Note:</strong> External API calls can introduce security risks and performance concerns. Review each endpoint carefully.\n </div>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"external-deps-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('external-deps-table', 0)\">Domain <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('external-deps-table', 1)\">Protocol <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('external-deps-table', 2)\">Risk Level <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('external-deps-table', 3)\">Calls <span class=\"sort-indicator\"></span></th>\n <th>Risk Factors</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate cross-entity automation section\n */\n htmlCrossEntitySection(links: CrossEntityLink[] | undefined): string {\n if (!links || links.length === 0) {\n return `<section id=\"cross-entity\" class=\"content-section\">\n <h2>Cross-Entity Automation</h2>\n <div class=\"empty-state\">\n <strong>Note:</strong> Cross-entity automation analysis is coming in a future update.\n </div>\n</section>`;\n }\n\n const rows = links.map(link => {\n return `<tr>\n <td>${this.escapeHtml(link.sourceEntityDisplayName)}</td>\n <td>${this.escapeHtml(link.targetEntityDisplayName)}</td>\n <td>${this.escapeHtml(link.automationType)}</td>\n <td>${this.escapeHtml(link.automationName)}</td>\n <td>${this.escapeHtml(link.operation)}</td>\n <td>${link.isAsynchronous ? 'Async' : 'Sync'}</td>\n</tr>`;\n }).join('\\n');\n\n return `<section id=\"cross-entity\" class=\"content-section\">\n <h2>Cross-Entity Automation (${links.length})</h2>\n <p class=\"section-description\">Automation that operates on multiple entities (e.g., when Contact changes, update related Account)</p>\n <div class=\"table-container\">\n <table class=\"data-table sortable\" id=\"cross-entity-table\">\n <thead>\n <tr>\n <th onclick=\"sortTable('cross-entity-table', 0)\">Source Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('cross-entity-table', 1)\">Target Entity <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('cross-entity-table', 2)\">Type <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('cross-entity-table', 3)\">Name <span class=\"sort-indicator\"></span></th>\n <th onclick=\"sortTable('cross-entity-table', 4)\">Operation <span class=\"sort-indicator\"></span></th>\n <th>Mode</th>\n </tr>\n </thead>\n <tbody>\n${rows}\n </tbody>\n </table>\n </div>\n</section>`;\n }\n\n /**\n * Generate footer\n */\n htmlFooter(): string {\n return `<footer class=\"report-footer\" role=\"contentinfo\">\n <p>Generated by <strong>Power Platform Solution Blueprint (PPSB)</strong></p>\n <p>For PPTB Desktop | <a href=\"https://powerplatformtoolbox.com\" target=\"_blank\">powerplatformtoolbox.com</a></p>\n</footer>`;\n }\n\n /**\n * Generate embedded JavaScript\n */\n htmlScripts(): string {\n return `<script>\n${this.embeddedJavaScript()}\n</script>`;\n }\n\n /**\n * Embedded CSS styles\n */\n private embeddedCSS(): string {\n return ` /* Base styles */\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n line-height: 1.6;\n color: #242424;\n background-color: #fafafa;\n margin: 0;\n padding: 0;\n }\n\n /* Sidebar navigation */\n .sidebar {\n position: fixed;\n top: 0;\n left: 0;\n width: 250px;\n height: 100vh;\n background: #323130;\n color: white;\n overflow-y: auto;\n z-index: 1000;\n padding: 20px 0;\n }\n\n .sidebar-header {\n padding: 0 20px 20px;\n border-bottom: 1px solid #484644;\n }\n\n .sidebar-header h3 {\n color: white;\n font-size: 1.2rem;\n margin-bottom: 10px;\n }\n\n .nav-toggle {\n display: none;\n background: transparent;\n border: 1px solid white;\n color: white;\n padding: 5px 10px;\n cursor: pointer;\n border-radius: 4px;\n }\n\n .nav-links {\n list-style: none;\n padding: 10px 0;\n }\n\n .nav-links li {\n margin: 0;\n }\n\n .nav-links a {\n display: block;\n padding: 10px 20px;\n color: #e1dfdd;\n text-decoration: none;\n transition: background-color 0.2s, color 0.2s;\n }\n\n .nav-links a:hover {\n background-color: #484644;\n color: white;\n }\n\n .nav-footer {\n padding: 20px;\n border-top: 1px solid #484644;\n margin-top: 20px;\n }\n\n .btn-print {\n width: 100%;\n padding: 10px;\n background: #0078d4;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.9rem;\n }\n\n .btn-print:hover {\n background: #106ebe;\n }\n\n /* Main content */\n main {\n margin-left: 250px;\n padding: 30px;\n max-width: 1400px;\n }\n\n /* Header */\n .report-header {\n background: white;\n padding: 30px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n margin-bottom: 30px;\n }\n\n .report-header h1 {\n color: #0078d4;\n font-size: 2rem;\n margin-bottom: 20px;\n }\n\n .metadata-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 15px;\n }\n\n .metadata-item {\n padding: 10px;\n background: #f3f2f1;\n border-radius: 4px;\n }\n\n .metadata-label {\n font-weight: 600;\n color: #605e5c;\n display: block;\n font-size: 0.9rem;\n }\n\n .metadata-value {\n font-size: 1.1rem;\n color: #242424;\n display: block;\n margin-top: 5px;\n }\n\n /* Content sections */\n .content-section {\n background: white;\n padding: 30px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n margin-bottom: 30px;\n }\n\n .content-section h2 {\n color: #323130;\n font-size: 1.75rem;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 2px solid #0078d4;\n }\n\n .section-description {\n color: #605e5c;\n margin-bottom: 20px;\n }\n\n /* Summary cards */\n .summary-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 20px;\n }\n\n .summary-card {\n background: linear-gradient(135deg, #0078d4 0%, #106ebe 100%);\n color: white;\n padding: 20px;\n border-radius: 8px;\n text-align: center;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n }\n\n .summary-card.card-warning {\n background: linear-gradient(135deg, #ffb900 0%, #e3008c 100%);\n }\n\n .card-number {\n font-size: 2.5rem;\n font-weight: bold;\n margin-bottom: 5px;\n }\n\n .card-label {\n font-size: 0.9rem;\n opacity: 0.95;\n }\n\n /* ERD */\n .erd-legend {\n background: #f3f2f1;\n padding: 15px;\n border-radius: 4px;\n margin-bottom: 20px;\n }\n\n .erd-legend h4 {\n margin-bottom: 10px;\n color: #323130;\n }\n\n .legend-items {\n display: flex;\n flex-wrap: wrap;\n gap: 15px;\n }\n\n .legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .legend-color {\n width: 20px;\n height: 20px;\n border-radius: 4px;\n border: 1px solid #d1d1d1;\n }\n\n .legend-label {\n font-size: 0.9rem;\n }\n\n .erd-diagram {\n margin-bottom: 40px;\n }\n\n .erd-diagram h3 {\n color: #323130;\n margin-bottom: 10px;\n }\n\n .diagram-description {\n color: #605e5c;\n margin-bottom: 15px;\n }\n\n .diagram-stats {\n color: #605e5c;\n font-size: 0.9rem;\n margin-top: 10px;\n }\n\n /* Accordion */\n .accordion-item {\n border: 1px solid #edebe9;\n border-radius: 4px;\n margin-bottom: 10px;\n overflow: hidden;\n }\n\n .accordion-header {\n background: #f3f2f1;\n padding: 15px 20px;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 10px;\n transition: background-color 0.2s;\n }\n\n .accordion-header:hover {\n background: #edebe9;\n }\n\n .accordion-icon {\n font-weight: bold;\n font-size: 1.2rem;\n width: 20px;\n text-align: center;\n color: #0078d4;\n }\n\n .accordion-header h3 {\n flex: 1;\n font-size: 1.1rem;\n color: #323130;\n margin: 0;\n }\n\n .entity-badges {\n display: flex;\n gap: 8px;\n }\n\n .accordion-content {\n padding: 20px;\n border-top: 1px solid #edebe9;\n }\n\n .entity-details {\n margin-bottom: 20px;\n padding: 15px;\n background: #faf9f8;\n border-radius: 4px;\n }\n\n .entity-details p {\n margin: 5px 0;\n color: #323130;\n }\n\n .entity-subsection {\n margin-top: 20px;\n }\n\n .entity-subsection h4 {\n color: #323130;\n margin-bottom: 10px;\n font-size: 1rem;\n }\n\n /* Entity Tabs */\n .entity-tabs {\n margin-top: 15px;\n }\n\n .tabs-header {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #edebe9;\n margin-bottom: 20px;\n }\n\n .tab-button {\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 3px solid transparent;\n cursor: pointer;\n font-size: 0.95rem;\n font-weight: 500;\n color: #605e5c;\n transition: all 0.2s;\n }\n\n .tab-button:hover {\n color: #323130;\n background: #faf9f8;\n }\n\n .tab-button.active {\n color: #0078d4;\n border-bottom-color: #0078d4;\n font-weight: 600;\n }\n\n .tab-content {\n display: none;\n }\n\n .tab-content.active {\n display: block;\n }\n\n /* Entity Overview */\n .entity-description {\n padding: 15px;\n background: #fff3cd;\n border-left: 4px solid #ffc107;\n margin-bottom: 20px;\n border-radius: 4px;\n color: #323130;\n }\n\n .entity-metadata {\n margin-bottom: 20px;\n }\n\n .metadata-table {\n width: 100%;\n border-collapse: collapse;\n }\n\n .metadata-table th {\n text-align: left;\n padding: 8px 12px;\n font-weight: 600;\n color: #605e5c;\n width: 40%;\n background: #faf9f8;\n }\n\n .metadata-table td {\n padding: 8px 12px;\n color: #323130;\n }\n\n .metadata-table tr {\n border-bottom: 1px solid #edebe9;\n }\n\n .automation-summary {\n background: #f3f2f1;\n padding: 15px;\n border-radius: 4px;\n }\n\n .summary-row {\n display: flex;\n justify-content: space-between;\n padding: 8px 0;\n border-bottom: 1px solid #e1dfdd;\n }\n\n .summary-row:last-child {\n border-bottom: none;\n }\n\n .summary-label {\n font-weight: 500;\n color: #605e5c;\n }\n\n .summary-value {\n font-weight: 600;\n color: #0078d4;\n }\n\n /* Pipeline Visualization */\n .pipeline-intro {\n margin-bottom: 20px;\n padding: 15px;\n background: #e7f3ff;\n border-left: 4px solid #0078d4;\n border-radius: 4px;\n }\n\n .pipeline-message {\n margin-bottom: 30px;\n padding: 20px;\n background: #fafafa;\n border-radius: 4px;\n }\n\n .pipeline-message h4 {\n color: #323130;\n margin-bottom: 15px;\n padding-bottom: 10px;\n border-bottom: 2px solid #edebe9;\n }\n\n .pipeline-message h5 {\n color: #323130;\n margin: 20px 0 10px;\n }\n\n .pipeline-visual {\n margin: 20px 0;\n padding: 15px;\n background: white;\n border: 1px solid #edebe9;\n border-radius: 4px;\n }\n\n .pipeline-stage {\n margin-bottom: 15px;\n border-left: 4px solid #d1d1d1;\n padding-left: 15px;\n }\n\n .stage-business-rules {\n border-left-color: #ffc107;\n }\n\n .stage-prevalidation {\n border-left-color: #dc3545;\n }\n\n .stage-preoperation {\n border-left-color: #fd7e14;\n }\n\n .stage-mainoperation {\n border-left-color: #0078d4;\n }\n\n .stage-postoperation {\n border-left-color: #28a745;\n }\n\n .stage-header {\n font-weight: 600;\n color: #323130;\n margin-bottom: 10px;\n font-size: 0.95rem;\n }\n\n .stage-steps {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .pipeline-step {\n padding: 10px 15px;\n background: #fafafa;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n }\n\n .step-sync {\n border-left: 3px solid #dc3545;\n }\n\n .step-async {\n border-left: 3px solid #28a745;\n }\n\n .step-active {\n border-left: 3px solid #28a745;\n }\n\n .step-draft {\n border-left: 3px solid #ffc107;\n }\n\n .step-badge {\n padding: 2px 8px;\n border-radius: 3px;\n font-size: 0.75rem;\n font-weight: 600;\n white-space: nowrap;\n }\n\n .badge-sync {\n background: #f8d7da;\n color: #721c24;\n }\n\n .badge-async {\n background: #d4edda;\n color: #155724;\n }\n\n .badge-active {\n background: #d4edda;\n color: #155724;\n }\n\n .badge-draft {\n background: #fff3cd;\n color: #856404;\n }\n\n .step-rank {\n font-size: 0.85rem;\n color: #605e5c;\n }\n\n .info-box {\n margin: 15px 0;\n padding: 15px;\n background: #e7f3ff;\n border-left: 4px solid #0078d4;\n border-radius: 4px;\n }\n\n .info-box strong {\n display: block;\n margin-bottom: 5px;\n color: #323130;\n }\n\n .info-box p {\n margin: 0;\n color: #605e5c;\n }\n\n .pipeline-table {\n margin-top: 15px;\n }\n\n .relationship-section {\n margin-top: 15px;\n }\n\n .relationship-section h5 {\n color: #323130;\n margin-bottom: 10px;\n font-size: 0.95rem;\n }\n\n .table-note {\n margin-top: 10px;\n color: #605e5c;\n font-size: 0.9rem;\n font-style: italic;\n }\n\n /* Tables */\n .table-container {\n overflow-x: auto;\n }\n\n .data-table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 15px;\n }\n\n .data-table thead {\n background: #f3f2f1;\n }\n\n .data-table th {\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: #323130;\n border-bottom: 2px solid #d1d1d1;\n cursor: pointer;\n user-select: none;\n position: relative;\n }\n\n .data-table th:hover {\n background: #edebe9;\n }\n\n .sort-indicator {\n margin-left: 5px;\n color: #605e5c;\n font-size: 0.8rem;\n }\n\n .data-table td {\n padding: 12px;\n border-bottom: 1px solid #edebe9;\n color: #323130;\n }\n\n .data-table tbody tr:hover {\n background: #faf9f8;\n }\n\n .data-table tbody tr:nth-child(even) {\n background: #f9f9f9;\n }\n\n .data-table tbody tr:nth-child(even):hover {\n background: #f3f2f1;\n }\n\n .table-note {\n margin-top: 10px;\n color: #605e5c;\n font-size: 0.9rem;\n font-style: italic;\n }\n\n /* Badges */\n .badge {\n display: inline-block;\n padding: 4px 10px;\n border-radius: 12px;\n font-size: 0.8rem;\n font-weight: 600;\n white-space: nowrap;\n }\n\n .badge-success {\n background: #dff6dd;\n color: #107c10;\n }\n\n .badge-warning {\n background: #fff4ce;\n color: #8a5100;\n }\n\n .badge-error {\n background: #fde7e9;\n color: #d13438;\n }\n\n .badge-info {\n background: #cfe4f7;\n color: #004578;\n }\n\n .badge-primary {\n background: #deecf9;\n color: #0078d4;\n }\n\n /* Security-specific styles */\n .profile-badge {\n display: inline-block;\n padding: 6px 12px;\n margin: 4px;\n background: #f3f2f1;\n border: 1px solid #d2d0ce;\n border-radius: 4px;\n font-size: 0.85rem;\n }\n\n .profile-badge .permissions {\n color: #0078d4;\n font-weight: 600;\n margin-left: 4px;\n }\n\n .legend {\n padding: 12px;\n background: #faf9f8;\n border-left: 3px solid #0078d4;\n border-radius: 4px;\n font-size: 0.9rem;\n color: #605e5c;\n margin-top: 10px;\n }\n\n .center {\n text-align: center;\n }\n\n /* Alerts */\n .alert {\n padding: 15px 20px;\n border-radius: 4px;\n margin-bottom: 20px;\n }\n\n .alert-warning {\n background: #fff4ce;\n border-left: 4px solid #ffb900;\n color: #3d2e00;\n }\n\n .alert-info {\n background: #deecf9;\n border-left: 4px solid #0078d4;\n color: #004578;\n }\n\n .alert strong {\n display: block;\n margin-bottom: 5px;\n }\n\n /* Empty state */\n .empty-state {\n text-align: center;\n padding: 40px;\n color: #605e5c;\n font-style: italic;\n }\n\n /* Footer */\n .report-footer {\n text-align: center;\n padding: 30px;\n color: #605e5c;\n font-size: 0.9rem;\n margin-top: 40px;\n border-top: 1px solid #edebe9;\n }\n\n .report-footer a {\n color: #0078d4;\n text-decoration: none;\n }\n\n .report-footer a:hover {\n text-decoration: underline;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .sidebar {\n transform: translateX(-100%);\n transition: transform 0.3s;\n }\n\n .sidebar.open {\n transform: translateX(0);\n }\n\n .nav-toggle {\n display: inline-block;\n }\n\n main {\n margin-left: 0;\n padding: 15px;\n }\n\n .metadata-grid {\n grid-template-columns: 1fr;\n }\n\n .summary-grid {\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n }\n }\n\n /* Print styles */\n @media print {\n .sidebar,\n .nav-toggle,\n .btn-print {\n display: none !important;\n }\n\n main {\n margin-left: 0;\n padding: 0;\n }\n\n .content-section {\n page-break-inside: avoid;\n box-shadow: none;\n }\n\n .accordion-content {\n display: block !important;\n }\n\n .accordion-icon {\n display: none;\n }\n\n body {\n background: white;\n }\n }`;\n }\n\n /**\n * Embedded JavaScript for interactivity\n */\n private embeddedJavaScript(): string {\n return ` // Initialize Mermaid\n mermaid.initialize({\n startOnLoad: true,\n theme: 'default',\n securityLevel: 'loose',\n flowchart: {\n useMaxWidth: true,\n htmlLabels: true\n }\n });\n\n // Accordion toggle\n function toggleAccordion(id) {\n const content = document.getElementById(id);\n const icon = document.getElementById('icon-' + id);\n\n if (content.style.display === 'none' || content.style.display === '') {\n content.style.display = 'block';\n icon.textContent = '−';\n } else {\n content.style.display = 'none';\n icon.textContent = '+';\n }\n }\n\n // Table sorting\n function sortTable(tableId, columnIndex) {\n const table = document.getElementById(tableId);\n const tbody = table.querySelector('tbody');\n const rows = Array.from(tbody.querySelectorAll('tr'));\n const header = table.querySelectorAll('th')[columnIndex];\n const isAscending = header.classList.contains('sort-asc');\n\n // Clear all sort indicators\n table.querySelectorAll('th').forEach(th => {\n th.classList.remove('sort-asc', 'sort-desc');\n const indicator = th.querySelector('.sort-indicator');\n if (indicator) indicator.textContent = '';\n });\n\n // Sort rows\n rows.sort((a, b) => {\n const aVal = a.cells[columnIndex].textContent.trim();\n const bVal = b.cells[columnIndex].textContent.trim();\n\n // Try to parse as number\n const aNum = parseFloat(aVal.replace(/[^0-9.-]/g, ''));\n const bNum = parseFloat(bVal.replace(/[^0-9.-]/g, ''));\n\n if (!isNaN(aNum) && !isNaN(bNum)) {\n return isAscending ? bNum - aNum : aNum - bNum;\n }\n\n // String comparison\n return isAscending ? bVal.localeCompare(aVal) : aVal.localeCompare(bVal);\n });\n\n // Update DOM\n rows.forEach(row => tbody.appendChild(row));\n\n // Update sort indicator\n if (isAscending) {\n header.classList.add('sort-desc');\n header.querySelector('.sort-indicator').textContent = 'â–ŧ';\n } else {\n header.classList.add('sort-asc');\n header.querySelector('.sort-indicator').textContent = '▲';\n }\n }\n\n // Smooth scroll for navigation\n document.querySelectorAll('.nav-links a').forEach(link => {\n link.addEventListener('click', function(e) {\n e.preventDefault();\n const targetId = this.getAttribute('href').substring(1);\n const targetElement = document.getElementById(targetId);\n\n if (targetElement) {\n targetElement.scrollIntoView({\n behavior: 'smooth',\n block: 'start'\n });\n }\n });\n });\n\n // Mobile navigation toggle\n const navToggle = document.getElementById('navToggle');\n const sidebar = document.getElementById('sidebar');\n\n if (navToggle && sidebar) {\n navToggle.addEventListener('click', function() {\n sidebar.classList.toggle('open');\n });\n\n // Close sidebar when clicking outside on mobile\n document.addEventListener('click', function(e) {\n if (window.innerWidth <= 768) {\n if (!sidebar.contains(e.target) && !navToggle.contains(e.target)) {\n sidebar.classList.remove('open');\n }\n }\n });\n }\n\n // Entity tab switching\n function switchEntityTab(entityId, tabName) {\n // Hide all tab contents for this entity\n const allTabContents = document.querySelectorAll('[id^=\"' + entityId + '-\"]');\n allTabContents.forEach(tab => {\n tab.classList.remove('active');\n });\n\n // Remove active class from all tab buttons in this entity\n const entityAccordion = document.getElementById(entityId);\n if (entityAccordion) {\n const tabButtons = entityAccordion.parentElement.querySelectorAll('.tab-button');\n tabButtons.forEach(btn => {\n btn.classList.remove('active');\n });\n }\n\n // Show selected tab content\n const selectedTab = document.getElementById(entityId + '-' + tabName);\n if (selectedTab) {\n selectedTab.classList.add('active');\n }\n\n // Add active class to clicked button\n event.target.classList.add('active');\n }\n\n // Security tab switching\n function switchTab(sectionId, tabName) {\n // Hide all tab contents in this section\n const section = document.getElementById(sectionId);\n if (section) {\n const allTabs = section.querySelectorAll('.tab-content');\n allTabs.forEach(tab => {\n tab.classList.remove('active');\n });\n\n // Remove active class from all tab buttons in this section\n const tabButtons = section.querySelectorAll('.tab-button');\n tabButtons.forEach(btn => {\n btn.classList.remove('active');\n });\n\n // Show selected tab content\n const selectedTab = document.getElementById(sectionId + '-' + tabName);\n if (selectedTab) {\n selectedTab.classList.add('active');\n }\n\n // Add active class to clicked button\n event.target.classList.add('active');\n }\n }`;\n }\n\n /**\n * Generate Security section (roles and field security profiles)\n */\n htmlSecuritySection(\n securityRoles?: import('../../discovery/SecurityRoleDiscovery.js').SecurityRoleDetail[],\n fieldSecurityProfiles?: import('../../discovery/FieldSecurityProfileDiscovery.js').FieldSecurityProfile[],\n attributeMaskingRules?: import('../../discovery/ColumnSecurityDiscovery.js').AttributeMaskingRule[],\n columnSecurityProfiles?: import('../../discovery/ColumnSecurityDiscovery.js').ColumnSecurityProfile[]\n ): string {\n if (!securityRoles && !fieldSecurityProfiles && !attributeMaskingRules && !columnSecurityProfiles) {\n return '';\n }\n\n if (!securityRoles?.length && !fieldSecurityProfiles?.length && !attributeMaskingRules?.length && !columnSecurityProfiles?.length) {\n return '';\n }\n\n let html = `\n <section id=\"security\" class=\"content-section\">\n <h2 class=\"section-title\">🔒 Security</h2>\n <p class=\"section-description\">Security roles and field security profiles in the selected solution(s).</p>\n\n <div class=\"tabs-container\">\n <div class=\"tabs\">`;\n\n // Add tabs\n const hasRoles = securityRoles && securityRoles.length > 0;\n const hasProfiles = fieldSecurityProfiles && fieldSecurityProfiles.length > 0;\n const hasMasking = attributeMaskingRules && attributeMaskingRules.length > 0;\n const hasColumnSecurity = columnSecurityProfiles && columnSecurityProfiles.length > 0;\n const firstTab = hasRoles ? 'roles' : hasProfiles ? 'profiles' : hasMasking ? 'masking' : 'columnsecurity';\n\n if (hasRoles) {\n html += `<button class=\"tab-button active\" onclick=\"switchTab('security', 'roles')\">Security Roles (${securityRoles.length})</button>`;\n }\n if (hasProfiles) {\n html += `<button class=\"tab-button${firstTab === 'profiles' ? ' active' : ''}\" onclick=\"switchTab('security', 'profiles')\">Field Security Profiles (${fieldSecurityProfiles.length})</button>`;\n }\n if (hasMasking) {\n html += `<button class=\"tab-button${firstTab === 'masking' ? ' active' : ''}\" onclick=\"switchTab('security', 'masking')\">Attribute Masking (${attributeMaskingRules.length})</button>`;\n }\n if (hasColumnSecurity) {\n html += `<button class=\"tab-button${firstTab === 'columnsecurity' ? ' active' : ''}\" onclick=\"switchTab('security', 'columnsecurity')\">Column Security (${columnSecurityProfiles.length})</button>`;\n }\n\n html += `</div>`;\n\n // Security Roles Tab\n if (securityRoles && securityRoles.length > 0) {\n html += `\n <div class=\"tab-content${firstTab === 'roles' ? ' active' : ''}\" id=\"security-roles\">\n <h3>Security Roles</h3>\n\n <div class=\"subsection\">\n <h4>Special Permissions Matrix</h4>\n <p>This table shows which security roles have special/miscellaneous permissions.</p>\n ${this.generateSpecialPermissionsTable(securityRoles)}\n </div>\n\n <div class=\"subsection\">\n <h4>Role Details</h4>\n ${this.generateSecurityRolesAccordion(securityRoles)}\n </div>\n </div>`;\n }\n\n // Field Security Profiles Tab\n if (fieldSecurityProfiles && fieldSecurityProfiles.length > 0) {\n html += `\n <div class=\"tab-content${firstTab === 'profiles' ? ' active' : ''}\" id=\"security-profiles\">\n <h3>Field Security Profiles</h3>\n <p>Field security profiles control who can read, create, or update specific secured fields.</p>\n ${this.generateFieldSecurityProfilesTable(fieldSecurityProfiles)}\n <p class=\"legend\"><strong>Note:</strong> Field-level permissions for specific entities are documented in each entity's schema tab.</p>\n </div>`;\n }\n\n // Attribute Masking Tab\n if (attributeMaskingRules && attributeMaskingRules.length > 0) {\n html += `\n <div class=\"tab-content${firstTab === 'masking' ? ' active' : ''}\" id=\"security-masking\">\n <h3>Attribute Masking Rules</h3>\n <p>Attribute masking rules control how sensitive data is masked when displayed to users without appropriate permissions.</p>\n ${this.generateAttributeMaskingTable(attributeMaskingRules)}\n <p class=\"legend\"><strong>Masking Types:</strong> Full = Entire value masked, Partial = Part of value shown, Email = Email format preserved, Custom = Custom masking format</p>\n </div>`;\n }\n\n // Column Security Profiles Tab\n if (columnSecurityProfiles && columnSecurityProfiles.length > 0) {\n html += `\n <div class=\"tab-content${firstTab === 'columnsecurity' ? ' active' : ''}\" id=\"security-columnsecurity\">\n <h3>Column Security Profiles</h3>\n <p>Column security profiles define which users can access specific secured columns across entities.</p>\n ${this.generateColumnSecurityTable(columnSecurityProfiles)}\n <p class=\"legend\"><strong>Note:</strong> Column-level permissions control create, read, and update access to secured fields.</p>\n </div>`;\n }\n\n html += `\n </div>\n </section>`;\n\n return html;\n }\n\n /**\n * Generate special permissions matrix table\n */\n private generateSpecialPermissionsTable(securityRoles: import('../../discovery/SecurityRoleDiscovery.js').SecurityRoleDetail[]): string {\n const specialPermissionKeys: Array<keyof import('../../discovery/SecurityRoleDiscovery.js').SpecialPermissions> = [\n 'documentGeneration',\n 'dynamics365ForMobile',\n 'exportToExcel',\n 'goOfflineInOutlook',\n 'mailMerge',\n 'print',\n 'syncToOutlook',\n 'useDynamics365AppForOutlook',\n 'activateRealtimeProcesses',\n 'executeWorkflowJob',\n 'runFlows',\n ];\n\n let html = `\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Role Name</th>\n <th>Business Unit</th>`;\n\n for (const key of specialPermissionKeys) {\n html += `<th>${this.formatSpecialPermissionName(key)}</th>`;\n }\n\n html += `\n </tr>\n </thead>\n <tbody>`;\n\n for (const role of securityRoles) {\n html += `\n <tr>\n <td><strong>${this.escapeHtml(role.name)}</strong></td>\n <td>${this.escapeHtml(role.businessunitname || 'Unknown')}</td>`;\n\n for (const key of specialPermissionKeys) {\n html += `<td class=\"center\">${role.specialPermissions[key] ? '✓' : ''}</td>`;\n }\n\n html += `</tr>`;\n }\n\n html += `\n </tbody>\n </table>`;\n\n return html;\n }\n\n /**\n * Generate security roles accordion with entity permissions\n */\n private generateSecurityRolesAccordion(securityRoles: import('../../discovery/SecurityRoleDiscovery.js').SecurityRoleDetail[]): string {\n let html = '<div class=\"accordion\">';\n\n for (let i = 0; i < securityRoles.length; i++) {\n const role = securityRoles[i];\n html += `\n <div class=\"accordion-item\">\n <div class=\"accordion-header\" onclick=\"toggleAccordion('role-${i}')\">\n <span class=\"accordion-icon\" id=\"icon-role-${i}\">+</span>\n <div class=\"accordion-title\">\n <strong>${this.escapeHtml(role.name)}</strong>\n <span class=\"badge\">${role.totalEntities} entities</span>\n ${role.hasSystemAdminPrivileges ? '<span class=\"badge badge-warning\">System Admin</span>' : ''}\n ${role.ismanaged ? '<span class=\"badge badge-info\">Managed</span>' : ''}\n </div>\n </div>\n <div class=\"accordion-content\" id=\"role-${i}\" style=\"display: none;\">\n <p><strong>Business Unit:</strong> ${this.escapeHtml(role.businessunitname || 'Unknown')}</p>\n ${role.description ? `<p><strong>Description:</strong> ${this.escapeHtml(role.description)}</p>` : ''}\n\n <h5>Entity Permissions</h5>\n ${this.generateEntityPermissionsTable(role.entityPermissions)}\n </div>\n </div>`;\n }\n\n html += '</div>';\n return html;\n }\n\n /**\n * Generate entity permissions table for a security role\n */\n private generateEntityPermissionsTable(entityPermissions: import('../../discovery/SecurityRoleDiscovery.js').EntityPermission[]): string {\n if (entityPermissions.length === 0) {\n return '<p class=\"empty-state\">No entity permissions defined</p>';\n }\n\n let html = `\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Create</th>\n <th>Read</th>\n <th>Write</th>\n <th>Delete</th>\n <th>Append</th>\n <th>AppendTo</th>\n <th>Assign</th>\n <th>Share</th>\n </tr>\n </thead>\n <tbody>`;\n\n for (const entityPerm of entityPermissions) {\n // Skip entities with no privileges\n if (entityPerm.privileges.length === 0) {\n continue;\n }\n\n const privMap = new Map(entityPerm.privileges.map(p => [p.type, p]));\n\n html += `\n <tr>\n <td><strong>${this.escapeHtml(entityPerm.entityLogicalName)}</strong></td>`;\n\n for (const type of ['Create', 'Read', 'Write', 'Delete', 'Append', 'AppendTo', 'Assign', 'Share']) {\n const priv = privMap.get(type as any);\n html += `<td class=\"center\">${priv ? this.escapeHtml(priv.depth) : ''}</td>`;\n }\n\n html += `</tr>`;\n }\n\n html += `\n </tbody>\n </table>\n <p class=\"legend\"><strong>Privilege Depth:</strong> Basic = User, Local = Business Unit, Deep = Parent+Child BU, Global = Organization</p>`;\n\n return html;\n }\n\n /**\n * Generate field security profiles table\n */\n private generateFieldSecurityProfilesTable(fieldSecurityProfiles: import('../../discovery/FieldSecurityProfileDiscovery.js').FieldSecurityProfile[]): string {\n let html = `\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Profile Name</th>\n <th>Description</th>\n </tr>\n </thead>\n <tbody>`;\n\n for (const profile of fieldSecurityProfiles) {\n html += `\n <tr>\n <td><strong>${this.escapeHtml(profile.name)}</strong></td>\n <td>${profile.description ? this.escapeHtml(profile.description) : '<em>No description</em>'}</td>\n </tr>`;\n }\n\n html += `\n </tbody>\n </table>`;\n\n return html;\n }\n\n /**\n * Generate attribute masking rules table\n */\n private generateAttributeMaskingTable(attributeMaskingRules: import('../../discovery/ColumnSecurityDiscovery.js').AttributeMaskingRule[]): string {\n let html = `\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Entity</th>\n <th>Attribute</th>\n <th>Masking Type</th>\n <th>Managed</th>\n </tr>\n </thead>\n <tbody>`;\n\n for (const rule of attributeMaskingRules) {\n const maskingType = rule.maskingtype === 1 ? 'Full' : rule.maskingtype === 2 ? 'Partial' : rule.maskingtype === 3 ? 'Email' : 'Custom';\n html += `\n <tr>\n <td><strong>${this.escapeHtml(rule.entitylogicalname)}</strong></td>\n <td>${this.escapeHtml(rule.attributelogicalname)}</td>\n <td><span class=\"badge\">${maskingType}</span></td>\n <td>${rule.ismanaged ? '<span class=\"badge\">Managed</span>' : ''}</td>\n </tr>`;\n }\n\n html += `\n </tbody>\n </table>`;\n\n return html;\n }\n\n /**\n * Generate column security profiles table\n */\n private generateColumnSecurityTable(columnSecurityProfiles: import('../../discovery/ColumnSecurityDiscovery.js').ColumnSecurityProfile[]): string {\n let html = `\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Profile Name</th>\n <th>Description</th>\n <th>Managed</th>\n </tr>\n </thead>\n <tbody>`;\n\n for (const profile of columnSecurityProfiles) {\n html += `\n <tr>\n <td><strong>${this.escapeHtml(profile.name)}</strong></td>\n <td>${profile.description ? this.escapeHtml(profile.description) : '<em>No description</em>'}</td>\n <td>${profile.ismanaged ? '<span class=\"badge\">Managed</span>' : ''}</td>\n </tr>`;\n }\n\n html += `\n </tbody>\n </table>`;\n\n return html;\n }\n\n /**\n * Format special permission name for display\n */\n private formatSpecialPermissionName(key: string): string {\n // Convert camelCase to Title Case with spaces\n return key\n .replace(/([A-Z])/g, ' $1')\n .replace(/^./, str => str.toUpperCase())\n .trim();\n }\n\n /**\n * Generate field security section for entity schema\n */\n private generateFieldSecuritySection(fieldSecurity: import('../../types/blueprint.js').EntityBlueprint['fieldSecurity']): string {\n if (!fieldSecurity || fieldSecurity.securedFields.length === 0) {\n return '';\n }\n\n let html = `\n <div class=\"entity-subsection\">\n <h4>đŸ›Ąī¸ Field Security (${fieldSecurity.securedFields.length} secured field${fieldSecurity.securedFields.length > 1 ? 's' : ''})</h4>\n <p class=\"subsection-description\">The following fields have field-level security permissions:</p>\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Field</th>\n <th>Profiles with Access</th>\n </tr>\n </thead>\n <tbody>`;\n\n for (const securedField of fieldSecurity.securedFields) {\n const profileDetails = securedField.profiles.map(p => {\n const permissions = [];\n if (p.canRead) permissions.push('R');\n if (p.canCreate) permissions.push('C');\n if (p.canUpdate) permissions.push('U');\n return `<div class=\"profile-badge\">${this.escapeHtml(p.profileName)} <span class=\"permissions\">(${permissions.join(', ')})</span></div>`;\n }).join('');\n\n html += `\n <tr>\n <td><strong>${this.escapeHtml(securedField.attributeLogicalName)}</strong></td>\n <td>${profileDetails}</td>\n </tr>`;\n }\n\n html += `\n </tbody>\n </table>\n <p class=\"legend\"><strong>Permissions:</strong> R = Read, C = Create, U = Update</p>\n </div>`;\n\n return html;\n }\n\n /**\n * Escape HTML special characters\n */\n private escapeHtml(text: string): string {\n const textNode = text || '';\n return textNode\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n }\n}\n","/**\n * HTML Reporter - Generates single-page interactive HTML blueprint\n *\n * Features:\n * - Self-contained HTML file (no external dependencies except Mermaid CDN)\n * - Sidebar navigation with smooth scrolling\n * - Interactive accordion for entities\n * - Sortable tables\n * - Responsive design (mobile-friendly)\n * - Print-optimized styles\n * - Professional Fluent UI-inspired design\n *\n * Use cases:\n * - Sharing with stakeholders (single HTML file)\n * - Offline viewing\n * - Presentation mode\n * - Documentation website\n * - Quick review and navigation\n */\nimport type { BlueprintResult } from '../types/blueprint.js';\nimport { HtmlTemplates } from './html/HtmlTemplates.js';\n\nexport class HtmlReporter {\n private templates: HtmlTemplates;\n\n constructor() {\n this.templates = new HtmlTemplates();\n }\n\n /**\n * Generate complete HTML blueprint document\n * @param result Complete blueprint result\n * @returns Self-contained HTML string\n */\n generate(result: BlueprintResult): string {\n // Build all sections\n const head = this.templates.htmlHead(result);\n const nav = this.templates.htmlNavigation();\n const header = this.templates.htmlHeader(result.metadata);\n const summary = this.templates.htmlSummary(result.summary);\n const erd = this.templates.htmlErdSection(result.erd);\n const entities = this.templates.htmlEntitiesAccordion(result.entities);\n const plugins = this.templates.htmlPluginsTable(result.plugins);\n const flows = this.templates.htmlFlowsTable(result.flows);\n const businessRules = this.templates.htmlBusinessRulesTable(result.businessRules);\n const classicWorkflows = this.templates.htmlClassicWorkflowsTable(result.classicWorkflows);\n const businessProcessFlows = this.templates.htmlBusinessProcessFlowsTable(result.businessProcessFlows);\n const webResources = this.templates.htmlWebResourcesTable(result.webResources);\n const customAPIs = this.templates.htmlCustomAPIsTable(result.customAPIs);\n const environmentVariables = this.templates.htmlEnvironmentVariablesTable(result.environmentVariables);\n const connectionReferences = this.templates.htmlConnectionReferencesTable(result.connectionReferences);\n const externalDependencies = this.templates.htmlExternalDependenciesSection(result.externalEndpoints);\n const crossEntity = this.templates.htmlCrossEntitySection(result.crossEntityLinks);\n const security = this.templates.htmlSecuritySection(\n result.securityRoles,\n result.fieldSecurityProfiles,\n result.attributeMaskingRules,\n result.columnSecurityProfiles\n );\n const footer = this.templates.htmlFooter();\n const scripts = this.templates.htmlScripts();\n\n // Combine into complete HTML document\n return `<!DOCTYPE html>\n<html lang=\"en\">\n${head}\n<body>\n ${nav}\n <main>\n ${header}\n ${summary}\n ${erd}\n ${entities}\n ${plugins}\n ${flows}\n ${businessRules}\n ${classicWorkflows}\n ${businessProcessFlows}\n ${webResources}\n ${customAPIs}\n ${environmentVariables}\n ${connectionReferences}\n ${security}\n ${externalDependencies}\n ${crossEntity}\n </main>\n ${footer}\n ${scripts}\n</body>\n</html>`;\n }\n}\n"],"names":["HtmlTemplates","result","title","metadata","generatedDate","erd","legendHtml","diagram","diagramHtml","legend","item","summary","entities","accordionItems","entityBp","index","_a","_b","_c","_d","_e","_f","entity","displayName","attributeCount","pluginCount","flowCount","brCount","hasExecutionPipeline","attributes","rows","attr","description","required","type","moreText","plugins","plugin","flows","flow","br","automationSummary","key","value","oneToMany","manyToOne","manyToMany","content","totalRelationships","pluginsByMessage","entityScopedBRs","dataverseFlows","f","message","sortedPlugins","a","b","byStage","syncPlugins","p","businessRules","html","idx","state","stage","stageName","stageClass","mode","stateBadge","modeBadge","relationships","rel","schemaName","referencingEntity","referencedAttribute","images","imagesText","entityDisplay","hasExternal","rule","conditions","actions","workflows","workflow","complexity","effort","bpfs","bpf","stages","crossEntity","webResources","wr","sizeKB","deprecated","customAPIs","api","binding","params","responses","envVars","envVar","hasValue","connRefs","connRef","connector","connected","endpoints","endpoint","riskColor","riskFactorsText","rf","links","link","securityRoles","fieldSecurityProfiles","attributeMaskingRules","columnSecurityProfiles","hasRoles","hasProfiles","hasMasking","hasColumnSecurity","firstTab","specialPermissionKeys","role","i","entityPermissions","entityPerm","privMap","priv","profile","maskingType","str","fieldSecurity","securedField","profileDetails","permissions","text","HtmlReporter","__publicField","head","nav","header","classicWorkflows","businessProcessFlows","environmentVariables","connectionReferences","externalDependencies","security","footer","scripts"],"mappings":"oKA0BO,MAAMA,CAAc,CAIzB,SAASC,EAAiC,CACxC,MAAMC,EAAQ,eAAeD,EAAO,SAAS,aAAe,gBAAgB,GAC5E,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,WAKA,KAAK,WAAWC,CAAK,CAAC;AAAA;AAAA;AAAA,EAG/B,KAAK,aAAa;AAAA;AAAA,QAGlB,CAKA,gBAAyB,CACvB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OA0BT,CAKA,WAAWC,EAAqC,CAC9C,MAAMC,EAAgBD,EAAS,YAAY,eAAA,EAC3C,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,qCAK0B,KAAK,WAAWA,EAAS,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA,qCAIrC,KAAK,WAAWC,CAAa,CAAC;AAAA;AAAA;AAAA;AAAA,qCAI9B,KAAK,WAAWD,EAAS,MAAM,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA,qCAI3CA,EAAS,WAAW;AAAA;AAAA;AAAA,UAIvD,CAMA,eAAeE,EAAwC,CACrD,GAAI,CAACA,GAAOA,EAAI,SAAS,SAAW,EAClC,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMC,EAAa,KAAK,mBAAmBD,EAAI,MAAM,EAG/CE,EAAUF,EAAI,SAAS,CAAC,EACxBG,EAAc;AAAA,QAChB,KAAK,WAAWD,EAAQ,KAAK,CAAC;AAAA,mCACH,KAAK,WAAWA,EAAQ,WAAW,CAAC;AAAA;AAAA,EAErEA,EAAQ,cAAc;AAAA;AAAA,uCAEeA,EAAQ,WAAW,qBAAqBA,EAAQ,iBAAiB;AAAA,QAGpG,MAAO;AAAA;AAAA,IAEPD,CAAU;AAAA,IACVE,CAAW;AAAA,WAEb,CAKQ,mBAAmBC,EAAuB,CAChD,MAAI,CAACA,GAAUA,EAAO,SAAW,EAAU,GASpC;AAAA;AAAA;AAAA,EAPOA,EAAO,IAAIC,GAChB;AAAA,wDAC2CA,EAAK,KAAK;AAAA,+BACnC,KAAK,WAAWA,EAAK,aAAa,CAAC,KAAKA,EAAK,WAAW;AAAA,OAElF,EAAE,KAAK;AAAA,CAAI,CAKT;AAAA;AAAA,OAGL,CAKA,YAAYC,EAAmC,CAC7C,MAAO;AAAA;AAAA;AAAA;AAAA,iCAIsBA,EAAQ,aAAa;AAAA;AAAA;AAAA;AAAA,iCAIrBA,EAAQ,eAAe;AAAA;AAAA;AAAA;AAAA,iCAIvBA,EAAQ,YAAY;AAAA;AAAA;AAAA;AAAA,iCAIpBA,EAAQ,UAAU;AAAA;AAAA;AAAA;AAAA,iCAIlBA,EAAQ,kBAAkB;AAAA;AAAA;AAAA;AAAA,iCAI1BA,EAAQ,iBAAiB;AAAA;AAAA;AAAA;AAAA,iCAIzBA,EAAQ,eAAe;AAAA;AAAA;AAAA;AAAA,iCAIvBA,EAAQ,kBAAkB;AAAA;AAAA;AAAA;AAAA,iCAI1BA,EAAQ,0BAA0B;AAAA;AAAA;AAAA,+BAGpCA,EAAQ,sBAAwB,EAAI,eAAiB,EAAE;AAAA,iCACrDA,EAAQ,qBAAqB;AAAA;AAAA;AAAA;AAAA,WAK5D,CAKA,sBAAsBC,EAAqC,CACzD,GAAIA,EAAS,SAAW,EACtB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMC,EAAiBD,EAAS,IAAI,CAACE,EAAUC,IAAU,CAlMtD,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAmMD,MAAMC,EAASR,EAAS,OAClBS,IAAcN,GAAAD,EAAAM,EAAO,cAAP,YAAAN,EAAoB,qBAApB,YAAAC,EAAwC,QAASK,EAAO,YACtEE,IAAiBN,EAAAI,EAAO,aAAP,YAAAJ,EAAmB,SAAU,EAC9CO,IAAcN,EAAAL,EAAS,UAAT,YAAAK,EAAkB,SAAU,EAC1CO,IAAYN,EAAAN,EAAS,QAAT,YAAAM,EAAgB,SAAU,EACtCO,IAAUN,EAAAP,EAAS,gBAAT,YAAAO,EAAwB,SAAU,EAG5CO,EAAuB,KAAK,2BAA2Bd,CAAQ,EAErE,MAAO;AAAA,mEACsDC,CAAK;AAAA,mDACrBA,CAAK;AAAA,UAC9C,KAAK,WAAWQ,CAAW,CAAC;AAAA;AAAA,QAE9BC,EAAiB,EAAI,kCAAkCA,CAAc,iBAAmB,EAAE;AAAA,QAC1FC,EAAc,EAAI,qCAAqCA,CAAW,kBAAoB,EAAE;AAAA,QACxFC,EAAY,EAAI,qCAAqCA,CAAS,gBAAkB,EAAE;AAAA,QAClFC,EAAU,EAAI,qCAAqCA,CAAO,gBAAkB,EAAE;AAAA;AAAA;AAAA,8CAGxCZ,CAAK;AAAA;AAAA;AAAA;AAAA,6EAI0BA,CAAK;AAAA,sEACZA,CAAK;AAAA,UACjE,KAAK,oBAAoBD,CAAQ,EAAI,+DAA+DC,CAAK,wCAA0C,EAAE;AAAA,UACrJa,EAAuB,+DAA+Db,CAAK,8CAAgD,EAAE;AAAA;AAAA;AAAA;AAAA,mDAIpGA,CAAK;AAAA,UAC9C,KAAK,0BAA0BD,CAAQ,CAAC;AAAA;AAAA;AAAA;AAAA,4CAINC,CAAK;AAAA,UACvC,KAAK,wBAAwBD,CAAQ,CAAC;AAAA;AAAA;AAAA,QAGxC,KAAK,oBAAoBA,CAAQ,EAAI;AAAA,4CACDC,CAAK;AAAA,UACvC,KAAK,4BAA4BD,CAAQ,CAAC;AAAA,cACpC,EAAE;AAAA;AAAA,QAEVc,EAAuB;AAAA,4CACab,CAAK;AAAA,UACvC,KAAK,0BAA0BD,CAAQ,CAAC;AAAA,cAClC,EAAE;AAAA;AAAA;AAAA,OAId,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,kBACOF,EAAS,MAAM;AAAA;AAAA,EAE/BC,CAAc;AAAA;AAAA,WAGd,CAKQ,wBAAwBgB,EAA2B,CACzD,GAAIA,EAAW,SAAW,EAAG,MAAO,GAEpC,MAAMC,EAAOD,EAAW,MAAM,EAAG,EAAE,EAAE,IAAIE,GAAQ,CAxQ9C,IAAAf,EAAAC,EAAAC,EAAAC,EAAAC,EAyQD,MAAMG,IAAcN,GAAAD,EAAAe,EAAK,cAAL,YAAAf,EAAkB,qBAAlB,YAAAC,EAAsC,QAASc,EAAK,YAClEC,IAAcb,GAAAD,EAAAa,EAAK,cAAL,YAAAb,EAAkB,qBAAlB,YAAAC,EAAsC,QAAS,GAC7Dc,IAAWb,EAAAW,EAAK,gBAAL,YAAAX,EAAoB,QAAS,OACxCc,EAAOH,EAAK,eAAiB,UAEnC,MAAO;AAAA,QACL,KAAK,WAAWA,EAAK,WAAW,CAAC;AAAA,QACjC,KAAK,WAAWR,CAAW,CAAC;AAAA,QAC5B,KAAK,WAAWW,CAAI,CAAC;AAAA,iCACID,IAAa,iBAAmB,QAAUA,IAAa,sBAAwB,UAAY,MAAM,KAAKA,CAAQ;AAAA,wCACvG,KAAK,WAAWD,CAAW,CAAC;AAAA,MAEhE,CAAC,EAAE,KAAK;AAAA,CAAI,EAENG,EAAWN,EAAW,OAAS,GAAK,uCAAuCA,EAAW,MAAM,kBAAoB,GAEtH,MAAO;AAAA,oBACSA,EAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYnCC,CAAI;AAAA;AAAA;AAAA,IAGFK,CAAQ;AAAA,OAEV,CAKQ,2BAA2BC,EAA+B,CAChE,GAAIA,EAAQ,SAAW,EAAG,MAAO,GAEjC,MAAMN,EAAOM,EAAQ,IAAIC,GAChB;AAAA,QACL,KAAK,WAAWA,EAAO,IAAI,CAAC;AAAA,QAC5B,KAAK,WAAWA,EAAO,SAAW,EAAE,CAAC;AAAA,QACrC,KAAK,WAAWA,EAAO,WAAa,EAAE,CAAC;AAAA,QACvC,KAAK,WAAWA,EAAO,UAAY,EAAE,CAAC;AAAA,wCACN,KAAK,WAAWA,EAAO,aAAe,EAAE,CAAC;AAAA,MAE5E,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,iBACMD,EAAQ,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY7BN,CAAI;AAAA;AAAA;AAAA,OAIJ,CAKQ,yBAAyBQ,EAAuB,CACtD,GAAIA,EAAM,SAAW,EAAG,MAAO,GAE/B,MAAMR,EAAOQ,EAAM,IAAIC,GACd;AAAA,QACL,KAAK,WAAWA,EAAK,IAAI,CAAC;AAAA,iCACDA,EAAK,QAAU,SAAW,UAAYA,EAAK,QAAU,QAAU,UAAY,OAAO,KAAKA,EAAK,KAAK;AAAA,QAC1H,KAAK,WAAWA,EAAK,WAAW,YAAY,CAAC;AAAA,wCACb,KAAK,WAAWA,EAAK,aAAe,EAAE,CAAC;AAAA,MAE1E,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,eACID,EAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWzBR,CAAI;AAAA;AAAA;AAAA,OAIJ,CAKQ,oBAAoBhB,EAAoC,CAC9D,OAAOA,EAAS,QAAQ,OAAS,GAC1BA,EAAS,MAAM,OAAS,GACxBA,EAAS,cAAc,OAAS,CACzC,CAKQ,2BAA2BA,EAAoC,CAUrE,MARI,GAAAA,EAAS,QAAQ,OAAS,GAGHA,EAAS,cAAc,KAAK0B,GAAMA,EAAG,YAAc,QAAQ,GAI5D1B,EAAS,MAAM,QAAayB,EAAK,WAAW,cAAgB,WAAW,EAInG,CAKQ,0BAA0BzB,EAAmC,CA/YhE,IAAAE,EAAAC,EAAAC,EAgZH,MAAMI,EAASR,EAAS,OAClBkB,IAAcf,GAAAD,EAAAM,EAAO,cAAP,YAAAN,EAAoB,qBAApB,YAAAC,EAAwC,QAAS,GAE/Dd,EAAW,CACf,CAAC,eAAgBmB,EAAO,WAAW,EACnC,CAAC,cAAeA,EAAO,UAAU,EACjC,CAAC,gBAAiBA,EAAO,sBAAwB,KAAK,EACtD,CAAC,YAAaA,EAAO,mBAAqB,KAAK,EAC/C,CAAC,cAAeA,EAAO,WAAa,MAAQ,IAAI,EAChD,CAAC,YAAaA,EAAO,eAAiB,MAAQ,IAAI,CAAA,EAG9CmB,EAAoB;AAAA;AAAA;AAAA;AAAA,wCAIU3B,EAAS,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,wCAIvBA,EAAS,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA,wCAIrBA,EAAS,cAAc,MAAM;AAAA;AAAA;AAAA;AAAA,0CAI7BI,EAAAI,EAAO,aAAP,YAAAJ,EAAmB,SAAU,CAAC;AAAA;AAAA;AAAA,MAKlE,MAAO;AAAA,QACHc,EAAc,mCAAmC,KAAK,WAAWA,CAAW,CAAC,SAAW,EAAE;AAAA;AAAA;AAAA;AAAA,YAItF7B,EAAS,IAAI,CAAC,CAACuC,EAAKC,CAAK,IAAM,WAAWD,CAAG,YAAY,KAAK,WAAWC,CAAK,CAAC,YAAY,EAAE,KAAK;AAAA,CAAI,CAAC;AAAA;AAAA;AAAA,QAG3GF,CAAiB;AAAA,KAEvB,CAKQ,wBAAwB3B,EAAmC,CACjE,MAAMQ,EAASR,EAAS,OAClBe,EAAaP,EAAO,YAAc,CAAA,EAClCsB,EAAYtB,EAAO,wBAA0B,CAAA,EAC7CuB,EAAYvB,EAAO,wBAA0B,CAAA,EAC7CwB,EAAaxB,EAAO,yBAA2B,CAAA,EAErD,IAAIyB,EAAU,GAGVlB,EAAW,OAAS,EACtBkB,GAAW,KAAK,wBAAwBlB,CAAU,EAElDkB,GAAW,qDAIb,MAAMC,EAAqBJ,EAAU,OAASC,EAAU,OAASC,EAAW,OAC5E,OAAIE,EAAqB,IACvBD,GAAW;AAAA,6BACYC,CAAkB;AAAA,UACrCJ,EAAU,OAAS,EAAI,KAAK,6BAA6B,cAAeA,CAAS,EAAI,EAAE;AAAA,UACvFC,EAAU,OAAS,EAAI,KAAK,6BAA6B,cAAeA,CAAS,EAAI,EAAE;AAAA,UACvFC,EAAW,OAAS,EAAI,KAAK,6BAA6B,eAAgBA,CAAU,EAAI,EAAE;AAAA,eAK5FhC,EAAS,eAAiBA,EAAS,cAAc,cAAc,OAAS,IAC1EiC,GAAW,KAAK,6BAA6BjC,EAAS,aAAa,GAG9DiC,CACT,CAKQ,4BAA4BjC,EAAmC,CACrE,IAAIiC,EAAU,GAId,OAFsBjC,EAAS,QAAQ,OAAS,GAAKA,EAAS,MAAM,OAAS,GAAKA,EAAS,cAAc,OAAS,GAO9GA,EAAS,QAAQ,OAAS,IAC5BiC,GAAW,KAAK,2BAA2BjC,EAAS,OAAO,GAIzDA,EAAS,MAAM,OAAS,IAC1BiC,GAAW,KAAK,yBAAyBjC,EAAS,KAAK,GAIrDA,EAAS,cAAc,OAAS,IAClCiC,GAAW,KAAK,iCAAiCjC,EAAS,aAAa,GAGlEiC,GAlBE,yEAmBX,CAKQ,0BAA0BjC,EAAmC,CApgBhE,IAAAE,EAAAC,EAqgBH,MAAMK,EAASR,EAAS,OAClBS,IAAcN,GAAAD,EAAAM,EAAO,cAAP,YAAAN,EAAoB,qBAApB,YAAAC,EAAwC,QAASK,EAAO,YAE5E,IAAIyB,EAAU;AAAA,+EAC6D,KAAK,WAAWxB,CAAW,CAAC;AAAA,YAIvG,MAAM0B,MAAuB,IAC7B,UAAWZ,KAAUvB,EAAS,QAAS,CACrC,MAAM4B,EAAML,EAAO,QACdY,EAAiB,IAAIP,CAAG,GAC3BO,EAAiB,IAAIP,EAAK,EAAE,EAE9BO,EAAiB,IAAIP,CAAG,EAAG,KAAKL,CAAM,CACxC,CAGA,MAAMa,EAAkBpC,EAAS,cAAc,OAAO0B,GAAMA,EAAG,YAAc,QAAQ,EAGrF,GAAI1B,EAAS,QAAQ,SAAW,EAAG,CACjCiC,GAAW,gEAEPG,EAAgB,OAAS,IAC3BH,GAAW;AAAA;AAAA,YAEP,KAAK,iCAAiCG,CAAe,CAAC;AAAA,iBAI5D,MAAMC,EAAiBrC,EAAS,MAAM,UAAYsC,EAAE,WAAW,cAAgB,WAAW,EAC1F,OAAID,EAAe,OAAS,IAC1BJ,GAAW;AAAA;AAAA,YAEP,KAAK,yBAAyBI,CAAc,CAAC;AAAA,iBAI5CJ,CACT,CAGA,SAAW,CAACM,EAASjB,CAAO,IAAKa,EAAkB,CACjDF,GAAW;AAAA,cACH,KAAK,WAAWM,CAAO,CAAC,cAGhC,MAAMC,EAAgB,CAAC,GAAGlB,CAAO,EAAE,KAAK,CAACmB,EAAGC,IACtCD,EAAE,QAAUC,EAAE,MAAcD,EAAE,MAAQC,EAAE,MACrCD,EAAE,KAAOC,EAAE,IACnB,EAGKC,MAAc,IACpB,UAAWpB,KAAUiB,EACdG,EAAQ,IAAIpB,EAAO,KAAK,GAC3BoB,EAAQ,IAAIpB,EAAO,MAAO,CAAA,CAAE,EAE9BoB,EAAQ,IAAIpB,EAAO,KAAK,EAAG,KAAKA,CAAM,EAIxCU,GAAW,KAAK,8BAA8BU,EAASP,CAAe,EAGtEH,GAAW,6BACXA,GAAW,KAAK,6BAA6BO,EAAeJ,CAAe,EAG3E,MAAMQ,EAAcJ,EAAc,OAAOK,GAAKA,EAAE,OAAS,CAAC,EACtDD,EAAY,OAAS,IACvBX,GAAW;AAAA;AAAA,eAEJW,EAAY,MAAM;AAAA,iBAI3BX,GAAW,QACb,CAGA,OAAIjC,EAAS,cAAc,OAAS,IAClCiC,GAAW;AAAA;AAAA;AAAA,UAGP,KAAK,iCAAiCjC,EAAS,aAAa,CAAC;AAAA,eAI5DiC,CACT,CAKQ,8BAA8BU,EAAoCG,EAAuC,CAC/G,IAAIC,EAAO,gCAGPD,EAAc,OAAS,IACzBC,GAAQ;AAAA;AAAA,mCAIRD,EAAc,QAAQ,CAACpB,EAAIsB,IAAQ,CACjC,MAAMC,EAAQvB,EAAG,QAAU,SAAW,SAAW,QACjDqB,GAAQ,kCAAkCE,CAAK;AAAA,YAC3CD,EAAM,CAAC,KAAK,KAAK,WAAWtB,EAAG,IAAI,CAAC,kCAAkCuB,CAAK,MAAMA,EAAM,aAAa;AAAA,eAE1G,CAAC,EAEDF,GAAQ,gBAIV,SAAW,CAACG,EAAO5B,CAAO,IAAKqB,EAAS,CACtC,MAAMQ,EAAY7B,EAAQ,CAAC,EAAE,UACvB8B,EAAa,KAAK,cAAcF,CAAK,EAE3CH,GAAQ,8BAA8BK,CAAU;AAAA,0CACZF,CAAK,KAAK,KAAK,WAAWC,CAAS,CAAC;AAAA,mCAGxE7B,EAAQ,QAAQ,CAACC,EAAQyB,IAAQ,CAC/B,MAAMK,EAAO9B,EAAO,OAAS,EAAI,OAAS,QAC1CwB,GAAQ,kCAAkCM,CAAI;AAAA,YAC1CL,EAAM,CAAC,KAAK,KAAK,WAAWzB,EAAO,IAAI,CAAC,kCAAkC8B,CAAI,MAAMA,EAAK,aAAa;AAAA,0CACxE9B,EAAO,IAAI;AAAA,eAE/C,CAAC,EAEDwB,GAAQ,cACV,CAEA,OAAAA,GAAQ,SACDA,CACT,CAKQ,cAAcG,EAAuB,CAC3C,OAAQA,EAAA,CACN,IAAK,IAAI,MAAO,sBAChB,IAAK,IAAI,MAAO,qBAChB,IAAK,IAAI,MAAO,sBAChB,IAAK,IAAI,MAAO,sBAChB,QAAS,MAAO,eAAA,CAEpB,CAKQ,6BAA6B5B,EAAuBwB,EAAuC,CACjG,MAAM9B,EAAiB,CAAA,EAGvB,OAAA8B,EAAc,QAAQ,CAACpB,EAAIsB,IAAQ,CACjC,MAAMM,EAAa5B,EAAG,QAAU,SAC5B,kDACA,iDACJV,EAAK,KAAK;AAAA,cACFgC,EAAM,CAAC;AAAA;AAAA,cAEP,KAAK,WAAWtB,EAAG,IAAI,CAAC;AAAA;AAAA,cAExB4B,CAAU;AAAA;AAAA,YAEZ,CACR,CAAC,EAGDhC,EAAQ,QAAQ,CAACC,EAAQyB,IAAQ,CAC/B,MAAMO,EAAYhC,EAAO,OAAS,EAC9B,oDACA,sDACJP,EAAK,KAAK;AAAA,cACF8B,EAAc,OAASE,EAAM,CAAC;AAAA;AAAA,cAE9B,KAAK,WAAWzB,EAAO,IAAI,CAAC;AAAA,cAC5B,KAAK,WAAWA,EAAO,SAAS,CAAC;AAAA,cACjCgC,CAAS;AAAA,cACThC,EAAO,IAAI;AAAA,YACb,CACR,CAAC,EAEM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAYDP,EAAK,KAAK;AAAA,CAAI,CAAC;AAAA;AAAA,aAGvB,CAKQ,iCAAiC8B,EAAuC,CAC9E,GAAIA,EAAc,SAAW,EAAG,MAAO,GAEvC,MAAM9B,EAAO8B,EAAc,IAAIpB,GAAM,CACnC,MAAM4B,EAAa5B,EAAG,QAAU,SAC5B,kDACA,iDACJ,MAAO;AAAA,cACC,KAAK,WAAWA,EAAG,IAAI,CAAC;AAAA,cACxB,KAAK,WAAWA,EAAG,SAAS,CAAC;AAAA,cAC7B,KAAK,WAAWA,EAAG,WAAW,gBAAgB,CAAC;AAAA,cAC/C4B,CAAU;AAAA,cACV5B,EAAG,WAAW,WAAW,MAAM;AAAA,cAC/BA,EAAG,WAAW,QAAQ,MAAM;AAAA,YAEtC,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,4BACiBoB,EAAc,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAapC9B,CAAI;AAAA;AAAA;AAAA,WAId,CAKQ,6BAA6BI,EAAcoC,EAA8B,CAC/E,GAAIA,EAAc,SAAW,EAAG,MAAO,GAEvC,MAAMxC,EAAOwC,EAAc,MAAM,EAAG,EAAE,EAAE,IAAIC,GAAO,CACjD,MAAMC,EAAaD,EAAI,YAAc,MAC/BE,EAAoBF,EAAI,mBAAqBA,EAAI,kBAAoB,MACrEG,EAAsBH,EAAI,qBAAuBA,EAAI,sBAAwB,MAEnF,MAAO;AAAA,cACC,KAAK,WAAWC,CAAU,CAAC;AAAA,cAC3B,KAAK,WAAWC,CAAiB,CAAC;AAAA,cAClC,KAAK,WAAWC,CAAmB,CAAC;AAAA,YAE9C,CAAC,EAAE,KAAK;AAAA,CAAI,EAENvC,EAAWmC,EAAc,OAAS,GAAK,uCAAuCA,EAAc,MAAM,qBAAuB,GAE/H,MAAO;AAAA,YACCpC,CAAI,KAAKoC,EAAc,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAU7BxC,CAAI;AAAA;AAAA;AAAA,QAGRK,CAAQ;AAAA,WAEd,CAKA,iBAAiBC,EAA+B,CAC9C,GAAIA,EAAQ,SAAW,EACrB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMN,EAAOM,EAAQ,IAAIC,GAAU,CACjC,MAAMsC,EAAmB,CAAA,EACrBtC,EAAO,UAAUsC,EAAO,KAAKtC,EAAO,SAAS,SAAS,EACtDA,EAAO,WAAWsC,EAAO,KAAKtC,EAAO,UAAU,SAAS,EAC5D,MAAMuC,EAAaD,EAAO,OAAS,EAAIA,EAAO,KAAK,IAAI,EAAI,OAE3D,MAAO;AAAA,QACL,KAAK,WAAWtC,EAAO,IAAI,CAAC;AAAA,QAC5B,KAAK,WAAWA,EAAO,QAAU,KAAK,CAAC;AAAA,QACvC,KAAK,WAAWA,EAAO,SAAW,KAAK,CAAC;AAAA,QACxC,KAAK,WAAWA,EAAO,WAAa,KAAK,CAAC;AAAA,QAC1C,KAAK,WAAWA,EAAO,UAAY,KAAK,CAAC;AAAA,QACzC,OAAOA,EAAO,MAAQ,CAAC,CAAC;AAAA,QACxB,KAAK,WAAWuC,CAAU,CAAC;AAAA,MAE/B,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,iBACMxC,EAAQ,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe7BN,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,eAAeQ,EAAuB,CACpC,GAAIA,EAAM,SAAW,EACnB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMR,EAAOQ,EAAM,IAAIC,GAAQ,CAC7B,MAAMsC,EAAgBtC,EAAK,mBAAqBA,EAAK,QAAU,MACzDuC,EAAcvC,EAAK,iBAEzB,MAAO;AAAA,QACL,KAAK,WAAWA,EAAK,IAAI,CAAC;AAAA,QAC1B,KAAK,WAAWsC,CAAa,CAAC;AAAA,iCACLtC,EAAK,QAAU,SAAW,UAAYA,EAAK,QAAU,QAAU,UAAY,OAAO,KAAKA,EAAK,KAAK;AAAA,QAC1H,KAAK,WAAWA,EAAK,WAAW,YAAY,CAAC;AAAA,QAC7C,KAAK,WAAWA,EAAK,WAAW,SAAS,CAAC;AAAA,QAC1CA,EAAK,WAAW,YAAY;AAAA,QAC5BuC,EAAc,+CAAiD,0CAA0C;AAAA,MAE7G,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,eACIxC,EAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAezBR,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,uBAAuB8B,EAAuC,CAC5D,GAAIA,EAAc,SAAW,EAC3B,MAAO;AAAA;AAAA;AAAA,YAMT,MAAM9B,EAAO8B,EAAc,IAAImB,GAAQ,CA/4BpC,IAAA/D,EAAAC,EAg5BD,MAAM4D,EAAgBE,EAAK,mBAAqBA,EAAK,OAC/CC,IAAahE,EAAA+D,EAAK,WAAW,aAAhB,YAAA/D,EAA4B,SAAU,EACnDiE,IAAUhE,EAAA8D,EAAK,WAAW,UAAhB,YAAA9D,EAAyB,SAAU,EAEnD,MAAO;AAAA,QACL,KAAK,WAAW8D,EAAK,IAAI,CAAC;AAAA,QAC1B,KAAK,WAAWF,CAAa,CAAC;AAAA,iCACLE,EAAK,QAAU,SAAW,UAAY,SAAS,KAAKA,EAAK,KAAK;AAAA,QACvF,KAAK,WAAWA,EAAK,KAAK,CAAC;AAAA,QAC3BC,CAAU;AAAA,QACVC,CAAO;AAAA,MAEX,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,wBACarB,EAAc,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc1C9B,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,0BAA0BoD,EAAsC,CAC9D,GAAIA,EAAU,SAAW,EACvB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMpD,EAAOoD,EAAU,IAAIC,GAAY,CA/7BpC,IAAAnE,EAAAC,EAg8BD,MAAM4D,EAAgBM,EAAS,mBAAqBA,EAAS,OACvDC,IAAapE,EAAAmE,EAAS,0BAAT,YAAAnE,EAAkC,aAAc,UAC7DqE,IAASpE,EAAAkE,EAAS,0BAAT,YAAAlE,EAAkC,SAAU,UAE3D,MAAO;AAAA,QACL,KAAK,WAAWkE,EAAS,IAAI,CAAC;AAAA,QAC9B,KAAK,WAAWN,CAAa,CAAC;AAAA,iCACLM,EAAS,QAAU,SAAW,UAAYA,EAAS,QAAU,QAAU,UAAY,OAAO,KAAKA,EAAS,KAAK;AAAA,QACtI,KAAK,WAAWA,EAAS,QAAQ,CAAC;AAAA,iCACTC,IAAe,WAAa,QAAUA,IAAe,OAAS,UAAY,MAAM,KAAKA,CAAU;AAAA,QACxH,KAAK,WAAWC,CAAM,CAAC;AAAA,MAE3B,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,gDACqCH,EAAU,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB9DpD,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,8BAA8BwD,EAAqC,CACjE,GAAIA,EAAK,SAAW,EAClB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMxD,EAAOwD,EAAK,IAAIC,GAAO,CAl/B1B,IAAAvE,EAm/BD,MAAM6D,EAAgBU,EAAI,0BAA4BA,EAAI,cACpDC,IAASxE,EAAAuE,EAAI,WAAW,SAAf,YAAAvE,EAAuB,SAAU,EAC1CyE,EAAcF,EAAI,WAAW,gBAEnC,MAAO;AAAA,QACL,KAAK,WAAWA,EAAI,IAAI,CAAC;AAAA,QACzB,KAAK,WAAWV,CAAa,CAAC;AAAA,iCACLU,EAAI,QAAU,SAAW,UAAY,SAAS,KAAKA,EAAI,KAAK;AAAA,QACrFC,CAAM;AAAA,QACND,EAAI,WAAW,UAAU;AAAA,QACzBE,EAAc,4CAA8C,IAAI;AAAA,MAEpE,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,gCACqBH,EAAK,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAczCxD,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,sBAAsB4D,EAAqC,CACzD,GAAIA,EAAa,SAAW,EAC1B,MAAO;AAAA;AAAA;AAAA,YAMT,MAAM5D,EAAO4D,EAAa,IAAIC,GAAM,CAClC,MAAMC,GAAUD,EAAG,YAAc,MAAM,QAAQ,CAAC,EAC1Cb,EAAca,EAAG,iBACjBE,EAAaF,EAAG,aAEtB,MAAO;AAAA,QACL,KAAK,WAAWA,EAAG,IAAI,CAAC;AAAA,QACxB,KAAK,WAAWA,EAAG,WAAW,CAAC;AAAA,QAC/B,KAAK,WAAWA,EAAG,QAAQ,CAAC;AAAA,QAC5BC,CAAM;AAAA,QACNd,EAAc,+CAAiD,IAAI;AAAA,QACnEe,EAAa,6CAA+C,IAAI;AAAA,MAEpE,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,uBACYH,EAAa,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcxC5D,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,oBAAoBgE,EAAiC,CACnD,GAAIA,EAAW,SAAW,EACxB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMhE,EAAOgE,EAAW,IAAIC,GAAO,CAllChC,IAAA/E,EAAAC,EAmlCD,MAAMiB,EAAO6D,EAAI,WAAa,WAAa,SACrCC,EAAUD,EAAI,YACdE,IAASjF,EAAA+E,EAAI,oBAAJ,YAAA/E,EAAuB,SAAU,EAC1CkF,IAAYjF,EAAA8E,EAAI,qBAAJ,YAAA9E,EAAwB,SAAU,EAEpD,MAAO;AAAA,QACL,KAAK,WAAW8E,EAAI,UAAU,CAAC;AAAA,QAC/B,KAAK,WAAWA,EAAI,WAAW,CAAC;AAAA,iCACPA,EAAI,WAAa,OAAS,SAAS,KAAK7D,CAAI;AAAA,QACrE,KAAK,WAAW8D,CAAO,CAAC;AAAA,QACxBC,CAAM;AAAA,QACNC,CAAS;AAAA,MAEb,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,qBACUJ,EAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcpChE,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,8BAA8BqE,EAAwC,CACpE,GAAIA,EAAQ,SAAW,EACrB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMrE,EAAOqE,EAAQ,IAAIC,GAAU,CACjC,MAAMC,EAAW,CAAC,CAACD,EAAO,aACpBnE,EAAWmE,EAAO,WAExB,MAAO;AAAA,QACL,KAAK,WAAWA,EAAO,UAAU,CAAC;AAAA,QAClC,KAAK,WAAWA,EAAO,WAAW,CAAC;AAAA,QACnC,KAAK,WAAWA,EAAO,QAAQ,CAAC;AAAA,QAChCnE,EAAW,kDAAoD,UAAU;AAAA,QACzEoE,EAAW,+CAAiD,kDAAkD;AAAA,MAElH,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,+BACoBF,EAAQ,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAa3CrE,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,8BAA8BwE,EAAyC,CACrE,GAAIA,EAAS,SAAW,EACtB,MAAO;AAAA;AAAA;AAAA,YAMT,MAAMxE,EAAOwE,EAAS,IAAIC,GAAW,CACnC,MAAMC,EAAYD,EAAQ,sBAAwB,UAC5CE,EAAY,CAAC,CAACF,EAAQ,aAE5B,MAAO;AAAA,QACL,KAAK,WAAWA,EAAQ,IAAI,CAAC;AAAA,QAC7B,KAAK,WAAWA,EAAQ,WAAW,CAAC;AAAA,QACpC,KAAK,WAAWC,CAAS,CAAC;AAAA,QAC1BC,EAAY,qDAAuD,sDAAsD;AAAA,MAE7H,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,+BACoBH,EAAS,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY5CxE,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,gCAAgC4E,EAAmD,CACjF,GAAI,CAACA,GAAaA,EAAU,SAAW,EACrC,MAAO;AAAA;AAAA;AAAA,YAMT,MAAM5E,EAAO4E,EAAU,IAAIC,GAAY,CACrC,MAAMC,EAAYD,EAAS,YAAc,UAAY,UAAYA,EAAS,YAAc,QAAU,UAAY,QACxGE,EAAkBF,EAAS,YAAY,IAAIG,GAAMA,EAAG,MAAM,EAAE,KAAK,IAAI,GAAK,OAEhF,MAAO;AAAA,QACL,KAAK,WAAWH,EAAS,MAAM,CAAC;AAAA,QAChC,KAAK,WAAWA,EAAS,SAAS,YAAA,CAAa,CAAC;AAAA,iCACvBC,CAAS,KAAKD,EAAS,SAAS;AAAA,QACzDA,EAAS,SAAS;AAAA,QAClB,KAAK,WAAWE,CAAe,CAAC;AAAA,MAEpC,CAAC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,+BACoBH,EAAU,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB7C5E,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,uBAAuBiF,EAA8C,CACnE,GAAI,CAACA,GAASA,EAAM,SAAW,EAC7B,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA,YAQT,MAAMjF,EAAOiF,EAAM,IAAIC,GACd;AAAA,QACL,KAAK,WAAWA,EAAK,uBAAuB,CAAC;AAAA,QAC7C,KAAK,WAAWA,EAAK,uBAAuB,CAAC;AAAA,QAC7C,KAAK,WAAWA,EAAK,cAAc,CAAC;AAAA,QACpC,KAAK,WAAWA,EAAK,cAAc,CAAC;AAAA,QACpC,KAAK,WAAWA,EAAK,SAAS,CAAC;AAAA,QAC/BA,EAAK,eAAiB,QAAU,MAAM;AAAA,MAEzC,EAAE,KAAK;AAAA,CAAI,EAEZ,MAAO;AAAA,iCACsBD,EAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe3CjF,CAAI;AAAA;AAAA;AAAA;AAAA,WAKJ,CAKA,YAAqB,CACnB,MAAO;AAAA;AAAA;AAAA,UAIT,CAKA,aAAsB,CACpB,MAAO;AAAA,EACT,KAAK,oBAAoB;AAAA,WAEzB,CAKQ,aAAsB,CAC5B,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
@@ -0,0 +1,2 @@
1
+ var r=Object.defineProperty;var a=(o,s,e)=>s in o?r(o,s,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[s]=e;var n=(o,s,e)=>a(o,typeof s!="symbol"?s+"":s,e);class b{constructor(){n(this,"toolVersion","1.0.0")}generate(s){const e={exportVersion:"1.0",exportedAt:new Date().toISOString(),toolVersion:this.toolVersion,blueprint:this.serializeResult(s)};return JSON.stringify(e,this.jsonReplacer,2)}serializeResult(s){return{metadata:{...s.metadata,generatedAt:s.metadata.generatedAt.toISOString()},entities:s.entities,summary:s.summary,plugins:s.plugins,pluginsByEntity:this.mapToObject(s.pluginsByEntity),flows:s.flows,flowsByEntity:this.mapToObject(s.flowsByEntity),businessRules:s.businessRules,businessRulesByEntity:this.mapToObject(s.businessRulesByEntity),classicWorkflows:s.classicWorkflows,classicWorkflowsByEntity:this.mapToObject(s.classicWorkflowsByEntity),businessProcessFlows:s.businessProcessFlows,businessProcessFlowsByEntity:this.mapToObject(s.businessProcessFlowsByEntity),customAPIs:s.customAPIs,environmentVariables:s.environmentVariables,connectionReferences:s.connectionReferences,globalChoices:s.globalChoices,customConnectors:s.customConnectors,webResources:s.webResources,webResourcesByType:this.mapToObject(s.webResourcesByType),erd:s.erd,crossEntityLinks:s.crossEntityLinks,externalEndpoints:s.externalEndpoints,solutionDistribution:s.solutionDistribution,securityRoles:s.securityRoles,fieldSecurityProfiles:s.fieldSecurityProfiles,attributeMaskingRules:s.attributeMaskingRules,columnSecurityProfiles:s.columnSecurityProfiles}}mapToObject(s){const e={};for(const[i,t]of s.entries())e[i]=t;return e}jsonReplacer(s,e){if(e===void 0)return null;if(e instanceof Date)return e.toISOString();if(e instanceof Map){const i={};for(const[t,c]of e.entries())i[t]=c;return i}return e}}export{b as JsonReporter};
2
+ //# sourceMappingURL=JsonReporter-BqDJorX-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonReporter-BqDJorX-.js","sources":["../../src/core/reporters/JsonReporter.ts"],"sourcesContent":["import type { BlueprintResult } from '../types/blueprint.js';\n\n/**\n * Export wrapper for JSON blueprint export\n */\ninterface JsonExportWrapper {\n exportVersion: string;\n exportedAt: string;\n toolVersion: string;\n blueprint: any; // Will be serialized BlueprintResult\n}\n\n/**\n * Exports blueprint as JSON with metadata wrapper\n *\n * Use cases:\n * - Baseline comparison (next day)\n * - Programmatic consumption\n * - Data analysis\n * - CI/CD pipelines\n * - Version control (git diff friendly)\n */\nexport class JsonReporter {\n private readonly toolVersion = '1.0.0';\n\n /**\n * Generate JSON export of blueprint\n * @param result Complete blueprint result\n * @returns JSON string (pretty-printed with 2-space indentation)\n */\n generate(result: BlueprintResult): string {\n // Create export wrapper with metadata\n const exportWrapper: JsonExportWrapper = {\n exportVersion: '1.0',\n exportedAt: new Date().toISOString(),\n toolVersion: this.toolVersion,\n blueprint: this.serializeResult(result),\n };\n\n // Pretty-print with 2-space indentation\n return JSON.stringify(exportWrapper, this.jsonReplacer, 2);\n }\n\n /**\n * Serialize BlueprintResult to plain object\n * Handles Maps, Dates, and undefined values\n */\n private serializeResult(result: BlueprintResult): any {\n return {\n metadata: {\n ...result.metadata,\n generatedAt: result.metadata.generatedAt.toISOString(),\n },\n entities: result.entities,\n summary: result.summary,\n plugins: result.plugins,\n pluginsByEntity: this.mapToObject(result.pluginsByEntity),\n flows: result.flows,\n flowsByEntity: this.mapToObject(result.flowsByEntity),\n businessRules: result.businessRules,\n businessRulesByEntity: this.mapToObject(result.businessRulesByEntity),\n classicWorkflows: result.classicWorkflows,\n classicWorkflowsByEntity: this.mapToObject(result.classicWorkflowsByEntity),\n businessProcessFlows: result.businessProcessFlows,\n businessProcessFlowsByEntity: this.mapToObject(result.businessProcessFlowsByEntity),\n customAPIs: result.customAPIs,\n environmentVariables: result.environmentVariables,\n connectionReferences: result.connectionReferences,\n globalChoices: result.globalChoices,\n customConnectors: result.customConnectors,\n webResources: result.webResources,\n webResourcesByType: this.mapToObject(result.webResourcesByType),\n erd: result.erd,\n crossEntityLinks: result.crossEntityLinks,\n externalEndpoints: result.externalEndpoints,\n solutionDistribution: result.solutionDistribution,\n securityRoles: result.securityRoles,\n fieldSecurityProfiles: result.fieldSecurityProfiles,\n attributeMaskingRules: result.attributeMaskingRules,\n columnSecurityProfiles: result.columnSecurityProfiles,\n };\n }\n\n /**\n * Convert Map to plain object for JSON serialization\n */\n private mapToObject<T>(map: Map<string, T>): Record<string, T> {\n const obj: Record<string, T> = {};\n for (const [key, value] of map.entries()) {\n obj[key] = value;\n }\n return obj;\n }\n\n /**\n * Custom JSON replacer function\n * - Converts undefined to null\n * - Handles Date objects\n * - Removes circular references\n */\n private jsonReplacer(_key: string, value: any): any {\n // Convert undefined to null\n if (value === undefined) {\n return null;\n }\n\n // Convert Date to ISO string\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n // Convert Map to object\n if (value instanceof Map) {\n const obj: Record<string, any> = {};\n for (const [k, v] of value.entries()) {\n obj[k] = v;\n }\n return obj;\n }\n\n return value;\n }\n}\n"],"names":["JsonReporter","__publicField","result","exportWrapper","map","obj","key","value","_key","k","v"],"mappings":"oKAsBO,MAAMA,CAAa,CAAnB,cACYC,EAAA,mBAAc,SAO/B,SAASC,EAAiC,CAExC,MAAMC,EAAmC,CACvC,cAAe,MACf,WAAY,IAAI,KAAA,EAAO,YAAA,EACvB,YAAa,KAAK,YAClB,UAAW,KAAK,gBAAgBD,CAAM,CAAA,EAIxC,OAAO,KAAK,UAAUC,EAAe,KAAK,aAAc,CAAC,CAC3D,CAMQ,gBAAgBD,EAA8B,CACpD,MAAO,CACL,SAAU,CACR,GAAGA,EAAO,SACV,YAAaA,EAAO,SAAS,YAAY,YAAA,CAAY,EAEvD,SAAUA,EAAO,SACjB,QAASA,EAAO,QAChB,QAASA,EAAO,QAChB,gBAAiB,KAAK,YAAYA,EAAO,eAAe,EACxD,MAAOA,EAAO,MACd,cAAe,KAAK,YAAYA,EAAO,aAAa,EACpD,cAAeA,EAAO,cACtB,sBAAuB,KAAK,YAAYA,EAAO,qBAAqB,EACpE,iBAAkBA,EAAO,iBACzB,yBAA0B,KAAK,YAAYA,EAAO,wBAAwB,EAC1E,qBAAsBA,EAAO,qBAC7B,6BAA8B,KAAK,YAAYA,EAAO,4BAA4B,EAClF,WAAYA,EAAO,WACnB,qBAAsBA,EAAO,qBAC7B,qBAAsBA,EAAO,qBAC7B,cAAeA,EAAO,cACtB,iBAAkBA,EAAO,iBACzB,aAAcA,EAAO,aACrB,mBAAoB,KAAK,YAAYA,EAAO,kBAAkB,EAC9D,IAAKA,EAAO,IACZ,iBAAkBA,EAAO,iBACzB,kBAAmBA,EAAO,kBAC1B,qBAAsBA,EAAO,qBAC7B,cAAeA,EAAO,cACtB,sBAAuBA,EAAO,sBAC9B,sBAAuBA,EAAO,sBAC9B,uBAAwBA,EAAO,sBAAA,CAEnC,CAKQ,YAAeE,EAAwC,CAC7D,MAAMC,EAAyB,CAAA,EAC/B,SAAW,CAACC,EAAKC,CAAK,IAAKH,EAAI,UAC7BC,EAAIC,CAAG,EAAIC,EAEb,OAAOF,CACT,CAQQ,aAAaG,EAAcD,EAAiB,CAElD,GAAIA,IAAU,OACZ,OAAO,KAIT,GAAIA,aAAiB,KACnB,OAAOA,EAAM,YAAA,EAIf,GAAIA,aAAiB,IAAK,CACxB,MAAMF,EAA2B,CAAA,EACjC,SAAW,CAACI,EAAGC,CAAC,IAAKH,EAAM,UACzBF,EAAII,CAAC,EAAIC,EAEX,OAAOL,CACT,CAEA,OAAOE,CACT,CACF"}
@@ -0,0 +1,53 @@
1
+ class n{static formatTable(s,e,t){if(s.length===0)return"";const o=t||s.map(()=>"left"),i=u=>(u||"").replace(/\|/g,"\\|"),a="| "+s.map(i).join(" | ")+" |",l="| "+s.map((u,m)=>{switch(o[m]||"left"){case"center":return":--------:";case"right":return"---------:";default:return"----------"}}).join(" | ")+" |",r=e.map(u=>"| "+s.map((c,p)=>i(u[p]||"")).join(" | ")+" |");return[a,l,...r].join(`
2
+ `)}static formatBadge(s,e){return`${{success:"✅",warning:"âš ī¸",error:"❌",info:"â„šī¸"}[e]} ${s}`}static formatLink(s,e){return`[${s}](${e})`}static formatCodeBlock(s,e){return`\`\`\`${e}
3
+ ${s}
4
+ \`\`\``}static formatList(s,e=!1){return s.length===0?"":e?s.map((t,o)=>`${o+1}. ${t}`).join(`
5
+ `):s.map(t=>`- ${t}`).join(`
6
+ `)}static formatHeading(s,e){const t=Math.max(1,Math.min(6,e));return`${"#".repeat(t)} ${s}`}static formatHorizontalRule(){return"---"}static escapeMarkdown(s){if(!s)return"";const e=/([*_\[\]()#+\-.!|\\])/g;return s.replace(e,"\\$1")}static formatFileTree(s){return this.formatFileTreeRecursive(s,"",!0,!0)}static formatFileTreeRecursive(s,e,t,o){const i=[],a=s.name+(s.type==="directory"?"/":"");if(o)i.push(a);else{const l=t?"└── ":"├── ";i.push(e+l+a)}return s.children&&s.children.length>0&&s.children.forEach((l,r)=>{const u=r===s.children.length-1;let m;o?m="":m=e+(t?" ":"│ ");const c=this.formatFileTreeRecursive(l,m,u,!1);i.push(c)}),i.join(`
7
+ `)}}class N{generate(s){const e=new Map;if(e.set("README.md",this.generateReadme(s)),e.set("summary/metrics.md",this.generateMetrics(s)),e.set("summary/all-plugins.md",this.generateAllPlugins(s)),e.set("summary/all-flows.md",this.generateAllFlows(s)),e.set("summary/all-business-rules.md",this.generateAllBusinessRules(s)),e.set("summary/all-classic-workflows.md",this.generateAllClassicWorkflows(s)),e.set("summary/all-webresources.md",this.generateAllWebResources(s)),e.set("summary/all-custom-apis.md",this.generateAllCustomAPIs(s)),e.set("summary/all-environment-variables.md",this.generateAllEnvironmentVariables(s)),e.set("summary/all-connection-references.md",this.generateAllConnectionReferences(s)),e.set("summary/all-business-process-flows.md",this.generateAllBusinessProcessFlows(s)),s.externalEndpoints&&s.externalEndpoints.length>0&&e.set("summary/external-integrations.md",this.generateExternalIntegrations(s)),s.crossEntityLinks&&s.crossEntityLinks.length>0&&e.set("summary/cross-entity-automation.md",this.generateCrossEntityAutomation(s)),s.solutionDistribution&&s.solutionDistribution.length>0&&e.set("summary/solution-distribution.md",this.generateSolutionDistribution(s)),s.securityRoles||s.fieldSecurityProfiles||s.attributeMaskingRules||s.columnSecurityProfiles){if(e.set("security/overview.md",this.generateSecurityOverview(s)),s.securityRoles)for(const i of s.securityRoles){const a=i.name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase();e.set(`security/roles/${a}.md`,this.generateSecurityRoleDetail(i))}s.fieldSecurityProfiles&&s.fieldSecurityProfiles.length>0&&e.set("security/field-security-profiles.md",this.generateFieldSecurityProfiles(s)),s.attributeMaskingRules&&s.attributeMaskingRules.length>0&&e.set("security/attribute-masking.md",this.generateAttributeMaskingRules(s)),s.columnSecurityProfiles&&s.columnSecurityProfiles.length>0&&e.set("security/column-security.md",this.generateColumnSecurityProfiles(s))}for(const i of s.entities){const a=i.entity.LogicalName;e.set(`entities/${a}/overview.md`,this.generateEntityOverview(i,s)),e.set(`entities/${a}/schema.md`,this.generateEntitySchema(i)),this.hasAutomation(i,s)&&e.set(`entities/${a}/automation.md`,this.generateEntityAutomation(i,s)),this.hasExecutionPipeline(i,s)&&e.set(`entities/${a}/execution-pipeline.md`,this.generateExecutionPipeline(i,s));const l=this.getEntityBpfs(i.entity.LogicalName,s);l.length>0&&e.set(`entities/${a}/business-process-flows.md`,this.generateEntityBpfs(i,l))}e.set("analysis/complexity-scores.md",this.generateComplexityScores(s)),e.set("analysis/performance-risks.md",this.generatePerformanceRisks(s)),e.set("analysis/migration-recommendations.md",this.generateMigrationRecommendations(s));const t=Array.from(e.values()).reduce((i,a)=>i+new TextEncoder().encode(a).length,0),o=this.buildFileTree(e);return{files:e,structure:o,totalFiles:e.size,totalSize:t}}generateReadme(s){const e=[];return e.push(n.formatHeading("Power Platform Solution Blueprint",1)),e.push(""),e.push(`**Generated:** ${s.metadata.generatedAt.toISOString()}`),e.push(`**Environment:** ${s.metadata.environment}`),e.push(`**Scope:** ${s.metadata.scope.description}`),e.push(""),e.push(n.formatHorizontalRule()),e.push(""),s.erd&&(e.push(n.formatHeading("Entity Relationship Diagram",2)),e.push(""),e.push(this.generateERDSection(s.erd)),e.push(""),e.push(n.formatHorizontalRule()),e.push("")),e.push(n.formatHeading("Summary",2)),e.push(""),e.push(this.generateQuickMetrics(s)),e.push(""),e.push(n.formatHorizontalRule()),e.push(""),s.erd&&s.erd.entityQuickLinks.length>0&&(e.push(n.formatHeading("Entities",2)),e.push(""),e.push(this.generateEntityQuickLinksTable(s.erd.entityQuickLinks)),e.push(""),e.push(n.formatHorizontalRule()),e.push("")),e.push(n.formatHeading("Documentation Structure",2)),e.push(""),e.push(this.generateNavigationLinks()),e.push(""),e.join(`
8
+ `)}generateERDSection(s){const e=[];if(s.legend.length>0){e.push(n.formatHeading("Publisher Legend",3)),e.push("");const t=["Publisher","Prefix","Entities","Color"],o=s.legend.map(i=>[i.publisherName,i.publisherPrefix,i.entityCount.toString(),i.color]);e.push(n.formatTable(t,o)),e.push("")}if(s.diagrams.length>0){const t=s.diagrams[0];e.push(n.formatHeading(t.title,3)),e.push(""),t.description&&(e.push(t.description),e.push("")),e.push(n.formatCodeBlock(t.mermaidDiagram,"mermaid")),e.push("")}return s.warnings&&s.warnings.length>0&&(e.push(n.formatHeading("Diagram Warnings",3)),e.push(""),e.push(n.formatList(s.warnings.map(t=>`âš ī¸ ${t}`))),e.push("")),e.join(`
9
+ `)}generateQuickMetrics(s){const e=[];return e.push(`**${s.summary.totalEntities}** Entities`),e.push(`**${s.summary.totalPlugins}** Plugins (${s.summary.totalPluginPackages} assemblies)`),e.push(`**${s.summary.totalFlows}** Cloud Flows`),e.push(`**${s.summary.totalBusinessRules}** Business Rules`),e.push(`**${s.summary.totalClassicWorkflows}** Classic Workflows âš ī¸`),e.push(`**${s.summary.totalBusinessProcessFlows}** Business Process Flows`),e.push(`**${s.summary.totalWebResources}** Web Resources`),e.push(`**${s.summary.totalCustomAPIs}** Custom APIs`),e.push(`**${s.summary.totalEnvironmentVariables}** Environment Variables`),e.push(`**${s.summary.totalConnectionReferences}** Connection References`),e.push(`**${s.summary.totalSecurityRoles}** Security Roles`),e.push(`**${s.summary.totalFieldSecurityProfiles}** Field Security Profiles`),n.formatList(e)}generateEntityQuickLinksTable(s){const e=["Entity","Publisher","Fields","Plugins","Flows","Rules","Complexity"],t=s.map(o=>[n.formatLink(o.displayName,`entities/${o.logicalName}/overview.md`),o.publisherPrefix,o.fieldCount.toString(),o.pluginCount.toString(),o.flowCount.toString(),o.businessRuleCount.toString(),this.formatComplexityBadge(o.complexity)]);return n.formatTable(e,t)}generateNavigationLinks(){const s=[];return s.push(n.formatHeading("Summary",3)),s.push(""),s.push(n.formatList([n.formatLink("Metrics & Statistics","summary/metrics.md"),n.formatLink("All Plugins","summary/all-plugins.md"),n.formatLink("All Flows","summary/all-flows.md"),n.formatLink("All Business Rules","summary/all-business-rules.md"),n.formatLink("All Classic Workflows","summary/all-classic-workflows.md"),n.formatLink("All Web Resources","summary/all-webresources.md"),n.formatLink("All Custom APIs","summary/all-custom-apis.md"),n.formatLink("All Environment Variables","summary/all-environment-variables.md"),n.formatLink("All Connection References","summary/all-connection-references.md"),n.formatLink("All Business Process Flows","summary/all-business-process-flows.md"),n.formatLink("External Integrations","summary/external-integrations.md"),n.formatLink("Cross-Entity Automation","summary/cross-entity-automation.md"),n.formatLink("Solution Distribution","summary/solution-distribution.md")])),s.push(""),s.push(n.formatHeading("Security",3)),s.push(""),s.push(n.formatList([n.formatLink("Security Overview","security/overview.md"),n.formatLink("Field Security Profiles","security/field-security-profiles.md"),n.formatLink("Attribute Masking Rules","security/attribute-masking.md"),n.formatLink("Column Security Profiles","security/column-security.md")])),s.push(""),s.push(n.formatHeading("Analysis",3)),s.push(""),s.push(n.formatList([n.formatLink("Complexity Scores","analysis/complexity-scores.md"),n.formatLink("Performance Risks","analysis/performance-risks.md"),n.formatLink("Migration Recommendations","analysis/migration-recommendations.md")])),s.push(""),s.join(`
10
+ `)}generateMetrics(s){const e=[];e.push(n.formatHeading("Blueprint Metrics & Statistics",1)),e.push(""),e.push(n.formatHeading("Component Counts",2)),e.push("");const t=["Component Type","Count"],o=[["Entities",s.summary.totalEntities.toString()],["Attributes (Fields)",s.summary.totalAttributes.toString()],["Plugins",s.summary.totalPlugins.toString()],["Plugin Assemblies",s.summary.totalPluginPackages.toString()],["Cloud Flows",s.summary.totalFlows.toString()],["Business Rules",s.summary.totalBusinessRules.toString()],["Classic Workflows",s.summary.totalClassicWorkflows.toString()],["Business Process Flows",s.summary.totalBusinessProcessFlows.toString()],["Web Resources",s.summary.totalWebResources.toString()],["Custom APIs",s.summary.totalCustomAPIs.toString()],["Environment Variables",s.summary.totalEnvironmentVariables.toString()],["Connection References",s.summary.totalConnectionReferences.toString()],["Global Choices",s.summary.totalGlobalChoices.toString()],["Custom Connectors",s.summary.totalCustomConnectors.toString()],["Security Roles",s.summary.totalSecurityRoles.toString()],["Field Security Profiles",s.summary.totalFieldSecurityProfiles.toString()],["Canvas Apps",s.summary.totalCanvasApps.toString()],["Custom Pages",s.summary.totalCustomPages.toString()]];if(e.push(n.formatTable(t,o)),e.push(""),s.externalEndpoints&&s.externalEndpoints.length>0){e.push(n.formatHeading("External Integration Summary",2)),e.push(""),e.push(`**Total External Endpoints:** ${s.externalEndpoints.length}`),e.push("");const a=s.plugins.filter(()=>!1).length,l=s.flows.filter(r=>r.hasExternalCalls).length;e.push(`- Plugins with external calls: ${a}`),e.push(`- Flows with external calls: ${l}`),e.push(""),e.push(n.formatLink("View detailed external integrations","external-integrations.md")),e.push("")}const i=[];for(const a of s.entities)a.performanceRisks&&i.push(...a.performanceRisks);if(i.length>0){e.push(n.formatHeading("Performance Risk Summary",2)),e.push("");const a=i.filter(m=>m.severity==="Critical").length,l=i.filter(m=>m.severity==="High").length,r=i.filter(m=>m.severity==="Medium").length,u=i.filter(m=>m.severity==="Low").length;e.push(`- ${n.formatBadge(`${a} Critical`,"error")}`),e.push(`- ${n.formatBadge(`${l} High`,"error")}`),e.push(`- ${n.formatBadge(`${r} Medium`,"warning")}`),e.push(`- ${n.formatBadge(`${u} Low`,"info")}`),e.push(""),e.push(n.formatLink("View detailed performance analysis","../analysis/performance-risks.md")),e.push("")}return e.join(`
11
+ `)}generateAllPlugins(s){const e=[];if(e.push(n.formatHeading("All Plugins",1)),e.push(""),e.push(`**Total Plugins:** ${s.summary.totalPlugins}`),e.push(`**Total Assemblies:** ${s.summary.totalPluginPackages}`),e.push(""),s.plugins.length===0)return e.push("No plugins found in this scope."),e.join(`
12
+ `);const t=this.groupPluginsByAssembly(s.plugins);for(const[i,a]of t){e.push(n.formatHeading(i,2)),e.push("");for(const[l,r]of a){e.push(n.formatHeading(l,3)),e.push("");const u=["Name","Message","Stage","Mode","Rank","External","Solution","Description"],m=r.map(c=>[c.name,c.message,c.stageName,c.modeName,c.rank.toString(),this.hasExternalCalls(c)?"🌐":"",this.getPluginSolution(c,s),c.description||""]);e.push(n.formatTable(u,m)),e.push("")}}const o=s.plugins.filter(i=>i.modeName==="Synchronous"&&this.hasExternalCalls(i));if(o.length>0){e.push(n.formatHeading("âš ī¸ Performance Warnings",2)),e.push(""),e.push("The following synchronous plugins may have external calls, which can impact performance:"),e.push("");const i=["Plugin","Entity","Message","Stage"],a=o.map(l=>[l.name,l.entity,l.message,l.stageName]);e.push(n.formatTable(i,a)),e.push("")}return e.join(`
13
+ `)}generateAllFlows(s){const e=[];if(e.push(n.formatHeading("All Cloud Flows",1)),e.push(""),e.push(`**Total Flows:** ${s.summary.totalFlows}`),e.push(""),s.flows.length===0)return e.push("No flows found in this scope."),e.join(`
14
+ `);const t=this.groupFlowsByEntity(s.flows);for(const[o,i]of t){e.push(n.formatHeading(o||"Manual/Scheduled Flows",2)),e.push("");const a=["Name","Trigger","Scope","State","External","Owner","Modified","Description"],l=i.map(r=>[r.name,`${r.definition.triggerType} (${r.definition.triggerEvent})`,r.scopeName,this.formatFlowStateBadge(r.state),r.hasExternalCalls?"🌐":"",r.owner,this.formatDate(r.modifiedOn),r.description||""]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
15
+ `)}generateAllBusinessRules(s){const e=[];if(e.push(n.formatHeading("All Business Rules",1)),e.push(""),e.push(`**Total Business Rules:** ${s.summary.totalBusinessRules}`),e.push(""),s.businessRules.length===0)return e.push("No business rules found in this scope."),e.join(`
16
+ `);const t=this.groupBusinessRulesByEntity(s.businessRules);for(const[o,i]of t){e.push(n.formatHeading(o,2)),e.push("");const a=["Name","Scope","Context","State","Conditions","Actions","Modified"],l=i.map(r=>[r.name,r.scopeName,r.definition.executionContext,r.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning"),r.definition.conditions.length.toString(),r.definition.actions.length.toString(),this.formatDate(r.modifiedOn)]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
17
+ `)}generateAllClassicWorkflows(s){const e=[];if(e.push(n.formatHeading("All Classic Workflows",1)),e.push(""),e.push("âš ī¸ **Classic workflows are deprecated and require migration to Power Automate.**"),e.push(""),e.push(`**Total Classic Workflows:** ${s.summary.totalClassicWorkflows}`),e.push(""),s.classicWorkflows.length===0)return e.push("No classic workflows found in this scope."),e.join(`
18
+ `);const t=this.groupClassicWorkflowsByEntity(s.classicWorkflows);for(const[o,i]of t){e.push(n.formatHeading(o,2)),e.push("");const a=["Name","Type","Mode","Triggers","State","Migration","Modified","Description"],l=i.map(r=>{var u;return[r.name,r.typeName,r.modeName,this.formatWorkflowTriggers(r),r.state,((u=r.migrationRecommendation)==null?void 0:u.complexity)||"Unknown",this.formatDate(r.modifiedOn),r.description||""]});e.push(n.formatTable(a,l)),e.push("")}return e.push(n.formatHeading("Migration Required",2)),e.push(""),e.push("See "+n.formatLink("Migration Recommendations","../analysis/migration-recommendations.md")+" for detailed migration guidance."),e.push(""),e.join(`
19
+ `)}generateAllWebResources(s){const e=[];if(e.push(n.formatHeading("All Web Resources",1)),e.push(""),e.push(`**Total Web Resources:** ${s.summary.totalWebResources}`),e.push(""),s.webResources.length===0)return e.push("No web resources found in this scope."),e.join(`
20
+ `);const t=this.groupWebResourcesByType(s.webResources);for(const[i,a]of t){e.push(n.formatHeading(`${i} Files`,2)),e.push("");const l=["Name","Display Name","Size","External Calls","Deprecated","Modified","Description"],r=a.map(u=>[u.name,u.displayName,this.formatFileSize(u.contentSize),u.hasExternalCalls?"🌐":"",u.isDeprecated?"âš ī¸ Yes":"",this.formatDate(u.modifiedOn),u.description||""]);e.push(n.formatTable(l,r)),e.push("")}const o=s.webResources.filter(i=>i.typeName==="JavaScript"&&i.analysis);if(o.length>0){e.push(n.formatHeading("JavaScript Analysis",2)),e.push("");const i=o.filter(r=>r.isDeprecated).length,a=o.filter(r=>r.hasExternalCalls).length,l=o.filter(r=>{var u;return((u=r.analysis)==null?void 0:u.complexity)==="High"}).length;e.push(`- Using deprecated Xrm.Page API: **${i}** files`),e.push(`- With external API calls: **${a}** files`),e.push(`- High complexity: **${l}** files`),e.push("")}return e.join(`
21
+ `)}generateAllCustomAPIs(s){const e=[];if(e.push(n.formatHeading("All Custom APIs",1)),e.push(""),e.push(`**Total Custom APIs:** ${s.summary.totalCustomAPIs}`),e.push(""),s.customAPIs.length===0)return e.push("No custom APIs found in this scope."),e.join(`
22
+ `);const t=this.groupCustomAPIsByBinding(s.customAPIs);for(const[o,i]of t){e.push(n.formatHeading(`${o} APIs`,2)),e.push("");const a=["Name","Type","Bound Entity","Private","Parameters","Responses","Modified"],l=i.map(r=>[r.uniqueName,r.isFunction?"Function":"Action",r.boundEntityLogicalName||"N/A",r.isPrivate?"Yes":"No",r.requestParameters.length.toString(),r.responseProperties.length.toString(),this.formatDate(r.modifiedOn)]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
23
+ `)}generateAllEnvironmentVariables(s){const e=[];if(e.push(n.formatHeading("All Environment Variables",1)),e.push(""),e.push(`**Total Environment Variables:** ${s.summary.totalEnvironmentVariables}`),e.push(""),s.environmentVariables.length===0)return e.push("No environment variables found in this scope."),e.join(`
24
+ `);const t=["Schema Name","Type","Required","Has Value","Modified"],o=s.environmentVariables.map(a=>[a.schemaName,a.typeName,a.isRequired?"Yes":"No",a.currentValue?"Yes":"No",this.formatDate(a.modifiedOn)]);e.push(n.formatTable(t,o)),e.push("");const i=s.environmentVariables.filter(a=>a.isRequired&&!a.currentValue);return i.length>0&&(e.push(n.formatHeading("âš ī¸ Missing Required Values",2)),e.push(""),e.push("The following required environment variables have no current value:"),e.push(""),e.push(n.formatList(i.map(a=>a.schemaName))),e.push("")),e.join(`
25
+ `)}generateAllConnectionReferences(s){const e=[];if(e.push(n.formatHeading("All Connection References",1)),e.push(""),e.push(`**Total Connection References:** ${s.summary.totalConnectionReferences}`),e.push(""),s.connectionReferences.length===0)return e.push("No connection references found in this scope."),e.join(`
26
+ `);const t=["Name","Connector","Status","Modified"],o=s.connectionReferences.map(i=>[i.displayName,i.connectorDisplayName||"Unknown",i.connectionId?n.formatBadge("Connected","success"):n.formatBadge("Not Connected","error"),this.formatDate(i.modifiedOn)]);return e.push(n.formatTable(t,o)),e.push(""),e.join(`
27
+ `)}generateAllBusinessProcessFlows(s){const e=[];if(e.push(n.formatHeading("All Business Process Flows",1)),e.push(""),e.push(`**Total Business Process Flows:** ${s.summary.totalBusinessProcessFlows}`),e.push(""),s.businessProcessFlows.length===0)return e.push("No business process flows found in this scope."),e.join(`
28
+ `);const t=this.groupBpfsByEntity(s.businessProcessFlows);for(const[o,i]of t){e.push(n.formatHeading(o,2)),e.push("");const a=["Name","Stages","Entities","Cross-Entity","State","Modified"],l=i.map(r=>[r.name,r.definition.stages.length.toString(),r.definition.entities.join(", "),r.definition.crossEntityFlow?"Yes":"No",r.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning"),this.formatDate(r.modifiedOn)]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
29
+ `)}generateExternalIntegrations(s){const e=[];if(e.push(n.formatHeading("External Integrations",1)),e.push(""),!s.externalEndpoints||s.externalEndpoints.length===0)return e.push("No external integrations detected."),e.join(`
30
+ `);e.push(`**Total External Endpoints:** ${s.externalEndpoints.length}`),e.push("");const t=new Map;for(const o of s.externalEndpoints){const i=o.riskLevel;t.has(i)||t.set(i,[]),t.get(i).push(o)}for(const[o,i]of t){e.push(n.formatHeading(`${o} Risk Endpoints`,2)),e.push("");const a=["Domain","Protocol","Calls","Detected In"],l=i.map(r=>[r.domain,r.protocol.toUpperCase(),r.callCount.toString(),r.detectedIn.length.toString()+" components"]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
31
+ `)}generateCrossEntityAutomation(s){const e=[];if(e.push(n.formatHeading("Cross-Entity Automation",1)),e.push(""),!s.crossEntityLinks||s.crossEntityLinks.length===0)return e.push("> **Note:** Cross-entity automation analysis is coming in a future update."),e.join(`
32
+ `);e.push(`**Total Cross-Entity Links:** ${s.crossEntityLinks.length}`),e.push("");const t=new Map;for(const o of s.crossEntityLinks)t.has(o.automationType)||t.set(o.automationType,[]),t.get(o.automationType).push(o);for(const[o,i]of t){e.push(n.formatHeading(o,2)),e.push("");const a=["Source Entity","Target Entity","Automation","Operation","Mode"],l=i.map(r=>[r.sourceEntityDisplayName,r.targetEntityDisplayName,r.automationName,r.operation,r.isAsynchronous?"Async":"Sync"]);e.push(n.formatTable(a,l)),e.push("")}return e.join(`
33
+ `)}generateSolutionDistribution(s){const e=[];if(e.push(n.formatHeading("Solution Distribution",1)),e.push(""),!s.solutionDistribution||s.solutionDistribution.length===0)return e.push("No solution distribution information available."),e.join(`
34
+ `);for(const t of s.solutionDistribution){e.push(n.formatHeading(t.solutionName,2)),e.push(""),e.push(`**Publisher:** ${t.publisher}`),e.push(`**Version:** ${t.version}`),e.push(`**Managed:** ${t.isManaged?"Yes":"No"}`),e.push(""),e.push(n.formatHeading("Component Distribution",3)),e.push("");const o=["Component Type","Count"],i=[["Entities",t.componentCounts.entities.toString()],["Plugins",t.componentCounts.plugins.toString()],["Flows",t.componentCounts.flows.toString()],["Business Rules",t.componentCounts.businessRules.toString()],["Classic Workflows",t.componentCounts.classicWorkflows.toString()],["Business Process Flows",t.componentCounts.bpfs.toString()],["Web Resources",t.componentCounts.webResources.toString()],["Custom APIs",t.componentCounts.customAPIs.toString()],["Environment Variables",t.componentCounts.environmentVariables.toString()],["Connection References",t.componentCounts.connectionReferences.toString()],["Global Choices",t.componentCounts.globalChoices.toString()]];e.push(n.formatTable(o,i)),e.push("")}return e.join(`
35
+ `)}generateEntityOverview(s,e){var r,u,m;const t=[],o=s.entity,i=((u=(r=o.DisplayName)==null?void 0:r.UserLocalizedLabel)==null?void 0:u.Label)||o.LogicalName;t.push(n.formatHeading(`${i} - Overview`,1)),t.push(""),t.push(n.formatHeading("Quick Stats",2)),t.push(""),t.push(`- **Logical Name:** ${o.LogicalName}`),t.push(`- **Schema Name:** ${o.SchemaName}`),t.push(`- **Primary ID:** ${o.PrimaryIdAttribute}`),t.push(`- **Primary Name:** ${o.PrimaryNameAttribute}`),t.push(`- **Custom Entity:** ${o.IsCustomEntity?"Yes":"No"}`),t.push(`- **Managed:** ${o.IsManaged?"Yes":"No"}`),t.push(""),t.push(`- **Total Attributes:** ${((m=o.Attributes)==null?void 0:m.length)||0}`),t.push(`- **Plugins:** ${s.plugins.length}`),t.push(`- **Flows:** ${s.flows.length}`),t.push(`- **Business Rules:** ${s.businessRules.length}`),t.push(`- **Forms:** ${s.forms.length}`),t.push(""),t.push(n.formatHeading("Documentation",2)),t.push("");const a=[n.formatLink("Schema & Fields","schema.md")];return this.hasAutomation(s,e)&&a.push(n.formatLink("Automation Details","automation.md")),this.hasExecutionPipeline(s,e)&&a.push(n.formatLink("Execution Pipeline","execution-pipeline.md")),this.getEntityBpfs(s.entity.LogicalName,e).length>0&&a.push(n.formatLink("Business Process Flows","business-process-flows.md")),t.push(n.formatList(a)),t.push(""),t.join(`
36
+ `)}generateEntitySchema(s){var a,l,r,u;const e=[],t=s.entity,o=((l=(a=t.DisplayName)==null?void 0:a.UserLocalizedLabel)==null?void 0:l.Label)||t.LogicalName;e.push(n.formatHeading(`${o} - Schema`,1)),e.push("");const i=(u=(r=t.Description)==null?void 0:r.UserLocalizedLabel)==null?void 0:u.Label;if(i&&(e.push(i),e.push("")),e.push(n.formatHeading("Attributes",2)),e.push(""),t.Attributes&&t.Attributes.length>0){const m=["Logical Name","Display Name","Type","Required","Custom","Description"],c=t.Attributes.map(p=>{var h,f,d,y;return[p.LogicalName,((f=(h=p.DisplayName)==null?void 0:h.UserLocalizedLabel)==null?void 0:f.Label)||"",p.AttributeType,p.RequiredLevel.Value,p.IsCustomAttribute?"Yes":"No",((y=(d=p.Description)==null?void 0:d.UserLocalizedLabel)==null?void 0:y.Label)||""]});e.push(n.formatTable(m,c)),e.push("")}else e.push("No attributes found."),e.push("");if(t.ManyToOneRelationships&&t.ManyToOneRelationships.length>0){e.push(n.formatHeading("Many-to-One Relationships (Lookups)",2)),e.push("");const m=["Schema Name","Referenced Entity","Referencing Attribute","Custom"],c=t.ManyToOneRelationships.map(p=>[p.SchemaName,p.ReferencedEntity,p.ReferencingAttribute,p.IsCustomRelationship?"Yes":"No"]);e.push(n.formatTable(m,c)),e.push("")}if(t.OneToManyRelationships&&t.OneToManyRelationships.length>0){e.push(n.formatHeading("One-to-Many Relationships",2)),e.push("");const m=["Schema Name","Referencing Entity","Referencing Attribute","Custom"],c=t.OneToManyRelationships.map(p=>[p.SchemaName,p.ReferencingEntity,p.ReferencingAttribute,p.IsCustomRelationship?"Yes":"No"]);e.push(n.formatTable(m,c)),e.push("")}if(t.ManyToManyRelationships&&t.ManyToManyRelationships.length>0){e.push(n.formatHeading("Many-to-Many Relationships",2)),e.push("");const m=["Schema Name","Entity 1","Entity 2","Intersect Table","Custom"],c=t.ManyToManyRelationships.map(p=>[p.SchemaName,p.Entity1LogicalName,p.Entity2LogicalName,p.IntersectEntityName,p.IsCustomRelationship?"Yes":"No"]);e.push(n.formatTable(m,c)),e.push("")}if(t.Keys&&t.Keys.length>0){e.push(n.formatHeading("Alternate Keys",2)),e.push("");const m=["Logical Name","Key Attributes","Status"],c=t.Keys.map(p=>[p.LogicalName,p.KeyAttributes.join(", "),p.EntityKeyIndexStatus||"Unknown"]);e.push(n.formatTable(m,c)),e.push("")}if(s.fieldSecurity&&s.fieldSecurity.securedFields.length>0){e.push(n.formatHeading("Field Security",2)),e.push(""),e.push(`This entity has **${s.fieldSecurity.securedFields.length}** secured field(s) with field-level permissions.`),e.push("");const m=["Field","Profiles with Access"],c=[];for(const p of s.fieldSecurity.securedFields){const h=p.profiles.map(f=>{const d=[];return f.canRead&&d.push("R"),f.canCreate&&d.push("C"),f.canUpdate&&d.push("U"),`${f.profileName} (${d.join(", ")})`}).join("; ");c.push([p.attributeLogicalName,h])}e.push(n.formatTable(m,c)),e.push(""),e.push("**Permissions:** R = Read, C = Create, U = Update"),e.push("")}return e.join(`
37
+ `)}generateEntityAutomation(s,e){var l,r;const t=[],o=s.entity,i=((r=(l=o.DisplayName)==null?void 0:l.UserLocalizedLabel)==null?void 0:r.Label)||o.LogicalName;if(t.push(n.formatHeading(`${i} - Automation`,1)),t.push(""),s.plugins.length>0){t.push(n.formatHeading("Plugins",2)),t.push("");const u=["Name","Message","Stage","Mode","Rank","Assembly"],m=s.plugins.map(c=>[c.name,c.message,c.stageName,c.modeName,c.rank.toString(),c.assemblyName]);t.push(n.formatTable(u,m)),t.push("")}if(s.flows.length>0){t.push(n.formatHeading("Cloud Flows",2)),t.push("");const u=["Name","Trigger","Scope","State","External"],m=s.flows.map(c=>[c.name,`${c.definition.triggerType} (${c.definition.triggerEvent})`,c.scopeName,this.formatFlowStateBadge(c.state),c.hasExternalCalls?"🌐":""]);t.push(n.formatTable(u,m)),t.push("")}if(s.businessRules.length>0){t.push(n.formatHeading("Business Rules",2)),t.push("");const u=["Name","Scope","Context","State","Conditions","Actions"],m=s.businessRules.map(c=>[c.name,c.scopeName,c.definition.executionContext,c.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning"),c.definition.conditions.length.toString(),c.definition.actions.length.toString()]);t.push(n.formatTable(u,m)),t.push("")}if(s.forms.length>0){const u=s.forms.flatMap(m=>m.eventHandlers);if(u.length>0){t.push(n.formatHeading("JavaScript Event Handlers",2)),t.push("");const m=["Event","Library","Function","Attribute","Enabled"],c=u.map(p=>[p.event,p.libraryName,p.functionName,p.attribute||"N/A",p.enabled?"Yes":"No"]);t.push(n.formatTable(m,c)),t.push("")}}const a=e.classicWorkflowsByEntity.get(o.LogicalName)||[];if(a.length>0){t.push(n.formatHeading("Classic Workflows (Deprecated)",2)),t.push(""),t.push("âš ī¸ These workflows require migration to Power Automate."),t.push("");const u=["Name","Type","Mode","Triggers","State"],m=a.map(c=>[c.name,c.typeName,c.modeName,this.formatWorkflowTriggers(c),c.state]);t.push(n.formatTable(u,m)),t.push("")}return t.join(`
38
+ `)}generateExecutionPipeline(s,e){var u,m;const t=[],o=s.entity,i=((m=(u=o.DisplayName)==null?void 0:u.UserLocalizedLabel)==null?void 0:m.Label)||o.LogicalName;t.push(n.formatHeading(`${i} - Execution Pipeline`,1)),t.push(""),t.push("This page shows the execution order of server-side automation on this entity."),t.push("");const a=new Map;for(const c of s.plugins){const p=c.message;a.has(p)||a.set(p,[]),a.get(p).push(c)}if(s.plugins.length===0){if(t.push("**No plugins registered on this entity.**"),t.push(""),s.businessRules.length>0){t.push(n.formatHeading("Business Rules",2)),t.push("");const p=["Name","Scope","State"],h=s.businessRules.map(f=>[f.name,f.scopeName,f.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning")]);t.push(n.formatTable(p,h)),t.push("")}const c=s.flows.filter(p=>p.definition.triggerType==="Dataverse");if(c.length>0){t.push(n.formatHeading("Dataverse Flows",2)),t.push("");const p=["Name","Trigger Event","Scope"],h=c.map(f=>[f.name,f.definition.triggerEvent,f.scopeName]);t.push(n.formatTable(p,h)),t.push("")}return t.join(`
39
+ `)}const l=s.businessRules.filter(c=>c.scopeName==="Entity");for(const[c,p]of a){t.push(n.formatHeading(`${c} Event`,2)),t.push("");const h=[...p].sort((g,w)=>g.stage!==w.stage?g.stage-w.stage:g.rank-w.rank),f=new Map;for(const g of h)f.has(g.stage)||f.set(g.stage,[]),f.get(g.stage).push(g);t.push(n.formatCodeBlock(this.generateSimplePipelineASCII(f,l),"text")),t.push(""),t.push(n.formatHeading("Execution Details",3)),t.push("");const d=["Order","Type","Name","Stage/Details","Mode","Rank"],y=[];l.length>0&&l.forEach(g=>{y.push([(y.length+1).toString(),"Business Rule",g.name,"Server-side (Entity scope)",g.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning"),"-"])}),h.forEach(g=>{y.push([(y.length+1).toString(),"Plugin",g.name,g.stageName,g.modeName,g.rank.toString()])}),t.push(n.formatTable(d,y)),t.push("");const b=h.filter(g=>g.mode===0);b.length>0&&(t.push(n.formatHeading("â„šī¸ Synchronous Plugins",3)),t.push(""),t.push(`${b.length} synchronous plugin(s) execute in this pipeline. Synchronous plugins block the transaction and should complete quickly.`),t.push(""))}if(s.businessRules.length>0){t.push(n.formatHeading("Business Rules",2)),t.push(""),t.push("Business rules execute on the client (form) or server depending on their scope."),t.push("");const c=["Name","Scope","Context","State"],p=s.businessRules.map(h=>[h.name,h.scopeName,h.definition.executionContext,h.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning")]);t.push(n.formatTable(c,p)),t.push("")}const r=s.flows.filter(c=>c.definition.triggerType==="Dataverse");if(r.length>0){t.push(n.formatHeading("Dataverse Flows (Real-time)",2)),t.push(""),t.push("These flows trigger when data changes occur."),t.push("");const c=["Name","Trigger Event","Scope","State"],p=r.map(h=>[h.name,h.definition.triggerEvent,h.scopeName,this.formatFlowStateBadge(h.state)]);t.push(n.formatTable(c,p)),t.push("")}return t.join(`
40
+ `)}generateSimplePipelineASCII(s,e){const t=[];if(t.push("Execution Order:"),t.push(""),e.length>0){t.push("┌─ Business Rules (Server-side, Entity-scoped)"),t.push("│");for(let i=0;i<e.length;i++){const a=e[i],l=i===e.length-1&&s.size===0,r=l?"└─":"├─",u=a.state==="Active"?"[ACTIVE]":"[DRAFT]";t.push(`${r} ${i+1}. ${a.name} ${u}`),l||t.push("│")}t.push("")}let o=0;for(const[i,a]of s){const l=a[0].stageName,r=o===s.size-1;t.push(`┌─ Stage ${i}: ${l}`),t.push("│");for(let u=0;u<a.length;u++){const m=a[u],c=u===a.length-1,p=c&&r?"└─":"├─",h=m.mode===0?"[SYNC]":"[ASYNC]";t.push(`${p} ${u+1}. ${m.name} ${h}`),!c||!r?t.push("│ (Rank: "+m.rank+")"):t.push(" (Rank: "+m.rank+")"),c||t.push("│")}t.push(""),o++}return t.join(`
41
+ `)}generateEntityBpfs(s,e){var a,l;const t=[],o=s.entity,i=((l=(a=o.DisplayName)==null?void 0:a.UserLocalizedLabel)==null?void 0:l.Label)||o.LogicalName;t.push(n.formatHeading(`${i} - Business Process Flows`,1)),t.push("");for(const r of e){t.push(n.formatHeading(r.name,2)),t.push(""),r.description&&(t.push(r.description),t.push("")),t.push(`**State:** ${r.state==="Active"?n.formatBadge("Active","success"):n.formatBadge("Draft","warning")}`),t.push(`**Entities:** ${r.definition.entities.join(", ")}`),t.push(`**Cross-Entity:** ${r.definition.crossEntityFlow?"Yes":"No"}`),t.push(""),t.push(n.formatHeading("Stages",3)),t.push("");for(const u of r.definition.stages){if(t.push(`**${u.order}. ${u.name}** (${u.entity})`),t.push(""),u.steps.length>0){const m=u.steps.map(c=>`${c.name} (${c.fieldName})${c.required?" *Required*":""}`);t.push(n.formatList(m))}t.push("")}}return t.join(`
42
+ `)}generateComplexityScores(s){const e=[];e.push(n.formatHeading("Entity Complexity Scores",1)),e.push("");const t=s.entities.map(a=>{var r,u;const l=this.calculateComplexityScore(a,s);return{entity:a.entity.LogicalName,displayName:((u=(r=a.entity.DisplayName)==null?void 0:r.UserLocalizedLabel)==null?void 0:u.Label)||a.entity.LogicalName,score:l.total,complexity:l.level,breakdown:l.breakdown}});t.sort((a,l)=>l.score-a.score);const o=["Entity","Score","Complexity","Fields","Plugins","Flows","Rules"],i=t.map(a=>[a.displayName,a.score.toString(),this.formatComplexityBadge(a.complexity),a.breakdown.attributes.toString(),a.breakdown.plugins.toString(),a.breakdown.flows.toString(),a.breakdown.businessRules.toString()]);return e.push(n.formatTable(o,i)),e.push(""),e.push(n.formatHeading("Scoring Methodology",2)),e.push(""),e.push("Complexity score is calculated based on:"),e.push(""),e.push(n.formatList(["Attributes: 1 point each","Plugins: 5 points each","Flows: 3 points each","Business Rules: 2 points each","Forms: 2 points each"])),e.push(""),e.push("**Complexity Levels:**"),e.push("- Low: 0-50 points"),e.push("- Medium: 51-150 points"),e.push("- High: 151+ points"),e.push(""),e.join(`
43
+ `)}generatePerformanceRisks(s){const e=[];e.push(n.formatHeading("Performance Risks",1)),e.push("");const t=[];for(const i of s.entities)if(i.performanceRisks)for(const a of i.performanceRisks)t.push({...a,entity:i.entity.LogicalName});if(t.length===0)return e.push("No performance risks detected."),e.join(`
44
+ `);const o=new Map;for(const i of t)o.has(i.severity)||o.set(i.severity,[]),o.get(i.severity).push(i);for(const i of["Critical","High","Medium","Low"]){const a=o.get(i)||[];if(a.length===0)continue;e.push(n.formatHeading(`${i} Risk (${a.length})`,2)),e.push("");const l=["Entity","Step","Type","Reason","Recommendation"],r=a.map(u=>[u.entity,u.step.name,u.step.type,u.reason,u.recommendation]);e.push(n.formatTable(l,r)),e.push("")}return e.join(`
45
+ `)}generateMigrationRecommendations(s){var o;const e=[];if(e.push(n.formatHeading("Migration Recommendations",1)),e.push(""),s.classicWorkflows.length===0)return e.push("No classic workflows found. No migration needed."),e.join(`
46
+ `);e.push("âš ī¸ **Classic workflows are deprecated and will be retired by Microsoft.**"),e.push(""),e.push(`**Total Classic Workflows:** ${s.classicWorkflows.length}`),e.push("");const t=new Map;for(const i of s.classicWorkflows){const a=((o=i.migrationRecommendation)==null?void 0:o.complexity)||"Unknown";t.has(a)||t.set(a,[]),t.get(a).push(i)}for(const i of["Critical","High","Medium","Low"]){const a=t.get(i)||[];if(a.length===0)continue;e.push(n.formatHeading(`${i} Complexity (${a.length})`,2)),e.push("");const l=["Workflow","Entity","Type","Effort","Approach"],r=a.map(u=>{var m,c;return[u.name,u.entityDisplayName||u.entity,u.typeName,((m=u.migrationRecommendation)==null?void 0:m.effort)||"Unknown",((c=u.migrationRecommendation)==null?void 0:c.approach.substring(0,50))+"..."||"Unknown"]});e.push(n.formatTable(l,r)),e.push("")}return e.push(n.formatHeading("General Migration Guidance",2)),e.push(""),e.push(n.formatList(["Prioritize critical and high complexity workflows first","Test thoroughly in a development environment before production","Update security roles and permissions for Power Automate","Consider using connection references for external integrations","Document any custom logic that may need reimplementation","Plan for user training on new flow behavior"])),e.push(""),e.push("**Resources:**"),e.push("- "+n.formatLink("Microsoft Migration Guide","https://learn.microsoft.com/power-automate/migrate-from-classic-workflows")),e.push(""),e.join(`
47
+ `)}buildFileTree(s){const e={name:"blueprint",type:"directory",path:"blueprint",children:[]};for(const t of s.keys())this.addFileToTree(e,t,s.get(t));return e}addFileToTree(s,e,t){const o=e.split("/");let i=s;for(let a=0;a<o.length;a++){const l=o[a],r=a===o.length-1;i.children||(i.children=[]);let u=i.children.find(m=>m.name===l);u||(u={name:l,type:r?"file":"directory",path:`blueprint/${o.slice(0,a+1).join("/")}`,children:r?void 0:[]},r&&(u.size=new TextEncoder().encode(t).length),i.children.push(u)),i=u}}hasAutomation(s,e){return s.plugins.length>0||s.flows.length>0||s.businessRules.length>0||s.forms.flatMap(i=>i.eventHandlers).length>0||(e.classicWorkflowsByEntity.get(s.entity.LogicalName)||[]).length>0}hasExecutionPipeline(s,e){return!!(s.plugins.length>0||s.businessRules.some(l=>l.scopeName==="Entity")||(e.classicWorkflowsByEntity.get(s.entity.LogicalName)||[]).some(l=>l.mode===0)||s.flows.some(l=>l.definition.triggerType==="Dataverse"))}getEntityBpfs(s,e){return e.businessProcessFlowsByEntity.get(s)||[]}formatComplexityBadge(s){return{Low:n.formatBadge("Low","success"),Medium:n.formatBadge("Medium","warning"),High:n.formatBadge("High","error")}[s]}formatFlowStateBadge(s){return{Active:n.formatBadge("Active","success"),Draft:n.formatBadge("Draft","warning"),Suspended:n.formatBadge("Suspended","error")}[s]}formatDate(s){return new Date(s).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}formatFileSize(s){if(s===0)return"0 B";const e=1024,t=["B","KB","MB","GB"],o=Math.floor(Math.log(s)/Math.log(e));return Math.round(s/Math.pow(e,o)*100)/100+" "+t[o]}formatWorkflowTriggers(s){const e=[];return s.triggerOnCreate&&e.push("Create"),s.triggerOnUpdate&&e.push("Update"),s.triggerOnDelete&&e.push("Delete"),s.onDemand&&e.push("Manual"),e.join(", ")||"None"}hasExternalCalls(s){return!1}getPluginSolution(s,e){return"Unknown"}groupPluginsByAssembly(s){const e=new Map;for(const t of s){e.has(t.assemblyName)||e.set(t.assemblyName,new Map);const o=e.get(t.assemblyName);o.has(t.entity)||o.set(t.entity,[]),o.get(t.entity).push(t)}return e}groupFlowsByEntity(s){const e=new Map;for(const t of s){const o=t.entity||"Manual/Scheduled";e.has(o)||e.set(o,[]),e.get(o).push(t)}return e}groupBusinessRulesByEntity(s){const e=new Map;for(const t of s)e.has(t.entity)||e.set(t.entity,[]),e.get(t.entity).push(t);return e}groupClassicWorkflowsByEntity(s){const e=new Map;for(const t of s)e.has(t.entity)||e.set(t.entity,[]),e.get(t.entity).push(t);return e}groupWebResourcesByType(s){const e=new Map;for(const t of s)e.has(t.typeName)||e.set(t.typeName,[]),e.get(t.typeName).push(t);return e}groupCustomAPIsByBinding(s){const e=new Map;for(const t of s)e.has(t.bindingType)||e.set(t.bindingType,[]),e.get(t.bindingType).push(t);return e}groupBpfsByEntity(s){const e=new Map;for(const t of s){const o=t.primaryEntityDisplayName||t.primaryEntity;e.has(o)||e.set(o,[]),e.get(o).push(t)}return e}calculateComplexityScore(s,e){var a;const t={attributes:((a=s.entity.Attributes)==null?void 0:a.length)||0,plugins:s.plugins.length,flows:s.flows.length,businessRules:s.businessRules.length,forms:s.forms.length},o=t.attributes*1+t.plugins*5+t.flows*3+t.businessRules*2+t.forms*2;let i;return o<=50?i="Low":o<=150?i="Medium":i="High",{total:o,level:i,breakdown:t}}generateSecurityOverview(s){const e=[];if(e.push(n.formatHeading("Security Overview",1)),e.push(""),e.push("This document provides an overview of security roles and field security profiles in the solution."),e.push(""),s.securityRoles&&s.securityRoles.length>0){e.push(n.formatHeading("Security Roles",2)),e.push(""),e.push(`Found **${s.securityRoles.length}** security role(s) in the selected solution(s).`),e.push(""),e.push(n.formatHeading("Special Permissions Matrix",3)),e.push(""),e.push("This table shows which security roles have special/miscellaneous permissions."),e.push("");const t=["documentGeneration","dynamics365ForMobile","exportToExcel","goOfflineInOutlook","mailMerge","print","syncToOutlook","useDynamics365AppForOutlook","activateRealtimeProcesses","executeWorkflowJob","runFlows"],o=["Role Name","Business Unit",...t.map(r=>this.formatSpecialPermissionName(r))],i=[];for(const r of s.securityRoles){const u=[`[${r.name}](roles/${r.name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase()}.md)`,r.businessunitname||"Unknown"];for(const m of t)u.push(r.specialPermissions[m]?"✓":"");i.push(u)}e.push(n.formatTable(o,i)),e.push(""),e.push(n.formatHeading("Role Summary",3)),e.push("");const a=["Role Name","Business Unit","Entities","System Admin","Managed"],l=[];for(const r of s.securityRoles)l.push([`[${r.name}](roles/${r.name.replace(/[^a-zA-Z0-9]/g,"-").toLowerCase()}.md)`,r.businessunitname||"Unknown",r.totalEntities.toString(),r.hasSystemAdminPrivileges?"Yes":"No",r.ismanaged?"Yes":"No"]);e.push(n.formatTable(a,l)),e.push("")}return s.fieldSecurityProfiles&&s.fieldSecurityProfiles.length>0&&(e.push(n.formatHeading("Field Security Profiles",2)),e.push(""),e.push(`Found **${s.fieldSecurityProfiles.length}** field security profile(s) in the selected solution(s).`),e.push(""),e.push("[View Field Security Profiles Details](field-security-profiles.md)"),e.push("")),e.join(`
48
+ `)}generateSecurityRoleDetail(s){const e=[];e.push(n.formatHeading(`Security Role: ${s.name}`,1)),e.push(""),e.push(n.formatHeading("Details",2)),e.push(""),e.push(`- **Business Unit:** ${s.businessunitname||"Unknown"}`),e.push(`- **Is Managed:** ${s.ismanaged?"Yes":"No"}`),e.push(`- **Is Customizable:** ${s.iscustomizable?"Yes":"No"}`),e.push(`- **Has System Admin Privileges:** ${s.hasSystemAdminPrivileges?"Yes":"No"}`),e.push(`- **Total Entities with Permissions:** ${s.totalEntities}`),s.description&&e.push(`- **Description:** ${s.description}`),e.push(""),e.push(n.formatHeading("Special Permissions",2)),e.push("");const t=Object.entries(s.specialPermissions).filter(([o,i])=>i).map(([o])=>this.formatSpecialPermissionName(o));if(t.length>0)for(const o of t)e.push(`- ✓ ${o}`);else e.push("*No special permissions granted*");if(e.push(""),e.push(n.formatHeading("Entity Permissions",2)),e.push(""),s.entityPermissions.length>0){e.push(`This role has permissions on **${s.entityPermissions.length}** entit${s.entityPermissions.length===1?"y":"ies"}.`),e.push("");const o=["Entity","Create","Read","Write","Delete","Append","AppendTo","Assign","Share"],i=[];for(const a of s.entityPermissions){if(a.privileges.length===0)continue;const l=[a.entityLogicalName],r=new Map(a.privileges.map(u=>[u.type,u]));for(const u of["Create","Read","Write","Delete","Append","AppendTo","Assign","Share"]){const m=r.get(u);l.push(m?m.depth:"")}i.push(l)}e.push(n.formatTable(o,i)),e.push(""),e.push("**Privilege Depth Legend:**"),e.push("- **Basic** - User level (own records only)"),e.push("- **Local** - Business unit level"),e.push("- **Deep** - Parent and child business units"),e.push("- **Global** - Organization level (all records)"),e.push("")}else e.push("*No entity permissions defined*"),e.push("");return e.join(`
49
+ `)}generateFieldSecurityProfiles(s){const e=[];if(e.push(n.formatHeading("Field Security Profiles",1)),e.push(""),e.push("Field security profiles control who can read, create, or update specific secured fields."),e.push(""),s.fieldSecurityProfiles&&s.fieldSecurityProfiles.length>0){const t=["Profile Name","Description"],o=[];for(const i of s.fieldSecurityProfiles)o.push([i.name,i.description||"*No description*"]);e.push(n.formatTable(t,o)),e.push(""),e.push("> **Note:** Field-level permissions for specific entities are documented in each entity's schema page."),e.push("")}else e.push("*No field security profiles found*"),e.push("");return e.join(`
50
+ `)}generateAttributeMaskingRules(s){const e=[];if(e.push(n.formatHeading("Attribute Masking Rules",1)),e.push(""),e.push("Attribute masking rules control how sensitive data is masked when displayed to users without appropriate permissions."),e.push(""),s.attributeMaskingRules&&s.attributeMaskingRules.length>0){const t=["Entity","Attribute","Masking Type","Managed"],o=[];for(const i of s.attributeMaskingRules){const a=i.maskingtype===1?"Full":i.maskingtype===2?"Partial":i.maskingtype===3?"Email":"Custom";o.push([i.entitylogicalname,i.attributelogicalname,a,i.ismanaged?"Yes":"No"])}e.push(n.formatTable(t,o)),e.push(""),e.push("**Masking Types:**"),e.push("- **Full**: Entire value is masked"),e.push("- **Partial**: Part of the value is shown"),e.push("- **Email**: Email format is preserved while masking"),e.push("- **Custom**: Custom masking format is applied"),e.push("")}else e.push("*No attribute masking rules found*"),e.push("");return e.join(`
51
+ `)}generateColumnSecurityProfiles(s){const e=[];if(e.push(n.formatHeading("Column Security Profiles",1)),e.push(""),e.push("Column security profiles define which users can access specific secured columns across entities."),e.push(""),s.columnSecurityProfiles&&s.columnSecurityProfiles.length>0){const t=["Profile Name","Description","Managed"],o=[];for(const i of s.columnSecurityProfiles)o.push([i.name,i.description||"*No description*",i.ismanaged?"Yes":"No"]);e.push(n.formatTable(t,o)),e.push(""),e.push("> **Note:** Column-level permissions control create, read, and update access to secured fields."),e.push("")}else e.push("*No column security profiles found*"),e.push("");return e.join(`
52
+ `)}formatSpecialPermissionName(s){return s.replace(/([A-Z])/g," $1").replace(/^./,e=>e.toUpperCase()).trim()}}export{N as MarkdownReporter};
53
+ //# sourceMappingURL=MarkdownReporter-B1FEpc6-.js.map