use crate::snippets::error::Result;
use crate::snippets::types::{Language, Snippet, SnippetStatus, ValidationLevel};
use crate::snippets::validators::SnippetValidator;
pub struct YamlValidator;
impl SnippetValidator for YamlValidator {
fn language(&self) -> Language {
Language::Yaml
}
fn is_available(&self) -> bool {
true
}
fn validate(
&self,
snippet: &Snippet,
_level: ValidationLevel,
_timeout_secs: u64,
) -> Result<(SnippetStatus, Option<String>)> {
let mut options = serde_saphyr::Options::default();
options.reject_non_finite_typeless_float = false;
match serde_saphyr::from_str_with_options::<serde::de::IgnoredAny>(&snippet.code, options) {
Ok(_) => Ok((SnippetStatus::Pass, None)),
Err(err) => Ok((SnippetStatus::Fail, Some(err.to_string()))),
}
}
fn max_level(&self) -> ValidationLevel {
ValidationLevel::Syntax
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::snippets::types::{SnippetMetadata, SourceOrigin};
fn yaml_snippet(code: &str) -> Snippet {
Snippet {
id: None,
path: "example.md".into(),
language: Language::Yaml,
title: None,
code: code.into(),
start_line: 1,
block_index: 0,
annotation: None,
metadata: SnippetMetadata::default(),
source_origin: SourceOrigin {
path: "example.md".into(),
line: 1,
block_index: 0,
},
}
}
fn status(code: &str) -> SnippetStatus {
YamlValidator
.validate(&yaml_snippet(code), ValidationLevel::Syntax, 10)
.expect("the YAML validator never fails to run")
.0
}
#[test]
fn malformed_yaml_still_fails_even_though_the_parsed_value_is_discarded() {
for broken in [
"a: [1, 2", "a: {b: 1", "a: 1\n b: 2\n", "a:\n\t- 1\n", "a: \"unterminated\n", "a: 1\nb\n", "a: *nonexistent\n", "jobs:\n build:\n steps: [ {uses: x}\n",
] {
assert_eq!(
status(broken),
SnippetStatus::Fail,
"malformed YAML must not pass validation: {broken:?}"
);
}
}
#[test]
fn valid_yaml_passes_including_shapes_a_json_shaped_target_would_reject() {
for valid in [
"", "# just a comment\n", "~", "a: 1\nb: [x, y]\n", "1: one\n", "a: !mytag hello\n", "a: .nan\nb: .inf\n", ] {
assert_eq!(
status(valid),
SnippetStatus::Pass,
"valid YAML must pass validation: {valid:?}"
);
}
}
}