diff --git a/.clang-tidy b/.clang-tidy index 00c9eaae..fb5be52a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -54,7 +54,7 @@ Checks: >- WarningsAsErrors: '*' HeaderFilterRegex: 'src' CheckOptions: - - key: readability-identifier-naming.ClassMemberSuffix + - key: readability-identifier-naming.PrivateMemberSuffix value: '_' - key: readability-identifier-naming.PublicMemberSuffix value: '' diff --git a/src/class_diagram/generators/json/class_diagram_generator.cc b/src/class_diagram/generators/json/class_diagram_generator.cc index 6d07a045..53a89c9b 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.cc +++ b/src/class_diagram/generators/json/class_diagram_generator.cc @@ -119,44 +119,38 @@ generator::generator(diagram_config &config, diagram_model &model) { } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(nlohmann::json &parent) const { - if (m_config.using_namespace) - json_["using_namespace"] = m_config.using_namespace().to_string(); - json_["name"] = m_model.name(); - json_["diagram_type"] = "class"; + if (config().using_namespace) + parent["using_namespace"] = config().using_namespace().to_string(); - json_["elements"] = std::vector{}; - json_["relationships"] = std::vector{}; + parent["elements"] = std::vector{}; + parent["relationships"] = std::vector{}; - generate_top_level_elements(json_); + generate_top_level_elements(parent); - generate_relationships(json_); - - generate_metadata(json_); - - ostr << json_; + generate_relationships(parent); } void generator::generate_top_level_elements(nlohmann::json &parent) const { - for (const auto &p : m_model) { + for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { if (!pkg->is_empty()) generate(*pkg, parent); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (m_model.should_include(*cls)) { + if (model().should_include(*cls)) { generate(*cls, parent); } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (m_model.should_include(*enm)) { + if (model().should_include(*enm)) { generate(*enm, parent); } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (m_model.should_include(*cpt)) { + if (model().should_include(*cpt)) { generate(*cpt, parent); } } @@ -165,17 +159,17 @@ void generator::generate_top_level_elements(nlohmann::json &parent) const void generator::generate(const package &p, nlohmann::json &parent) const { - const auto &uns = m_config.using_namespace(); + const auto &uns = config().using_namespace(); nlohmann::json package_object; - if (m_config.generate_packages()) { + if (config().generate_packages()) { // Don't generate packages from namespaces filtered out by // using_namespace if (!uns.starts_with({p.full_name(false)})) { LOG_DBG("Generating package {}", p.name()); - if (m_config.package_type() == config::package_type_t::kDirectory) + if (config().package_type() == config::package_type_t::kDirectory) package_object["type"] = "directory"; else package_object["type"] = "namespace"; @@ -189,31 +183,31 @@ void generator::generate(const package &p, nlohmann::json &parent) const if (dynamic_cast(subpackage.get()) != nullptr) { const auto &sp = dynamic_cast(*subpackage); if (!sp.is_empty()) { - if (m_config.generate_packages()) + if (config().generate_packages()) generate(sp, package_object); else generate(sp, parent); } } else if (auto *cls = dynamic_cast(subpackage.get()); cls) { - if (m_model.should_include(*cls)) { - if (m_config.generate_packages()) + if (model().should_include(*cls)) { + if (config().generate_packages()) generate(*cls, package_object); else generate(*cls, parent); } } else if (auto *enm = dynamic_cast(subpackage.get()); enm) { - if (m_model.should_include(*enm)) { - if (m_config.generate_packages()) + if (model().should_include(*enm)) { + if (config().generate_packages()) generate(*enm, package_object); else generate(*enm, parent); } } else if (auto *cpt = dynamic_cast(subpackage.get()); cpt) { - if (m_model.should_include(*cpt)) { - if (m_config.generate_packages()) + if (model().should_include(*cpt)) { + if (config().generate_packages()) generate(*cpt, package_object); else generate(*cpt, parent); @@ -221,7 +215,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const } } - if (m_config.generate_packages() && !package_object.empty()) { + if (config().generate_packages() && !package_object.empty()) { parent["elements"].push_back(std::move(package_object)); } } @@ -246,22 +240,22 @@ void generator::generate(const concept_ &c, nlohmann::json &parent) const void generator::generate_relationships(nlohmann::json &parent) const { - for (const auto &p : m_model) { + for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { generate_relationships(*pkg, parent); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (m_model.should_include(*cls)) { + if (model().should_include(*cls)) { generate_relationships(*cls, parent); } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (m_model.should_include(*enm)) { + if (model().should_include(*enm)) { generate_relationships(*enm, parent); } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (m_model.should_include(*cpt)) { + if (model().should_include(*cpt)) { generate_relationships(*cpt, parent); } } @@ -272,7 +266,7 @@ void generator::generate_relationships( const class_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - auto target_element = m_model.get(r.destination()); + auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " "to unresolved destination id", @@ -285,7 +279,7 @@ void generator::generate_relationships( parent["relationships"].push_back(rel); } - if (m_model.should_include(relationship_t::kExtension)) { + if (model().should_include(relationship_t::kExtension)) { for (const auto &b : c.parents()) { common::model::relationship r( relationship_t::kExtension, b.id(), b.access()); @@ -300,7 +294,7 @@ void generator::generate_relationships( const enum_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - auto target_element = m_model.get(r.destination()); + auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " "to unresolved destination id", @@ -318,7 +312,7 @@ void generator::generate_relationships( const concept_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - auto target_element = m_model.get(r.destination()); + auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " "to unresolved destination id", @@ -342,19 +336,19 @@ void generator::generate_relationships( generate_relationships(sp, parent); } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), parent); } } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), parent); } } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), parent); } diff --git a/src/class_diagram/generators/json/class_diagram_generator.h b/src/class_diagram/generators/json/class_diagram_generator.h index 2b1aca36..b1d31d16 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.h +++ b/src/class_diagram/generators/json/class_diagram_generator.h @@ -63,6 +63,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -71,7 +73,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(nlohmann::json &parent) const override; /** * Render class element into a JSON node. @@ -158,9 +160,6 @@ public: * @param parent JSON node */ void generate_relationships(const package &p, nlohmann::json &parent) const; - -private: - mutable nlohmann::json json_; }; } // namespace json diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 4095f937..551b9b10 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -38,16 +38,16 @@ void generator::generate_link( auto context = element_context(e); - if (!m_config.generate_links().link.empty()) { + if (!config().generate_links().link.empty()) { ostr << " [[["; ostr << env().render( - std::string_view{m_config.generate_links().link}, context); + std::string_view{config().generate_links().link}, context); } - if (!m_config.generate_links().tooltip.empty()) { + if (!config().generate_links().tooltip.empty()) { ostr << "{"; ostr << env().render( - std::string_view{m_config.generate_links().tooltip}, context); + std::string_view{config().generate_links().tooltip}, context); ostr << "}"; } ostr << "]]]"; @@ -67,7 +67,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const class_type = "abstract"; std::string full_name; - if (m_config.generate_packages()) + if (config().generate_packages()) full_name = c.full_name_no_ns(); else full_name = c.full_name(); @@ -77,7 +77,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const print_debug(c, ostr); ostr << class_type << " \"" - << m_config.simplify_template_type(render_name(full_name)); + << config().simplify_template_type(render_name(full_name)); ostr << "\" as " << c.alias() << '\n'; @@ -89,7 +89,7 @@ void generator::generate_alias(const enum_ &e, std::ostream &ostr) const { print_debug(e, ostr); - if (m_config.generate_packages()) + if (config().generate_packages()) ostr << "enum" << " \"" << e.name(); else @@ -106,7 +106,7 @@ void generator::generate_alias(const concept_ &c, std::ostream &ostr) const { print_debug(c, ostr); - if (m_config.generate_packages()) + if (config().generate_packages()) ostr << "class" << " \"" << c.name(); else @@ -133,7 +133,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const ostr << " " << "<>"; - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link(ostr, c); } @@ -145,7 +145,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const // // Process methods // - if (m_config.group_methods()) { + if (config().group_methods()) { generate_methods(group_methods(c.methods()), ostr); } else { @@ -160,7 +160,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const std::stringstream all_relations_str; for (const auto &r : c.relationships()) { - if (!m_model.should_include(r.type())) + if (!model().should_include(r.type())) continue; try { @@ -182,14 +182,14 @@ void generator::generate(const class_ &c, std::ostream &ostr) const sort_class_elements(members); - if (m_config.group_methods()) + if (config().group_methods()) ostr << "__\n"; for (const auto &m : members) { - if (!m_model.should_include(m)) + if (!model().should_include(m)) continue; - if (!m_config.include_relations_also_as_members() && + if (!config().include_relations_also_as_members() && rendered_relations.find(m.name()) != rendered_relations.end()) continue; @@ -232,7 +232,7 @@ void generator::generate_methods( sort_class_elements(sorted_methods); for (const auto &m : sorted_methods) { - if (!m_model.should_include(m)) + if (!model().should_include(m)) continue; generate_method(m, ostr); @@ -250,7 +250,7 @@ generator::method_groups_t generator::group_methods( std::vector filtered_methods; std::copy_if(methods.cbegin(), methods.cend(), std::back_inserter(filtered_methods), - [this](auto &m) { return m_model.should_include(m); }); + [this](auto &m) { return model().should_include(m); }); for (const auto &g : method_groups_) { result[g] = {}; @@ -278,7 +278,7 @@ void generator::generate_method( const class_diagram::model::class_method &m, std::ostream &ostr) const { namespace plantuml_common = clanguml::common::generators::plantuml; - const auto &uns = m_config.using_namespace(); + const auto &uns = config().using_namespace(); constexpr auto kAbbreviatedMethodArgumentsLength{15}; @@ -290,25 +290,25 @@ void generator::generate_method( if (m.is_static()) ostr << "{static} "; - std::string type{uns.relative(m_config.simplify_template_type(m.type()))}; + std::string type{uns.relative(config().simplify_template_type(m.type()))}; ostr << plantuml_common::to_plantuml(m.access()) << m.name(); if (!m.template_params().empty()) { - m.render_template_params(ostr, m_config.using_namespace(), false); + m.render_template_params(ostr, config().using_namespace(), false); } ostr << "("; - if (m_config.generate_method_arguments() != + if (config().generate_method_arguments() != config::method_arguments::none) { std::vector params; std::transform(m.parameters().cbegin(), m.parameters().cend(), std::back_inserter(params), [this](const auto &mp) { - return m_config.simplify_template_type( - mp.to_string(m_config.using_namespace())); + return config().simplify_template_type( + mp.to_string(config().using_namespace())); }); auto args_string = fmt::format("{}", fmt::join(params, ", ")); - if (m_config.generate_method_arguments() == + if (config().generate_method_arguments() == config::method_arguments::abbreviated) { args_string = clanguml::util::abbreviate( args_string, kAbbreviatedMethodArgumentsLength); @@ -340,7 +340,7 @@ void generator::generate_method( ostr << " : " << type; - if (m_config.generate_links) { + if (config().generate_links) { generate_link(ostr, m); } } @@ -349,7 +349,7 @@ void generator::generate_member( const class_diagram::model::class_member &m, std::ostream &ostr) const { namespace plantuml_common = clanguml::common::generators::plantuml; - const auto &uns = m_config.using_namespace(); + const auto &uns = config().using_namespace(); print_debug(m, ostr); @@ -358,9 +358,9 @@ void generator::generate_member( ostr << plantuml_common::to_plantuml(m.access()) << m.name() << " : " << render_name( - uns.relative(m_config.simplify_template_type(m.type()))); + uns.relative(config().simplify_template_type(m.type()))); - if (m_config.generate_links) { + if (config().generate_links) { generate_link(ostr, m); } } @@ -371,7 +371,7 @@ void generator::generate(const concept_ &c, std::ostream &ostr) const ostr << class_type << " " << c.alias() << " <>"; - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link(ostr, c); } @@ -385,7 +385,7 @@ void generator::generate(const concept_ &c, std::ostream &ostr) const std::vector parameters; parameters.reserve(c.requires_parameters().size()); for (const auto &p : c.requires_parameters()) { - parameters.emplace_back(p.to_string(m_config.using_namespace())); + parameters.emplace_back(p.to_string(config().using_namespace())); } ostr << fmt::format("({})\n", fmt::join(parameters, ",")); @@ -403,7 +403,7 @@ void generator::generate_member_notes(std::ostream &ostr, { for (const auto &decorator : member.decorators()) { auto note = std::dynamic_pointer_cast(decorator); - if (note && note->applies_to_diagram(m_config.name)) { + if (note && note->applies_to_diagram(config().name)) { ostr << "note " << note->position << " of " << alias << "::" << member.name() << '\n' << note->text << '\n' @@ -414,22 +414,22 @@ void generator::generate_member_notes(std::ostream &ostr, void generator::generate_relationships(std::ostream &ostr) const { - for (const auto &p : m_model) { + for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { generate_relationships(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (m_model.should_include(*cls)) { + if (model().should_include(*cls)) { generate_relationships(*cls, ostr); } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (m_model.should_include(*enm)) { + if (model().should_include(*enm)) { generate_relationships(*enm, ostr); } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (m_model.should_include(*cpt)) { + if (model().should_include(*cpt)) { generate_relationships(*cpt, ostr); } } @@ -446,7 +446,7 @@ void generator::generate_relationship( std::string destination; - auto target_element = m_model.get(r.destination()); + auto target_element = model().get(r.destination()); if (!target_element.has_value()) throw error::uml_alias_missing{fmt::format( "Missing element in the model for ID: {}", r.destination())}; @@ -484,7 +484,7 @@ void generator::generate_relationships( std::set unique_relations; for (const auto &r : c.relationships()) { - if (!m_model.should_include(r.type())) + if (!model().should_include(r.type())) continue; LOG_DBG("== Processing relationship {}", @@ -506,7 +506,7 @@ void generator::generate_relationships( std::string target_alias; try { - target_alias = m_model.to_alias(destination); + target_alias = model().to_alias(destination); } catch (...) { LOG_DBG("Failed to find alias to {}", destination); @@ -543,11 +543,11 @@ void generator::generate_relationships( } } - if (m_model.should_include(relationship_t::kExtension)) { + if (model().should_include(relationship_t::kExtension)) { for (const auto &b : c.parents()) { std::stringstream relstr; try { - auto target_alias = m_model.to_alias(b.id()); + auto target_alias = model().to_alias(b.id()); if (m_generated_aliases.find(target_alias) == m_generated_aliases.end()) @@ -581,7 +581,7 @@ void generator::generate_relationships( std::set unique_relations; for (const auto &r : c.relationships()) { - if (!m_model.should_include(r.type())) + if (!model().should_include(r.type())) continue; LOG_DBG("== Processing relationship {}", @@ -603,7 +603,7 @@ void generator::generate_relationships( std::string target_alias; try { - target_alias = m_model.to_alias(destination); + target_alias = model().to_alias(destination); } catch (...) { LOG_DBG("Failed to find alias to {}", destination); @@ -647,7 +647,7 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const { ostr << "enum " << e.alias(); - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link(ostr, e); } @@ -668,7 +668,7 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const { for (const auto &r : e.relationships()) { - if (!m_model.should_include(r.type())) + if (!model().should_include(r.type())) continue; clanguml::common::id_t destination{0}; @@ -676,7 +676,7 @@ void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const try { destination = r.destination(); - auto target_alias = m_model.to_alias(destination); + auto target_alias = model().to_alias(destination); if (m_generated_aliases.find(target_alias) == m_generated_aliases.end()) @@ -706,9 +706,9 @@ void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const void generator::generate(const package &p, std::ostream &ostr) const { - const auto &uns = m_config.using_namespace(); + const auto &uns = config().using_namespace(); - if (m_config.generate_packages()) { + if (config().generate_packages()) { LOG_DBG("Generating package {}", p.name()); // Don't generate packages from namespaces filtered out by @@ -741,9 +741,9 @@ void generator::generate(const package &p, std::ostream &ostr) const } } else if (auto *cls = dynamic_cast(subpackage.get()); cls) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { auto together_group = - m_config.get_together_group(cls->full_name(false)); + config().get_together_group(cls->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), cls); @@ -755,9 +755,9 @@ void generator::generate(const package &p, std::ostream &ostr) const } } else if (auto *enm = dynamic_cast(subpackage.get()); enm) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { auto together_group = - m_config.get_together_group(subpackage->full_name(false)); + config().get_together_group(subpackage->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), enm); @@ -769,9 +769,9 @@ void generator::generate(const package &p, std::ostream &ostr) const } } else if (auto *cpt = dynamic_cast(subpackage.get()); cpt) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { auto together_group = - m_config.get_together_group(cpt->full_name(false)); + config().get_together_group(cpt->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), cpt); @@ -784,7 +784,7 @@ void generator::generate(const package &p, std::ostream &ostr) const } } - if (m_config.generate_packages()) { + if (config().generate_packages()) { // Now generate any diagram elements which are in together // groups for (const auto &[group_name, group_elements] : @@ -829,24 +829,24 @@ void generator::generate_relationships( const auto &sp = dynamic_cast(*subpackage); if (!sp.is_empty() && !sp.all_of([this](const common::model::element &e) { - return !m_model.should_include(e); + return !model().should_include(e); })) generate_relationships(sp, ostr); } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), ostr); } } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), ostr); } } else if (dynamic_cast(subpackage.get()) != nullptr) { - if (m_model.should_include(*subpackage)) { + if (model().should_include(*subpackage)) { generate_relationships( dynamic_cast(*subpackage), ostr); } @@ -854,14 +854,8 @@ void generator::generate_relationships( } } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(std::ostream &ostr) const { - update_context(); - - ostr << "@startuml" << '\n'; - - generate_plantuml_directives(ostr, m_config.puml().before); - generate_top_level_elements(ostr); generate_groups(ostr); @@ -869,28 +863,22 @@ void generator::generate(std::ostream &ostr) const generate_relationships(ostr); generate_config_layout_hints(ostr); - - generate_plantuml_directives(ostr, m_config.puml().after); - - generate_metadata(ostr); - - ostr << "@enduml" << '\n'; } void generator::generate_top_level_elements(std::ostream &ostr) const { - for (const auto &p : m_model) { + for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { if (!pkg->is_empty() && !pkg->all_of([this](const common::model::element &e) { - return !m_model.should_include(e); + return !model().should_include(e); })) generate(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (m_model.should_include(*cls)) { + if (model().should_include(*cls)) { auto together_group = - m_config.get_together_group(cls->full_name(false)); + config().get_together_group(cls->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), cls); @@ -902,9 +890,9 @@ void generator::generate_top_level_elements(std::ostream &ostr) const } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (m_model.should_include(*enm)) { + if (model().should_include(*enm)) { auto together_group = - m_config.get_together_group(enm->full_name(false)); + config().get_together_group(enm->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), enm); @@ -916,9 +904,9 @@ void generator::generate_top_level_elements(std::ostream &ostr) const } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (m_model.should_include(*cpt)) { + if (model().should_include(*cpt)) { auto together_group = - m_config.get_together_group(cpt->full_name(false)); + config().get_together_group(cpt->full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), cpt); diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index 54adce86..7e303dc2 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -68,6 +68,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -76,7 +78,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(std::ostream &ostr) const override; /** * @brief In a nested diagram, generate the top level elements. @@ -273,7 +275,7 @@ private: template void sort_class_elements(std::vector &elements) const { - if (m_config.member_order() == config::member_order_t::lexical) { + if (config().member_order() == config::member_order_t::lexical) { std::sort(elements.begin(), elements.end(), [](const auto &m1, const auto &m2) { return m1.name() < m2.name(); diff --git a/src/common/generators/generator.h b/src/common/generators/generator.h new file mode 100644 index 00000000..116d2770 --- /dev/null +++ b/src/common/generators/generator.h @@ -0,0 +1,76 @@ +/** + * @file src/common/generators/generator.h + * + * Copyright (c) 2021-2023 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace clanguml::common::generators { + +/** + * @brief Common diagram generator interface + * + * This class defines common interface for all diagram generators. + */ +template class generator { +public: + /** + * @brief Constructor + * + * @param config Reference to instance of @link clanguml::config::diagram + * @param model Reference to instance of @link clanguml::model::diagram + */ + generator(ConfigType &config, DiagramType &model) + : config_{config} + , model_{model} + { + } + + virtual ~generator() = default; + + /** + * @brief Generate diagram + * + * This is the main diagram generation entrypoint. It is responsible for + * calling other methods in appropriate order to generate the diagram into + * the output stream. It generates diagram elements, that are common + * to all types of diagrams in a given generator. + * + * @param ostr Output stream + */ + virtual void generate(std::ostream &ostr) const = 0; + + /** + * @brief Get reference to diagram config + * + * @return Diagram config + */ + const ConfigType &config() const { return config_; } + + /** + * @brief Get reference to diagram model + * + * @return Diagram model + */ + const DiagramType &model() const { return model_; } + +private: + ConfigType &config_; + DiagramType &model_; +}; + +} // namespace clanguml::common::generators \ No newline at end of file diff --git a/src/common/generators/json/generator.h b/src/common/generators/json/generator.h index 8ff1bff1..236b7096 100644 --- a/src/common/generators/json/generator.h +++ b/src/common/generators/json/generator.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/generators/generator.h" #include "common/model/diagram_filter.h" #include "config/config.h" #include "util/error.h" @@ -56,32 +57,36 @@ using clanguml::common::model::relationship_t; * @tparam ConfigType Configuration type * @tparam DiagramType Diagram model type */ -template class generator { +template +class generator + : public clanguml::common::generators::generator { public: - /** - * @brief Constructor - * - * @param config Reference to instance of @link clanguml::config::diagram - * @param model Reference to instance of @link clanguml::model::diagram - */ - generator(ConfigType &config, DiagramType &model) - : m_config{config} - , m_model{model} - { - } + using clanguml::common::generators::generator::generator; - virtual ~generator() = default; + ~generator() override = default; /** * @brief Generate diagram * - * This method must be implemented in subclasses for specific diagram - * types. It is responsible for calling other methods in appropriate - * order to generate the diagram into the output stream. + * This is the main diagram generation entrypoint. It is responsible for + * calling other methods in appropriate order to generate the diagram into + * the output stream. It generates diagram elements, that are common + * to all types of diagrams in a given generator. * * @param ostr Output stream */ - virtual void generate(std::ostream &ostr) const = 0; + void generate(std::ostream &ostr) const override; + + /** + * @brief Generate diagram model + * + * This method must be implemented in subclasses for specific diagram + * types. + * + * @param ostr Output stream + */ + virtual void generate_diagram(nlohmann::json &parent) const = 0; /** * @brief Generate metadata element with diagram metadata @@ -89,11 +94,6 @@ public: * @param parent Root JSON object */ void generate_metadata(nlohmann::json &parent) const; - -private: -protected: - ConfigType &m_config; - DiagramType &m_model; }; template @@ -104,10 +104,24 @@ std::ostream &operator<<( return os; } +template +void generator::generate(std::ostream &ostr) const +{ + nlohmann::json j; + j["name"] = generators::generator::model().name(); + j["diagram_type"] = to_string(generators::generator::model().type()); + + generate_diagram(j); + + generate_metadata(j); + + ostr << j; +} + template void generator::generate_metadata(nlohmann::json &parent) const { - if (m_config.generate_metadata()) { + if (generators::generator::config().generate_metadata()) { parent["metadata"]["clang_uml_version"] = clanguml::version::CLANG_UML_VERSION; parent["metadata"]["schema_version"] = diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 7f203e9f..7a38ee81 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/generators/generator.h" #include "common/model/diagram_filter.h" #include "config/config.h" #include "util/error.h" @@ -30,8 +31,6 @@ #include #include -#include - namespace clanguml::common::generators::plantuml { using clanguml::common::model::access_t; @@ -49,7 +48,9 @@ std::string to_plantuml(message_t r); * @tparam ConfigType Configuration type * @tparam DiagramType Diagram model type */ -template class generator { +template +class generator + : public clanguml::common::generators::generator { public: /** * @brief Constructor @@ -58,25 +59,36 @@ public: * @param model Reference to instance of @link clanguml::model::diagram */ generator(ConfigType &config, DiagramType &model) - : m_config{config} - , m_model{model} + : clanguml::common::generators::generator{ + config, model} { init_context(); init_env(); } - virtual ~generator() = default; + ~generator() override = default; /** * @brief Generate diagram * - * This method must be implemented in subclasses for specific diagram - * types. It is responsible for calling other methods in appropriate - * order to generate the diagram into the output stream. + * This is the main diagram generation entrypoint. It is responsible for + * calling other methods in appropriate order to generate the diagram into + * the output stream. It generates diagram elements, that are common + * to all types of diagrams in a given generator. * * @param ostr Output stream */ - virtual void generate(std::ostream &ostr) const = 0; + void generate(std::ostream &ostr) const override; + + /** + * @brief Generate diagram specific part + * + * This method must be implemented in subclasses for specific diagram + * types. + * + * @param ostr Output stream + */ + virtual void generate_diagram(std::ostream &ostr) const = 0; /** * @brief Generate diagram layout hints @@ -169,8 +181,6 @@ private: void init_env(); protected: - ConfigType &m_config; - DiagramType &m_model; mutable std::set m_generated_aliases; mutable inja::json m_context; mutable inja::Environment m_env; @@ -222,13 +232,35 @@ inja::json generator::element_context(const E &e) const return ctx; } +template +void generator::generate(std::ostream &ostr) const +{ + const auto &config = generators::generator::config(); + + update_context(); + + ostr << "@startuml" << '\n'; + + generate_plantuml_directives(ostr, config.puml().before); + + generate_diagram(ostr); + + generate_plantuml_directives(ostr, config.puml().after); + + generate_metadata(ostr); + + ostr << "@enduml" << '\n'; +} + template void generator::generate_config_layout_hints(std::ostream &ostr) const { using namespace clanguml::util; + const auto &config = generators::generator::config(); + // Generate layout hints - for (const auto &[entity_name, hints] : m_config.layout()) { + for (const auto &[entity_name, hints] : config.layout()) { for (const auto &hint : hints) { try { if (hint.hint == config::hint_t::together) { @@ -255,7 +287,10 @@ template void generator::generate_row_column_hints(std::ostream &ostr, const std::string &entity_name, const config::layout_hint &hint) const { - const auto &uns = m_config.using_namespace(); + const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); + + const auto &uns = config.using_namespace(); std::vector group_elements; std::vector> element_aliases_pairs; @@ -265,9 +300,9 @@ void generator::generate_row_column_hints(std::ostream &ostr, std::copy(group_tail.begin(), group_tail.end(), std::back_inserter(group_elements)); - auto element_opt = this->m_model.get(entity_name); + auto element_opt = model.get(entity_name); if (!element_opt) - element_opt = this->m_model.get((uns | entity_name).to_string()); + element_opt = model.get((uns | entity_name).to_string()); for (auto it = cbegin(group_elements); it != cend(group_elements) && std::next(it) != cend(group_elements); @@ -275,13 +310,13 @@ void generator::generate_row_column_hints(std::ostream &ostr, const auto &first = *it; const auto &second = *std::next(it); - auto first_opt = this->m_model.get(first); + auto first_opt = model.get(first); if (!first_opt) - first_opt = this->m_model.get((uns | first).to_string()); + first_opt = model.get((uns | first).to_string()); - auto second_opt = this->m_model.get(second); + auto second_opt = model.get(second); if (!second_opt) - second_opt = this->m_model.get((uns | second).to_string()); + second_opt = model.get((uns | second).to_string()); element_aliases_pairs.emplace_back( first_opt.value().alias(), second_opt.value().alias()); @@ -299,17 +334,20 @@ template void generator::generate_position_hints(std::ostream &ostr, const std::string &entity_name, const config::layout_hint &hint) const { - const auto &uns = m_config.using_namespace(); + const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); + + const auto &uns = config.using_namespace(); const auto &hint_entity = std::get(hint.entity); - auto element_opt = m_model.get(entity_name); + auto element_opt = model.get(entity_name); if (!element_opt) - element_opt = m_model.get((uns | entity_name).to_string()); + element_opt = model.get((uns | entity_name).to_string()); - auto hint_element_opt = m_model.get(hint_entity); + auto hint_element_opt = model.get(hint_entity); if (!hint_element_opt) - hint_element_opt = m_model.get((uns | hint_entity).to_string()); + hint_element_opt = model.get((uns | hint_entity).to_string()); if (!element_opt || !hint_element_opt) return; @@ -327,6 +365,9 @@ template void generator::generate_plantuml_directives( std::ostream &ostr, const std::vector &directives) const { + const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); + using common::model::namespace_; for (const auto &d : directives) { @@ -339,8 +380,8 @@ void generator::generate_plantuml_directives( std::tuple alias_match; while (util::find_element_alias(directive, alias_match)) { const auto full_name = - m_config.using_namespace() | std::get<0>(alias_match); - auto element_opt = m_model.get(full_name.to_string()); + config.using_namespace() | std::get<0>(alias_match); + auto element_opt = model.get(full_name.to_string()); if (element_opt) directive.replace(std::get<1>(alias_match), @@ -383,9 +424,11 @@ template void generator::generate_notes( std::ostream &ostr, const model::element &e) const { + const auto &config = generators::generator::config(); + for (const auto &decorator : e.decorators()) { auto note = std::dynamic_pointer_cast(decorator); - if (note && note->applies_to_diagram(m_config.name)) { + if (note && note->applies_to_diagram(config.name)) { ostr << "note " << note->position << " of " << e.alias() << '\n' << note->text << '\n' << "end note\n"; @@ -396,7 +439,9 @@ void generator::generate_notes( template void generator::generate_metadata(std::ostream &ostr) const { - if (m_config.generate_metadata()) { + const auto &config = generators::generator::config(); + + if (config.generate_metadata()) { ostr << '\n' << "'Generated with clang-uml, version " << clanguml::version::CLANG_UML_VERSION << '\n' @@ -408,42 +453,43 @@ template template void generator::generate_link(std::ostream &ostr, const E &e) const { + const auto &config = generators::generator::config(); + if (e.file().empty()) return; ostr << " [["; try { - if (!m_config.generate_links().link.empty()) { + if (!config.generate_links().link.empty()) { - ostr << env().render( - std::string_view{m_config.generate_links().link}, + ostr << env().render(std::string_view{config.generate_links().link}, element_context(e)); } } catch (const inja::json::parse_error &e) { - LOG_ERROR("Failed to parse Jinja template: {}", - m_config.generate_links().link); + LOG_ERROR( + "Failed to parse Jinja template: {}", config.generate_links().link); } catch (const inja::json::exception &e) { LOG_ERROR("Failed to render PlantUML directive: \n{}\n due to: {}", - m_config.generate_links().link, e.what()); + config.generate_links().link, e.what()); } ostr << "{"; try { - if (!m_config.generate_links().tooltip.empty()) { + if (!config.generate_links().tooltip.empty()) { ostr << env().render( - std::string_view{m_config.generate_links().tooltip}, + std::string_view{config.generate_links().tooltip}, element_context(e)); } } catch (const inja::json::parse_error &e) { - LOG_ERROR("Failed to parse Jinja template: {}", - m_config.generate_links().link); + LOG_ERROR( + "Failed to parse Jinja template: {}", config.generate_links().link); } catch (const inja::json::exception &e) { LOG_ERROR("Failed to render PlantUML directive: \n{}\n due to: {}", - m_config.generate_links().link, e.what()); + config.generate_links().link, e.what()); } ostr << "}"; @@ -454,7 +500,9 @@ template void generator::print_debug( const common::model::source_location &e, std::ostream &ostr) const { - if (m_config.debug_mode()) + const auto &config = generators::generator::config(); + + if (config.debug_mode()) ostr << "' " << e.file() << ":" << e.line() << '\n'; } @@ -468,21 +516,26 @@ std::ostream &operator<<( template void generator::init_context() { - if (m_config.git) { - m_context["git"]["branch"] = m_config.git().branch; - m_context["git"]["revision"] = m_config.git().revision; - m_context["git"]["commit"] = m_config.git().commit; - m_context["git"]["toplevel"] = m_config.git().toplevel; + const auto &config = generators::generator::config(); + + if (config.git) { + m_context["git"]["branch"] = config.git().branch; + m_context["git"]["revision"] = config.git().revision; + m_context["git"]["commit"] = config.git().commit; + m_context["git"]["toplevel"] = config.git().toplevel; } } template void generator::update_context() const { - m_context["diagram"] = m_model.context(); + m_context["diagram"] = generators::generator::model().context(); } template void generator::init_env() { + const auto &model = generators::generator::model(); + const auto &config = generators::generator::config(); + // // Add basic string functions to inja environment // @@ -532,10 +585,10 @@ template void generator::init_env() // e.g.: // {{ element("clanguml::t00050::A").comment }} // - m_env.add_callback("element", 1, [this](inja::Arguments &args) { + m_env.add_callback("element", 1, [&model, &config](inja::Arguments &args) { inja::json res{}; - auto element_opt = m_model.get_with_namespace( - args[0]->get(), m_config.using_namespace()); + auto element_opt = model.get_with_namespace( + args[0]->get(), config.using_namespace()); if (element_opt.has_value()) res = element_opt.value().context(); @@ -548,9 +601,9 @@ template void generator::init_env() // Shortcut to: // {{ element("A").alias }} // - m_env.add_callback("alias", 1, [this](inja::Arguments &args) { - auto element_opt = m_model.get_with_namespace( - args[0]->get(), m_config.using_namespace()); + m_env.add_callback("alias", 1, [&model, &config](inja::Arguments &args) { + auto element_opt = model.get_with_namespace( + args[0]->get(), config.using_namespace()); if (!element_opt.has_value()) throw clanguml::error::uml_alias_missing( @@ -564,10 +617,10 @@ template void generator::init_env() // Shortcut to: // {{ element("A").comment }} // - m_env.add_callback("comment", 1, [this](inja::Arguments &args) { + m_env.add_callback("comment", 1, [&model, &config](inja::Arguments &args) { inja::json res{}; - auto element_opt = m_model.get_with_namespace( - args[0]->get(), m_config.using_namespace()); + auto element_opt = model.get_with_namespace( + args[0]->get(), config.using_namespace()); if (!element_opt.has_value()) throw clanguml::error::uml_alias_missing( diff --git a/src/include_diagram/generators/json/include_diagram_generator.cc b/src/include_diagram/generators/json/include_diagram_generator.cc index 04e6944e..56ebaa81 100644 --- a/src/include_diagram/generators/json/include_diagram_generator.cc +++ b/src/include_diagram/generators/json/include_diagram_generator.cc @@ -41,11 +41,11 @@ void generator::generate_relationships( else { util::for_each_if( f.relationships(), - [this](const auto &r) { return m_model.should_include(r.type()); }, - [&f, this](const auto &r) { + [this](const auto &r) { return model().should_include(r.type()); }, + [&f, &parent](const auto &r) { nlohmann::json rel = r; rel["source"] = std::to_string(f.id()); - json_["relationships"].push_back(std::move(rel)); + parent["relationships"].push_back(std::move(rel)); }); } } @@ -73,7 +73,7 @@ void generator::generate(const source_file &f, nlohmann::json &parent) const parent["elements"].push_back(std::move(j)); } else { - if (m_model.should_include(f)) { + if (model().should_include(f)) { LOG_DBG("Generating file {}", f.name()); j["type"] = "file"; @@ -84,28 +84,19 @@ void generator::generate(const source_file &f, nlohmann::json &parent) const } } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(nlohmann::json &parent) const { - json_["name"] = m_model.name(); - json_["diagram_type"] = "include"; - - json_["elements"] = std::vector{}; - json_["relationships"] = std::vector{}; + parent["elements"] = std::vector{}; + parent["relationships"] = std::vector{}; // Generate files and folders - util::for_each_if( - m_model, [](const auto & /*f*/) { return true; }, - [this](const auto &f) { - generate(dynamic_cast(*f), json_); - }); - - // Process file include relationships - util::for_each(m_model, [this](const auto &f) { - generate_relationships(dynamic_cast(*f), json_); + util::for_each(model(), [this, &parent](const auto &f) { + generate(dynamic_cast(*f), parent); }); - generate_metadata(json_); - - ostr << json_; + // Process file include relationships + util::for_each(model(), [this, &parent](const auto &f) { + generate_relationships(dynamic_cast(*f), parent); + }); } } // namespace clanguml::include_diagram::generators::json diff --git a/src/include_diagram/generators/json/include_diagram_generator.h b/src/include_diagram/generators/json/include_diagram_generator.h index e399d438..ad20340f 100644 --- a/src/include_diagram/generators/json/include_diagram_generator.h +++ b/src/include_diagram/generators/json/include_diagram_generator.h @@ -52,6 +52,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -60,7 +62,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(nlohmann::json &parent) const override; /** * @brief Generate relationships originating from source_file `f` @@ -78,9 +80,6 @@ public: * @param parent Parent JSON node */ void generate(const source_file &e, nlohmann::json &parent) const; - -private: - mutable nlohmann::json json_; }; } // namespace clanguml::include_diagram::generators::json diff --git a/src/include_diagram/generators/plantuml/include_diagram_generator.cc b/src/include_diagram/generators/plantuml/include_diagram_generator.cc index 6649d6ee..79cc663b 100644 --- a/src/include_diagram/generators/plantuml/include_diagram_generator.cc +++ b/src/include_diagram/generators/plantuml/include_diagram_generator.cc @@ -47,21 +47,20 @@ void generator::generate_relationships( util::for_each_if( f.relationships(), [this](const auto &r) { - return m_model.should_include(r.type()) && + return model().should_include(r.type()) && util::contains(m_generated_aliases, - m_model.get(r.destination()).value().alias()); + model().get(r.destination()).value().alias()); }, [&f, &ostr, this](const auto &r) { ostr << f.alias() << " " << plantuml_common::to_plantuml(r.type(), r.style()) << " " - << m_model.get(r.destination()).value().alias() << '\n'; + << model().get(r.destination()).value().alias() << '\n'; }); } } void generator::generate(const source_file &f, std::ostream &ostr) const { - if (f.type() == common::model::source_file_t::kDirectory) { LOG_DBG("Generating directory {}", f.name()); @@ -80,10 +79,10 @@ void generator::generate(const source_file &f, std::ostream &ostr) const else { LOG_DBG("Generating file {}", f.name()); - if (m_model.should_include(f)) { + if (model().should_include(f)) { ostr << "file \"" << f.name() << "\" as " << f.alias(); - if (m_config.generate_links) { + if (config().generate_links) { generate_link(ostr, f); } @@ -94,34 +93,18 @@ void generator::generate(const source_file &f, std::ostream &ostr) const } } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(std::ostream &ostr) const { - update_context(); - - ostr << "@startuml" << '\n'; - - if (m_config.puml) - generate_plantuml_directives(ostr, m_config.puml().before); - // Generate files and folders - util::for_each_if( - m_model, [](const auto & /*f*/) { return true; }, - [this, &ostr](const auto &f) { - generate(dynamic_cast(*f), ostr); - }); + util::for_each(model(), [this, &ostr](const auto &f) { + generate(dynamic_cast(*f), ostr); + }); // Process file include relationships - util::for_each(m_model, [this, &ostr](const auto &f) { + util::for_each(model(), [this, &ostr](const auto &f) { generate_relationships(dynamic_cast(*f), ostr); }); generate_config_layout_hints(ostr); - - if (m_config.puml) - generate_plantuml_directives(ostr, m_config.puml().after); - - generate_metadata(ostr); - - ostr << "@enduml" << '\n'; } } // namespace clanguml::include_diagram::generators::plantuml diff --git a/src/include_diagram/generators/plantuml/include_diagram_generator.h b/src/include_diagram/generators/plantuml/include_diagram_generator.h index 28742512..4b9530d2 100644 --- a/src/include_diagram/generators/plantuml/include_diagram_generator.h +++ b/src/include_diagram/generators/plantuml/include_diagram_generator.h @@ -53,6 +53,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -61,7 +63,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(std::ostream &ostr) const override; /** * @brief Generate relationships originating from source_file `f` diff --git a/src/package_diagram/generators/json/package_diagram_generator.cc b/src/package_diagram/generators/json/package_diagram_generator.cc index 3d50a142..d37230ba 100644 --- a/src/package_diagram/generators/json/package_diagram_generator.cc +++ b/src/package_diagram/generators/json/package_diagram_generator.cc @@ -33,11 +33,11 @@ void generator::generate_relationships( LOG_DBG("Generating relationships for package {}", p.full_name(true)); // Generate this packages relationship - if (m_model.should_include(relationship_t::kDependency)) { + if (model().should_include(relationship_t::kDependency)) { for (const auto &r : p.relationships()) { nlohmann::json rel = r; rel["source"] = std::to_string(p.id()); - json_["relationships"].push_back(std::move(rel)); + parent["relationships"].push_back(std::move(rel)); } } @@ -66,7 +66,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (m_model.should_include(pkg)) { + if (model().should_include(pkg)) { generate(pkg, j); } } @@ -74,33 +74,29 @@ void generator::generate(const package &p, nlohmann::json &parent) const parent["elements"].push_back(std::move(j)); } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(nlohmann::json &parent) const { - if (m_config.using_namespace) - json_["using_namespace"] = m_config.using_namespace().to_string(); + if (config().using_namespace) + parent["using_namespace"] = config().using_namespace().to_string(); - json_["name"] = m_model.name(); - json_["diagram_type"] = "package"; + parent["name"] = model().name(); + parent["diagram_type"] = "package"; - json_["elements"] = std::vector{}; - json_["relationships"] = std::vector{}; + parent["elements"] = std::vector{}; + parent["relationships"] = std::vector{}; - for (const auto &p : m_model) { + for (const auto &p : model()) { auto &pkg = dynamic_cast(*p); - if (m_model.should_include(pkg)) { - generate(pkg, json_); + if (model().should_include(pkg)) { + generate(pkg, parent); } } // Process package relationships - for (const auto &p : m_model) { - if (m_model.should_include(dynamic_cast(*p))) - generate_relationships(dynamic_cast(*p), json_); + for (const auto &p : model()) { + if (model().should_include(dynamic_cast(*p))) + generate_relationships(dynamic_cast(*p), parent); } - - generate_metadata(json_); - - ostr << json_; } } // namespace clanguml::package_diagram::generators::json diff --git a/src/package_diagram/generators/json/package_diagram_generator.h b/src/package_diagram/generators/json/package_diagram_generator.h index 5c05faa3..e6a10803 100644 --- a/src/package_diagram/generators/json/package_diagram_generator.h +++ b/src/package_diagram/generators/json/package_diagram_generator.h @@ -51,6 +51,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -59,7 +61,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(nlohmann::json &parent) const override; /** * @brief Generate relationships originating from package `p` @@ -76,9 +78,6 @@ public: * @param parent Parent JSON node */ void generate(const package &p, nlohmann::json &parent) const; - -private: - mutable nlohmann::json json_; }; } // namespace clanguml::package_diagram::generators::json diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index 4540a43b..8ee8d7e2 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -34,11 +34,11 @@ void generator::generate_relationships( LOG_DBG("Generating relationships for package {}", p.full_name(true)); // Generate this packages relationship - if (m_model.should_include(relationship_t::kDependency)) { + if (model().should_include(relationship_t::kDependency)) { for (const auto &r : p.relationships()) { std::stringstream relstr; try { - auto destination = m_model.to_alias(r.destination()); + auto destination = model().to_alias(r.destination()); if (!destination.empty()) { relstr << p.alias() << " ..> " << destination << '\n'; ostr << relstr.str(); @@ -65,7 +65,7 @@ void generator::generate(const package &p, std::ostream &ostr) const together_group_stack_.enter(); - const auto &uns = m_config.using_namespace(); + const auto &uns = config().using_namespace(); // Don't generate packages from namespaces filtered out by // using_namespace @@ -76,7 +76,7 @@ void generator::generate(const package &p, std::ostream &ostr) const if (p.is_deprecated()) ostr << " <>"; - if (m_config.generate_links) { + if (config().generate_links) { generate_link(ostr, p); } @@ -88,9 +88,9 @@ void generator::generate(const package &p, std::ostream &ostr) const for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (m_model.should_include(pkg)) { + if (model().should_include(pkg)) { auto together_group = - m_config.get_together_group(pkg.full_name(false)); + config().get_together_group(pkg.full_name(false)); if (together_group) { together_group_stack_.group_together( together_group.value(), &pkg); @@ -112,46 +112,6 @@ void generator::generate(const package &p, std::ostream &ostr) const together_group_stack_.leave(); } -void generator::generate(std::ostream &ostr) const -{ - update_context(); - - ostr << "@startuml" << '\n'; - - generate_plantuml_directives(ostr, m_config.puml().before); - - for (const auto &p : m_model) { - auto &pkg = dynamic_cast(*p); - if (m_model.should_include(pkg)) { - auto together_group = - m_config.get_together_group(pkg.full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), &pkg); - } - else { - generate(pkg, ostr); - } - } - } - - generate_groups(ostr); - - // Process package relationships - for (const auto &p : m_model) { - if (m_model.should_include(dynamic_cast(*p))) - generate_relationships(dynamic_cast(*p), ostr); - } - - generate_config_layout_hints(ostr); - - generate_plantuml_directives(ostr, m_config.puml().after); - - generate_metadata(ostr); - - ostr << "@enduml" << '\n'; -} - void generator::generate_groups(std::ostream &ostr) const { for (const auto &[group_name, group_elements] : @@ -166,4 +126,32 @@ void generator::generate_groups(std::ostream &ostr) const } } +void generator::generate_diagram(std::ostream &ostr) const +{ + for (const auto &p : model()) { + auto &pkg = dynamic_cast(*p); + if (model().should_include(pkg)) { + auto together_group = + config().get_together_group(pkg.full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), &pkg); + } + else { + generate(pkg, ostr); + } + } + } + + generate_groups(ostr); + + // Process package relationships + for (const auto &p : model()) { + if (model().should_include(dynamic_cast(*p))) + generate_relationships(dynamic_cast(*p), ostr); + } + + generate_config_layout_hints(ostr); +} + } // namespace clanguml::package_diagram::generators::plantuml diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.h b/src/package_diagram/generators/plantuml/package_diagram_generator.h index d94cf82a..be74d676 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.h +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.h @@ -55,6 +55,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -63,7 +65,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(std::ostream &ostr) const override; /** * @brief Generate relationships originating from package `p` diff --git a/src/sequence_diagram/generators/json/sequence_diagram_generator.cc b/src/sequence_diagram/generators/json/sequence_diagram_generator.cc index e0930781..5e5d75f0 100644 --- a/src/sequence_diagram/generators/json/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/json/sequence_diagram_generator.cc @@ -70,8 +70,8 @@ generator::generator( void generator::generate_call(const message &m, nlohmann::json &parent) const { - const auto &from = m_model.get_participant(m.from()); - const auto &to = m_model.get_participant(m.to()); + const auto &from = model().get_participant(m.from()); + const auto &to = model().get_participant(m.to()); if (!from || !to) { LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to()); @@ -90,7 +90,7 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const message = dynamic_cast(to.value()) .message_name(render_mode); } - else if (m_config.combine_free_functions_into_file_participants()) { + else if (config().combine_free_functions_into_file_participants()) { if (to.value().type_name() == "function") { message = dynamic_cast(to.value()) .message_name(render_mode); @@ -113,16 +113,17 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const if (from.value().type_name() == "method") { const auto &class_participant = - m_model.get_participant(from.value().id()).value(); + model().get_participant(from.value().id()).value(); msg["from"]["participant_id"] = std::to_string(class_participant.class_id()); } else if (from.value().type_name() == "function" || from.value().type_name() == "function_template") { - if (m_config.combine_free_functions_into_file_participants()) { + if (config().combine_free_functions_into_file_participants()) { const auto &file_participant = - m_model.get_participant(from.value().id()) + model() + .get_participant(from.value().id()) .value(); msg["from"]["participant_id"] = std::to_string(common::to_id(file_participant.file_relative())); @@ -138,16 +139,17 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const if (to.value().type_name() == "method") { const auto &class_participant = - m_model.get_participant(to.value().id()).value(); + model().get_participant(to.value().id()).value(); msg["to"]["participant_id"] = std::to_string(class_participant.class_id()); } else if (to.value().type_name() == "function" || to.value().type_name() == "function_template") { - if (m_config.combine_free_functions_into_file_participants()) { + if (config().combine_free_functions_into_file_participants()) { const auto &file_participant = - m_model.get_participant(to.value().id()) + model() + .get_participant(to.value().id()) .value(); msg["to"]["participant_id"] = std::to_string(common::to_id(file_participant.file_relative())); @@ -258,14 +260,14 @@ void generator::process_call_message(const model::message &m, generate_call(m, current_block_statement()); - if (m_model.sequences().find(m.to()) != m_model.sequences().end()) { + if (model().sequences().find(m.to()) != model().sequences().end()) { if (std::find(visited.begin(), visited.end(), m.to()) == visited.end()) { // break infinite recursion on recursive calls LOG_DBG("Creating activity {} --> {} - missing sequence {}", m.from(), m.to(), m.to()); - generate_activity(m_model.get_activity(m.to()), visited); + generate_activity(model().get_activity(m.to()), visited); } } else @@ -506,7 +508,7 @@ void generator::process_if_message(const message &m) const void generator::generate_participant( nlohmann::json &parent, const std::string &name) const { - auto p = m_model.get(name); + auto p = model().get(name); if (!p.has_value()) { LOG_WARN("Cannot find participant {} from `participants_order` option", @@ -523,7 +525,7 @@ common::id_t generator::generate_participant( common::id_t participant_id{0}; if (!force) { - for (const auto pid : m_model.active_participants()) { + for (const auto pid : model().active_participants()) { if (pid == id) { participant_id = pid; break; @@ -540,10 +542,11 @@ common::id_t generator::generate_participant( return participant_id; const auto &participant = - m_model.get_participant(participant_id).value(); + model().get_participant(participant_id).value(); if (participant.type_name() == "method") { - participant_id = m_model.get_participant(participant_id) + participant_id = model() + .get_participant(participant_id) .value() .class_id(); @@ -551,21 +554,21 @@ common::id_t generator::generate_participant( return participant_id; const auto &class_participant = - m_model.get_participant(participant_id).value(); + model().get_participant(participant_id).value(); parent["participants"].push_back(class_participant); } else if ((participant.type_name() == "function" || participant.type_name() == "function_template") && - m_config.combine_free_functions_into_file_participants()) { + config().combine_free_functions_into_file_participants()) { // Create a single participant for all functions declared in a // single file const auto &function_participant = - m_model.get_participant(participant_id).value(); + model().get_participant(participant_id).value(); nlohmann::json j = function_participant; j["name"] = util::path_to_url( - m_config.make_path_relative(function_participant.file()).string()); + config().make_path_relative(function_participant.file()).string()); participant_id = common::to_id(function_participant.file_relative()); @@ -592,28 +595,26 @@ bool generator::is_participant_generated(common::id_t id) const id) != generated_participants_.end(); } -void generator::generate(std::ostream &ostr) const +void generator::generate_diagram(nlohmann::json &parent) const { - m_model.print(); + model().print(); - json_["name"] = m_model.name(); - json_["diagram_type"] = "sequence"; - if (m_config.using_namespace) - json_["using_namespace"] = m_config.using_namespace().to_string(); + if (config().using_namespace) + parent["using_namespace"] = config().using_namespace().to_string(); - if (m_config.participants_order.has_value) { - for (const auto &p : m_config.participants_order()) { + if (config().participants_order.has_value) { + for (const auto &p : config().participants_order()) { LOG_DBG("Pregenerating participant {}", p); - generate_participant(json_, p); + generate_participant(parent, p); } } - for (const auto &sf : m_config.start_from()) { + for (const auto &sf : config().start_from()) { if (sf.location_type == location_t::function) { common::model::diagram_element::id_t start_from{0}; std::string start_from_str; - for (const auto &[k, v] : m_model.sequences()) { - const auto &caller = *m_model.participants().at(v.from()); + for (const auto &[k, v] : model().sequences()) { + const auto &caller = *model().participants().at(v.from()); std::string vfrom = caller.full_name(false); if (vfrom == sf.location) { LOG_DBG("Found sequence diagram start point: {}", k); @@ -634,7 +635,7 @@ void generator::generate(std::ostream &ostr) const visited_participants; const auto &from = - m_model.get_participant(start_from); + model().get_participant(start_from); if (!from.has_value()) { LOG_WARN("Failed to find participant {} for start_from " @@ -655,12 +656,12 @@ void generator::generate(std::ostream &ostr) const block_statements_stack_.push_back(std::ref(sequence)); generate_activity( - m_model.get_activity(start_from), visited_participants); + model().get_activity(start_from), visited_participants); block_statements_stack_.pop_back(); if (from.value().type_name() == "method" || - m_config.combine_free_functions_into_file_participants()) { + config().combine_free_functions_into_file_participants()) { sequence["return_type"] = from.value().return_type(); } @@ -673,8 +674,6 @@ void generator::generate(std::ostream &ostr) const } } - generate_metadata(json_); - - ostr << json_; + parent.update(json_); } } // namespace clanguml::sequence_diagram::generators::json diff --git a/src/sequence_diagram/generators/json/sequence_diagram_generator.h b/src/sequence_diagram/generators/json/sequence_diagram_generator.h index c0cd4ba8..4e8ad13d 100644 --- a/src/sequence_diagram/generators/json/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/json/sequence_diagram_generator.h @@ -47,6 +47,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -55,7 +57,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(nlohmann::json &parent) const override; /** * @brief Generate sequence diagram message. diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 6cc032c3..33accb93 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -45,8 +45,8 @@ std::string generator::render_name(std::string name) const void generator::generate_call(const message &m, std::ostream &ostr) const { - const auto &from = m_model.get_participant(m.from()); - const auto &to = m_model.get_participant(m.to()); + const auto &from = model().get_participant(m.from()); + const auto &to = model().get_participant(m.to()); if (!from || !to) { LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to()); @@ -61,10 +61,10 @@ void generator::generate_call(const message &m, std::ostream &ostr) const model::function::message_render_mode render_mode = model::function::message_render_mode::full; - if (m_config.generate_method_arguments() == + if (config().generate_method_arguments() == config::method_arguments::abbreviated) render_mode = model::function::message_render_mode::abbreviated; - else if (m_config.generate_method_arguments() == + else if (config().generate_method_arguments() == config::method_arguments::none) render_mode = model::function::message_render_mode::no_arguments; @@ -74,7 +74,7 @@ void generator::generate_call(const message &m, std::ostream &ostr) const message = fmt::format("{}{}{}", style, f.message_name(render_mode), style); } - else if (m_config.combine_free_functions_into_file_participants()) { + else if (config().combine_free_functions_into_file_participants()) { if (to.value().type_name() == "function") { message = dynamic_cast(to.value()) .message_name(render_mode); @@ -95,7 +95,7 @@ void generator::generate_call(const message &m, std::ostream &ostr) const ostr << to_alias; - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link(ostr, m); } @@ -119,8 +119,8 @@ void generator::generate_return(const message &m, std::ostream &ostr) const { // Add return activity only for messages between different actors and // only if the return type is different than void - const auto &from = m_model.get_participant(m.from()); - const auto &to = m_model.get_participant(m.to()); + const auto &from = model().get_participant(m.from()); + const auto &to = model().get_participant(m.to()); if ((m.from() != m.to()) && !to.value().is_void()) { const std::string from_alias = generate_alias(from.value()); @@ -130,7 +130,7 @@ void generator::generate_return(const message &m, std::ostream &ostr) const << common::generators::plantuml::to_plantuml(message_t::kReturn) << " " << from_alias; - if (m_config.generate_return_types()) { + if (config().generate_return_types()) { ostr << " : //" << m.return_type() << "//"; } @@ -144,7 +144,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, for (const auto &m : a.messages()) { if (m.type() == message_t::kCall) { const auto &to = - m_model.get_participant(m.to()); + model().get_participant(m.to()); visited.push_back(m.from()); @@ -156,14 +156,14 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, ostr << "activate " << to_alias << std::endl; - if (m_model.sequences().find(m.to()) != m_model.sequences().end()) { + if (model().sequences().find(m.to()) != model().sequences().end()) { if (std::find(visited.begin(), visited.end(), m.to()) == visited .end()) { // break infinite recursion on recursive calls LOG_DBG("Creating activity {} --> {} - missing sequence {}", m.from(), m.to(), m.to()); generate_activity( - m_model.get_activity(m.to()), ostr, visited); + model().get_activity(m.to()), ostr, visited); } } else @@ -270,7 +270,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, void generator::generate_participant( std::ostream &ostr, const std::string &name) const { - auto p = m_model.get(name); + auto p = model().get(name); if (!p.has_value()) { LOG_WARN("Cannot find participant {} from `participants_order` option", @@ -287,7 +287,7 @@ void generator::generate_participant( common::id_t participant_id{0}; if (!force) { - for (const auto pid : m_model.active_participants()) { + for (const auto pid : model().active_participants()) { if (pid == id) { participant_id = pid; break; @@ -304,11 +304,12 @@ void generator::generate_participant( return; const auto &participant = - m_model.get_participant(participant_id).value(); + model().get_participant(participant_id).value(); if (participant.type_name() == "method") { const auto class_id = - m_model.get_participant(participant_id) + model() + .get_participant(participant_id) .value() .class_id(); @@ -316,16 +317,16 @@ void generator::generate_participant( return; const auto &class_participant = - m_model.get_participant(class_id).value(); + model().get_participant(class_id).value(); print_debug(class_participant, ostr); ostr << "participant \"" - << render_name(m_config.using_namespace().relative( + << render_name(config().using_namespace().relative( class_participant.full_name(false))) << "\" as " << class_participant.alias(); - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link( ostr, class_participant); } @@ -336,11 +337,12 @@ void generator::generate_participant( } else if ((participant.type_name() == "function" || participant.type_name() == "function_template") && - m_config.combine_free_functions_into_file_participants()) { + config().combine_free_functions_into_file_participants()) { // Create a single participant for all functions declared in a // single file const auto &file_path = - m_model.get_participant(participant_id) + model() + .get_participant(participant_id) .value() .file(); @@ -352,7 +354,7 @@ void generator::generate_participant( return; auto participant_name = util::path_to_url(std::filesystem::relative( - std::filesystem::path{file_path}, m_config.root_directory()) + std::filesystem::path{file_path}, config().root_directory()) .string()); ostr << "participant \"" << render_name(participant_name) << "\" as " @@ -366,11 +368,11 @@ void generator::generate_participant( print_debug(participant, ostr); ostr << "participant \"" - << m_config.using_namespace().relative( + << config().using_namespace().relative( participant.full_name(false)) << "\" as " << participant.alias(); - if (m_config.generate_links) { + if (config().generate_links) { common_generator::generate_link( ostr, participant); } @@ -388,28 +390,36 @@ bool generator::is_participant_generated(common::id_t id) const id) != generated_participants_.end(); } -void generator::generate(std::ostream &ostr) const +std::string generator::generate_alias( + const model::participant &participant) const { - update_context(); + if ((participant.type_name() == "function" || + participant.type_name() == "function_template") && + config().combine_free_functions_into_file_participants()) { + const auto file_id = common::to_id(participant.file()); - m_model.print(); + return fmt::format("C_{:022}", file_id); + } - ostr << "@startuml" << std::endl; + return participant.alias(); +} - generate_plantuml_directives(ostr, m_config.puml().before); +void generator::generate_diagram(std::ostream &ostr) const +{ + model().print(); - if (m_config.participants_order.has_value) { - for (const auto &p : m_config.participants_order()) { + if (config().participants_order.has_value) { + for (const auto &p : config().participants_order()) { LOG_DBG("Pregenerating participant {}", p); generate_participant(ostr, p); } } - for (const auto &sf : m_config.start_from()) { + for (const auto &sf : config().start_from()) { if (sf.location_type == location_t::function) { common::model::diagram_element::id_t start_from{0}; - for (const auto &[k, v] : m_model.sequences()) { - const auto &caller = *m_model.participants().at(v.from()); + for (const auto &[k, v] : model().sequences()) { + const auto &caller = *model().participants().at(v.from()); std::string vfrom = caller.full_name(false); if (vfrom == sf.location) { LOG_DBG("Found sequence diagram start point: {}", k); @@ -430,7 +440,7 @@ void generator::generate(std::ostream &ostr) const visited_participants; const auto &from = - m_model.get_participant(start_from); + model().get_participant(start_from); if (!from.has_value()) { LOG_WARN("Failed to find participant {} for start_from " @@ -446,10 +456,10 @@ void generator::generate(std::ostream &ostr) const model::function::message_render_mode render_mode = model::function::message_render_mode::full; - if (m_config.generate_method_arguments() == + if (config().generate_method_arguments() == config::method_arguments::abbreviated) render_mode = model::function::message_render_mode::abbreviated; - else if (m_config.generate_method_arguments() == + else if (config().generate_method_arguments() == config::method_arguments::none) render_mode = model::function::message_render_mode::no_arguments; @@ -459,7 +469,7 @@ void generator::generate(std::ostream &ostr) const // which method relates to the first activity for this 'start_from' // condition if (from.value().type_name() == "method" || - m_config.combine_free_functions_into_file_participants()) { + config().combine_free_functions_into_file_participants()) { ostr << "[->" << " " << from_alias << " : " << from.value().message_name(render_mode) << std::endl; @@ -468,16 +478,16 @@ void generator::generate(std::ostream &ostr) const ostr << "activate " << from_alias << std::endl; generate_activity( - m_model.get_activity(start_from), ostr, visited_participants); + model().get_activity(start_from), ostr, visited_participants); if (from.value().type_name() == "method" || - m_config.combine_free_functions_into_file_participants()) { + config().combine_free_functions_into_file_participants()) { if (!from.value().is_void()) { ostr << "[<--" << " " << from_alias; - if (m_config.generate_return_types()) + if (config().generate_return_types()) ostr << " : //" << from.value().return_type() << "//"; ostr << '\n'; @@ -491,25 +501,6 @@ void generator::generate(std::ostream &ostr) const continue; } } - - generate_plantuml_directives(ostr, m_config.puml().after); - - generate_metadata(ostr); - - ostr << "@enduml" << std::endl; } -std::string generator::generate_alias( - const model::participant &participant) const -{ - if ((participant.type_name() == "function" || - participant.type_name() == "function_template") && - m_config.combine_free_functions_into_file_participants()) { - const auto file_id = common::to_id(participant.file()); - - return fmt::format("C_{:022}", file_id); - } - - return participant.alias(); -} } // namespace clanguml::sequence_diagram::generators::plantuml diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index fa8b8dec..df1466fe 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -49,6 +49,8 @@ class generator : public common_generator { public: generator(diagram_config &config, diagram_model &model); + using common_generator::generate; + /** * @brief Main generator method. * @@ -57,7 +59,7 @@ public: * * @param ostr Output stream. */ - void generate(std::ostream &ostr) const override; + void generate_diagram(std::ostream &ostr) const override; /** * @brief Generate sequence diagram message. diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index ee74b694..630722dc 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -93,6 +93,12 @@ void diagram::add_active_participant(common::model::diagram_element::id_t id) active_participants_.emplace(id); } +const activity &diagram::get_activity( + common::model::diagram_element::id_t id) const +{ + return sequences_.at(id); +} + activity &diagram::get_activity(common::model::diagram_element::id_t id) { return sequences_.at(id); @@ -173,6 +179,12 @@ std::set &diagram::active_participants() return active_participants_; } +const std::set & +diagram::active_participants() const +{ + return active_participants_; +} + bool diagram::should_include( const sequence_diagram::model::participant &p) const { diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index 17db4ae5..30cc81b4 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -98,6 +98,14 @@ public: */ void add_active_participant(common::model::diagram_element::id_t id); + /** + * @brief Get reference to current activity of a participant + * + * @param id Participant id + * @return + */ + const activity &get_activity(common::model::diagram_element::id_t id) const; + /** * @brief Get reference to current activity of a participant * @@ -179,6 +187,14 @@ public: */ std::set &active_participants(); + /** + * @brief Get all active participants in the diagram + * + * @return Set of all active participant ids + */ + const std::set & + active_participants() const; + /** * @brief Convert element full name to PlantUML alias. *