use super::documents::Document;
use super::toml_diag::{error_at_named_key, syntax_error};
use crate::manifest::Manifest;
use crate::object_definition::ObjectDefinition;
use lsp_types::{Diagnostic, DiagnosticSeverity};
use std::path::Path;
pub(super) fn validate_manifest(doc: &Document, root: &Path) -> Vec<Diagnostic> {
if let Err(err) = toml::from_str::<toml::Table>(&doc.text) {
return vec![syntax_error(doc, &err)];
}
match Manifest::from_string(root, doc.text.clone(), Some("")) {
Ok(_) => vec![],
Err(err) => vec![error_at_named_key(
doc,
err.to_string(),
DiagnosticSeverity::ERROR,
)],
}
}
pub(super) fn validate_definitions(doc: &Document, manifest: Option<&Manifest>) -> Vec<Diagnostic> {
if let Err(err) = toml::from_str::<toml::Table>(&doc.text) {
return vec![syntax_error(doc, &err)];
}
let editor_types = manifest.map(|m| m.editor_types.clone()).unwrap_or_default();
match ObjectDefinition::from_source(&doc.text, &editor_types) {
Ok(_) => vec![],
Err(err) => vec![error_at_named_key(
doc,
err.to_string(),
DiagnosticSeverity::ERROR,
)],
}
}
#[cfg(test)]
mod tests {
use super::*;
fn manifest(text: &str) -> Vec<Diagnostic> {
validate_manifest(&Document::new(text.to_string()), Path::new("/site"))
}
fn definitions(text: &str) -> Vec<Diagnostic> {
validate_definitions(&Document::new(text.to_string()), None)
}
#[test]
fn accepts_a_valid_manifest() {
assert!(manifest("site_name = \"a\"\npages = \"pages\"\n").is_empty());
}
#[test]
fn reports_a_manifest_field_of_the_wrong_type() {
let found = manifest("pages = 42\n");
assert_eq!(found.len(), 1, "{found:#?}");
assert_eq!(found[0].severity, Some(DiagnosticSeverity::ERROR));
}
#[test]
fn reports_manifest_syntax_errors() {
let found = manifest("site_name = \n");
assert_eq!(found.len(), 1, "{found:#?}");
}
#[test]
fn accepts_valid_definitions() {
assert!(definitions("[post]\ntitle = \"string\"\nbody = \"markdown\"\n").is_empty());
}
#[test]
fn reports_an_unrecognized_field_type() {
let found = definitions("[post]\ntitle = \"strng\"\n");
assert_eq!(found.len(), 1, "{found:#?}");
assert!(found[0].message.contains("strng"), "{:?}", found[0].message);
}
#[test]
fn reports_a_reserved_object_name() {
let found = definitions("[objects]\ntitle = \"string\"\n");
assert_eq!(found.len(), 1, "{found:#?}");
}
#[test]
fn resolves_custom_types_from_the_manifest() {
let source = "[post]\nthumb = \"hero\"\n";
assert_eq!(definitions(source).len(), 1);
let manifest = Manifest::from_string(
Path::new("/site"),
"[editor_types.hero]\ntype = \"image\"\n".to_string(),
Some(""),
)
.unwrap();
let doc = Document::new(source.to_string());
assert!(validate_definitions(&doc, Some(&manifest)).is_empty());
}
}