llmwiki_tooling/cmd/
frontmatter_cmd.rs1use std::path::Path;
2
3use crate::error::WikiError;
4use crate::wiki::Wiki;
5
6pub fn get(wiki: &Wiki, file: &Path, field: Option<&str>) -> Result<(), WikiError> {
8 let file_path = wiki.abs_path(file);
9
10 let fm_result = wiki.frontmatter(&file_path)?;
11
12 let fm = match fm_result {
13 Ok(Some(fm)) => fm,
14 Ok(None) => {
15 eprintln!("no frontmatter in {}", file_path.display());
16 return Ok(());
17 }
18 Err(e) => {
19 eprintln!("frontmatter error in {}: {e}", file_path.display());
20 return Ok(());
21 }
22 };
23
24 match field {
25 Some(name) => {
26 if let Some(val) = fm.get(name) {
27 let json: serde_json::Value =
28 serde_json::to_value(val).unwrap_or(serde_json::Value::Null);
29 println!("{json}");
30 } else {
31 eprintln!("field '{name}' not found");
32 }
33 }
34 None => {
35 let json =
36 serde_json::to_value(fm.data()).expect("valid YAML frontmatter serializes to JSON");
37 println!("{}", serde_json::to_string_pretty(&json).unwrap());
38 }
39 }
40
41 Ok(())
42}
43
44pub fn set(wiki: &mut Wiki, file: &Path, field: &str, value: &str) -> Result<(), WikiError> {
46 let file_path = wiki.abs_path(file);
47
48 let cached = wiki.file(&file_path)?;
50 let source = cached.source();
51
52 let fm = match cached.frontmatter() {
53 Ok(Some(fm)) => fm,
54 Ok(None) => {
55 eprintln!("no frontmatter in {}", file_path.display());
56 return Ok(());
57 }
58 Err(e) => {
59 eprintln!("frontmatter error in {}: {e}", file_path.display());
60 return Ok(());
61 }
62 };
63
64 let mut yaml_value: serde_yml::Value =
65 serde_yml::from_str(&fm.raw_yaml).map_err(|e| WikiError::Frontmatter {
66 path: file_path.clone(),
67 source: crate::error::FrontmatterError::Yaml {
68 source: e,
69 context: field.to_owned(),
70 },
71 })?;
72
73 let parsed_value: serde_yml::Value =
74 serde_yml::from_str(value).unwrap_or(serde_yml::Value::String(value.to_owned()));
75
76 if let serde_yml::Value::Mapping(ref mut map) = yaml_value {
77 map.insert(serde_yml::Value::String(field.to_owned()), parsed_value);
78 }
79
80 let new_yaml = serde_yml::to_string(&yaml_value).map_err(|e| WikiError::Frontmatter {
81 path: file_path.clone(),
82 source: crate::error::FrontmatterError::Yaml {
83 source: e,
84 context: field.to_owned(),
85 },
86 })?;
87
88 let body = &source[fm.byte_range.end..];
89 let new_source = format!("---\n{new_yaml}---\n{body}");
90
91 wiki.write_file(&file_path, &new_source)?;
93
94 println!("updated '{}' in {}", field, file_path.display());
95 Ok(())
96}