Added complete json generation for class diagrams

This commit is contained in:
Bartek Kryza
2023-03-14 00:53:57 +01:00
parent 19ae58f493
commit 08d6f87d23
2 changed files with 294 additions and 15 deletions

View File

@@ -20,6 +20,127 @@
#include "util/error.h"
namespace clanguml::common::model {
using nlohmann::json;
void to_json(nlohmann::json &j, const source_location &sl)
{
j = json{{"file", sl.file()}, {"line", sl.line()}};
}
void to_json(nlohmann::json &j, const element &c)
{
j = json{{"id", std::to_string(c.id())}, {"name", c.name()},
{"namespace", c.get_namespace().to_string()}, {"type", c.type_name()},
{"display_name", c.full_name(false)}};
if (!c.file().empty())
j["source_location"] =
dynamic_cast<const common::model::source_location &>(c);
}
void to_json(nlohmann::json &j, const template_parameter &c)
{
j["type"] = c.type();
j["name"] = c.name();
if (!c.default_value().empty())
j["default_value"] = c.default_value();
j["is_template_parameter"] = c.is_template_parameter();
j["is_template_template_parameter"] = c.is_template_template_parameter();
if (c.concept_constraint())
j["concept_constraint"] = c.concept_constraint().value();
j["is_variadic"] = c.is_variadic();
}
void to_json(nlohmann::json &j, const relationship &c)
{
j["type"] = to_string(c.type());
j["destination"] = std::to_string(c.destination());
if (!c.multiplicity_source().empty())
j["multiplicity_source"] = c.multiplicity_source();
if (!c.multiplicity_destination().empty())
j["multiplicity_destination"] = c.multiplicity_destination();
j["access"] = to_string(c.access());
}
}
namespace clanguml::class_diagram::model {
using nlohmann::json;
void to_json(nlohmann::json &j, const class_element &c)
{
j = {{"name", c.name()}, {"type", c.type()},
{"access", to_string(c.access())}};
if (!c.file().empty())
j["source_location"] =
dynamic_cast<const common::model::source_location &>(c);
}
void to_json(nlohmann::json &j, const class_member &c)
{
j = dynamic_cast<const class_element &>(c);
j["is_static"] = c.is_static();
}
void to_json(nlohmann::json &j, const method_parameter &c)
{
j["name"] = c.name();
j["type"] = c.type();
if (!c.default_value().empty())
j["default_value"] = c.default_value();
}
void to_json(nlohmann::json &j, const class_method &c)
{
j["is_static"] = c.is_static();
j["is_const"] = c.is_const();
j["is_defaulted"] = c.is_defaulted();
j["is_pure_virtual"] = c.is_pure_virtual();
j["is_virtual"] = c.is_virtual();
j["is_implicit"] = c.is_implicit();
j["parameters"] = c.parameters();
}
void to_json(nlohmann::json &j, const class_parent &c)
{
j["is_virtual"] = c.is_virtual();
j["id"] = std::to_string(c.id());
j["access"] = to_string(c.access());
j["name"] = c.name();
}
void to_json(nlohmann::json &j, const class_ &c)
{
j = dynamic_cast<const common::model::element &>(c);
j["is_struct"] = c.is_struct();
j["is_abstract"] = c.is_abstract();
j["is_union"] = c.is_union();
j["is_nested"] = c.is_nested();
j["is_template"] = c.is_template();
j["members"] = c.members();
j["methods"] = c.methods();
j["bases"] = c.parents();
j["template_parameters"] = c.templates();
}
void to_json(nlohmann::json &j, const enum_ &c)
{
j = dynamic_cast<const common::model::element &>(c);
j["is_nested"] = c.is_nested();
j["constants"] = c.constants();
}
void to_json(nlohmann::json &j, const concept_ &c)
{
j = dynamic_cast<const common::model::element &>(c);
j["parameters"] = c.requires_parameters();
j["statements"] = c.requires_statements();
}
}
namespace clanguml::class_diagram::generators::json {
generator::generator(diagram_config &config, diagram_model &model)
@@ -29,32 +150,175 @@ generator::generator(diagram_config &config, diagram_model &model)
void generator::generate(std::ostream &ostr) const
{
generate_top_level_elements(ostr);
generate_top_level_elements(json_);
ostr << json_;
}
void generator::generate_top_level_elements(std::ostream &ostr) const
void generator::generate_top_level_elements(nlohmann::json &parent) const
{
for (const auto &p : m_model) {
if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
if (!pkg->is_empty())
generate(*pkg, parent);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (m_model.should_include(*cls)) {
generate(*cls, ostr);
generate(*cls, parent);
}
}
}
}
void generator::generate(const class_ &c, std::ostream & /*ostr*/) const
void generator::generate(const package &p, nlohmann::json &parent) const
{
const auto &uns = m_config.using_namespace();
nlohmann::json object;
object["id"] = std::to_string(c.id());
object["name"] = c.name();
object["namespace"] = c.get_namespace().to_string();
object["type"] = c.type_name();
object["display_name"] = c.full_name(false);
nlohmann::json package_object;
if (m_config.generate_packages()) {
LOG_DBG("Generating package {}", p.name());
// Don't generate packages from namespaces filtered out by
// using_namespace
if (!uns.starts_with({p.full_name(false)})) {
package_object["type"] = "namespace";
package_object["name"] = p.name();
package_object["display_name"] = p.full_name(false);
}
}
for (const auto &subpackage : p) {
if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
// TODO: add option - generate_empty_packages
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty()) {
if (m_config.generate_packages())
generate(sp, package_object);
else
generate(sp, parent);
}
}
else if (auto *cls = dynamic_cast<class_ *>(subpackage.get()); cls) {
const auto &sp = dynamic_cast<class_ &>(*subpackage);
if (m_model.should_include(*subpackage)) {
if (m_config.generate_packages())
generate(sp, package_object);
else
generate(sp, parent);
}
}
else if (auto *enm = dynamic_cast<enum_ *>(subpackage.get()); enm) {
const auto &sp = dynamic_cast<enum_ &>(*subpackage);
if (m_model.should_include(*subpackage)) {
if (m_config.generate_packages())
generate(sp, package_object);
else
generate(sp, parent);
}
}
else if (auto *cpt = dynamic_cast<concept_ *>(subpackage.get()); cpt) {
const auto &sp = dynamic_cast<concept_ &>(*subpackage);
if (m_model.should_include(*subpackage)) {
if (m_config.generate_packages())
generate(sp, package_object);
else
generate(sp, parent);
}
}
}
if (m_config.generate_packages()) {
parent["elements"].push_back(std::move(package_object));
}
}
void generator::generate(const class_ &c, nlohmann::json &parent) const
{
nlohmann::json object = c;
json_["elements"].push_back(std::move(object));
}
void generator::generate(const enum_ &e, nlohmann::json &parent) const
{
nlohmann::json object = e;
json_["elements"].push_back(std::move(object));
}
void generator::generate(const concept_ &c, nlohmann::json &parent) const
{
nlohmann::json object = c;
json_["elements"].push_back(std::move(object));
generate_relationships(json_);
}
void generator::generate_relationships(nlohmann::json &parent) const
{
for (const auto &p : m_model) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
generate_relationships(*pkg, parent);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (m_model.should_include(*cls)) {
generate_relationships(*cls, parent);
}
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (m_model.should_include(*enm)) {
generate_relationships(*enm, parent);
}
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (m_model.should_include(*cpt)) {
generate_relationships(*cpt, parent);
}
}
}
}
void generator::generate_relationships(
const class_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
nlohmann::json rel = r;
rel["source"] = std::to_string(c.id());
parent["relationships"].push_back(rel);
}
if (m_model.should_include(relationship_t::kExtension)) {
for (const auto &b : c.parents()) {
common::model::relationship r(
relationship_t::kExtension, b.id(), b.access());
nlohmann::json rel = r;
rel["source"] = std::to_string(c.id());
parent["relationships"].push_back(rel);
}
}
}
void generator::generate_relationships(
const enum_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
nlohmann::json rel = r;
rel["source"] = std::to_string(c.id());
parent["relationships"].push_back(rel);
}
}
void generator::generate_relationships(
const concept_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
nlohmann::json rel = r;
rel["source"] = std::to_string(c.id());
parent["relationships"].push_back(rel);
}
}
void generator::generate_relationships(
const package &p, nlohmann::json &parent) const
{
}
} // namespace clanguml::class_diagram::generators::plantuml

View File

@@ -60,15 +60,30 @@ class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
void generate(const class_ &c, std::ostream &ostr) const;
void generate(const class_ &c, nlohmann::json &parent) const;
void generate_top_level_elements(std::ostream &ostr) const;
void generate(const enum_ &c, nlohmann::json &parent) const;
void generate(const concept_ &c, nlohmann::json &parent) const;
void generate(const package &p, nlohmann::json &parent) const;
void generate_top_level_elements(nlohmann::json &parent) const;
void generate(std::ostream &ostr) const override;
private:
std::string render_name(std::string name) const;
void generate_relationships(nlohmann::json &parent) const;
void generate_relationships(const class_ &c, nlohmann::json &parent) const;
void generate_relationships(const enum_ &c, nlohmann::json &parent) const;
void generate_relationships(
const concept_ &c, nlohmann::json &parent) const;
void generate_relationships(const package &p, nlohmann::json &parent) const;
private:
mutable nlohmann::json json_;
};