23#include <inja/inja.hpp>
41 ostr <<
"classDiagram\n";
49 assert(!full_name.empty());
53 auto class_label =
config().simplify_template_type(full_name);
55 ostr << indent(1) <<
"class " << c.
alias() <<
"[\""
56 << escape_name(class_label) <<
"\"]\n";
64 std::string class_type{
"class"};
66 ostr << indent(1) <<
"class " << c.
alias();
71 ostr << indent(2) <<
"<<union>>\n";
73 ostr << indent(2) <<
"<<abstract>>\n";
89 std::set<std::string> rendered_relations;
91 std::stringstream all_relations_str;
97 LOG_DBG(
"Skipping {} relation from {} to {} due "
99 to_string(r.type()), c.
full_name(
false), r.destination(),
107 std::vector<clanguml::class_diagram::model::class_member> members{
112 for (
const auto &m : members) {
113 if (!
config().include_relations_also_as_members() &&
114 rendered_relations.find(m.name()) != rendered_relations.end())
122 ostr << indent(1) <<
"}" <<
'\n';
124 if (
config().generate_links) {
130 for (
const auto &member : c.
members())
133 for (
const auto &method : c.
methods())
140 const std::vector<class_method> &methods, std::ostream &ostr)
const
142 auto sorted_methods = methods;
145 for (
const auto &m : sorted_methods) {
152 const std::vector<objc_method> &methods, std::ostream &ostr)
const
154 auto sorted_methods = methods;
157 for (
const auto &m : sorted_methods) {
167 const auto &uns =
config().using_namespace();
169 constexpr auto kAbbreviatedMethodArgumentsLength{15};
173 std::string type{uns.relative(
176 ostr << indent(2) << mermaid_common::to_mermaid(m.
access()) << m.
name();
183 if (
config().generate_method_arguments() !=
185 std::vector<std::string> params;
187 std::back_inserter(params), [
this](
const auto &mp) {
188 return config().simplify_template_type(
189 mp.to_string(config().using_namespace()));
191 auto args_string = fmt::format(
"{}", fmt::join(params,
", "));
192 if (
config().generate_method_arguments() ==
195 args_string, kAbbreviatedMethodArgumentsLength);
197 ostr << escape_name(args_string);
203 std::vector<std::string> method_mods;
205 method_mods.emplace_back(
"default");
208 method_mods.emplace_back(
"const");
211 method_mods.emplace_back(
"constexpr");
214 method_mods.emplace_back(
"consteval");
217 method_mods.emplace_back(
"coroutine");
220 if (!method_mods.empty()) {
221 ostr << fmt::format(
"[{}] ", fmt::join(method_mods,
","));
224 ostr << escape_name(type);
237 const auto &uns =
config().using_namespace();
239 constexpr auto kAbbreviatedMethodArgumentsLength{15};
243 std::string type{uns.relative(
246 ostr << indent(2) << mermaid_common::to_mermaid(m.
access()) << m.
name();
249 if (
config().generate_method_arguments() !=
251 std::vector<std::string> params;
253 std::back_inserter(params), [
this](
const auto &mp) {
254 return config().simplify_template_type(
255 mp.to_string(config().using_namespace()));
257 auto args_string = fmt::format(
"{}", fmt::join(params,
", "));
258 if (
config().generate_method_arguments() ==
261 args_string, kAbbreviatedMethodArgumentsLength);
263 ostr << escape_name(args_string);
269 std::vector<std::string> method_mods;
271 method_mods.emplace_back(
"default");
274 if (!method_mods.empty()) {
275 ostr << fmt::format(
"[{}] ", fmt::join(method_mods,
","));
278 ostr << escape_name(type);
288 const auto &uns =
config().using_namespace();
292 ostr << indent(2) << mermaid_common::to_mermaid(m.
access()) << m.
name()
294 << escape_name(uns.relative(
config().simplify_template_type(
302 const auto &uns =
config().using_namespace();
306 ostr << indent(2) << mermaid_common::to_mermaid(m.
access()) << m.
name()
308 << escape_name(uns.relative(
config().simplify_template_type(
314 ostr << indent(1) <<
"class" <<
" " << c.
alias();
316 ostr <<
" {" <<
'\n';
317 ostr << indent(2) <<
"<<concept>>\n";
319 if (
config().generate_concept_requirements() &&
321 std::vector<std::string> parameters;
324 parameters.emplace_back(
325 escape_name(p.to_string(
config().using_namespace())));
329 << fmt::format(
"\"({})\"\n", fmt::join(parameters,
","));
333 << fmt::format(
"\"{}\"\n", escape_name(req,
false));
337 ostr << indent(1) <<
"}" <<
'\n';
339 if (
config().generate_links) {
347 for (
const auto &decorator : member.
decorators()) {
348 auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
349 if (note && note->applies_to_diagram(
config().name)) {
350 ostr << indent(1) <<
"note for " << alias <<
" \"" << note->text
357 const relationship &r, std::set<std::string> &rendered_relations)
const
361 LOG_DBG(
"Processing relationship {}", to_string(r.
type()));
363 std::string destination;
366 if (!target_element.has_value())
368 "Missing element in the model for ID: {}", r.
destination())};
370 destination = target_element.value().full_name(
false);
373 destination = destination.substr(2, destination.size());
375 std::string mmd_relation;
379 mmd_relation += mermaid_common::to_mermaid(r.
type());
384 if (!r.
label().empty()) {
385 if (r.
type() == relationship_t::kFriendship)
386 rendered_relations.emplace(fmt::format(
387 "{}[friend]", mermaid_common::to_mermaid(r.
access())));
389 rendered_relations.emplace(r.
label());
394 const class_ &c, std::ostream &ostr)
const
401 std::set<std::string> rendered_relations;
403 std::stringstream all_relations_str;
404 std::set<std::string> unique_relations;
407 LOG_DBG(
"== Processing relationship {}", to_string(r.type()));
409 std::stringstream relstr;
412 destination = r.destination();
414 std::string relation_str;
416 if (!r.multiplicity_source().empty())
417 relation_str +=
"\"" + r.multiplicity_source() +
"\" ";
419 relation_str += mermaid_common::to_mermaid(r.type());
421 if (!r.multiplicity_destination().empty())
422 relation_str +=
" \"" + r.multiplicity_destination() +
"\"";
424 std::string target_alias;
426 target_alias =
model().to_alias(destination);
429 LOG_DBG(
"Failed to find alias to {}", destination);
437 if (r.type() == relationship_t::kContainment) {
438 relstr << indent(1) << target_alias <<
" " << relation_str
441 else if (r.type() == relationship_t::kExtension) {
442 relstr << indent(1) << target_alias <<
" <|-- " << c.
alias();
445 relstr << indent(1) << c.
alias() <<
" " << relation_str <<
" "
451 if (!r.label().empty()) {
452 auto lbl = r.label();
453 if (r.type() == relationship_t::kFriendship)
455 relstr << mermaid_common::to_mermaid(r.access()) << lbl;
456 rendered_relations.emplace(r.label());
459 if (unique_relations.count(relstr.str()) == 0) {
460 unique_relations.emplace(relstr.str());
462 LOG_DBG(
"=== Adding relation {}", relstr.str());
464 all_relations_str << relstr.str() <<
'\n';
468 LOG_DBG(
"=== Skipping {} relation from {} to {} due "
470 to_string(r.type()), c.
full_name(
true), destination, e.what());
474 ostr << all_relations_str.str();
478 const concept_ &c, std::ostream &ostr)
const
485 std::set<std::string> rendered_relations;
487 std::stringstream all_relations_str;
488 std::set<std::string> unique_relations;
491 LOG_DBG(
"== Processing relationship {}", to_string(r.type()));
493 std::stringstream relstr;
496 destination = r.destination();
498 std::string mmd_relation;
499 if (!r.multiplicity_source().empty())
500 mmd_relation +=
"\"" + r.multiplicity_source() +
"\" ";
502 mmd_relation += mermaid_common::to_mermaid(r.type());
504 if (!r.multiplicity_destination().empty())
505 mmd_relation +=
" \"" + r.multiplicity_destination() +
"\"";
507 std::string target_alias;
509 target_alias =
model().to_alias(destination);
512 LOG_DBG(
"Failed to find alias to {}", destination);
520 if (r.type() == relationship_t::kContainment) {
521 relstr << indent(1) << target_alias <<
" " << mmd_relation
525 relstr << indent(1) << c.
alias() <<
" " << mmd_relation <<
" "
531 if (!r.label().empty()) {
532 auto lbl = r.label();
533 if (r.type() == relationship_t::kFriendship)
535 relstr << mermaid_common::to_mermaid(r.access()) << lbl;
536 rendered_relations.emplace(r.label());
539 if (unique_relations.count(relstr.str()) == 0) {
540 unique_relations.emplace(relstr.str());
542 LOG_TRACE(
"=== Adding relation {}", relstr.str());
544 all_relations_str << relstr.str() <<
'\n';
548 LOG_DBG(
"=== Skipping {} relation from {} to {} due "
550 to_string(r.type()), c.
full_name(
true), destination, e.what());
554 ostr << all_relations_str.str();
561 std::stringstream relstr;
563 destination = r.destination();
565 auto target_alias =
model().to_alias(destination);
571 if (r.type() == relationship_t::kContainment) {
572 relstr << indent(1) << target_alias <<
" "
578 relstr << indent(1) << e.
alias() <<
" "
581 <<
" " << target_alias;
584 auto lbl = r.label();
585 if (r.type() == relationship_t::kFriendship)
588 relstr <<
" : " << r.label();
592 ostr << relstr.str();
595 LOG_DBG(
"Skipping {} relation from {} to {} due "
598 e.
full_name(
true), destination, ex.what());
605 ostr << indent(1) <<
"class " << e.
alias();
607 ostr <<
" {" <<
'\n';
609 ostr << indent(2) <<
"<<enumeration>>\n";
611 for (
const auto &enum_constant : e.
constants()) {
612 ostr << indent(2) << enum_constant <<
'\n';
615 ostr << indent(1) <<
"}" <<
'\n';
617 if (
config().generate_links) {
626 std::string class_type{
"class"};
628 ostr << indent(1) <<
"class " << c.
alias();
630 ostr <<
" {" <<
'\n';
633 ostr << indent(2) <<
"<< ObjC Protocol >>\n";
635 ostr << indent(2) <<
"<< ObjC Category >>\n";
637 ostr << indent(2) <<
"<< ObjC Interface >>\n";
648 std::set<std::string> rendered_relations;
650 std::stringstream all_relations_str;
656 LOG_DBG(
"Skipping {} relation from {} to {} due "
658 to_string(r.type()), c.
full_name(
true), r.destination(),
666 std::vector<clanguml::class_diagram::model::objc_member> members{
671 for (
const auto &m : members) {
672 if (!
config().include_relations_also_as_members() &&
673 rendered_relations.find(m.name()) != rendered_relations.end())
681 ostr << indent(1) <<
"}" <<
'\n';
683 if (
config().generate_links) {
689 for (
const auto &member : c.
members())
692 for (
const auto &method : c.
methods())
704 std::set<std::string> rendered_relations;
706 std::stringstream all_relations_str;
707 std::set<std::string> unique_relations;
710 LOG_DBG(
"== Processing relationship {}", to_string(r.type()));
712 std::stringstream relstr;
715 destination = r.destination();
717 std::string relation_str;
719 if (!r.multiplicity_source().empty())
720 relation_str +=
"\"" + r.multiplicity_source() +
"\" ";
722 relation_str += mermaid_common::to_mermaid(r.type());
724 if (!r.multiplicity_destination().empty())
725 relation_str +=
" \"" + r.multiplicity_destination() +
"\"";
727 std::string target_alias;
729 target_alias =
model().to_alias(destination);
732 LOG_DBG(
"Failed to find alias to {}", destination);
740 if (r.type() == relationship_t::kExtension) {
741 relstr << indent(1) << target_alias <<
" <|-- " << c.
alias();
744 relstr << indent(1) << c.
alias() <<
" " << relation_str <<
" "
750 if (!r.label().empty()) {
751 auto lbl = r.label();
752 if (r.type() == relationship_t::kFriendship)
754 relstr << mermaid_common::to_mermaid(r.access()) << lbl;
755 rendered_relations.emplace(r.label());
758 if (unique_relations.count(relstr.str()) == 0) {
759 unique_relations.emplace(relstr.str());
761 LOG_TRACE(
"=== Adding relation {}", relstr.str());
763 all_relations_str << relstr.str() <<
'\n';
767 LOG_DBG(
"=== Skipping {} relation from {} to {} due "
769 to_string(r.type()), c.
full_name(
true), destination, e.what());
773 ostr << all_relations_str.str();
786 const std::string &group_name, std::ostream &ostr)
const
791 const std::string &group_name, std::ostream &ostr)
const