# DependencyAnalyzer 设计文档

## 📋 需求分析

### 目标
自动分析代码依赖关系，构建依赖图

### 核心功能
1. ✅ 分析单个文件的 import 依赖
2. ✅ 构建项目依赖图
3. ✅ 查找依赖链
4. ✅ 查找反向依赖

---

## 🎯 简化版实现方案（v1.0）

### 设计原则
1. **最小改动**：基于简单的正则匹配
2. **聚焦仓颉**：专门分析仓颉代码
3. **实用为主**：提供基础依赖查询
4. **可扩展**：预留接口用于LSP集成

---

## 🏗️ 架构设计

### 核心类

```cangjie
// 文件依赖信息
public class FileDependencies {
    public let filePath: Path
    public let imports: Array<String>        // 导入的包
    public let directDeps: Array<Path>       // 直接依赖的文件
}

// 依赖图节点
public class DependencyNode {
    public let path: Path
    public var dependencies: ArrayList<Path>     // 依赖的文件
    public var dependents: ArrayList<Path>       // 被谁依赖
}

// 依赖图
public class DependencyGraph {
    private var nodes: HashMap<String, DependencyNode>
    
    public func addNode(path: Path): Unit
    public func addEdge(from: Path, to: Path): Unit
    public func getDependencies(path: Path): Array<Path>
    public func getDependents(path: Path): Array<Path>
}

// 依赖分析器
public class DependencyAnalyzer {
    private var graph: DependencyGraph
    private var contextEngine: ContextEngine
    
    public func analyzeFile(path: Path): FileDependencies
    public func buildGraph(rootPath: Path): Unit
    public func findRelatedFiles(path: Path): Array<Path>
}
```

---

## 💡 实现策略

### 方案A：正则表达式解析（推荐）
**特点**：
- 简单可靠
- 适用于仓颉 import 语法
- 无需复杂的AST解析

**import 语法模式**：
```cangjie
import std.fs.{Path, File}
import cli.core.config.CliConfig
import magic.log.LogUtils
```

**正则表达式**：
```
import\s+([\w.]+)(?:\.\{([^}]+)\})?
```

**解析逻辑**：
1. 提取包名 (如 `std.fs`, `cli.core.config`)
2. 提取符号列表 (如 `Path, File`)
3. 根据包名推断文件路径

---

### 方案B：LSP集成（未来版本）
**特点**：
- 准确度高
- 需要LSP支持
- 实现复杂

**暂不实现**

---

## 📝 详细实现

### 1. FileDependencies 类

```cangjie
public class FileDependencies {
    public let filePath: Path
    public let imports: Array<String>
    public let directDeps: Array<Path>
    
    public init(filePath: Path, imports: Array<String>, directDeps: Array<Path>) {
        this.filePath = filePath
        this.imports = imports
        this.directDeps = directDeps
    }
}
```

### 2. DependencyNode 类

```cangjie
public class DependencyNode {
    public let path: Path
    public var dependencies: ArrayList<Path>
    public var dependents: ArrayList<Path>
    
    public init(path: Path) {
        this.path = path
        this.dependencies = ArrayList<Path>()
        this.dependents = ArrayList<Path>()
    }
}
```

### 3. DependencyGraph 类

```cangjie
public class DependencyGraph {
    private var nodes: HashMap<String, DependencyNode>
    
    public init() {
        this.nodes = HashMap<String, DependencyNode>()
    }
    
    public func addNode(path: Path): Unit {
        let key = path.toString()
        if (this.nodes.get(key) == None) {
            this.nodes[key] = DependencyNode(path)
        }
    }
    
    public func addEdge(from: Path, to: Path): Unit {
        // from depends on to
        addNode(from)
        addNode(to)
        
        let fromNode = this.nodes.get(from.toString())
        let toNode = this.nodes.get(to.toString())
        
        match (fromNode, toNode) {
            case (Some(f), Some(t)) =>
                if (!f.dependencies.contains(to)) {
                    f.dependencies.add(to)
                }
                if (!t.dependents.contains(from)) {
                    t.dependents.add(from)
                }
            case _ => ()
        }
    }
    
    public func getDependencies(path: Path): Array<Path> {
        let node = this.nodes.get(path.toString())
        match (node) {
            case Some(n) => return n.dependencies.toArray()
            case _ => return Array<Path>(0, i => Path(""))
        }
    }
    
    public func getDependents(path: Path): Array<Path> {
        let node = this.nodes.get(path.toString())
        match (node) {
            case Some(n) => return n.dependents.toArray()
            case _ => return Array<Path>(0, i => Path(""))
        }
    }
}
```

### 4. DependencyAnalyzer 类

```cangjie
public class DependencyAnalyzer {
    private var graph: DependencyGraph
    private var contextEngine: ContextEngine
    
    public init(contextEngine: ContextEngine) {
        this.graph = DependencyGraph()
        this.contextEngine = contextEngine
    }
    
    /**
     * 分析单个文件的依赖
     */
    public func analyzeFile(path: Path): FileDependencies {
        var imports = ArrayList<String>()
        
        // 读取文件内容
        if (!exists(path)) {
            return FileDependencies(path, Array<String>(0), Array<Path>(0))
        }
        
        try {
            let content = String.fromUtf8(File.readFrom(path))
            
            // 使用正则表达式提取 import 语句
            imports = extractImports(content)
            
        } catch (e: Exception) {
            LogUtils.error("Failed to analyze file ${path.toString()}: ${e.message}")
        }
        
        return FileDependencies(path, imports.toArray(), Array<Path>(0))
    }
    
    /**
     * 提取 import 语句
     */
    private func extractImports(content: String): ArrayList<String> {
        let imports = ArrayList<String>()
        
        // 简单的行扫描提取 import
        for (line in content.split("\n")) {
            let trimmed = line.trimAscii()
            if (trimmed.startsWith("import ")) {
                // 提取包名
                let importStr = extractPackageName(trimmed)
                if (!importStr.isEmpty()) {
                    imports.add(importStr)
                }
            }
        }
        
        return imports
    }
    
    /**
     * 从 import 语句提取包名
     */
    private func extractPackageName(importLine: String): String {
        // 移除 "import " 前缀
        var line = importLine[7..].trimAscii()
        
        // 移除花括号部分 {xxx}
        if (let Some(braceIndex) <- line.indexOf("{")) {
            line = line[0..braceIndex].trimAscii()
            // 移除末尾的点
            if (line.endsWith(".")) {
                line = line[0..(line.size - 1)]
            }
        }
        
        return line
    }
    
    /**
     * 查找相关文件（依赖+被依赖）
     */
    public func findRelatedFiles(path: Path): Array<Path> {
        let related = ArrayList<Path>()
        
        // 添加依赖
        for (dep in this.graph.getDependencies(path)) {
            related.add(dep)
        }
        
        // 添加被依赖
        for (dependent in this.graph.getDependents(path)) {
            related.add(dependent)
        }
        
        return related.toArray()
    }
}
```

---

## 🔌 集成点

### 1. 与 ContextEngine 集成

当文件添加到缓存时，自动分析依赖：

```cangjie
// 在 ContextEngine 中添加
public func addFileWithDeps(path: Path, content: String, analyzer: DependencyAnalyzer): Unit {
    // 添加到缓存
    this.addFile(path, content)
    
    // 分析依赖
    let deps = analyzer.analyzeFile(path)
    
    // 更新依赖图
    for (importPkg in deps.imports) {
        // 可以根据需要处理
    }
}
```

---

## ⚠️ 限制和约束

### 当前限制（v1.0）
1. **只支持简单的 import 语句**
2. **不解析包到文件的映射**（需要项目结构信息）
3. **不检测循环依赖**
4. **不支持动态导入**

### 未来改进（v2.0）
1. 使用 LSP 获取精确依赖
2. 包到文件路径的映射
3. 循环依赖检测
4. 可视化依赖图

---

## 📊 工作量估算

### 代码量
- `dependency_analyzer.cj`：约 150 行
- `dependency_analyzer_test.cj`：约 100 行
- 集成代码：约 20 行
- **总计**：约 270 行

### 时间估算
- 核心实现：1 天
- 集成测试：0.5 天
- **总计**：1.5 天

---

## ✅ 验收标准

1. ✅ 能提取文件的 import 语句
2. ✅ 能构建依赖图
3. ✅ 能查询依赖和被依赖
4. ✅ 编译通过
5. ✅ 测试通过

---

**设计者**：AI Assistant  
**设计日期**：2024-10-24  
**版本**：v1.0 设计草案

