Added initial support for MermaidJS include diagrams

This commit is contained in:
Bartek Kryza
2023-09-09 01:46:08 +02:00
parent ee998e7a38
commit cfc0a42320
8 changed files with 265 additions and 6 deletions

View File

@@ -26,6 +26,7 @@
#include "common/model/diagram_filter.h" #include "common/model/diagram_filter.h"
#include "config/config.h" #include "config/config.h"
#include "include_diagram/generators/json/include_diagram_generator.h" #include "include_diagram/generators/json/include_diagram_generator.h"
#include "include_diagram/generators/mermaid/include_diagram_generator.h"
#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"
@@ -180,11 +181,11 @@ 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> {
// using type = clanguml::include_diagram::generators::mermaid::generator; using type = clanguml::include_diagram::generators::mermaid::generator;
// }; };
/** @} */ /** @} */
/** /**

View File

@@ -0,0 +1,132 @@
/**
* @file src/include_diagram/generators/mermaid/include_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 "include_diagram_generator.h"
#include "util/error.h"
namespace clanguml::include_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}
{
}
void generator::generate_relationships(
const source_file &f, std::ostream &ostr) const
{
if (!util::contains(m_generated_aliases, f.alias()))
return;
LOG_DBG("Generating relationships for file {}", f.full_name(true));
namespace mermaid_common = clanguml::common::generators::mermaid;
if (f.type() == common::model::source_file_t::kDirectory) {
util::for_each(f, [this, &ostr](const auto &file) {
generate_relationships(
dynamic_cast<const source_file &>(*file), ostr);
});
}
else {
util::for_each_if(
f.relationships(),
[this](const auto &r) {
return model().should_include(r.type()) &&
util::contains(m_generated_aliases,
model().get(r.destination()).value().alias());
},
[&f, &ostr, this](const auto &r) {
ostr << indent(1) << f.alias() << " "
<< (r.type() == common::model::relationship_t::kDependency
? "-.->"
: "-->")
<< " " << 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());
ostr << indent(1) << "subgraph " << f.alias() << "[" << f.name()
<< "]\n";
util::for_each(f, [this, &ostr](const auto &file) {
generate(dynamic_cast<const source_file &>(*file), ostr);
});
ostr << indent(1) << "end" << '\n';
m_generated_aliases.emplace(f.alias());
}
else {
LOG_DBG("Generating file {}", f.name());
if (model().should_include(f)) {
ostr << indent(1) << f.alias() << "[" << f.name() << "]\n";
m_generated_aliases.emplace(f.alias());
}
}
}
void generator::generate_notes(
std::ostream &ostr, const common::model::source_file &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";
// Generate files and folders
util::for_each(model(), [this, &ostr](const auto &f) {
generate(dynamic_cast<source_file &>(*f), ostr);
});
// Process file include relationships
util::for_each(model(), [this, &ostr](const auto &f) {
generate_relationships(dynamic_cast<source_file &>(*f), ostr);
});
// Process file notes
util::for_each(model(), [this, &ostr](const auto &f) {
generate_notes(ostr, dynamic_cast<source_file &>(*f));
});
}
} // namespace clanguml::include_diagram::generators::plantuml

View File

@@ -0,0 +1,96 @@
/**
* @file src/include_diagram/generators/mermaid/include_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/model/package.h"
#include "common/model/relationship.h"
#include "common/model/source_file.h"
#include "config/config.h"
#include "include_diagram/model/diagram.h"
#include "include_diagram/visitor/translation_unit_visitor.h"
#include "util/util.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
namespace clanguml::include_diagram::generators::mermaid {
using diagram_config = clanguml::config::include_diagram;
using diagram_model = clanguml::include_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 clanguml::common::model::source_file;
using namespace clanguml::util;
/**
* @brief Include 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 source_file `f`
*
* @param p Diagram element
* @param parent Output stream
*/
void generate_relationships(const source_file &p, std::ostream &ostr) const;
/**
* @brief Generate notes attached to files
*
* @param ostr Output stream
* @param element Element with a note
*/
void generate_notes(
std::ostream &ostr, const common::model::source_file &element) const;
/**
* @brief Generate diagram element
*
* @param e Source file diagram element
* @param parent Output stream
*/
void generate(const source_file &e, std::ostream &ostr) const;
private:
mutable unsigned long note_id_{0UL};
};
} // namespace clanguml::include_diagram::generators::mermaid

View File

@@ -21,3 +21,7 @@ diagrams:
after: after:
- 'note right of {{ alias("include/lib1") }}: This is a lib1 include dir' - 'note right of {{ alias("include/lib1") }}: This is a lib1 include dir'
- 'note right of {{ alias("include/t40001_include1.h") }}: This is a t40001_include1.h include file' - 'note right of {{ alias("include/t40001_include1.h") }}: This is a t40001_include1.h include file'
mermaid:
after:
- 'N_00001(This is a lib1 include dir)-.-{{ alias("include/lib1") }}'
- 'N_00002(This is a lib1 include dir)-.-{{ alias("include/t40001_include1.h") }}'

View File

@@ -79,4 +79,10 @@ TEST_CASE("t40001", "[test-case][include]")
save_json(config.output_directory(), diagram->name + ".json", j); save_json(config.output_directory(), diagram->name + ".json", j);
} }
{
auto mmd = generate_include_mermaid(diagram, *model);
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
}
} }

View File

@@ -110,4 +110,10 @@ TEST_CASE("t40002", "[test-case][include]")
save_json(config.output_directory(), diagram->name + ".json", j); save_json(config.output_directory(), diagram->name + ".json", j);
} }
{
auto mmd = generate_include_mermaid(diagram, *model);
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
}
} }

View File

@@ -74,4 +74,10 @@ TEST_CASE("t40003", "[test-case][include]")
save_json(config.output_directory(), diagram->name + ".json", j); save_json(config.output_directory(), diagram->name + ".json", j);
} }
{
auto mmd = generate_include_mermaid(diagram, *model);
save_mermaid(config.output_directory(), diagram->name + ".mmd", mmd);
}
} }

View File

@@ -251,6 +251,14 @@ std::string generate_package_mermaid(
config, model); config, model);
} }
std::string generate_include_mermaid(
std::shared_ptr<clanguml::config::diagram> config,
clanguml::include_diagram::model::diagram &model)
{
return detail::generate_diagram_mermaid<clanguml::config::include_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)
{ {