diff --git a/src/class_diagram/generators/json/class_diagram_generator.cc b/src/class_diagram/generators/json/class_diagram_generator.cc index e367cd5b..40ce347e 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.cc +++ b/src/class_diagram/generators/json/class_diagram_generator.cc @@ -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(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(c); +} + +void to_json(nlohmann::json &j, const class_member &c) +{ + j = dynamic_cast(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(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(c); + j["is_nested"] = c.is_nested(); + j["constants"] = c.constants(); +} + +void to_json(nlohmann::json &j, const concept_ &c) +{ + j = dynamic_cast(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(p.get()); cls) { + 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)) { - 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(subpackage.get()) != nullptr) { + // TODO: add option - generate_empty_packages + const auto &sp = dynamic_cast(*subpackage); + if (!sp.is_empty()) { + if (m_config.generate_packages()) + generate(sp, package_object); + else + generate(sp, parent); + } + } + else if (auto *cls = dynamic_cast(subpackage.get()); cls) { + const auto &sp = dynamic_cast(*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(subpackage.get()); enm) { + const auto &sp = dynamic_cast(*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(subpackage.get()); cpt) { + const auto &sp = dynamic_cast(*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(p.get()); pkg) { + generate_relationships(*pkg, parent); + } + else if (auto *cls = dynamic_cast(p.get()); cls) { + if (m_model.should_include(*cls)) { + generate_relationships(*cls, parent); + } + } + else if (auto *enm = dynamic_cast(p.get()); enm) { + if (m_model.should_include(*enm)) { + generate_relationships(*enm, parent); + } + } + else if (auto *cpt = dynamic_cast(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 diff --git a/src/class_diagram/generators/json/class_diagram_generator.h b/src/class_diagram/generators/json/class_diagram_generator.h index 1d58f2d9..30f51f5b 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.h +++ b/src/class_diagram/generators/json/class_diagram_generator.h @@ -60,15 +60,30 @@ class generator : public common_generator { 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_; };