mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-10-27 06:53:11 +08:00
Performance & quality: - Transaction wrapping (Querier interface, single tx per index run) - Composite indexes on edges table for faster traversals - Cypher WHERE push-down (=, CONTAINS, STARTS WITH → SQL) - golangci-lint with 25 linters, zero violations - 11 benchmarks for pipeline, search, and BFS Incremental indexing: - Content-hash based file change detection - Dependency-aware two-level invalidation (changed + dependents) - Stale file cleanup for deleted files Async boundary detection: - Project-wide env var URL scanner (Dockerfile, YAML, .tf, .sh, .env, TOML, properties files) with 3-layer secret exclusion - Env var default extraction in constant propagation (getEnv, os.environ.get, process.env with ||/?? fallback) - ASYNC_CALLS edge type for Cloud Tasks, Pub/Sub, SQS/SNS, RabbitMQ, Kafka dispatch patterns, separate from synchronous HTTP_CALLS - Tool descriptions updated with all edge types Other improvements: - Type inference for method dispatch resolution - Interface implementation detection (IMPLEMENTS edges) - Improved tool descriptions for discoverability
104 lines
3.4 KiB
Go
104 lines
3.4 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
tree_sitter "github.com/tree-sitter/go-tree-sitter"
|
|
|
|
tree_sitter_lua "github.com/tree-sitter-grammars/tree-sitter-lua/bindings/go"
|
|
tree_sitter_cpp "github.com/tree-sitter/tree-sitter-cpp/bindings/go"
|
|
tree_sitter_go "github.com/tree-sitter/tree-sitter-go/bindings/go"
|
|
tree_sitter_java "github.com/tree-sitter/tree-sitter-java/bindings/go"
|
|
tree_sitter_javascript "github.com/tree-sitter/tree-sitter-javascript/bindings/go"
|
|
tree_sitter_php "github.com/tree-sitter/tree-sitter-php/bindings/go"
|
|
tree_sitter_python "github.com/tree-sitter/tree-sitter-python/bindings/go"
|
|
tree_sitter_rust "github.com/tree-sitter/tree-sitter-rust/bindings/go"
|
|
tree_sitter_scala "github.com/tree-sitter/tree-sitter-scala/bindings/go"
|
|
tree_sitter_typescript "github.com/tree-sitter/tree-sitter-typescript/bindings/go"
|
|
|
|
"github.com/DeusData/codebase-memory-mcp/internal/lang"
|
|
)
|
|
|
|
var (
|
|
languagesOnce sync.Once
|
|
languages map[lang.Language]*tree_sitter.Language
|
|
)
|
|
|
|
func initLanguages() {
|
|
languagesOnce.Do(func() {
|
|
languages = map[lang.Language]*tree_sitter.Language{
|
|
lang.Python: tree_sitter.NewLanguage(tree_sitter_python.Language()),
|
|
lang.JavaScript: tree_sitter.NewLanguage(tree_sitter_javascript.Language()),
|
|
lang.TypeScript: tree_sitter.NewLanguage(tree_sitter_typescript.LanguageTypescript()),
|
|
lang.TSX: tree_sitter.NewLanguage(tree_sitter_typescript.LanguageTSX()),
|
|
lang.Go: tree_sitter.NewLanguage(tree_sitter_go.Language()),
|
|
lang.Rust: tree_sitter.NewLanguage(tree_sitter_rust.Language()),
|
|
lang.Java: tree_sitter.NewLanguage(tree_sitter_java.Language()),
|
|
lang.CPP: tree_sitter.NewLanguage(tree_sitter_cpp.Language()),
|
|
// C# skipped: upstream module path mismatch (tree-sitter-c-sharp vs tree-sitter-c_sharp)
|
|
lang.PHP: tree_sitter.NewLanguage(tree_sitter_php.LanguagePHPOnly()),
|
|
lang.Lua: tree_sitter.NewLanguage(tree_sitter_lua.Language()),
|
|
lang.Scala: tree_sitter.NewLanguage(tree_sitter_scala.Language()),
|
|
}
|
|
})
|
|
}
|
|
|
|
// GetLanguage returns the tree-sitter Language for a lang.Language.
|
|
func GetLanguage(l lang.Language) (*tree_sitter.Language, error) {
|
|
initLanguages()
|
|
tsLang, ok := languages[l]
|
|
if !ok {
|
|
return nil, fmt.Errorf("unsupported language: %s", l)
|
|
}
|
|
return tsLang, nil
|
|
}
|
|
|
|
// Parse parses source code into a tree-sitter AST Tree.
|
|
// The caller must call tree.Close() when done.
|
|
func Parse(l lang.Language, source []byte) (*tree_sitter.Tree, error) {
|
|
tsLang, err := GetLanguage(l)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p := tree_sitter.NewParser()
|
|
defer p.Close()
|
|
|
|
if err := p.SetLanguage(tsLang); err != nil {
|
|
return nil, fmt.Errorf("set language %s: %w", l, err)
|
|
}
|
|
|
|
tree := p.Parse(source, nil)
|
|
if tree == nil {
|
|
return nil, fmt.Errorf("parse failed for language %s", l)
|
|
}
|
|
|
|
return tree, nil
|
|
}
|
|
|
|
// WalkFunc is called for each node during AST traversal.
|
|
// Return false to skip children.
|
|
type WalkFunc func(node *tree_sitter.Node) bool
|
|
|
|
// Walk traverses the AST in depth-first order.
|
|
func Walk(node *tree_sitter.Node, fn WalkFunc) {
|
|
if node == nil {
|
|
return
|
|
}
|
|
if !fn(node) {
|
|
return
|
|
}
|
|
for i := uint(0); i < node.ChildCount(); i++ {
|
|
child := node.Child(i)
|
|
if child != nil {
|
|
Walk(child, fn)
|
|
}
|
|
}
|
|
}
|
|
|
|
// NodeText returns the text content of a node.
|
|
func NodeText(node *tree_sitter.Node, source []byte) string {
|
|
return string(source[node.StartByte():node.EndByte()])
|
|
}
|