add yaml::stringify
This commit is contained in:
parent
2aea19febd
commit
396fab02b3
@ -1,6 +1,8 @@
|
|||||||
#include "yaml.hpp"
|
#include "yaml.hpp"
|
||||||
#include "BasicParser.hpp"
|
#include "BasicParser.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
using namespace yaml;
|
using namespace yaml;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -316,3 +318,142 @@ dv::value yaml::parse(std::string_view filename, std::string_view source) {
|
|||||||
dv::value yaml::parse(std::string_view source) {
|
dv::value yaml::parse(std::string_view source) {
|
||||||
return parse("[string]", source);
|
return parse("[string]", source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_indent(std::stringstream& ss, int indent) {
|
||||||
|
for (int i = 0; i < indent; i++) {
|
||||||
|
ss << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_string(
|
||||||
|
std::stringstream& ss, const std::string& string, int indent
|
||||||
|
) {
|
||||||
|
bool has_spec_chars = false;
|
||||||
|
bool multiline = false;
|
||||||
|
for (char c : string) {
|
||||||
|
if (c < ' ' || c == '"' || c == '\'') {
|
||||||
|
has_spec_chars = true;
|
||||||
|
if (multiline) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
multiline = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiline) {
|
||||||
|
ss << "|-\n";
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t newoffset = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
offset = newoffset;
|
||||||
|
if (offset == string.length() - 1 && string[offset] == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
add_indent(ss, indent);
|
||||||
|
newoffset = string.find('\n', offset + 1);
|
||||||
|
if (newoffset == std::string::npos) {
|
||||||
|
ss << string.substr(offset);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ss << string.substr(offset + 1, newoffset - offset - 1);
|
||||||
|
}
|
||||||
|
ss << '\n';
|
||||||
|
} while (true);
|
||||||
|
} else {
|
||||||
|
if (has_spec_chars || string.empty()) {
|
||||||
|
ss << util::escape(string, false);
|
||||||
|
} else {
|
||||||
|
ss << string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_string(
|
||||||
|
std::stringstream& ss,
|
||||||
|
const dv::value& value,
|
||||||
|
int indent,
|
||||||
|
bool eliminateIndent = false
|
||||||
|
) {
|
||||||
|
using dv::value_type;
|
||||||
|
|
||||||
|
switch (value.getType()) {
|
||||||
|
case value_type::string:
|
||||||
|
insert_string(ss, value.asString(), indent);
|
||||||
|
break;
|
||||||
|
case value_type::number:
|
||||||
|
ss << std::setprecision(15) << value.asNumber();
|
||||||
|
break;
|
||||||
|
case value_type::integer:
|
||||||
|
ss << value.asInteger();
|
||||||
|
break;
|
||||||
|
case value_type::boolean:
|
||||||
|
ss << (value.asBoolean() ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case value_type::none:
|
||||||
|
ss << "null";
|
||||||
|
break;
|
||||||
|
case value_type::object: {
|
||||||
|
if (value.empty()) {
|
||||||
|
ss << "{}";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool first = true;
|
||||||
|
for (const auto& [key, elem] : value.asObject()) {
|
||||||
|
if (!first) {
|
||||||
|
ss << '\n';
|
||||||
|
}
|
||||||
|
if (!eliminateIndent) {
|
||||||
|
add_indent(ss, indent);
|
||||||
|
} else {
|
||||||
|
eliminateIndent = false;
|
||||||
|
}
|
||||||
|
ss << key << ": ";
|
||||||
|
if ((elem.isObject() || elem.isList()) && !elem.empty()) {
|
||||||
|
ss << "\n";
|
||||||
|
to_string(ss, elem, indent + 1);
|
||||||
|
} else {
|
||||||
|
to_string(ss, elem, indent + 1);
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_type::list: {
|
||||||
|
if (value.empty()) {
|
||||||
|
ss << "[]";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool first = true;
|
||||||
|
for (const auto& elem : value) {
|
||||||
|
if (!first) {
|
||||||
|
ss << '\n';
|
||||||
|
}
|
||||||
|
if (!eliminateIndent) {
|
||||||
|
add_indent(ss, indent);
|
||||||
|
} else {
|
||||||
|
eliminateIndent = false;
|
||||||
|
}
|
||||||
|
ss << "- ";
|
||||||
|
to_string(ss, elem, indent + 1, true);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_type::bytes: {
|
||||||
|
const auto& bytes = value.asBytes();
|
||||||
|
auto b64 = util::base64_encode(bytes.data(), bytes.size());
|
||||||
|
b64 = util::join(util::split_by_n(b64, 64), '\n');
|
||||||
|
insert_string(ss, b64, indent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string yaml::stringify(const dv::value& value) {
|
||||||
|
std::stringstream ss;
|
||||||
|
to_string(ss, value, 0);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|||||||
@ -7,4 +7,6 @@
|
|||||||
namespace yaml {
|
namespace yaml {
|
||||||
dv::value parse(std::string_view filename, std::string_view source);
|
dv::value parse(std::string_view filename, std::string_view source);
|
||||||
dv::value parse(std::string_view source);
|
dv::value parse(std::string_view source);
|
||||||
|
|
||||||
|
std::string stringify(const dv::value& value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,4 +115,29 @@ namespace util {
|
|||||||
std::string format_data_size(size_t size);
|
std::string format_data_size(size_t size);
|
||||||
|
|
||||||
std::pair<std::string, std::string> split_at(std::string_view view, char c);
|
std::pair<std::string, std::string> split_at(std::string_view view, char c);
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::vector<std::basic_string<CharT>> split_by_n(
|
||||||
|
const std::basic_string<CharT>& str, size_t n
|
||||||
|
) {
|
||||||
|
std::vector<std::basic_string<CharT>> result;
|
||||||
|
for (size_t i = 0; i < str.length(); i += n) {
|
||||||
|
result.push_back(str.substr(i, n));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::basic_string<CharT> join(
|
||||||
|
const std::vector<std::basic_string<CharT>>& strings, CharT delimiter
|
||||||
|
) {
|
||||||
|
std::basic_stringstream<CharT> ss;
|
||||||
|
for (size_t i = 0; i < strings.size(); ++i) {
|
||||||
|
ss << strings[i];
|
||||||
|
if (i != strings.size() - 1) {
|
||||||
|
ss << delimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ TEST(YAML, EncodeDecode) {
|
|||||||
auto filename = "root:.github/workflows/windows-clang.yml";
|
auto filename = "root:.github/workflows/windows-clang.yml";
|
||||||
try {
|
try {
|
||||||
auto value = yaml::parse(io::read_string(filename));
|
auto value = yaml::parse(io::read_string(filename));
|
||||||
std::cout << json::stringify(value, true) << std::endl;
|
std::cout << yaml::stringify(value) << std::endl;
|
||||||
} catch (const parsing_error& error) {
|
} catch (const parsing_error& error) {
|
||||||
std::cerr << error.errorLog() << std::endl;
|
std::cerr << error.errorLog() << std::endl;
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user