Skip to content

Commit 4cb5ab6

Browse files
authored
Improve YAML parsing of quoted numbers (#1583)
See: sourcemeta/jsonschema#241 Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 7cc3d4d commit 4cb5ab6

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

src/core/yaml/yaml.cc

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <sourcemeta/core/yaml.h>
22

3-
#include <sstream> // std::ostringstream
3+
#include <sstream> // std::ostringstream, std::istringstream
44
#include <string_view> // std::string_view
55

66
// See https://pyyaml.org/wiki/LibYAML for basic documentation
@@ -21,9 +21,24 @@ static auto yaml_node_to_json(yaml_node_t *const node,
2121
reinterpret_cast<char *>(node->data.scalar.value),
2222
node->data.scalar.length};
2323

24+
if (node->data.scalar.style == YAML_SINGLE_QUOTED_SCALAR_STYLE ||
25+
node->data.scalar.style == YAML_DOUBLE_QUOTED_SCALAR_STYLE) {
26+
return sourcemeta::core::JSON{input};
27+
}
28+
29+
// TODO: Avoid this std::string transformation
30+
std::istringstream stream{std::string{input}};
31+
2432
try {
25-
// TODO: Avoid this std::string transformation
26-
return sourcemeta::core::parse_json(std::string{input});
33+
auto result{sourcemeta::core::parse_json(stream)};
34+
35+
// If the entire input was not consumed, then we are missing
36+
// something
37+
if (stream.peek() != std::char_traits<char>::eof()) {
38+
return sourcemeta::core::JSON{input};
39+
}
40+
41+
return result;
2742
// Looks like it is very hard in YAML, given a scalar value, to
2843
// determine whether it is a string or something else without attempting
2944
// to parsing it and potentially failing to do so

test/yaml/yaml_parse_test.cc

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ TEST(YAML_parse, scalar_1) {
1212
EXPECT_EQ(result, expected);
1313
}
1414

15+
TEST(YAML_parse, scalar_2) {
16+
const std::string input{" 1 "};
17+
const auto result{sourcemeta::core::parse_yaml(input)};
18+
const sourcemeta::core::JSON expected{1};
19+
EXPECT_EQ(result, expected);
20+
}
21+
1522
TEST(YAML_parse, object_1) {
1623
const std::string input{"hello: world\nfoo: 1\nbar: true"};
1724

@@ -38,6 +45,66 @@ TEST(YAML_parse, object_2) {
3845
EXPECT_EQ(result, expected);
3946
}
4047

48+
TEST(YAML_parse, object_3) {
49+
const std::string input{"version: \"1.29.2\""};
50+
51+
const auto result{sourcemeta::core::parse_yaml(input)};
52+
53+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
54+
"version": "1.29.2"
55+
})JSON");
56+
57+
EXPECT_EQ(result, expected);
58+
}
59+
60+
TEST(YAML_parse, object_4) {
61+
const std::string input{"version: \'1.29.2\'"};
62+
63+
const auto result{sourcemeta::core::parse_yaml(input)};
64+
65+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
66+
"version": "1.29.2"
67+
})JSON");
68+
69+
EXPECT_EQ(result, expected);
70+
}
71+
72+
TEST(YAML_parse, object_5) {
73+
const std::string input{"version: 1.29.2"};
74+
75+
const auto result{sourcemeta::core::parse_yaml(input)};
76+
77+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
78+
"version": "1.29.2"
79+
})JSON");
80+
81+
EXPECT_EQ(result, expected);
82+
}
83+
84+
TEST(YAML_parse, object_6) {
85+
const std::string input{"version: v1.29.2"};
86+
87+
const auto result{sourcemeta::core::parse_yaml(input)};
88+
89+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
90+
"version": "v1.29.2"
91+
})JSON");
92+
93+
EXPECT_EQ(result, expected);
94+
}
95+
96+
TEST(YAML_parse, object_7) {
97+
const std::string input{"version: 1.29v"};
98+
99+
const auto result{sourcemeta::core::parse_yaml(input)};
100+
101+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
102+
"version": "1.29v"
103+
})JSON");
104+
105+
EXPECT_EQ(result, expected);
106+
}
107+
41108
TEST(YAML_parse, array_1) {
42109
const std::string input{"- foo\n- true"};
43110

0 commit comments

Comments
 (0)