@jterrats/smart-deployment 1.0.3
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.
- package/README.md +193 -0
- package/lib/ai/agentforce-error-handler.d.ts +81 -0
- package/lib/ai/agentforce-error-handler.js +196 -0
- package/lib/ai/agentforce-error-handler.js.map +1 -0
- package/lib/ai/agentforce-priority-service.d.ts +82 -0
- package/lib/ai/agentforce-priority-service.js +257 -0
- package/lib/ai/agentforce-priority-service.js.map +1 -0
- package/lib/ai/agentforce-service.d.ts +99 -0
- package/lib/ai/agentforce-service.js +300 -0
- package/lib/ai/agentforce-service.js.map +1 -0
- package/lib/ai/circuit-breaker.d.ts +115 -0
- package/lib/ai/circuit-breaker.js +277 -0
- package/lib/ai/circuit-breaker.js.map +1 -0
- package/lib/ai/dependency-inference-service.d.ts +76 -0
- package/lib/ai/dependency-inference-service.js +220 -0
- package/lib/ai/dependency-inference-service.js.map +1 -0
- package/lib/ai/llm-provider-factory.d.ts +15 -0
- package/lib/ai/llm-provider-factory.js +36 -0
- package/lib/ai/llm-provider-factory.js.map +1 -0
- package/lib/ai/llm-provider.d.ts +27 -0
- package/lib/ai/llm-provider.js +2 -0
- package/lib/ai/llm-provider.js.map +1 -0
- package/lib/ai/openai-service.d.ts +20 -0
- package/lib/ai/openai-service.js +89 -0
- package/lib/ai/openai-service.js.map +1 -0
- package/lib/ai/prompt-builder.d.ts +79 -0
- package/lib/ai/prompt-builder.js +180 -0
- package/lib/ai/prompt-builder.js.map +1 -0
- package/lib/ai/response-parser.d.ts +67 -0
- package/lib/ai/response-parser.js +234 -0
- package/lib/ai/response-parser.js.map +1 -0
- package/lib/ai/wave-validation-service.d.ts +111 -0
- package/lib/ai/wave-validation-service.js +381 -0
- package/lib/ai/wave-validation-service.js.map +1 -0
- package/lib/analysis/analysis-reporter.d.ts +56 -0
- package/lib/analysis/analysis-reporter.js +170 -0
- package/lib/analysis/analysis-reporter.js.map +1 -0
- package/lib/analytics/error-analytics.d.ts +80 -0
- package/lib/analytics/error-analytics.js +162 -0
- package/lib/analytics/error-analytics.js.map +1 -0
- package/lib/commands/analyze.d.ts +49 -0
- package/lib/commands/analyze.js +232 -0
- package/lib/commands/analyze.js.map +1 -0
- package/lib/commands/config.d.ts +42 -0
- package/lib/commands/config.js +219 -0
- package/lib/commands/config.js.map +1 -0
- package/lib/commands/resume.d.ts +26 -0
- package/lib/commands/resume.js +69 -0
- package/lib/commands/resume.js.map +1 -0
- package/lib/commands/start.d.ts +70 -0
- package/lib/commands/start.js +659 -0
- package/lib/commands/start.js.map +1 -0
- package/lib/commands/status.d.ts +37 -0
- package/lib/commands/status.js +69 -0
- package/lib/commands/status.js.map +1 -0
- package/lib/commands/validate.d.ts +33 -0
- package/lib/commands/validate.js +66 -0
- package/lib/commands/validate.js.map +1 -0
- package/lib/config/repo-config.d.ts +22 -0
- package/lib/config/repo-config.js +31 -0
- package/lib/config/repo-config.js.map +1 -0
- package/lib/constants/agentforce-limits.d.ts +174 -0
- package/lib/constants/agentforce-limits.js +262 -0
- package/lib/constants/agentforce-limits.js.map +1 -0
- package/lib/constants/api-version.d.ts +70 -0
- package/lib/constants/api-version.js +122 -0
- package/lib/constants/api-version.js.map +1 -0
- package/lib/constants/deployment-order.d.ts +68 -0
- package/lib/constants/deployment-order.js +162 -0
- package/lib/constants/deployment-order.js.map +1 -0
- package/lib/constants/salesforce-limits.d.ts +107 -0
- package/lib/constants/salesforce-limits.js +104 -0
- package/lib/constants/salesforce-limits.js.map +1 -0
- package/lib/dependencies/circular-dependency-detector.d.ts +137 -0
- package/lib/dependencies/circular-dependency-detector.js +329 -0
- package/lib/dependencies/circular-dependency-detector.js.map +1 -0
- package/lib/dependencies/cycle-remediation-planner.d.ts +50 -0
- package/lib/dependencies/cycle-remediation-planner.js +192 -0
- package/lib/dependencies/cycle-remediation-planner.js.map +1 -0
- package/lib/dependencies/dependency-cache.d.ts +134 -0
- package/lib/dependencies/dependency-cache.js +303 -0
- package/lib/dependencies/dependency-cache.js.map +1 -0
- package/lib/dependencies/dependency-depth-calculator.d.ts +145 -0
- package/lib/dependencies/dependency-depth-calculator.js +368 -0
- package/lib/dependencies/dependency-depth-calculator.js.map +1 -0
- package/lib/dependencies/dependency-graph-builder.d.ts +151 -0
- package/lib/dependencies/dependency-graph-builder.js +411 -0
- package/lib/dependencies/dependency-graph-builder.js.map +1 -0
- package/lib/dependencies/dependency-impact-analyzer.d.ts +145 -0
- package/lib/dependencies/dependency-impact-analyzer.js +330 -0
- package/lib/dependencies/dependency-impact-analyzer.js.map +1 -0
- package/lib/dependencies/dependency-merger.d.ts +122 -0
- package/lib/dependencies/dependency-merger.js +245 -0
- package/lib/dependencies/dependency-merger.js.map +1 -0
- package/lib/dependencies/dependency-resolver.d.ts +157 -0
- package/lib/dependencies/dependency-resolver.js +298 -0
- package/lib/dependencies/dependency-resolver.js.map +1 -0
- package/lib/dependencies/dependency-validator.d.ts +123 -0
- package/lib/dependencies/dependency-validator.js +291 -0
- package/lib/dependencies/dependency-validator.js.map +1 -0
- package/lib/dependencies/graph-visualizer.d.ts +110 -0
- package/lib/dependencies/graph-visualizer.js +262 -0
- package/lib/dependencies/graph-visualizer.js.map +1 -0
- package/lib/dependencies/heuristic-inference.d.ts +136 -0
- package/lib/dependencies/heuristic-inference.js +430 -0
- package/lib/dependencies/heuristic-inference.js.map +1 -0
- package/lib/deployment/cycle-source-editor.d.ts +34 -0
- package/lib/deployment/cycle-source-editor.js +121 -0
- package/lib/deployment/cycle-source-editor.js.map +1 -0
- package/lib/deployment/deployment-error-handler.d.ts +38 -0
- package/lib/deployment/deployment-error-handler.js +79 -0
- package/lib/deployment/deployment-error-handler.js.map +1 -0
- package/lib/deployment/deployment-reporter.d.ts +63 -0
- package/lib/deployment/deployment-reporter.js +150 -0
- package/lib/deployment/deployment-reporter.js.map +1 -0
- package/lib/deployment/deployment-state-summary.d.ts +38 -0
- package/lib/deployment/deployment-state-summary.js +209 -0
- package/lib/deployment/deployment-state-summary.js.map +1 -0
- package/lib/deployment/deployment-status-service.d.ts +36 -0
- package/lib/deployment/deployment-status-service.js +128 -0
- package/lib/deployment/deployment-status-service.js.map +1 -0
- package/lib/deployment/deployment-tracker.d.ts +42 -0
- package/lib/deployment/deployment-tracker.js +79 -0
- package/lib/deployment/deployment-tracker.js.map +1 -0
- package/lib/deployment/deployment-validation-service.d.ts +28 -0
- package/lib/deployment/deployment-validation-service.js +161 -0
- package/lib/deployment/deployment-validation-service.js.map +1 -0
- package/lib/deployment/retry-handler.d.ts +37 -0
- package/lib/deployment/retry-handler.js +86 -0
- package/lib/deployment/retry-handler.js.map +1 -0
- package/lib/deployment/sf-cli-integration.d.ts +42 -0
- package/lib/deployment/sf-cli-integration.js +105 -0
- package/lib/deployment/sf-cli-integration.js.map +1 -0
- package/lib/deployment/state-manager.d.ts +61 -0
- package/lib/deployment/state-manager.js +83 -0
- package/lib/deployment/state-manager.js.map +1 -0
- package/lib/deployment/test-executor.d.ts +41 -0
- package/lib/deployment/test-executor.js +87 -0
- package/lib/deployment/test-executor.js.map +1 -0
- package/lib/errors/base-error.d.ts +24 -0
- package/lib/errors/base-error.js +66 -0
- package/lib/errors/base-error.js.map +1 -0
- package/lib/errors/dependency-error.d.ts +37 -0
- package/lib/errors/dependency-error.js +76 -0
- package/lib/errors/dependency-error.js.map +1 -0
- package/lib/errors/deployment-error.d.ts +55 -0
- package/lib/errors/deployment-error.js +132 -0
- package/lib/errors/deployment-error.js.map +1 -0
- package/lib/errors/index.d.ts +45 -0
- package/lib/errors/index.js +71 -0
- package/lib/errors/index.js.map +1 -0
- package/lib/errors/network-error.d.ts +53 -0
- package/lib/errors/network-error.js +111 -0
- package/lib/errors/network-error.js.map +1 -0
- package/lib/errors/parsing-error.d.ts +41 -0
- package/lib/errors/parsing-error.js +69 -0
- package/lib/errors/parsing-error.js.map +1 -0
- package/lib/errors/validation-error-reporter.d.ts +34 -0
- package/lib/errors/validation-error-reporter.js +99 -0
- package/lib/errors/validation-error-reporter.js.map +1 -0
- package/lib/errors/validation-error.d.ts +58 -0
- package/lib/errors/validation-error.js +131 -0
- package/lib/errors/validation-error.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/monitoring/performance-monitor.d.ts +98 -0
- package/lib/monitoring/performance-monitor.js +260 -0
- package/lib/monitoring/performance-monitor.js.map +1 -0
- package/lib/parsers/apex-class-parser.d.ts +47 -0
- package/lib/parsers/apex-class-parser.js +368 -0
- package/lib/parsers/apex-class-parser.js.map +1 -0
- package/lib/parsers/apex-trigger-parser.d.ts +48 -0
- package/lib/parsers/apex-trigger-parser.js +229 -0
- package/lib/parsers/apex-trigger-parser.js.map +1 -0
- package/lib/parsers/aura-parser.d.ts +55 -0
- package/lib/parsers/aura-parser.js +229 -0
- package/lib/parsers/aura-parser.js.map +1 -0
- package/lib/parsers/bot-parser.d.ts +65 -0
- package/lib/parsers/bot-parser.js +225 -0
- package/lib/parsers/bot-parser.js.map +1 -0
- package/lib/parsers/custom-metadata-parser.d.ts +94 -0
- package/lib/parsers/custom-metadata-parser.js +199 -0
- package/lib/parsers/custom-metadata-parser.js.map +1 -0
- package/lib/parsers/custom-object-parser.d.ts +62 -0
- package/lib/parsers/custom-object-parser.js +297 -0
- package/lib/parsers/custom-object-parser.js.map +1 -0
- package/lib/parsers/email-template-parser.d.ts +64 -0
- package/lib/parsers/email-template-parser.js +238 -0
- package/lib/parsers/email-template-parser.js.map +1 -0
- package/lib/parsers/error-resilient-parser.d.ts +110 -0
- package/lib/parsers/error-resilient-parser.js +277 -0
- package/lib/parsers/error-resilient-parser.js.map +1 -0
- package/lib/parsers/flexipage-parser.d.ts +64 -0
- package/lib/parsers/flexipage-parser.js +196 -0
- package/lib/parsers/flexipage-parser.js.map +1 -0
- package/lib/parsers/flow-parser.d.ts +54 -0
- package/lib/parsers/flow-parser.js +287 -0
- package/lib/parsers/flow-parser.js.map +1 -0
- package/lib/parsers/genai-prompt-parser.d.ts +67 -0
- package/lib/parsers/genai-prompt-parser.js +160 -0
- package/lib/parsers/genai-prompt-parser.js.map +1 -0
- package/lib/parsers/layout-parser.d.ts +64 -0
- package/lib/parsers/layout-parser.js +267 -0
- package/lib/parsers/layout-parser.js.map +1 -0
- package/lib/parsers/lwc-parser.d.ts +60 -0
- package/lib/parsers/lwc-parser.js +264 -0
- package/lib/parsers/lwc-parser.js.map +1 -0
- package/lib/parsers/permission-set-parser.d.ts +86 -0
- package/lib/parsers/permission-set-parser.js +152 -0
- package/lib/parsers/permission-set-parser.js.map +1 -0
- package/lib/parsers/profile-parser.d.ts +81 -0
- package/lib/parsers/profile-parser.js +141 -0
- package/lib/parsers/profile-parser.js.map +1 -0
- package/lib/parsers/visualforce-parser.d.ts +47 -0
- package/lib/parsers/visualforce-parser.js +180 -0
- package/lib/parsers/visualforce-parser.js.map +1 -0
- package/lib/provisioning/data-provisioner.d.ts +88 -0
- package/lib/provisioning/data-provisioner.js +257 -0
- package/lib/provisioning/data-provisioner.js.map +1 -0
- package/lib/scanner/custom-structure-scanner.d.ts +66 -0
- package/lib/scanner/custom-structure-scanner.js +229 -0
- package/lib/scanner/custom-structure-scanner.js.map +1 -0
- package/lib/scanner/forceignore-parser.d.ts +69 -0
- package/lib/scanner/forceignore-parser.js +195 -0
- package/lib/scanner/forceignore-parser.js.map +1 -0
- package/lib/scanner/metadata-format-scanner.d.ts +77 -0
- package/lib/scanner/metadata-format-scanner.js +282 -0
- package/lib/scanner/metadata-format-scanner.js.map +1 -0
- package/lib/scanner/monorepo-scanner.d.ts +71 -0
- package/lib/scanner/monorepo-scanner.js +225 -0
- package/lib/scanner/monorepo-scanner.js.map +1 -0
- package/lib/scanner/project-validator.d.ts +55 -0
- package/lib/scanner/project-validator.js +235 -0
- package/lib/scanner/project-validator.js.map +1 -0
- package/lib/scanner/sfdx-project-detector.d.ts +86 -0
- package/lib/scanner/sfdx-project-detector.js +240 -0
- package/lib/scanner/sfdx-project-detector.js.map +1 -0
- package/lib/scanner/structure-validator.d.ts +64 -0
- package/lib/scanner/structure-validator.js +296 -0
- package/lib/scanner/structure-validator.js.map +1 -0
- package/lib/services/metadata-scanner-service.d.ts +64 -0
- package/lib/services/metadata-scanner-service.js +651 -0
- package/lib/services/metadata-scanner-service.js.map +1 -0
- package/lib/types/agentforce.d.ts +157 -0
- package/lib/types/agentforce.js +2 -0
- package/lib/types/agentforce.js.map +1 -0
- package/lib/types/dependency.d.ts +98 -0
- package/lib/types/dependency.js +5 -0
- package/lib/types/dependency.js.map +1 -0
- package/lib/types/deployment-plan.d.ts +81 -0
- package/lib/types/deployment-plan.js +6 -0
- package/lib/types/deployment-plan.js.map +1 -0
- package/lib/types/deployment.d.ts +88 -0
- package/lib/types/deployment.js +5 -0
- package/lib/types/deployment.js.map +1 -0
- package/lib/types/graph.d.ts +35 -0
- package/lib/types/graph.js +5 -0
- package/lib/types/graph.js.map +1 -0
- package/lib/types/index.d.ts +12 -0
- package/lib/types/index.js +17 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/metadata.d.ts +101 -0
- package/lib/types/metadata.js +13 -0
- package/lib/types/metadata.js.map +1 -0
- package/lib/types/project.d.ts +156 -0
- package/lib/types/project.js +56 -0
- package/lib/types/project.js.map +1 -0
- package/lib/types/salesforce/apex.d.ts +94 -0
- package/lib/types/salesforce/apex.js +6 -0
- package/lib/types/salesforce/apex.js.map +1 -0
- package/lib/types/salesforce/aura.d.ts +150 -0
- package/lib/types/salesforce/aura.js +6 -0
- package/lib/types/salesforce/aura.js.map +1 -0
- package/lib/types/salesforce/bot.d.ts +293 -0
- package/lib/types/salesforce/bot.js +6 -0
- package/lib/types/salesforce/bot.js.map +1 -0
- package/lib/types/salesforce/common.d.ts +15 -0
- package/lib/types/salesforce/common.js +5 -0
- package/lib/types/salesforce/common.js.map +1 -0
- package/lib/types/salesforce/custom-metadata.d.ts +92 -0
- package/lib/types/salesforce/custom-metadata.js +6 -0
- package/lib/types/salesforce/custom-metadata.js.map +1 -0
- package/lib/types/salesforce/email.d.ts +56 -0
- package/lib/types/salesforce/email.js +6 -0
- package/lib/types/salesforce/email.js.map +1 -0
- package/lib/types/salesforce/flexipage.d.ts +149 -0
- package/lib/types/salesforce/flexipage.js +6 -0
- package/lib/types/salesforce/flexipage.js.map +1 -0
- package/lib/types/salesforce/flow.d.ts +516 -0
- package/lib/types/salesforce/flow.js +6 -0
- package/lib/types/salesforce/flow.js.map +1 -0
- package/lib/types/salesforce/genai.d.ts +67 -0
- package/lib/types/salesforce/genai.js +6 -0
- package/lib/types/salesforce/genai.js.map +1 -0
- package/lib/types/salesforce/index.d.ts +27 -0
- package/lib/types/salesforce/index.js +43 -0
- package/lib/types/salesforce/index.js.map +1 -0
- package/lib/types/salesforce/layout.d.ts +236 -0
- package/lib/types/salesforce/layout.js +6 -0
- package/lib/types/salesforce/layout.js.map +1 -0
- package/lib/types/salesforce/lwc.d.ts +123 -0
- package/lib/types/salesforce/lwc.js +6 -0
- package/lib/types/salesforce/lwc.js.map +1 -0
- package/lib/types/salesforce/object.d.ts +427 -0
- package/lib/types/salesforce/object.js +6 -0
- package/lib/types/salesforce/object.js.map +1 -0
- package/lib/types/salesforce/parser-types.d.ts +79 -0
- package/lib/types/salesforce/parser-types.js +80 -0
- package/lib/types/salesforce/parser-types.js.map +1 -0
- package/lib/types/salesforce/permission.d.ts +289 -0
- package/lib/types/salesforce/permission.js +6 -0
- package/lib/types/salesforce/permission.js.map +1 -0
- package/lib/types/salesforce/resource.d.ts +93 -0
- package/lib/types/salesforce/resource.js +6 -0
- package/lib/types/salesforce/resource.js.map +1 -0
- package/lib/types/salesforce/visualforce.d.ts +70 -0
- package/lib/types/salesforce/visualforce.js +6 -0
- package/lib/types/salesforce/visualforce.js.map +1 -0
- package/lib/utils/cache-manager.d.ts +158 -0
- package/lib/utils/cache-manager.js +429 -0
- package/lib/utils/cache-manager.js.map +1 -0
- package/lib/utils/deployment-plan-manager.d.ts +40 -0
- package/lib/utils/deployment-plan-manager.js +183 -0
- package/lib/utils/deployment-plan-manager.js.map +1 -0
- package/lib/utils/error-aggregator.d.ts +117 -0
- package/lib/utils/error-aggregator.js +268 -0
- package/lib/utils/error-aggregator.js.map +1 -0
- package/lib/utils/file-system.d.ts +62 -0
- package/lib/utils/file-system.js +167 -0
- package/lib/utils/file-system.js.map +1 -0
- package/lib/utils/functional.d.ts +52 -0
- package/lib/utils/functional.js +61 -0
- package/lib/utils/functional.js.map +1 -0
- package/lib/utils/graph-algorithms.d.ts +53 -0
- package/lib/utils/graph-algorithms.js +177 -0
- package/lib/utils/graph-algorithms.js.map +1 -0
- package/lib/utils/logger.d.ts +154 -0
- package/lib/utils/logger.js +327 -0
- package/lib/utils/logger.js.map +1 -0
- package/lib/utils/network-handler.d.ts +64 -0
- package/lib/utils/network-handler.js +147 -0
- package/lib/utils/network-handler.js.map +1 -0
- package/lib/utils/performance.d.ts +148 -0
- package/lib/utils/performance.js +294 -0
- package/lib/utils/performance.js.map +1 -0
- package/lib/utils/string.d.ts +197 -0
- package/lib/utils/string.js +331 -0
- package/lib/utils/string.js.map +1 -0
- package/lib/utils/xml.d.ts +97 -0
- package/lib/utils/xml.js +227 -0
- package/lib/utils/xml.js.map +1 -0
- package/lib/validators/xml-metadata-validator.d.ts +106 -0
- package/lib/validators/xml-metadata-validator.js +509 -0
- package/lib/validators/xml-metadata-validator.js.map +1 -0
- package/lib/waves/priority-wave-generator-ai.d.ts +85 -0
- package/lib/waves/priority-wave-generator-ai.js +191 -0
- package/lib/waves/priority-wave-generator-ai.js.map +1 -0
- package/lib/waves/priority-wave-generator.d.ts +47 -0
- package/lib/waves/priority-wave-generator.js +88 -0
- package/lib/waves/priority-wave-generator.js.map +1 -0
- package/lib/waves/test-optimizer.d.ts +155 -0
- package/lib/waves/test-optimizer.js +290 -0
- package/lib/waves/test-optimizer.js.map +1 -0
- package/lib/waves/wave-builder.d.ts +147 -0
- package/lib/waves/wave-builder.js +286 -0
- package/lib/waves/wave-builder.js.map +1 -0
- package/lib/waves/wave-diff-generator.d.ts +17 -0
- package/lib/waves/wave-diff-generator.js +6 -0
- package/lib/waves/wave-diff-generator.js.map +1 -0
- package/lib/waves/wave-executor.d.ts +33 -0
- package/lib/waves/wave-executor.js +50 -0
- package/lib/waves/wave-executor.js.map +1 -0
- package/lib/waves/wave-merger.d.ts +96 -0
- package/lib/waves/wave-merger.js +181 -0
- package/lib/waves/wave-merger.js.map +1 -0
- package/lib/waves/wave-metadata-generator.d.ts +13 -0
- package/lib/waves/wave-metadata-generator.js +12 -0
- package/lib/waves/wave-metadata-generator.js.map +1 -0
- package/lib/waves/wave-splitter.d.ts +154 -0
- package/lib/waves/wave-splitter.js +307 -0
- package/lib/waves/wave-splitter.js.map +1 -0
- package/lib/waves/wave-validator.d.ts +17 -0
- package/lib/waves/wave-validator.js +15 -0
- package/lib/waves/wave-validator.js.map +1 -0
- package/messages/analyze.json +18 -0
- package/messages/config.json +29 -0
- package/messages/resume.json +9 -0
- package/messages/start.json +24 -0
- package/messages/status.json +8 -0
- package/messages/validate.json +9 -0
- package/npm-shrinkwrap.json +25676 -0
- package/oclif.lock +11988 -0
- package/oclif.manifest.json +589 -0
- package/package.json +224 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circular Dependency Detector
|
|
3
|
+
* Detects and reports circular dependencies in the dependency graph
|
|
4
|
+
*
|
|
5
|
+
* @ac US-030-AC-1: Detect simple cycles (A→B→A)
|
|
6
|
+
* @ac US-030-AC-2: Detect complex cycles (A→B→C→A)
|
|
7
|
+
* @ac US-030-AC-3: Report all nodes in cycle
|
|
8
|
+
* @ac US-030-AC-4: Suggest where to break cycle
|
|
9
|
+
* @ac US-030-AC-5: Support user-defined cycle breaks
|
|
10
|
+
* @ac US-030-AC-6: Handle multiple separate cycles
|
|
11
|
+
*
|
|
12
|
+
* @issue #30
|
|
13
|
+
*/
|
|
14
|
+
import { getLogger } from '../utils/logger.js';
|
|
15
|
+
const logger = getLogger('CircularDependencyDetector');
|
|
16
|
+
/**
|
|
17
|
+
* Circular Dependency Detector
|
|
18
|
+
*
|
|
19
|
+
* Uses depth-first search (DFS) to detect cycles in the dependency graph.
|
|
20
|
+
* Supports both simple (A→B→A) and complex (A→B→C→A) cycles.
|
|
21
|
+
*
|
|
22
|
+
* Performance: O(V + E) where V = vertices, E = edges
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const detector = new CircularDependencyDetector(graph);
|
|
26
|
+
* const cycles = detector.detectCycles();
|
|
27
|
+
* if (cycles.length > 0) {
|
|
28
|
+
* console.log(`Found ${cycles.length} circular dependencies`);
|
|
29
|
+
* console.log('Suggestion:', cycles[0].breakSuggestions[0]);
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
export class CircularDependencyDetector {
|
|
33
|
+
graph;
|
|
34
|
+
options;
|
|
35
|
+
ignoredEdges;
|
|
36
|
+
constructor(graph, options = {}) {
|
|
37
|
+
this.graph = graph;
|
|
38
|
+
this.options = {
|
|
39
|
+
maxDepth: options.maxDepth ?? 100,
|
|
40
|
+
ignoreEdges: options.ignoreEdges ?? [],
|
|
41
|
+
generateSuggestions: options.generateSuggestions ?? true,
|
|
42
|
+
};
|
|
43
|
+
// Create set of ignored edges for O(1) lookup
|
|
44
|
+
this.ignoredEdges = new Set(this.options.ignoreEdges.map(({ from, to }) => `${from}->${to}`));
|
|
45
|
+
logger.debug('Initialized CircularDependencyDetector', {
|
|
46
|
+
nodes: this.graph.size,
|
|
47
|
+
ignoredEdges: this.ignoredEdges.size,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Private static helper methods
|
|
51
|
+
/**
|
|
52
|
+
* Calculate priority for breaking an edge
|
|
53
|
+
* Higher = better candidate to break
|
|
54
|
+
*/
|
|
55
|
+
static calculateBreakPriority(from, to) {
|
|
56
|
+
let priority = 50; // Base priority
|
|
57
|
+
// Test classes are good candidates to break (they can be deployed separately)
|
|
58
|
+
if (from.includes('Test') || to.includes('Test')) {
|
|
59
|
+
priority += 30;
|
|
60
|
+
}
|
|
61
|
+
// Utility/helper classes are good candidates
|
|
62
|
+
if (CircularDependencyDetector.isUtilityClass(from) || CircularDependencyDetector.isUtilityClass(to)) {
|
|
63
|
+
priority += 20;
|
|
64
|
+
}
|
|
65
|
+
// Handler -> Service edges are typically safe to break
|
|
66
|
+
if (from.includes('Handler') && to.includes('Service')) {
|
|
67
|
+
priority += 15;
|
|
68
|
+
}
|
|
69
|
+
// Controller -> Service edges can be broken
|
|
70
|
+
if (from.includes('Controller') && to.includes('Service')) {
|
|
71
|
+
priority += 15;
|
|
72
|
+
}
|
|
73
|
+
// Trigger -> Handler edges should not be broken (tightly coupled)
|
|
74
|
+
if (from.includes('Trigger') && to.includes('Handler')) {
|
|
75
|
+
priority -= 20;
|
|
76
|
+
}
|
|
77
|
+
// Core domain classes should not be broken if possible
|
|
78
|
+
if (CircularDependencyDetector.isCoreDomainClass(from) && CircularDependencyDetector.isCoreDomainClass(to)) {
|
|
79
|
+
priority -= 15;
|
|
80
|
+
}
|
|
81
|
+
return Math.max(0, Math.min(100, priority));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get human-readable reason for break suggestion
|
|
85
|
+
*/
|
|
86
|
+
static getBreakReason(from, to, priority) {
|
|
87
|
+
if (priority >= 80) {
|
|
88
|
+
return `High priority: ${from} → ${to} is a test or utility dependency`;
|
|
89
|
+
}
|
|
90
|
+
else if (priority >= 65) {
|
|
91
|
+
return `Medium priority: ${from} → ${to} can be broken safely`;
|
|
92
|
+
}
|
|
93
|
+
else if (priority >= 50) {
|
|
94
|
+
return `Low priority: ${from} → ${to} may be tightly coupled`;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return `Not recommended: ${from} → ${to} appears to be core business logic`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if a class is a utility/helper class
|
|
102
|
+
*/
|
|
103
|
+
static isUtilityClass(nodeId) {
|
|
104
|
+
const name = nodeId.toLowerCase();
|
|
105
|
+
return name.includes('util') || name.includes('helper') || name.includes('constant') || name.includes('logger');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if a class is core domain logic
|
|
109
|
+
*/
|
|
110
|
+
static isCoreDomainClass(nodeId) {
|
|
111
|
+
const name = nodeId.toLowerCase();
|
|
112
|
+
// Core classes typically don't have suffixes like Test, Handler, etc.
|
|
113
|
+
return (!name.includes('test') &&
|
|
114
|
+
!name.includes('handler') &&
|
|
115
|
+
!name.includes('controller') &&
|
|
116
|
+
!name.includes('util') &&
|
|
117
|
+
!name.includes('helper'));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generate a unique ID for a cycle (order-independent)
|
|
121
|
+
*/
|
|
122
|
+
static generateCycleId(cycle) {
|
|
123
|
+
// Sort to make it order-independent: [A,B,C] and [B,C,A] are the same cycle
|
|
124
|
+
const sorted = [...cycle].sort();
|
|
125
|
+
return sorted.join('->');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Check if a cycle is a duplicate of already found cycles
|
|
129
|
+
*/
|
|
130
|
+
static isDuplicateCycle(cycle, existingCycles) {
|
|
131
|
+
const cycleId = CircularDependencyDetector.generateCycleId(cycle);
|
|
132
|
+
return existingCycles.some((c) => c.id === cycleId);
|
|
133
|
+
}
|
|
134
|
+
// Public methods
|
|
135
|
+
/**
|
|
136
|
+
* Detect all circular dependencies in the graph
|
|
137
|
+
*
|
|
138
|
+
* @ac US-030-AC-1: Detect simple cycles (A→B→A)
|
|
139
|
+
* @ac US-030-AC-2: Detect complex cycles (A→B→C→A)
|
|
140
|
+
* @ac US-030-AC-6: Handle multiple separate cycles
|
|
141
|
+
*/
|
|
142
|
+
detectCycles() {
|
|
143
|
+
const startTime = Date.now();
|
|
144
|
+
const allCycles = [];
|
|
145
|
+
const visited = new Set();
|
|
146
|
+
const recursionStack = new Set();
|
|
147
|
+
const currentPath = [];
|
|
148
|
+
const dfs = (nodeId, depth) => {
|
|
149
|
+
// Depth limit check
|
|
150
|
+
if (depth > this.options.maxDepth) {
|
|
151
|
+
logger.warn('Max depth reached during cycle detection', { nodeId, depth });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
visited.add(nodeId);
|
|
155
|
+
recursionStack.add(nodeId);
|
|
156
|
+
currentPath.push(nodeId);
|
|
157
|
+
const dependencies = this.graph.get(nodeId) ?? new Set();
|
|
158
|
+
for (const depId of dependencies) {
|
|
159
|
+
// Skip ignored edges
|
|
160
|
+
if (this.isEdgeIgnored(nodeId, depId)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (!visited.has(depId)) {
|
|
164
|
+
// Continue DFS
|
|
165
|
+
dfs(depId, depth + 1);
|
|
166
|
+
}
|
|
167
|
+
else if (recursionStack.has(depId)) {
|
|
168
|
+
// Found a cycle!
|
|
169
|
+
const cycleStartIndex = currentPath.indexOf(depId);
|
|
170
|
+
const cycle = currentPath.slice(cycleStartIndex);
|
|
171
|
+
// Check if we've already found this cycle
|
|
172
|
+
if (!CircularDependencyDetector.isDuplicateCycle(cycle, allCycles)) {
|
|
173
|
+
allCycles.push(this.createDetectedCycle(cycle, depId));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
recursionStack.delete(nodeId);
|
|
178
|
+
currentPath.pop();
|
|
179
|
+
};
|
|
180
|
+
// Run DFS from each node
|
|
181
|
+
for (const nodeId of this.graph.keys()) {
|
|
182
|
+
if (!visited.has(nodeId)) {
|
|
183
|
+
dfs(nodeId, 0);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const duration = Date.now() - startTime;
|
|
187
|
+
logger.info('Cycle detection completed', {
|
|
188
|
+
cyclesFound: allCycles.length,
|
|
189
|
+
nodesScanned: visited.size,
|
|
190
|
+
durationMs: duration,
|
|
191
|
+
});
|
|
192
|
+
return allCycles;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Detect cycles starting from a specific node
|
|
196
|
+
*/
|
|
197
|
+
detectCyclesFromNode(startNode) {
|
|
198
|
+
const cycles = [];
|
|
199
|
+
const recursionStack = new Set();
|
|
200
|
+
const currentPath = [];
|
|
201
|
+
const dfs = (nodeId, depth) => {
|
|
202
|
+
if (depth > this.options.maxDepth) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
recursionStack.add(nodeId);
|
|
206
|
+
currentPath.push(nodeId);
|
|
207
|
+
const dependencies = this.graph.get(nodeId) ?? new Set();
|
|
208
|
+
for (const depId of dependencies) {
|
|
209
|
+
if (this.isEdgeIgnored(nodeId, depId)) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (recursionStack.has(depId)) {
|
|
213
|
+
const cycleStartIndex = currentPath.indexOf(depId);
|
|
214
|
+
const cycle = currentPath.slice(cycleStartIndex);
|
|
215
|
+
if (!CircularDependencyDetector.isDuplicateCycle(cycle, cycles)) {
|
|
216
|
+
cycles.push(this.createDetectedCycle(cycle, depId));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
dfs(depId, depth + 1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
recursionStack.delete(nodeId);
|
|
224
|
+
currentPath.pop();
|
|
225
|
+
};
|
|
226
|
+
dfs(startNode, 0);
|
|
227
|
+
return cycles;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if a specific path creates a cycle
|
|
231
|
+
*/
|
|
232
|
+
wouldCreateCycle(from, to) {
|
|
233
|
+
// Check if adding edge from->to would create a cycle
|
|
234
|
+
// This means: can we reach 'from' starting from 'to'?
|
|
235
|
+
const visited = new Set();
|
|
236
|
+
const queue = [to];
|
|
237
|
+
while (queue.length > 0) {
|
|
238
|
+
const current = queue.shift();
|
|
239
|
+
if (current === from) {
|
|
240
|
+
return true; // Found a path back to 'from'
|
|
241
|
+
}
|
|
242
|
+
if (visited.has(current)) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
visited.add(current);
|
|
246
|
+
const deps = this.graph.get(current) ?? new Set();
|
|
247
|
+
for (const dep of deps) {
|
|
248
|
+
if (!this.isEdgeIgnored(current, dep) && !visited.has(dep)) {
|
|
249
|
+
queue.push(dep);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* @ac US-030-AC-3: Report all nodes in cycle
|
|
257
|
+
*
|
|
258
|
+
* Create a detected cycle with full information
|
|
259
|
+
*/
|
|
260
|
+
createDetectedCycle(cycle, closingNode) {
|
|
261
|
+
const cycleId = CircularDependencyDetector.generateCycleId(cycle);
|
|
262
|
+
const message = `Circular dependency: ${cycle.join(' → ')} → ${closingNode}`;
|
|
263
|
+
const detected = {
|
|
264
|
+
id: cycleId,
|
|
265
|
+
cycle: [...cycle],
|
|
266
|
+
severity: cycle.length <= 2 ? 'error' : 'warning',
|
|
267
|
+
message,
|
|
268
|
+
breakSuggestions: [],
|
|
269
|
+
};
|
|
270
|
+
// Generate break suggestions if enabled
|
|
271
|
+
if (this.options.generateSuggestions) {
|
|
272
|
+
detected.breakSuggestions = CircularDependencyDetector.generateBreakSuggestions(cycle, closingNode);
|
|
273
|
+
}
|
|
274
|
+
return detected;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* @ac US-030-AC-4: Suggest where to break cycle
|
|
278
|
+
*
|
|
279
|
+
* Generate suggestions for breaking the cycle
|
|
280
|
+
* Priority based on:
|
|
281
|
+
* - Test classes (high priority to break)
|
|
282
|
+
* - Utility classes (medium priority)
|
|
283
|
+
* - Core business logic (low priority)
|
|
284
|
+
*/
|
|
285
|
+
static generateBreakSuggestions(cycle, closingNode) {
|
|
286
|
+
const suggestions = [];
|
|
287
|
+
// Add closing edge
|
|
288
|
+
const fullCycle = [...cycle, closingNode];
|
|
289
|
+
// Analyze each edge in the cycle
|
|
290
|
+
for (let i = 0; i < fullCycle.length - 1; i++) {
|
|
291
|
+
const from = fullCycle[i];
|
|
292
|
+
const to = fullCycle[i + 1];
|
|
293
|
+
const priority = CircularDependencyDetector.calculateBreakPriority(from, to);
|
|
294
|
+
const reason = CircularDependencyDetector.getBreakReason(from, to, priority);
|
|
295
|
+
suggestions.push({
|
|
296
|
+
from,
|
|
297
|
+
to,
|
|
298
|
+
reason,
|
|
299
|
+
priority,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// Sort by priority (highest first)
|
|
303
|
+
suggestions.sort((a, b) => b.priority - a.priority);
|
|
304
|
+
return suggestions;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* @ac US-030-AC-5: Support user-defined cycle breaks
|
|
308
|
+
*
|
|
309
|
+
* Check if an edge is in the ignore list
|
|
310
|
+
*/
|
|
311
|
+
isEdgeIgnored(from, to) {
|
|
312
|
+
return this.ignoredEdges.has(`${from}->${to}`);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Get summary statistics
|
|
316
|
+
*/
|
|
317
|
+
getStats() {
|
|
318
|
+
let totalEdges = 0;
|
|
319
|
+
for (const deps of this.graph.values()) {
|
|
320
|
+
totalEdges += deps.size;
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
totalNodes: this.graph.size,
|
|
324
|
+
totalEdges,
|
|
325
|
+
ignoredEdges: this.ignoredEdges.size,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=circular-dependency-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circular-dependency-detector.js","sourceRoot":"","sources":["../../src/dependencies/circular-dependency-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cycle Remediation Planner
|
|
3
|
+
*
|
|
4
|
+
* First-slice planner that identifies strongly connected components, detects
|
|
5
|
+
* self-loops, and classifies cycles for safe remediation planning.
|
|
6
|
+
*/
|
|
7
|
+
import type { DependencyGraph, NodeId } from '../types/dependency.js';
|
|
8
|
+
import type { MetadataComponent } from '../types/metadata.js';
|
|
9
|
+
export type CycleRemediationStrategy = 'comment-reference' | 'manual';
|
|
10
|
+
export type CycleRemediationSourceEdit = {
|
|
11
|
+
nodeId: NodeId;
|
|
12
|
+
targetDependency: NodeId;
|
|
13
|
+
operation: 'comment-reference';
|
|
14
|
+
filePath?: string;
|
|
15
|
+
targetDescription: string;
|
|
16
|
+
};
|
|
17
|
+
export type CycleRemediationDeployPhase = {
|
|
18
|
+
phase: 1 | 2;
|
|
19
|
+
description: string;
|
|
20
|
+
components: NodeId[];
|
|
21
|
+
restoreEdits?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type RemediationCycle = {
|
|
24
|
+
id: string;
|
|
25
|
+
nodes: NodeId[];
|
|
26
|
+
strategy: CycleRemediationStrategy;
|
|
27
|
+
warnings: string[];
|
|
28
|
+
edits: CycleRemediationSourceEdit[];
|
|
29
|
+
deployPhases: CycleRemediationDeployPhase[];
|
|
30
|
+
};
|
|
31
|
+
export type CycleRemediationPlan = {
|
|
32
|
+
cycles: RemediationCycle[];
|
|
33
|
+
supported: boolean;
|
|
34
|
+
warnings: string[];
|
|
35
|
+
};
|
|
36
|
+
export type CycleRemediationPlannerOptions = {
|
|
37
|
+
components?: ReadonlyMap<NodeId, MetadataComponent>;
|
|
38
|
+
};
|
|
39
|
+
export declare class CycleRemediationPlanner {
|
|
40
|
+
private readonly graph;
|
|
41
|
+
private readonly components?;
|
|
42
|
+
constructor(graph: DependencyGraph, options?: CycleRemediationPlannerOptions);
|
|
43
|
+
createPlan(): CycleRemediationPlan;
|
|
44
|
+
private findCycles;
|
|
45
|
+
private planCycle;
|
|
46
|
+
private getInternalEdges;
|
|
47
|
+
private isSimpleCycle;
|
|
48
|
+
private createCommentReferenceEdit;
|
|
49
|
+
private createDeployPhases;
|
|
50
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cycle Remediation Planner
|
|
3
|
+
*
|
|
4
|
+
* First-slice planner that identifies strongly connected components, detects
|
|
5
|
+
* self-loops, and classifies cycles for safe remediation planning.
|
|
6
|
+
*/
|
|
7
|
+
const SUPPORTED_AUTOMATIC_TYPES = new Set(['ApexClass']);
|
|
8
|
+
function compareNodeIds(left, right) {
|
|
9
|
+
return left.localeCompare(right);
|
|
10
|
+
}
|
|
11
|
+
function parseTypeFromNodeId(nodeId) {
|
|
12
|
+
const separatorIndex = nodeId.indexOf(':');
|
|
13
|
+
return separatorIndex === -1 ? 'Unknown' : nodeId.slice(0, separatorIndex);
|
|
14
|
+
}
|
|
15
|
+
function collectGraphNodeIds(graph) {
|
|
16
|
+
const nodeIds = new Set();
|
|
17
|
+
for (const [nodeId, dependencies] of graph) {
|
|
18
|
+
nodeIds.add(nodeId);
|
|
19
|
+
for (const dependencyId of dependencies) {
|
|
20
|
+
nodeIds.add(dependencyId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return [...nodeIds].sort(compareNodeIds);
|
|
24
|
+
}
|
|
25
|
+
function getSortedDependencies(graph, nodeId) {
|
|
26
|
+
return [...(graph.get(nodeId) ?? new Set())].sort(compareNodeIds);
|
|
27
|
+
}
|
|
28
|
+
function getNodeType(nodeId, components) {
|
|
29
|
+
return components?.get(nodeId)?.type ?? parseTypeFromNodeId(nodeId);
|
|
30
|
+
}
|
|
31
|
+
function createCycleId(nodes) {
|
|
32
|
+
return nodes.join('|');
|
|
33
|
+
}
|
|
34
|
+
export class CycleRemediationPlanner {
|
|
35
|
+
graph;
|
|
36
|
+
components;
|
|
37
|
+
constructor(graph, options = {}) {
|
|
38
|
+
this.graph = graph;
|
|
39
|
+
this.components = options.components;
|
|
40
|
+
}
|
|
41
|
+
createPlan() {
|
|
42
|
+
const cycles = this.findCycles().map((cycleNodes) => this.planCycle(cycleNodes));
|
|
43
|
+
const warnings = [...new Set(cycles.flatMap((cycle) => cycle.warnings))].sort();
|
|
44
|
+
return {
|
|
45
|
+
cycles,
|
|
46
|
+
supported: cycles.every((cycle) => cycle.strategy === 'comment-reference'),
|
|
47
|
+
warnings,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
findCycles() {
|
|
51
|
+
const nodeIds = collectGraphNodeIds(this.graph);
|
|
52
|
+
const indexMap = new Map();
|
|
53
|
+
const lowLinkMap = new Map();
|
|
54
|
+
const activeStack = new Set();
|
|
55
|
+
const stack = [];
|
|
56
|
+
const stronglyConnectedComponents = [];
|
|
57
|
+
let currentIndex = 0;
|
|
58
|
+
const visit = (nodeId) => {
|
|
59
|
+
indexMap.set(nodeId, currentIndex);
|
|
60
|
+
lowLinkMap.set(nodeId, currentIndex);
|
|
61
|
+
currentIndex += 1;
|
|
62
|
+
stack.push(nodeId);
|
|
63
|
+
activeStack.add(nodeId);
|
|
64
|
+
for (const dependencyId of getSortedDependencies(this.graph, nodeId)) {
|
|
65
|
+
if (!indexMap.has(dependencyId)) {
|
|
66
|
+
visit(dependencyId);
|
|
67
|
+
lowLinkMap.set(nodeId, Math.min(lowLinkMap.get(nodeId), lowLinkMap.get(dependencyId)));
|
|
68
|
+
}
|
|
69
|
+
else if (activeStack.has(dependencyId)) {
|
|
70
|
+
lowLinkMap.set(nodeId, Math.min(lowLinkMap.get(nodeId), indexMap.get(dependencyId)));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (lowLinkMap.get(nodeId) !== indexMap.get(nodeId)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const component = [];
|
|
77
|
+
while (stack.length > 0) {
|
|
78
|
+
const stackNodeId = stack.pop();
|
|
79
|
+
activeStack.delete(stackNodeId);
|
|
80
|
+
component.push(stackNodeId);
|
|
81
|
+
if (stackNodeId === nodeId) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
stronglyConnectedComponents.push(component.sort(compareNodeIds));
|
|
86
|
+
};
|
|
87
|
+
for (const nodeId of nodeIds) {
|
|
88
|
+
if (!indexMap.has(nodeId)) {
|
|
89
|
+
visit(nodeId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return stronglyConnectedComponents
|
|
93
|
+
.filter((component) => {
|
|
94
|
+
if (component.length > 1) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
const [nodeId] = component;
|
|
98
|
+
return (this.graph.get(nodeId) ?? new Set()).has(nodeId);
|
|
99
|
+
})
|
|
100
|
+
.sort((left, right) => createCycleId(left).localeCompare(createCycleId(right)));
|
|
101
|
+
}
|
|
102
|
+
planCycle(nodes) {
|
|
103
|
+
const nodeSet = new Set(nodes);
|
|
104
|
+
const internalEdges = this.getInternalEdges(nodes, nodeSet);
|
|
105
|
+
const nodeTypes = [...new Set(nodes.map((nodeId) => getNodeType(nodeId, this.components)))].sort();
|
|
106
|
+
const warnings = [];
|
|
107
|
+
let strategy = 'manual';
|
|
108
|
+
let edits = [];
|
|
109
|
+
if (!nodeTypes.every((type) => SUPPORTED_AUTOMATIC_TYPES.has(type))) {
|
|
110
|
+
warnings.push(`Automatic remediation currently supports ApexClass-only cycles; found ${nodeTypes.join(', ')} in ${createCycleId(nodes)}.`);
|
|
111
|
+
}
|
|
112
|
+
else if (!this.isSimpleCycle(nodes, internalEdges)) {
|
|
113
|
+
warnings.push(`Cycle ${createCycleId(nodes)} requires manual remediation because it is not a simple directed cycle.`);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
strategy = 'comment-reference';
|
|
117
|
+
edits = [this.createCommentReferenceEdit(internalEdges[0])];
|
|
118
|
+
for (const nodeId of nodes) {
|
|
119
|
+
if (!this.components?.get(nodeId)?.filePath) {
|
|
120
|
+
warnings.push(`Missing component file path for ${nodeId}; execution must resolve the source file before applying edits.`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
id: createCycleId(nodes),
|
|
126
|
+
nodes,
|
|
127
|
+
strategy,
|
|
128
|
+
warnings: warnings.sort(),
|
|
129
|
+
edits,
|
|
130
|
+
deployPhases: this.createDeployPhases(nodes, strategy),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
getInternalEdges(nodes, nodeSet) {
|
|
134
|
+
return nodes
|
|
135
|
+
.flatMap((nodeId) => getSortedDependencies(this.graph, nodeId)
|
|
136
|
+
.filter((dependencyId) => nodeSet.has(dependencyId))
|
|
137
|
+
.map((dependencyId) => ({ from: nodeId, to: dependencyId })))
|
|
138
|
+
.sort((left, right) => {
|
|
139
|
+
const fromComparison = compareNodeIds(left.from, right.from);
|
|
140
|
+
return fromComparison !== 0 ? fromComparison : compareNodeIds(left.to, right.to);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
isSimpleCycle(nodes, internalEdges) {
|
|
144
|
+
if (nodes.length === 1) {
|
|
145
|
+
return internalEdges.length === 1 && internalEdges[0].from === internalEdges[0].to;
|
|
146
|
+
}
|
|
147
|
+
if (internalEdges.length !== nodes.length) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const outgoingCounts = new Map();
|
|
151
|
+
const incomingCounts = new Map();
|
|
152
|
+
for (const { from, to } of internalEdges) {
|
|
153
|
+
outgoingCounts.set(from, (outgoingCounts.get(from) ?? 0) + 1);
|
|
154
|
+
incomingCounts.set(to, (incomingCounts.get(to) ?? 0) + 1);
|
|
155
|
+
}
|
|
156
|
+
return nodes.every((nodeId) => outgoingCounts.get(nodeId) === 1 && incomingCounts.get(nodeId) === 1);
|
|
157
|
+
}
|
|
158
|
+
createCommentReferenceEdit(edge) {
|
|
159
|
+
return {
|
|
160
|
+
nodeId: edge.from,
|
|
161
|
+
targetDependency: edge.to,
|
|
162
|
+
operation: 'comment-reference',
|
|
163
|
+
filePath: this.components?.get(edge.from)?.filePath,
|
|
164
|
+
targetDescription: `Temporarily comment the ${edge.from} reference to ${edge.to} during phase 1.`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
createDeployPhases(nodes, strategy) {
|
|
168
|
+
if (strategy === 'comment-reference') {
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
phase: 1,
|
|
172
|
+
description: 'Deploy temporarily cycle-broken metadata.',
|
|
173
|
+
components: nodes,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
phase: 2,
|
|
177
|
+
description: 'Restore original references and redeploy the same components.',
|
|
178
|
+
components: nodes,
|
|
179
|
+
restoreEdits: true,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
return [
|
|
184
|
+
{
|
|
185
|
+
phase: 1,
|
|
186
|
+
description: 'Manual remediation required before deployment can continue.',
|
|
187
|
+
components: nodes,
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=cycle-remediation-planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cycle-remediation-planner.js","sourceRoot":"","sources":["../../src/dependencies/cycle-remediation-planner.ts"],"names":[],"mappings":"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"}
|