1use crate::ManifestParser;
4use kdo_core::{DepKind, Dependency, KdoError, Language, Project};
5use std::path::Path;
6use tracing::debug;
7
8pub struct AnchorParser;
10
11impl ManifestParser for AnchorParser {
12 fn manifest_name(&self) -> &str {
13 "Anchor.toml"
14 }
15
16 fn can_parse(&self, manifest_path: &Path) -> bool {
17 manifest_path
18 .file_name()
19 .map(|f| f == "Anchor.toml")
20 .unwrap_or(false)
21 }
22
23 fn parse(
24 &self,
25 manifest_path: &Path,
26 workspace_root: &Path,
27 ) -> Result<(Project, Vec<Dependency>), KdoError> {
28 let content = std::fs::read_to_string(manifest_path)?;
29 let doc: toml::Value = toml::from_str(&content).map_err(|e| KdoError::ParseError {
30 path: manifest_path.to_path_buf(),
31 source: e.into(),
32 })?;
33
34 let project_dir = manifest_path
35 .parent()
36 .unwrap_or(Path::new("."))
37 .to_path_buf();
38
39 let programs = doc
42 .get("programs")
43 .and_then(|p| p.as_table())
44 .and_then(|t| {
45 t.values().next().and_then(|v| v.as_table())
47 });
48
49 let program_names: Vec<String> = programs
50 .map(|p| p.keys().cloned().collect())
51 .unwrap_or_default();
52
53 let name = program_names.first().cloned().unwrap_or_else(|| {
55 project_dir
56 .file_name()
57 .map(|f| f.to_string_lossy().to_string())
58 .unwrap_or_else(|| "anchor-project".to_string())
59 });
60
61 debug!(name = %name, programs = ?program_names, "parsed Anchor.toml");
62
63 let mut deps = Vec::new();
65 if let Some(workspace) = doc.get("workspace") {
66 if let Some(members) = workspace.get("members").and_then(|m| m.as_array()) {
67 for member in members {
68 if let Some(member_str) = member.as_str() {
69 let member_path = workspace_root.join(member_str);
71 if member_path.is_dir() {
72 deps.push(Dependency {
73 name: member_path
74 .file_name()
75 .map(|f| f.to_string_lossy().to_string())
76 .unwrap_or_default(),
77 version_req: "path".to_string(),
78 kind: DepKind::Source,
79 is_workspace: true,
80 resolved_path: Some(member_path),
81 });
82 }
83 }
84 }
85 }
86 }
87
88 let project = Project {
89 name,
90 path: project_dir,
91 language: Language::Anchor,
92 manifest_path: manifest_path.to_path_buf(),
93 context_summary: None,
94 public_api_files: Vec::new(),
95 internal_files: Vec::new(),
96 content_hash: [0u8; 32],
97 };
98
99 Ok((project, deps))
100 }
101}