codeguardian-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +348 -0
- package/dist/agent/agentTools.d.ts +26 -0
- package/dist/agent/agentTools.d.ts.map +1 -0
- package/dist/agent/agentTools.js +699 -0
- package/dist/agent/agentTools.js.map +1 -0
- package/dist/agent/autoValidator.d.ts +110 -0
- package/dist/agent/autoValidator.d.ts.map +1 -0
- package/dist/agent/autoValidator.js +964 -0
- package/dist/agent/autoValidator.js.map +1 -0
- package/dist/agent/fileWatcher.d.ts +28 -0
- package/dist/agent/fileWatcher.d.ts.map +1 -0
- package/dist/agent/fileWatcher.js +88 -0
- package/dist/agent/fileWatcher.js.map +1 -0
- package/dist/agent/guardianPersistence.d.ts +98 -0
- package/dist/agent/guardianPersistence.d.ts.map +1 -0
- package/dist/agent/guardianPersistence.js +296 -0
- package/dist/agent/guardianPersistence.js.map +1 -0
- package/dist/agent/mcpNotifications.d.ts +38 -0
- package/dist/agent/mcpNotifications.d.ts.map +1 -0
- package/dist/agent/mcpNotifications.js +81 -0
- package/dist/agent/mcpNotifications.js.map +1 -0
- package/dist/analyzers/aiPatterns.d.ts +16 -0
- package/dist/analyzers/aiPatterns.d.ts.map +1 -0
- package/dist/analyzers/aiPatterns.js +103 -0
- package/dist/analyzers/aiPatterns.js.map +1 -0
- package/dist/analyzers/antiPatterns.d.ts +60 -0
- package/dist/analyzers/antiPatterns.d.ts.map +1 -0
- package/dist/analyzers/antiPatterns.js +198 -0
- package/dist/analyzers/antiPatterns.js.map +1 -0
- package/dist/analyzers/builtinTypes.d.ts +18 -0
- package/dist/analyzers/builtinTypes.d.ts.map +1 -0
- package/dist/analyzers/builtinTypes.js +1275 -0
- package/dist/analyzers/builtinTypes.js.map +1 -0
- package/dist/analyzers/complexity.d.ts +14 -0
- package/dist/analyzers/complexity.d.ts.map +1 -0
- package/dist/analyzers/complexity.js +610 -0
- package/dist/analyzers/complexity.js.map +1 -0
- package/dist/analyzers/findingVerifier.d.ts +59 -0
- package/dist/analyzers/findingVerifier.d.ts.map +1 -0
- package/dist/analyzers/findingVerifier.js +1169 -0
- package/dist/analyzers/findingVerifier.js.map +1 -0
- package/dist/analyzers/impactAnalyzer.d.ts +53 -0
- package/dist/analyzers/impactAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/impactAnalyzer.js +152 -0
- package/dist/analyzers/impactAnalyzer.js.map +1 -0
- package/dist/analyzers/languageDetector.d.ts +48 -0
- package/dist/analyzers/languageDetector.d.ts.map +1 -0
- package/dist/analyzers/languageDetector.js +404 -0
- package/dist/analyzers/languageDetector.js.map +1 -0
- package/dist/analyzers/parsers/incrementalParser.d.ts +53 -0
- package/dist/analyzers/parsers/incrementalParser.d.ts.map +1 -0
- package/dist/analyzers/parsers/incrementalParser.js +193 -0
- package/dist/analyzers/parsers/incrementalParser.js.map +1 -0
- package/dist/analyzers/parsers/scopeResolver.d.ts +92 -0
- package/dist/analyzers/parsers/scopeResolver.d.ts.map +1 -0
- package/dist/analyzers/parsers/scopeResolver.js +324 -0
- package/dist/analyzers/parsers/scopeResolver.js.map +1 -0
- package/dist/analyzers/parsers/semanticIndex.d.ts +127 -0
- package/dist/analyzers/parsers/semanticIndex.d.ts.map +1 -0
- package/dist/analyzers/parsers/semanticIndex.js +429 -0
- package/dist/analyzers/parsers/semanticIndex.js.map +1 -0
- package/dist/analyzers/parsers/sessionDiffAnalyzer.d.ts +42 -0
- package/dist/analyzers/parsers/sessionDiffAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/parsers/sessionDiffAnalyzer.js +233 -0
- package/dist/analyzers/parsers/sessionDiffAnalyzer.js.map +1 -0
- package/dist/analyzers/parsers/treeSitterParser.d.ts +76 -0
- package/dist/analyzers/parsers/treeSitterParser.d.ts.map +1 -0
- package/dist/analyzers/parsers/treeSitterParser.js +709 -0
- package/dist/analyzers/parsers/treeSitterParser.js.map +1 -0
- package/dist/analyzers/relevanceScorer.d.ts +43 -0
- package/dist/analyzers/relevanceScorer.d.ts.map +1 -0
- package/dist/analyzers/relevanceScorer.js +200 -0
- package/dist/analyzers/relevanceScorer.js.map +1 -0
- package/dist/analyzers/standardLibrary.d.ts +22 -0
- package/dist/analyzers/standardLibrary.d.ts.map +1 -0
- package/dist/analyzers/standardLibrary.js +211 -0
- package/dist/analyzers/standardLibrary.js.map +1 -0
- package/dist/analyzers/symbolGraph.d.ts +30 -0
- package/dist/analyzers/symbolGraph.d.ts.map +1 -0
- package/dist/analyzers/symbolGraph.js +380 -0
- package/dist/analyzers/symbolGraph.js.map +1 -0
- package/dist/analyzers/symbolTable.d.ts +18 -0
- package/dist/analyzers/symbolTable.d.ts.map +1 -0
- package/dist/analyzers/symbolTable.js +176 -0
- package/dist/analyzers/symbolTable.js.map +1 -0
- package/dist/analyzers/typeChecker.d.ts +13 -0
- package/dist/analyzers/typeChecker.d.ts.map +1 -0
- package/dist/analyzers/typeChecker.js +580 -0
- package/dist/analyzers/typeChecker.js.map +1 -0
- package/dist/analyzers/usagePatterns.d.ts +42 -0
- package/dist/analyzers/usagePatterns.d.ts.map +1 -0
- package/dist/analyzers/usagePatterns.js +75 -0
- package/dist/analyzers/usagePatterns.js.map +1 -0
- package/dist/api-contract/context/backend.d.ts +19 -0
- package/dist/api-contract/context/backend.d.ts.map +1 -0
- package/dist/api-contract/context/backend.js +64 -0
- package/dist/api-contract/context/backend.js.map +1 -0
- package/dist/api-contract/context/contract.d.ts +34 -0
- package/dist/api-contract/context/contract.d.ts.map +1 -0
- package/dist/api-contract/context/contract.js +306 -0
- package/dist/api-contract/context/contract.js.map +1 -0
- package/dist/api-contract/context/frontend.d.ts +19 -0
- package/dist/api-contract/context/frontend.d.ts.map +1 -0
- package/dist/api-contract/context/frontend.js +64 -0
- package/dist/api-contract/context/frontend.js.map +1 -0
- package/dist/api-contract/detector.d.ts +28 -0
- package/dist/api-contract/detector.d.ts.map +1 -0
- package/dist/api-contract/detector.js +393 -0
- package/dist/api-contract/detector.js.map +1 -0
- package/dist/api-contract/extractors/python.d.ts +32 -0
- package/dist/api-contract/extractors/python.d.ts.map +1 -0
- package/dist/api-contract/extractors/python.js +521 -0
- package/dist/api-contract/extractors/python.js.map +1 -0
- package/dist/api-contract/extractors/pythonAstUtils.d.ts +44 -0
- package/dist/api-contract/extractors/pythonAstUtils.d.ts.map +1 -0
- package/dist/api-contract/extractors/pythonAstUtils.js +489 -0
- package/dist/api-contract/extractors/pythonAstUtils.js.map +1 -0
- package/dist/api-contract/extractors/tsAstUtils.d.ts +47 -0
- package/dist/api-contract/extractors/tsAstUtils.d.ts.map +1 -0
- package/dist/api-contract/extractors/tsAstUtils.js +173 -0
- package/dist/api-contract/extractors/tsAstUtils.js.map +1 -0
- package/dist/api-contract/extractors/typescript.d.ts +32 -0
- package/dist/api-contract/extractors/typescript.d.ts.map +1 -0
- package/dist/api-contract/extractors/typescript.js +666 -0
- package/dist/api-contract/extractors/typescript.js.map +1 -0
- package/dist/api-contract/index.d.ts +104 -0
- package/dist/api-contract/index.d.ts.map +1 -0
- package/dist/api-contract/index.js +232 -0
- package/dist/api-contract/index.js.map +1 -0
- package/dist/api-contract/types.d.ts +151 -0
- package/dist/api-contract/types.d.ts.map +1 -0
- package/dist/api-contract/types.js +19 -0
- package/dist/api-contract/types.js.map +1 -0
- package/dist/api-contract/validators/endpoint.d.ts +21 -0
- package/dist/api-contract/validators/endpoint.d.ts.map +1 -0
- package/dist/api-contract/validators/endpoint.js +224 -0
- package/dist/api-contract/validators/endpoint.js.map +1 -0
- package/dist/api-contract/validators/index.d.ts +40 -0
- package/dist/api-contract/validators/index.d.ts.map +1 -0
- package/dist/api-contract/validators/index.js +875 -0
- package/dist/api-contract/validators/index.js.map +1 -0
- package/dist/api-contract/validators/parameter.d.ts +17 -0
- package/dist/api-contract/validators/parameter.d.ts.map +1 -0
- package/dist/api-contract/validators/parameter.js +250 -0
- package/dist/api-contract/validators/parameter.js.map +1 -0
- package/dist/api-contract/validators/type.d.ts +38 -0
- package/dist/api-contract/validators/type.d.ts.map +1 -0
- package/dist/api-contract/validators/type.js +244 -0
- package/dist/api-contract/validators/type.js.map +1 -0
- package/dist/context/apiContract/complexTypeSupport.d.ts +83 -0
- package/dist/context/apiContract/complexTypeSupport.d.ts.map +1 -0
- package/dist/context/apiContract/complexTypeSupport.js +665 -0
- package/dist/context/apiContract/complexTypeSupport.js.map +1 -0
- package/dist/context/apiContract/graphqlSupport.d.ts +105 -0
- package/dist/context/apiContract/graphqlSupport.d.ts.map +1 -0
- package/dist/context/apiContract/graphqlSupport.js +671 -0
- package/dist/context/apiContract/graphqlSupport.js.map +1 -0
- package/dist/context/apiContract/index.d.ts +14 -0
- package/dist/context/apiContract/index.d.ts.map +1 -0
- package/dist/context/apiContract/index.js +17 -0
- package/dist/context/apiContract/index.js.map +1 -0
- package/dist/context/apiContract/webSocketSupport.d.ts +104 -0
- package/dist/context/apiContract/webSocketSupport.d.ts.map +1 -0
- package/dist/context/apiContract/webSocketSupport.js +465 -0
- package/dist/context/apiContract/webSocketSupport.js.map +1 -0
- package/dist/context/apiContractContext.d.ts +15 -0
- package/dist/context/apiContractContext.d.ts.map +1 -0
- package/dist/context/apiContractContext.js +979 -0
- package/dist/context/apiContractContext.js.map +1 -0
- package/dist/context/apiContractExtraction.d.ts +52 -0
- package/dist/context/apiContractExtraction.d.ts.map +1 -0
- package/dist/context/apiContractExtraction.js +438 -0
- package/dist/context/apiContractExtraction.js.map +1 -0
- package/dist/context/contextLineage.d.ts +79 -0
- package/dist/context/contextLineage.d.ts.map +1 -0
- package/dist/context/contextLineage.js +259 -0
- package/dist/context/contextLineage.js.map +1 -0
- package/dist/context/contextOrchestrator.d.ts +57 -0
- package/dist/context/contextOrchestrator.d.ts.map +1 -0
- package/dist/context/contextOrchestrator.js +162 -0
- package/dist/context/contextOrchestrator.js.map +1 -0
- package/dist/context/intentTracker.d.ts +73 -0
- package/dist/context/intentTracker.d.ts.map +1 -0
- package/dist/context/intentTracker.js +168 -0
- package/dist/context/intentTracker.js.map +1 -0
- package/dist/context/projectContext.d.ts +219 -0
- package/dist/context/projectContext.d.ts.map +1 -0
- package/dist/context/projectContext.js +1984 -0
- package/dist/context/projectContext.js.map +1 -0
- package/dist/prompts/index.d.ts +17 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +260 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/library.d.ts +51 -0
- package/dist/prompts/library.d.ts.map +1 -0
- package/dist/prompts/library.js +65 -0
- package/dist/prompts/library.js.map +1 -0
- package/dist/prompts/templates.d.ts +44 -0
- package/dist/prompts/templates.d.ts.map +1 -0
- package/dist/prompts/templates.js +97 -0
- package/dist/prompts/templates.js.map +1 -0
- package/dist/queue/jobPersistence.d.ts +46 -0
- package/dist/queue/jobPersistence.d.ts.map +1 -0
- package/dist/queue/jobPersistence.js +158 -0
- package/dist/queue/jobPersistence.js.map +1 -0
- package/dist/queue/jobQueue.d.ts +116 -0
- package/dist/queue/jobQueue.d.ts.map +1 -0
- package/dist/queue/jobQueue.js +275 -0
- package/dist/queue/jobQueue.js.map +1 -0
- package/dist/queue/validationJob.d.ts +69 -0
- package/dist/queue/validationJob.d.ts.map +1 -0
- package/dist/queue/validationJob.js +435 -0
- package/dist/queue/validationJob.js.map +1 -0
- package/dist/resources/index.d.ts +15 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +328 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/validationReportStore.d.ts +170 -0
- package/dist/resources/validationReportStore.d.ts.map +1 -0
- package/dist/resources/validationReportStore.js +515 -0
- package/dist/resources/validationReportStore.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +102 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/asyncValidation.d.ts +19 -0
- package/dist/tools/asyncValidation.d.ts.map +1 -0
- package/dist/tools/asyncValidation.js +346 -0
- package/dist/tools/asyncValidation.js.map +1 -0
- package/dist/tools/buildContext.d.ts +17 -0
- package/dist/tools/buildContext.d.ts.map +1 -0
- package/dist/tools/buildContext.js +188 -0
- package/dist/tools/buildContext.js.map +1 -0
- package/dist/tools/getDependencyGraph.d.ts +16 -0
- package/dist/tools/getDependencyGraph.d.ts.map +1 -0
- package/dist/tools/getDependencyGraph.js +436 -0
- package/dist/tools/getDependencyGraph.js.map +1 -0
- package/dist/tools/incrementalValidation.d.ts +71 -0
- package/dist/tools/incrementalValidation.d.ts.map +1 -0
- package/dist/tools/incrementalValidation.js +203 -0
- package/dist/tools/incrementalValidation.js.map +1 -0
- package/dist/tools/index.d.ts +24 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +106 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/validateCode.d.ts +17 -0
- package/dist/tools/validateCode.d.ts.map +1 -0
- package/dist/tools/validateCode.js +368 -0
- package/dist/tools/validateCode.js.map +1 -0
- package/dist/tools/validateCodeLite.d.ts +2 -0
- package/dist/tools/validateCodeLite.d.ts.map +1 -0
- package/dist/tools/validateCodeLite.js +2 -0
- package/dist/tools/validateCodeLite.js.map +1 -0
- package/dist/tools/validation/builtins.d.ts +92 -0
- package/dist/tools/validation/builtins.d.ts.map +1 -0
- package/dist/tools/validation/builtins.js +2184 -0
- package/dist/tools/validation/builtins.js.map +1 -0
- package/dist/tools/validation/contextualNaming.d.ts +99 -0
- package/dist/tools/validation/contextualNaming.d.ts.map +1 -0
- package/dist/tools/validation/contextualNaming.js +959 -0
- package/dist/tools/validation/contextualNaming.js.map +1 -0
- package/dist/tools/validation/deadCode.d.ts +115 -0
- package/dist/tools/validation/deadCode.d.ts.map +1 -0
- package/dist/tools/validation/deadCode.js +861 -0
- package/dist/tools/validation/deadCode.js.map +1 -0
- package/dist/tools/validation/extractors/index.d.ts +131 -0
- package/dist/tools/validation/extractors/index.d.ts.map +1 -0
- package/dist/tools/validation/extractors/index.js +233 -0
- package/dist/tools/validation/extractors/index.js.map +1 -0
- package/dist/tools/validation/extractors/javascript.d.ts +73 -0
- package/dist/tools/validation/extractors/javascript.d.ts.map +1 -0
- package/dist/tools/validation/extractors/javascript.js +1841 -0
- package/dist/tools/validation/extractors/javascript.js.map +1 -0
- package/dist/tools/validation/extractors/python.d.ts +93 -0
- package/dist/tools/validation/extractors/python.d.ts.map +1 -0
- package/dist/tools/validation/extractors/python.js +799 -0
- package/dist/tools/validation/extractors/python.js.map +1 -0
- package/dist/tools/validation/manifest.d.ts +45 -0
- package/dist/tools/validation/manifest.d.ts.map +1 -0
- package/dist/tools/validation/manifest.js +719 -0
- package/dist/tools/validation/manifest.js.map +1 -0
- package/dist/tools/validation/parser.d.ts +58 -0
- package/dist/tools/validation/parser.d.ts.map +1 -0
- package/dist/tools/validation/parser.js +232 -0
- package/dist/tools/validation/parser.js.map +1 -0
- package/dist/tools/validation/registry.d.ts +15 -0
- package/dist/tools/validation/registry.d.ts.map +1 -0
- package/dist/tools/validation/registry.js +169 -0
- package/dist/tools/validation/registry.js.map +1 -0
- package/dist/tools/validation/scoring.d.ts +54 -0
- package/dist/tools/validation/scoring.d.ts.map +1 -0
- package/dist/tools/validation/scoring.js +242 -0
- package/dist/tools/validation/scoring.js.map +1 -0
- package/dist/tools/validation/types.d.ts +120 -0
- package/dist/tools/validation/types.d.ts.map +1 -0
- package/dist/tools/validation/types.js +11 -0
- package/dist/tools/validation/types.js.map +1 -0
- package/dist/tools/validation/unusedLocals.d.ts +36 -0
- package/dist/tools/validation/unusedLocals.d.ts.map +1 -0
- package/dist/tools/validation/unusedLocals.js +333 -0
- package/dist/tools/validation/unusedLocals.js.map +1 -0
- package/dist/tools/validation/validation.d.ts +98 -0
- package/dist/tools/validation/validation.d.ts.map +1 -0
- package/dist/tools/validation/validation.js +1837 -0
- package/dist/tools/validation/validation.js.map +1 -0
- package/dist/types/codeGraph.d.ts +163 -0
- package/dist/types/codeGraph.d.ts.map +1 -0
- package/dist/types/codeGraph.js +9 -0
- package/dist/types/codeGraph.js.map +1 -0
- package/dist/types/symbolGraph.d.ts +68 -0
- package/dist/types/symbolGraph.d.ts.map +1 -0
- package/dist/types/symbolGraph.js +10 -0
- package/dist/types/symbolGraph.js.map +1 -0
- package/dist/types/tools.d.ts +43 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +7 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/utils/fileFilter.d.ts +37 -0
- package/dist/utils/fileFilter.d.ts.map +1 -0
- package/dist/utils/fileFilter.js +91 -0
- package/dist/utils/fileFilter.js.map +1 -0
- package/dist/utils/gitUtils.d.ts +28 -0
- package/dist/utils/gitUtils.d.ts.map +1 -0
- package/dist/utils/gitUtils.js +81 -0
- package/dist/utils/gitUtils.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +38 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/serialization.d.ts +25 -0
- package/dist/utils/serialization.d.ts.map +1 -0
- package/dist/utils/serialization.js +53 -0
- package/dist/utils/serialization.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage Pattern Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Secret #5: Usage Pattern Consistency (The Helpfulness Pattern)
|
|
5
|
+
*
|
|
6
|
+
* Learns "rituals" from the codebase:
|
|
7
|
+
* - Co-occurrence: Which functions are almost always called together?
|
|
8
|
+
* - Argument Rituals: Common arguments passed to specific functions.
|
|
9
|
+
* - Call Ordering: (Heuristic) Which symbols often appear in sequence.
|
|
10
|
+
*
|
|
11
|
+
* @format
|
|
12
|
+
*/
|
|
13
|
+
import { logger } from "../utils/logger.js";
|
|
14
|
+
export class UsagePatternAnalyzer {
|
|
15
|
+
patterns = new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Analyze the symbol graph to discover patterns
|
|
18
|
+
*/
|
|
19
|
+
async analyze(graph) {
|
|
20
|
+
logger.debug(`Analyzing usage patterns for ${graph.usage.size} symbols...`);
|
|
21
|
+
for (const [symbolName, usage] of graph.usage.entries()) {
|
|
22
|
+
// We only care about symbols used at least 3 times to establish a pattern
|
|
23
|
+
if (usage.usageCount < 3)
|
|
24
|
+
continue;
|
|
25
|
+
const coOccurring = this.extractCoOccurrence(symbolName, graph);
|
|
26
|
+
// If we found significant co-occurrence, store the pattern
|
|
27
|
+
if (coOccurring.length > 0) {
|
|
28
|
+
this.patterns.set(symbolName, {
|
|
29
|
+
symbol: symbolName,
|
|
30
|
+
coOccurringSymbols: coOccurring,
|
|
31
|
+
commonArguments: [], // To be implemented with deeper AST mining
|
|
32
|
+
callConfidence: usage.usageCount > 10 ? 0.9 : 0.7,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
logger.debug(`Established ${this.patterns.size} usage pattern rituals.`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if new code deviates from established patterns
|
|
40
|
+
*/
|
|
41
|
+
checkDeviations(symbolName, surroundingSymbols) {
|
|
42
|
+
const pattern = this.patterns.get(symbolName);
|
|
43
|
+
if (!pattern)
|
|
44
|
+
return [];
|
|
45
|
+
const deviations = [];
|
|
46
|
+
const surroundingSet = new Set(surroundingSymbols);
|
|
47
|
+
// If a symbol has a high co-occurrence (e.g. > 80% usage),
|
|
48
|
+
// it should probably be present
|
|
49
|
+
for (const ritual of pattern.coOccurringSymbols) {
|
|
50
|
+
if (ritual.frequency > 0.8 && !surroundingSet.has(ritual.name)) {
|
|
51
|
+
deviations.push(`When using '${symbolName}', projects usually also call '${ritual.name}'.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return deviations;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract co-occurrence statistics for a symbol
|
|
58
|
+
*/
|
|
59
|
+
extractCoOccurrence(symbolName, graph) {
|
|
60
|
+
const results = [];
|
|
61
|
+
const coChanges = graph.coOccurrence.get(symbolName);
|
|
62
|
+
if (!coChanges)
|
|
63
|
+
return results;
|
|
64
|
+
const totalUsage = graph.usage.get(symbolName)?.usageCount || 1;
|
|
65
|
+
for (const [otherName, count] of coChanges.entries()) {
|
|
66
|
+
const frequency = count / totalUsage;
|
|
67
|
+
if (frequency > 0.5) { // Significant ritual if seen in >50% of cases
|
|
68
|
+
results.push({ name: otherName, frequency });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return results.sort((a, b) => b.frequency - a.frequency);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export const usagePatternAnalyzer = new UsagePatternAnalyzer();
|
|
75
|
+
//# sourceMappingURL=usagePatterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usagePatterns.js","sourceRoot":"","sources":["../../src/analyzers/usagePatterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Backend Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds the backend context by extracting routes, models, and configuration.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import type { BackendContext, BackendProject } from "../types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Build backend context from a project path
|
|
11
|
+
* Extracts routes, models, and API configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildBackendContext(project: BackendProject): Promise<BackendContext>;
|
|
14
|
+
/**
|
|
15
|
+
* Incrementally update backend context when a file changes
|
|
16
|
+
* Only re-extracts from the changed file
|
|
17
|
+
*/
|
|
18
|
+
export declare function updateBackendContext(context: BackendContext, projectPath: string, changedFile: string): Promise<BackendContext>;
|
|
19
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../../src/api-contract/context/backend.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlE;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAyBzB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAwCzB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Backend Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds the backend context by extracting routes, models, and configuration.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "../../utils/logger.js";
|
|
9
|
+
import { extractRoutes, extractModels, extractApiConfig, } from "../extractors/python.js";
|
|
10
|
+
/**
|
|
11
|
+
* Build backend context from a project path
|
|
12
|
+
* Extracts routes, models, and API configuration
|
|
13
|
+
*/
|
|
14
|
+
export async function buildBackendContext(project) {
|
|
15
|
+
logger.info(`Building backend context for ${project.framework} project...`);
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
// Extract routes and models in parallel
|
|
18
|
+
const [routes, models, config] = await Promise.all([
|
|
19
|
+
extractRoutes(project.path, project.framework),
|
|
20
|
+
extractModels(project.path),
|
|
21
|
+
extractApiConfig(project.path),
|
|
22
|
+
]);
|
|
23
|
+
const context = {
|
|
24
|
+
framework: project.framework,
|
|
25
|
+
routes,
|
|
26
|
+
models,
|
|
27
|
+
apiPrefix: config.apiPrefix,
|
|
28
|
+
};
|
|
29
|
+
logger.info(`Backend context built in ${Date.now() - startTime}ms ` +
|
|
30
|
+
`(${routes.length} routes, ${models.length} models)`);
|
|
31
|
+
return context;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Incrementally update backend context when a file changes
|
|
35
|
+
* Only re-extracts from the changed file
|
|
36
|
+
*/
|
|
37
|
+
export async function updateBackendContext(context, projectPath, changedFile) {
|
|
38
|
+
logger.debug(`Updating backend context for changed file: ${changedFile}`);
|
|
39
|
+
// Remove old entries from this file
|
|
40
|
+
context.routes = context.routes.filter((r) => !r.file.includes(changedFile));
|
|
41
|
+
context.models = context.models.filter((m) => !m.file.includes(changedFile));
|
|
42
|
+
// Re-extract from changed file if it's a relevant file
|
|
43
|
+
if (changedFile.includes("/routes/") ||
|
|
44
|
+
changedFile.includes("/routers/") ||
|
|
45
|
+
changedFile.includes("/api/") ||
|
|
46
|
+
changedFile.includes("/models/") ||
|
|
47
|
+
changedFile.includes("/schemas/")) {
|
|
48
|
+
try {
|
|
49
|
+
const fs = await import("fs/promises");
|
|
50
|
+
const content = await fs.readFile(changedFile, "utf-8");
|
|
51
|
+
// Import extractors dynamically to avoid circular dependencies
|
|
52
|
+
const { extractRoutesFromFile, extractModelsFromFile, } = await import("../extractors/python.js");
|
|
53
|
+
const newRoutes = extractRoutesFromFile(content, changedFile, context.framework);
|
|
54
|
+
const newModels = extractModelsFromFile(content, changedFile);
|
|
55
|
+
context.routes.push(...newRoutes);
|
|
56
|
+
context.models.push(...newModels);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
logger.debug(`Failed to update context for ${changedFile}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return context;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../../src/api-contract/context/backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Contract Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Links frontend and backend contexts to create a unified contract view.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import type { FrontendContext, BackendContext, ContractContext, EndpointMapping, TypeMapping, ServiceDefinition, RouteDefinition } from "../types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Build contract context by linking frontend and backend
|
|
11
|
+
* Matches services to routes and types to models
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildContractContext(frontendContext: FrontendContext, backendContext: BackendContext): Promise<ContractContext>;
|
|
14
|
+
/**
|
|
15
|
+
* Get contract context for a specific endpoint
|
|
16
|
+
*/
|
|
17
|
+
export declare function getEndpointContract(context: ContractContext, endpoint: string): EndpointMapping | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Get type mapping for a specific type
|
|
20
|
+
*/
|
|
21
|
+
export declare function getTypeContract(context: ContractContext, typeName: string): TypeMapping | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a service has a matching backend route
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasMatchingRoute(context: ContractContext, service: ServiceDefinition): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Get all unmatched frontend services
|
|
28
|
+
*/
|
|
29
|
+
export declare function getUnmatchedFrontendServices(context: ContractContext): ServiceDefinition[];
|
|
30
|
+
/**
|
|
31
|
+
* Get all unmatched backend routes
|
|
32
|
+
*/
|
|
33
|
+
export declare function getUnmatchedBackendRoutes(context: ContractContext): RouteDefinition[];
|
|
34
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/api-contract/context/contract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,EAIhB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,eAAe,CAAC,CA8D1B;AA0SD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,MAAM,GACf,eAAe,GAAG,SAAS,CAE7B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,MAAM,GACf,WAAW,GAAG,SAAS,CAEzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAET;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,eAAe,GACvB,iBAAiB,EAAE,CAErB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,eAAe,GACvB,eAAe,EAAE,CAEnB"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Contract Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Links frontend and backend contexts to create a unified contract view.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "../../utils/logger.js";
|
|
9
|
+
/**
|
|
10
|
+
* Build contract context by linking frontend and backend
|
|
11
|
+
* Matches services to routes and types to models
|
|
12
|
+
*/
|
|
13
|
+
export async function buildContractContext(frontendContext, backendContext) {
|
|
14
|
+
logger.info("Building contract context...");
|
|
15
|
+
const startTime = Date.now();
|
|
16
|
+
const endpoints = new Map();
|
|
17
|
+
const types = new Map();
|
|
18
|
+
const unmatchedFrontend = [];
|
|
19
|
+
const unmatchedBackend = [];
|
|
20
|
+
// Match frontend services to backend routes
|
|
21
|
+
for (const service of frontendContext.services) {
|
|
22
|
+
const matchingRoute = findMatchingRoute(service, backendContext.routes);
|
|
23
|
+
if (matchingRoute) {
|
|
24
|
+
const score = calculateEndpointMatchScore(service, matchingRoute);
|
|
25
|
+
endpoints.set(service.endpoint, {
|
|
26
|
+
frontend: service,
|
|
27
|
+
backend: matchingRoute,
|
|
28
|
+
score,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
unmatchedFrontend.push(service);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Find unmatched backend routes
|
|
36
|
+
for (const route of backendContext.routes) {
|
|
37
|
+
const isMatched = Array.from(endpoints.values()).some((mapping) => mapping.backend === route);
|
|
38
|
+
if (!isMatched) {
|
|
39
|
+
unmatchedBackend.push(route);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Match frontend types to backend models
|
|
43
|
+
for (const type of frontendContext.types) {
|
|
44
|
+
const matchingModel = findMatchingModel(type, backendContext.models);
|
|
45
|
+
if (matchingModel) {
|
|
46
|
+
const compatibility = calculateTypeCompatibility(type, matchingModel);
|
|
47
|
+
types.set(type.name, {
|
|
48
|
+
frontend: type,
|
|
49
|
+
backend: matchingModel,
|
|
50
|
+
compatibility,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const context = {
|
|
55
|
+
endpoints,
|
|
56
|
+
types,
|
|
57
|
+
unmatchedFrontend,
|
|
58
|
+
unmatchedBackend,
|
|
59
|
+
};
|
|
60
|
+
logger.info(`Contract context built in ${Date.now() - startTime}ms ` +
|
|
61
|
+
`(${endpoints.size} matched endpoints, ${types.size} matched types, ` +
|
|
62
|
+
`${unmatchedFrontend.length} unmatched frontend, ${unmatchedBackend.length} unmatched backend)`);
|
|
63
|
+
return context;
|
|
64
|
+
}
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Endpoint Matching
|
|
67
|
+
// ============================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Find a matching backend route for a frontend service
|
|
70
|
+
*/
|
|
71
|
+
function findMatchingRoute(service, routes) {
|
|
72
|
+
// Normalize the service endpoint
|
|
73
|
+
const normalizedEndpoint = normalizePath(service.endpoint);
|
|
74
|
+
// First try exact match
|
|
75
|
+
const exactMatch = routes.find((route) => {
|
|
76
|
+
const normalizedRoute = normalizePath(route.path);
|
|
77
|
+
return (normalizedRoute === normalizedEndpoint &&
|
|
78
|
+
route.method.toUpperCase() === service.method.toUpperCase());
|
|
79
|
+
});
|
|
80
|
+
if (exactMatch) {
|
|
81
|
+
return exactMatch;
|
|
82
|
+
}
|
|
83
|
+
// Try fuzzy match (handle API prefix differences)
|
|
84
|
+
// Frontend: /clients, Backend: /api/clients
|
|
85
|
+
const fuzzyMatch = routes.find((route) => {
|
|
86
|
+
const normalizedRoute = normalizePath(route.path);
|
|
87
|
+
const routeWithoutPrefix = removeApiPrefix(normalizedRoute);
|
|
88
|
+
const serviceWithoutPrefix = removeApiPrefix(normalizedEndpoint);
|
|
89
|
+
return (routeWithoutPrefix === serviceWithoutPrefix &&
|
|
90
|
+
route.method.toUpperCase() === service.method.toUpperCase());
|
|
91
|
+
});
|
|
92
|
+
return fuzzyMatch;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Calculate match score for endpoint mapping
|
|
96
|
+
*/
|
|
97
|
+
function calculateEndpointMatchScore(service, route) {
|
|
98
|
+
let score = 100;
|
|
99
|
+
// Method match is critical
|
|
100
|
+
if (service.method.toUpperCase() !== route.method.toUpperCase()) {
|
|
101
|
+
score -= 50;
|
|
102
|
+
}
|
|
103
|
+
// Path match
|
|
104
|
+
const normalizedService = normalizePath(service.endpoint);
|
|
105
|
+
const normalizedRoute = normalizePath(route.path);
|
|
106
|
+
if (normalizedService === normalizedRoute) {
|
|
107
|
+
score += 10;
|
|
108
|
+
}
|
|
109
|
+
else if (removeApiPrefix(normalizedService) === removeApiPrefix(normalizedRoute)) {
|
|
110
|
+
score += 5;
|
|
111
|
+
}
|
|
112
|
+
// Type name match bonus
|
|
113
|
+
if (service.requestType && service.requestType === route.requestModel) {
|
|
114
|
+
score += 10;
|
|
115
|
+
}
|
|
116
|
+
if (service.responseType && service.responseType === route.responseModel) {
|
|
117
|
+
score += 10;
|
|
118
|
+
}
|
|
119
|
+
return Math.max(0, Math.min(100, score));
|
|
120
|
+
}
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// Type Matching
|
|
123
|
+
// ============================================================================
|
|
124
|
+
/**
|
|
125
|
+
* Find a matching backend model for a frontend type
|
|
126
|
+
*/
|
|
127
|
+
function findMatchingModel(type, models) {
|
|
128
|
+
// Try exact name match first
|
|
129
|
+
const exactMatch = models.find((m) => m.name === type.name);
|
|
130
|
+
if (exactMatch) {
|
|
131
|
+
return exactMatch;
|
|
132
|
+
}
|
|
133
|
+
// Try normalized name match (handle naming conventions)
|
|
134
|
+
// ClientCreate -> client_create, clientCreate
|
|
135
|
+
const normalizedTypeName = normalizeName(type.name);
|
|
136
|
+
const normalizedMatch = models.find((m) => normalizeName(m.name) === normalizedTypeName);
|
|
137
|
+
if (normalizedMatch) {
|
|
138
|
+
return normalizedMatch;
|
|
139
|
+
}
|
|
140
|
+
// Try fuzzy match based on field similarity
|
|
141
|
+
let bestMatch;
|
|
142
|
+
let bestScore = 0;
|
|
143
|
+
for (const model of models) {
|
|
144
|
+
const score = calculateFieldSimilarity(type, model);
|
|
145
|
+
if (score > bestScore && score > 0.7) {
|
|
146
|
+
// 70% threshold
|
|
147
|
+
bestScore = score;
|
|
148
|
+
bestMatch = model;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return bestMatch;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Calculate type compatibility between frontend and backend
|
|
155
|
+
*/
|
|
156
|
+
function calculateTypeCompatibility(type, model) {
|
|
157
|
+
const issues = [];
|
|
158
|
+
let score = 100;
|
|
159
|
+
// Check for missing required fields in frontend
|
|
160
|
+
for (const modelField of model.fields) {
|
|
161
|
+
if (modelField.required) {
|
|
162
|
+
const frontendField = type.fields.find((f) => normalizeName(f.name) === normalizeName(modelField.name));
|
|
163
|
+
if (!frontendField) {
|
|
164
|
+
score -= 15;
|
|
165
|
+
issues.push(`Missing required field: ${modelField.name}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Check for naming convention mismatches
|
|
170
|
+
for (const frontendField of type.fields) {
|
|
171
|
+
const backendField = model.fields.find((f) => normalizeName(f.name) === normalizeName(frontendField.name));
|
|
172
|
+
if (backendField && frontendField.name !== backendField.name) {
|
|
173
|
+
score -= 5;
|
|
174
|
+
issues.push(`Naming convention mismatch: ${frontendField.name} vs ${backendField.name}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Check type compatibility
|
|
178
|
+
for (const frontendField of type.fields) {
|
|
179
|
+
const backendField = model.fields.find((f) => normalizeName(f.name) === normalizeName(frontendField.name));
|
|
180
|
+
if (backendField) {
|
|
181
|
+
const typeCompatible = areTypesCompatible(frontendField.type, backendField.type);
|
|
182
|
+
if (!typeCompatible) {
|
|
183
|
+
score -= 10;
|
|
184
|
+
issues.push(`Type mismatch: ${frontendField.name} (${frontendField.type} vs ${backendField.type})`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
score: Math.max(0, score),
|
|
190
|
+
issues,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Calculate field similarity between type and model
|
|
195
|
+
*/
|
|
196
|
+
function calculateFieldSimilarity(type, model) {
|
|
197
|
+
if (type.fields.length === 0 || model.fields.length === 0) {
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
const typeFieldNames = new Set(type.fields.map((f) => normalizeName(f.name)));
|
|
201
|
+
const modelFieldNames = new Set(model.fields.map((f) => normalizeName(f.name)));
|
|
202
|
+
// Calculate Jaccard similarity
|
|
203
|
+
const intersection = new Set([...typeFieldNames].filter((x) => modelFieldNames.has(x)));
|
|
204
|
+
const union = new Set([...typeFieldNames, ...modelFieldNames]);
|
|
205
|
+
return intersection.size / union.size;
|
|
206
|
+
}
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// Type Compatibility
|
|
209
|
+
// ============================================================================
|
|
210
|
+
/**
|
|
211
|
+
* Check if TypeScript and Python types are compatible
|
|
212
|
+
*/
|
|
213
|
+
function areTypesCompatible(tsType, pyType) {
|
|
214
|
+
const typeMap = {
|
|
215
|
+
string: ["str", "String", "text"],
|
|
216
|
+
number: ["int", "float", "Number", "integer", "decimal"],
|
|
217
|
+
boolean: ["bool", "Boolean"],
|
|
218
|
+
Date: ["datetime", "date", "time"],
|
|
219
|
+
"string[]": ["list[str]", "List[str]", "Sequence[str]"],
|
|
220
|
+
"number[]": ["list[int]", "list[float]", "List[int]", "List[float]"],
|
|
221
|
+
object: ["dict", "Dict", "Mapping"],
|
|
222
|
+
"any[]": ["list", "List", "Sequence"],
|
|
223
|
+
};
|
|
224
|
+
// Normalize types
|
|
225
|
+
const normalizedTsType = tsType.toLowerCase().replace(/\s+/g, "");
|
|
226
|
+
const normalizedPyType = pyType.toLowerCase().replace(/\s+/g, "");
|
|
227
|
+
// Direct match
|
|
228
|
+
if (normalizedTsType === normalizedPyType) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
// Check type map
|
|
232
|
+
const compatibleTypes = typeMap[normalizedTsType] || [];
|
|
233
|
+
if (compatibleTypes.some((t) => normalizedPyType.includes(t.toLowerCase().replace(/\s+/g, "")))) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
// Handle optional types
|
|
237
|
+
if (tsType.includes("?") || tsType.includes("undefined")) {
|
|
238
|
+
return true; // Optional fields are always compatible
|
|
239
|
+
}
|
|
240
|
+
if (pyType.toLowerCase().includes("optional")) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// Utility Functions
|
|
247
|
+
// ============================================================================
|
|
248
|
+
/**
|
|
249
|
+
* Normalize a path for comparison
|
|
250
|
+
* Removes trailing slashes and ensures consistent format
|
|
251
|
+
*/
|
|
252
|
+
function normalizePath(path) {
|
|
253
|
+
return path
|
|
254
|
+
.replace(/\/+/g, "/") // Remove duplicate slashes
|
|
255
|
+
.replace(/\/$/, "") // Remove trailing slash
|
|
256
|
+
.replace(/^\//, ""); // Remove leading slash
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Remove API prefix from path for fuzzy matching
|
|
260
|
+
*/
|
|
261
|
+
function removeApiPrefix(path) {
|
|
262
|
+
return path.replace(/^(api|v\d+|rest)\//, "");
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Normalize a name for comparison
|
|
266
|
+
* Handles different naming conventions (camelCase, snake_case, PascalCase)
|
|
267
|
+
*/
|
|
268
|
+
function normalizeName(name) {
|
|
269
|
+
return (name
|
|
270
|
+
// Convert camelCase/PascalCase to snake_case
|
|
271
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
272
|
+
.toLowerCase()
|
|
273
|
+
// Remove underscores for comparison
|
|
274
|
+
.replace(/_/g, ""));
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get contract context for a specific endpoint
|
|
278
|
+
*/
|
|
279
|
+
export function getEndpointContract(context, endpoint) {
|
|
280
|
+
return context.endpoints.get(endpoint);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get type mapping for a specific type
|
|
284
|
+
*/
|
|
285
|
+
export function getTypeContract(context, typeName) {
|
|
286
|
+
return context.types.get(typeName);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Check if a service has a matching backend route
|
|
290
|
+
*/
|
|
291
|
+
export function hasMatchingRoute(context, service) {
|
|
292
|
+
return context.endpoints.has(service.endpoint);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Get all unmatched frontend services
|
|
296
|
+
*/
|
|
297
|
+
export function getUnmatchedFrontendServices(context) {
|
|
298
|
+
return context.unmatchedFrontend;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get all unmatched backend routes
|
|
302
|
+
*/
|
|
303
|
+
export function getUnmatchedBackendRoutes(context) {
|
|
304
|
+
return context.unmatchedBackend;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/api-contract/context/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Frontend Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds the frontend context by extracting services, types, and configuration.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import type { FrontendContext, FrontendProject } from "../types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Build frontend context from a project path
|
|
11
|
+
* Extracts services, types, and API configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildFrontendContext(project: FrontendProject): Promise<FrontendContext>;
|
|
14
|
+
/**
|
|
15
|
+
* Incrementally update frontend context when a file changes
|
|
16
|
+
* Only re-extracts from the changed file
|
|
17
|
+
*/
|
|
18
|
+
export declare function updateFrontendContext(context: FrontendContext, projectPath: string, changedFile: string): Promise<FrontendContext>;
|
|
19
|
+
//# sourceMappingURL=frontend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend.d.ts","sourceRoot":"","sources":["../../../src/api-contract/context/frontend.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOpE;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,eAAe,CAAC,CA0B1B;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CAoC1B"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Frontend Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds the frontend context by extracting services, types, and configuration.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "../../utils/logger.js";
|
|
9
|
+
import { extractServices, extractTypes, extractApiConfig, } from "../extractors/typescript.js";
|
|
10
|
+
/**
|
|
11
|
+
* Build frontend context from a project path
|
|
12
|
+
* Extracts services, types, and API configuration
|
|
13
|
+
*/
|
|
14
|
+
export async function buildFrontendContext(project) {
|
|
15
|
+
logger.info(`Building frontend context for ${project.framework} project...`);
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
// Extract services and types in parallel
|
|
18
|
+
const [services, types, config] = await Promise.all([
|
|
19
|
+
extractServices(project.path),
|
|
20
|
+
extractTypes(project.path),
|
|
21
|
+
extractApiConfig(project.path),
|
|
22
|
+
]);
|
|
23
|
+
const context = {
|
|
24
|
+
framework: project.framework,
|
|
25
|
+
services,
|
|
26
|
+
types,
|
|
27
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
28
|
+
httpClient: config.httpClient,
|
|
29
|
+
};
|
|
30
|
+
logger.info(`Frontend context built in ${Date.now() - startTime}ms ` +
|
|
31
|
+
`(${services.length} services, ${types.length} types)`);
|
|
32
|
+
return context;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Incrementally update frontend context when a file changes
|
|
36
|
+
* Only re-extracts from the changed file
|
|
37
|
+
*/
|
|
38
|
+
export async function updateFrontendContext(context, projectPath, changedFile) {
|
|
39
|
+
logger.debug(`Updating frontend context for changed file: ${changedFile}`);
|
|
40
|
+
// Remove old entries from this file
|
|
41
|
+
context.services = context.services.filter((s) => !s.file.includes(changedFile));
|
|
42
|
+
context.types = context.types.filter((t) => !t.file.includes(changedFile));
|
|
43
|
+
// Re-extract from changed file if it's a relevant file
|
|
44
|
+
if (changedFile.includes("/services/") ||
|
|
45
|
+
changedFile.includes("/api/") ||
|
|
46
|
+
changedFile.includes("/types/") ||
|
|
47
|
+
changedFile.includes("/interfaces/")) {
|
|
48
|
+
try {
|
|
49
|
+
const fs = await import("fs/promises");
|
|
50
|
+
const content = await fs.readFile(changedFile, "utf-8");
|
|
51
|
+
// Import extractors dynamically to avoid circular dependencies
|
|
52
|
+
const { extractServicesFromFile, extractTypesFromFile } = await import("../extractors/typescript.js");
|
|
53
|
+
const newServices = extractServicesFromFile(content, changedFile);
|
|
54
|
+
const newTypes = extractTypesFromFile(content, changedFile);
|
|
55
|
+
context.services.push(...newServices);
|
|
56
|
+
context.types.push(...newTypes);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
logger.debug(`Failed to update context for ${changedFile}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return context;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=frontend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend.js","sourceRoot":"","sources":["../../../src/api-contract/context/frontend.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EACL,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAwB;IAExB,MAAM,CAAC,IAAI,CAAC,iCAAiC,OAAO,CAAC,SAAS,aAAa,CAAC,CAAC;IAE7E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,yCAAyC;IACzC,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7B,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1B,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC;KAC/B,CAAC,CAAC;IAEH,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ;QACR,KAAK;QACL,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,KAAK;QACtD,IAAI,QAAQ,CAAC,MAAM,cAAc,KAAK,CAAC,MAAM,SAAS,CACzD,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAwB,EACxB,WAAmB,EACnB,WAAmB;IAEnB,MAAM,CAAC,KAAK,CAAC,+CAA+C,WAAW,EAAE,CAAC,CAAC;IAE3E,oCAAoC;IACpC,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CACrC,CAAC;IACF,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;IAE3E,uDAAuD;IACvD,IACE,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC;QAClC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC7B,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC/B,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,EACpC,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAExD,+DAA+D;YAC/D,MAAM,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CACpE,6BAA6B,CAC9B,CAAC;YAEF,MAAM,WAAW,GAAG,uBAAuB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAClE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAE5D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,gCAAgC,WAAW,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Guardian - Project Detector
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects project structure (frontend/backend) without configuration.
|
|
5
|
+
*
|
|
6
|
+
* @format
|
|
7
|
+
*/
|
|
8
|
+
import type { ProjectStructure, FrontendFramework, BackendFramework } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Detect project structure automatically
|
|
11
|
+
* Scans for frontend and backend projects in the given root path
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectProjectStructure(rootPath: string): Promise<ProjectStructure>;
|
|
14
|
+
/**
|
|
15
|
+
* Create project structure from manual configuration
|
|
16
|
+
* Used when auto-detection fails or is disabled
|
|
17
|
+
*/
|
|
18
|
+
export declare function createProjectStructureFromConfig(config: {
|
|
19
|
+
frontend?: {
|
|
20
|
+
path: string;
|
|
21
|
+
framework: FrontendFramework;
|
|
22
|
+
};
|
|
23
|
+
backend?: {
|
|
24
|
+
path: string;
|
|
25
|
+
framework: BackendFramework;
|
|
26
|
+
};
|
|
27
|
+
}): ProjectStructure;
|
|
28
|
+
//# sourceMappingURL=detector.d.ts.map
|