Added initial support for MermaidJS package diagrams
This commit is contained in:
@@ -29,6 +29,7 @@
|
|||||||
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
|
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
|
||||||
#include "indicators/indicators.hpp"
|
#include "indicators/indicators.hpp"
|
||||||
#include "package_diagram/generators/json/package_diagram_generator.h"
|
#include "package_diagram/generators/json/package_diagram_generator.h"
|
||||||
|
#include "package_diagram/generators/mermaid/package_diagram_generator.h"
|
||||||
#include "package_diagram/generators/plantuml/package_diagram_generator.h"
|
#include "package_diagram/generators/plantuml/package_diagram_generator.h"
|
||||||
#include "sequence_diagram/generators/json/sequence_diagram_generator.h"
|
#include "sequence_diagram/generators/json/sequence_diagram_generator.h"
|
||||||
#include "sequence_diagram/generators/mermaid/sequence_diagram_generator.h"
|
#include "sequence_diagram/generators/mermaid/sequence_diagram_generator.h"
|
||||||
@@ -174,11 +175,11 @@ struct diagram_generator_t<clanguml::config::sequence_diagram,
|
|||||||
mermaid_generator_tag> {
|
mermaid_generator_tag> {
|
||||||
using type = clanguml::sequence_diagram::generators::mermaid::generator;
|
using type = clanguml::sequence_diagram::generators::mermaid::generator;
|
||||||
};
|
};
|
||||||
// template <>
|
template <>
|
||||||
// struct diagram_generator_t<clanguml::config::package_diagram,
|
struct diagram_generator_t<clanguml::config::package_diagram,
|
||||||
// mermaid_generator_tag> {
|
mermaid_generator_tag> {
|
||||||
// using type = clanguml::package_diagram::generators::mermaid::generator;
|
using type = clanguml::package_diagram::generators::mermaid::generator;
|
||||||
// };
|
};
|
||||||
// template <>
|
// template <>
|
||||||
// struct diagram_generator_t<clanguml::config::include_diagram,
|
// struct diagram_generator_t<clanguml::config::include_diagram,
|
||||||
// mermaid_generator_tag> {
|
// mermaid_generator_tag> {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public:
|
|||||||
* @param ostr Output stream
|
* @param ostr Output stream
|
||||||
* @param element Element to which the note should be attached
|
* @param element Element to which the note should be attached
|
||||||
*/
|
*/
|
||||||
void generate_notes(
|
virtual void generate_notes(
|
||||||
std::ostream &ostr, const model::element &element) const;
|
std::ostream &ostr, const model::element &element) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/**
|
||||||
|
* @file src/package_diagram/generators/mermaid/package_diagram_generator.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "package_diagram_generator.h"
|
||||||
|
|
||||||
|
#include "util/error.h"
|
||||||
|
|
||||||
|
namespace clanguml::package_diagram::generators::mermaid {
|
||||||
|
|
||||||
|
using clanguml::common::generators::mermaid::indent;
|
||||||
|
|
||||||
|
generator::generator(diagram_config &config, diagram_model &model)
|
||||||
|
: common_generator<diagram_config, diagram_model>{config, model}
|
||||||
|
, together_group_stack_{false}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void generator::generate_relationships(
|
||||||
|
const package &p, std::ostream &ostr) const
|
||||||
|
{
|
||||||
|
LOG_DBG("Generating relationships for package {}", p.full_name(true));
|
||||||
|
|
||||||
|
// Generate this packages relationship
|
||||||
|
if (model().should_include(relationship_t::kDependency)) {
|
||||||
|
for (const auto &r : p.relationships()) {
|
||||||
|
std::stringstream relstr;
|
||||||
|
try {
|
||||||
|
auto destination = model().to_alias(r.destination());
|
||||||
|
if (!destination.empty()) {
|
||||||
|
relstr << p.alias() << " -.-> " << destination << '\n';
|
||||||
|
ostr << indent(1) << relstr.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error::uml_alias_missing &e) {
|
||||||
|
LOG_DBG("=== Skipping dependency relation from {} to {} due "
|
||||||
|
"to: {}",
|
||||||
|
p.full_name(false), r.destination(), e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process it's subpackages relationships
|
||||||
|
for (const auto &subpackage : p) {
|
||||||
|
generate_relationships(
|
||||||
|
dynamic_cast<const package &>(*subpackage), ostr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generator::generate(const package &p, std::ostream &ostr) const
|
||||||
|
{
|
||||||
|
LOG_DBG("Generating package {}", p.name());
|
||||||
|
|
||||||
|
together_group_stack_.enter();
|
||||||
|
|
||||||
|
const auto &uns = config().using_namespace();
|
||||||
|
|
||||||
|
// Don't generate packages from namespaces filtered out by
|
||||||
|
// using_namespace
|
||||||
|
if (!uns.starts_with({p.full_name(false)})) {
|
||||||
|
ostr << indent(1) << "subgraph " << p.alias() << "[" << p.name()
|
||||||
|
<< "]\n";
|
||||||
|
|
||||||
|
if (p.is_deprecated())
|
||||||
|
ostr << indent(1) << "%% <<deprecated>>";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &subpackage : p) {
|
||||||
|
auto &pkg = dynamic_cast<package &>(*subpackage);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!uns.starts_with({p.full_name(false)})) {
|
||||||
|
ostr << indent(1) << "end" << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_notes(ostr, p);
|
||||||
|
|
||||||
|
together_group_stack_.leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void generator::generate_groups(std::ostream &ostr) const
|
||||||
|
{
|
||||||
|
for (const auto &[group_name, group_elements] :
|
||||||
|
together_group_stack_.get_current_groups()) {
|
||||||
|
ostr << indent(1) << "%% together group - not rendered in MermaidJS \n";
|
||||||
|
|
||||||
|
for (auto *pkg : group_elements) {
|
||||||
|
generate(*pkg, ostr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ostr << indent(1) << "%% end together group\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generator::generate_notes(
|
||||||
|
std::ostream &ostr, const common::model::element &element) const
|
||||||
|
{
|
||||||
|
const auto &config =
|
||||||
|
common_generator<diagram_config, diagram_model>::config();
|
||||||
|
|
||||||
|
for (const auto &decorator : element.decorators()) {
|
||||||
|
auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
|
||||||
|
if (note && note->applies_to_diagram(config.name)) {
|
||||||
|
auto note_id_str = fmt::format("N_{}", note_id_++);
|
||||||
|
|
||||||
|
ostr << indent(1) << note_id_str << "(" << note->text << ")\n";
|
||||||
|
|
||||||
|
ostr << indent(1) << note_id_str << "-.-" << element.alias()
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generator::generate_diagram(std::ostream &ostr) const
|
||||||
|
{
|
||||||
|
ostr << "flowchart\n";
|
||||||
|
|
||||||
|
for (const auto &p : model()) {
|
||||||
|
auto &pkg = dynamic_cast<package &>(*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<package &>(*p)))
|
||||||
|
generate_relationships(dynamic_cast<package &>(*p), ostr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace clanguml::package_diagram::generators::mermaid
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* @file src/package_diagram/generators/mermaid/package_diagram_generator.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 "common/generators/mermaid/generator.h"
|
||||||
|
#include "common/generators/nested_element_stack.h"
|
||||||
|
#include "common/model/package.h"
|
||||||
|
#include "common/model/relationship.h"
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "package_diagram/model/diagram.h"
|
||||||
|
#include "package_diagram/visitor/translation_unit_visitor.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace clanguml {
|
||||||
|
namespace package_diagram {
|
||||||
|
namespace generators {
|
||||||
|
namespace mermaid {
|
||||||
|
|
||||||
|
using diagram_config = clanguml::config::package_diagram;
|
||||||
|
using diagram_model = clanguml::package_diagram::model::diagram;
|
||||||
|
|
||||||
|
template <typename C, typename D>
|
||||||
|
using common_generator = clanguml::common::generators::mermaid::generator<C, D>;
|
||||||
|
|
||||||
|
using clanguml::common::model::access_t;
|
||||||
|
using clanguml::common::model::package;
|
||||||
|
using clanguml::common::model::relationship_t;
|
||||||
|
using namespace clanguml::util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Package diagram MermaidJS generator
|
||||||
|
*/
|
||||||
|
class generator : public common_generator<diagram_config, diagram_model> {
|
||||||
|
public:
|
||||||
|
generator(diagram_config &config, diagram_model &model);
|
||||||
|
|
||||||
|
using common_generator<diagram_config, diagram_model>::generate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main generator method.
|
||||||
|
*
|
||||||
|
* This method is called first and coordinates the entire diagram
|
||||||
|
* generation.
|
||||||
|
*
|
||||||
|
* @param ostr Output stream.
|
||||||
|
*/
|
||||||
|
void generate_diagram(std::ostream &ostr) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate relationships originating from package `p`
|
||||||
|
*
|
||||||
|
* @param p Diagram element
|
||||||
|
* @param parent Output stream
|
||||||
|
*/
|
||||||
|
void generate_relationships(const package &p, std::ostream &ostr) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate diagram package element
|
||||||
|
*
|
||||||
|
* @param p Package diagram element
|
||||||
|
* @param parent Output stream
|
||||||
|
*/
|
||||||
|
void generate(const package &e, std::ostream &ostr) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate package elements grouped using `together` MermaidJS tag
|
||||||
|
*
|
||||||
|
* @param ostr Output stream
|
||||||
|
*/
|
||||||
|
void generate_groups(std::ostream &ostr) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate notes attached to packages
|
||||||
|
*
|
||||||
|
* @param ostr Output stream
|
||||||
|
* @param element Element with a note
|
||||||
|
*/
|
||||||
|
void generate_notes(std::ostream &ostr,
|
||||||
|
const common::model::element &element) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable unsigned long note_id_{0UL};
|
||||||
|
mutable common::generators::nested_element_stack<common::model::package>
|
||||||
|
together_group_stack_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mermaid
|
||||||
|
} // namespace generators
|
||||||
|
} // namespace package_diagram
|
||||||
|
} // namespace clanguml
|
||||||
@@ -82,4 +82,10 @@ TEST_CASE("t30001", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,4 +121,10 @@ TEST_CASE("t30002", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,4 +63,10 @@ TEST_CASE("t30003", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,4 +58,10 @@ TEST_CASE("t30004", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,4 +65,10 @@ TEST_CASE("t30005", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,4 +59,10 @@ TEST_CASE("t30006", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,4 +63,10 @@ TEST_CASE("t30007", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,4 +77,10 @@ TEST_CASE("t30008", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,4 +64,10 @@ TEST_CASE("t30009", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -57,4 +57,10 @@ TEST_CASE("t30010", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -57,4 +57,10 @@ TEST_CASE("t30011", "[test-case][package]")
|
|||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto mmd = generate_package_mermaid(diagram, *model);
|
||||||
|
|
||||||
|
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -243,6 +243,14 @@ std::string generate_sequence_mermaid(
|
|||||||
config, model);
|
config, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string generate_package_mermaid(
|
||||||
|
std::shared_ptr<clanguml::config::diagram> config,
|
||||||
|
clanguml::package_diagram::model::diagram &model)
|
||||||
|
{
|
||||||
|
return detail::generate_diagram_mermaid<clanguml::config::package_diagram>(
|
||||||
|
config, model);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void save_diagram(const std::filesystem::path &path, const T &diagram)
|
void save_diagram(const std::filesystem::path &path, const T &diagram)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user