Skip to main content

gen_completions/parse_deser/
mod.rs

1//! For parsing completions from a serialization language (KDL or JSON)
2
3pub mod error;
4mod kdl;
5
6use std::{fs, path::Path};
7
8use miette::NamedSource;
9
10use self::error::DeserError;
11use crate::{parse_deser::error::Error, CommandInfo};
12
13pub type Result<T> = std::result::Result<T, Error>;
14
15#[derive(Copy, Clone)]
16pub enum InputFormat {
17  Kdl,
18  Json,
19}
20
21/// # Errors
22///
23/// Fails if the file's extension isn't recognized (only KDL and JSON are
24/// supported), or if [`parse_from_str`] fails.
25pub fn parse(file: impl AsRef<Path>) -> Result<CommandInfo> {
26  let file = file.as_ref();
27  let file_path = file.to_string_lossy().to_string();
28  if let Some(ext) = file.extension() {
29    match fs::read_to_string(file) {
30      Ok(text) => {
31        if let Some(ext) = ext.to_str() {
32          let format = match ext {
33            "json" => InputFormat::Json,
34            "kdl" => InputFormat::Kdl,
35            _ => return Err(Error::UnrecognizableExtension { file_path }),
36          };
37          parse_from_str(&text, format).map_err(|error| Error::Deser {
38            source_code: NamedSource::new(file_path, text),
39            error: Box::new(error),
40          })
41        } else {
42          Err(Error::UnrecognizableExtension { file_path })
43        }
44      }
45      Err(e) => Err(Error::Io {
46        file_path,
47        source: e,
48      }),
49    }
50  } else {
51    Err(Error::NoExtension { file_path })
52  }
53}
54
55/// # Errors
56///
57/// Fails if the shape of the KDL/JSON didn't match a [`CommandInfo`]
58pub fn parse_from_str(
59  text: &str,
60  format: InputFormat,
61) -> std::result::Result<CommandInfo, DeserError> {
62  let cmd_info = match format {
63    InputFormat::Json => serde_json::from_str(text)?,
64    InputFormat::Kdl => kdl::parse_from_str(text)?,
65  };
66  Ok(cmd_info)
67}