From c05cd674e62c92ac9a4dc5f62ce2498566dd9e39 Mon Sep 17 00:00:00 2001 From: Foster Brereton Date: Wed, 21 Jun 2023 11:52:49 -0700 Subject: [PATCH] Adding all `hyde` values under a top-level `hyde` YAML key (#80) * adding all `hyde` values under a top-level `hyde` YAML key * adding `fixup-hyde-subfield` flag * fixes to the merge logic --- emitters/yaml_base_emitter.cpp | 69 ++++++++++++++++++++++------ emitters/yaml_base_emitter_fwd.hpp | 10 ++-- emitters/yaml_class_emitter.cpp | 12 ++--- emitters/yaml_enum_emitter.cpp | 6 +-- emitters/yaml_function_emitter.cpp | 10 ++-- emitters/yaml_library_emitter.cpp | 8 ++-- emitters/yaml_sourcefile_emitter.cpp | 2 +- sources/main.cpp | 9 +++- 8 files changed, 86 insertions(+), 40 deletions(-) diff --git a/emitters/yaml_base_emitter.cpp b/emitters/yaml_base_emitter.cpp index da1ff23..c7ecf43 100644 --- a/emitters/yaml_base_emitter.cpp +++ b/emitters/yaml_base_emitter.cpp @@ -171,6 +171,11 @@ YAML::Node json_to_yaml_ordered(hyde::json j) { move_key("methods"); move_key("overloads"); + if (j.count("hyde")) { + result["hyde"] = json_to_yaml_ordered(j["hyde"]); + j.erase("hyde"); + } + // copy over the remainder of the keys. for (auto it = j.begin(); it != j.end(); ++it) { result[it.key()] = json_to_yaml(it.value()); @@ -179,6 +184,31 @@ YAML::Node json_to_yaml_ordered(hyde::json j) { return result; } +/**************************************************************************************************/ +// See Issue #75 and PR #80. Take the relevant hyde fields and move them under a top-level +// `hyde` subfield. Only do this when we're asked to, in case this has already been done and those +// high-level fields are used by something else. When we do this fixup, we don't know which fields +// hyde actually uses, so this will move _all_ fields that are not `layout` and `title`. +hyde::json fixup_hyde_subfield(hyde::json&& j) { + hyde::json result; + + if (j.count("layout")) { + result["layout"] = std::move(j.at("layout")); + j.erase("layout"); + } + + if (j.count("title")) { + result["title"] = std::move(j.at("title")); + j.erase("title"); + } + + result["hyde"] = std::move(j); + + std::string result_str = result.dump(4); + + return result; +} + /**************************************************************************************************/ static const std::string front_matter_delimiter_k("---\n"); @@ -202,9 +232,10 @@ json yaml_base_emitter::base_emitter_node(std::string layout, std::string title, node["layout"] = std::move(layout); node["title"] = std::move(title); - node["owner"] = tag_value_missing_k; - node["tags"].emplace_back(std::move(tag)); - node["brief"] = tag_value_missing_k; + + node["hyde"]["owner"] = tag_value_missing_k; + node["hyde"]["tags"].emplace_back(std::move(tag)); + node["hyde"]["brief"] = tag_value_missing_k; return node; } @@ -215,7 +246,7 @@ void yaml_base_emitter::insert_typedefs(const json& j, json& node) { if (j.count("typedefs")) { for (const auto& type_def : j["typedefs"]) { const std::string& key = type_def["name"]; - auto& type_node = node["typedefs"][key]; + auto& type_node = node["hyde"]["typedefs"][key]; type_node["definition"] = static_cast(type_def["type"]); type_node["description"] = tag_value_missing_k; maybe_annotate(type_def, type_node); @@ -225,7 +256,7 @@ void yaml_base_emitter::insert_typedefs(const json& j, json& node) { if (j.count("typealiases")) { for (const auto& type_def : j["typealiases"]) { const std::string& key = type_def["name"]; - auto& type_node = node["typedefs"][key]; + auto& type_node = node["hyde"]["typedefs"][key]; type_node["definition"] = static_cast(type_def["type"]); type_node["description"] = tag_value_missing_k; maybe_annotate(type_def, type_node); @@ -890,11 +921,18 @@ std::pair yaml_base_emitter::merge(const std::string& filepath, } else { failure |= check_scalar(filepath, have, expected, "", merged, "title"); } - failure |= check_editable_scalar(filepath, have, expected, "", merged, "owner"); - failure |= check_editable_scalar(filepath, have, expected, "", merged, "brief"); - failure |= check_scalar_array(filepath, have, expected, "", merged, "tags"); - failure |= do_merge(filepath, have, expected, merged); + { + auto& expected_hyde = expected.at("hyde"); + auto& have_hyde = have.at("hyde"); + auto& merged_hyde = merged["hyde"]; + + failure |= check_editable_scalar(filepath, have_hyde, expected_hyde, "", merged_hyde, "owner"); + failure |= check_editable_scalar(filepath, have_hyde, expected_hyde, "", merged_hyde, "brief"); + failure |= check_scalar_array(filepath, have_hyde, expected_hyde, "", merged_hyde, "tags"); + + failure |= do_merge(filepath, have_hyde, expected_hyde, merged_hyde); + } return std::make_pair(failure, std::move(merged)); } @@ -1071,6 +1109,11 @@ bool yaml_base_emitter::reconcile(json expected, have_contents.erase(front_matter_pos, front_matter_end + front_matter_delimiter_k.size()); std::string remainder = std::move(have_contents); json have = yaml_to_json(load_yaml(path)); + + if (_mode == yaml_mode::update && _options._fixup_hyde_subfield) { + have = fixup_hyde_subfield(std::move(have)); + } + json merged; std::tie(failure, merged) = merge(relative_path, have, expected); @@ -1144,14 +1187,14 @@ void yaml_base_emitter::maybe_annotate(const json& j, json& node) { const std::string& access = j["access"]; if (access != "public") { - node["annotation"].push_back(access); + node["hyde"]["annotation"].push_back(access); } } if (j.count("default") && j["default"]) - node["annotation"].push_back("default"); + node["hyde"]["annotation"].push_back("default"); else if (j.count("delete") && j["delete"]) - node["annotation"].push_back("delete"); + node["hyde"]["annotation"].push_back("delete"); if (j.count("deprecated") && j["deprecated"]) { std::string deprecated("deprecated"); @@ -1163,7 +1206,7 @@ void yaml_base_emitter::maybe_annotate(const json& j, json& node) { .append(")"); } } - node["annotation"].push_back(deprecated); + node["hyde"]["annotation"].push_back(deprecated); } } diff --git a/emitters/yaml_base_emitter_fwd.hpp b/emitters/yaml_base_emitter_fwd.hpp index 347e756..674a177 100644 --- a/emitters/yaml_base_emitter_fwd.hpp +++ b/emitters/yaml_base_emitter_fwd.hpp @@ -55,13 +55,9 @@ static inline bool is_tag(const std::string& s) { /**************************************************************************************************/ struct emit_options { - attribute_category _tested_by; - bool _ignore_extraneous_files; - - emit_options() : - _tested_by(attribute_category::disabled), - _ignore_extraneous_files(false) - {} + attribute_category _tested_by{attribute_category::disabled}; + bool _ignore_extraneous_files{false}; + bool _fixup_hyde_subfield{false}; }; /**************************************************************************************************/ diff --git a/emitters/yaml_class_emitter.cpp b/emitters/yaml_class_emitter.cpp index e20c1c6..e9239a3 100644 --- a/emitters/yaml_class_emitter.cpp +++ b/emitters/yaml_class_emitter.cpp @@ -66,24 +66,24 @@ bool yaml_class_emitter::do_merge(const std::string& filepath, bool yaml_class_emitter::emit(const json& j, json& out_emitted) { json node = base_emitter_node("class", j["name"], "class"); - node["defined_in_file"] = defined_in_file(j["defined_in_file"], _src_root); + node["hyde"]["defined_in_file"] = defined_in_file(j["defined_in_file"], _src_root); maybe_annotate(j, node); std::string declaration = format_template_parameters(j, true) + '\n' + static_cast(j["kind"]) + " " + static_cast(j["qualified_name"]) + ";"; - node["declaration"] = std::move(declaration); + node["hyde"]["declaration"] = std::move(declaration); for (const auto& ns : j["namespaces"]) - node["namespace"].push_back(static_cast(ns)); + node["hyde"]["namespace"].push_back(static_cast(ns)); - if (j.count("ctor")) node["ctor"] = static_cast(j["ctor"]); - if (j.count("dtor")) node["dtor"] = static_cast(j["dtor"]); + if (j.count("ctor")) node["hyde"]["ctor"] = static_cast(j["ctor"]); + if (j.count("dtor")) node["hyde"]["dtor"] = static_cast(j["dtor"]); if (j.count("fields")) { for (const auto& field : j["fields"]) { const std::string& key = field["name"]; - auto& field_node = node["fields"][key]; + auto& field_node = node["hyde"]["fields"][key]; field_node["type"] = static_cast(field["type"]); field_node["description"] = tag_value_missing_k; maybe_annotate(field, field_node); diff --git a/emitters/yaml_enum_emitter.cpp b/emitters/yaml_enum_emitter.cpp index 19dd8bd..bce7146 100644 --- a/emitters/yaml_enum_emitter.cpp +++ b/emitters/yaml_enum_emitter.cpp @@ -56,13 +56,13 @@ bool yaml_enum_emitter::emit(const json& j, json& out_emitted) { if (j["values"].empty()) return true; json node = base_emitter_node("enumeration", j["name"], "enumeration"); - node["defined_in_file"] = defined_in_file(j["defined_in_file"], _src_root); + node["hyde"]["defined_in_file"] = defined_in_file(j["defined_in_file"], _src_root); maybe_annotate(j, node); std::string filename; for (const auto& ns : j["namespaces"]) { const std::string& namespace_str = ns; - node["namespace"].push_back(namespace_str); + node["hyde"]["namespace"].push_back(namespace_str); filename += namespace_str + "::"; } filename = filename_filter(std::move(filename) + name) + ".md"; @@ -71,7 +71,7 @@ bool yaml_enum_emitter::emit(const json& j, json& out_emitted) { json cur_value; cur_value["name"] = value["name"]; cur_value["description"] = tag_value_missing_k; - node["values"].push_back(std::move(cur_value)); + node["hyde"]["values"].push_back(std::move(cur_value)); } return reconcile(std::move(node), _dst_root, dst_path(j) / filename, out_emitted); diff --git a/emitters/yaml_function_emitter.cpp b/emitters/yaml_function_emitter.cpp index e5c9896..c68fb77 100644 --- a/emitters/yaml_function_emitter.cpp +++ b/emitters/yaml_function_emitter.cpp @@ -122,17 +122,17 @@ bool yaml_function_emitter::emit(const json& jsn, json& out_emitted) { json node = base_emitter_node(_as_methods ? "method" : "function", name, _as_methods ? "method" : "function"); - node["defined_in_file"] = defined_path; + node["hyde"]["defined_in_file"] = defined_path; if (!_as_methods && jsn.size() > 0) { // All overloads will have the same namespace for (const auto& ns : jsn.front()["namespaces"]) - node["namespace"].push_back(static_cast(ns)); + node["hyde"]["namespace"].push_back(static_cast(ns)); } - node["overloads"] = std::move(overloads); - if (is_ctor) node["is_ctor"] = true; - if (is_dtor) node["is_dtor"] = true; + node["hyde"]["overloads"] = std::move(overloads); + if (is_ctor) node["hyde"]["is_ctor"] = true; + if (is_dtor) node["hyde"]["is_dtor"] = true; return reconcile(std::move(node), _dst_root, dst / (filename + ".md"), out_emitted); } diff --git a/emitters/yaml_library_emitter.cpp b/emitters/yaml_library_emitter.cpp index 4fc2036..3066308 100644 --- a/emitters/yaml_library_emitter.cpp +++ b/emitters/yaml_library_emitter.cpp @@ -39,10 +39,10 @@ bool yaml_library_emitter::do_merge(const std::string& filepath, bool yaml_library_emitter::emit(const json&, json& out_emitted) { json node = base_emitter_node("library", tag_value_missing_k, "library"); - node["library-type"] = "library"; - node["icon"] = tag_value_missing_k; - node["tab"] = tag_value_missing_k; - node["short_title"] = tag_value_optional_k; + node["hyde"]["library-type"] = "library"; + node["hyde"]["icon"] = tag_value_missing_k; + node["hyde"]["tab"] = tag_value_missing_k; + node["hyde"]["short_title"] = tag_value_optional_k; return reconcile(std::move(node), _dst_root, _dst_root / index_filename_k, out_emitted); } diff --git a/emitters/yaml_sourcefile_emitter.cpp b/emitters/yaml_sourcefile_emitter.cpp index 96557d6..c194c47 100644 --- a/emitters/yaml_sourcefile_emitter.cpp +++ b/emitters/yaml_sourcefile_emitter.cpp @@ -38,7 +38,7 @@ bool yaml_sourcefile_emitter::do_merge(const std::string& filepath, bool yaml_sourcefile_emitter::emit(const json& j, json& out_emitted) { const auto sub_path = subcomponent(static_cast(j["paths"]["src_path"]), _src_root); json node = base_emitter_node("library", sub_path.string(), "sourcefile"); - node["library-type"] = "sourcefile"; + node["hyde"]["library-type"] = "sourcefile"; insert_typedefs(j, node); diff --git a/sources/main.cpp b/sources/main.cpp index f91d44f..fa1eaa0 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -127,6 +127,12 @@ static cl::opt EmitJson( cl::cat(MyToolCategory), cl::ValueDisallowed); +static cl::opt FixupHydeSubfield( + "fixup-hyde-subfield", + cl::desc("Fix-up preexisting documentation; move all fields except `layout` and `title` into a `hyde` subfield. `hyde-update` mode only."), + cl::cat(MyToolCategory), + cl::ValueDisallowed); + static cl::opt TestedBy( "hyde-tested-by", cl::values( @@ -595,7 +601,8 @@ int main(int argc, const char** argv) try { hyde::emit_options emit_options; emit_options._tested_by = TestedBy; emit_options._ignore_extraneous_files = IgnoreExtraneousFiles; - + emit_options._fixup_hyde_subfield = FixupHydeSubfield; + auto out_emitted = hyde::json::object(); output_yaml(std::move(result), std::move(src_root), std::move(dst_root), out_emitted, ToolMode == ToolModeYAMLValidate ? hyde::yaml_mode::validate :