codemap-ai 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-Q4IB4JZ6.js → chunk-LXZ73T7X.js} +3 -3
- package/dist/{chunk-X54UKOJM.js.map → chunk-LXZ73T7X.js.map} +1 -1
- package/dist/{chunk-X54UKOJM.js → chunk-VB74K47A.js} +3 -3
- package/dist/{chunk-Q4IB4JZ6.js.map → chunk-VB74K47A.js.map} +1 -1
- package/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/dist/{flow-server-4LJZBCB4.js → flow-server-B2SVQKDG.js} +3 -3
- package/dist/{flow-server-4LJZBCB4.js.map → flow-server-B2SVQKDG.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
|
@@ -726,11 +726,11 @@ var FlowStorage = class {
|
|
|
726
726
|
* Get all file hashes (for detecting changes)
|
|
727
727
|
*/
|
|
728
728
|
getAllFileHashes() {
|
|
729
|
-
const stmt = this.db.prepare("SELECT
|
|
729
|
+
const stmt = this.db.prepare("SELECT path, hash FROM files WHERE hash IS NOT NULL");
|
|
730
730
|
const rows = stmt.all();
|
|
731
731
|
const hashes = {};
|
|
732
732
|
for (const row of rows) {
|
|
733
|
-
hashes[row.
|
|
733
|
+
hashes[row.path] = row.hash;
|
|
734
734
|
}
|
|
735
735
|
return hashes;
|
|
736
736
|
}
|
|
@@ -775,4 +775,4 @@ var FlowStorage = class {
|
|
|
775
775
|
export {
|
|
776
776
|
FlowStorage
|
|
777
777
|
};
|
|
778
|
-
//# sourceMappingURL=chunk-
|
|
778
|
+
//# sourceMappingURL=chunk-LXZ73T7X.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/flow/storage.ts"],"sourcesContent":["/**\n * Flow-focused storage for call graphs\n * Simplified from graph/storage.ts with enhanced call resolution\n */\n\nimport Database from \"better-sqlite3\";\nimport type { GraphNode, GraphEdge } from \"../types.js\";\n\nexport interface CallPath {\n nodes: Array<{\n id: string;\n name: string;\n file: string;\n line: number;\n }>;\n edges: Array<{\n from: string;\n to: string;\n type: string;\n }>;\n}\n\nexport class FlowStorage {\n public db: Database.Database; // Public for builder to access\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n -- Nodes table (enhanced with hash)\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n language TEXT NOT NULL,\n hash TEXT,\n metadata TEXT\n );\n\n -- Edges table (calls and related edges)\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Files table\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n language TEXT NOT NULL,\n hash TEXT NOT NULL,\n analyzed_at TEXT NOT NULL\n );\n\n -- Exports: symbols exported by each file\n CREATE TABLE IF NOT EXISTS exports (\n file_path TEXT NOT NULL,\n symbol_name TEXT NOT NULL,\n node_id TEXT NOT NULL,\n PRIMARY KEY (file_path, symbol_name)\n );\n\n -- Imports: what each file imports and from where\n CREATE TABLE IF NOT EXISTS imports (\n file_path TEXT NOT NULL,\n imported_symbol TEXT NOT NULL,\n from_module TEXT NOT NULL,\n resolved_node_id TEXT,\n line INTEGER NOT NULL\n );\n\n -- Containers (Docker services)\n CREATE TABLE IF NOT EXISTS containers (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n image TEXT,\n ports TEXT,\n environment TEXT,\n depends_on TEXT,\n networks TEXT,\n metadata TEXT\n );\n\n -- HTTP Endpoints (API routes)\n CREATE TABLE IF NOT EXISTS http_endpoints (\n id TEXT PRIMARY KEY,\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n handler_node_id TEXT,\n container_id TEXT,\n middleware TEXT,\n metadata TEXT\n );\n\n -- HTTP Calls (client requests)\n CREATE TABLE IF NOT EXISTS http_calls (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_endpoint_id TEXT,\n url TEXT NOT NULL,\n method TEXT NOT NULL,\n line INTEGER,\n metadata TEXT\n );\n\n -- Framework Dependencies (FastAPI Depends, etc.)\n CREATE TABLE IF NOT EXISTS framework_dependencies (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_node_id TEXT,\n framework TEXT NOT NULL,\n pattern TEXT NOT NULL,\n parameter_name TEXT,\n line INTEGER,\n unresolved_name TEXT,\n metadata TEXT\n );\n\n -- Database Operations\n CREATE TABLE IF NOT EXISTS database_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n database_type TEXT NOT NULL,\n operation TEXT NOT NULL,\n collection TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Message Queue Operations\n CREATE TABLE IF NOT EXISTS message_queue_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n operation TEXT NOT NULL,\n exchange TEXT,\n routing_key TEXT,\n queue TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Variable Type Tracking\n CREATE TABLE IF NOT EXISTS variable_types (\n id TEXT PRIMARY KEY,\n variable_name TEXT NOT NULL,\n type_name TEXT NOT NULL,\n scope_node_id TEXT NOT NULL,\n file_path TEXT NOT NULL,\n line INTEGER NOT NULL,\n is_parameter BOOLEAN DEFAULT 0,\n metadata TEXT\n );\n\n -- Indexes for fast queries\n CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);\n CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);\n CREATE INDEX IF NOT EXISTS idx_nodes_hash ON nodes(hash);\n CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_edges_resolved ON edges(target_id) WHERE target_id NOT LIKE 'ref:%';\n CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);\n CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);\n CREATE INDEX IF NOT EXISTS idx_http_endpoints_path ON http_endpoints(method, path);\n CREATE INDEX IF NOT EXISTS idx_http_calls_url ON http_calls(url);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_source ON framework_dependencies(source_node_id);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_target ON framework_dependencies(target_node_id);\n CREATE INDEX IF NOT EXISTS idx_variable_types_scope ON variable_types(scope_node_id, variable_name);\n CREATE INDEX IF NOT EXISTS idx_variable_types_file ON variable_types(file_path, variable_name);\n `);\n }\n\n // ============ Node Operations ============\n\n insertNode(node: GraphNode & { hash?: string }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, hash, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n node.id,\n node.type,\n node.name,\n node.filePath,\n node.startLine,\n node.endLine,\n node.language,\n node.hash || null,\n node.metadata ? JSON.stringify(node.metadata) : null\n );\n }\n\n getNode(id: string): GraphNode | null {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n searchNodesByName(name: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE name = ? OR name LIKE ?\");\n const rows = stmt.all(name, `%${name}%`) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n getNodesByFile(filePath: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE file_path = ?\");\n const rows = stmt.all(filePath) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n private rowToNode(row: Record<string, unknown>): GraphNode {\n return {\n id: row.id as string,\n type: row.type as GraphNode[\"type\"],\n name: row.name as string,\n filePath: row.file_path as string,\n startLine: row.start_line as number,\n endLine: row.end_line as number,\n language: row.language as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n };\n }\n\n // ============ Edge Operations ============\n\n insertEdge(edge: GraphEdge): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)\n VALUES (?, ?, ?, ?, ?)\n `);\n stmt.run(\n edge.id,\n edge.type,\n edge.sourceId,\n edge.targetId,\n edge.metadata ? JSON.stringify(edge.metadata) : null\n );\n }\n\n // ============ Call Graph Queries ============\n\n /**\n * Get all resolved callees (functions this node calls)\n */\n getResolvedCallees(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.target_id\n WHERE e.source_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get all resolved callers (functions that call this node)\n */\n getResolvedCallers(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.source_id\n WHERE e.target_id = ? AND e.type = 'calls'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get impact: all nodes affected by changes to this node (BFS traversal)\n */\n getImpactedNodes(nodeId: string, maxDepth: number = 3): GraphNode[] {\n const visited = new Set<string>();\n const result: GraphNode[] = [];\n const queue: Array<{ id: string; depth: number }> = [{ id: nodeId, depth: 0 }];\n\n while (queue.length > 0) {\n const { id, depth } = queue.shift()!;\n\n if (visited.has(id) || depth > maxDepth) continue;\n visited.add(id);\n\n const callers = this.getResolvedCallers(id);\n for (const caller of callers) {\n if (!visited.has(caller.id)) {\n result.push(caller);\n queue.push({ id: caller.id, depth: depth + 1 });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Trace call path from source to target using BFS\n */\n traceCallPath(fromId: string, toId: string): CallPath | null {\n const visited = new Set<string>();\n const parent = new Map<string, { nodeId: string; edgeType: string }>();\n const queue: string[] = [fromId];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current === toId) {\n // Reconstruct path\n const path: string[] = [];\n let node = toId;\n while (node !== fromId) {\n path.unshift(node);\n node = parent.get(node)!.nodeId;\n }\n path.unshift(fromId);\n\n // Get node details\n const nodes = path.map((id) => {\n const n = this.getNode(id);\n return {\n id: n!.id,\n name: n!.name,\n file: n!.filePath,\n line: n!.startLine,\n };\n });\n\n const edges = [];\n for (let i = 0; i < path.length - 1; i++) {\n edges.push({\n from: path[i],\n to: path[i + 1],\n type: 'calls',\n });\n }\n\n return { nodes, edges };\n }\n\n if (visited.has(current)) continue;\n visited.add(current);\n\n const callees = this.getResolvedCallees(current);\n for (const callee of callees) {\n if (!visited.has(callee.id)) {\n parent.set(callee.id, { nodeId: current, edgeType: 'calls' });\n queue.push(callee.id);\n }\n }\n }\n\n return null;\n }\n\n // ============ Export/Import Tracking ============\n\n registerExport(filePath: string, symbolName: string, nodeId: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO exports (file_path, symbol_name, node_id)\n VALUES (?, ?, ?)\n `);\n stmt.run(filePath, symbolName, nodeId);\n }\n\n registerImport(filePath: string, symbol: string, fromModule: string, line: number): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO imports (file_path, imported_symbol, from_module, line)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, symbol, fromModule, line);\n }\n\n resolveImport(filePath: string, symbol: string): string | null {\n // Get the import statement\n const importStmt = this.db.prepare(`\n SELECT from_module FROM imports WHERE file_path = ? AND imported_symbol = ?\n `).get(filePath, symbol) as { from_module: string } | undefined;\n\n if (!importStmt) return null;\n\n // Convert module path to possible file paths\n // Examples:\n // - \"backend.authentication\" -> [\"backend/authentication.py\", \"backend/authentication/__init__.py\"]\n // - \"..authentication\" -> relative import (handle separately)\n const modulePath = importStmt.from_module;\n const possiblePaths = this.resolvePythonModulePath(filePath, modulePath);\n\n // Try each possible path\n for (const targetPath of possiblePaths) {\n const exportStmt = this.db.prepare(`\n SELECT node_id FROM exports WHERE file_path = ? AND symbol_name = ?\n `).get(targetPath, symbol) as { node_id: string } | undefined;\n\n if (exportStmt) {\n return exportStmt.node_id;\n }\n }\n\n return null;\n }\n\n /**\n * Resolve a Python module path to possible file paths\n * Handles: absolute imports, relative imports, __init__.py\n */\n private resolvePythonModulePath(currentFile: string, modulePath: string): string[] {\n const possiblePaths: string[] = [];\n\n // Handle relative imports (from . import x, from .. import y)\n if (modulePath.startsWith(\".\")) {\n const currentDir = currentFile.substring(0, currentFile.lastIndexOf(\"/\"));\n const depth = modulePath.match(/^\\.+/)?.[0].length || 0;\n const moduleName = modulePath.replace(/^\\.+/, \"\");\n\n // Go up directories based on depth\n let targetDir = currentDir;\n for (let i = 1; i < depth; i++) {\n const lastSlash = targetDir.lastIndexOf(\"/\");\n if (lastSlash > 0) {\n targetDir = targetDir.substring(0, lastSlash);\n }\n }\n\n if (moduleName) {\n const relativePath = moduleName.replace(/\\./g, \"/\");\n possiblePaths.push(`${targetDir}/${relativePath}.py`);\n possiblePaths.push(`${targetDir}/${relativePath}/__init__.py`);\n } else {\n possiblePaths.push(`${targetDir}/__init__.py`);\n }\n } else {\n // Absolute import - convert dots to slashes\n const pathComponents = modulePath.split(\".\");\n\n // Try different interpretations\n // 1. Full path as file: backend.authentication -> backend/authentication.py\n const filePath = pathComponents.join(\"/\");\n possiblePaths.push(`${filePath}.py`);\n possiblePaths.push(`${filePath}/__init__.py`);\n\n // 2. Try with src/ prefix (common pattern)\n possiblePaths.push(`src/${filePath}.py`);\n possiblePaths.push(`src/${filePath}/__init__.py`);\n\n // 3. Query actual files to find match\n // Get all files that end with the last component\n const lastComponent = pathComponents[pathComponents.length - 1];\n const matchingFiles = this.db.prepare(`\n SELECT DISTINCT file_path FROM exports\n WHERE file_path LIKE ?\n `).all(`%/${lastComponent}.py`) as Array<{ file_path: string }>;\n\n for (const file of matchingFiles) {\n // Check if the file path ends with the module path\n const normalizedFilePath = file.file_path.replace(/\\\\/g, \"/\");\n if (normalizedFilePath.includes(filePath)) {\n possiblePaths.push(normalizedFilePath);\n }\n }\n }\n\n return possiblePaths;\n }\n\n /**\n * Resolve a class method call like ClassName.method_name\n * Handles: static methods, class methods, imported classes\n */\n resolveClassMethod(className: string, methodName: string, callerFilePath: string): string | null {\n // Strategy 1: Check if the class is imported in the caller file\n const classNodeId = this.resolveImport(callerFilePath, className);\n\n if (classNodeId) {\n // Find the method within this class\n const methods = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'contains'\n `).all(classNodeId) as Array<{ target_id: string }>;\n\n for (const edge of methods) {\n const methodNode = this.getNode(edge.target_id);\n if (methodNode && methodNode.name === methodName) {\n return methodNode.id;\n }\n }\n }\n\n // Strategy 2: Search for class in the same file\n const classNode = this.db.prepare(`\n SELECT id FROM nodes\n WHERE file_path = ? AND name = ? AND type = 'class'\n `).get(callerFilePath, className) as { id: string } | undefined;\n\n if (classNode) {\n // Find the method within this class\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(classNode.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n // Strategy 3: Search globally for the class\n const allClasses = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).all(className) as Array<{ id: string }>;\n\n for (const cls of allClasses) {\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(cls.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n return null;\n }\n\n // ============ Variable Type Tracking ============\n\n /**\n * Register a variable type (from assignment or parameter)\n */\n registerVariableType(\n variableName: string,\n typeName: string,\n scopeNodeId: string,\n filePath: string,\n line: number,\n isParameter: boolean = false\n ): void {\n const id = `${scopeNodeId}:var:${variableName}`;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO variable_types\n (id, variable_name, type_name, scope_node_id, file_path, line, is_parameter)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(id, variableName, typeName, scopeNodeId, filePath, line, isParameter ? 1 : 0);\n }\n\n /**\n * Resolve variable.method to actual method node\n * Example: user.get_name() where user is of type User\n */\n resolveVariableMethod(variableName: string, methodName: string, scopeNodeId: string): string | null {\n // Special case: self.method calls - resolve to methods in parent class\n if (variableName === \"self\") {\n return this.resolveSelfMethod(methodName, scopeNodeId);\n }\n\n // Get the variable's type\n const varType = this.db.prepare(`\n SELECT type_name FROM variable_types\n WHERE scope_node_id = ? AND variable_name = ?\n `).get(scopeNodeId, variableName) as { type_name: string } | undefined;\n\n if (!varType) {\n return null;\n }\n\n // Now resolve ClassName.method_name\n return this.resolveClassMethod(varType.type_name, methodName, \"\");\n }\n\n /**\n * Resolve self.method() calls to methods in the same class\n */\n private resolveSelfMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of this method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Find the method with this name in the same class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(parentClass.source_id, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n /**\n * Resolve super().method() calls to parent class methods\n */\n resolveSuperMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of the current method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Get the class node\n const classNode = this.getNode(parentClass.source_id);\n if (!classNode || classNode.type !== 'class') {\n return null;\n }\n\n // Find the parent class (via extends edge)\n const baseClass = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'extends'\n `).get(classNode.id) as { target_id: string } | undefined;\n\n if (!baseClass) {\n return null;\n }\n\n // The target might be a ref, resolve it first\n let baseClassId = baseClass.target_id;\n if (baseClassId.startsWith('ref:')) {\n const baseClassName = baseClassId.replace('ref:', '');\n // Search for the class by name\n const resolvedClass = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).get(baseClassName) as { id: string } | undefined;\n\n if (!resolvedClass) {\n return null;\n }\n baseClassId = resolvedClass.id;\n }\n\n // Find the method in the parent class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(baseClassId, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n // ============ File Operations ============\n\n upsertFile(filePath: string, language: string, hash: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO files (path, language, hash, analyzed_at)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, language, hash, new Date().toISOString());\n }\n\n getFileHash(filePath: string): string | null {\n const stmt = this.db.prepare(\"SELECT hash FROM files WHERE path = ?\");\n const row = stmt.get(filePath) as { hash: string } | undefined;\n return row?.hash || null;\n }\n\n deleteFileData(filePath: string): void {\n this.db.prepare(\"DELETE FROM nodes WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM exports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM imports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(filePath);\n }\n\n // ============ Stats ============\n\n getStats(): {\n totalFiles: number;\n totalNodes: number;\n totalEdges: number;\n resolvedCalls: number;\n unresolvedCalls: number;\n httpEndpoints: number;\n frameworkDependencies: number;\n resolvedDependencies: number;\n containers: number;\n } {\n const totalFiles = (this.db.prepare(\"SELECT COUNT(*) as count FROM files\").get() as { count: number }).count;\n const totalNodes = (this.db.prepare(\"SELECT COUNT(*) as count FROM nodes\").get() as { count: number }).count;\n const totalEdges = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls'\").get() as { count: number }).count;\n const resolvedCalls = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls' AND target_id NOT LIKE 'ref:%'\").get() as { count: number }).count;\n const unresolvedCalls = totalEdges - resolvedCalls;\n const httpEndpoints = (this.db.prepare(\"SELECT COUNT(*) as count FROM http_endpoints\").get() as { count: number }).count;\n const frameworkDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies\").get() as { count: number }).count;\n const resolvedDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies WHERE target_node_id IS NOT NULL\").get() as { count: number }).count;\n const containers = (this.db.prepare(\"SELECT COUNT(*) as count FROM containers\").get() as { count: number }).count;\n\n return {\n totalFiles,\n totalNodes,\n totalEdges,\n resolvedCalls,\n unresolvedCalls,\n httpEndpoints,\n frameworkDependencies,\n resolvedDependencies,\n containers,\n };\n }\n\n // ============ Container Operations ============\n\n insertContainer(container: {\n id: string;\n name: string;\n image?: string;\n ports?: Array<{ host: number; container: number }>;\n environment?: Record<string, string>;\n depends_on?: string[];\n networks?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO containers (id, name, image, ports, environment, depends_on, networks, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n container.id,\n container.name,\n container.image || null,\n container.ports ? JSON.stringify(container.ports) : null,\n container.environment ? JSON.stringify(container.environment) : null,\n container.depends_on ? JSON.stringify(container.depends_on) : null,\n container.networks ? JSON.stringify(container.networks) : null,\n container.metadata ? JSON.stringify(container.metadata) : null\n );\n }\n\n getContainer(id: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM containers WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n getAllContainers(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM containers\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n // ============ HTTP Endpoint Operations ============\n\n insertHttpEndpoint(endpoint: {\n id: string;\n method: string;\n path: string;\n handler_node_id?: string;\n container_id?: string;\n middleware?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO http_endpoints (id, method, path, handler_node_id, container_id, middleware, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n endpoint.id,\n endpoint.method,\n endpoint.path,\n endpoint.handler_node_id || null,\n endpoint.container_id || null,\n endpoint.middleware ? JSON.stringify(endpoint.middleware) : null,\n endpoint.metadata ? JSON.stringify(endpoint.metadata) : null\n );\n }\n\n insertDatabaseOperation(dbOp: {\n id: string;\n node_id: string;\n database_type: string;\n operation: string;\n collection?: string;\n line?: number;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO database_operations (id, node_id, database_type, operation, collection, line, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dbOp.id,\n dbOp.node_id,\n dbOp.database_type,\n dbOp.operation,\n dbOp.collection || null,\n dbOp.line || null,\n dbOp.metadata ? JSON.stringify(dbOp.metadata) : null\n );\n }\n\n findHttpEndpoint(method: string, path: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM http_endpoints WHERE method = ? AND path = ?\");\n const row = stmt.get(method, path) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n method: row.method,\n path: row.path,\n handler_node_id: row.handler_node_id,\n container_id: row.container_id,\n middleware: row.middleware ? JSON.parse(row.middleware as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n // ============ Framework Dependency Operations ============\n\n insertFrameworkDependency(dep: {\n id: string;\n source_node_id: string;\n target_node_id?: string;\n framework: string;\n pattern: string;\n parameter_name?: string;\n line?: number;\n unresolved_name?: string;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO framework_dependencies\n (id, source_node_id, target_node_id, framework, pattern, parameter_name, line, unresolved_name, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dep.id,\n dep.source_node_id,\n dep.target_node_id || null,\n dep.framework,\n dep.pattern,\n dep.parameter_name || null,\n dep.line || null,\n dep.unresolved_name || null,\n dep.metadata ? JSON.stringify(dep.metadata) : null\n );\n }\n\n getFrameworkDependencies(sourceNodeId: string): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE source_node_id = ?\");\n const rows = stmt.all(sourceNodeId) as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n target_node_id: row.target_node_id,\n framework: row.framework,\n pattern: row.pattern,\n parameter_name: row.parameter_name,\n line: row.line,\n unresolved_name: row.unresolved_name,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n getAllUnresolvedDependencies(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE target_node_id IS NULL\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n framework: row.framework,\n pattern: row.pattern,\n unresolved_name: row.unresolved_name,\n line: row.line,\n }));\n }\n\n updateFrameworkDependencyTarget(id: string, targetNodeId: string): void {\n const stmt = this.db.prepare(\"UPDATE framework_dependencies SET target_node_id = ? WHERE id = ?\");\n stmt.run(targetNodeId, id);\n }\n\n clear(): void {\n this.db.exec(`\n DELETE FROM nodes;\n DELETE FROM edges;\n DELETE FROM files;\n DELETE FROM exports;\n DELETE FROM imports;\n DELETE FROM containers;\n DELETE FROM http_endpoints;\n DELETE FROM http_calls;\n DELETE FROM framework_dependencies;\n DELETE FROM database_operations;\n DELETE FROM message_queue_operations;\n `);\n }\n\n /**\n * Get all file hashes (for detecting changes)\n */\n getAllFileHashes(): Record<string, string> {\n const stmt = this.db.prepare(\"SELECT file_path, hash FROM files WHERE hash IS NOT NULL\");\n const rows = stmt.all() as Array<{ file_path: string; hash: string }>;\n const hashes: Record<string, string> = {};\n for (const row of rows) {\n hashes[row.file_path] = row.hash;\n }\n return hashes;\n }\n\n /**\n * Get all nodes (for impact comparison)\n */\n getAllNodes(): Array<{ id: string; name: string; type: string; filePath: string }> {\n const stmt = this.db.prepare(\"SELECT id, name, type, file_path FROM nodes\");\n return stmt.all() as Array<{ id: string; name: string; type: string; filePath: string }>;\n }\n\n /**\n * Get all edges (for impact comparison)\n */\n getAllEdges(): Array<{ id: string; source_id: string; target_id: string; type: string }> {\n const stmt = this.db.prepare(\"SELECT id, source_id, target_id, type FROM edges\");\n return stmt.all() as Array<{ id: string; source_id: string; target_id: string; type: string }>;\n }\n\n /**\n * Get resolved callers with file/line info (for impact analysis)\n */\n getResolvedCallersWithLocation(nodeId: string): Array<{ name: string; file: string; line: number }> {\n const stmt = this.db.prepare(`\n SELECT n.name, n.file_path as file, n.start_line as line\n FROM edges e\n JOIN nodes n ON e.source_id = n.id\n WHERE e.target_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n return stmt.all(nodeId) as Array<{ name: string; file: string; line: number }>;\n }\n\n /**\n * Get HTTP endpoints by handler node ID\n */\n getHttpEndpointsByHandler(handlerNodeId: string): Array<{ method: string; path: string }> {\n const stmt = this.db.prepare(\"SELECT method, path FROM http_endpoints WHERE handler_node_id = ?\");\n return stmt.all(handlerNodeId) as Array<{ method: string; path: string }>;\n }\n\n close(): void {\n this.db.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/flow/storage.ts"],"sourcesContent":["/**\n * Flow-focused storage for call graphs\n * Simplified from graph/storage.ts with enhanced call resolution\n */\n\nimport Database from \"better-sqlite3\";\nimport type { GraphNode, GraphEdge } from \"../types.js\";\n\nexport interface CallPath {\n nodes: Array<{\n id: string;\n name: string;\n file: string;\n line: number;\n }>;\n edges: Array<{\n from: string;\n to: string;\n type: string;\n }>;\n}\n\nexport class FlowStorage {\n public db: Database.Database; // Public for builder to access\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n -- Nodes table (enhanced with hash)\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n language TEXT NOT NULL,\n hash TEXT,\n metadata TEXT\n );\n\n -- Edges table (calls and related edges)\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Files table\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n language TEXT NOT NULL,\n hash TEXT NOT NULL,\n analyzed_at TEXT NOT NULL\n );\n\n -- Exports: symbols exported by each file\n CREATE TABLE IF NOT EXISTS exports (\n file_path TEXT NOT NULL,\n symbol_name TEXT NOT NULL,\n node_id TEXT NOT NULL,\n PRIMARY KEY (file_path, symbol_name)\n );\n\n -- Imports: what each file imports and from where\n CREATE TABLE IF NOT EXISTS imports (\n file_path TEXT NOT NULL,\n imported_symbol TEXT NOT NULL,\n from_module TEXT NOT NULL,\n resolved_node_id TEXT,\n line INTEGER NOT NULL\n );\n\n -- Containers (Docker services)\n CREATE TABLE IF NOT EXISTS containers (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n image TEXT,\n ports TEXT,\n environment TEXT,\n depends_on TEXT,\n networks TEXT,\n metadata TEXT\n );\n\n -- HTTP Endpoints (API routes)\n CREATE TABLE IF NOT EXISTS http_endpoints (\n id TEXT PRIMARY KEY,\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n handler_node_id TEXT,\n container_id TEXT,\n middleware TEXT,\n metadata TEXT\n );\n\n -- HTTP Calls (client requests)\n CREATE TABLE IF NOT EXISTS http_calls (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_endpoint_id TEXT,\n url TEXT NOT NULL,\n method TEXT NOT NULL,\n line INTEGER,\n metadata TEXT\n );\n\n -- Framework Dependencies (FastAPI Depends, etc.)\n CREATE TABLE IF NOT EXISTS framework_dependencies (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_node_id TEXT,\n framework TEXT NOT NULL,\n pattern TEXT NOT NULL,\n parameter_name TEXT,\n line INTEGER,\n unresolved_name TEXT,\n metadata TEXT\n );\n\n -- Database Operations\n CREATE TABLE IF NOT EXISTS database_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n database_type TEXT NOT NULL,\n operation TEXT NOT NULL,\n collection TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Message Queue Operations\n CREATE TABLE IF NOT EXISTS message_queue_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n operation TEXT NOT NULL,\n exchange TEXT,\n routing_key TEXT,\n queue TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Variable Type Tracking\n CREATE TABLE IF NOT EXISTS variable_types (\n id TEXT PRIMARY KEY,\n variable_name TEXT NOT NULL,\n type_name TEXT NOT NULL,\n scope_node_id TEXT NOT NULL,\n file_path TEXT NOT NULL,\n line INTEGER NOT NULL,\n is_parameter BOOLEAN DEFAULT 0,\n metadata TEXT\n );\n\n -- Indexes for fast queries\n CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);\n CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);\n CREATE INDEX IF NOT EXISTS idx_nodes_hash ON nodes(hash);\n CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_edges_resolved ON edges(target_id) WHERE target_id NOT LIKE 'ref:%';\n CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);\n CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);\n CREATE INDEX IF NOT EXISTS idx_http_endpoints_path ON http_endpoints(method, path);\n CREATE INDEX IF NOT EXISTS idx_http_calls_url ON http_calls(url);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_source ON framework_dependencies(source_node_id);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_target ON framework_dependencies(target_node_id);\n CREATE INDEX IF NOT EXISTS idx_variable_types_scope ON variable_types(scope_node_id, variable_name);\n CREATE INDEX IF NOT EXISTS idx_variable_types_file ON variable_types(file_path, variable_name);\n `);\n }\n\n // ============ Node Operations ============\n\n insertNode(node: GraphNode & { hash?: string }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, hash, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n node.id,\n node.type,\n node.name,\n node.filePath,\n node.startLine,\n node.endLine,\n node.language,\n node.hash || null,\n node.metadata ? JSON.stringify(node.metadata) : null\n );\n }\n\n getNode(id: string): GraphNode | null {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n searchNodesByName(name: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE name = ? OR name LIKE ?\");\n const rows = stmt.all(name, `%${name}%`) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n getNodesByFile(filePath: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE file_path = ?\");\n const rows = stmt.all(filePath) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n private rowToNode(row: Record<string, unknown>): GraphNode {\n return {\n id: row.id as string,\n type: row.type as GraphNode[\"type\"],\n name: row.name as string,\n filePath: row.file_path as string,\n startLine: row.start_line as number,\n endLine: row.end_line as number,\n language: row.language as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n };\n }\n\n // ============ Edge Operations ============\n\n insertEdge(edge: GraphEdge): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)\n VALUES (?, ?, ?, ?, ?)\n `);\n stmt.run(\n edge.id,\n edge.type,\n edge.sourceId,\n edge.targetId,\n edge.metadata ? JSON.stringify(edge.metadata) : null\n );\n }\n\n // ============ Call Graph Queries ============\n\n /**\n * Get all resolved callees (functions this node calls)\n */\n getResolvedCallees(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.target_id\n WHERE e.source_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get all resolved callers (functions that call this node)\n */\n getResolvedCallers(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.source_id\n WHERE e.target_id = ? AND e.type = 'calls'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get impact: all nodes affected by changes to this node (BFS traversal)\n */\n getImpactedNodes(nodeId: string, maxDepth: number = 3): GraphNode[] {\n const visited = new Set<string>();\n const result: GraphNode[] = [];\n const queue: Array<{ id: string; depth: number }> = [{ id: nodeId, depth: 0 }];\n\n while (queue.length > 0) {\n const { id, depth } = queue.shift()!;\n\n if (visited.has(id) || depth > maxDepth) continue;\n visited.add(id);\n\n const callers = this.getResolvedCallers(id);\n for (const caller of callers) {\n if (!visited.has(caller.id)) {\n result.push(caller);\n queue.push({ id: caller.id, depth: depth + 1 });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Trace call path from source to target using BFS\n */\n traceCallPath(fromId: string, toId: string): CallPath | null {\n const visited = new Set<string>();\n const parent = new Map<string, { nodeId: string; edgeType: string }>();\n const queue: string[] = [fromId];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current === toId) {\n // Reconstruct path\n const path: string[] = [];\n let node = toId;\n while (node !== fromId) {\n path.unshift(node);\n node = parent.get(node)!.nodeId;\n }\n path.unshift(fromId);\n\n // Get node details\n const nodes = path.map((id) => {\n const n = this.getNode(id);\n return {\n id: n!.id,\n name: n!.name,\n file: n!.filePath,\n line: n!.startLine,\n };\n });\n\n const edges = [];\n for (let i = 0; i < path.length - 1; i++) {\n edges.push({\n from: path[i],\n to: path[i + 1],\n type: 'calls',\n });\n }\n\n return { nodes, edges };\n }\n\n if (visited.has(current)) continue;\n visited.add(current);\n\n const callees = this.getResolvedCallees(current);\n for (const callee of callees) {\n if (!visited.has(callee.id)) {\n parent.set(callee.id, { nodeId: current, edgeType: 'calls' });\n queue.push(callee.id);\n }\n }\n }\n\n return null;\n }\n\n // ============ Export/Import Tracking ============\n\n registerExport(filePath: string, symbolName: string, nodeId: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO exports (file_path, symbol_name, node_id)\n VALUES (?, ?, ?)\n `);\n stmt.run(filePath, symbolName, nodeId);\n }\n\n registerImport(filePath: string, symbol: string, fromModule: string, line: number): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO imports (file_path, imported_symbol, from_module, line)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, symbol, fromModule, line);\n }\n\n resolveImport(filePath: string, symbol: string): string | null {\n // Get the import statement\n const importStmt = this.db.prepare(`\n SELECT from_module FROM imports WHERE file_path = ? AND imported_symbol = ?\n `).get(filePath, symbol) as { from_module: string } | undefined;\n\n if (!importStmt) return null;\n\n // Convert module path to possible file paths\n // Examples:\n // - \"backend.authentication\" -> [\"backend/authentication.py\", \"backend/authentication/__init__.py\"]\n // - \"..authentication\" -> relative import (handle separately)\n const modulePath = importStmt.from_module;\n const possiblePaths = this.resolvePythonModulePath(filePath, modulePath);\n\n // Try each possible path\n for (const targetPath of possiblePaths) {\n const exportStmt = this.db.prepare(`\n SELECT node_id FROM exports WHERE file_path = ? AND symbol_name = ?\n `).get(targetPath, symbol) as { node_id: string } | undefined;\n\n if (exportStmt) {\n return exportStmt.node_id;\n }\n }\n\n return null;\n }\n\n /**\n * Resolve a Python module path to possible file paths\n * Handles: absolute imports, relative imports, __init__.py\n */\n private resolvePythonModulePath(currentFile: string, modulePath: string): string[] {\n const possiblePaths: string[] = [];\n\n // Handle relative imports (from . import x, from .. import y)\n if (modulePath.startsWith(\".\")) {\n const currentDir = currentFile.substring(0, currentFile.lastIndexOf(\"/\"));\n const depth = modulePath.match(/^\\.+/)?.[0].length || 0;\n const moduleName = modulePath.replace(/^\\.+/, \"\");\n\n // Go up directories based on depth\n let targetDir = currentDir;\n for (let i = 1; i < depth; i++) {\n const lastSlash = targetDir.lastIndexOf(\"/\");\n if (lastSlash > 0) {\n targetDir = targetDir.substring(0, lastSlash);\n }\n }\n\n if (moduleName) {\n const relativePath = moduleName.replace(/\\./g, \"/\");\n possiblePaths.push(`${targetDir}/${relativePath}.py`);\n possiblePaths.push(`${targetDir}/${relativePath}/__init__.py`);\n } else {\n possiblePaths.push(`${targetDir}/__init__.py`);\n }\n } else {\n // Absolute import - convert dots to slashes\n const pathComponents = modulePath.split(\".\");\n\n // Try different interpretations\n // 1. Full path as file: backend.authentication -> backend/authentication.py\n const filePath = pathComponents.join(\"/\");\n possiblePaths.push(`${filePath}.py`);\n possiblePaths.push(`${filePath}/__init__.py`);\n\n // 2. Try with src/ prefix (common pattern)\n possiblePaths.push(`src/${filePath}.py`);\n possiblePaths.push(`src/${filePath}/__init__.py`);\n\n // 3. Query actual files to find match\n // Get all files that end with the last component\n const lastComponent = pathComponents[pathComponents.length - 1];\n const matchingFiles = this.db.prepare(`\n SELECT DISTINCT file_path FROM exports\n WHERE file_path LIKE ?\n `).all(`%/${lastComponent}.py`) as Array<{ file_path: string }>;\n\n for (const file of matchingFiles) {\n // Check if the file path ends with the module path\n const normalizedFilePath = file.file_path.replace(/\\\\/g, \"/\");\n if (normalizedFilePath.includes(filePath)) {\n possiblePaths.push(normalizedFilePath);\n }\n }\n }\n\n return possiblePaths;\n }\n\n /**\n * Resolve a class method call like ClassName.method_name\n * Handles: static methods, class methods, imported classes\n */\n resolveClassMethod(className: string, methodName: string, callerFilePath: string): string | null {\n // Strategy 1: Check if the class is imported in the caller file\n const classNodeId = this.resolveImport(callerFilePath, className);\n\n if (classNodeId) {\n // Find the method within this class\n const methods = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'contains'\n `).all(classNodeId) as Array<{ target_id: string }>;\n\n for (const edge of methods) {\n const methodNode = this.getNode(edge.target_id);\n if (methodNode && methodNode.name === methodName) {\n return methodNode.id;\n }\n }\n }\n\n // Strategy 2: Search for class in the same file\n const classNode = this.db.prepare(`\n SELECT id FROM nodes\n WHERE file_path = ? AND name = ? AND type = 'class'\n `).get(callerFilePath, className) as { id: string } | undefined;\n\n if (classNode) {\n // Find the method within this class\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(classNode.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n // Strategy 3: Search globally for the class\n const allClasses = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).all(className) as Array<{ id: string }>;\n\n for (const cls of allClasses) {\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(cls.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n return null;\n }\n\n // ============ Variable Type Tracking ============\n\n /**\n * Register a variable type (from assignment or parameter)\n */\n registerVariableType(\n variableName: string,\n typeName: string,\n scopeNodeId: string,\n filePath: string,\n line: number,\n isParameter: boolean = false\n ): void {\n const id = `${scopeNodeId}:var:${variableName}`;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO variable_types\n (id, variable_name, type_name, scope_node_id, file_path, line, is_parameter)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(id, variableName, typeName, scopeNodeId, filePath, line, isParameter ? 1 : 0);\n }\n\n /**\n * Resolve variable.method to actual method node\n * Example: user.get_name() where user is of type User\n */\n resolveVariableMethod(variableName: string, methodName: string, scopeNodeId: string): string | null {\n // Special case: self.method calls - resolve to methods in parent class\n if (variableName === \"self\") {\n return this.resolveSelfMethod(methodName, scopeNodeId);\n }\n\n // Get the variable's type\n const varType = this.db.prepare(`\n SELECT type_name FROM variable_types\n WHERE scope_node_id = ? AND variable_name = ?\n `).get(scopeNodeId, variableName) as { type_name: string } | undefined;\n\n if (!varType) {\n return null;\n }\n\n // Now resolve ClassName.method_name\n return this.resolveClassMethod(varType.type_name, methodName, \"\");\n }\n\n /**\n * Resolve self.method() calls to methods in the same class\n */\n private resolveSelfMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of this method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Find the method with this name in the same class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(parentClass.source_id, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n /**\n * Resolve super().method() calls to parent class methods\n */\n resolveSuperMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of the current method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Get the class node\n const classNode = this.getNode(parentClass.source_id);\n if (!classNode || classNode.type !== 'class') {\n return null;\n }\n\n // Find the parent class (via extends edge)\n const baseClass = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'extends'\n `).get(classNode.id) as { target_id: string } | undefined;\n\n if (!baseClass) {\n return null;\n }\n\n // The target might be a ref, resolve it first\n let baseClassId = baseClass.target_id;\n if (baseClassId.startsWith('ref:')) {\n const baseClassName = baseClassId.replace('ref:', '');\n // Search for the class by name\n const resolvedClass = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).get(baseClassName) as { id: string } | undefined;\n\n if (!resolvedClass) {\n return null;\n }\n baseClassId = resolvedClass.id;\n }\n\n // Find the method in the parent class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(baseClassId, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n // ============ File Operations ============\n\n upsertFile(filePath: string, language: string, hash: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO files (path, language, hash, analyzed_at)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, language, hash, new Date().toISOString());\n }\n\n getFileHash(filePath: string): string | null {\n const stmt = this.db.prepare(\"SELECT hash FROM files WHERE path = ?\");\n const row = stmt.get(filePath) as { hash: string } | undefined;\n return row?.hash || null;\n }\n\n deleteFileData(filePath: string): void {\n this.db.prepare(\"DELETE FROM nodes WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM exports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM imports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(filePath);\n }\n\n // ============ Stats ============\n\n getStats(): {\n totalFiles: number;\n totalNodes: number;\n totalEdges: number;\n resolvedCalls: number;\n unresolvedCalls: number;\n httpEndpoints: number;\n frameworkDependencies: number;\n resolvedDependencies: number;\n containers: number;\n } {\n const totalFiles = (this.db.prepare(\"SELECT COUNT(*) as count FROM files\").get() as { count: number }).count;\n const totalNodes = (this.db.prepare(\"SELECT COUNT(*) as count FROM nodes\").get() as { count: number }).count;\n const totalEdges = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls'\").get() as { count: number }).count;\n const resolvedCalls = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls' AND target_id NOT LIKE 'ref:%'\").get() as { count: number }).count;\n const unresolvedCalls = totalEdges - resolvedCalls;\n const httpEndpoints = (this.db.prepare(\"SELECT COUNT(*) as count FROM http_endpoints\").get() as { count: number }).count;\n const frameworkDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies\").get() as { count: number }).count;\n const resolvedDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies WHERE target_node_id IS NOT NULL\").get() as { count: number }).count;\n const containers = (this.db.prepare(\"SELECT COUNT(*) as count FROM containers\").get() as { count: number }).count;\n\n return {\n totalFiles,\n totalNodes,\n totalEdges,\n resolvedCalls,\n unresolvedCalls,\n httpEndpoints,\n frameworkDependencies,\n resolvedDependencies,\n containers,\n };\n }\n\n // ============ Container Operations ============\n\n insertContainer(container: {\n id: string;\n name: string;\n image?: string;\n ports?: Array<{ host: number; container: number }>;\n environment?: Record<string, string>;\n depends_on?: string[];\n networks?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO containers (id, name, image, ports, environment, depends_on, networks, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n container.id,\n container.name,\n container.image || null,\n container.ports ? JSON.stringify(container.ports) : null,\n container.environment ? JSON.stringify(container.environment) : null,\n container.depends_on ? JSON.stringify(container.depends_on) : null,\n container.networks ? JSON.stringify(container.networks) : null,\n container.metadata ? JSON.stringify(container.metadata) : null\n );\n }\n\n getContainer(id: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM containers WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n getAllContainers(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM containers\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n // ============ HTTP Endpoint Operations ============\n\n insertHttpEndpoint(endpoint: {\n id: string;\n method: string;\n path: string;\n handler_node_id?: string;\n container_id?: string;\n middleware?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO http_endpoints (id, method, path, handler_node_id, container_id, middleware, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n endpoint.id,\n endpoint.method,\n endpoint.path,\n endpoint.handler_node_id || null,\n endpoint.container_id || null,\n endpoint.middleware ? JSON.stringify(endpoint.middleware) : null,\n endpoint.metadata ? JSON.stringify(endpoint.metadata) : null\n );\n }\n\n insertDatabaseOperation(dbOp: {\n id: string;\n node_id: string;\n database_type: string;\n operation: string;\n collection?: string;\n line?: number;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO database_operations (id, node_id, database_type, operation, collection, line, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dbOp.id,\n dbOp.node_id,\n dbOp.database_type,\n dbOp.operation,\n dbOp.collection || null,\n dbOp.line || null,\n dbOp.metadata ? JSON.stringify(dbOp.metadata) : null\n );\n }\n\n findHttpEndpoint(method: string, path: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM http_endpoints WHERE method = ? AND path = ?\");\n const row = stmt.get(method, path) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n method: row.method,\n path: row.path,\n handler_node_id: row.handler_node_id,\n container_id: row.container_id,\n middleware: row.middleware ? JSON.parse(row.middleware as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n // ============ Framework Dependency Operations ============\n\n insertFrameworkDependency(dep: {\n id: string;\n source_node_id: string;\n target_node_id?: string;\n framework: string;\n pattern: string;\n parameter_name?: string;\n line?: number;\n unresolved_name?: string;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO framework_dependencies\n (id, source_node_id, target_node_id, framework, pattern, parameter_name, line, unresolved_name, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dep.id,\n dep.source_node_id,\n dep.target_node_id || null,\n dep.framework,\n dep.pattern,\n dep.parameter_name || null,\n dep.line || null,\n dep.unresolved_name || null,\n dep.metadata ? JSON.stringify(dep.metadata) : null\n );\n }\n\n getFrameworkDependencies(sourceNodeId: string): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE source_node_id = ?\");\n const rows = stmt.all(sourceNodeId) as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n target_node_id: row.target_node_id,\n framework: row.framework,\n pattern: row.pattern,\n parameter_name: row.parameter_name,\n line: row.line,\n unresolved_name: row.unresolved_name,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n getAllUnresolvedDependencies(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE target_node_id IS NULL\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n framework: row.framework,\n pattern: row.pattern,\n unresolved_name: row.unresolved_name,\n line: row.line,\n }));\n }\n\n updateFrameworkDependencyTarget(id: string, targetNodeId: string): void {\n const stmt = this.db.prepare(\"UPDATE framework_dependencies SET target_node_id = ? WHERE id = ?\");\n stmt.run(targetNodeId, id);\n }\n\n clear(): void {\n this.db.exec(`\n DELETE FROM nodes;\n DELETE FROM edges;\n DELETE FROM files;\n DELETE FROM exports;\n DELETE FROM imports;\n DELETE FROM containers;\n DELETE FROM http_endpoints;\n DELETE FROM http_calls;\n DELETE FROM framework_dependencies;\n DELETE FROM database_operations;\n DELETE FROM message_queue_operations;\n `);\n }\n\n /**\n * Get all file hashes (for detecting changes)\n */\n getAllFileHashes(): Record<string, string> {\n const stmt = this.db.prepare(\"SELECT path, hash FROM files WHERE hash IS NOT NULL\");\n const rows = stmt.all() as Array<{ path: string; hash: string }>;\n const hashes: Record<string, string> = {};\n for (const row of rows) {\n hashes[row.path] = row.hash;\n }\n return hashes;\n }\n\n /**\n * Get all nodes (for impact comparison)\n */\n getAllNodes(): Array<{ id: string; name: string; type: string; filePath: string }> {\n const stmt = this.db.prepare(\"SELECT id, name, type, file_path FROM nodes\");\n return stmt.all() as Array<{ id: string; name: string; type: string; filePath: string }>;\n }\n\n /**\n * Get all edges (for impact comparison)\n */\n getAllEdges(): Array<{ id: string; source_id: string; target_id: string; type: string }> {\n const stmt = this.db.prepare(\"SELECT id, source_id, target_id, type FROM edges\");\n return stmt.all() as Array<{ id: string; source_id: string; target_id: string; type: string }>;\n }\n\n /**\n * Get resolved callers with file/line info (for impact analysis)\n */\n getResolvedCallersWithLocation(nodeId: string): Array<{ name: string; file: string; line: number }> {\n const stmt = this.db.prepare(`\n SELECT n.name, n.file_path as file, n.start_line as line\n FROM edges e\n JOIN nodes n ON e.source_id = n.id\n WHERE e.target_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n return stmt.all(nodeId) as Array<{ name: string; file: string; line: number }>;\n }\n\n /**\n * Get HTTP endpoints by handler node ID\n */\n getHttpEndpointsByHandler(handlerNodeId: string): Array<{ method: string; path: string }> {\n const stmt = this.db.prepare(\"SELECT method, path FROM http_endpoints WHERE handler_node_id = ?\");\n return stmt.all(handlerNodeId) as Array<{ method: string; path: string }>;\n }\n\n close(): void {\n this.db.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -723,11 +723,11 @@ var FlowStorage = class {
|
|
|
723
723
|
* Get all file hashes (for detecting changes)
|
|
724
724
|
*/
|
|
725
725
|
getAllFileHashes() {
|
|
726
|
-
const stmt = this.db.prepare("SELECT
|
|
726
|
+
const stmt = this.db.prepare("SELECT path, hash FROM files WHERE hash IS NOT NULL");
|
|
727
727
|
const rows = stmt.all();
|
|
728
728
|
const hashes = {};
|
|
729
729
|
for (const row of rows) {
|
|
730
|
-
hashes[row.
|
|
730
|
+
hashes[row.path] = row.hash;
|
|
731
731
|
}
|
|
732
732
|
return hashes;
|
|
733
733
|
}
|
|
@@ -772,4 +772,4 @@ var FlowStorage = class {
|
|
|
772
772
|
export {
|
|
773
773
|
FlowStorage
|
|
774
774
|
};
|
|
775
|
-
//# sourceMappingURL=chunk-
|
|
775
|
+
//# sourceMappingURL=chunk-VB74K47A.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/flow/storage.ts"],"sourcesContent":["/**\n * Flow-focused storage for call graphs\n * Simplified from graph/storage.ts with enhanced call resolution\n */\n\nimport Database from \"better-sqlite3\";\nimport type { GraphNode, GraphEdge } from \"../types.js\";\n\nexport interface CallPath {\n nodes: Array<{\n id: string;\n name: string;\n file: string;\n line: number;\n }>;\n edges: Array<{\n from: string;\n to: string;\n type: string;\n }>;\n}\n\nexport class FlowStorage {\n public db: Database.Database; // Public for builder to access\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n -- Nodes table (enhanced with hash)\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n language TEXT NOT NULL,\n hash TEXT,\n metadata TEXT\n );\n\n -- Edges table (calls and related edges)\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Files table\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n language TEXT NOT NULL,\n hash TEXT NOT NULL,\n analyzed_at TEXT NOT NULL\n );\n\n -- Exports: symbols exported by each file\n CREATE TABLE IF NOT EXISTS exports (\n file_path TEXT NOT NULL,\n symbol_name TEXT NOT NULL,\n node_id TEXT NOT NULL,\n PRIMARY KEY (file_path, symbol_name)\n );\n\n -- Imports: what each file imports and from where\n CREATE TABLE IF NOT EXISTS imports (\n file_path TEXT NOT NULL,\n imported_symbol TEXT NOT NULL,\n from_module TEXT NOT NULL,\n resolved_node_id TEXT,\n line INTEGER NOT NULL\n );\n\n -- Containers (Docker services)\n CREATE TABLE IF NOT EXISTS containers (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n image TEXT,\n ports TEXT,\n environment TEXT,\n depends_on TEXT,\n networks TEXT,\n metadata TEXT\n );\n\n -- HTTP Endpoints (API routes)\n CREATE TABLE IF NOT EXISTS http_endpoints (\n id TEXT PRIMARY KEY,\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n handler_node_id TEXT,\n container_id TEXT,\n middleware TEXT,\n metadata TEXT\n );\n\n -- HTTP Calls (client requests)\n CREATE TABLE IF NOT EXISTS http_calls (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_endpoint_id TEXT,\n url TEXT NOT NULL,\n method TEXT NOT NULL,\n line INTEGER,\n metadata TEXT\n );\n\n -- Framework Dependencies (FastAPI Depends, etc.)\n CREATE TABLE IF NOT EXISTS framework_dependencies (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_node_id TEXT,\n framework TEXT NOT NULL,\n pattern TEXT NOT NULL,\n parameter_name TEXT,\n line INTEGER,\n unresolved_name TEXT,\n metadata TEXT\n );\n\n -- Database Operations\n CREATE TABLE IF NOT EXISTS database_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n database_type TEXT NOT NULL,\n operation TEXT NOT NULL,\n collection TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Message Queue Operations\n CREATE TABLE IF NOT EXISTS message_queue_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n operation TEXT NOT NULL,\n exchange TEXT,\n routing_key TEXT,\n queue TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Variable Type Tracking\n CREATE TABLE IF NOT EXISTS variable_types (\n id TEXT PRIMARY KEY,\n variable_name TEXT NOT NULL,\n type_name TEXT NOT NULL,\n scope_node_id TEXT NOT NULL,\n file_path TEXT NOT NULL,\n line INTEGER NOT NULL,\n is_parameter BOOLEAN DEFAULT 0,\n metadata TEXT\n );\n\n -- Indexes for fast queries\n CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);\n CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);\n CREATE INDEX IF NOT EXISTS idx_nodes_hash ON nodes(hash);\n CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_edges_resolved ON edges(target_id) WHERE target_id NOT LIKE 'ref:%';\n CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);\n CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);\n CREATE INDEX IF NOT EXISTS idx_http_endpoints_path ON http_endpoints(method, path);\n CREATE INDEX IF NOT EXISTS idx_http_calls_url ON http_calls(url);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_source ON framework_dependencies(source_node_id);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_target ON framework_dependencies(target_node_id);\n CREATE INDEX IF NOT EXISTS idx_variable_types_scope ON variable_types(scope_node_id, variable_name);\n CREATE INDEX IF NOT EXISTS idx_variable_types_file ON variable_types(file_path, variable_name);\n `);\n }\n\n // ============ Node Operations ============\n\n insertNode(node: GraphNode & { hash?: string }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, hash, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n node.id,\n node.type,\n node.name,\n node.filePath,\n node.startLine,\n node.endLine,\n node.language,\n node.hash || null,\n node.metadata ? JSON.stringify(node.metadata) : null\n );\n }\n\n getNode(id: string): GraphNode | null {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n searchNodesByName(name: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE name = ? OR name LIKE ?\");\n const rows = stmt.all(name, `%${name}%`) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n getNodesByFile(filePath: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE file_path = ?\");\n const rows = stmt.all(filePath) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n private rowToNode(row: Record<string, unknown>): GraphNode {\n return {\n id: row.id as string,\n type: row.type as GraphNode[\"type\"],\n name: row.name as string,\n filePath: row.file_path as string,\n startLine: row.start_line as number,\n endLine: row.end_line as number,\n language: row.language as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n };\n }\n\n // ============ Edge Operations ============\n\n insertEdge(edge: GraphEdge): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)\n VALUES (?, ?, ?, ?, ?)\n `);\n stmt.run(\n edge.id,\n edge.type,\n edge.sourceId,\n edge.targetId,\n edge.metadata ? JSON.stringify(edge.metadata) : null\n );\n }\n\n // ============ Call Graph Queries ============\n\n /**\n * Get all resolved callees (functions this node calls)\n */\n getResolvedCallees(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.target_id\n WHERE e.source_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get all resolved callers (functions that call this node)\n */\n getResolvedCallers(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.source_id\n WHERE e.target_id = ? AND e.type = 'calls'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get impact: all nodes affected by changes to this node (BFS traversal)\n */\n getImpactedNodes(nodeId: string, maxDepth: number = 3): GraphNode[] {\n const visited = new Set<string>();\n const result: GraphNode[] = [];\n const queue: Array<{ id: string; depth: number }> = [{ id: nodeId, depth: 0 }];\n\n while (queue.length > 0) {\n const { id, depth } = queue.shift()!;\n\n if (visited.has(id) || depth > maxDepth) continue;\n visited.add(id);\n\n const callers = this.getResolvedCallers(id);\n for (const caller of callers) {\n if (!visited.has(caller.id)) {\n result.push(caller);\n queue.push({ id: caller.id, depth: depth + 1 });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Trace call path from source to target using BFS\n */\n traceCallPath(fromId: string, toId: string): CallPath | null {\n const visited = new Set<string>();\n const parent = new Map<string, { nodeId: string; edgeType: string }>();\n const queue: string[] = [fromId];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current === toId) {\n // Reconstruct path\n const path: string[] = [];\n let node = toId;\n while (node !== fromId) {\n path.unshift(node);\n node = parent.get(node)!.nodeId;\n }\n path.unshift(fromId);\n\n // Get node details\n const nodes = path.map((id) => {\n const n = this.getNode(id);\n return {\n id: n!.id,\n name: n!.name,\n file: n!.filePath,\n line: n!.startLine,\n };\n });\n\n const edges = [];\n for (let i = 0; i < path.length - 1; i++) {\n edges.push({\n from: path[i],\n to: path[i + 1],\n type: 'calls',\n });\n }\n\n return { nodes, edges };\n }\n\n if (visited.has(current)) continue;\n visited.add(current);\n\n const callees = this.getResolvedCallees(current);\n for (const callee of callees) {\n if (!visited.has(callee.id)) {\n parent.set(callee.id, { nodeId: current, edgeType: 'calls' });\n queue.push(callee.id);\n }\n }\n }\n\n return null;\n }\n\n // ============ Export/Import Tracking ============\n\n registerExport(filePath: string, symbolName: string, nodeId: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO exports (file_path, symbol_name, node_id)\n VALUES (?, ?, ?)\n `);\n stmt.run(filePath, symbolName, nodeId);\n }\n\n registerImport(filePath: string, symbol: string, fromModule: string, line: number): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO imports (file_path, imported_symbol, from_module, line)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, symbol, fromModule, line);\n }\n\n resolveImport(filePath: string, symbol: string): string | null {\n // Get the import statement\n const importStmt = this.db.prepare(`\n SELECT from_module FROM imports WHERE file_path = ? AND imported_symbol = ?\n `).get(filePath, symbol) as { from_module: string } | undefined;\n\n if (!importStmt) return null;\n\n // Convert module path to possible file paths\n // Examples:\n // - \"backend.authentication\" -> [\"backend/authentication.py\", \"backend/authentication/__init__.py\"]\n // - \"..authentication\" -> relative import (handle separately)\n const modulePath = importStmt.from_module;\n const possiblePaths = this.resolvePythonModulePath(filePath, modulePath);\n\n // Try each possible path\n for (const targetPath of possiblePaths) {\n const exportStmt = this.db.prepare(`\n SELECT node_id FROM exports WHERE file_path = ? AND symbol_name = ?\n `).get(targetPath, symbol) as { node_id: string } | undefined;\n\n if (exportStmt) {\n return exportStmt.node_id;\n }\n }\n\n return null;\n }\n\n /**\n * Resolve a Python module path to possible file paths\n * Handles: absolute imports, relative imports, __init__.py\n */\n private resolvePythonModulePath(currentFile: string, modulePath: string): string[] {\n const possiblePaths: string[] = [];\n\n // Handle relative imports (from . import x, from .. import y)\n if (modulePath.startsWith(\".\")) {\n const currentDir = currentFile.substring(0, currentFile.lastIndexOf(\"/\"));\n const depth = modulePath.match(/^\\.+/)?.[0].length || 0;\n const moduleName = modulePath.replace(/^\\.+/, \"\");\n\n // Go up directories based on depth\n let targetDir = currentDir;\n for (let i = 1; i < depth; i++) {\n const lastSlash = targetDir.lastIndexOf(\"/\");\n if (lastSlash > 0) {\n targetDir = targetDir.substring(0, lastSlash);\n }\n }\n\n if (moduleName) {\n const relativePath = moduleName.replace(/\\./g, \"/\");\n possiblePaths.push(`${targetDir}/${relativePath}.py`);\n possiblePaths.push(`${targetDir}/${relativePath}/__init__.py`);\n } else {\n possiblePaths.push(`${targetDir}/__init__.py`);\n }\n } else {\n // Absolute import - convert dots to slashes\n const pathComponents = modulePath.split(\".\");\n\n // Try different interpretations\n // 1. Full path as file: backend.authentication -> backend/authentication.py\n const filePath = pathComponents.join(\"/\");\n possiblePaths.push(`${filePath}.py`);\n possiblePaths.push(`${filePath}/__init__.py`);\n\n // 2. Try with src/ prefix (common pattern)\n possiblePaths.push(`src/${filePath}.py`);\n possiblePaths.push(`src/${filePath}/__init__.py`);\n\n // 3. Query actual files to find match\n // Get all files that end with the last component\n const lastComponent = pathComponents[pathComponents.length - 1];\n const matchingFiles = this.db.prepare(`\n SELECT DISTINCT file_path FROM exports\n WHERE file_path LIKE ?\n `).all(`%/${lastComponent}.py`) as Array<{ file_path: string }>;\n\n for (const file of matchingFiles) {\n // Check if the file path ends with the module path\n const normalizedFilePath = file.file_path.replace(/\\\\/g, \"/\");\n if (normalizedFilePath.includes(filePath)) {\n possiblePaths.push(normalizedFilePath);\n }\n }\n }\n\n return possiblePaths;\n }\n\n /**\n * Resolve a class method call like ClassName.method_name\n * Handles: static methods, class methods, imported classes\n */\n resolveClassMethod(className: string, methodName: string, callerFilePath: string): string | null {\n // Strategy 1: Check if the class is imported in the caller file\n const classNodeId = this.resolveImport(callerFilePath, className);\n\n if (classNodeId) {\n // Find the method within this class\n const methods = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'contains'\n `).all(classNodeId) as Array<{ target_id: string }>;\n\n for (const edge of methods) {\n const methodNode = this.getNode(edge.target_id);\n if (methodNode && methodNode.name === methodName) {\n return methodNode.id;\n }\n }\n }\n\n // Strategy 2: Search for class in the same file\n const classNode = this.db.prepare(`\n SELECT id FROM nodes\n WHERE file_path = ? AND name = ? AND type = 'class'\n `).get(callerFilePath, className) as { id: string } | undefined;\n\n if (classNode) {\n // Find the method within this class\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(classNode.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n // Strategy 3: Search globally for the class\n const allClasses = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).all(className) as Array<{ id: string }>;\n\n for (const cls of allClasses) {\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(cls.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n return null;\n }\n\n // ============ Variable Type Tracking ============\n\n /**\n * Register a variable type (from assignment or parameter)\n */\n registerVariableType(\n variableName: string,\n typeName: string,\n scopeNodeId: string,\n filePath: string,\n line: number,\n isParameter: boolean = false\n ): void {\n const id = `${scopeNodeId}:var:${variableName}`;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO variable_types\n (id, variable_name, type_name, scope_node_id, file_path, line, is_parameter)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(id, variableName, typeName, scopeNodeId, filePath, line, isParameter ? 1 : 0);\n }\n\n /**\n * Resolve variable.method to actual method node\n * Example: user.get_name() where user is of type User\n */\n resolveVariableMethod(variableName: string, methodName: string, scopeNodeId: string): string | null {\n // Special case: self.method calls - resolve to methods in parent class\n if (variableName === \"self\") {\n return this.resolveSelfMethod(methodName, scopeNodeId);\n }\n\n // Get the variable's type\n const varType = this.db.prepare(`\n SELECT type_name FROM variable_types\n WHERE scope_node_id = ? AND variable_name = ?\n `).get(scopeNodeId, variableName) as { type_name: string } | undefined;\n\n if (!varType) {\n return null;\n }\n\n // Now resolve ClassName.method_name\n return this.resolveClassMethod(varType.type_name, methodName, \"\");\n }\n\n /**\n * Resolve self.method() calls to methods in the same class\n */\n private resolveSelfMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of this method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Find the method with this name in the same class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(parentClass.source_id, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n /**\n * Resolve super().method() calls to parent class methods\n */\n resolveSuperMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of the current method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Get the class node\n const classNode = this.getNode(parentClass.source_id);\n if (!classNode || classNode.type !== 'class') {\n return null;\n }\n\n // Find the parent class (via extends edge)\n const baseClass = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'extends'\n `).get(classNode.id) as { target_id: string } | undefined;\n\n if (!baseClass) {\n return null;\n }\n\n // The target might be a ref, resolve it first\n let baseClassId = baseClass.target_id;\n if (baseClassId.startsWith('ref:')) {\n const baseClassName = baseClassId.replace('ref:', '');\n // Search for the class by name\n const resolvedClass = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).get(baseClassName) as { id: string } | undefined;\n\n if (!resolvedClass) {\n return null;\n }\n baseClassId = resolvedClass.id;\n }\n\n // Find the method in the parent class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(baseClassId, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n // ============ File Operations ============\n\n upsertFile(filePath: string, language: string, hash: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO files (path, language, hash, analyzed_at)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, language, hash, new Date().toISOString());\n }\n\n getFileHash(filePath: string): string | null {\n const stmt = this.db.prepare(\"SELECT hash FROM files WHERE path = ?\");\n const row = stmt.get(filePath) as { hash: string } | undefined;\n return row?.hash || null;\n }\n\n deleteFileData(filePath: string): void {\n this.db.prepare(\"DELETE FROM nodes WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM exports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM imports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(filePath);\n }\n\n // ============ Stats ============\n\n getStats(): {\n totalFiles: number;\n totalNodes: number;\n totalEdges: number;\n resolvedCalls: number;\n unresolvedCalls: number;\n httpEndpoints: number;\n frameworkDependencies: number;\n resolvedDependencies: number;\n containers: number;\n } {\n const totalFiles = (this.db.prepare(\"SELECT COUNT(*) as count FROM files\").get() as { count: number }).count;\n const totalNodes = (this.db.prepare(\"SELECT COUNT(*) as count FROM nodes\").get() as { count: number }).count;\n const totalEdges = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls'\").get() as { count: number }).count;\n const resolvedCalls = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls' AND target_id NOT LIKE 'ref:%'\").get() as { count: number }).count;\n const unresolvedCalls = totalEdges - resolvedCalls;\n const httpEndpoints = (this.db.prepare(\"SELECT COUNT(*) as count FROM http_endpoints\").get() as { count: number }).count;\n const frameworkDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies\").get() as { count: number }).count;\n const resolvedDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies WHERE target_node_id IS NOT NULL\").get() as { count: number }).count;\n const containers = (this.db.prepare(\"SELECT COUNT(*) as count FROM containers\").get() as { count: number }).count;\n\n return {\n totalFiles,\n totalNodes,\n totalEdges,\n resolvedCalls,\n unresolvedCalls,\n httpEndpoints,\n frameworkDependencies,\n resolvedDependencies,\n containers,\n };\n }\n\n // ============ Container Operations ============\n\n insertContainer(container: {\n id: string;\n name: string;\n image?: string;\n ports?: Array<{ host: number; container: number }>;\n environment?: Record<string, string>;\n depends_on?: string[];\n networks?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO containers (id, name, image, ports, environment, depends_on, networks, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n container.id,\n container.name,\n container.image || null,\n container.ports ? JSON.stringify(container.ports) : null,\n container.environment ? JSON.stringify(container.environment) : null,\n container.depends_on ? JSON.stringify(container.depends_on) : null,\n container.networks ? JSON.stringify(container.networks) : null,\n container.metadata ? JSON.stringify(container.metadata) : null\n );\n }\n\n getContainer(id: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM containers WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n getAllContainers(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM containers\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n // ============ HTTP Endpoint Operations ============\n\n insertHttpEndpoint(endpoint: {\n id: string;\n method: string;\n path: string;\n handler_node_id?: string;\n container_id?: string;\n middleware?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO http_endpoints (id, method, path, handler_node_id, container_id, middleware, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n endpoint.id,\n endpoint.method,\n endpoint.path,\n endpoint.handler_node_id || null,\n endpoint.container_id || null,\n endpoint.middleware ? JSON.stringify(endpoint.middleware) : null,\n endpoint.metadata ? JSON.stringify(endpoint.metadata) : null\n );\n }\n\n insertDatabaseOperation(dbOp: {\n id: string;\n node_id: string;\n database_type: string;\n operation: string;\n collection?: string;\n line?: number;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO database_operations (id, node_id, database_type, operation, collection, line, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dbOp.id,\n dbOp.node_id,\n dbOp.database_type,\n dbOp.operation,\n dbOp.collection || null,\n dbOp.line || null,\n dbOp.metadata ? JSON.stringify(dbOp.metadata) : null\n );\n }\n\n findHttpEndpoint(method: string, path: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM http_endpoints WHERE method = ? AND path = ?\");\n const row = stmt.get(method, path) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n method: row.method,\n path: row.path,\n handler_node_id: row.handler_node_id,\n container_id: row.container_id,\n middleware: row.middleware ? JSON.parse(row.middleware as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n // ============ Framework Dependency Operations ============\n\n insertFrameworkDependency(dep: {\n id: string;\n source_node_id: string;\n target_node_id?: string;\n framework: string;\n pattern: string;\n parameter_name?: string;\n line?: number;\n unresolved_name?: string;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO framework_dependencies\n (id, source_node_id, target_node_id, framework, pattern, parameter_name, line, unresolved_name, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dep.id,\n dep.source_node_id,\n dep.target_node_id || null,\n dep.framework,\n dep.pattern,\n dep.parameter_name || null,\n dep.line || null,\n dep.unresolved_name || null,\n dep.metadata ? JSON.stringify(dep.metadata) : null\n );\n }\n\n getFrameworkDependencies(sourceNodeId: string): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE source_node_id = ?\");\n const rows = stmt.all(sourceNodeId) as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n target_node_id: row.target_node_id,\n framework: row.framework,\n pattern: row.pattern,\n parameter_name: row.parameter_name,\n line: row.line,\n unresolved_name: row.unresolved_name,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n getAllUnresolvedDependencies(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE target_node_id IS NULL\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n framework: row.framework,\n pattern: row.pattern,\n unresolved_name: row.unresolved_name,\n line: row.line,\n }));\n }\n\n updateFrameworkDependencyTarget(id: string, targetNodeId: string): void {\n const stmt = this.db.prepare(\"UPDATE framework_dependencies SET target_node_id = ? WHERE id = ?\");\n stmt.run(targetNodeId, id);\n }\n\n clear(): void {\n this.db.exec(`\n DELETE FROM nodes;\n DELETE FROM edges;\n DELETE FROM files;\n DELETE FROM exports;\n DELETE FROM imports;\n DELETE FROM containers;\n DELETE FROM http_endpoints;\n DELETE FROM http_calls;\n DELETE FROM framework_dependencies;\n DELETE FROM database_operations;\n DELETE FROM message_queue_operations;\n `);\n }\n\n /**\n * Get all file hashes (for detecting changes)\n */\n getAllFileHashes(): Record<string, string> {\n const stmt = this.db.prepare(\"SELECT file_path, hash FROM files WHERE hash IS NOT NULL\");\n const rows = stmt.all() as Array<{ file_path: string; hash: string }>;\n const hashes: Record<string, string> = {};\n for (const row of rows) {\n hashes[row.file_path] = row.hash;\n }\n return hashes;\n }\n\n /**\n * Get all nodes (for impact comparison)\n */\n getAllNodes(): Array<{ id: string; name: string; type: string; filePath: string }> {\n const stmt = this.db.prepare(\"SELECT id, name, type, file_path FROM nodes\");\n return stmt.all() as Array<{ id: string; name: string; type: string; filePath: string }>;\n }\n\n /**\n * Get all edges (for impact comparison)\n */\n getAllEdges(): Array<{ id: string; source_id: string; target_id: string; type: string }> {\n const stmt = this.db.prepare(\"SELECT id, source_id, target_id, type FROM edges\");\n return stmt.all() as Array<{ id: string; source_id: string; target_id: string; type: string }>;\n }\n\n /**\n * Get resolved callers with file/line info (for impact analysis)\n */\n getResolvedCallersWithLocation(nodeId: string): Array<{ name: string; file: string; line: number }> {\n const stmt = this.db.prepare(`\n SELECT n.name, n.file_path as file, n.start_line as line\n FROM edges e\n JOIN nodes n ON e.source_id = n.id\n WHERE e.target_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n return stmt.all(nodeId) as Array<{ name: string; file: string; line: number }>;\n }\n\n /**\n * Get HTTP endpoints by handler node ID\n */\n getHttpEndpointsByHandler(handlerNodeId: string): Array<{ method: string; path: string }> {\n const stmt = this.db.prepare(\"SELECT method, path FROM http_endpoints WHERE handler_node_id = ?\");\n return stmt.all(handlerNodeId) as Array<{ method: string; path: string }>;\n }\n\n close(): void {\n this.db.close();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/flow/storage.ts"],"sourcesContent":["/**\n * Flow-focused storage for call graphs\n * Simplified from graph/storage.ts with enhanced call resolution\n */\n\nimport Database from \"better-sqlite3\";\nimport type { GraphNode, GraphEdge } from \"../types.js\";\n\nexport interface CallPath {\n nodes: Array<{\n id: string;\n name: string;\n file: string;\n line: number;\n }>;\n edges: Array<{\n from: string;\n to: string;\n type: string;\n }>;\n}\n\nexport class FlowStorage {\n public db: Database.Database; // Public for builder to access\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n -- Nodes table (enhanced with hash)\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n language TEXT NOT NULL,\n hash TEXT,\n metadata TEXT\n );\n\n -- Edges table (calls and related edges)\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n metadata TEXT\n );\n\n -- Files table\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n language TEXT NOT NULL,\n hash TEXT NOT NULL,\n analyzed_at TEXT NOT NULL\n );\n\n -- Exports: symbols exported by each file\n CREATE TABLE IF NOT EXISTS exports (\n file_path TEXT NOT NULL,\n symbol_name TEXT NOT NULL,\n node_id TEXT NOT NULL,\n PRIMARY KEY (file_path, symbol_name)\n );\n\n -- Imports: what each file imports and from where\n CREATE TABLE IF NOT EXISTS imports (\n file_path TEXT NOT NULL,\n imported_symbol TEXT NOT NULL,\n from_module TEXT NOT NULL,\n resolved_node_id TEXT,\n line INTEGER NOT NULL\n );\n\n -- Containers (Docker services)\n CREATE TABLE IF NOT EXISTS containers (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n image TEXT,\n ports TEXT,\n environment TEXT,\n depends_on TEXT,\n networks TEXT,\n metadata TEXT\n );\n\n -- HTTP Endpoints (API routes)\n CREATE TABLE IF NOT EXISTS http_endpoints (\n id TEXT PRIMARY KEY,\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n handler_node_id TEXT,\n container_id TEXT,\n middleware TEXT,\n metadata TEXT\n );\n\n -- HTTP Calls (client requests)\n CREATE TABLE IF NOT EXISTS http_calls (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_endpoint_id TEXT,\n url TEXT NOT NULL,\n method TEXT NOT NULL,\n line INTEGER,\n metadata TEXT\n );\n\n -- Framework Dependencies (FastAPI Depends, etc.)\n CREATE TABLE IF NOT EXISTS framework_dependencies (\n id TEXT PRIMARY KEY,\n source_node_id TEXT NOT NULL,\n target_node_id TEXT,\n framework TEXT NOT NULL,\n pattern TEXT NOT NULL,\n parameter_name TEXT,\n line INTEGER,\n unresolved_name TEXT,\n metadata TEXT\n );\n\n -- Database Operations\n CREATE TABLE IF NOT EXISTS database_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n database_type TEXT NOT NULL,\n operation TEXT NOT NULL,\n collection TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Message Queue Operations\n CREATE TABLE IF NOT EXISTS message_queue_operations (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL,\n operation TEXT NOT NULL,\n exchange TEXT,\n routing_key TEXT,\n queue TEXT,\n line INTEGER,\n metadata TEXT\n );\n\n -- Variable Type Tracking\n CREATE TABLE IF NOT EXISTS variable_types (\n id TEXT PRIMARY KEY,\n variable_name TEXT NOT NULL,\n type_name TEXT NOT NULL,\n scope_node_id TEXT NOT NULL,\n file_path TEXT NOT NULL,\n line INTEGER NOT NULL,\n is_parameter BOOLEAN DEFAULT 0,\n metadata TEXT\n );\n\n -- Indexes for fast queries\n CREATE INDEX IF NOT EXISTS idx_nodes_file ON nodes(file_path);\n CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);\n CREATE INDEX IF NOT EXISTS idx_nodes_hash ON nodes(hash);\n CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id);\n CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id);\n CREATE INDEX IF NOT EXISTS idx_edges_resolved ON edges(target_id) WHERE target_id NOT LIKE 'ref:%';\n CREATE INDEX IF NOT EXISTS idx_exports_file ON exports(file_path);\n CREATE INDEX IF NOT EXISTS idx_imports_file ON imports(file_path);\n CREATE INDEX IF NOT EXISTS idx_http_endpoints_path ON http_endpoints(method, path);\n CREATE INDEX IF NOT EXISTS idx_http_calls_url ON http_calls(url);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_source ON framework_dependencies(source_node_id);\n CREATE INDEX IF NOT EXISTS idx_framework_deps_target ON framework_dependencies(target_node_id);\n CREATE INDEX IF NOT EXISTS idx_variable_types_scope ON variable_types(scope_node_id, variable_name);\n CREATE INDEX IF NOT EXISTS idx_variable_types_file ON variable_types(file_path, variable_name);\n `);\n }\n\n // ============ Node Operations ============\n\n insertNode(node: GraphNode & { hash?: string }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO nodes (id, type, name, file_path, start_line, end_line, language, hash, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n node.id,\n node.type,\n node.name,\n node.filePath,\n node.startLine,\n node.endLine,\n node.language,\n node.hash || null,\n node.metadata ? JSON.stringify(node.metadata) : null\n );\n }\n\n getNode(id: string): GraphNode | null {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n searchNodesByName(name: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE name = ? OR name LIKE ?\");\n const rows = stmt.all(name, `%${name}%`) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n getNodesByFile(filePath: string): GraphNode[] {\n const stmt = this.db.prepare(\"SELECT * FROM nodes WHERE file_path = ?\");\n const rows = stmt.all(filePath) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n private rowToNode(row: Record<string, unknown>): GraphNode {\n return {\n id: row.id as string,\n type: row.type as GraphNode[\"type\"],\n name: row.name as string,\n filePath: row.file_path as string,\n startLine: row.start_line as number,\n endLine: row.end_line as number,\n language: row.language as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n };\n }\n\n // ============ Edge Operations ============\n\n insertEdge(edge: GraphEdge): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO edges (id, type, source_id, target_id, metadata)\n VALUES (?, ?, ?, ?, ?)\n `);\n stmt.run(\n edge.id,\n edge.type,\n edge.sourceId,\n edge.targetId,\n edge.metadata ? JSON.stringify(edge.metadata) : null\n );\n }\n\n // ============ Call Graph Queries ============\n\n /**\n * Get all resolved callees (functions this node calls)\n */\n getResolvedCallees(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.target_id\n WHERE e.source_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get all resolved callers (functions that call this node)\n */\n getResolvedCallers(nodeId: string): GraphNode[] {\n const stmt = this.db.prepare(`\n SELECT n.* FROM nodes n\n JOIN edges e ON n.id = e.source_id\n WHERE e.target_id = ? AND e.type = 'calls'\n `);\n const rows = stmt.all(nodeId) as Record<string, unknown>[];\n return rows.map((r) => this.rowToNode(r));\n }\n\n /**\n * Get impact: all nodes affected by changes to this node (BFS traversal)\n */\n getImpactedNodes(nodeId: string, maxDepth: number = 3): GraphNode[] {\n const visited = new Set<string>();\n const result: GraphNode[] = [];\n const queue: Array<{ id: string; depth: number }> = [{ id: nodeId, depth: 0 }];\n\n while (queue.length > 0) {\n const { id, depth } = queue.shift()!;\n\n if (visited.has(id) || depth > maxDepth) continue;\n visited.add(id);\n\n const callers = this.getResolvedCallers(id);\n for (const caller of callers) {\n if (!visited.has(caller.id)) {\n result.push(caller);\n queue.push({ id: caller.id, depth: depth + 1 });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Trace call path from source to target using BFS\n */\n traceCallPath(fromId: string, toId: string): CallPath | null {\n const visited = new Set<string>();\n const parent = new Map<string, { nodeId: string; edgeType: string }>();\n const queue: string[] = [fromId];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current === toId) {\n // Reconstruct path\n const path: string[] = [];\n let node = toId;\n while (node !== fromId) {\n path.unshift(node);\n node = parent.get(node)!.nodeId;\n }\n path.unshift(fromId);\n\n // Get node details\n const nodes = path.map((id) => {\n const n = this.getNode(id);\n return {\n id: n!.id,\n name: n!.name,\n file: n!.filePath,\n line: n!.startLine,\n };\n });\n\n const edges = [];\n for (let i = 0; i < path.length - 1; i++) {\n edges.push({\n from: path[i],\n to: path[i + 1],\n type: 'calls',\n });\n }\n\n return { nodes, edges };\n }\n\n if (visited.has(current)) continue;\n visited.add(current);\n\n const callees = this.getResolvedCallees(current);\n for (const callee of callees) {\n if (!visited.has(callee.id)) {\n parent.set(callee.id, { nodeId: current, edgeType: 'calls' });\n queue.push(callee.id);\n }\n }\n }\n\n return null;\n }\n\n // ============ Export/Import Tracking ============\n\n registerExport(filePath: string, symbolName: string, nodeId: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO exports (file_path, symbol_name, node_id)\n VALUES (?, ?, ?)\n `);\n stmt.run(filePath, symbolName, nodeId);\n }\n\n registerImport(filePath: string, symbol: string, fromModule: string, line: number): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO imports (file_path, imported_symbol, from_module, line)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, symbol, fromModule, line);\n }\n\n resolveImport(filePath: string, symbol: string): string | null {\n // Get the import statement\n const importStmt = this.db.prepare(`\n SELECT from_module FROM imports WHERE file_path = ? AND imported_symbol = ?\n `).get(filePath, symbol) as { from_module: string } | undefined;\n\n if (!importStmt) return null;\n\n // Convert module path to possible file paths\n // Examples:\n // - \"backend.authentication\" -> [\"backend/authentication.py\", \"backend/authentication/__init__.py\"]\n // - \"..authentication\" -> relative import (handle separately)\n const modulePath = importStmt.from_module;\n const possiblePaths = this.resolvePythonModulePath(filePath, modulePath);\n\n // Try each possible path\n for (const targetPath of possiblePaths) {\n const exportStmt = this.db.prepare(`\n SELECT node_id FROM exports WHERE file_path = ? AND symbol_name = ?\n `).get(targetPath, symbol) as { node_id: string } | undefined;\n\n if (exportStmt) {\n return exportStmt.node_id;\n }\n }\n\n return null;\n }\n\n /**\n * Resolve a Python module path to possible file paths\n * Handles: absolute imports, relative imports, __init__.py\n */\n private resolvePythonModulePath(currentFile: string, modulePath: string): string[] {\n const possiblePaths: string[] = [];\n\n // Handle relative imports (from . import x, from .. import y)\n if (modulePath.startsWith(\".\")) {\n const currentDir = currentFile.substring(0, currentFile.lastIndexOf(\"/\"));\n const depth = modulePath.match(/^\\.+/)?.[0].length || 0;\n const moduleName = modulePath.replace(/^\\.+/, \"\");\n\n // Go up directories based on depth\n let targetDir = currentDir;\n for (let i = 1; i < depth; i++) {\n const lastSlash = targetDir.lastIndexOf(\"/\");\n if (lastSlash > 0) {\n targetDir = targetDir.substring(0, lastSlash);\n }\n }\n\n if (moduleName) {\n const relativePath = moduleName.replace(/\\./g, \"/\");\n possiblePaths.push(`${targetDir}/${relativePath}.py`);\n possiblePaths.push(`${targetDir}/${relativePath}/__init__.py`);\n } else {\n possiblePaths.push(`${targetDir}/__init__.py`);\n }\n } else {\n // Absolute import - convert dots to slashes\n const pathComponents = modulePath.split(\".\");\n\n // Try different interpretations\n // 1. Full path as file: backend.authentication -> backend/authentication.py\n const filePath = pathComponents.join(\"/\");\n possiblePaths.push(`${filePath}.py`);\n possiblePaths.push(`${filePath}/__init__.py`);\n\n // 2. Try with src/ prefix (common pattern)\n possiblePaths.push(`src/${filePath}.py`);\n possiblePaths.push(`src/${filePath}/__init__.py`);\n\n // 3. Query actual files to find match\n // Get all files that end with the last component\n const lastComponent = pathComponents[pathComponents.length - 1];\n const matchingFiles = this.db.prepare(`\n SELECT DISTINCT file_path FROM exports\n WHERE file_path LIKE ?\n `).all(`%/${lastComponent}.py`) as Array<{ file_path: string }>;\n\n for (const file of matchingFiles) {\n // Check if the file path ends with the module path\n const normalizedFilePath = file.file_path.replace(/\\\\/g, \"/\");\n if (normalizedFilePath.includes(filePath)) {\n possiblePaths.push(normalizedFilePath);\n }\n }\n }\n\n return possiblePaths;\n }\n\n /**\n * Resolve a class method call like ClassName.method_name\n * Handles: static methods, class methods, imported classes\n */\n resolveClassMethod(className: string, methodName: string, callerFilePath: string): string | null {\n // Strategy 1: Check if the class is imported in the caller file\n const classNodeId = this.resolveImport(callerFilePath, className);\n\n if (classNodeId) {\n // Find the method within this class\n const methods = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'contains'\n `).all(classNodeId) as Array<{ target_id: string }>;\n\n for (const edge of methods) {\n const methodNode = this.getNode(edge.target_id);\n if (methodNode && methodNode.name === methodName) {\n return methodNode.id;\n }\n }\n }\n\n // Strategy 2: Search for class in the same file\n const classNode = this.db.prepare(`\n SELECT id FROM nodes\n WHERE file_path = ? AND name = ? AND type = 'class'\n `).get(callerFilePath, className) as { id: string } | undefined;\n\n if (classNode) {\n // Find the method within this class\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(classNode.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n // Strategy 3: Search globally for the class\n const allClasses = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).all(className) as Array<{ id: string }>;\n\n for (const cls of allClasses) {\n const methodNode = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(cls.id, methodName) as { id: string } | undefined;\n\n if (methodNode) {\n return methodNode.id;\n }\n }\n\n return null;\n }\n\n // ============ Variable Type Tracking ============\n\n /**\n * Register a variable type (from assignment or parameter)\n */\n registerVariableType(\n variableName: string,\n typeName: string,\n scopeNodeId: string,\n filePath: string,\n line: number,\n isParameter: boolean = false\n ): void {\n const id = `${scopeNodeId}:var:${variableName}`;\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO variable_types\n (id, variable_name, type_name, scope_node_id, file_path, line, is_parameter)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(id, variableName, typeName, scopeNodeId, filePath, line, isParameter ? 1 : 0);\n }\n\n /**\n * Resolve variable.method to actual method node\n * Example: user.get_name() where user is of type User\n */\n resolveVariableMethod(variableName: string, methodName: string, scopeNodeId: string): string | null {\n // Special case: self.method calls - resolve to methods in parent class\n if (variableName === \"self\") {\n return this.resolveSelfMethod(methodName, scopeNodeId);\n }\n\n // Get the variable's type\n const varType = this.db.prepare(`\n SELECT type_name FROM variable_types\n WHERE scope_node_id = ? AND variable_name = ?\n `).get(scopeNodeId, variableName) as { type_name: string } | undefined;\n\n if (!varType) {\n return null;\n }\n\n // Now resolve ClassName.method_name\n return this.resolveClassMethod(varType.type_name, methodName, \"\");\n }\n\n /**\n * Resolve self.method() calls to methods in the same class\n */\n private resolveSelfMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of this method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Find the method with this name in the same class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(parentClass.source_id, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n /**\n * Resolve super().method() calls to parent class methods\n */\n resolveSuperMethod(methodName: string, scopeNodeId: string): string | null {\n // Find the parent class of the current method\n const parentClass = this.db.prepare(`\n SELECT source_id FROM edges\n WHERE target_id = ? AND type = 'contains'\n `).get(scopeNodeId) as { source_id: string } | undefined;\n\n if (!parentClass) {\n return null;\n }\n\n // Get the class node\n const classNode = this.getNode(parentClass.source_id);\n if (!classNode || classNode.type !== 'class') {\n return null;\n }\n\n // Find the parent class (via extends edge)\n const baseClass = this.db.prepare(`\n SELECT target_id FROM edges\n WHERE source_id = ? AND type = 'extends'\n `).get(classNode.id) as { target_id: string } | undefined;\n\n if (!baseClass) {\n return null;\n }\n\n // The target might be a ref, resolve it first\n let baseClassId = baseClass.target_id;\n if (baseClassId.startsWith('ref:')) {\n const baseClassName = baseClassId.replace('ref:', '');\n // Search for the class by name\n const resolvedClass = this.db.prepare(`\n SELECT id FROM nodes WHERE name = ? AND type = 'class'\n `).get(baseClassName) as { id: string } | undefined;\n\n if (!resolvedClass) {\n return null;\n }\n baseClassId = resolvedClass.id;\n }\n\n // Find the method in the parent class\n const method = this.db.prepare(`\n SELECT n.id FROM nodes n\n JOIN edges e ON e.target_id = n.id\n WHERE e.source_id = ? AND e.type = 'contains' AND n.name = ?\n `).get(baseClassId, methodName) as { id: string } | undefined;\n\n return method?.id || null;\n }\n\n // ============ File Operations ============\n\n upsertFile(filePath: string, language: string, hash: string): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO files (path, language, hash, analyzed_at)\n VALUES (?, ?, ?, ?)\n `);\n stmt.run(filePath, language, hash, new Date().toISOString());\n }\n\n getFileHash(filePath: string): string | null {\n const stmt = this.db.prepare(\"SELECT hash FROM files WHERE path = ?\");\n const row = stmt.get(filePath) as { hash: string } | undefined;\n return row?.hash || null;\n }\n\n deleteFileData(filePath: string): void {\n this.db.prepare(\"DELETE FROM nodes WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM exports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM imports WHERE file_path = ?\").run(filePath);\n this.db.prepare(\"DELETE FROM files WHERE path = ?\").run(filePath);\n }\n\n // ============ Stats ============\n\n getStats(): {\n totalFiles: number;\n totalNodes: number;\n totalEdges: number;\n resolvedCalls: number;\n unresolvedCalls: number;\n httpEndpoints: number;\n frameworkDependencies: number;\n resolvedDependencies: number;\n containers: number;\n } {\n const totalFiles = (this.db.prepare(\"SELECT COUNT(*) as count FROM files\").get() as { count: number }).count;\n const totalNodes = (this.db.prepare(\"SELECT COUNT(*) as count FROM nodes\").get() as { count: number }).count;\n const totalEdges = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls'\").get() as { count: number }).count;\n const resolvedCalls = (this.db.prepare(\"SELECT COUNT(*) as count FROM edges WHERE type = 'calls' AND target_id NOT LIKE 'ref:%'\").get() as { count: number }).count;\n const unresolvedCalls = totalEdges - resolvedCalls;\n const httpEndpoints = (this.db.prepare(\"SELECT COUNT(*) as count FROM http_endpoints\").get() as { count: number }).count;\n const frameworkDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies\").get() as { count: number }).count;\n const resolvedDependencies = (this.db.prepare(\"SELECT COUNT(*) as count FROM framework_dependencies WHERE target_node_id IS NOT NULL\").get() as { count: number }).count;\n const containers = (this.db.prepare(\"SELECT COUNT(*) as count FROM containers\").get() as { count: number }).count;\n\n return {\n totalFiles,\n totalNodes,\n totalEdges,\n resolvedCalls,\n unresolvedCalls,\n httpEndpoints,\n frameworkDependencies,\n resolvedDependencies,\n containers,\n };\n }\n\n // ============ Container Operations ============\n\n insertContainer(container: {\n id: string;\n name: string;\n image?: string;\n ports?: Array<{ host: number; container: number }>;\n environment?: Record<string, string>;\n depends_on?: string[];\n networks?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO containers (id, name, image, ports, environment, depends_on, networks, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n container.id,\n container.name,\n container.image || null,\n container.ports ? JSON.stringify(container.ports) : null,\n container.environment ? JSON.stringify(container.environment) : null,\n container.depends_on ? JSON.stringify(container.depends_on) : null,\n container.networks ? JSON.stringify(container.networks) : null,\n container.metadata ? JSON.stringify(container.metadata) : null\n );\n }\n\n getContainer(id: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM containers WHERE id = ?\");\n const row = stmt.get(id) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n getAllContainers(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM containers\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n name: row.name,\n image: row.image,\n ports: row.ports ? JSON.parse(row.ports as string) : [],\n environment: row.environment ? JSON.parse(row.environment as string) : {},\n depends_on: row.depends_on ? JSON.parse(row.depends_on as string) : [],\n networks: row.networks ? JSON.parse(row.networks as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n // ============ HTTP Endpoint Operations ============\n\n insertHttpEndpoint(endpoint: {\n id: string;\n method: string;\n path: string;\n handler_node_id?: string;\n container_id?: string;\n middleware?: string[];\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO http_endpoints (id, method, path, handler_node_id, container_id, middleware, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n endpoint.id,\n endpoint.method,\n endpoint.path,\n endpoint.handler_node_id || null,\n endpoint.container_id || null,\n endpoint.middleware ? JSON.stringify(endpoint.middleware) : null,\n endpoint.metadata ? JSON.stringify(endpoint.metadata) : null\n );\n }\n\n insertDatabaseOperation(dbOp: {\n id: string;\n node_id: string;\n database_type: string;\n operation: string;\n collection?: string;\n line?: number;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO database_operations (id, node_id, database_type, operation, collection, line, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dbOp.id,\n dbOp.node_id,\n dbOp.database_type,\n dbOp.operation,\n dbOp.collection || null,\n dbOp.line || null,\n dbOp.metadata ? JSON.stringify(dbOp.metadata) : null\n );\n }\n\n findHttpEndpoint(method: string, path: string): any | null {\n const stmt = this.db.prepare(\"SELECT * FROM http_endpoints WHERE method = ? AND path = ?\");\n const row = stmt.get(method, path) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n id: row.id,\n method: row.method,\n path: row.path,\n handler_node_id: row.handler_node_id,\n container_id: row.container_id,\n middleware: row.middleware ? JSON.parse(row.middleware as string) : [],\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n };\n }\n\n // ============ Framework Dependency Operations ============\n\n insertFrameworkDependency(dep: {\n id: string;\n source_node_id: string;\n target_node_id?: string;\n framework: string;\n pattern: string;\n parameter_name?: string;\n line?: number;\n unresolved_name?: string;\n metadata?: Record<string, unknown>;\n }): void {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO framework_dependencies\n (id, source_node_id, target_node_id, framework, pattern, parameter_name, line, unresolved_name, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n stmt.run(\n dep.id,\n dep.source_node_id,\n dep.target_node_id || null,\n dep.framework,\n dep.pattern,\n dep.parameter_name || null,\n dep.line || null,\n dep.unresolved_name || null,\n dep.metadata ? JSON.stringify(dep.metadata) : null\n );\n }\n\n getFrameworkDependencies(sourceNodeId: string): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE source_node_id = ?\");\n const rows = stmt.all(sourceNodeId) as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n target_node_id: row.target_node_id,\n framework: row.framework,\n pattern: row.pattern,\n parameter_name: row.parameter_name,\n line: row.line,\n unresolved_name: row.unresolved_name,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : {},\n }));\n }\n\n getAllUnresolvedDependencies(): any[] {\n const stmt = this.db.prepare(\"SELECT * FROM framework_dependencies WHERE target_node_id IS NULL\");\n const rows = stmt.all() as Record<string, unknown>[];\n return rows.map(row => ({\n id: row.id,\n source_node_id: row.source_node_id,\n framework: row.framework,\n pattern: row.pattern,\n unresolved_name: row.unresolved_name,\n line: row.line,\n }));\n }\n\n updateFrameworkDependencyTarget(id: string, targetNodeId: string): void {\n const stmt = this.db.prepare(\"UPDATE framework_dependencies SET target_node_id = ? WHERE id = ?\");\n stmt.run(targetNodeId, id);\n }\n\n clear(): void {\n this.db.exec(`\n DELETE FROM nodes;\n DELETE FROM edges;\n DELETE FROM files;\n DELETE FROM exports;\n DELETE FROM imports;\n DELETE FROM containers;\n DELETE FROM http_endpoints;\n DELETE FROM http_calls;\n DELETE FROM framework_dependencies;\n DELETE FROM database_operations;\n DELETE FROM message_queue_operations;\n `);\n }\n\n /**\n * Get all file hashes (for detecting changes)\n */\n getAllFileHashes(): Record<string, string> {\n const stmt = this.db.prepare(\"SELECT path, hash FROM files WHERE hash IS NOT NULL\");\n const rows = stmt.all() as Array<{ path: string; hash: string }>;\n const hashes: Record<string, string> = {};\n for (const row of rows) {\n hashes[row.path] = row.hash;\n }\n return hashes;\n }\n\n /**\n * Get all nodes (for impact comparison)\n */\n getAllNodes(): Array<{ id: string; name: string; type: string; filePath: string }> {\n const stmt = this.db.prepare(\"SELECT id, name, type, file_path FROM nodes\");\n return stmt.all() as Array<{ id: string; name: string; type: string; filePath: string }>;\n }\n\n /**\n * Get all edges (for impact comparison)\n */\n getAllEdges(): Array<{ id: string; source_id: string; target_id: string; type: string }> {\n const stmt = this.db.prepare(\"SELECT id, source_id, target_id, type FROM edges\");\n return stmt.all() as Array<{ id: string; source_id: string; target_id: string; type: string }>;\n }\n\n /**\n * Get resolved callers with file/line info (for impact analysis)\n */\n getResolvedCallersWithLocation(nodeId: string): Array<{ name: string; file: string; line: number }> {\n const stmt = this.db.prepare(`\n SELECT n.name, n.file_path as file, n.start_line as line\n FROM edges e\n JOIN nodes n ON e.source_id = n.id\n WHERE e.target_id = ? AND e.type = 'calls' AND e.target_id NOT LIKE 'ref:%'\n `);\n return stmt.all(nodeId) as Array<{ name: string; file: string; line: number }>;\n }\n\n /**\n * Get HTTP endpoints by handler node ID\n */\n getHttpEndpointsByHandler(handlerNodeId: string): Array<{ method: string; path: string }> {\n const stmt = this.db.prepare(\"SELECT method, path FROM http_endpoints WHERE handler_node_id = ?\");\n return stmt.all(handlerNodeId) as Array<{ method: string; path: string }>;\n }\n\n close(): void {\n this.db.close();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
FlowStorage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LXZ73T7X.js";
|
|
6
6
|
|
|
7
7
|
// src/cli-flow.ts
|
|
8
8
|
import { Command } from "commander";
|
|
@@ -1499,7 +1499,7 @@ function configureMCPServer(projectPath) {
|
|
|
1499
1499
|
return false;
|
|
1500
1500
|
}
|
|
1501
1501
|
}
|
|
1502
|
-
program.name("codemap").description("CodeMap Flow - Call graph analyzer for understanding code impact").version("3.1.
|
|
1502
|
+
program.name("codemap").description("CodeMap Flow - Call graph analyzer for understanding code impact").version("3.1.1");
|
|
1503
1503
|
program.command("index").description("Build call graph for your codebase").argument("[path]", "Path to the project root", ".").option("-f, --force", "Force reindex all files (ignore cache)").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").action(async (path, options) => {
|
|
1504
1504
|
const rootPath = resolve3(path);
|
|
1505
1505
|
const outputDir = join3(rootPath, ".codemap");
|
|
@@ -1721,7 +1721,7 @@ program.command("reindex").description("Force full re-index of codebase").argume
|
|
|
1721
1721
|
program.command("mcp-server").description("Start MCP server for Claude Code integration").option("-p, --path <path>", "Project root path", ".").action(async (options) => {
|
|
1722
1722
|
process.env.CODEMAP_PROJECT_ROOT = resolve3(options.path);
|
|
1723
1723
|
process.env.CODEMAP_DB_PATH = join3(resolve3(options.path), ".codemap", "graph.db");
|
|
1724
|
-
await import("./flow-server-
|
|
1724
|
+
await import("./flow-server-B2SVQKDG.js");
|
|
1725
1725
|
});
|
|
1726
1726
|
program.parse();
|
|
1727
1727
|
//# sourceMappingURL=cli.js.map
|