mod json;
mod yaml;
use std::path::Path;
pub use json::parse_json;
pub use yaml::parse_yaml;
use crate::diagnostics::DiagnosticReport;
use crate::model::DataContract;
#[derive(Debug, Clone)]
pub struct ParseResult {
pub contract: Option<DataContract>,
pub report: DiagnosticReport,
}
impl ParseResult {
pub fn into_contract(self) -> Result<DataContract, DiagnosticReport> {
match (self.contract, self.report.is_valid()) {
(Some(contract), true) => Ok(contract),
(_, false) => Err(self.report),
(None, true) => Err(self.report),
}
}
#[must_use]
pub fn validate(self) -> DiagnosticReport {
let mut report = self.report;
if let Some(contract) = self.contract {
report.merge(crate::validate(&contract));
}
report
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DocumentFormat {
Yaml,
Json,
}
impl DocumentFormat {
#[must_use]
pub fn from_path(path: &Path) -> Option<Self> {
match path.extension()?.to_str()? {
"yaml" | "yml" => Some(Self::Yaml),
"json" => Some(Self::Json),
_ => None,
}
}
}
#[must_use]
pub fn parse(content: &[u8], format: DocumentFormat) -> ParseResult {
match format {
DocumentFormat::Yaml => parse_yaml(content),
DocumentFormat::Json => parse_json(content),
}
}
pub fn parse_file(path: impl AsRef<Path>) -> miette::Result<ParseResult> {
let path = path.as_ref();
let content = std::fs::read(path)
.map_err(|e| miette::miette!("failed to read {}: {e}", path.display()))?;
let format = DocumentFormat::from_path(path).ok_or_else(|| {
miette::miette!(
"unsupported file extension for {}: expected .yaml, .yml, or .json",
path.display()
)
})?;
Ok(parse(&content, format))
}