@agentic-qe/v3 3.0.0-alpha.6 → 3.0.0-alpha.8
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/assets/agents/v3/subagents/v3-qe-code-reviewer.md +339 -0
- package/assets/agents/v3/subagents/v3-qe-integration-reviewer.md +344 -0
- package/assets/agents/v3/subagents/v3-qe-performance-reviewer.md +351 -0
- package/assets/agents/v3/subagents/v3-qe-security-reviewer.md +374 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-green.md +334 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-red.md +329 -0
- package/assets/agents/v3/subagents/v3-qe-tdd-refactor.md +361 -0
- package/assets/agents/v3/v3-qe-accessibility-auditor.md +266 -0
- package/assets/agents/v3/v3-qe-bdd-generator.md +279 -0
- package/assets/agents/v3/v3-qe-chaos-engineer.md +265 -0
- package/assets/agents/v3/v3-qe-code-complexity.md +298 -0
- package/assets/agents/v3/v3-qe-code-intelligence.md +262 -0
- package/assets/agents/v3/v3-qe-contract-validator.md +267 -0
- package/assets/agents/v3/v3-qe-coverage-specialist.md +227 -0
- package/assets/agents/v3/v3-qe-defect-predictor.md +251 -0
- package/assets/agents/v3/v3-qe-dependency-mapper.md +277 -0
- package/assets/agents/v3/v3-qe-deployment-advisor.md +275 -0
- package/assets/agents/v3/v3-qe-flaky-hunter.md +248 -0
- package/assets/agents/v3/v3-qe-fleet-commander.md +293 -0
- package/assets/agents/v3/v3-qe-gap-detector.md +260 -0
- package/assets/agents/v3/v3-qe-graphql-tester.md +308 -0
- package/assets/agents/v3/v3-qe-impact-analyzer.md +299 -0
- package/assets/agents/v3/v3-qe-integration-tester.md +238 -0
- package/assets/agents/v3/v3-qe-kg-builder.md +273 -0
- package/assets/agents/v3/v3-qe-learning-coordinator.md +226 -0
- package/assets/agents/v3/v3-qe-load-tester.md +280 -0
- package/assets/agents/v3/v3-qe-metrics-optimizer.md +300 -0
- package/assets/agents/v3/v3-qe-mutation-tester.md +301 -0
- package/assets/agents/v3/v3-qe-parallel-executor.md +240 -0
- package/assets/agents/v3/v3-qe-pattern-learner.md +271 -0
- package/assets/agents/v3/v3-qe-performance-tester.md +262 -0
- package/assets/agents/v3/v3-qe-property-tester.md +247 -0
- package/assets/agents/v3/v3-qe-quality-gate.md +218 -0
- package/assets/agents/v3/v3-qe-queen-coordinator.md +214 -0
- package/assets/agents/v3/v3-qe-qx-partner.md +313 -0
- package/assets/agents/v3/v3-qe-regression-analyzer.md +322 -0
- package/assets/agents/v3/v3-qe-requirements-validator.md +360 -0
- package/assets/agents/v3/v3-qe-responsive-tester.md +311 -0
- package/assets/agents/v3/v3-qe-retry-handler.md +256 -0
- package/assets/agents/v3/v3-qe-risk-assessor.md +273 -0
- package/assets/agents/v3/v3-qe-root-cause-analyzer.md +286 -0
- package/assets/agents/v3/v3-qe-security-auditor.md +299 -0
- package/assets/agents/v3/v3-qe-security-scanner.md +235 -0
- package/assets/agents/v3/v3-qe-tdd-specialist.md +239 -0
- package/assets/agents/v3/v3-qe-test-architect.md +233 -0
- package/assets/agents/v3/v3-qe-transfer-specialist.md +295 -0
- package/assets/agents/v3/v3-qe-visual-tester.md +232 -0
- package/assets/skills/accessibility-testing/SKILL.md +216 -0
- package/assets/skills/agentdb-advanced/SKILL.md +550 -0
- package/assets/skills/agentdb-learning/SKILL.md +545 -0
- package/assets/skills/agentdb-memory-patterns/SKILL.md +339 -0
- package/assets/skills/agentdb-optimization/SKILL.md +509 -0
- package/assets/skills/agentdb-vector-search/SKILL.md +339 -0
- package/assets/skills/agentic-jujutsu/SKILL.md +645 -0
- package/assets/skills/agentic-quality-engineering/SKILL.md +335 -0
- package/assets/skills/api-testing-patterns/SKILL.md +294 -0
- package/assets/skills/aqe-v2-v3-migration/skill.md +322 -0
- package/assets/skills/brutal-honesty-review/README.md +218 -0
- package/assets/skills/brutal-honesty-review/SKILL.md +235 -0
- package/assets/skills/brutal-honesty-review/resources/assessment-rubrics.md +295 -0
- package/assets/skills/brutal-honesty-review/resources/review-template.md +102 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-code.sh +179 -0
- package/assets/skills/brutal-honesty-review/scripts/assess-tests.sh +223 -0
- package/assets/skills/bug-reporting-excellence/SKILL.md +225 -0
- package/assets/skills/chaos-engineering-resilience/SKILL.md +158 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/README.md +304 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/SKILL.md +315 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/microservice-pipeline.md +239 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/mobile-pipeline.md +375 -0
- package/assets/skills/cicd-pipeline-qe-orchestrator/resources/workflows/monolith-pipeline.md +268 -0
- package/assets/skills/code-review-quality/SKILL.md +227 -0
- package/assets/skills/compatibility-testing/SKILL.md +205 -0
- package/assets/skills/compliance-testing/SKILL.md +225 -0
- package/assets/skills/consultancy-practices/SKILL.md +202 -0
- package/assets/skills/context-driven-testing/SKILL.md +196 -0
- package/assets/skills/contract-testing/SKILL.md +222 -0
- package/assets/skills/database-testing/SKILL.md +244 -0
- package/assets/skills/exploratory-testing-advanced/SKILL.md +201 -0
- package/assets/skills/flow-nexus-neural/SKILL.md +738 -0
- package/assets/skills/flow-nexus-platform/SKILL.md +1157 -0
- package/assets/skills/flow-nexus-swarm/SKILL.md +610 -0
- package/assets/skills/github-code-review/SKILL.md +1140 -0
- package/assets/skills/github-multi-repo/SKILL.md +874 -0
- package/assets/skills/github-project-management/SKILL.md +1277 -0
- package/assets/skills/github-release-management/SKILL.md +1081 -0
- package/assets/skills/github-workflow-automation/SKILL.md +1065 -0
- package/assets/skills/hive-mind-advanced/SKILL.md +712 -0
- package/assets/skills/holistic-testing-pact/SKILL.md +171 -0
- package/assets/skills/hooks-automation/SKILL.md +1201 -0
- package/assets/skills/localization-testing/SKILL.md +221 -0
- package/assets/skills/mobile-testing/SKILL.md +219 -0
- package/assets/skills/mutation-testing/SKILL.md +229 -0
- package/assets/skills/n8n-expression-testing/SKILL.md +434 -0
- package/assets/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
- package/assets/skills/n8n-security-testing/SKILL.md +599 -0
- package/assets/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
- package/assets/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
- package/assets/skills/pair-programming/SKILL.md +1202 -0
- package/assets/skills/performance-analysis/SKILL.md +563 -0
- package/assets/skills/performance-testing/SKILL.md +310 -0
- package/assets/skills/quality-metrics/SKILL.md +225 -0
- package/assets/skills/reasoningbank-agentdb/SKILL.md +446 -0
- package/assets/skills/reasoningbank-intelligence/SKILL.md +201 -0
- package/assets/skills/refactoring-patterns/SKILL.md +205 -0
- package/assets/skills/regression-testing/SKILL.md +227 -0
- package/assets/skills/risk-based-testing/SKILL.md +206 -0
- package/assets/skills/security-testing/SKILL.md +306 -0
- package/assets/skills/sherlock-review/SKILL.md +250 -0
- package/assets/skills/shift-left-testing/SKILL.md +225 -0
- package/assets/skills/shift-right-testing/SKILL.md +227 -0
- package/assets/skills/six-thinking-hats/README.md +190 -0
- package/assets/skills/six-thinking-hats/SKILL.md +280 -0
- package/assets/skills/six-thinking-hats/resources/examples/api-testing-example.md +345 -0
- package/assets/skills/six-thinking-hats/resources/templates/solo-session-template.md +167 -0
- package/assets/skills/six-thinking-hats/resources/templates/team-session-template.md +336 -0
- package/assets/skills/skill-builder/SKILL.md +910 -0
- package/assets/skills/sparc-methodology/SKILL.md +1115 -0
- package/assets/skills/stream-chain/SKILL.md +563 -0
- package/assets/skills/swarm-advanced/SKILL.md +973 -0
- package/assets/skills/swarm-orchestration/SKILL.md +179 -0
- package/assets/skills/tdd-london-chicago/SKILL.md +244 -0
- package/assets/skills/technical-writing/SKILL.md +178 -0
- package/assets/skills/test-automation-strategy/SKILL.md +230 -0
- package/assets/skills/test-data-management/SKILL.md +270 -0
- package/assets/skills/test-design-techniques/SKILL.md +244 -0
- package/assets/skills/test-environment-management/SKILL.md +243 -0
- package/assets/skills/test-reporting-analytics/SKILL.md +214 -0
- package/assets/skills/testability-scoring/README.md +71 -0
- package/assets/skills/testability-scoring/SKILL.md +346 -0
- package/assets/skills/testability-scoring/resources/templates/config.template.js +84 -0
- package/assets/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
- package/assets/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
- package/assets/skills/testability-scoring/scripts/run-assessment.sh +70 -0
- package/assets/skills/v3-qe-chaos-resilience/SKILL.md +238 -0
- package/assets/skills/v3-qe-code-intelligence/SKILL.md +209 -0
- package/assets/skills/v3-qe-contract-testing/SKILL.md +218 -0
- package/assets/skills/v3-qe-coverage-analysis/SKILL.md +187 -0
- package/assets/skills/v3-qe-defect-intelligence/SKILL.md +205 -0
- package/assets/skills/v3-qe-learning-optimization/SKILL.md +238 -0
- package/assets/skills/v3-qe-quality-assessment/SKILL.md +213 -0
- package/assets/skills/v3-qe-requirements-validation/SKILL.md +248 -0
- package/assets/skills/v3-qe-test-execution/SKILL.md +182 -0
- package/assets/skills/v3-qe-test-generation/SKILL.md +141 -0
- package/assets/skills/v3-qe-visual-accessibility/SKILL.md +242 -0
- package/assets/skills/verification-quality/SKILL.md +649 -0
- package/assets/skills/visual-testing-advanced/SKILL.md +219 -0
- package/assets/skills/xp-practices/SKILL.md +229 -0
- package/dist/cli/bundle.js +23 -13
- package/dist/init/agents-installer.js +4 -4
- package/dist/init/agents-installer.js.map +1 -1
- package/dist/init/init-wizard.d.ts.map +1 -1
- package/dist/init/init-wizard.js +15 -5
- package/dist/init/init-wizard.js.map +1 -1
- package/dist/init/skills-installer.js +4 -4
- package/dist/init/skills-installer.js.map +1 -1
- package/package.json +7 -1
- package/docs/analysis/V3-INIT-REQUIREMENTS-ANALYSIS.md +0 -352
- package/implementation/README.md +0 -90
- package/implementation/adrs/ADR-030-coherence-gated-quality-gates.md +0 -312
- package/implementation/adrs/ADR-031-strange-loop-self-awareness.md +0 -484
- package/implementation/adrs/ADR-032-time-crystal-scheduling.md +0 -530
- package/implementation/adrs/ADR-033-early-exit-testing.md +0 -634
- package/implementation/adrs/ADR-034-neural-topology-optimizer.md +0 -589
- package/implementation/adrs/ADR-035-causal-discovery.md +0 -610
- package/implementation/adrs/ADR-036-result-persistence.md +0 -326
- package/implementation/adrs/ADR-037-v3-qe-agent-naming.md +0 -105
- package/implementation/adrs/ADR-038-v3-qe-memory-unification.md +0 -154
- package/implementation/adrs/ADR-039-v3-qe-mcp-optimization.md +0 -179
- package/implementation/adrs/ADR-040-v3-qe-agentic-flow-integration.md +0 -240
- package/implementation/adrs/ADR-041-v3-qe-cli-enhancement.md +0 -296
- package/implementation/adrs/ADR-042-v3-qe-token-tracking-integration.md +0 -517
- package/implementation/adrs/v3-adrs.md +0 -2783
- package/implementation/planning/AQE-V3-MASTER-PLAN.md +0 -815
- package/security-scan-report-2026-01-11.md +0 -410
- package/security-verification-report-2026-01-11.md +0 -278
- package/src/benchmarks/performance-benchmarks.ts +0 -646
- package/src/benchmarks/run-benchmarks.ts +0 -324
- package/src/causal-discovery/causal-graph.ts +0 -450
- package/src/causal-discovery/discovery-engine.ts +0 -438
- package/src/causal-discovery/index.ts +0 -117
- package/src/causal-discovery/types.ts +0 -456
- package/src/causal-discovery/weight-matrix.ts +0 -453
- package/src/cli/commands/qe-tools.ts +0 -634
- package/src/cli/index.ts +0 -1976
- package/src/compatibility/agent-mapper.ts +0 -291
- package/src/compatibility/cli-adapter.ts +0 -277
- package/src/compatibility/config-migrator.ts +0 -334
- package/src/compatibility/index.ts +0 -112
- package/src/compatibility/mcp-adapter.ts +0 -248
- package/src/compatibility/types.ts +0 -156
- package/src/coordination/claims/claim-repository.ts +0 -636
- package/src/coordination/claims/claim-service.ts +0 -675
- package/src/coordination/claims/handoff-manager.ts +0 -535
- package/src/coordination/claims/index.ts +0 -276
- package/src/coordination/claims/interfaces.ts +0 -687
- package/src/coordination/claims/work-stealing.ts +0 -436
- package/src/coordination/cross-domain-router.ts +0 -492
- package/src/coordination/index.ts +0 -127
- package/src/coordination/interfaces.ts +0 -691
- package/src/coordination/protocol-executor.ts +0 -760
- package/src/coordination/protocols/code-intelligence-index.ts +0 -855
- package/src/coordination/protocols/defect-investigation.ts +0 -1184
- package/src/coordination/protocols/index.ts +0 -11
- package/src/coordination/protocols/learning-consolidation.ts +0 -1181
- package/src/coordination/protocols/morning-sync.ts +0 -1055
- package/src/coordination/protocols/quality-gate.ts +0 -1566
- package/src/coordination/protocols/security-audit.ts +0 -1587
- package/src/coordination/queen-coordinator.ts +0 -1176
- package/src/coordination/result-saver.ts +0 -780
- package/src/coordination/task-executor.ts +0 -1146
- package/src/coordination/workflow-orchestrator.ts +0 -1917
- package/src/domains/chaos-resilience/coordinator.ts +0 -1032
- package/src/domains/chaos-resilience/index.ts +0 -143
- package/src/domains/chaos-resilience/interfaces.ts +0 -659
- package/src/domains/chaos-resilience/plugin.ts +0 -691
- package/src/domains/chaos-resilience/services/chaos-engineer.ts +0 -1097
- package/src/domains/chaos-resilience/services/index.ts +0 -19
- package/src/domains/chaos-resilience/services/load-tester.ts +0 -799
- package/src/domains/chaos-resilience/services/performance-profiler.ts +0 -792
- package/src/domains/code-intelligence/coordinator.ts +0 -631
- package/src/domains/code-intelligence/index.ts +0 -86
- package/src/domains/code-intelligence/interfaces.ts +0 -162
- package/src/domains/code-intelligence/plugin.ts +0 -451
- package/src/domains/code-intelligence/services/impact-analyzer.ts +0 -567
- package/src/domains/code-intelligence/services/index.ts +0 -26
- package/src/domains/code-intelligence/services/knowledge-graph.ts +0 -1067
- package/src/domains/code-intelligence/services/semantic-analyzer.ts +0 -901
- package/src/domains/contract-testing/coordinator.ts +0 -1038
- package/src/domains/contract-testing/index.ts +0 -122
- package/src/domains/contract-testing/interfaces.ts +0 -458
- package/src/domains/contract-testing/plugin.ts +0 -746
- package/src/domains/contract-testing/services/api-compatibility.ts +0 -748
- package/src/domains/contract-testing/services/contract-validator.ts +0 -1700
- package/src/domains/contract-testing/services/index.ts +0 -19
- package/src/domains/contract-testing/services/schema-validator.ts +0 -1102
- package/src/domains/coverage-analysis/coordinator.ts +0 -485
- package/src/domains/coverage-analysis/index.ts +0 -114
- package/src/domains/coverage-analysis/interfaces.ts +0 -142
- package/src/domains/coverage-analysis/plugin.ts +0 -172
- package/src/domains/coverage-analysis/services/coverage-analyzer.ts +0 -449
- package/src/domains/coverage-analysis/services/coverage-embedder.ts +0 -733
- package/src/domains/coverage-analysis/services/coverage-parser.ts +0 -753
- package/src/domains/coverage-analysis/services/gap-detector.ts +0 -592
- package/src/domains/coverage-analysis/services/hnsw-index.ts +0 -728
- package/src/domains/coverage-analysis/services/index.ts +0 -61
- package/src/domains/coverage-analysis/services/risk-scorer.ts +0 -540
- package/src/domains/coverage-analysis/services/sublinear-analyzer.ts +0 -747
- package/src/domains/defect-intelligence/coordinator.ts +0 -635
- package/src/domains/defect-intelligence/index.ts +0 -83
- package/src/domains/defect-intelligence/interfaces.ts +0 -152
- package/src/domains/defect-intelligence/plugin.ts +0 -483
- package/src/domains/defect-intelligence/services/causal-root-cause-analyzer.ts +0 -494
- package/src/domains/defect-intelligence/services/defect-predictor.ts +0 -852
- package/src/domains/defect-intelligence/services/index.ts +0 -37
- package/src/domains/defect-intelligence/services/pattern-learner.ts +0 -738
- package/src/domains/defect-intelligence/services/root-cause-analyzer.ts +0 -637
- package/src/domains/domain-interface.ts +0 -77
- package/src/domains/index.ts +0 -23
- package/src/domains/learning-optimization/coordinator.ts +0 -1215
- package/src/domains/learning-optimization/index.ts +0 -127
- package/src/domains/learning-optimization/interfaces.ts +0 -570
- package/src/domains/learning-optimization/plugin.ts +0 -851
- package/src/domains/learning-optimization/services/index.ts +0 -29
- package/src/domains/learning-optimization/services/learning-coordinator.ts +0 -972
- package/src/domains/learning-optimization/services/metrics-optimizer.ts +0 -915
- package/src/domains/learning-optimization/services/production-intel.ts +0 -971
- package/src/domains/learning-optimization/services/transfer-specialist.ts +0 -723
- package/src/domains/quality-assessment/coherence/gate-controller.ts +0 -549
- package/src/domains/quality-assessment/coherence/index.ts +0 -211
- package/src/domains/quality-assessment/coherence/lambda-calculator.ts +0 -384
- package/src/domains/quality-assessment/coherence/partition-detector.ts +0 -469
- package/src/domains/quality-assessment/coherence/types.ts +0 -384
- package/src/domains/quality-assessment/coordinator.ts +0 -605
- package/src/domains/quality-assessment/index.ts +0 -97
- package/src/domains/quality-assessment/interfaces.ts +0 -152
- package/src/domains/quality-assessment/plugin.ts +0 -496
- package/src/domains/quality-assessment/services/coherence-gate.ts +0 -358
- package/src/domains/quality-assessment/services/deployment-advisor.ts +0 -571
- package/src/domains/quality-assessment/services/index.ts +0 -34
- package/src/domains/quality-assessment/services/quality-analyzer.ts +0 -670
- package/src/domains/quality-assessment/services/quality-gate.ts +0 -384
- package/src/domains/requirements-validation/coordinator.ts +0 -812
- package/src/domains/requirements-validation/index.ts +0 -92
- package/src/domains/requirements-validation/interfaces.ts +0 -303
- package/src/domains/requirements-validation/plugin.ts +0 -576
- package/src/domains/requirements-validation/services/bdd-scenario-writer.ts +0 -676
- package/src/domains/requirements-validation/services/index.ts +0 -20
- package/src/domains/requirements-validation/services/requirements-validator.ts +0 -559
- package/src/domains/requirements-validation/services/testability-scorer.ts +0 -639
- package/src/domains/security-compliance/coordinator.ts +0 -757
- package/src/domains/security-compliance/index.ts +0 -120
- package/src/domains/security-compliance/interfaces.ts +0 -434
- package/src/domains/security-compliance/plugin.ts +0 -509
- package/src/domains/security-compliance/services/compliance-validator.ts +0 -1226
- package/src/domains/security-compliance/services/index.ts +0 -31
- package/src/domains/security-compliance/services/security-auditor.ts +0 -2227
- package/src/domains/security-compliance/services/security-scanner.ts +0 -2354
- package/src/domains/security-compliance/services/semgrep-integration.ts +0 -289
- package/src/domains/test-execution/coordinator.ts +0 -426
- package/src/domains/test-execution/index.ts +0 -76
- package/src/domains/test-execution/interfaces.ts +0 -119
- package/src/domains/test-execution/plugin.ts +0 -208
- package/src/domains/test-execution/services/flaky-detector.ts +0 -1240
- package/src/domains/test-execution/services/index.ts +0 -8
- package/src/domains/test-execution/services/retry-handler.ts +0 -820
- package/src/domains/test-execution/services/test-executor.ts +0 -885
- package/src/domains/test-generation/coordinator.ts +0 -656
- package/src/domains/test-generation/index.ts +0 -77
- package/src/domains/test-generation/interfaces.ts +0 -118
- package/src/domains/test-generation/plugin.ts +0 -397
- package/src/domains/test-generation/services/index.ts +0 -23
- package/src/domains/test-generation/services/pattern-matcher.ts +0 -1725
- package/src/domains/test-generation/services/test-generator.ts +0 -2750
- package/src/domains/visual-accessibility/coordinator.ts +0 -860
- package/src/domains/visual-accessibility/index.ts +0 -116
- package/src/domains/visual-accessibility/interfaces.ts +0 -435
- package/src/domains/visual-accessibility/plugin.ts +0 -568
- package/src/domains/visual-accessibility/services/accessibility-tester.ts +0 -982
- package/src/domains/visual-accessibility/services/axe-core-audit.ts +0 -630
- package/src/domains/visual-accessibility/services/index.ts +0 -28
- package/src/domains/visual-accessibility/services/responsive-tester.ts +0 -934
- package/src/domains/visual-accessibility/services/visual-tester.ts +0 -458
- package/src/early-exit/early-exit-controller.ts +0 -490
- package/src/early-exit/early-exit-decision.ts +0 -391
- package/src/early-exit/index.ts +0 -115
- package/src/early-exit/quality-signal.ts +0 -389
- package/src/early-exit/speculative-executor.ts +0 -505
- package/src/early-exit/types.ts +0 -407
- package/src/feedback/coverage-learner.ts +0 -456
- package/src/feedback/feedback-loop.ts +0 -426
- package/src/feedback/index.ts +0 -72
- package/src/feedback/pattern-promotion.ts +0 -373
- package/src/feedback/quality-score-calculator.ts +0 -334
- package/src/feedback/test-outcome-tracker.ts +0 -450
- package/src/feedback/types.ts +0 -497
- package/src/index.ts +0 -224
- package/src/init/agents-installer.ts +0 -536
- package/src/init/index.ts +0 -80
- package/src/init/init-wizard.ts +0 -1061
- package/src/init/project-analyzer.ts +0 -696
- package/src/init/self-configurator.ts +0 -488
- package/src/init/skills-installer.ts +0 -467
- package/src/init/types.ts +0 -432
- package/src/integrations/ruvector/ast-complexity.ts +0 -470
- package/src/integrations/ruvector/coverage-router.ts +0 -594
- package/src/integrations/ruvector/diff-risk-classifier.ts +0 -759
- package/src/integrations/ruvector/fallback.ts +0 -942
- package/src/integrations/ruvector/graph-boundaries.ts +0 -809
- package/src/integrations/ruvector/index.ts +0 -363
- package/src/integrations/ruvector/interfaces.ts +0 -609
- package/src/integrations/ruvector/q-learning-router.ts +0 -550
- package/src/kernel/agent-coordinator.ts +0 -165
- package/src/kernel/agentdb-backend.ts +0 -504
- package/src/kernel/event-bus.ts +0 -129
- package/src/kernel/hybrid-backend.ts +0 -538
- package/src/kernel/index.ts +0 -28
- package/src/kernel/interfaces.ts +0 -257
- package/src/kernel/kernel.ts +0 -285
- package/src/kernel/memory-backend.ts +0 -169
- package/src/kernel/memory-factory.ts +0 -293
- package/src/kernel/plugin-loader.ts +0 -179
- package/src/learning/index.ts +0 -219
- package/src/learning/pattern-store.ts +0 -990
- package/src/learning/qe-guidance.ts +0 -832
- package/src/learning/qe-hooks.ts +0 -644
- package/src/learning/qe-patterns.ts +0 -449
- package/src/learning/qe-reasoning-bank.ts +0 -951
- package/src/learning/real-embeddings.ts +0 -277
- package/src/learning/real-qe-reasoning-bank.ts +0 -833
- package/src/learning/sqlite-persistence.ts +0 -554
- package/src/mcp/entry.ts +0 -59
- package/src/mcp/handlers/agent-handlers.ts +0 -285
- package/src/mcp/handlers/core-handlers.ts +0 -317
- package/src/mcp/handlers/domain-handlers.ts +0 -1444
- package/src/mcp/handlers/index.ts +0 -57
- package/src/mcp/handlers/memory-handlers.ts +0 -338
- package/src/mcp/handlers/task-handlers.ts +0 -363
- package/src/mcp/index.ts +0 -30
- package/src/mcp/metrics/index.ts +0 -14
- package/src/mcp/metrics/metrics-collector.ts +0 -503
- package/src/mcp/protocol-server.ts +0 -752
- package/src/mcp/security/cve-prevention.ts +0 -742
- package/src/mcp/security/index.ts +0 -356
- package/src/mcp/security/oauth21-provider.ts +0 -821
- package/src/mcp/security/rate-limiter.ts +0 -615
- package/src/mcp/security/sampling-server.ts +0 -662
- package/src/mcp/security/schema-validator.ts +0 -855
- package/src/mcp/server.ts +0 -657
- package/src/mcp/tool-registry.ts +0 -391
- package/src/mcp/tools/base.ts +0 -399
- package/src/mcp/tools/chaos-resilience/inject.ts +0 -699
- package/src/mcp/tools/code-intelligence/analyze.ts +0 -745
- package/src/mcp/tools/contract-testing/validate.ts +0 -708
- package/src/mcp/tools/coverage-analysis/index.ts +0 -770
- package/src/mcp/tools/defect-intelligence/predict.ts +0 -466
- package/src/mcp/tools/index.ts +0 -214
- package/src/mcp/tools/learning-optimization/optimize.ts +0 -772
- package/src/mcp/tools/quality-assessment/evaluate.ts +0 -385
- package/src/mcp/tools/registry.ts +0 -248
- package/src/mcp/tools/requirements-validation/validate.ts +0 -394
- package/src/mcp/tools/security-compliance/scan.ts +0 -365
- package/src/mcp/tools/test-execution/execute.ts +0 -291
- package/src/mcp/tools/test-generation/generate.ts +0 -544
- package/src/mcp/tools/visual-accessibility/index.ts +0 -791
- package/src/mcp/transport/index.ts +0 -31
- package/src/mcp/transport/stdio.ts +0 -318
- package/src/mcp/types.ts +0 -543
- package/src/neural-optimizer/index.ts +0 -111
- package/src/neural-optimizer/replay-buffer.ts +0 -455
- package/src/neural-optimizer/swarm-topology.ts +0 -508
- package/src/neural-optimizer/topology-optimizer.ts +0 -828
- package/src/neural-optimizer/types.ts +0 -481
- package/src/neural-optimizer/value-network.ts +0 -351
- package/src/optimization/auto-tuner.ts +0 -817
- package/src/optimization/index.ts +0 -77
- package/src/optimization/metric-collectors.ts +0 -474
- package/src/optimization/qe-workers.ts +0 -704
- package/src/optimization/tuning-algorithm.ts +0 -401
- package/src/optimization/types.ts +0 -314
- package/src/routing/index.ts +0 -51
- package/src/routing/qe-agent-registry.ts +0 -963
- package/src/routing/qe-task-router.ts +0 -564
- package/src/routing/routing-feedback.ts +0 -365
- package/src/routing/types.ts +0 -406
- package/src/shared/embeddings/embedding-cache.ts +0 -157
- package/src/shared/embeddings/index.ts +0 -50
- package/src/shared/embeddings/nomic-embedder.ts +0 -404
- package/src/shared/embeddings/ollama-client.ts +0 -195
- package/src/shared/embeddings/types.ts +0 -147
- package/src/shared/entities/agent.ts +0 -141
- package/src/shared/entities/base-entity.ts +0 -79
- package/src/shared/entities/index.ts +0 -6
- package/src/shared/events/domain-events.ts +0 -259
- package/src/shared/events/index.ts +0 -5
- package/src/shared/git/git-analyzer.ts +0 -656
- package/src/shared/git/index.ts +0 -11
- package/src/shared/http/http-client.ts +0 -420
- package/src/shared/http/index.ts +0 -13
- package/src/shared/index.ts +0 -41
- package/src/shared/io/file-reader.ts +0 -525
- package/src/shared/io/index.ts +0 -25
- package/src/shared/llm/cache.ts +0 -473
- package/src/shared/llm/circuit-breaker.ts +0 -369
- package/src/shared/llm/cost-tracker.ts +0 -460
- package/src/shared/llm/index.ts +0 -140
- package/src/shared/llm/interfaces.ts +0 -629
- package/src/shared/llm/provider-manager.ts +0 -685
- package/src/shared/llm/providers/claude.ts +0 -524
- package/src/shared/llm/providers/index.ts +0 -8
- package/src/shared/llm/providers/ollama.ts +0 -575
- package/src/shared/llm/providers/openai.ts +0 -609
- package/src/shared/metrics/code-metrics.ts +0 -520
- package/src/shared/metrics/index.ts +0 -23
- package/src/shared/metrics/system-metrics.ts +0 -353
- package/src/shared/parsers/index.ts +0 -6
- package/src/shared/parsers/typescript-parser.ts +0 -841
- package/src/shared/security/compliance-patterns.ts +0 -666
- package/src/shared/security/index.ts +0 -30
- package/src/shared/security/osv-client.ts +0 -468
- package/src/shared/types/index.ts +0 -150
- package/src/shared/value-objects/index.ts +0 -273
- package/src/strange-loop/healing-controller.ts +0 -833
- package/src/strange-loop/index.ts +0 -104
- package/src/strange-loop/self-model.ts +0 -494
- package/src/strange-loop/strange-loop.ts +0 -446
- package/src/strange-loop/swarm-observer.ts +0 -448
- package/src/strange-loop/topology-analyzer.ts +0 -565
- package/src/strange-loop/types.ts +0 -640
- package/src/time-crystal/default-phases.ts +0 -520
- package/src/time-crystal/index.ts +0 -164
- package/src/time-crystal/oscillator.ts +0 -425
- package/src/time-crystal/phase-executor.ts +0 -521
- package/src/time-crystal/scheduler.ts +0 -1025
- package/src/time-crystal/test-runner.ts +0 -787
- package/src/time-crystal/types.ts +0 -421
- package/src/workers/base-worker.ts +0 -304
- package/src/workers/daemon.ts +0 -264
- package/src/workers/index.ts +0 -119
- package/src/workers/interfaces.ts +0 -393
- package/src/workers/worker-manager.ts +0 -424
- package/src/workers/workers/compliance-checker.ts +0 -445
- package/src/workers/workers/coverage-tracker.ts +0 -344
- package/src/workers/workers/defect-predictor.ts +0 -375
- package/src/workers/workers/flaky-detector.ts +0 -390
- package/src/workers/workers/index.ts +0 -17
- package/src/workers/workers/learning-consolidation.ts +0 -442
- package/src/workers/workers/performance-baseline.ts +0 -434
- package/src/workers/workers/quality-gate.ts +0 -419
- package/src/workers/workers/regression-monitor.ts +0 -357
- package/src/workers/workers/security-scan.ts +0 -349
- package/src/workers/workers/test-health.ts +0 -359
- package/tests/integration/code-intelligence/knowledge-graph-real.test.ts +0 -540
- package/tests/integration/coordination/cross-domain-router.test.ts +0 -403
- package/tests/integration/coordination/protocol-executor.test.ts +0 -454
- package/tests/integration/coordination/workflow-orchestrator.test.ts +0 -418
- package/tests/integration/feedback/feedback-loop-integration.test.ts +0 -560
- package/tests/integration/migration/v2-to-v3-migration.test.ts +0 -471
- package/tests/integration/parsers/typescript-parser.test.ts +0 -463
- package/tests/integration/security/vulnerability-detection.test.ts +0 -628
- package/tests/integration/test-execution/coordinator.test.ts +0 -410
- package/tests/integration/test-generation/coordinator.test.ts +0 -361
- package/tests/mocks/index.ts +0 -228
- package/tests/time-crystal/default-phases.test.ts +0 -476
- package/tests/time-crystal/oscillator.test.ts +0 -541
- package/tests/time-crystal/phase-executor.test.ts +0 -653
- package/tests/time-crystal/scheduler.test.ts +0 -626
- package/tests/time-crystal/test-runner.test.ts +0 -594
- package/tests/unit/causal-discovery/causal-graph.test.ts +0 -504
- package/tests/unit/causal-discovery/causal-root-cause-analyzer.test.ts +0 -347
- package/tests/unit/causal-discovery/discovery-engine.test.ts +0 -435
- package/tests/unit/causal-discovery/weight-matrix.test.ts +0 -328
- package/tests/unit/cli/cli.test.ts +0 -341
- package/tests/unit/cli/commands.test.ts +0 -414
- package/tests/unit/cli/init-command.test.ts +0 -274
- package/tests/unit/cli/migrate-command.test.ts +0 -396
- package/tests/unit/coordination/claims/claim-service.test.ts +0 -949
- package/tests/unit/coordination/claims/handoff-manager.test.ts +0 -773
- package/tests/unit/coordination/claims/work-stealing.test.ts +0 -492
- package/tests/unit/coordination/queen-coordinator.test.ts +0 -966
- package/tests/unit/coordination/result-saver.test.ts +0 -653
- package/tests/unit/coordination/task-executor.test.ts +0 -810
- package/tests/unit/domains/chaos-resilience/chaos-engineer.test.ts +0 -484
- package/tests/unit/domains/chaos-resilience/load-tester.test.ts +0 -559
- package/tests/unit/domains/chaos-resilience/performance-profiler.test.ts +0 -490
- package/tests/unit/domains/code-intelligence/impact-analyzer.test.ts +0 -560
- package/tests/unit/domains/code-intelligence/knowledge-graph.test.ts +0 -460
- package/tests/unit/domains/code-intelligence/semantic-analyzer.test.ts +0 -584
- package/tests/unit/domains/contract-testing/api-compatibility.test.ts +0 -483
- package/tests/unit/domains/contract-testing/contract-validator.test.ts +0 -370
- package/tests/unit/domains/contract-testing/schema-validator.test.ts +0 -610
- package/tests/unit/domains/coverage-analysis/coverage-embedder.test.ts +0 -298
- package/tests/unit/domains/coverage-analysis/hnsw-index.test.ts +0 -292
- package/tests/unit/domains/coverage-analysis/sublinear-analyzer.test.ts +0 -506
- package/tests/unit/domains/defect-intelligence/defect-predictor.test.ts +0 -370
- package/tests/unit/domains/defect-intelligence/pattern-learner.test.ts +0 -546
- package/tests/unit/domains/defect-intelligence/root-cause-analyzer.test.ts +0 -534
- package/tests/unit/domains/learning-optimization/learning-coordinator.test.ts +0 -541
- package/tests/unit/domains/learning-optimization/metrics-optimizer.test.ts +0 -552
- package/tests/unit/domains/learning-optimization/production-intel.test.ts +0 -589
- package/tests/unit/domains/learning-optimization/transfer-specialist.test.ts +0 -453
- package/tests/unit/domains/quality-assessment/coherence-gate.test.ts +0 -1006
- package/tests/unit/domains/quality-assessment/deployment-advisor.test.ts +0 -515
- package/tests/unit/domains/quality-assessment/quality-analyzer.test.ts +0 -401
- package/tests/unit/domains/quality-assessment/quality-gate.test.ts +0 -324
- package/tests/unit/domains/requirements-validation/bdd-scenario-writer.test.ts +0 -479
- package/tests/unit/domains/requirements-validation/requirements-validator.test.ts +0 -452
- package/tests/unit/domains/requirements-validation/testability-scorer.test.ts +0 -505
- package/tests/unit/domains/security-compliance/compliance-validator.test.ts +0 -500
- package/tests/unit/domains/security-compliance/security-auditor.test.ts +0 -498
- package/tests/unit/domains/security-compliance/security-scanner.test.ts +0 -412
- package/tests/unit/domains/visual-accessibility/accessibility-tester.test.ts +0 -432
- package/tests/unit/domains/visual-accessibility/responsive-tester.test.ts +0 -506
- package/tests/unit/domains/visual-accessibility/visual-tester.test.ts +0 -412
- package/tests/unit/early-exit/early-exit-controller.test.ts +0 -548
- package/tests/unit/early-exit/early-exit-decision.test.ts +0 -617
- package/tests/unit/early-exit/index.test.ts +0 -254
- package/tests/unit/early-exit/quality-signal.test.ts +0 -589
- package/tests/unit/early-exit/speculative-executor.test.ts +0 -453
- package/tests/unit/feedback/coverage-learner.test.ts +0 -288
- package/tests/unit/feedback/feedback-loop.test.ts +0 -458
- package/tests/unit/feedback/pattern-promotion.test.ts +0 -390
- package/tests/unit/feedback/quality-score-calculator.test.ts +0 -364
- package/tests/unit/feedback/test-outcome-tracker.test.ts +0 -243
- package/tests/unit/init/init-wizard.test.ts +0 -881
- package/tests/unit/init/project-analyzer.test.ts +0 -807
- package/tests/unit/init/self-configurator.test.ts +0 -493
- package/tests/unit/integrations/ruvector/ast-complexity.test.ts +0 -240
- package/tests/unit/integrations/ruvector/coverage-router.test.ts +0 -366
- package/tests/unit/integrations/ruvector/diff-risk-classifier.test.ts +0 -340
- package/tests/unit/integrations/ruvector/graph-boundaries.test.ts +0 -355
- package/tests/unit/integrations/ruvector/q-learning-router.test.ts +0 -314
- package/tests/unit/kernel/agent-coordinator.test.ts +0 -220
- package/tests/unit/kernel/event-bus.test.ts +0 -197
- package/tests/unit/learning/qe-reasoning-bank.test.ts +0 -666
- package/tests/unit/learning/real-qe-reasoning-bank.benchmark.test.ts +0 -415
- package/tests/unit/mcp/mcp-server.test.ts +0 -544
- package/tests/unit/mcp/metrics/metrics-collector.test.ts +0 -340
- package/tests/unit/mcp/security/cve-prevention.test.ts +0 -512
- package/tests/unit/mcp/security/oauth21-provider.test.ts +0 -624
- package/tests/unit/mcp/security/rate-limiter.test.ts +0 -410
- package/tests/unit/mcp/security/sampling-server.test.ts +0 -420
- package/tests/unit/mcp/security/schema-validator.test.ts +0 -494
- package/tests/unit/mcp/tools/base.test.ts +0 -336
- package/tests/unit/mcp/tools/domain-tools.test.ts +0 -759
- package/tests/unit/mcp/tools/registry.test.ts +0 -240
- package/tests/unit/neural-optimizer/replay-buffer.test.ts +0 -403
- package/tests/unit/neural-optimizer/swarm-topology.test.ts +0 -473
- package/tests/unit/neural-optimizer/topology-optimizer.test.ts +0 -595
- package/tests/unit/neural-optimizer/value-network.test.ts +0 -343
- package/tests/unit/optimization/auto-tuner.test.ts +0 -506
- package/tests/unit/optimization/metric-collectors.test.ts +0 -352
- package/tests/unit/optimization/qe-workers.test.ts +0 -407
- package/tests/unit/optimization/tuning-algorithm.test.ts +0 -467
- package/tests/unit/routing/qe-agent-registry.test.ts +0 -229
- package/tests/unit/routing/qe-task-router.test.ts +0 -390
- package/tests/unit/routing/routing-feedback.test.ts +0 -339
- package/tests/unit/shared/embeddings/nomic-embedder.test.ts +0 -419
- package/tests/unit/shared/http/http-client.test.ts +0 -719
- package/tests/unit/shared/io/file-reader.test.ts +0 -511
- package/tests/unit/shared/llm/cache.test.ts +0 -391
- package/tests/unit/shared/llm/circuit-breaker.test.ts +0 -293
- package/tests/unit/shared/llm/cost-tracker.test.ts +0 -431
- package/tests/unit/shared/llm/provider-manager.test.ts +0 -550
- package/tests/unit/shared/llm/providers.test.ts +0 -532
- package/tests/unit/shared/parsers/typescript-parser.test.ts +0 -693
- package/tests/unit/shared/value-objects.test.ts +0 -184
- package/tests/unit/strange-loop/strange-loop.test.ts +0 -1170
- package/tests/unit/workers/base-worker.test.ts +0 -341
- package/tests/unit/workers/daemon.test.ts +0 -291
- package/tests/unit/workers/worker-manager.test.ts +0 -284
- package/tsconfig.json +0 -32
- package/vitest.config.ts +0 -27
|
@@ -1,1725 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agentic QE v3 - Pattern Matching Service
|
|
3
|
-
* Implements IPatternMatchingService for learning and applying test patterns
|
|
4
|
-
*
|
|
5
|
-
* Uses TypeScript Compiler API for real AST parsing and pattern extraction
|
|
6
|
-
* Uses NomicEmbedder for semantic embeddings when available
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
-
import * as ts from 'typescript';
|
|
11
|
-
import * as fs from 'fs';
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
import { Result, ok, err } from '../../../shared/types';
|
|
14
|
-
import { MemoryBackend, VectorSearchResult } from '../../../kernel/interfaces';
|
|
15
|
-
import { Pattern, LearnPatternsRequest, LearnedPatterns } from '../interfaces';
|
|
16
|
-
import { NomicEmbedder, IEmbeddingProvider, EMBEDDING_CONFIG } from '../../../shared/embeddings';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Interface for the pattern matching service
|
|
20
|
-
*/
|
|
21
|
-
export interface IPatternMatchingService {
|
|
22
|
-
findMatchingPatterns(
|
|
23
|
-
context: PatternSearchContext
|
|
24
|
-
): Promise<Result<PatternMatch[], Error>>;
|
|
25
|
-
applyPattern(patternId: string, targetCode: string): Promise<Result<AppliedPattern, Error>>;
|
|
26
|
-
recordPattern(pattern: PatternDefinition): Promise<Result<Pattern, Error>>;
|
|
27
|
-
learnPatterns(request: LearnPatternsRequest): Promise<Result<LearnedPatterns, Error>>;
|
|
28
|
-
getPattern(patternId: string): Promise<Pattern | undefined>;
|
|
29
|
-
listPatterns(filter?: PatternFilter): Promise<Pattern[]>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Context for pattern search
|
|
34
|
-
*/
|
|
35
|
-
export interface PatternSearchContext {
|
|
36
|
-
sourceCode?: string;
|
|
37
|
-
fileType?: string;
|
|
38
|
-
testType?: 'unit' | 'integration' | 'e2e' | 'property';
|
|
39
|
-
framework?: string;
|
|
40
|
-
tags?: string[];
|
|
41
|
-
semanticQuery?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Pattern match result
|
|
46
|
-
*/
|
|
47
|
-
export interface PatternMatch {
|
|
48
|
-
pattern: Pattern;
|
|
49
|
-
score: number;
|
|
50
|
-
matchReason: string;
|
|
51
|
-
suggestedApplication: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Applied pattern result
|
|
56
|
-
*/
|
|
57
|
-
export interface AppliedPattern {
|
|
58
|
-
patternId: string;
|
|
59
|
-
generatedCode: string;
|
|
60
|
-
modifications: PatternModification[];
|
|
61
|
-
confidence: number;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Pattern modification record
|
|
66
|
-
*/
|
|
67
|
-
export interface PatternModification {
|
|
68
|
-
location: string;
|
|
69
|
-
original?: string;
|
|
70
|
-
replacement: string;
|
|
71
|
-
reason: string;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Pattern definition for recording
|
|
76
|
-
*/
|
|
77
|
-
export interface PatternDefinition {
|
|
78
|
-
name: string;
|
|
79
|
-
structure: string;
|
|
80
|
-
description?: string;
|
|
81
|
-
tags?: string[];
|
|
82
|
-
testType?: 'unit' | 'integration' | 'e2e' | 'property';
|
|
83
|
-
framework?: string;
|
|
84
|
-
examples?: PatternExample[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Pattern example
|
|
89
|
-
*/
|
|
90
|
-
export interface PatternExample {
|
|
91
|
-
input: string;
|
|
92
|
-
output: string;
|
|
93
|
-
context?: string;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Pattern filter
|
|
98
|
-
*/
|
|
99
|
-
export interface PatternFilter {
|
|
100
|
-
testType?: 'unit' | 'integration' | 'e2e' | 'property';
|
|
101
|
-
framework?: string;
|
|
102
|
-
tags?: string[];
|
|
103
|
-
minApplicability?: number;
|
|
104
|
-
limit?: number;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Configuration for the pattern matcher
|
|
109
|
-
*/
|
|
110
|
-
export interface PatternMatcherConfig {
|
|
111
|
-
maxPatterns: number;
|
|
112
|
-
minMatchScore: number;
|
|
113
|
-
enableVectorSearch: boolean;
|
|
114
|
-
embeddingDimension: number;
|
|
115
|
-
patternNamespace: string;
|
|
116
|
-
/** Optional embedder instance (defaults to NomicEmbedder with fallback) */
|
|
117
|
-
embedder?: IEmbeddingProvider;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const DEFAULT_CONFIG: PatternMatcherConfig = {
|
|
121
|
-
maxPatterns: 100,
|
|
122
|
-
minMatchScore: 0.5,
|
|
123
|
-
enableVectorSearch: true,
|
|
124
|
-
embeddingDimension: EMBEDDING_CONFIG.DIMENSIONS,
|
|
125
|
-
patternNamespace: 'test-generation:patterns',
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Pattern Matching Service Implementation
|
|
130
|
-
* Manages test patterns with learning and semantic search capabilities
|
|
131
|
-
*/
|
|
132
|
-
export class PatternMatcherService implements IPatternMatchingService {
|
|
133
|
-
private readonly config: PatternMatcherConfig;
|
|
134
|
-
private readonly patternCache: Map<string, Pattern> = new Map();
|
|
135
|
-
private readonly tsParser: TypeScriptASTParser;
|
|
136
|
-
private readonly embedder: IEmbeddingProvider;
|
|
137
|
-
|
|
138
|
-
constructor(
|
|
139
|
-
private readonly memory: MemoryBackend,
|
|
140
|
-
config: Partial<PatternMatcherConfig> = {}
|
|
141
|
-
) {
|
|
142
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
143
|
-
this.tsParser = new TypeScriptASTParser();
|
|
144
|
-
// Use provided embedder or create NomicEmbedder with fallback enabled
|
|
145
|
-
this.embedder = config.embedder ?? new NomicEmbedder({ enableFallback: true });
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Match testable patterns from a source file
|
|
150
|
-
* Uses TypeScript AST to identify functions, classes, and methods that need tests
|
|
151
|
-
*/
|
|
152
|
-
async matchTestablePatterns(filePath: string): Promise<Result<TestablePattern[], Error>> {
|
|
153
|
-
try {
|
|
154
|
-
// Read file content
|
|
155
|
-
let content: string;
|
|
156
|
-
try {
|
|
157
|
-
content = fs.readFileSync(filePath, 'utf-8');
|
|
158
|
-
} catch {
|
|
159
|
-
return err(new Error(`Cannot read file: ${filePath}`));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return this.matchTestablePatternsFromCode(content, filePath);
|
|
163
|
-
} catch (error) {
|
|
164
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Match testable patterns from source code string
|
|
170
|
-
*/
|
|
171
|
-
async matchTestablePatternsFromCode(
|
|
172
|
-
sourceCode: string,
|
|
173
|
-
fileName: string = 'module.ts'
|
|
174
|
-
): Promise<Result<TestablePattern[], Error>> {
|
|
175
|
-
try {
|
|
176
|
-
const patterns: TestablePattern[] = [];
|
|
177
|
-
const sourceFile = this.tsParser.parseSource(sourceCode, fileName);
|
|
178
|
-
|
|
179
|
-
// Extract functions and generate test suggestions
|
|
180
|
-
const functions = this.tsParser.extractFunctions(sourceFile);
|
|
181
|
-
for (const fn of functions) {
|
|
182
|
-
patterns.push(this.createFunctionPattern(fn));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Extract classes and their methods
|
|
186
|
-
const classes = this.tsParser.extractClasses(sourceFile);
|
|
187
|
-
for (const cls of classes) {
|
|
188
|
-
// Add class-level pattern
|
|
189
|
-
patterns.push(this.createClassPattern(cls));
|
|
190
|
-
|
|
191
|
-
// Add method-level patterns for each public method
|
|
192
|
-
for (const method of cls.methods) {
|
|
193
|
-
patterns.push(this.createMethodPattern(cls.name, method));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return ok(patterns);
|
|
198
|
-
} catch (error) {
|
|
199
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create a testable pattern for a function
|
|
205
|
-
*/
|
|
206
|
-
private createFunctionPattern(fn: FunctionInfo): TestablePattern {
|
|
207
|
-
const suggestedTests = this.suggestTestsForFunction(fn);
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
type: 'function',
|
|
211
|
-
name: fn.name,
|
|
212
|
-
complexity: fn.complexity,
|
|
213
|
-
lines: { start: fn.startLine, end: fn.endLine },
|
|
214
|
-
branches: this.estimateBranches(fn.complexity),
|
|
215
|
-
suggestedTests,
|
|
216
|
-
context: {
|
|
217
|
-
parameters: fn.parameters,
|
|
218
|
-
returnType: fn.returnType,
|
|
219
|
-
isAsync: fn.isAsync,
|
|
220
|
-
},
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Create a testable pattern for a class
|
|
226
|
-
*/
|
|
227
|
-
private createClassPattern(cls: ClassInfo): TestablePattern {
|
|
228
|
-
const totalComplexity = cls.methods.reduce((sum, m) => sum + m.complexity, 0);
|
|
229
|
-
const suggestedTests = this.suggestTestsForClass(cls);
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
type: 'class',
|
|
233
|
-
name: cls.name,
|
|
234
|
-
complexity: totalComplexity,
|
|
235
|
-
lines: { start: cls.startLine, end: cls.endLine },
|
|
236
|
-
branches: this.estimateBranches(totalComplexity),
|
|
237
|
-
suggestedTests,
|
|
238
|
-
context: {
|
|
239
|
-
dependencies: cls.properties
|
|
240
|
-
.filter((p) => !p.isPrivate)
|
|
241
|
-
.map((p) => p.name),
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Create a testable pattern for a class method
|
|
248
|
-
*/
|
|
249
|
-
private createMethodPattern(className: string, method: FunctionInfo): TestablePattern {
|
|
250
|
-
const suggestedTests = this.suggestTestsForMethod(className, method);
|
|
251
|
-
|
|
252
|
-
return {
|
|
253
|
-
type: 'method',
|
|
254
|
-
name: `${className}.${method.name}`,
|
|
255
|
-
complexity: method.complexity,
|
|
256
|
-
lines: { start: method.startLine, end: method.endLine },
|
|
257
|
-
branches: this.estimateBranches(method.complexity),
|
|
258
|
-
suggestedTests,
|
|
259
|
-
context: {
|
|
260
|
-
parameters: method.parameters,
|
|
261
|
-
returnType: method.returnType,
|
|
262
|
-
isAsync: method.isAsync,
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Suggest tests for a function based on its signature and complexity
|
|
269
|
-
*/
|
|
270
|
-
private suggestTestsForFunction(fn: FunctionInfo): SuggestedTest[] {
|
|
271
|
-
const tests: SuggestedTest[] = [];
|
|
272
|
-
|
|
273
|
-
// Happy path test
|
|
274
|
-
tests.push({
|
|
275
|
-
description: `handles valid input correctly`,
|
|
276
|
-
type: 'happy-path',
|
|
277
|
-
priority: 'high',
|
|
278
|
-
testCode: this.generateHappyPathTest(fn.name, fn.parameters, fn.isAsync),
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// Parameter validation tests
|
|
282
|
-
for (const param of fn.parameters) {
|
|
283
|
-
if (!param.optional) {
|
|
284
|
-
tests.push({
|
|
285
|
-
description: `handles missing ${param.name} parameter`,
|
|
286
|
-
type: 'error-handling',
|
|
287
|
-
priority: 'high',
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Type-specific tests
|
|
292
|
-
if (param.type?.includes('string')) {
|
|
293
|
-
tests.push({
|
|
294
|
-
description: `handles empty string for ${param.name}`,
|
|
295
|
-
type: 'boundary',
|
|
296
|
-
priority: 'medium',
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (param.type?.includes('number')) {
|
|
301
|
-
tests.push({
|
|
302
|
-
description: `handles zero value for ${param.name}`,
|
|
303
|
-
type: 'boundary',
|
|
304
|
-
priority: 'medium',
|
|
305
|
-
});
|
|
306
|
-
tests.push({
|
|
307
|
-
description: `handles negative value for ${param.name}`,
|
|
308
|
-
type: 'edge-case',
|
|
309
|
-
priority: 'medium',
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (param.type?.includes('[]') || param.type?.includes('Array')) {
|
|
314
|
-
tests.push({
|
|
315
|
-
description: `handles empty array for ${param.name}`,
|
|
316
|
-
type: 'boundary',
|
|
317
|
-
priority: 'medium',
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Async-specific tests
|
|
323
|
-
if (fn.isAsync) {
|
|
324
|
-
tests.push({
|
|
325
|
-
description: `handles async rejection`,
|
|
326
|
-
type: 'error-handling',
|
|
327
|
-
priority: 'high',
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Complexity-based tests
|
|
332
|
-
if (fn.complexity > 5) {
|
|
333
|
-
tests.push({
|
|
334
|
-
description: `handles complex branching logic`,
|
|
335
|
-
type: 'edge-case',
|
|
336
|
-
priority: 'medium',
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return tests;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Suggest tests for a class
|
|
345
|
-
*/
|
|
346
|
-
private suggestTestsForClass(cls: ClassInfo): SuggestedTest[] {
|
|
347
|
-
const tests: SuggestedTest[] = [];
|
|
348
|
-
|
|
349
|
-
// Constructor test
|
|
350
|
-
if (cls.hasConstructor) {
|
|
351
|
-
tests.push({
|
|
352
|
-
description: `instantiates correctly`,
|
|
353
|
-
type: 'happy-path',
|
|
354
|
-
priority: 'high',
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Public methods coverage
|
|
359
|
-
const publicMethods = cls.methods.filter(
|
|
360
|
-
(m) => !m.name.startsWith('_') && !m.name.startsWith('#')
|
|
361
|
-
);
|
|
362
|
-
if (publicMethods.length > 0) {
|
|
363
|
-
tests.push({
|
|
364
|
-
description: `all public methods are callable`,
|
|
365
|
-
type: 'happy-path',
|
|
366
|
-
priority: 'high',
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// State management test
|
|
371
|
-
if (cls.properties.some((p) => !p.isReadonly)) {
|
|
372
|
-
tests.push({
|
|
373
|
-
description: `maintains correct state after operations`,
|
|
374
|
-
type: 'edge-case',
|
|
375
|
-
priority: 'medium',
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return tests;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Suggest tests for a class method
|
|
384
|
-
*/
|
|
385
|
-
private suggestTestsForMethod(_className: string, method: FunctionInfo): SuggestedTest[] {
|
|
386
|
-
// Reuse function test suggestions with method-specific context
|
|
387
|
-
const tests = this.suggestTestsForFunction(method);
|
|
388
|
-
|
|
389
|
-
// Add method-specific tests
|
|
390
|
-
tests.push({
|
|
391
|
-
description: `correctly modifies instance state`,
|
|
392
|
-
type: 'edge-case',
|
|
393
|
-
priority: 'medium',
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
return tests;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Generate a happy path test code snippet
|
|
401
|
-
*/
|
|
402
|
-
private generateHappyPathTest(
|
|
403
|
-
fnName: string,
|
|
404
|
-
params: ParameterInfo[],
|
|
405
|
-
isAsync: boolean
|
|
406
|
-
): string {
|
|
407
|
-
const paramList = params.map((p) => this.generateMockValue(p)).join(', ');
|
|
408
|
-
const call = `${fnName}(${paramList})`;
|
|
409
|
-
const assertion = isAsync ? `await ${call}` : call;
|
|
410
|
-
|
|
411
|
-
return `it('should handle valid input correctly', ${isAsync ? 'async ' : ''}() => {
|
|
412
|
-
const result = ${assertion};
|
|
413
|
-
expect(result).toBeDefined();
|
|
414
|
-
});`;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Generate a mock value for a parameter based on its type
|
|
419
|
-
*/
|
|
420
|
-
private generateMockValue(param: ParameterInfo): string {
|
|
421
|
-
if (param.defaultValue) {
|
|
422
|
-
return param.defaultValue;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const type = param.type?.toLowerCase() || 'unknown';
|
|
426
|
-
|
|
427
|
-
if (type.includes('string')) return `'test-${param.name}'`;
|
|
428
|
-
if (type.includes('number')) return '42';
|
|
429
|
-
if (type.includes('boolean')) return 'true';
|
|
430
|
-
if (type.includes('[]') || type.includes('array')) return '[]';
|
|
431
|
-
if (type.includes('object') || type.includes('{')) return '{}';
|
|
432
|
-
if (type.includes('function')) return '() => {}';
|
|
433
|
-
if (type.includes('promise')) return 'Promise.resolve()';
|
|
434
|
-
if (type.includes('date')) return 'new Date()';
|
|
435
|
-
if (type.includes('null')) return 'null';
|
|
436
|
-
if (type.includes('undefined')) return 'undefined';
|
|
437
|
-
|
|
438
|
-
return `mock${param.name.charAt(0).toUpperCase() + param.name.slice(1)}`;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Estimate number of branches from cyclomatic complexity
|
|
443
|
-
*/
|
|
444
|
-
private estimateBranches(complexity: number): number {
|
|
445
|
-
// Branches = complexity - 1 (assuming one path is the default)
|
|
446
|
-
return Math.max(0, complexity - 1);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Find patterns matching the given context
|
|
451
|
-
*/
|
|
452
|
-
async findMatchingPatterns(
|
|
453
|
-
context: PatternSearchContext
|
|
454
|
-
): Promise<Result<PatternMatch[], Error>> {
|
|
455
|
-
try {
|
|
456
|
-
const matches: PatternMatch[] = [];
|
|
457
|
-
|
|
458
|
-
// Strategy 1: Semantic search if enabled and query provided
|
|
459
|
-
if (this.config.enableVectorSearch && context.semanticQuery) {
|
|
460
|
-
const semanticMatches = await this.semanticSearch(context.semanticQuery);
|
|
461
|
-
matches.push(...semanticMatches);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Strategy 2: Tag-based matching
|
|
465
|
-
if (context.tags && context.tags.length > 0) {
|
|
466
|
-
const tagMatches = await this.matchByTags(context.tags);
|
|
467
|
-
this.mergeMatches(matches, tagMatches);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Strategy 3: File type and framework matching
|
|
471
|
-
if (context.fileType || context.framework || context.testType) {
|
|
472
|
-
const metadataMatches = await this.matchByMetadata(context);
|
|
473
|
-
this.mergeMatches(matches, metadataMatches);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Strategy 4: Code structure analysis
|
|
477
|
-
if (context.sourceCode) {
|
|
478
|
-
const structureMatches = await this.matchByStructure(context.sourceCode);
|
|
479
|
-
this.mergeMatches(matches, structureMatches);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// Filter by minimum score and sort by relevance
|
|
483
|
-
const filteredMatches = matches
|
|
484
|
-
.filter((m) => m.score >= this.config.minMatchScore)
|
|
485
|
-
.sort((a, b) => b.score - a.score)
|
|
486
|
-
.slice(0, this.config.maxPatterns);
|
|
487
|
-
|
|
488
|
-
return ok(filteredMatches);
|
|
489
|
-
} catch (error) {
|
|
490
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* Apply a pattern to generate code
|
|
496
|
-
*/
|
|
497
|
-
async applyPattern(
|
|
498
|
-
patternId: string,
|
|
499
|
-
targetCode: string
|
|
500
|
-
): Promise<Result<AppliedPattern, Error>> {
|
|
501
|
-
try {
|
|
502
|
-
const pattern = await this.getPattern(patternId);
|
|
503
|
-
if (!pattern) {
|
|
504
|
-
return err(new Error(`Pattern not found: ${patternId}`));
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Analyze target code structure
|
|
508
|
-
const codeAnalysis = this.analyzeCodeStructure(targetCode);
|
|
509
|
-
|
|
510
|
-
// Apply pattern transformations
|
|
511
|
-
const modifications: PatternModification[] = [];
|
|
512
|
-
let generatedCode = pattern.structure;
|
|
513
|
-
|
|
514
|
-
// Replace placeholders in pattern with actual code elements
|
|
515
|
-
const placeholders = this.extractPlaceholders(pattern.structure);
|
|
516
|
-
for (const placeholder of placeholders) {
|
|
517
|
-
const replacement = this.resolvePlaceholder(placeholder, codeAnalysis);
|
|
518
|
-
if (replacement) {
|
|
519
|
-
generatedCode = generatedCode.replace(
|
|
520
|
-
new RegExp(`\\{\\{${placeholder}\\}\\}`, 'g'),
|
|
521
|
-
replacement
|
|
522
|
-
);
|
|
523
|
-
modifications.push({
|
|
524
|
-
location: placeholder,
|
|
525
|
-
original: `{{${placeholder}}}`,
|
|
526
|
-
replacement,
|
|
527
|
-
reason: `Resolved from code analysis`,
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Calculate confidence based on how well the pattern matched
|
|
533
|
-
const confidence = this.calculateApplicationConfidence(
|
|
534
|
-
pattern,
|
|
535
|
-
codeAnalysis,
|
|
536
|
-
modifications
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
// Update pattern usage statistics
|
|
540
|
-
await this.recordPatternUsage(patternId);
|
|
541
|
-
|
|
542
|
-
return ok({
|
|
543
|
-
patternId,
|
|
544
|
-
generatedCode,
|
|
545
|
-
modifications,
|
|
546
|
-
confidence,
|
|
547
|
-
});
|
|
548
|
-
} catch (error) {
|
|
549
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Record a new pattern
|
|
555
|
-
*/
|
|
556
|
-
async recordPattern(definition: PatternDefinition): Promise<Result<Pattern, Error>> {
|
|
557
|
-
try {
|
|
558
|
-
const pattern: Pattern = {
|
|
559
|
-
id: uuidv4(),
|
|
560
|
-
name: definition.name,
|
|
561
|
-
structure: definition.structure,
|
|
562
|
-
examples: definition.examples?.length ?? 0,
|
|
563
|
-
applicability: 0.5, // Start with neutral applicability
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
// Store pattern in memory
|
|
567
|
-
const patternKey = `${this.config.patternNamespace}:${pattern.id}`;
|
|
568
|
-
await this.memory.set(patternKey, {
|
|
569
|
-
...pattern,
|
|
570
|
-
description: definition.description,
|
|
571
|
-
tags: definition.tags,
|
|
572
|
-
testType: definition.testType,
|
|
573
|
-
framework: definition.framework,
|
|
574
|
-
examples: definition.examples,
|
|
575
|
-
createdAt: new Date().toISOString(),
|
|
576
|
-
usageCount: 0,
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
// Store vector embedding for semantic search if enabled
|
|
580
|
-
if (this.config.enableVectorSearch) {
|
|
581
|
-
const embedding = await this.generatePatternEmbedding(definition);
|
|
582
|
-
await this.memory.storeVector(patternKey, embedding, {
|
|
583
|
-
patternId: pattern.id,
|
|
584
|
-
name: pattern.name,
|
|
585
|
-
tags: definition.tags,
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// Add to local cache
|
|
590
|
-
this.patternCache.set(pattern.id, pattern);
|
|
591
|
-
|
|
592
|
-
return ok(pattern);
|
|
593
|
-
} catch (error) {
|
|
594
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Learn patterns from existing test files
|
|
600
|
-
*/
|
|
601
|
-
async learnPatterns(request: LearnPatternsRequest): Promise<Result<LearnedPatterns, Error>> {
|
|
602
|
-
try {
|
|
603
|
-
const { testFiles, depth } = request;
|
|
604
|
-
const patterns: Pattern[] = [];
|
|
605
|
-
|
|
606
|
-
for (const file of testFiles) {
|
|
607
|
-
const filePatterns = await this.extractPatternsFromFile(file, depth);
|
|
608
|
-
patterns.push(...filePatterns);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Deduplicate similar patterns
|
|
612
|
-
const uniquePatterns = this.deduplicatePatterns(patterns);
|
|
613
|
-
|
|
614
|
-
// Store learned patterns
|
|
615
|
-
for (const pattern of uniquePatterns) {
|
|
616
|
-
await this.recordPattern({
|
|
617
|
-
name: pattern.name,
|
|
618
|
-
structure: pattern.structure,
|
|
619
|
-
tags: ['learned', 'auto-extracted'],
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// Calculate overall confidence based on pattern consistency
|
|
624
|
-
const confidence = this.calculateLearningConfidence(uniquePatterns);
|
|
625
|
-
|
|
626
|
-
return ok({
|
|
627
|
-
patterns: uniquePatterns,
|
|
628
|
-
confidence,
|
|
629
|
-
});
|
|
630
|
-
} catch (error) {
|
|
631
|
-
return err(error instanceof Error ? error : new Error(String(error)));
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Get a pattern by ID
|
|
637
|
-
*/
|
|
638
|
-
async getPattern(patternId: string): Promise<Pattern | undefined> {
|
|
639
|
-
// Check cache first
|
|
640
|
-
if (this.patternCache.has(patternId)) {
|
|
641
|
-
return this.patternCache.get(patternId);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Load from memory
|
|
645
|
-
const patternKey = `${this.config.patternNamespace}:${patternId}`;
|
|
646
|
-
const stored = await this.memory.get<Pattern & { usageCount: number }>(patternKey);
|
|
647
|
-
|
|
648
|
-
if (stored) {
|
|
649
|
-
const pattern: Pattern = {
|
|
650
|
-
id: stored.id,
|
|
651
|
-
name: stored.name,
|
|
652
|
-
structure: stored.structure,
|
|
653
|
-
examples: stored.examples,
|
|
654
|
-
applicability: stored.applicability,
|
|
655
|
-
};
|
|
656
|
-
this.patternCache.set(patternId, pattern);
|
|
657
|
-
return pattern;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
return undefined;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* List patterns with optional filtering
|
|
665
|
-
*/
|
|
666
|
-
async listPatterns(filter?: PatternFilter): Promise<Pattern[]> {
|
|
667
|
-
const patterns: Pattern[] = [];
|
|
668
|
-
const limit = filter?.limit ?? this.config.maxPatterns;
|
|
669
|
-
|
|
670
|
-
// Search for patterns in memory
|
|
671
|
-
const keys = await this.memory.search(`${this.config.patternNamespace}:*`, limit * 2);
|
|
672
|
-
|
|
673
|
-
for (const key of keys) {
|
|
674
|
-
const stored = await this.memory.get<Pattern & {
|
|
675
|
-
testType?: string;
|
|
676
|
-
framework?: string;
|
|
677
|
-
tags?: string[];
|
|
678
|
-
}>(key);
|
|
679
|
-
|
|
680
|
-
if (stored) {
|
|
681
|
-
// Apply filters
|
|
682
|
-
if (filter?.testType && stored.testType !== filter.testType) continue;
|
|
683
|
-
if (filter?.framework && stored.framework !== filter.framework) continue;
|
|
684
|
-
if (filter?.minApplicability && stored.applicability < filter.minApplicability) continue;
|
|
685
|
-
if (filter?.tags && filter.tags.length > 0) {
|
|
686
|
-
const hasTag = filter.tags.some((t) => stored.tags?.includes(t));
|
|
687
|
-
if (!hasTag) continue;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
patterns.push({
|
|
691
|
-
id: stored.id,
|
|
692
|
-
name: stored.name,
|
|
693
|
-
structure: stored.structure,
|
|
694
|
-
examples: stored.examples,
|
|
695
|
-
applicability: stored.applicability,
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
if (patterns.length >= limit) break;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
return patterns.sort((a, b) => b.applicability - a.applicability);
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// ============================================================================
|
|
706
|
-
// Private Helper Methods
|
|
707
|
-
// ============================================================================
|
|
708
|
-
|
|
709
|
-
private async semanticSearch(query: string): Promise<PatternMatch[]> {
|
|
710
|
-
// Generate embedding for query and search using NomicEmbedder
|
|
711
|
-
const queryEmbedding = await this.generateQueryEmbedding(query);
|
|
712
|
-
const results: VectorSearchResult[] = await this.memory.vectorSearch(
|
|
713
|
-
queryEmbedding,
|
|
714
|
-
10
|
|
715
|
-
);
|
|
716
|
-
|
|
717
|
-
const matches: PatternMatch[] = [];
|
|
718
|
-
for (const result of results) {
|
|
719
|
-
const pattern = await this.getPattern(
|
|
720
|
-
(result.metadata as { patternId: string })?.patternId
|
|
721
|
-
);
|
|
722
|
-
if (pattern) {
|
|
723
|
-
matches.push({
|
|
724
|
-
pattern,
|
|
725
|
-
score: result.score,
|
|
726
|
-
matchReason: 'Semantic similarity to query',
|
|
727
|
-
suggestedApplication: `Apply ${pattern.name} pattern to generate tests`,
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
return matches;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
private async matchByTags(tags: string[]): Promise<PatternMatch[]> {
|
|
736
|
-
const matches: PatternMatch[] = [];
|
|
737
|
-
const patterns = await this.listPatterns({ tags });
|
|
738
|
-
|
|
739
|
-
for (const pattern of patterns) {
|
|
740
|
-
matches.push({
|
|
741
|
-
pattern,
|
|
742
|
-
score: 0.7, // Tag matching gives moderate score
|
|
743
|
-
matchReason: `Pattern tags match: ${tags.join(', ')}`,
|
|
744
|
-
suggestedApplication: `Apply ${pattern.name} pattern based on tag match`,
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
return matches;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
private async matchByMetadata(context: PatternSearchContext): Promise<PatternMatch[]> {
|
|
752
|
-
const matches: PatternMatch[] = [];
|
|
753
|
-
const patterns = await this.listPatterns({
|
|
754
|
-
testType: context.testType,
|
|
755
|
-
framework: context.framework,
|
|
756
|
-
});
|
|
757
|
-
|
|
758
|
-
for (const pattern of patterns) {
|
|
759
|
-
matches.push({
|
|
760
|
-
pattern,
|
|
761
|
-
score: 0.6, // Metadata matching gives moderate score
|
|
762
|
-
matchReason: `Pattern matches ${context.testType || ''} ${context.framework || ''}`.trim(),
|
|
763
|
-
suggestedApplication: `Apply ${pattern.name} pattern for ${context.testType || 'test'} generation`,
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
return matches;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
private async matchByStructure(sourceCode: string): Promise<PatternMatch[]> {
|
|
771
|
-
// Analyze code structure using TypeScript AST and find matching patterns
|
|
772
|
-
const analysis = this.analyzeCodeStructure(sourceCode);
|
|
773
|
-
const matches: PatternMatch[] = [];
|
|
774
|
-
|
|
775
|
-
// Look for patterns that match detected constructs
|
|
776
|
-
const allPatterns = await this.listPatterns();
|
|
777
|
-
for (const pattern of allPatterns) {
|
|
778
|
-
const structureScore = this.calculateStructureMatch(pattern, analysis);
|
|
779
|
-
if (structureScore > 0) {
|
|
780
|
-
matches.push({
|
|
781
|
-
pattern,
|
|
782
|
-
score: structureScore,
|
|
783
|
-
matchReason: `Pattern structure matches code constructs`,
|
|
784
|
-
suggestedApplication: `Apply ${pattern.name} based on code structure analysis`,
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
return matches;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
private mergeMatches(target: PatternMatch[], source: PatternMatch[]): void {
|
|
793
|
-
for (const match of source) {
|
|
794
|
-
const existing = target.find((m) => m.pattern.id === match.pattern.id);
|
|
795
|
-
if (existing) {
|
|
796
|
-
// Combine scores
|
|
797
|
-
existing.score = Math.min(1, existing.score + match.score * 0.5);
|
|
798
|
-
existing.matchReason += `, ${match.matchReason}`;
|
|
799
|
-
} else {
|
|
800
|
-
target.push(match);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
private analyzeCodeStructure(code: string): CodeAnalysis {
|
|
806
|
-
// Use real TypeScript AST parsing for accurate analysis
|
|
807
|
-
const parser = new TypeScriptASTParser();
|
|
808
|
-
const sourceFile = parser.parseSource(code);
|
|
809
|
-
const functions = parser.extractFunctions(sourceFile);
|
|
810
|
-
const classes = parser.extractClasses(sourceFile);
|
|
811
|
-
|
|
812
|
-
// Calculate total complexity from all functions and methods
|
|
813
|
-
let totalComplexity = functions.reduce((sum, fn) => sum + fn.complexity, 0);
|
|
814
|
-
for (const cls of classes) {
|
|
815
|
-
totalComplexity += cls.methods.reduce((sum, m) => sum + m.complexity, 0);
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
return {
|
|
819
|
-
hasClasses: classes.length > 0,
|
|
820
|
-
hasFunctions: functions.length > 0,
|
|
821
|
-
hasAsyncCode: functions.some((f) => f.isAsync) ||
|
|
822
|
-
classes.some((c) => c.methods.some((m) => m.isAsync)),
|
|
823
|
-
hasExports: functions.some((f) => f.isExported) ||
|
|
824
|
-
classes.some((c) => c.isExported),
|
|
825
|
-
imports: this.extractImports(code),
|
|
826
|
-
identifiers: this.extractIdentifiers(code),
|
|
827
|
-
complexity: totalComplexity || this.estimateComplexity(code),
|
|
828
|
-
functions,
|
|
829
|
-
classes,
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
private extractImports(code: string): string[] {
|
|
834
|
-
const importRegex = /import\s+(?:\{[^}]+\}|\*\s+as\s+\w+|\w+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
835
|
-
const imports: string[] = [];
|
|
836
|
-
let match;
|
|
837
|
-
while ((match = importRegex.exec(code)) !== null) {
|
|
838
|
-
imports.push(match[1]);
|
|
839
|
-
}
|
|
840
|
-
return imports;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
private extractIdentifiers(code: string): string[] {
|
|
844
|
-
const identifierRegex = /(?:class|function|const|let|var)\s+(\w+)/g;
|
|
845
|
-
const identifiers: string[] = [];
|
|
846
|
-
let match;
|
|
847
|
-
while ((match = identifierRegex.exec(code)) !== null) {
|
|
848
|
-
identifiers.push(match[1]);
|
|
849
|
-
}
|
|
850
|
-
return identifiers;
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
private estimateComplexity(code: string): number {
|
|
854
|
-
// Simple complexity estimation based on control flow statements
|
|
855
|
-
const controlFlowPatterns = [
|
|
856
|
-
/if\s*\(/g,
|
|
857
|
-
/else\s*{/g,
|
|
858
|
-
/for\s*\(/g,
|
|
859
|
-
/while\s*\(/g,
|
|
860
|
-
/switch\s*\(/g,
|
|
861
|
-
/\?\s*:/g, // ternary
|
|
862
|
-
];
|
|
863
|
-
|
|
864
|
-
let complexity = 1;
|
|
865
|
-
for (const pattern of controlFlowPatterns) {
|
|
866
|
-
const matches = code.match(pattern);
|
|
867
|
-
complexity += matches ? matches.length : 0;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
return complexity;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
private extractPlaceholders(structure: string): string[] {
|
|
874
|
-
const placeholderRegex = /\{\{(\w+)\}\}/g;
|
|
875
|
-
const placeholders: string[] = [];
|
|
876
|
-
let match;
|
|
877
|
-
while ((match = placeholderRegex.exec(structure)) !== null) {
|
|
878
|
-
placeholders.push(match[1]);
|
|
879
|
-
}
|
|
880
|
-
return placeholders;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
private resolvePlaceholder(placeholder: string, analysis: CodeAnalysis): string | null {
|
|
884
|
-
// Resolve placeholders based on code analysis results
|
|
885
|
-
switch (placeholder.toLowerCase()) {
|
|
886
|
-
case 'classname':
|
|
887
|
-
case 'modulename':
|
|
888
|
-
return analysis.identifiers[0] || 'Module';
|
|
889
|
-
case 'functionname':
|
|
890
|
-
return analysis.identifiers.find((id) => /^[a-z]/.test(id)) || 'func';
|
|
891
|
-
case 'imports':
|
|
892
|
-
return analysis.imports.map((i) => `import '${i}'`).join('\n');
|
|
893
|
-
default:
|
|
894
|
-
return null;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
private calculateApplicationConfidence(
|
|
899
|
-
pattern: Pattern,
|
|
900
|
-
analysis: CodeAnalysis,
|
|
901
|
-
modifications: PatternModification[]
|
|
902
|
-
): number {
|
|
903
|
-
// Base confidence from pattern applicability
|
|
904
|
-
let confidence = pattern.applicability;
|
|
905
|
-
|
|
906
|
-
// Adjust based on how many placeholders were resolved
|
|
907
|
-
const placeholders = this.extractPlaceholders(pattern.structure);
|
|
908
|
-
const resolvedRatio = modifications.length / Math.max(placeholders.length, 1);
|
|
909
|
-
confidence = confidence * 0.5 + resolvedRatio * 0.5;
|
|
910
|
-
|
|
911
|
-
// Adjust based on code complexity match
|
|
912
|
-
if (analysis.complexity > 10) {
|
|
913
|
-
confidence *= 0.9; // Slightly lower confidence for complex code
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
return Math.min(1, Math.max(0, confidence));
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
private calculateStructureMatch(pattern: Pattern, analysis: CodeAnalysis): number {
|
|
920
|
-
// Calculate how well pattern structure matches code using AST analysis
|
|
921
|
-
let score = 0;
|
|
922
|
-
|
|
923
|
-
// Check for structural similarities
|
|
924
|
-
if (analysis.hasClasses && pattern.structure.includes('class')) score += 0.3;
|
|
925
|
-
if (analysis.hasFunctions && pattern.structure.includes('function')) score += 0.3;
|
|
926
|
-
if (analysis.hasAsyncCode && pattern.structure.includes('async')) score += 0.2;
|
|
927
|
-
if (analysis.hasExports && pattern.structure.includes('export')) score += 0.2;
|
|
928
|
-
|
|
929
|
-
return Math.min(1, score);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
private async recordPatternUsage(patternId: string): Promise<void> {
|
|
933
|
-
const patternKey = `${this.config.patternNamespace}:${patternId}`;
|
|
934
|
-
const stored = await this.memory.get<Pattern & { usageCount: number }>(patternKey);
|
|
935
|
-
|
|
936
|
-
if (stored) {
|
|
937
|
-
const usageCount = (stored.usageCount || 0) + 1;
|
|
938
|
-
// Increase applicability score based on usage
|
|
939
|
-
const newApplicability = Math.min(1, stored.applicability + 0.01);
|
|
940
|
-
|
|
941
|
-
await this.memory.set(patternKey, {
|
|
942
|
-
...stored,
|
|
943
|
-
usageCount,
|
|
944
|
-
applicability: newApplicability,
|
|
945
|
-
lastUsedAt: new Date().toISOString(),
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
// Update cache
|
|
949
|
-
if (this.patternCache.has(patternId)) {
|
|
950
|
-
const cached = this.patternCache.get(patternId)!;
|
|
951
|
-
cached.applicability = newApplicability;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
private async extractPatternsFromFile(
|
|
957
|
-
file: string,
|
|
958
|
-
depth: 'shallow' | 'deep'
|
|
959
|
-
): Promise<Pattern[]> {
|
|
960
|
-
const patterns: Pattern[] = [];
|
|
961
|
-
|
|
962
|
-
try {
|
|
963
|
-
// Read the file content
|
|
964
|
-
let content: string;
|
|
965
|
-
try {
|
|
966
|
-
content = fs.readFileSync(file, 'utf-8');
|
|
967
|
-
} catch {
|
|
968
|
-
// File doesn't exist or can't be read, return empty
|
|
969
|
-
return patterns;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// Parse with TypeScript AST
|
|
973
|
-
const parser = new TypeScriptASTParser();
|
|
974
|
-
const sourceFile = parser.parseSource(content, path.basename(file));
|
|
975
|
-
|
|
976
|
-
// Extract test patterns from describe/it/test blocks
|
|
977
|
-
const testPatterns = this.extractTestBlockPatterns(sourceFile, content);
|
|
978
|
-
patterns.push(...testPatterns);
|
|
979
|
-
|
|
980
|
-
// Deep analysis extracts more detailed patterns
|
|
981
|
-
if (depth === 'deep') {
|
|
982
|
-
// Extract setup/teardown patterns
|
|
983
|
-
const setupPatterns = this.extractSetupTeardownPatterns(sourceFile, content);
|
|
984
|
-
patterns.push(...setupPatterns);
|
|
985
|
-
|
|
986
|
-
// Extract assertion patterns
|
|
987
|
-
const assertionPatterns = this.extractAssertionPatterns(content);
|
|
988
|
-
patterns.push(...assertionPatterns);
|
|
989
|
-
|
|
990
|
-
// Extract mocking patterns
|
|
991
|
-
const mockPatterns = this.extractMockingPatterns(content);
|
|
992
|
-
patterns.push(...mockPatterns);
|
|
993
|
-
}
|
|
994
|
-
} catch {
|
|
995
|
-
// If parsing fails, return a basic pattern
|
|
996
|
-
patterns.push({
|
|
997
|
-
id: uuidv4(),
|
|
998
|
-
name: `Basic pattern from ${path.basename(file)}`,
|
|
999
|
-
structure: `describe('{{moduleName}}', () => {\n it('should {{behavior}}', () => {\n // Test implementation\n });\n});`,
|
|
1000
|
-
examples: 1,
|
|
1001
|
-
applicability: 0.5,
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
return patterns;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/**
|
|
1009
|
-
* Extract test block patterns (describe/it/test)
|
|
1010
|
-
*/
|
|
1011
|
-
private extractTestBlockPatterns(
|
|
1012
|
-
_sourceFile: ts.SourceFile,
|
|
1013
|
-
content: string
|
|
1014
|
-
): Pattern[] {
|
|
1015
|
-
const patterns: Pattern[] = [];
|
|
1016
|
-
|
|
1017
|
-
// Find describe blocks with their nested structure
|
|
1018
|
-
const describeRegex = /describe\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?:function\s*\(\s*\)|(?:\(\s*\))?\s*=>)\s*\{/g;
|
|
1019
|
-
let match;
|
|
1020
|
-
|
|
1021
|
-
while ((match = describeRegex.exec(content)) !== null) {
|
|
1022
|
-
const startIndex = match.index;
|
|
1023
|
-
const blockContent = this.extractBlockContent(content, startIndex + match[0].length - 1);
|
|
1024
|
-
|
|
1025
|
-
if (blockContent) {
|
|
1026
|
-
// Analyze the structure of tests within this describe block
|
|
1027
|
-
const itCount = (blockContent.match(/\bit\s*\(/g) || []).length;
|
|
1028
|
-
const testCount = (blockContent.match(/\btest\s*\(/g) || []).length;
|
|
1029
|
-
const hasBeforeEach = /beforeEach\s*\(/.test(blockContent);
|
|
1030
|
-
const hasAfterEach = /afterEach\s*\(/.test(blockContent);
|
|
1031
|
-
|
|
1032
|
-
// Create a structural pattern
|
|
1033
|
-
let structure = `describe('{{moduleName}}', () => {\n`;
|
|
1034
|
-
if (hasBeforeEach) structure += ` beforeEach(() => {\n // Setup\n });\n\n`;
|
|
1035
|
-
if (hasAfterEach) structure += ` afterEach(() => {\n // Teardown\n });\n\n`;
|
|
1036
|
-
|
|
1037
|
-
for (let i = 0; i < Math.max(itCount, testCount); i++) {
|
|
1038
|
-
structure += ` it('should {{behavior${i > 0 ? i + 1 : ''}}}', () => {\n // Test implementation\n });\n`;
|
|
1039
|
-
}
|
|
1040
|
-
structure += '});';
|
|
1041
|
-
|
|
1042
|
-
patterns.push({
|
|
1043
|
-
id: uuidv4(),
|
|
1044
|
-
name: `Test block pattern: ${match[1]}`,
|
|
1045
|
-
structure,
|
|
1046
|
-
examples: 1,
|
|
1047
|
-
applicability: 0.6,
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
return patterns;
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
/**
|
|
1056
|
-
* Extract setup/teardown patterns (beforeEach, afterEach, etc.)
|
|
1057
|
-
*/
|
|
1058
|
-
private extractSetupTeardownPatterns(
|
|
1059
|
-
_sourceFile: ts.SourceFile,
|
|
1060
|
-
content: string
|
|
1061
|
-
): Pattern[] {
|
|
1062
|
-
const patterns: Pattern[] = [];
|
|
1063
|
-
|
|
1064
|
-
// beforeEach pattern
|
|
1065
|
-
if (/beforeEach\s*\(/.test(content)) {
|
|
1066
|
-
const beforeEachMatch = content.match(/beforeEach\s*\(\s*(?:async\s*)?\(\s*\)\s*=>\s*\{([^}]*)\}/);
|
|
1067
|
-
if (beforeEachMatch) {
|
|
1068
|
-
patterns.push({
|
|
1069
|
-
id: uuidv4(),
|
|
1070
|
-
name: 'beforeEach setup pattern',
|
|
1071
|
-
structure: `beforeEach(async () => {\n {{setupCode}}\n});`,
|
|
1072
|
-
examples: 1,
|
|
1073
|
-
applicability: 0.7,
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
// afterEach pattern
|
|
1079
|
-
if (/afterEach\s*\(/.test(content)) {
|
|
1080
|
-
patterns.push({
|
|
1081
|
-
id: uuidv4(),
|
|
1082
|
-
name: 'afterEach teardown pattern',
|
|
1083
|
-
structure: `afterEach(async () => {\n {{teardownCode}}\n});`,
|
|
1084
|
-
examples: 1,
|
|
1085
|
-
applicability: 0.7,
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// beforeAll pattern
|
|
1090
|
-
if (/beforeAll\s*\(/.test(content)) {
|
|
1091
|
-
patterns.push({
|
|
1092
|
-
id: uuidv4(),
|
|
1093
|
-
name: 'beforeAll setup pattern',
|
|
1094
|
-
structure: `beforeAll(async () => {\n {{setupCode}}\n});`,
|
|
1095
|
-
examples: 1,
|
|
1096
|
-
applicability: 0.6,
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
return patterns;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
/**
|
|
1104
|
-
* Extract assertion patterns from test code
|
|
1105
|
-
*/
|
|
1106
|
-
private extractAssertionPatterns(content: string): Pattern[] {
|
|
1107
|
-
const patterns: Pattern[] = [];
|
|
1108
|
-
const assertionTypes = new Set<string>();
|
|
1109
|
-
|
|
1110
|
-
// Detect assertion styles
|
|
1111
|
-
if (/expect\([^)]+\)\.toBe\(/.test(content)) assertionTypes.add('toBe');
|
|
1112
|
-
if (/expect\([^)]+\)\.toEqual\(/.test(content)) assertionTypes.add('toEqual');
|
|
1113
|
-
if (/expect\([^)]+\)\.toThrow\(/.test(content)) assertionTypes.add('toThrow');
|
|
1114
|
-
if (/expect\([^)]+\)\.toHaveBeenCalled/.test(content)) assertionTypes.add('toHaveBeenCalled');
|
|
1115
|
-
if (/expect\([^)]+\)\.resolves/.test(content)) assertionTypes.add('resolves');
|
|
1116
|
-
if (/expect\([^)]+\)\.rejects/.test(content)) assertionTypes.add('rejects');
|
|
1117
|
-
|
|
1118
|
-
if (assertionTypes.size > 0) {
|
|
1119
|
-
const assertionStructures = Array.from(assertionTypes).map((type) => {
|
|
1120
|
-
switch (type) {
|
|
1121
|
-
case 'toBe':
|
|
1122
|
-
return 'expect({{actual}}).toBe({{expected}})';
|
|
1123
|
-
case 'toEqual':
|
|
1124
|
-
return 'expect({{actual}}).toEqual({{expected}})';
|
|
1125
|
-
case 'toThrow':
|
|
1126
|
-
return 'expect(() => {{call}}).toThrow({{error}})';
|
|
1127
|
-
case 'toHaveBeenCalled':
|
|
1128
|
-
return 'expect({{mock}}).toHaveBeenCalledWith({{args}})';
|
|
1129
|
-
case 'resolves':
|
|
1130
|
-
return 'await expect({{promise}}).resolves.toEqual({{expected}})';
|
|
1131
|
-
case 'rejects':
|
|
1132
|
-
return 'await expect({{promise}}).rejects.toThrow({{error}})';
|
|
1133
|
-
default:
|
|
1134
|
-
return `expect({{actual}}).${type}({{expected}})`;
|
|
1135
|
-
}
|
|
1136
|
-
});
|
|
1137
|
-
|
|
1138
|
-
patterns.push({
|
|
1139
|
-
id: uuidv4(),
|
|
1140
|
-
name: 'Assertion patterns',
|
|
1141
|
-
structure: assertionStructures.join('\n'),
|
|
1142
|
-
examples: assertionTypes.size,
|
|
1143
|
-
applicability: 0.8,
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
return patterns;
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
/**
|
|
1151
|
-
* Extract mocking patterns from test code
|
|
1152
|
-
*/
|
|
1153
|
-
private extractMockingPatterns(content: string): Pattern[] {
|
|
1154
|
-
const patterns: Pattern[] = [];
|
|
1155
|
-
|
|
1156
|
-
// jest.mock pattern
|
|
1157
|
-
if (/jest\.mock\(/.test(content)) {
|
|
1158
|
-
patterns.push({
|
|
1159
|
-
id: uuidv4(),
|
|
1160
|
-
name: 'Jest module mock pattern',
|
|
1161
|
-
structure: `jest.mock('{{modulePath}}', () => ({\n {{mockImplementation}}\n}));`,
|
|
1162
|
-
examples: 1,
|
|
1163
|
-
applicability: 0.7,
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
// jest.fn pattern
|
|
1168
|
-
if (/jest\.fn\(/.test(content)) {
|
|
1169
|
-
patterns.push({
|
|
1170
|
-
id: uuidv4(),
|
|
1171
|
-
name: 'Jest function mock pattern',
|
|
1172
|
-
structure: `const {{mockName}} = jest.fn().mockReturnValue({{returnValue}});`,
|
|
1173
|
-
examples: 1,
|
|
1174
|
-
applicability: 0.7,
|
|
1175
|
-
});
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
// vi.mock pattern (vitest)
|
|
1179
|
-
if (/vi\.mock\(/.test(content)) {
|
|
1180
|
-
patterns.push({
|
|
1181
|
-
id: uuidv4(),
|
|
1182
|
-
name: 'Vitest module mock pattern',
|
|
1183
|
-
structure: `vi.mock('{{modulePath}}', () => ({\n {{mockImplementation}}\n}));`,
|
|
1184
|
-
examples: 1,
|
|
1185
|
-
applicability: 0.7,
|
|
1186
|
-
});
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
// vi.fn pattern (vitest)
|
|
1190
|
-
if (/vi\.fn\(/.test(content)) {
|
|
1191
|
-
patterns.push({
|
|
1192
|
-
id: uuidv4(),
|
|
1193
|
-
name: 'Vitest function mock pattern',
|
|
1194
|
-
structure: `const {{mockName}} = vi.fn().mockReturnValue({{returnValue}});`,
|
|
1195
|
-
examples: 1,
|
|
1196
|
-
applicability: 0.7,
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
// spyOn pattern
|
|
1201
|
-
if (/(?:jest|vi)\.spyOn\(/.test(content)) {
|
|
1202
|
-
patterns.push({
|
|
1203
|
-
id: uuidv4(),
|
|
1204
|
-
name: 'SpyOn pattern',
|
|
1205
|
-
structure: `const spy = {{framework}}.spyOn({{object}}, '{{method}}').mockImplementation({{impl}});`,
|
|
1206
|
-
examples: 1,
|
|
1207
|
-
applicability: 0.6,
|
|
1208
|
-
});
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
return patterns;
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
/**
|
|
1215
|
-
* Extract a complete block of code starting from an opening brace
|
|
1216
|
-
*/
|
|
1217
|
-
private extractBlockContent(content: string, startIndex: number): string | null {
|
|
1218
|
-
let braceCount = 0;
|
|
1219
|
-
let endIndex = startIndex;
|
|
1220
|
-
let started = false;
|
|
1221
|
-
|
|
1222
|
-
for (let i = startIndex; i < content.length; i++) {
|
|
1223
|
-
const char = content[i];
|
|
1224
|
-
if (char === '{') {
|
|
1225
|
-
braceCount++;
|
|
1226
|
-
started = true;
|
|
1227
|
-
} else if (char === '}') {
|
|
1228
|
-
braceCount--;
|
|
1229
|
-
if (started && braceCount === 0) {
|
|
1230
|
-
endIndex = i;
|
|
1231
|
-
break;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
if (endIndex > startIndex) {
|
|
1237
|
-
return content.substring(startIndex, endIndex + 1);
|
|
1238
|
-
}
|
|
1239
|
-
return null;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
private deduplicatePatterns(patterns: Pattern[]): Pattern[] {
|
|
1243
|
-
const seen = new Map<string, Pattern>();
|
|
1244
|
-
|
|
1245
|
-
for (const pattern of patterns) {
|
|
1246
|
-
// Use structure hash as key for deduplication
|
|
1247
|
-
const structureKey = this.hashStructure(pattern.structure);
|
|
1248
|
-
if (!seen.has(structureKey)) {
|
|
1249
|
-
seen.set(structureKey, pattern);
|
|
1250
|
-
} else {
|
|
1251
|
-
// Merge examples count
|
|
1252
|
-
const existing = seen.get(structureKey)!;
|
|
1253
|
-
existing.examples += pattern.examples;
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
return Array.from(seen.values());
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
private hashStructure(structure: string): string {
|
|
1261
|
-
// Simple hash for structure comparison
|
|
1262
|
-
const normalized = structure.replace(/\s+/g, ' ').trim();
|
|
1263
|
-
let hash = 0;
|
|
1264
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
1265
|
-
const char = normalized.charCodeAt(i);
|
|
1266
|
-
hash = ((hash << 5) - hash) + char;
|
|
1267
|
-
hash = hash & hash;
|
|
1268
|
-
}
|
|
1269
|
-
return hash.toString(16);
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
private calculateLearningConfidence(patterns: Pattern[]): number {
|
|
1273
|
-
if (patterns.length === 0) return 0;
|
|
1274
|
-
|
|
1275
|
-
// Confidence based on:
|
|
1276
|
-
// 1. Number of patterns found
|
|
1277
|
-
// 2. Average examples per pattern
|
|
1278
|
-
// 3. Structural diversity
|
|
1279
|
-
|
|
1280
|
-
const avgExamples =
|
|
1281
|
-
patterns.reduce((sum, p) => sum + p.examples, 0) / patterns.length;
|
|
1282
|
-
const countFactor = Math.min(1, patterns.length / 10);
|
|
1283
|
-
const examplesFactor = Math.min(1, avgExamples / 5);
|
|
1284
|
-
|
|
1285
|
-
return countFactor * 0.5 + examplesFactor * 0.5;
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
/**
|
|
1289
|
-
* Generate embedding for a pattern definition
|
|
1290
|
-
* Uses NomicEmbedder for semantic embeddings (falls back to pseudo-embeddings if Ollama unavailable)
|
|
1291
|
-
*/
|
|
1292
|
-
private async generatePatternEmbedding(definition: PatternDefinition): Promise<number[]> {
|
|
1293
|
-
const text = this.formatPatternForEmbedding(definition);
|
|
1294
|
-
return this.embedder.embed(text);
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
/**
|
|
1298
|
-
* Generate embedding for a search query
|
|
1299
|
-
* Uses the same embedder as patterns for consistent similarity matching
|
|
1300
|
-
*/
|
|
1301
|
-
private async generateQueryEmbedding(query: string): Promise<number[]> {
|
|
1302
|
-
return this.embedder.embed(query);
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
/**
|
|
1306
|
-
* Format a pattern definition for embedding generation
|
|
1307
|
-
* Creates a semantic-rich text representation
|
|
1308
|
-
*/
|
|
1309
|
-
private formatPatternForEmbedding(definition: PatternDefinition): string {
|
|
1310
|
-
const parts = [
|
|
1311
|
-
`Pattern: ${definition.name}`,
|
|
1312
|
-
definition.description ? `Description: ${definition.description}` : '',
|
|
1313
|
-
`Structure: ${definition.structure}`,
|
|
1314
|
-
definition.tags?.length ? `Tags: ${definition.tags.join(', ')}` : '',
|
|
1315
|
-
definition.testType ? `Test type: ${definition.testType}` : '',
|
|
1316
|
-
definition.framework ? `Framework: ${definition.framework}` : '',
|
|
1317
|
-
].filter(Boolean);
|
|
1318
|
-
|
|
1319
|
-
return parts.join('\n');
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
/**
|
|
1324
|
-
* Code analysis result
|
|
1325
|
-
*/
|
|
1326
|
-
interface CodeAnalysis {
|
|
1327
|
-
hasClasses: boolean;
|
|
1328
|
-
hasFunctions: boolean;
|
|
1329
|
-
hasAsyncCode: boolean;
|
|
1330
|
-
hasExports: boolean;
|
|
1331
|
-
imports: string[];
|
|
1332
|
-
identifiers: string[];
|
|
1333
|
-
complexity: number;
|
|
1334
|
-
functions?: FunctionInfo[];
|
|
1335
|
-
classes?: ClassInfo[];
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
/**
|
|
1339
|
-
* Information about a function extracted from AST
|
|
1340
|
-
*/
|
|
1341
|
-
interface FunctionInfo {
|
|
1342
|
-
name: string;
|
|
1343
|
-
parameters: ParameterInfo[];
|
|
1344
|
-
returnType: string | undefined;
|
|
1345
|
-
isAsync: boolean;
|
|
1346
|
-
isExported: boolean;
|
|
1347
|
-
complexity: number;
|
|
1348
|
-
startLine: number;
|
|
1349
|
-
endLine: number;
|
|
1350
|
-
body?: string;
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
/**
|
|
1354
|
-
* Information about a class extracted from AST
|
|
1355
|
-
*/
|
|
1356
|
-
interface ClassInfo {
|
|
1357
|
-
name: string;
|
|
1358
|
-
methods: FunctionInfo[];
|
|
1359
|
-
properties: PropertyInfo[];
|
|
1360
|
-
isExported: boolean;
|
|
1361
|
-
hasConstructor: boolean;
|
|
1362
|
-
startLine: number;
|
|
1363
|
-
endLine: number;
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
/**
|
|
1367
|
-
* Information about a parameter
|
|
1368
|
-
*/
|
|
1369
|
-
interface ParameterInfo {
|
|
1370
|
-
name: string;
|
|
1371
|
-
type: string | undefined;
|
|
1372
|
-
optional: boolean;
|
|
1373
|
-
defaultValue: string | undefined;
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
/**
|
|
1377
|
-
* Information about a class property
|
|
1378
|
-
*/
|
|
1379
|
-
interface PropertyInfo {
|
|
1380
|
-
name: string;
|
|
1381
|
-
type: string | undefined;
|
|
1382
|
-
isPrivate: boolean;
|
|
1383
|
-
isReadonly: boolean;
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
/**
|
|
1387
|
-
* Testable pattern extracted from code analysis
|
|
1388
|
-
*/
|
|
1389
|
-
export interface TestablePattern {
|
|
1390
|
-
type: 'function' | 'class' | 'method' | 'module';
|
|
1391
|
-
name: string;
|
|
1392
|
-
complexity: number;
|
|
1393
|
-
lines: { start: number; end: number };
|
|
1394
|
-
branches: number;
|
|
1395
|
-
suggestedTests: SuggestedTest[];
|
|
1396
|
-
context: {
|
|
1397
|
-
parameters?: ParameterInfo[];
|
|
1398
|
-
returnType?: string;
|
|
1399
|
-
dependencies?: string[];
|
|
1400
|
-
isAsync?: boolean;
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
/**
|
|
1405
|
-
* Suggested test for a pattern
|
|
1406
|
-
*/
|
|
1407
|
-
interface SuggestedTest {
|
|
1408
|
-
description: string;
|
|
1409
|
-
type: 'happy-path' | 'edge-case' | 'error-handling' | 'boundary';
|
|
1410
|
-
priority: 'high' | 'medium' | 'low';
|
|
1411
|
-
testCode?: string;
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
/**
|
|
1415
|
-
* TypeScript AST Parser Helper
|
|
1416
|
-
* Provides utilities for parsing TypeScript files and extracting patterns
|
|
1417
|
-
*/
|
|
1418
|
-
class TypeScriptASTParser {
|
|
1419
|
-
private sourceFile: ts.SourceFile | null = null;
|
|
1420
|
-
private sourceCode: string = '';
|
|
1421
|
-
|
|
1422
|
-
/**
|
|
1423
|
-
* Parse a TypeScript file and return the source file AST
|
|
1424
|
-
*/
|
|
1425
|
-
parseFile(filePath: string, content?: string): ts.SourceFile {
|
|
1426
|
-
if (content) {
|
|
1427
|
-
this.sourceCode = content;
|
|
1428
|
-
} else {
|
|
1429
|
-
this.sourceCode = fs.readFileSync(filePath, 'utf-8');
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
this.sourceFile = ts.createSourceFile(
|
|
1433
|
-
path.basename(filePath),
|
|
1434
|
-
this.sourceCode,
|
|
1435
|
-
ts.ScriptTarget.Latest,
|
|
1436
|
-
true,
|
|
1437
|
-
ts.ScriptKind.TS
|
|
1438
|
-
);
|
|
1439
|
-
|
|
1440
|
-
return this.sourceFile;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
/**
|
|
1444
|
-
* Parse source code string directly
|
|
1445
|
-
*/
|
|
1446
|
-
parseSource(source: string, fileName: string = 'module.ts'): ts.SourceFile {
|
|
1447
|
-
this.sourceCode = source;
|
|
1448
|
-
this.sourceFile = ts.createSourceFile(
|
|
1449
|
-
fileName,
|
|
1450
|
-
source,
|
|
1451
|
-
ts.ScriptTarget.Latest,
|
|
1452
|
-
true,
|
|
1453
|
-
ts.ScriptKind.TS
|
|
1454
|
-
);
|
|
1455
|
-
return this.sourceFile;
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
/**
|
|
1459
|
-
* Extract all functions from the AST
|
|
1460
|
-
*/
|
|
1461
|
-
extractFunctions(sourceFile: ts.SourceFile): FunctionInfo[] {
|
|
1462
|
-
const functions: FunctionInfo[] = [];
|
|
1463
|
-
|
|
1464
|
-
const visit = (node: ts.Node): void => {
|
|
1465
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
1466
|
-
functions.push(this.extractFunctionInfo(node, sourceFile));
|
|
1467
|
-
} else if (ts.isVariableStatement(node)) {
|
|
1468
|
-
// Handle arrow functions assigned to variables
|
|
1469
|
-
for (const declaration of node.declarationList.declarations) {
|
|
1470
|
-
if (
|
|
1471
|
-
ts.isVariableDeclaration(declaration) &&
|
|
1472
|
-
declaration.initializer &&
|
|
1473
|
-
(ts.isArrowFunction(declaration.initializer) ||
|
|
1474
|
-
ts.isFunctionExpression(declaration.initializer))
|
|
1475
|
-
) {
|
|
1476
|
-
const name = declaration.name.getText(sourceFile);
|
|
1477
|
-
functions.push(
|
|
1478
|
-
this.extractArrowFunctionInfo(
|
|
1479
|
-
name,
|
|
1480
|
-
declaration.initializer,
|
|
1481
|
-
sourceFile,
|
|
1482
|
-
node
|
|
1483
|
-
)
|
|
1484
|
-
);
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
ts.forEachChild(node, visit);
|
|
1489
|
-
};
|
|
1490
|
-
|
|
1491
|
-
ts.forEachChild(sourceFile, visit);
|
|
1492
|
-
return functions;
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
/**
|
|
1496
|
-
* Extract all classes from the AST
|
|
1497
|
-
*/
|
|
1498
|
-
extractClasses(sourceFile: ts.SourceFile): ClassInfo[] {
|
|
1499
|
-
const classes: ClassInfo[] = [];
|
|
1500
|
-
|
|
1501
|
-
const visit = (node: ts.Node): void => {
|
|
1502
|
-
if (ts.isClassDeclaration(node) && node.name) {
|
|
1503
|
-
classes.push(this.extractClassInfo(node, sourceFile));
|
|
1504
|
-
}
|
|
1505
|
-
ts.forEachChild(node, visit);
|
|
1506
|
-
};
|
|
1507
|
-
|
|
1508
|
-
ts.forEachChild(sourceFile, visit);
|
|
1509
|
-
return classes;
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
/**
|
|
1513
|
-
* Extract information from a function declaration
|
|
1514
|
-
*/
|
|
1515
|
-
private extractFunctionInfo(
|
|
1516
|
-
node: ts.FunctionDeclaration,
|
|
1517
|
-
sourceFile: ts.SourceFile
|
|
1518
|
-
): FunctionInfo {
|
|
1519
|
-
const name = node.name?.getText(sourceFile) || 'anonymous';
|
|
1520
|
-
const parameters = this.extractParameters(node.parameters, sourceFile);
|
|
1521
|
-
const returnType = node.type?.getText(sourceFile);
|
|
1522
|
-
const isAsync = node.modifiers?.some(
|
|
1523
|
-
(m) => m.kind === ts.SyntaxKind.AsyncKeyword
|
|
1524
|
-
) ?? false;
|
|
1525
|
-
const isExported = node.modifiers?.some(
|
|
1526
|
-
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
1527
|
-
) ?? false;
|
|
1528
|
-
|
|
1529
|
-
const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1530
|
-
node.getStart(sourceFile)
|
|
1531
|
-
);
|
|
1532
|
-
const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1533
|
-
node.getEnd()
|
|
1534
|
-
);
|
|
1535
|
-
|
|
1536
|
-
const complexity = this.calculateCyclomaticComplexity(node);
|
|
1537
|
-
|
|
1538
|
-
return {
|
|
1539
|
-
name,
|
|
1540
|
-
parameters,
|
|
1541
|
-
returnType,
|
|
1542
|
-
isAsync,
|
|
1543
|
-
isExported,
|
|
1544
|
-
complexity,
|
|
1545
|
-
startLine: startLine + 1,
|
|
1546
|
-
endLine: endLine + 1,
|
|
1547
|
-
body: node.body?.getText(sourceFile),
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
/**
|
|
1552
|
-
* Extract information from an arrow function or function expression
|
|
1553
|
-
*/
|
|
1554
|
-
private extractArrowFunctionInfo(
|
|
1555
|
-
name: string,
|
|
1556
|
-
node: ts.ArrowFunction | ts.FunctionExpression,
|
|
1557
|
-
sourceFile: ts.SourceFile,
|
|
1558
|
-
parentNode: ts.Node
|
|
1559
|
-
): FunctionInfo {
|
|
1560
|
-
const parameters = this.extractParameters(node.parameters, sourceFile);
|
|
1561
|
-
const returnType = node.type?.getText(sourceFile);
|
|
1562
|
-
const isAsync = node.modifiers?.some(
|
|
1563
|
-
(m) => m.kind === ts.SyntaxKind.AsyncKeyword
|
|
1564
|
-
) ?? false;
|
|
1565
|
-
|
|
1566
|
-
// Check if parent is exported
|
|
1567
|
-
const isExported = ts.isVariableStatement(parentNode) &&
|
|
1568
|
-
(parentNode.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false);
|
|
1569
|
-
|
|
1570
|
-
const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1571
|
-
node.getStart(sourceFile)
|
|
1572
|
-
);
|
|
1573
|
-
const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1574
|
-
node.getEnd()
|
|
1575
|
-
);
|
|
1576
|
-
|
|
1577
|
-
const complexity = this.calculateCyclomaticComplexity(node);
|
|
1578
|
-
|
|
1579
|
-
return {
|
|
1580
|
-
name,
|
|
1581
|
-
parameters,
|
|
1582
|
-
returnType,
|
|
1583
|
-
isAsync,
|
|
1584
|
-
isExported,
|
|
1585
|
-
complexity,
|
|
1586
|
-
startLine: startLine + 1,
|
|
1587
|
-
endLine: endLine + 1,
|
|
1588
|
-
body: node.body?.getText(sourceFile),
|
|
1589
|
-
};
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
/**
|
|
1593
|
-
* Extract class information
|
|
1594
|
-
*/
|
|
1595
|
-
private extractClassInfo(
|
|
1596
|
-
node: ts.ClassDeclaration,
|
|
1597
|
-
sourceFile: ts.SourceFile
|
|
1598
|
-
): ClassInfo {
|
|
1599
|
-
const name = node.name?.getText(sourceFile) || 'AnonymousClass';
|
|
1600
|
-
const methods: FunctionInfo[] = [];
|
|
1601
|
-
const properties: PropertyInfo[] = [];
|
|
1602
|
-
let hasConstructor = false;
|
|
1603
|
-
|
|
1604
|
-
const isExported = node.modifiers?.some(
|
|
1605
|
-
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
1606
|
-
) ?? false;
|
|
1607
|
-
|
|
1608
|
-
for (const member of node.members) {
|
|
1609
|
-
if (ts.isMethodDeclaration(member)) {
|
|
1610
|
-
const methodName = member.name.getText(sourceFile);
|
|
1611
|
-
const parameters = this.extractParameters(member.parameters, sourceFile);
|
|
1612
|
-
const returnType = member.type?.getText(sourceFile);
|
|
1613
|
-
const isAsync = member.modifiers?.some(
|
|
1614
|
-
(m) => m.kind === ts.SyntaxKind.AsyncKeyword
|
|
1615
|
-
) ?? false;
|
|
1616
|
-
|
|
1617
|
-
const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1618
|
-
member.getStart(sourceFile)
|
|
1619
|
-
);
|
|
1620
|
-
const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1621
|
-
member.getEnd()
|
|
1622
|
-
);
|
|
1623
|
-
|
|
1624
|
-
methods.push({
|
|
1625
|
-
name: methodName,
|
|
1626
|
-
parameters,
|
|
1627
|
-
returnType,
|
|
1628
|
-
isAsync,
|
|
1629
|
-
isExported: false,
|
|
1630
|
-
complexity: this.calculateCyclomaticComplexity(member),
|
|
1631
|
-
startLine: startLine + 1,
|
|
1632
|
-
endLine: endLine + 1,
|
|
1633
|
-
body: member.body?.getText(sourceFile),
|
|
1634
|
-
});
|
|
1635
|
-
} else if (ts.isConstructorDeclaration(member)) {
|
|
1636
|
-
hasConstructor = true;
|
|
1637
|
-
} else if (ts.isPropertyDeclaration(member)) {
|
|
1638
|
-
const propName = member.name.getText(sourceFile);
|
|
1639
|
-
const propType = member.type?.getText(sourceFile);
|
|
1640
|
-
const isPrivate = member.modifiers?.some(
|
|
1641
|
-
(m) => m.kind === ts.SyntaxKind.PrivateKeyword
|
|
1642
|
-
) ?? false;
|
|
1643
|
-
const isReadonly = member.modifiers?.some(
|
|
1644
|
-
(m) => m.kind === ts.SyntaxKind.ReadonlyKeyword
|
|
1645
|
-
) ?? false;
|
|
1646
|
-
|
|
1647
|
-
properties.push({
|
|
1648
|
-
name: propName,
|
|
1649
|
-
type: propType,
|
|
1650
|
-
isPrivate,
|
|
1651
|
-
isReadonly,
|
|
1652
|
-
});
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
const { line: startLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1657
|
-
node.getStart(sourceFile)
|
|
1658
|
-
);
|
|
1659
|
-
const { line: endLine } = sourceFile.getLineAndCharacterOfPosition(
|
|
1660
|
-
node.getEnd()
|
|
1661
|
-
);
|
|
1662
|
-
|
|
1663
|
-
return {
|
|
1664
|
-
name,
|
|
1665
|
-
methods,
|
|
1666
|
-
properties,
|
|
1667
|
-
isExported,
|
|
1668
|
-
hasConstructor,
|
|
1669
|
-
startLine: startLine + 1,
|
|
1670
|
-
endLine: endLine + 1,
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
/**
|
|
1675
|
-
* Extract parameter information
|
|
1676
|
-
*/
|
|
1677
|
-
private extractParameters(
|
|
1678
|
-
params: ts.NodeArray<ts.ParameterDeclaration>,
|
|
1679
|
-
sourceFile: ts.SourceFile
|
|
1680
|
-
): ParameterInfo[] {
|
|
1681
|
-
return params.map((param) => ({
|
|
1682
|
-
name: param.name.getText(sourceFile),
|
|
1683
|
-
type: param.type?.getText(sourceFile),
|
|
1684
|
-
optional: param.questionToken !== undefined,
|
|
1685
|
-
defaultValue: param.initializer?.getText(sourceFile),
|
|
1686
|
-
}));
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
/**
|
|
1690
|
-
* Calculate cyclomatic complexity of a node
|
|
1691
|
-
*/
|
|
1692
|
-
calculateCyclomaticComplexity(node: ts.Node): number {
|
|
1693
|
-
let complexity = 1;
|
|
1694
|
-
|
|
1695
|
-
const visit = (n: ts.Node): void => {
|
|
1696
|
-
switch (n.kind) {
|
|
1697
|
-
case ts.SyntaxKind.IfStatement:
|
|
1698
|
-
case ts.SyntaxKind.ForStatement:
|
|
1699
|
-
case ts.SyntaxKind.ForInStatement:
|
|
1700
|
-
case ts.SyntaxKind.ForOfStatement:
|
|
1701
|
-
case ts.SyntaxKind.WhileStatement:
|
|
1702
|
-
case ts.SyntaxKind.DoStatement:
|
|
1703
|
-
case ts.SyntaxKind.CaseClause:
|
|
1704
|
-
case ts.SyntaxKind.CatchClause:
|
|
1705
|
-
case ts.SyntaxKind.ConditionalExpression:
|
|
1706
|
-
case ts.SyntaxKind.QuestionQuestionToken:
|
|
1707
|
-
complexity++;
|
|
1708
|
-
break;
|
|
1709
|
-
case ts.SyntaxKind.BinaryExpression:
|
|
1710
|
-
const binary = n as ts.BinaryExpression;
|
|
1711
|
-
if (
|
|
1712
|
-
binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
1713
|
-
binary.operatorToken.kind === ts.SyntaxKind.BarBarToken
|
|
1714
|
-
) {
|
|
1715
|
-
complexity++;
|
|
1716
|
-
}
|
|
1717
|
-
break;
|
|
1718
|
-
}
|
|
1719
|
-
ts.forEachChild(n, visit);
|
|
1720
|
-
};
|
|
1721
|
-
|
|
1722
|
-
ts.forEachChild(node, visit);
|
|
1723
|
-
return complexity;
|
|
1724
|
-
}
|
|
1725
|
-
}
|