tstring-bindings 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/Cargo.lock +8 -8
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/Cargo.toml +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/PKG-INFO +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/json-tstring-rs/Cargo.toml +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/json-tstring-rs/src/lib.rs +100 -2
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/json-tstring-rs/tests/parser.rs +31 -3
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/pyproject.toml +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python-bindings/Cargo.toml +5 -5
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python-bindings/src/lib.rs +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/toml-tstring-rs/Cargo.toml +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/toml-tstring-rs/src/lib.rs +108 -4
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/toml-tstring-rs/tests/parser.rs +40 -3
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-core-rs/src/lib.rs +22 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/Cargo.toml +4 -4
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/benches/render_paths.rs +29 -5
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/Cargo.toml +1 -1
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/src/lib.rs +172 -3
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/tests/parser.rs +62 -2
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/json-tstring-rs/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/json-tstring-rs/tests/conformance.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/__init__.py +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/__init__.pyi +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/_profiles.py +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/_types.py +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/py.typed +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/tstring_bindings.pyi +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python-bindings/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/toml-tstring-rs/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/toml-tstring-rs/tests/conformance.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-core-rs/Cargo.toml +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-core-rs/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/src/json.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/src/lib.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/src/toml.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/src/yaml.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/README.md +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/test-support/renderer_layout.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/tests/conformance.rs +0 -0
- {tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/tests/normalized.rs +0 -0
|
@@ -725,7 +725,7 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
|
|
|
725
725
|
|
|
726
726
|
[[package]]
|
|
727
727
|
name = "tstring-backend-e2e-tests"
|
|
728
|
-
version = "0.2.
|
|
728
|
+
version = "0.2.2"
|
|
729
729
|
dependencies = [
|
|
730
730
|
"tstring-json",
|
|
731
731
|
"tstring-syntax",
|
|
@@ -735,7 +735,7 @@ dependencies = [
|
|
|
735
735
|
|
|
736
736
|
[[package]]
|
|
737
737
|
name = "tstring-bindings"
|
|
738
|
-
version = "0.2.
|
|
738
|
+
version = "0.2.2"
|
|
739
739
|
dependencies = [
|
|
740
740
|
"pyo3",
|
|
741
741
|
"pythonize",
|
|
@@ -751,7 +751,7 @@ dependencies = [
|
|
|
751
751
|
|
|
752
752
|
[[package]]
|
|
753
753
|
name = "tstring-json"
|
|
754
|
-
version = "0.2.
|
|
754
|
+
version = "0.2.2"
|
|
755
755
|
dependencies = [
|
|
756
756
|
"serde_json",
|
|
757
757
|
"toml",
|
|
@@ -760,7 +760,7 @@ dependencies = [
|
|
|
760
760
|
|
|
761
761
|
[[package]]
|
|
762
762
|
name = "tstring-pyo3-bindings"
|
|
763
|
-
version = "0.2.
|
|
763
|
+
version = "0.2.2"
|
|
764
764
|
dependencies = [
|
|
765
765
|
"criterion",
|
|
766
766
|
"pyo3",
|
|
@@ -776,14 +776,14 @@ dependencies = [
|
|
|
776
776
|
|
|
777
777
|
[[package]]
|
|
778
778
|
name = "tstring-syntax"
|
|
779
|
-
version = "0.2.
|
|
779
|
+
version = "0.2.2"
|
|
780
780
|
dependencies = [
|
|
781
781
|
"num-bigint",
|
|
782
782
|
]
|
|
783
783
|
|
|
784
784
|
[[package]]
|
|
785
785
|
name = "tstring-toml"
|
|
786
|
-
version = "0.2.
|
|
786
|
+
version = "0.2.2"
|
|
787
787
|
dependencies = [
|
|
788
788
|
"serde_json",
|
|
789
789
|
"toml",
|
|
@@ -792,7 +792,7 @@ dependencies = [
|
|
|
792
792
|
|
|
793
793
|
[[package]]
|
|
794
794
|
name = "tstring-yaml"
|
|
795
|
-
version = "0.2.
|
|
795
|
+
version = "0.2.2"
|
|
796
796
|
dependencies = [
|
|
797
797
|
"saphyr",
|
|
798
798
|
"saphyr-parser",
|
|
@@ -803,7 +803,7 @@ dependencies = [
|
|
|
803
803
|
|
|
804
804
|
[[package]]
|
|
805
805
|
name = "tstring-yaml-pyo3-tests"
|
|
806
|
-
version = "0.2.
|
|
806
|
+
version = "0.2.2"
|
|
807
807
|
dependencies = [
|
|
808
808
|
"pyo3",
|
|
809
809
|
"saphyr",
|
|
@@ -9,7 +9,7 @@ homepage = "https://github.com/koxudaxi/tstring-structured-data"
|
|
|
9
9
|
license = "MIT"
|
|
10
10
|
repository = "https://github.com/koxudaxi/tstring-structured-data"
|
|
11
11
|
rust-version = "1.94.0"
|
|
12
|
-
version = "0.2.
|
|
12
|
+
version = "0.2.2"
|
|
13
13
|
|
|
14
14
|
[workspace.dependencies]
|
|
15
15
|
num-bigint = "0.4.6"
|
|
@@ -18,7 +18,7 @@ test = false
|
|
|
18
18
|
|
|
19
19
|
[dependencies]
|
|
20
20
|
serde_json = { workspace = true }
|
|
21
|
-
tstring-syntax = { version = "0.2.
|
|
21
|
+
tstring-syntax = { version = "0.2.2", path = "../tstring-core-rs" }
|
|
22
22
|
|
|
23
23
|
[dev-dependencies]
|
|
24
24
|
toml = { workspace = true }
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
use serde_json::Value;
|
|
2
2
|
use std::str::FromStr;
|
|
3
3
|
use tstring_syntax::{
|
|
4
|
-
BackendError, BackendResult, NormalizedDocument, NormalizedFloat,
|
|
5
|
-
NormalizedStream, NormalizedValue, SourcePosition, SourceSpan, StreamItem,
|
|
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,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
use tstring_json::{
|
|
2
|
-
JsonKeyValue, JsonStringPart, JsonValueNode, check_template, format_template,
|
|
3
|
-
parse_validated_template, validate_template,
|
|
2
|
+
JsonKeyValue, JsonStringPart, JsonValueNode, check_template, format_template,
|
|
3
|
+
interpolation_type_requirements, parse_template, parse_validated_template, validate_template,
|
|
4
|
+
};
|
|
5
|
+
use tstring_syntax::{
|
|
6
|
+
InterpolationTypeRequirement, TemplateInput, TemplateInterpolation, TemplateSegment,
|
|
4
7
|
};
|
|
5
|
-
use tstring_syntax::{TemplateInput, TemplateInterpolation, TemplateSegment};
|
|
6
8
|
|
|
7
9
|
fn interpolation(index: usize, expression: &str) -> TemplateSegment {
|
|
8
10
|
TemplateSegment::Interpolation(TemplateInterpolation {
|
|
@@ -69,6 +71,32 @@ fn checks_valid_json_templates() {
|
|
|
69
71
|
check_template(&template).expect("expected check success");
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
#[test]
|
|
75
|
+
fn reports_contextual_interpolation_type_requirements() {
|
|
76
|
+
let template = TemplateInput::from_segments(vec![
|
|
77
|
+
TemplateSegment::StaticText("{".to_owned()),
|
|
78
|
+
interpolation(0, "key"),
|
|
79
|
+
TemplateSegment::StaticText(": ".to_owned()),
|
|
80
|
+
interpolation(1, "value"),
|
|
81
|
+
TemplateSegment::StaticText(", \"label\": \"".to_owned()),
|
|
82
|
+
interpolation(2, "label"),
|
|
83
|
+
TemplateSegment::StaticText("\"}".to_owned()),
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
assert_eq!(
|
|
87
|
+
interpolation_type_requirements(&template).expect("expected type requirements"),
|
|
88
|
+
vec![
|
|
89
|
+
InterpolationTypeRequirement::new(0, "str", "json object key"),
|
|
90
|
+
InterpolationTypeRequirement::new(
|
|
91
|
+
1,
|
|
92
|
+
"str | int | float | bool | None | dict[str, object] | list[object]",
|
|
93
|
+
"json value"
|
|
94
|
+
),
|
|
95
|
+
InterpolationTypeRequirement::new(2, "str", "json string fragment"),
|
|
96
|
+
]
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
72
100
|
#[test]
|
|
73
101
|
fn validates_json_templates_with_supported_interpolations() {
|
|
74
102
|
let template = TemplateInput::from_segments(vec![
|
|
@@ -24,12 +24,12 @@ pyo3 = { workspace = true, features = ["abi3-py314"] }
|
|
|
24
24
|
pythonize = { workspace = true }
|
|
25
25
|
saphyr = { workspace = true }
|
|
26
26
|
serde_json = { workspace = true }
|
|
27
|
-
tstring-json = { version = "0.2.
|
|
28
|
-
tstring-pyo3-bindings = { version = "0.2.
|
|
29
|
-
tstring-syntax = { version = "0.2.
|
|
27
|
+
tstring-json = { version = "0.2.2", path = "../json-tstring-rs" }
|
|
28
|
+
tstring-pyo3-bindings = { version = "0.2.2", path = "../tstring-pyo3-bindings" }
|
|
29
|
+
tstring-syntax = { version = "0.2.2", path = "../tstring-core-rs" }
|
|
30
30
|
toml = { workspace = true }
|
|
31
|
-
tstring-toml = { version = "0.2.
|
|
32
|
-
tstring-yaml = { version = "0.2.
|
|
31
|
+
tstring-toml = { version = "0.2.2", path = "../toml-tstring-rs" }
|
|
32
|
+
tstring-yaml = { version = "0.2.2", path = "../yaml-tstring-rs" }
|
|
33
33
|
|
|
34
34
|
[dev-dependencies]
|
|
35
35
|
pyo3 = { workspace = true, features = ["auto-initialize"] }
|
|
@@ -627,7 +627,7 @@ fn normalized_offset_to_python(py: Python<'_>, offset_minutes: i16) -> PyResult<
|
|
|
627
627
|
|
|
628
628
|
#[pymodule]
|
|
629
629
|
fn tstring_bindings(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
630
|
-
module.add("__version__", "0.2.
|
|
630
|
+
module.add("__version__", "0.2.2")?;
|
|
631
631
|
module.add("__contract_version__", CONTRACT_VERSION)?;
|
|
632
632
|
module.add("__contract_symbols__", PyTuple::new(py, CONTRACT_SYMBOLS)?)?;
|
|
633
633
|
module.add("TemplateError", py.get_type::<TemplateError>())?;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
use tstring_syntax::{
|
|
2
|
-
BackendError, BackendResult, NormalizedDate, NormalizedDocument,
|
|
3
|
-
NormalizedFloat, NormalizedKey, NormalizedLocalDateTime,
|
|
4
|
-
NormalizedStream, NormalizedTemporal, NormalizedTime,
|
|
5
|
-
SourceSpan, StreamItem, TemplateInput,
|
|
2
|
+
BackendError, BackendResult, InterpolationTypeRequirement, NormalizedDate, NormalizedDocument,
|
|
3
|
+
NormalizedEntry, NormalizedFloat, NormalizedKey, NormalizedLocalDateTime,
|
|
4
|
+
NormalizedOffsetDateTime, NormalizedStream, NormalizedTemporal, NormalizedTime,
|
|
5
|
+
NormalizedValue, SourcePosition, SourceSpan, StreamItem, TemplateInput,
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
const TOML_VALUE_PYTHON_TYPE: &str = "str | int | float | bool | datetime.date | datetime.time | datetime.datetime | list[object] | dict[str, object]";
|
|
9
|
+
const STRING_PYTHON_TYPE: &str = "str";
|
|
10
|
+
|
|
8
11
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
9
12
|
pub enum TomlProfile {
|
|
10
13
|
V1_0,
|
|
@@ -1146,6 +1149,107 @@ pub fn check_template(template: &TemplateInput) -> BackendResult<()> {
|
|
|
1146
1149
|
check_template_with_profile(template, TomlProfile::default())
|
|
1147
1150
|
}
|
|
1148
1151
|
|
|
1152
|
+
pub fn interpolation_type_requirements_with_profile(
|
|
1153
|
+
template: &TemplateInput,
|
|
1154
|
+
profile: TomlProfile,
|
|
1155
|
+
) -> BackendResult<Vec<InterpolationTypeRequirement>> {
|
|
1156
|
+
let document = parse_validated_template_with_profile(template, profile)?;
|
|
1157
|
+
let mut requirements = Vec::new();
|
|
1158
|
+
collect_toml_document_type_requirements(&document, &mut requirements);
|
|
1159
|
+
requirements.sort_by_key(|requirement| requirement.interpolation_index);
|
|
1160
|
+
Ok(requirements)
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
pub fn interpolation_type_requirements(
|
|
1164
|
+
template: &TemplateInput,
|
|
1165
|
+
) -> BackendResult<Vec<InterpolationTypeRequirement>> {
|
|
1166
|
+
interpolation_type_requirements_with_profile(template, TomlProfile::default())
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
fn collect_toml_document_type_requirements(
|
|
1170
|
+
document: &TomlDocumentNode,
|
|
1171
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
1172
|
+
) {
|
|
1173
|
+
for statement in &document.statements {
|
|
1174
|
+
match statement {
|
|
1175
|
+
TomlStatementNode::Assignment(node) => {
|
|
1176
|
+
collect_toml_key_path_type_requirements(&node.key_path, requirements);
|
|
1177
|
+
collect_toml_value_type_requirements(&node.value, requirements);
|
|
1178
|
+
}
|
|
1179
|
+
TomlStatementNode::TableHeader(node) => {
|
|
1180
|
+
collect_toml_key_path_type_requirements(&node.key_path, requirements);
|
|
1181
|
+
}
|
|
1182
|
+
TomlStatementNode::ArrayTableHeader(node) => {
|
|
1183
|
+
collect_toml_key_path_type_requirements(&node.key_path, requirements);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
fn collect_toml_key_path_type_requirements(
|
|
1190
|
+
key_path: &TomlKeyPathNode,
|
|
1191
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
1192
|
+
) {
|
|
1193
|
+
for segment in &key_path.segments {
|
|
1194
|
+
match &segment.value {
|
|
1195
|
+
TomlKeySegmentValue::Bare(_) => {}
|
|
1196
|
+
TomlKeySegmentValue::String(node) => {
|
|
1197
|
+
collect_toml_string_type_requirements(node, requirements);
|
|
1198
|
+
}
|
|
1199
|
+
TomlKeySegmentValue::Interpolation(node) => {
|
|
1200
|
+
requirements.push(InterpolationTypeRequirement::new(
|
|
1201
|
+
node.interpolation_index,
|
|
1202
|
+
STRING_PYTHON_TYPE,
|
|
1203
|
+
"toml key",
|
|
1204
|
+
));
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
fn collect_toml_value_type_requirements(
|
|
1211
|
+
value: &TomlValueNode,
|
|
1212
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
1213
|
+
) {
|
|
1214
|
+
match value {
|
|
1215
|
+
TomlValueNode::String(node) => collect_toml_string_type_requirements(node, requirements),
|
|
1216
|
+
TomlValueNode::Literal(_) => {}
|
|
1217
|
+
TomlValueNode::Interpolation(node) => {
|
|
1218
|
+
requirements.push(InterpolationTypeRequirement::new(
|
|
1219
|
+
node.interpolation_index,
|
|
1220
|
+
TOML_VALUE_PYTHON_TYPE,
|
|
1221
|
+
"toml value",
|
|
1222
|
+
));
|
|
1223
|
+
}
|
|
1224
|
+
TomlValueNode::Array(node) => {
|
|
1225
|
+
for item in &node.items {
|
|
1226
|
+
collect_toml_value_type_requirements(item, requirements);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
TomlValueNode::InlineTable(node) => {
|
|
1230
|
+
for entry in &node.entries {
|
|
1231
|
+
collect_toml_key_path_type_requirements(&entry.key_path, requirements);
|
|
1232
|
+
collect_toml_value_type_requirements(&entry.value, requirements);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
fn collect_toml_string_type_requirements(
|
|
1239
|
+
string: &TomlStringNode,
|
|
1240
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
1241
|
+
) {
|
|
1242
|
+
for chunk in &string.chunks {
|
|
1243
|
+
if let TomlStringPart::Interpolation(node) = chunk {
|
|
1244
|
+
requirements.push(InterpolationTypeRequirement::new(
|
|
1245
|
+
node.interpolation_index,
|
|
1246
|
+
STRING_PYTHON_TYPE,
|
|
1247
|
+
"toml string fragment",
|
|
1248
|
+
));
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1149
1253
|
pub fn format_template_with_profile(
|
|
1150
1254
|
template: &TemplateInput,
|
|
1151
1255
|
profile: TomlProfile,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
use tstring_syntax::{
|
|
1
|
+
use tstring_syntax::{
|
|
2
|
+
InterpolationTypeRequirement, TemplateInput, TemplateInterpolation, TemplateSegment,
|
|
3
|
+
};
|
|
2
4
|
use tstring_toml::{
|
|
3
|
-
TomlStatementNode, TomlValueNode, check_template, format_template,
|
|
4
|
-
parse_validated_template, validate_template,
|
|
5
|
+
TomlStatementNode, TomlValueNode, check_template, format_template,
|
|
6
|
+
interpolation_type_requirements, parse_template, parse_validated_template, validate_template,
|
|
5
7
|
};
|
|
6
8
|
|
|
7
9
|
fn interpolation(index: usize, expression: &str) -> TemplateSegment {
|
|
@@ -83,6 +85,41 @@ fn validates_toml_templates_with_supported_interpolations() {
|
|
|
83
85
|
parse_validated_template(&template).expect("expected validated parse success");
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
#[test]
|
|
89
|
+
fn reports_contextual_interpolation_type_requirements() {
|
|
90
|
+
let template = TemplateInput::from_segments(vec![
|
|
91
|
+
interpolation(0, "table"),
|
|
92
|
+
TemplateSegment::StaticText(".title = ".to_owned()),
|
|
93
|
+
interpolation(1, "value"),
|
|
94
|
+
TemplateSegment::StaticText("\nmessage = \"Hello ".to_owned()),
|
|
95
|
+
interpolation(2, "fragment"),
|
|
96
|
+
TemplateSegment::StaticText("\"\nmeta = { ".to_owned()),
|
|
97
|
+
interpolation(3, "inline_key"),
|
|
98
|
+
TemplateSegment::StaticText(" = ".to_owned()),
|
|
99
|
+
interpolation(4, "inline_value"),
|
|
100
|
+
TemplateSegment::StaticText(" }\n".to_owned()),
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
assert_eq!(
|
|
104
|
+
interpolation_type_requirements(&template).expect("expected type requirements"),
|
|
105
|
+
vec![
|
|
106
|
+
InterpolationTypeRequirement::new(0, "str", "toml key"),
|
|
107
|
+
InterpolationTypeRequirement::new(
|
|
108
|
+
1,
|
|
109
|
+
"str | int | float | bool | datetime.date | datetime.time | datetime.datetime | list[object] | dict[str, object]",
|
|
110
|
+
"toml value"
|
|
111
|
+
),
|
|
112
|
+
InterpolationTypeRequirement::new(2, "str", "toml string fragment"),
|
|
113
|
+
InterpolationTypeRequirement::new(3, "str", "toml key"),
|
|
114
|
+
InterpolationTypeRequirement::new(
|
|
115
|
+
4,
|
|
116
|
+
"str | int | float | bool | datetime.date | datetime.time | datetime.datetime | list[object] | dict[str, object]",
|
|
117
|
+
"toml value"
|
|
118
|
+
),
|
|
119
|
+
]
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
86
123
|
#[test]
|
|
87
124
|
fn formats_toml_templates_with_raw_interpolations() {
|
|
88
125
|
let template = TemplateInput::from_segments(vec![
|
|
@@ -176,6 +176,28 @@ impl std::error::Error for BackendError {}
|
|
|
176
176
|
|
|
177
177
|
pub type BackendResult<T> = Result<T, BackendError>;
|
|
178
178
|
|
|
179
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
180
|
+
pub struct InterpolationTypeRequirement {
|
|
181
|
+
pub interpolation_index: usize,
|
|
182
|
+
pub expected_python_type: String,
|
|
183
|
+
pub expected_description: String,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
impl InterpolationTypeRequirement {
|
|
187
|
+
#[must_use]
|
|
188
|
+
pub fn new(
|
|
189
|
+
interpolation_index: usize,
|
|
190
|
+
expected_python_type: impl Into<String>,
|
|
191
|
+
expected_description: impl Into<String>,
|
|
192
|
+
) -> Self {
|
|
193
|
+
Self {
|
|
194
|
+
interpolation_index,
|
|
195
|
+
expected_python_type: expected_python_type.into(),
|
|
196
|
+
expected_description: expected_description.into(),
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
179
201
|
#[derive(Clone, Debug, PartialEq)]
|
|
180
202
|
pub struct NormalizedStream {
|
|
181
203
|
pub documents: Vec<NormalizedDocument>,
|
|
@@ -16,10 +16,10 @@ serde_json = { workspace = true }
|
|
|
16
16
|
saphyr = { workspace = true }
|
|
17
17
|
saphyr-parser = { workspace = true }
|
|
18
18
|
toml = { workspace = true }
|
|
19
|
-
tstring-json = { version = "0.2.
|
|
20
|
-
tstring-syntax = { version = "0.2.
|
|
21
|
-
tstring-toml = { version = "0.2.
|
|
22
|
-
tstring-yaml = { version = "0.2.
|
|
19
|
+
tstring-json = { version = "0.2.2", path = "../json-tstring-rs" }
|
|
20
|
+
tstring-syntax = { version = "0.2.2", path = "../tstring-core-rs" }
|
|
21
|
+
tstring-toml = { version = "0.2.2", path = "../toml-tstring-rs" }
|
|
22
|
+
tstring-yaml = { version = "0.2.2", path = "../yaml-tstring-rs" }
|
|
23
23
|
|
|
24
24
|
[dev-dependencies]
|
|
25
25
|
criterion = "0.8.2"
|
{tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/tstring-pyo3-bindings/benches/render_paths.rs
RENAMED
|
@@ -11,7 +11,7 @@ fn benchmark_json_metadata_render(criterion: &mut Criterion) {
|
|
|
11
11
|
let module = PyModule::from_code(
|
|
12
12
|
py,
|
|
13
13
|
pyo3::ffi::c_str!(
|
|
14
|
-
"value=3.14159\nlabel='service'\nitems=[1, 2, 3]\nmeta={'region': 'us-east-1', 'count': 3}\ntemplate=t'{\"format\": {value:.2f}, \"label\": \"{label!s}\", \"items\": {items}, \"meta\": {meta}, \"fragment\": \"pi={value:.2f}\"}'\n"
|
|
14
|
+
"value=3.14159\nlabel='service'\nitems=[1, 2, 3]\nmeta={'region': 'us-east-1', 'count': 3}\ntemplate=t'{{\"format\": {value:.2f}, \"label\": \"{label!s}\", \"items\": {items}, \"meta\": {meta}, \"fragment\": \"pi={value:.2f}\"}}'\n"
|
|
15
15
|
),
|
|
16
16
|
pyo3::ffi::c_str!("bench_json_metadata.py"),
|
|
17
17
|
pyo3::ffi::c_str!("bench_json_metadata"),
|
|
@@ -26,7 +26,13 @@ fn benchmark_json_metadata_render(criterion: &mut Criterion) {
|
|
|
26
26
|
criterion.bench_function("json_metadata_render", |bench| {
|
|
27
27
|
bench.iter(|| {
|
|
28
28
|
Python::with_gil(|py| {
|
|
29
|
-
json_backend::render_document(
|
|
29
|
+
json_backend::render_document(
|
|
30
|
+
py,
|
|
31
|
+
&template,
|
|
32
|
+
tstring_json::JsonProfile::default(),
|
|
33
|
+
node.as_ref(),
|
|
34
|
+
)
|
|
35
|
+
.unwrap();
|
|
30
36
|
});
|
|
31
37
|
});
|
|
32
38
|
});
|
|
@@ -52,7 +58,13 @@ fn benchmark_toml_metadata_render(criterion: &mut Criterion) {
|
|
|
52
58
|
criterion.bench_function("toml_metadata_render", |bench| {
|
|
53
59
|
bench.iter(|| {
|
|
54
60
|
Python::with_gil(|py| {
|
|
55
|
-
toml_backend::render_document(
|
|
61
|
+
toml_backend::render_document(
|
|
62
|
+
py,
|
|
63
|
+
&template,
|
|
64
|
+
tstring_toml::TomlProfile::default(),
|
|
65
|
+
node.as_ref(),
|
|
66
|
+
)
|
|
67
|
+
.unwrap();
|
|
56
68
|
});
|
|
57
69
|
});
|
|
58
70
|
});
|
|
@@ -78,7 +90,13 @@ fn benchmark_toml_dynamic_header_render(criterion: &mut Criterion) {
|
|
|
78
90
|
criterion.bench_function("toml_dynamic_header_render", |bench| {
|
|
79
91
|
bench.iter(|| {
|
|
80
92
|
Python::with_gil(|py| {
|
|
81
|
-
toml_backend::render_document(
|
|
93
|
+
toml_backend::render_document(
|
|
94
|
+
py,
|
|
95
|
+
&template,
|
|
96
|
+
tstring_toml::TomlProfile::default(),
|
|
97
|
+
node.as_ref(),
|
|
98
|
+
)
|
|
99
|
+
.unwrap();
|
|
82
100
|
});
|
|
83
101
|
});
|
|
84
102
|
});
|
|
@@ -104,7 +122,13 @@ fn benchmark_yaml_metadata_render(criterion: &mut Criterion) {
|
|
|
104
122
|
criterion.bench_function("yaml_metadata_render", |bench| {
|
|
105
123
|
bench.iter(|| {
|
|
106
124
|
Python::with_gil(|py| {
|
|
107
|
-
yaml_backend::render_document(
|
|
125
|
+
yaml_backend::render_document(
|
|
126
|
+
py,
|
|
127
|
+
&template,
|
|
128
|
+
tstring_yaml::YamlProfile::default(),
|
|
129
|
+
node.as_ref(),
|
|
130
|
+
)
|
|
131
|
+
.unwrap();
|
|
108
132
|
});
|
|
109
133
|
});
|
|
110
134
|
});
|
|
@@ -20,7 +20,7 @@ test = false
|
|
|
20
20
|
saphyr = { workspace = true }
|
|
21
21
|
saphyr-parser = { workspace = true }
|
|
22
22
|
serde_json = { workspace = true }
|
|
23
|
-
tstring-syntax = { version = "0.2.
|
|
23
|
+
tstring-syntax = { version = "0.2.2", path = "../tstring-core-rs" }
|
|
24
24
|
|
|
25
25
|
[dev-dependencies]
|
|
26
26
|
toml = { workspace = true }
|
|
@@ -3,11 +3,14 @@ use saphyr_parser::{ScalarStyle, Tag};
|
|
|
3
3
|
use std::borrow::Cow;
|
|
4
4
|
use std::str::FromStr;
|
|
5
5
|
use tstring_syntax::{
|
|
6
|
-
BackendError, BackendResult, NormalizedDocument, NormalizedEntry,
|
|
7
|
-
NormalizedKey, NormalizedKeyEntry, NormalizedStream, NormalizedValue,
|
|
8
|
-
SourceSpan, StreamItem, TemplateInput,
|
|
6
|
+
BackendError, BackendResult, InterpolationTypeRequirement, NormalizedDocument, NormalizedEntry,
|
|
7
|
+
NormalizedFloat, NormalizedKey, NormalizedKeyEntry, NormalizedStream, NormalizedValue,
|
|
8
|
+
SourcePosition, SourceSpan, StreamItem, TemplateInput,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
const YAML_VALUE_PYTHON_TYPE: &str = "str | int | float | bool | None | datetime.date | datetime.time | datetime.datetime | list[object] | dict[object, object]";
|
|
12
|
+
const STRING_PYTHON_TYPE: &str = "str";
|
|
13
|
+
|
|
11
14
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
12
15
|
pub enum YamlProfile {
|
|
13
16
|
V1_2_2,
|
|
@@ -2084,6 +2087,172 @@ pub fn check_template(template: &TemplateInput) -> BackendResult<()> {
|
|
|
2084
2087
|
check_template_with_profile(template, YamlProfile::default())
|
|
2085
2088
|
}
|
|
2086
2089
|
|
|
2090
|
+
pub fn interpolation_type_requirements_with_profile(
|
|
2091
|
+
template: &TemplateInput,
|
|
2092
|
+
profile: YamlProfile,
|
|
2093
|
+
) -> BackendResult<Vec<InterpolationTypeRequirement>> {
|
|
2094
|
+
let stream = parse_validated_template_with_profile(template, profile)?;
|
|
2095
|
+
let mut requirements = Vec::new();
|
|
2096
|
+
collect_yaml_stream_type_requirements(&stream, &mut requirements);
|
|
2097
|
+
requirements.sort_by_key(|requirement| requirement.interpolation_index);
|
|
2098
|
+
Ok(requirements)
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
pub fn interpolation_type_requirements(
|
|
2102
|
+
template: &TemplateInput,
|
|
2103
|
+
) -> BackendResult<Vec<InterpolationTypeRequirement>> {
|
|
2104
|
+
interpolation_type_requirements_with_profile(template, YamlProfile::default())
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
2108
|
+
enum YamlInterpolationContext {
|
|
2109
|
+
Value,
|
|
2110
|
+
MappingKey,
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
fn collect_yaml_stream_type_requirements(
|
|
2114
|
+
stream: &YamlStreamNode,
|
|
2115
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
2116
|
+
) {
|
|
2117
|
+
for document in &stream.documents {
|
|
2118
|
+
collect_yaml_value_type_requirements(
|
|
2119
|
+
&document.value,
|
|
2120
|
+
YamlInterpolationContext::Value,
|
|
2121
|
+
requirements,
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
fn collect_yaml_value_type_requirements(
|
|
2127
|
+
value: &YamlValueNode,
|
|
2128
|
+
context: YamlInterpolationContext,
|
|
2129
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
2130
|
+
) {
|
|
2131
|
+
match value {
|
|
2132
|
+
YamlValueNode::Scalar(node) => {
|
|
2133
|
+
collect_yaml_scalar_type_requirements(node, "yaml scalar fragment", requirements);
|
|
2134
|
+
}
|
|
2135
|
+
YamlValueNode::Interpolation(node) => {
|
|
2136
|
+
requirements.push(yaml_value_type_requirement(node, context));
|
|
2137
|
+
}
|
|
2138
|
+
YamlValueNode::Mapping(node) => {
|
|
2139
|
+
for entry in &node.entries {
|
|
2140
|
+
collect_yaml_key_type_requirements(&entry.key, requirements);
|
|
2141
|
+
collect_yaml_value_type_requirements(
|
|
2142
|
+
&entry.value,
|
|
2143
|
+
YamlInterpolationContext::Value,
|
|
2144
|
+
requirements,
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
YamlValueNode::Sequence(node) => {
|
|
2149
|
+
for item in &node.items {
|
|
2150
|
+
collect_yaml_value_type_requirements(item, context, requirements);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
YamlValueNode::Decorated(node) => {
|
|
2154
|
+
if let Some(tag) = &node.tag {
|
|
2155
|
+
collect_yaml_chunk_type_requirements(
|
|
2156
|
+
&tag.chunks,
|
|
2157
|
+
"yaml metadata fragment",
|
|
2158
|
+
requirements,
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
if let Some(anchor) = &node.anchor {
|
|
2162
|
+
collect_yaml_chunk_type_requirements(
|
|
2163
|
+
&anchor.chunks,
|
|
2164
|
+
"yaml metadata fragment",
|
|
2165
|
+
requirements,
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
collect_yaml_value_type_requirements(&node.value, context, requirements);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
fn collect_yaml_key_type_requirements(
|
|
2174
|
+
key: &YamlKeyNode,
|
|
2175
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
2176
|
+
) {
|
|
2177
|
+
match &key.value {
|
|
2178
|
+
YamlKeyValue::Scalar(node) => {
|
|
2179
|
+
collect_yaml_scalar_type_requirements(node, "yaml scalar fragment", requirements);
|
|
2180
|
+
}
|
|
2181
|
+
YamlKeyValue::Interpolation(node) => {
|
|
2182
|
+
requirements.push(yaml_value_type_requirement(
|
|
2183
|
+
node,
|
|
2184
|
+
YamlInterpolationContext::MappingKey,
|
|
2185
|
+
));
|
|
2186
|
+
}
|
|
2187
|
+
YamlKeyValue::Complex(node) => {
|
|
2188
|
+
collect_yaml_value_type_requirements(
|
|
2189
|
+
node,
|
|
2190
|
+
YamlInterpolationContext::MappingKey,
|
|
2191
|
+
requirements,
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
fn collect_yaml_scalar_type_requirements(
|
|
2198
|
+
scalar: &YamlScalarNode,
|
|
2199
|
+
description: &'static str,
|
|
2200
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
2201
|
+
) {
|
|
2202
|
+
match scalar {
|
|
2203
|
+
YamlScalarNode::Plain(node) => {
|
|
2204
|
+
collect_yaml_chunk_type_requirements(&node.chunks, description, requirements);
|
|
2205
|
+
}
|
|
2206
|
+
YamlScalarNode::DoubleQuoted(node) => {
|
|
2207
|
+
collect_yaml_chunk_type_requirements(&node.chunks, description, requirements);
|
|
2208
|
+
}
|
|
2209
|
+
YamlScalarNode::SingleQuoted(node) => {
|
|
2210
|
+
collect_yaml_chunk_type_requirements(&node.chunks, description, requirements);
|
|
2211
|
+
}
|
|
2212
|
+
YamlScalarNode::Block(node) => {
|
|
2213
|
+
collect_yaml_chunk_type_requirements(&node.chunks, description, requirements);
|
|
2214
|
+
}
|
|
2215
|
+
YamlScalarNode::Alias(node) => {
|
|
2216
|
+
collect_yaml_chunk_type_requirements(
|
|
2217
|
+
&node.chunks,
|
|
2218
|
+
"yaml metadata fragment",
|
|
2219
|
+
requirements,
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
fn collect_yaml_chunk_type_requirements(
|
|
2226
|
+
chunks: &[YamlChunk],
|
|
2227
|
+
description: &'static str,
|
|
2228
|
+
requirements: &mut Vec<InterpolationTypeRequirement>,
|
|
2229
|
+
) {
|
|
2230
|
+
for chunk in chunks {
|
|
2231
|
+
if let YamlChunk::Interpolation(node) = chunk {
|
|
2232
|
+
requirements.push(InterpolationTypeRequirement::new(
|
|
2233
|
+
node.interpolation_index,
|
|
2234
|
+
STRING_PYTHON_TYPE,
|
|
2235
|
+
description,
|
|
2236
|
+
));
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
fn yaml_value_type_requirement(
|
|
2242
|
+
node: &YamlInterpolationNode,
|
|
2243
|
+
context: YamlInterpolationContext,
|
|
2244
|
+
) -> InterpolationTypeRequirement {
|
|
2245
|
+
let description = match context {
|
|
2246
|
+
YamlInterpolationContext::Value => "yaml value",
|
|
2247
|
+
YamlInterpolationContext::MappingKey => "yaml mapping key",
|
|
2248
|
+
};
|
|
2249
|
+
InterpolationTypeRequirement::new(
|
|
2250
|
+
node.interpolation_index,
|
|
2251
|
+
YAML_VALUE_PYTHON_TYPE,
|
|
2252
|
+
description,
|
|
2253
|
+
)
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2087
2256
|
pub fn format_template_with_profile(
|
|
2088
2257
|
template: &TemplateInput,
|
|
2089
2258
|
profile: YamlProfile,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
use tstring_syntax::{
|
|
1
|
+
use tstring_syntax::{
|
|
2
|
+
InterpolationTypeRequirement, TemplateInput, TemplateInterpolation, TemplateSegment,
|
|
3
|
+
};
|
|
2
4
|
use tstring_yaml::{
|
|
3
|
-
YamlValueNode, check_template, format_template,
|
|
5
|
+
YamlValueNode, check_template, format_template, interpolation_type_requirements,
|
|
6
|
+
parse_template, validate_template,
|
|
4
7
|
};
|
|
5
8
|
|
|
6
9
|
fn interpolation(index: usize, expression: &str) -> TemplateSegment {
|
|
@@ -129,6 +132,63 @@ fn validates_plain_scalars_with_multiple_interpolations_and_no_whitespace() {
|
|
|
129
132
|
validate_template(&template).expect("expected YAML validation success");
|
|
130
133
|
}
|
|
131
134
|
|
|
135
|
+
#[test]
|
|
136
|
+
fn reports_contextual_interpolation_type_requirements() {
|
|
137
|
+
let template = TemplateInput::from_segments(vec![
|
|
138
|
+
interpolation(0, "key"),
|
|
139
|
+
TemplateSegment::StaticText(": ".to_owned()),
|
|
140
|
+
interpolation(1, "value"),
|
|
141
|
+
TemplateSegment::StaticText("\nmessage: \"Hello ".to_owned()),
|
|
142
|
+
interpolation(2, "fragment"),
|
|
143
|
+
TemplateSegment::StaticText("\"\ntagged: !<tag:".to_owned()),
|
|
144
|
+
interpolation(3, "tag"),
|
|
145
|
+
TemplateSegment::StaticText("> ".to_owned()),
|
|
146
|
+
interpolation(4, "tagged_value"),
|
|
147
|
+
TemplateSegment::StaticText("\n".to_owned()),
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
assert_eq!(
|
|
151
|
+
interpolation_type_requirements(&template).expect("expected type requirements"),
|
|
152
|
+
vec![
|
|
153
|
+
InterpolationTypeRequirement::new(
|
|
154
|
+
0,
|
|
155
|
+
"str | int | float | bool | None | datetime.date | datetime.time | datetime.datetime | list[object] | dict[object, object]",
|
|
156
|
+
"yaml mapping key"
|
|
157
|
+
),
|
|
158
|
+
InterpolationTypeRequirement::new(
|
|
159
|
+
1,
|
|
160
|
+
"str | int | float | bool | None | datetime.date | datetime.time | datetime.datetime | list[object] | dict[object, object]",
|
|
161
|
+
"yaml value"
|
|
162
|
+
),
|
|
163
|
+
InterpolationTypeRequirement::new(2, "str", "yaml scalar fragment"),
|
|
164
|
+
InterpolationTypeRequirement::new(3, "str", "yaml metadata fragment"),
|
|
165
|
+
InterpolationTypeRequirement::new(
|
|
166
|
+
4,
|
|
167
|
+
"str | int | float | bool | None | datetime.date | datetime.time | datetime.datetime | list[object] | dict[object, object]",
|
|
168
|
+
"yaml value"
|
|
169
|
+
),
|
|
170
|
+
]
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
#[test]
|
|
175
|
+
fn reports_complex_key_interpolation_requirements_in_key_context() {
|
|
176
|
+
let template = TemplateInput::from_segments(vec![
|
|
177
|
+
TemplateSegment::StaticText("? [".to_owned()),
|
|
178
|
+
interpolation(0, "item"),
|
|
179
|
+
TemplateSegment::StaticText("]\n: ok\n".to_owned()),
|
|
180
|
+
]);
|
|
181
|
+
|
|
182
|
+
assert_eq!(
|
|
183
|
+
interpolation_type_requirements(&template).expect("expected type requirements"),
|
|
184
|
+
vec![InterpolationTypeRequirement::new(
|
|
185
|
+
0,
|
|
186
|
+
"str | int | float | bool | None | datetime.date | datetime.time | datetime.datetime | list[object] | dict[object, object]",
|
|
187
|
+
"yaml mapping key"
|
|
188
|
+
)]
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
132
192
|
#[test]
|
|
133
193
|
fn formats_yaml_templates_with_raw_interpolations() {
|
|
134
194
|
let template = TemplateInput::from_segments(vec![
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/python/tstring_bindings/tstring_bindings.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tstring_bindings-0.2.1 → tstring_bindings-0.2.2}/yaml-tstring-rs/test-support/renderer_layout.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|