schemalint 1.1.0

Static analysis tool for JSON Schema compatibility with LLM structured-output providers
Documentation
use crate::ir::{Arena, NodeId};
use crate::profile::{Profile, Severity};
use crate::rules::class_b::helpers::schema_is_array;
use crate::rules::metadata::{RuleCategory, RuleMetadata};
use crate::rules::registry::{Diagnostic, DiagnosticSeverity, Rule};

#[derive(Debug, Clone)]
pub(super) struct ArrayItemsRule {
    pub(super) profile_name: String,
}

impl Rule for ArrayItemsRule {
    fn check(&self, node: NodeId, arena: &Arena, profile: &Profile) -> Vec<Diagnostic> {
        let node_ref = &arena[node];
        if !schema_is_array(node_ref) || node_ref.annotations.items.is_some() {
            return Vec::new();
        }
        vec![Diagnostic {
            code: format!("{}-S-array-items", profile.code_prefix),
            severity: DiagnosticSeverity::Error,
            message: "array schema must declare items".to_string(),
            pointer: node_ref.json_pointer.clone(),
            source: None,
            profile: self.profile_name.clone(),
            hint: Some("Add an items schema for provider compatibility".to_string()),
        }]
    }

    fn metadata(&self) -> Option<RuleMetadata> {
        Some(RuleMetadata {
            name: "array-items".into(),
            code: "{prefix}-S-array-items".into(),
            description: "Array schemas must declare an items schema".into(),
            rationale: format!(
                "{} rejects array schemas that omit the items keyword.",
                self.profile_name
            ),
            severity: Severity::Forbid,
            category: RuleCategory::Structural,
            bad_example: r#"{ "type": "array" }"#.into(),
            good_example: r#"{ "type": "array", "items": { "type": "string" } }"#.into(),
            see_also: Vec::new(),
            profile: Some(self.profile_name.clone()),
        })
    }
}