|
1 | 1 | use serde_json::Value; |
2 | 2 | use std::str::FromStr; |
3 | 3 | use tstring_syntax::{ |
4 | | - BackendError, BackendResult, NormalizedDocument, NormalizedFloat, NormalizedKey, |
5 | | - NormalizedStream, NormalizedValue, SourcePosition, SourceSpan, StreamItem, TemplateInput, |
| 4 | + BackendError, BackendResult, InterpolationTypeRequirement, NormalizedDocument, NormalizedFloat, |
| 5 | + NormalizedKey, NormalizedStream, NormalizedValue, SourcePosition, SourceSpan, StreamItem, |
| 6 | + TemplateInput, |
6 | 7 | }; |
7 | 8 |
|
| 9 | +const JSON_VALUE_PYTHON_TYPE: &str = |
| 10 | + "str | int | float | bool | None | dict[str, object] | list[object]"; |
| 11 | +const STRING_PYTHON_TYPE: &str = "str"; |
| 12 | + |
8 | 13 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
9 | 14 | pub enum JsonProfile { |
10 | 15 | Rfc8259, |
@@ -636,6 +641,99 @@ pub fn check_template(template: &TemplateInput) -> BackendResult<()> { |
636 | 641 | check_template_with_profile(template, JsonProfile::default()) |
637 | 642 | } |
638 | 643 |
|
| 644 | +pub fn interpolation_type_requirements_with_profile( |
| 645 | + template: &TemplateInput, |
| 646 | + profile: JsonProfile, |
| 647 | +) -> BackendResult<Vec<InterpolationTypeRequirement>> { |
| 648 | + let document = parse_validated_template_with_profile(template, profile)?; |
| 649 | + let mut requirements = Vec::new(); |
| 650 | + collect_json_value_type_requirements(&document.value, &mut requirements); |
| 651 | + requirements.sort_by_key(|requirement| requirement.interpolation_index); |
| 652 | + Ok(requirements) |
| 653 | +} |
| 654 | + |
| 655 | +pub fn interpolation_type_requirements( |
| 656 | + template: &TemplateInput, |
| 657 | +) -> BackendResult<Vec<InterpolationTypeRequirement>> { |
| 658 | + interpolation_type_requirements_with_profile(template, JsonProfile::default()) |
| 659 | +} |
| 660 | + |
| 661 | +fn collect_json_value_type_requirements( |
| 662 | + value: &JsonValueNode, |
| 663 | + requirements: &mut Vec<InterpolationTypeRequirement>, |
| 664 | +) { |
| 665 | + match value { |
| 666 | + JsonValueNode::String(node) => { |
| 667 | + collect_json_string_type_requirements(node, requirements); |
| 668 | + } |
| 669 | + JsonValueNode::Literal(_) => {} |
| 670 | + JsonValueNode::Interpolation(node) => { |
| 671 | + requirements.push(json_type_requirement(node)); |
| 672 | + } |
| 673 | + JsonValueNode::Object(node) => { |
| 674 | + for member in &node.members { |
| 675 | + collect_json_key_type_requirements(&member.key, requirements); |
| 676 | + collect_json_value_type_requirements(&member.value, requirements); |
| 677 | + } |
| 678 | + } |
| 679 | + JsonValueNode::Array(node) => { |
| 680 | + for item in &node.items { |
| 681 | + collect_json_value_type_requirements(item, requirements); |
| 682 | + } |
| 683 | + } |
| 684 | + } |
| 685 | +} |
| 686 | + |
| 687 | +fn collect_json_key_type_requirements( |
| 688 | + key: &JsonKeyNode, |
| 689 | + requirements: &mut Vec<InterpolationTypeRequirement>, |
| 690 | +) { |
| 691 | + match &key.value { |
| 692 | + JsonKeyValue::String(node) => { |
| 693 | + collect_json_string_type_requirements(node, requirements); |
| 694 | + } |
| 695 | + JsonKeyValue::Interpolation(node) => { |
| 696 | + requirements.push(json_type_requirement(node)); |
| 697 | + } |
| 698 | + } |
| 699 | +} |
| 700 | + |
| 701 | +fn collect_json_string_type_requirements( |
| 702 | + string: &JsonStringNode, |
| 703 | + requirements: &mut Vec<InterpolationTypeRequirement>, |
| 704 | +) { |
| 705 | + for chunk in &string.chunks { |
| 706 | + if let JsonStringPart::Interpolation(node) = chunk { |
| 707 | + requirements.push(json_type_requirement(node)); |
| 708 | + } |
| 709 | + } |
| 710 | +} |
| 711 | + |
| 712 | +fn json_type_requirement(node: &JsonInterpolationNode) -> InterpolationTypeRequirement { |
| 713 | + match node.role.as_str() { |
| 714 | + "value" => InterpolationTypeRequirement::new( |
| 715 | + node.interpolation_index, |
| 716 | + JSON_VALUE_PYTHON_TYPE, |
| 717 | + "json value", |
| 718 | + ), |
| 719 | + "key" => InterpolationTypeRequirement::new( |
| 720 | + node.interpolation_index, |
| 721 | + STRING_PYTHON_TYPE, |
| 722 | + "json object key", |
| 723 | + ), |
| 724 | + "string_fragment" => InterpolationTypeRequirement::new( |
| 725 | + node.interpolation_index, |
| 726 | + STRING_PYTHON_TYPE, |
| 727 | + "json string fragment", |
| 728 | + ), |
| 729 | + _ => InterpolationTypeRequirement::new( |
| 730 | + node.interpolation_index, |
| 731 | + JSON_VALUE_PYTHON_TYPE, |
| 732 | + "json interpolation", |
| 733 | + ), |
| 734 | + } |
| 735 | +} |
| 736 | + |
639 | 737 | pub fn format_template_with_profile( |
640 | 738 | template: &TemplateInput, |
641 | 739 | profile: JsonProfile, |
|
0 commit comments