mod diagnostic;
pub(crate) mod filesystem;
pub(crate) mod semantic;
pub(crate) mod structural;
pub use diagnostic::{
Diagnostic, DiagnosticCode, FileReport, FileStatus, Location, Severity, Summary,
ValidationReport,
};
pub use semantic::find_unknown_fields;
pub use structural::detect_unknown_fields;
use crate::preset::Preset;
use std::path::Path;
impl Preset {
pub fn validate(path: &Path) -> FileReport {
let toml_str = match std::fs::read_to_string(path) {
Ok(s) => s,
Err(e) => {
return FileReport::new(
path.to_string_lossy(),
vec![Diagnostic {
severity: Severity::Error,
code: DiagnosticCode::FileNotReadable,
message: format!("failed to read file: {}", e),
location: Location {
line: 1,
column: 1,
field: String::new(),
},
}],
);
}
};
if let Err(parse_err) = toml::from_str::<toml::Value>(&toml_str) {
let (line, column) = parse_err
.span()
.map(|s| {
let prefix = &toml_str[..s.start];
let line = prefix.matches('\n').count() + 1;
let last_newline = prefix.rfind('\n').map(|i| i + 1).unwrap_or(0);
let column = s.start - last_newline + 1;
(line, column)
})
.unwrap_or((1, 1));
let raw = parse_err.message().replace('\n', "; ");
let message = if raw.is_empty() {
"TOML syntax error".to_string()
} else {
format!("TOML syntax error: {}", raw)
};
return FileReport::new(
path.to_string_lossy(),
vec![Diagnostic {
severity: Severity::Error,
code: DiagnosticCode::SyntaxError,
message,
location: Location {
line,
column,
field: String::new(),
},
}],
);
}
let mut diagnostics = Vec::new();
diagnostics.extend(structural::detect_unknown_fields(&toml_str));
diagnostics.extend(semantic::check_schema(&toml_str));
diagnostics.extend(semantic::find_unknown_fields(&toml_str));
diagnostics.extend(filesystem::check_filesystem(path));
FileReport::new(path.to_string_lossy(), diagnostics)
}
}
#[cfg(test)]
mod tests;