Basic JSON Schema validator covering the most common constraints.
(value: &Value, schema: &Value, path: &str)
| 605 | |
| 606 | /// Basic JSON Schema validator covering the most common constraints. |
| 607 | fn basic_schema_validate(value: &Value, schema: &Value, path: &str) -> Vec<String> { |
| 608 | let mut errors = Vec::new(); |
| 609 | |
| 610 | // Handle $ref — not supported in basic validator, skip |
| 611 | if schema.get("$ref").is_some() { |
| 612 | return errors; |
| 613 | } |
| 614 | |
| 615 | // Handle anyOf / oneOf: value must match at least one sub-schema |
| 616 | if let Some(any_of) = schema |
| 617 | .get("anyOf") |
| 618 | .or_else(|| schema.get("oneOf")) |
| 619 | .and_then(|v| v.as_array()) |
| 620 | { |
| 621 | let matched = any_of |
| 622 | .iter() |
| 623 | .any(|sub| basic_schema_validate(value, sub, path).is_empty()); |
| 624 | if !matched { |
| 625 | errors.push(format!( |
| 626 | "{}: value does not match any variant in anyOf/oneOf", |
| 627 | path_or_root(path), |
| 628 | )); |
| 629 | } |
| 630 | return errors; |
| 631 | } |
| 632 | |
| 633 | // Handle enum |
| 634 | if let Some(enum_values) = schema.get("enum").and_then(|v| v.as_array()) { |
| 635 | if !enum_values.contains(value) { |
| 636 | errors.push(format!( |
| 637 | "{}: value {:?} not in enum {:?}", |
| 638 | path_or_root(path), |
| 639 | value, |
| 640 | enum_values |
| 641 | )); |
| 642 | } |
| 643 | return errors; |
| 644 | } |
| 645 | |
| 646 | // Handle const |
| 647 | if let Some(const_val) = schema.get("const") { |
| 648 | if value != const_val { |
| 649 | errors.push(format!( |
| 650 | "{}: expected const {:?}, got {:?}", |
| 651 | path_or_root(path), |
| 652 | const_val, |
| 653 | value |
| 654 | )); |
| 655 | } |
| 656 | return errors; |
| 657 | } |
| 658 | |
| 659 | // Type checking (supports nullable via type array: ["string", "null"]) |
| 660 | if let Some(type_val) = schema.get("type") { |
| 661 | let type_ok = if let Some(type_str) = type_val.as_str() { |
| 662 | check_type(value, type_str) |
| 663 | } else if let Some(type_arr) = type_val.as_array() { |
| 664 | type_arr |
no test coverage detected