@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,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Validator
|
|
3
|
+
* Validates the dependency graph for correctness and consistency
|
|
4
|
+
*
|
|
5
|
+
* @ac US-034-AC-1: Validate no dangling references
|
|
6
|
+
* @ac US-034-AC-2: Validate all nodes have types
|
|
7
|
+
* @ac US-034-AC-3: Validate no self-loops (except cycles)
|
|
8
|
+
* @ac US-034-AC-4: Validate edge consistency
|
|
9
|
+
* @ac US-034-AC-5: Generate validation report
|
|
10
|
+
* @ac US-034-AC-6: Fail on critical issues
|
|
11
|
+
*
|
|
12
|
+
* @issue #34
|
|
13
|
+
*/
|
|
14
|
+
import { getLogger } from '../utils/logger.js';
|
|
15
|
+
const logger = getLogger('DependencyValidator');
|
|
16
|
+
/**
|
|
17
|
+
* Dependency Validator
|
|
18
|
+
*
|
|
19
|
+
* Validates dependency graph integrity:
|
|
20
|
+
* - No dangling references (edges to non-existent nodes)
|
|
21
|
+
* - All nodes have valid types
|
|
22
|
+
* - No self-loops (unless in known cycles)
|
|
23
|
+
* - Edge consistency (graph ↔ components)
|
|
24
|
+
*
|
|
25
|
+
* Performance: O(V + E)
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const validator = new DependencyValidator(graph, components);
|
|
29
|
+
* const result = validator.validate();
|
|
30
|
+
* if (!result.isValid) {
|
|
31
|
+
* console.error(`Found ${result.errors.length} errors`);
|
|
32
|
+
* result.errors.forEach(e => console.error(e.message));
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
export class DependencyValidator {
|
|
36
|
+
graph;
|
|
37
|
+
components;
|
|
38
|
+
options;
|
|
39
|
+
constructor(graph, components, options = {}) {
|
|
40
|
+
this.graph = graph;
|
|
41
|
+
this.components = components;
|
|
42
|
+
this.options = {
|
|
43
|
+
strictMode: options.strictMode ?? false,
|
|
44
|
+
circularDependencies: options.circularDependencies ?? [],
|
|
45
|
+
allowSelfLoops: options.allowSelfLoops ?? false,
|
|
46
|
+
};
|
|
47
|
+
logger.debug('Initialized DependencyValidator', {
|
|
48
|
+
nodes: this.graph.size,
|
|
49
|
+
components: this.components.size,
|
|
50
|
+
strictMode: this.options.strictMode,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate the dependency graph
|
|
55
|
+
*
|
|
56
|
+
* @ac US-034-AC-5: Generate validation report
|
|
57
|
+
* @ac US-034-AC-6: Fail on critical issues
|
|
58
|
+
*/
|
|
59
|
+
validate() {
|
|
60
|
+
const startTime = Date.now();
|
|
61
|
+
const issues = [];
|
|
62
|
+
// Run all validations
|
|
63
|
+
issues.push(...this.validateDanglingReferences());
|
|
64
|
+
issues.push(...this.validateNodeTypes());
|
|
65
|
+
issues.push(...this.validateSelfLoops());
|
|
66
|
+
issues.push(...this.validateEdgeConsistency());
|
|
67
|
+
// Categorize issues by severity
|
|
68
|
+
const errors = issues.filter((i) => i.severity === 'error');
|
|
69
|
+
const warnings = issues.filter((i) => i.severity === 'warning');
|
|
70
|
+
const critical = issues.filter((i) => i.severity === 'critical');
|
|
71
|
+
// Calculate stats
|
|
72
|
+
const stats = this.calculateStats(issues);
|
|
73
|
+
// Determine if valid
|
|
74
|
+
const isValid = critical.length === 0 && errors.length === 0 && (!this.options.strictMode || warnings.length === 0);
|
|
75
|
+
const duration = Date.now() - startTime;
|
|
76
|
+
logger.info('Validation completed', {
|
|
77
|
+
isValid,
|
|
78
|
+
issues: issues.length,
|
|
79
|
+
errors: errors.length,
|
|
80
|
+
warnings: warnings.length,
|
|
81
|
+
critical: critical.length,
|
|
82
|
+
durationMs: duration,
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
isValid,
|
|
86
|
+
issues,
|
|
87
|
+
errors,
|
|
88
|
+
warnings,
|
|
89
|
+
critical,
|
|
90
|
+
stats,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @ac US-034-AC-1: Validate no dangling references
|
|
95
|
+
*/
|
|
96
|
+
validateDanglingReferences() {
|
|
97
|
+
const issues = [];
|
|
98
|
+
for (const [nodeId, deps] of this.graph.entries()) {
|
|
99
|
+
for (const dep of deps) {
|
|
100
|
+
// Check if dependency exists in graph
|
|
101
|
+
if (!this.graph.has(dep) && !this.components.has(dep)) {
|
|
102
|
+
issues.push({
|
|
103
|
+
severity: 'error',
|
|
104
|
+
code: 'DANGLING_REFERENCE',
|
|
105
|
+
message: `Dangling reference: ${nodeId} references non-existent ${dep}`,
|
|
106
|
+
nodeId,
|
|
107
|
+
relatedNodes: [dep],
|
|
108
|
+
suggestion: `Ensure ${dep} exists in the project or remove the reference`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
logger.debug('Dangling reference validation', { danglingRefs: issues.length });
|
|
114
|
+
return issues;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* @ac US-034-AC-2: Validate all nodes have types
|
|
118
|
+
*/
|
|
119
|
+
validateNodeTypes() {
|
|
120
|
+
const issues = [];
|
|
121
|
+
for (const nodeId of this.graph.keys()) {
|
|
122
|
+
// Check if node ID has valid format: "Type:Name"
|
|
123
|
+
if (!nodeId.includes(':')) {
|
|
124
|
+
issues.push({
|
|
125
|
+
severity: 'critical',
|
|
126
|
+
code: 'INVALID_NODE_FORMAT',
|
|
127
|
+
message: `Invalid node format: ${nodeId} (expected "Type:Name")`,
|
|
128
|
+
nodeId,
|
|
129
|
+
suggestion: 'Node IDs must follow the format "MetadataType:ComponentName"',
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const [type, name] = nodeId.split(':');
|
|
134
|
+
if (!type || type.trim().length === 0) {
|
|
135
|
+
issues.push({
|
|
136
|
+
severity: 'critical',
|
|
137
|
+
code: 'MISSING_TYPE',
|
|
138
|
+
message: `Node ${nodeId} has no type`,
|
|
139
|
+
nodeId,
|
|
140
|
+
suggestion: 'All nodes must have a valid metadata type',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (!name || name.trim().length === 0) {
|
|
144
|
+
issues.push({
|
|
145
|
+
severity: 'critical',
|
|
146
|
+
code: 'MISSING_NAME',
|
|
147
|
+
message: `Node ${nodeId} has no name`,
|
|
148
|
+
nodeId,
|
|
149
|
+
suggestion: 'All nodes must have a valid component name',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
logger.debug('Node type validation', { invalidNodes: issues.length });
|
|
154
|
+
return issues;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* @ac US-034-AC-3: Validate no self-loops (except cycles)
|
|
158
|
+
*/
|
|
159
|
+
validateSelfLoops() {
|
|
160
|
+
const issues = [];
|
|
161
|
+
// Build set of nodes in known cycles
|
|
162
|
+
const cyclicNodes = new Set();
|
|
163
|
+
for (const cycle of this.options.circularDependencies) {
|
|
164
|
+
for (const nodeId of cycle.cycle) {
|
|
165
|
+
cyclicNodes.add(nodeId);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const [nodeId, deps] of this.graph.entries()) {
|
|
169
|
+
if (deps.has(nodeId)) {
|
|
170
|
+
// Self-loop detected
|
|
171
|
+
if (!this.options.allowSelfLoops && !cyclicNodes.has(nodeId)) {
|
|
172
|
+
issues.push({
|
|
173
|
+
severity: 'error',
|
|
174
|
+
code: 'SELF_LOOP',
|
|
175
|
+
message: `Self-loop detected: ${nodeId} depends on itself`,
|
|
176
|
+
nodeId,
|
|
177
|
+
suggestion: 'Remove the self-reference or declare it as a circular dependency',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else if (cyclicNodes.has(nodeId)) {
|
|
181
|
+
issues.push({
|
|
182
|
+
severity: 'info',
|
|
183
|
+
code: 'KNOWN_SELF_LOOP',
|
|
184
|
+
message: `Self-loop in known circular dependency: ${nodeId}`,
|
|
185
|
+
nodeId,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
logger.debug('Self-loop validation', { selfLoops: issues.length });
|
|
191
|
+
return issues;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* @ac US-034-AC-4: Validate edge consistency
|
|
195
|
+
*/
|
|
196
|
+
validateEdgeConsistency() {
|
|
197
|
+
const issues = [];
|
|
198
|
+
// Validate that components match graph
|
|
199
|
+
for (const [nodeId, component] of this.components.entries()) {
|
|
200
|
+
const graphDeps = this.graph.get(nodeId) ?? new Set();
|
|
201
|
+
const componentDeps = component.dependencies;
|
|
202
|
+
// Check if graph has all component dependencies
|
|
203
|
+
for (const dep of componentDeps) {
|
|
204
|
+
if (!graphDeps.has(dep)) {
|
|
205
|
+
issues.push({
|
|
206
|
+
severity: 'warning',
|
|
207
|
+
code: 'GRAPH_COMPONENT_MISMATCH',
|
|
208
|
+
message: `Component ${nodeId} declares dependency ${dep} but not in graph`,
|
|
209
|
+
nodeId,
|
|
210
|
+
relatedNodes: [dep],
|
|
211
|
+
suggestion: 'Ensure dependency graph is built from component metadata',
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Check if component has all graph dependencies
|
|
216
|
+
for (const dep of graphDeps) {
|
|
217
|
+
if (!componentDeps.has(dep)) {
|
|
218
|
+
issues.push({
|
|
219
|
+
severity: 'warning',
|
|
220
|
+
code: 'COMPONENT_GRAPH_MISMATCH',
|
|
221
|
+
message: `Graph has edge ${nodeId} → ${dep} but component doesn't declare it`,
|
|
222
|
+
nodeId,
|
|
223
|
+
relatedNodes: [dep],
|
|
224
|
+
suggestion: 'Synchronize graph with component metadata',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
logger.debug('Edge consistency validation', { inconsistencies: issues.length });
|
|
230
|
+
return issues;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Calculate validation statistics
|
|
234
|
+
*/
|
|
235
|
+
calculateStats(issues) {
|
|
236
|
+
const danglingReferences = issues.filter((i) => i.code === 'DANGLING_REFERENCE').length;
|
|
237
|
+
const selfLoops = issues.filter((i) => i.code === 'SELF_LOOP' || i.code === 'KNOWN_SELF_LOOP').length;
|
|
238
|
+
const invalidNodes = issues.filter((i) => i.code === 'INVALID_NODE_FORMAT' || i.code === 'MISSING_TYPE' || i.code === 'MISSING_NAME').length;
|
|
239
|
+
const edgeInconsistencies = issues.filter((i) => i.code === 'GRAPH_COMPONENT_MISMATCH' || i.code === 'COMPONENT_GRAPH_MISMATCH').length;
|
|
240
|
+
let totalEdges = 0;
|
|
241
|
+
for (const deps of this.graph.values()) {
|
|
242
|
+
totalEdges += deps.size;
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
totalNodes: this.graph.size,
|
|
246
|
+
totalEdges,
|
|
247
|
+
danglingReferences,
|
|
248
|
+
selfLoops,
|
|
249
|
+
invalidNodes,
|
|
250
|
+
edgeInconsistencies,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Validate a specific component
|
|
255
|
+
*/
|
|
256
|
+
validateComponent(nodeId) {
|
|
257
|
+
const issues = [];
|
|
258
|
+
// Check if component exists
|
|
259
|
+
if (!this.graph.has(nodeId)) {
|
|
260
|
+
issues.push({
|
|
261
|
+
severity: 'error',
|
|
262
|
+
code: 'NODE_NOT_FOUND',
|
|
263
|
+
message: `Component ${nodeId} not found in graph`,
|
|
264
|
+
nodeId,
|
|
265
|
+
});
|
|
266
|
+
return issues;
|
|
267
|
+
}
|
|
268
|
+
// Validate its dependencies
|
|
269
|
+
const deps = this.graph.get(nodeId);
|
|
270
|
+
for (const dep of deps) {
|
|
271
|
+
if (!this.graph.has(dep)) {
|
|
272
|
+
issues.push({
|
|
273
|
+
severity: 'error',
|
|
274
|
+
code: 'DANGLING_REFERENCE',
|
|
275
|
+
message: `${nodeId} references non-existent ${dep}`,
|
|
276
|
+
nodeId,
|
|
277
|
+
relatedNodes: [dep],
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return issues;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Check if validation would pass
|
|
285
|
+
*/
|
|
286
|
+
isValid() {
|
|
287
|
+
const result = this.validate();
|
|
288
|
+
return result.isValid;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=dependency-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-validator.js","sourceRoot":"","sources":["../../src/dependencies/dependency-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Visualizer
|
|
3
|
+
* Generates visual representations of the dependency graph
|
|
4
|
+
*
|
|
5
|
+
* @ac US-035-AC-1: Generate Mermaid diagram
|
|
6
|
+
* @ac US-035-AC-2: Generate DOT format
|
|
7
|
+
* @ac US-035-AC-3: Support filtering by type
|
|
8
|
+
* @ac US-035-AC-4: Support filtering by depth
|
|
9
|
+
* @ac US-035-AC-5: Highlight critical path
|
|
10
|
+
* @ac US-035-AC-6: Export as SVG/PNG (requires external tools)
|
|
11
|
+
*
|
|
12
|
+
* @issue #35
|
|
13
|
+
*/
|
|
14
|
+
import type { NodeId, DependencyGraph } from '../types/dependency.js';
|
|
15
|
+
import type { MetadataType } from '../types/metadata.js';
|
|
16
|
+
/**
|
|
17
|
+
* Visualization format
|
|
18
|
+
*/
|
|
19
|
+
export type VisualizationFormat = 'mermaid' | 'dot' | 'ascii';
|
|
20
|
+
/**
|
|
21
|
+
* Visualization options
|
|
22
|
+
*/
|
|
23
|
+
export type VisualizationOptions = {
|
|
24
|
+
/** Filter by metadata types */
|
|
25
|
+
includeTypes?: MetadataType[];
|
|
26
|
+
/** Exclude metadata types */
|
|
27
|
+
excludeTypes?: MetadataType[];
|
|
28
|
+
/** Maximum depth to visualize */
|
|
29
|
+
maxDepth?: number;
|
|
30
|
+
/** Nodes in critical path to highlight */
|
|
31
|
+
criticalPath?: NodeId[];
|
|
32
|
+
/** Show node labels */
|
|
33
|
+
showLabels?: boolean;
|
|
34
|
+
/** Color scheme */
|
|
35
|
+
colorScheme?: 'default' | 'type' | 'depth';
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Graph Visualizer
|
|
39
|
+
*
|
|
40
|
+
* Generates visual representations of dependency graphs in multiple formats:
|
|
41
|
+
* - Mermaid: For GitHub, documentation
|
|
42
|
+
* - DOT: For Graphviz rendering
|
|
43
|
+
* - ASCII: For terminal output
|
|
44
|
+
*
|
|
45
|
+
* Performance: O(V + E)
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* const visualizer = new GraphVisualizer(graph);
|
|
49
|
+
* const mermaid = visualizer.toMermaid({ criticalPath });
|
|
50
|
+
* const dot = visualizer.toDot({ includeTypes: ['ApexClass'] });
|
|
51
|
+
* const ascii = visualizer.toAscii();
|
|
52
|
+
*/
|
|
53
|
+
export declare class GraphVisualizer {
|
|
54
|
+
private graph;
|
|
55
|
+
private options;
|
|
56
|
+
constructor(graph: DependencyGraph, options?: VisualizationOptions);
|
|
57
|
+
/**
|
|
58
|
+
* @ac US-035-AC-1: Generate Mermaid diagram
|
|
59
|
+
* @ac US-035-AC-5: Highlight critical path
|
|
60
|
+
*/
|
|
61
|
+
toMermaid(overrideOptions?: VisualizationOptions): string;
|
|
62
|
+
/**
|
|
63
|
+
* @ac US-035-AC-2: Generate DOT format
|
|
64
|
+
*/
|
|
65
|
+
toDot(overrideOptions?: VisualizationOptions): string;
|
|
66
|
+
/**
|
|
67
|
+
* Generate ASCII tree view
|
|
68
|
+
*/
|
|
69
|
+
toAscii(rootNode?: NodeId, overrideOptions?: VisualizationOptions): string;
|
|
70
|
+
/**
|
|
71
|
+
* @ac US-035-AC-3: Support filtering by type
|
|
72
|
+
* @ac US-035-AC-4: Support filtering by depth
|
|
73
|
+
*/
|
|
74
|
+
private filterGraph;
|
|
75
|
+
/**
|
|
76
|
+
* Check if node matches any of the given types
|
|
77
|
+
*/
|
|
78
|
+
private matchesType;
|
|
79
|
+
/**
|
|
80
|
+
* Get Mermaid node styling
|
|
81
|
+
*/
|
|
82
|
+
private getMermaidNodeStyle;
|
|
83
|
+
/**
|
|
84
|
+
* Get DOT color for node
|
|
85
|
+
*/
|
|
86
|
+
private getDotColor;
|
|
87
|
+
/**
|
|
88
|
+
* Get node label (short name)
|
|
89
|
+
*/
|
|
90
|
+
private getNodeLabel;
|
|
91
|
+
/**
|
|
92
|
+
* Escape node ID for Mermaid
|
|
93
|
+
*/
|
|
94
|
+
private escapeNodeId;
|
|
95
|
+
/**
|
|
96
|
+
* Check if node has incoming edges
|
|
97
|
+
*/
|
|
98
|
+
private hasIncomingEdge;
|
|
99
|
+
/**
|
|
100
|
+
* Find a suitable root node for ASCII tree
|
|
101
|
+
*/
|
|
102
|
+
private findRootNode;
|
|
103
|
+
/**
|
|
104
|
+
* Get graph statistics
|
|
105
|
+
*/
|
|
106
|
+
getStats(): {
|
|
107
|
+
nodes: number;
|
|
108
|
+
edges: number;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Visualizer
|
|
3
|
+
* Generates visual representations of the dependency graph
|
|
4
|
+
*
|
|
5
|
+
* @ac US-035-AC-1: Generate Mermaid diagram
|
|
6
|
+
* @ac US-035-AC-2: Generate DOT format
|
|
7
|
+
* @ac US-035-AC-3: Support filtering by type
|
|
8
|
+
* @ac US-035-AC-4: Support filtering by depth
|
|
9
|
+
* @ac US-035-AC-5: Highlight critical path
|
|
10
|
+
* @ac US-035-AC-6: Export as SVG/PNG (requires external tools)
|
|
11
|
+
*
|
|
12
|
+
* @issue #35
|
|
13
|
+
*/
|
|
14
|
+
import { getLogger } from '../utils/logger.js';
|
|
15
|
+
const logger = getLogger('GraphVisualizer');
|
|
16
|
+
/**
|
|
17
|
+
* Color palette for metadata types
|
|
18
|
+
*/
|
|
19
|
+
const TYPE_COLORS = {
|
|
20
|
+
ApexClass: '#FF6B6B',
|
|
21
|
+
ApexTrigger: '#4ECDC4',
|
|
22
|
+
CustomObject: '#45B7D1',
|
|
23
|
+
CustomField: '#96CEB4',
|
|
24
|
+
Flow: '#FFEAA7',
|
|
25
|
+
LightningComponentBundle: '#DFE6E9',
|
|
26
|
+
AuraDefinitionBundle: '#74B9FF',
|
|
27
|
+
VisualforcePage: '#A29BFE',
|
|
28
|
+
EmailTemplate: '#FD79A8',
|
|
29
|
+
PermissionSet: '#FDCB6E',
|
|
30
|
+
Layout: '#6C5CE7',
|
|
31
|
+
Profile: '#E17055',
|
|
32
|
+
FlexiPage: '#00B894',
|
|
33
|
+
Bot: '#00CEC9',
|
|
34
|
+
GenAiPromptTemplate: '#B2BEC3',
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Graph Visualizer
|
|
38
|
+
*
|
|
39
|
+
* Generates visual representations of dependency graphs in multiple formats:
|
|
40
|
+
* - Mermaid: For GitHub, documentation
|
|
41
|
+
* - DOT: For Graphviz rendering
|
|
42
|
+
* - ASCII: For terminal output
|
|
43
|
+
*
|
|
44
|
+
* Performance: O(V + E)
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const visualizer = new GraphVisualizer(graph);
|
|
48
|
+
* const mermaid = visualizer.toMermaid({ criticalPath });
|
|
49
|
+
* const dot = visualizer.toDot({ includeTypes: ['ApexClass'] });
|
|
50
|
+
* const ascii = visualizer.toAscii();
|
|
51
|
+
*/
|
|
52
|
+
export class GraphVisualizer {
|
|
53
|
+
graph;
|
|
54
|
+
options;
|
|
55
|
+
constructor(graph, options = {}) {
|
|
56
|
+
this.graph = graph;
|
|
57
|
+
this.options = {
|
|
58
|
+
showLabels: options.showLabels ?? true,
|
|
59
|
+
colorScheme: options.colorScheme ?? 'type',
|
|
60
|
+
...options,
|
|
61
|
+
};
|
|
62
|
+
logger.debug('Initialized GraphVisualizer', {
|
|
63
|
+
nodes: this.graph.size,
|
|
64
|
+
format: 'multi',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @ac US-035-AC-1: Generate Mermaid diagram
|
|
69
|
+
* @ac US-035-AC-5: Highlight critical path
|
|
70
|
+
*/
|
|
71
|
+
toMermaid(overrideOptions) {
|
|
72
|
+
const opts = { ...this.options, ...overrideOptions };
|
|
73
|
+
const filtered = this.filterGraph(opts);
|
|
74
|
+
const criticalSet = new Set(opts.criticalPath ?? []);
|
|
75
|
+
const lines = ['graph TD'];
|
|
76
|
+
// Add nodes with styling
|
|
77
|
+
for (const [nodeId, deps] of filtered.entries()) {
|
|
78
|
+
for (const dep of deps) {
|
|
79
|
+
const fromStyle = this.getMermaidNodeStyle(nodeId, criticalSet);
|
|
80
|
+
const toStyle = this.getMermaidNodeStyle(dep, criticalSet);
|
|
81
|
+
const edgeStyle = criticalSet.has(nodeId) && criticalSet.has(dep) ? '==>' : '-->';
|
|
82
|
+
lines.push(` ${this.escapeNodeId(nodeId)}${fromStyle} ${edgeStyle} ${this.escapeNodeId(dep)}${toStyle}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Add isolated nodes
|
|
86
|
+
for (const nodeId of filtered.keys()) {
|
|
87
|
+
if (filtered.get(nodeId).size === 0 && !this.hasIncomingEdge(nodeId, filtered)) {
|
|
88
|
+
const style = this.getMermaidNodeStyle(nodeId, criticalSet);
|
|
89
|
+
lines.push(` ${this.escapeNodeId(nodeId)}${style}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Add styling classes
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push(' %% Styling');
|
|
95
|
+
lines.push(' classDef critical fill:#ff6b6b,stroke:#ff0000,stroke-width:3px');
|
|
96
|
+
lines.push(' classDef normal fill:#4ecdc4,stroke:#333,stroke-width:1px');
|
|
97
|
+
return lines.join('\n');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* @ac US-035-AC-2: Generate DOT format
|
|
101
|
+
*/
|
|
102
|
+
toDot(overrideOptions) {
|
|
103
|
+
const opts = { ...this.options, ...overrideOptions };
|
|
104
|
+
const filtered = this.filterGraph(opts);
|
|
105
|
+
const criticalSet = new Set(opts.criticalPath ?? []);
|
|
106
|
+
const lines = ['digraph Dependencies {'];
|
|
107
|
+
lines.push(' rankdir=LR;');
|
|
108
|
+
lines.push(' node [shape=box, style=rounded];');
|
|
109
|
+
lines.push('');
|
|
110
|
+
// Add nodes with styling
|
|
111
|
+
for (const nodeId of filtered.keys()) {
|
|
112
|
+
const color = this.getDotColor(nodeId, criticalSet);
|
|
113
|
+
const label = opts.showLabels ? this.getNodeLabel(nodeId) : nodeId;
|
|
114
|
+
lines.push(` "${nodeId}" [label="${label}", fillcolor="${color}", style="filled,rounded"];`);
|
|
115
|
+
}
|
|
116
|
+
lines.push('');
|
|
117
|
+
// Add edges
|
|
118
|
+
for (const [nodeId, deps] of filtered.entries()) {
|
|
119
|
+
for (const dep of deps) {
|
|
120
|
+
const edgeStyle = criticalSet.has(nodeId) && criticalSet.has(dep) ? ', color=red, penwidth=2.0' : '';
|
|
121
|
+
lines.push(` "${nodeId}" -> "${dep}"${edgeStyle};`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
lines.push('}');
|
|
125
|
+
return lines.join('\n');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Generate ASCII tree view
|
|
129
|
+
*/
|
|
130
|
+
toAscii(rootNode, overrideOptions) {
|
|
131
|
+
const opts = { ...this.options, ...overrideOptions };
|
|
132
|
+
const filtered = this.filterGraph(opts);
|
|
133
|
+
const selectedRootNode = rootNode ?? this.findRootNode(filtered);
|
|
134
|
+
if (!selectedRootNode) {
|
|
135
|
+
return 'Empty graph';
|
|
136
|
+
}
|
|
137
|
+
const visited = new Set();
|
|
138
|
+
const lines = [];
|
|
139
|
+
const buildTree = (nodeId, prefix, isLast) => {
|
|
140
|
+
if (visited.has(nodeId)) {
|
|
141
|
+
lines.push(`${prefix}${isLast ? '└─' : '├─'} ${nodeId} (circular)`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
visited.add(nodeId);
|
|
145
|
+
const label = opts.showLabels ? this.getNodeLabel(nodeId) : nodeId;
|
|
146
|
+
lines.push(`${prefix}${isLast ? '└─' : '├─'} ${label}`);
|
|
147
|
+
const deps = Array.from(filtered.get(nodeId) ?? []);
|
|
148
|
+
const newPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
149
|
+
deps.forEach((dep, index) => {
|
|
150
|
+
const depIsLast = index === deps.length - 1;
|
|
151
|
+
buildTree(dep, newPrefix, depIsLast);
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
buildTree(selectedRootNode, '', true);
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @ac US-035-AC-3: Support filtering by type
|
|
159
|
+
* @ac US-035-AC-4: Support filtering by depth
|
|
160
|
+
*/
|
|
161
|
+
filterGraph(opts) {
|
|
162
|
+
const filtered = new Map();
|
|
163
|
+
for (const [nodeId, deps] of this.graph.entries()) {
|
|
164
|
+
// Filter by type
|
|
165
|
+
if (opts.includeTypes && !this.matchesType(nodeId, opts.includeTypes)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (opts.excludeTypes && this.matchesType(nodeId, opts.excludeTypes)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// Filter dependencies
|
|
172
|
+
const filteredDeps = new Set();
|
|
173
|
+
for (const dep of deps) {
|
|
174
|
+
if (opts.includeTypes && !this.matchesType(dep, opts.includeTypes)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (opts.excludeTypes && this.matchesType(dep, opts.excludeTypes)) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
filteredDeps.add(dep);
|
|
181
|
+
}
|
|
182
|
+
filtered.set(nodeId, filteredDeps);
|
|
183
|
+
}
|
|
184
|
+
return filtered;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Check if node matches any of the given types
|
|
188
|
+
*/
|
|
189
|
+
matchesType(nodeId, types) {
|
|
190
|
+
const nodeType = nodeId.split(':')[0];
|
|
191
|
+
return types.includes(nodeType);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get Mermaid node styling
|
|
195
|
+
*/
|
|
196
|
+
getMermaidNodeStyle(nodeId, criticalSet) {
|
|
197
|
+
if (criticalSet.has(nodeId)) {
|
|
198
|
+
return ':::critical';
|
|
199
|
+
}
|
|
200
|
+
return ':::normal';
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get DOT color for node
|
|
204
|
+
*/
|
|
205
|
+
getDotColor(nodeId, criticalSet) {
|
|
206
|
+
if (criticalSet.has(nodeId)) {
|
|
207
|
+
return '#ff6b6b';
|
|
208
|
+
}
|
|
209
|
+
const type = nodeId.split(':')[0];
|
|
210
|
+
return TYPE_COLORS[type] ?? '#e0e0e0';
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get node label (short name)
|
|
214
|
+
*/
|
|
215
|
+
getNodeLabel(nodeId) {
|
|
216
|
+
const parts = nodeId.split(':');
|
|
217
|
+
return parts.length === 2 ? parts[1] : nodeId;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Escape node ID for Mermaid
|
|
221
|
+
*/
|
|
222
|
+
escapeNodeId(nodeId) {
|
|
223
|
+
return nodeId.replace(/:/g, '_');
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if node has incoming edges
|
|
227
|
+
*/
|
|
228
|
+
hasIncomingEdge(nodeId, graph) {
|
|
229
|
+
for (const deps of graph.values()) {
|
|
230
|
+
if (deps.has(nodeId)) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Find a suitable root node for ASCII tree
|
|
238
|
+
*/
|
|
239
|
+
findRootNode(graph) {
|
|
240
|
+
// Find node with most dependencies
|
|
241
|
+
let maxDeps = 0;
|
|
242
|
+
let root;
|
|
243
|
+
for (const [nodeId, deps] of graph.entries()) {
|
|
244
|
+
if (deps.size > maxDeps) {
|
|
245
|
+
maxDeps = deps.size;
|
|
246
|
+
root = nodeId;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return root;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get graph statistics
|
|
253
|
+
*/
|
|
254
|
+
getStats() {
|
|
255
|
+
let edges = 0;
|
|
256
|
+
for (const deps of this.graph.values()) {
|
|
257
|
+
edges += deps.size;
|
|
258
|
+
}
|
|
259
|
+
return { nodes: this.graph.size, edges };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=graph-visualizer.js.map
|