From 2092a0e3e6405c10972e50d7ddbe02542440cb1a Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 7 Mar 2023 23:03:02 +0100 Subject: [PATCH] Added diagram templates to config --- src/common/model/enums.cc | 15 +++++++ src/common/model/enums.h | 2 + src/config/config.h | 8 ++++ src/config/yaml_decoders.cc | 43 +++++++++++++++++++ tests/test_config.cc | 45 +++++++++++++++++++- tests/test_config_data/diagram_templates.yml | 39 +++++++++++++++++ 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 tests/test_config_data/diagram_templates.yml diff --git a/src/common/model/enums.cc b/src/common/model/enums.cc index feeb740c..7d199d62 100644 --- a/src/common/model/enums.cc +++ b/src/common/model/enums.cc @@ -18,6 +18,7 @@ #include "enums.h" #include +#include namespace clanguml::common::model { @@ -135,4 +136,18 @@ std::string to_string(const diagram_t t) } } +diagram_t from_string(const std::string &s) +{ + if (s == "class") + return diagram_t::kClass; + else if (s == "sequence") + return diagram_t::kSequence; + else if (s == "include") + return diagram_t::kInclude; + else if (s == "package") + return diagram_t::kPackage; + else + throw std::runtime_error{"Invalid diagram type: " + s}; +} + } // namespace clanguml::common::model diff --git a/src/common/model/enums.h b/src/common/model/enums.h index 399c812f..3ec183c4 100644 --- a/src/common/model/enums.h +++ b/src/common/model/enums.h @@ -80,4 +80,6 @@ std::string to_string(message_t m); std::string to_string(diagram_t r); +diagram_t from_string(const std::string &s); + } // namespace clanguml::common::model diff --git a/src/config/config.h b/src/config/config.h index 942650ff..71e7df42 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -50,6 +50,11 @@ struct plantuml { void append(const plantuml &r); }; +struct diagram_template { + common::model::diagram_t type; + std::string jinja_template; +}; + struct filter { std::vector namespaces; @@ -218,6 +223,9 @@ struct config : public inheritable_diagram_options { "compilation_database_dir", "."}; option output_directory{"output_directory"}; + option> diagram_templates{ + "diagram_templates"}; + std::map> diagrams; }; diff --git a/src/config/yaml_decoders.cc b/src/config/yaml_decoders.cc index 23d24ef0..5fa98f11 100644 --- a/src/config/yaml_decoders.cc +++ b/src/config/yaml_decoders.cc @@ -23,6 +23,7 @@ using clanguml::common::model::access_t; using clanguml::common::model::relationship_t; using clanguml::config::class_diagram; using clanguml::config::config; +using clanguml::config::diagram_template; using clanguml::config::filter; using clanguml::config::generate_links_config; using clanguml::config::git_config; @@ -101,6 +102,21 @@ void get_option(const Node &node, } } +template <> +void get_option>( + const Node &node, + clanguml::config::option< + std::map> &option) +{ + if (!node[option.name]) { + return; + } + + option.set( + node[option.name] + .as>()); +} + std::shared_ptr parse_diagram_config(const Node &d) { const auto diagram_type = d["type"].as(); @@ -526,6 +542,31 @@ template <> struct convert { } }; +// +// diagram_template Yaml decoder +// +template <> struct convert { + static bool decode(const Node &node, diagram_template &rhs) + { + assert(node.Type() == NodeType::Map || node.Type() == NodeType::Scalar); + + if (node.Type() == NodeType::Scalar) { + // Check that the template provided as string is at least valid YAML + const auto yaml_node = Load(node.as()); + const auto diagram_type = yaml_node["type"].as(); + rhs.type = clanguml::common::model::from_string(diagram_type); + rhs.jinja_template = Dump(yaml_node); + } + else { + const auto diagram_type = node["type"].as(); + rhs.type = clanguml::common::model::from_string(diagram_type); + rhs.jinja_template = Dump(node); + } + + return true; + } +}; + // // config Yaml decoder // @@ -547,6 +588,8 @@ template <> struct convert { rhs.base_directory.set(node["__parent_path"].as()); get_option(node, rhs.relative_to); + get_option(node, rhs.diagram_templates); + auto diagrams = node["diagrams"]; assert(diagrams.Type() == NodeType::Map); diff --git a/tests/test_config.cc b/tests/test_config.cc index a4f2d946..2759c706 100644 --- a/tests/test_config.cc +++ b/tests/test_config.cc @@ -258,4 +258,47 @@ TEST_CASE("Test config emitters", "[unit-test]") REQUIRE(cfg.diagrams.size() == cfg_emitted.diagrams.size()); std::filesystem::remove(tmp_file); -} \ No newline at end of file +} + +TEST_CASE("Test config diagram_templates", "[unit-test]") +{ + auto cfg = + clanguml::config::load("./test_config_data/diagram_templates.yml"); + + REQUIRE(cfg.diagram_templates().size() == 3); + + REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].type == + clanguml::common::model::diagram_t::kClass); + REQUIRE(cfg.diagram_templates()["bases_hierarchy_tmpl"].jinja_template == + R"(name: "{{ class_name }}_parents_hierarchy" +type: class +include: + parents: "{{ class_name }}" + namespaces: "{{ namespace_name }}" +relationships: + - inheritance +exclude: + access: [public, protected, private] +plantuml: + before: + - left to right direction)"); + + REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].type == + clanguml::common::model::diagram_t::kClass); + REQUIRE(cfg.diagram_templates()["children_hierarchy_tmpl"].jinja_template == + R"(name: "{{ class_name }}_children_hierarchy" +type: class +include: + subclasses: "{{ class_name }}" + namespaces: "{{ namespace_name }}" +relationships: + - inheritance +exclude: + access: [public, protected, private] +plantuml: + before: + - left to right direction)"); + + REQUIRE(cfg.diagram_templates()["main_sequence_tmpl"].type == + clanguml::common::model::diagram_t::kSequence); +} diff --git a/tests/test_config_data/diagram_templates.yml b/tests/test_config_data/diagram_templates.yml new file mode 100644 index 00000000..5d442233 --- /dev/null +++ b/tests/test_config_data/diagram_templates.yml @@ -0,0 +1,39 @@ +compilation_database_dir: debug +output_directory: output + +diagram_templates: + bases_hierarchy_tmpl: + name: '{{ class_name }}_parents_hierarchy' + type: class + include: + parents: '{{ class_name }}' + namespaces: '{{ namespace_name }}' + relationships: + - inheritance + exclude: + access: [public, protected, private] + plantuml: + before: + - left to right direction + children_hierarchy_tmpl: | + name: '{{ class_name }}_children_hierarchy' + type: class + include: + subclasses: '{{ class_name }}' + namespaces: '{{ namespace_name }}' + relationships: + - inheritance + exclude: + access: [public, protected, private] + plantuml: + before: + - left to right direction + main_sequence_tmpl: | + name: main_sequence_diargam + type: sequence + glob: [ {{ }} ] + start_from: + - function: 'main(int,const char**)' +diagrams: + diagram1: + type: class \ No newline at end of file