Skip to content

Commit

Permalink
Extend config and schema with typed element filters (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Oct 30, 2024
1 parent e6c5693 commit 7704192
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 13 deletions.
27 changes: 19 additions & 8 deletions src/common/model/filters/diagram_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ tvl::value_t modules_filter::match(
}

element_filter::element_filter(
filter_t type, std::vector<common::string_or_regex> elements)
filter_t type, std::vector<config::element_filter_t> elements)
: filter_visitor{type}
, elements_{std::move(elements)}
{
Expand All @@ -463,8 +463,14 @@ tvl::value_t element_filter::match(const diagram &d, const element &e) const

return tvl::any_of(
elements_.begin(), elements_.end(), [&e](const auto &el) {
return ((el == e.full_name(false)) ||
(el == fmt::format("::{}", e.full_name(false))));
// First check if elements type matches the filter
if ((el.type != config::element_filter_t::filtered_type::any) &&
(config::to_string(el.type) != e.type_name())) {
return false;
}

return ((el.name == e.full_name(false)) ||
(el.name == fmt::format("::{}", e.full_name(false))));
});
}

Expand All @@ -481,19 +487,24 @@ tvl::value_t element_filter::match(
dynamic_cast<const sequence_diagram::model::diagram &>(d);
return tvl::any_of(elements_.begin(), elements_.end(),
[&sequence_model, &p](const auto &el) {
if (p.type_name() == "method") {
// First check if elements type matches the filter
if (el.type != config::element_filter_t::filtered_type::any &&
config::to_string(el.type) != p.type_name()) {
return false;
}

if (p.type_name() == "method") {
const auto &m = dynamic_cast<const method &>(p);
const auto class_id = m.class_id();
const auto &class_participant =
sequence_model.get_participant<participant>(class_id)
.value();

return el == p.full_name(false) ||
el == class_participant.full_name(false);
return el.name == p.full_name(false) ||
el.name == class_participant.full_name(false);
}

return el == p.full_name(false);
return el.name == p.full_name(false);
});
}

Expand Down Expand Up @@ -1084,4 +1095,4 @@ bool diagram_filter::should_include<std::string>(const std::string &name) const

return should_include(ns, n);
}
} // namespace clanguml::common::model
} // namespace clanguml::common::model
4 changes: 2 additions & 2 deletions src/common/model/filters/diagram_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ struct modules_filter : public filter_visitor {
*/
struct element_filter : public filter_visitor {
element_filter(
filter_t type, std::vector<common::string_or_regex> elements);
filter_t type, std::vector<config::element_filter_t> elements);

~element_filter() override = default;

Expand All @@ -275,7 +275,7 @@ struct element_filter : public filter_visitor {
const sequence_diagram::model::participant &p) const override;

private:
std::vector<common::string_or_regex> elements_;
std::vector<config::element_filter_t> elements_;
};

/**
Expand Down
23 changes: 23 additions & 0 deletions src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ std::string to_string(const hint_t t)
}
}

std::string to_string(element_filter_t::filtered_type ft)
{
switch (ft) {
case element_filter_t::filtered_type::any:
return "any";
case element_filter_t::filtered_type::class_:
return "class";
case element_filter_t::filtered_type::function:
return "function";
case element_filter_t::filtered_type::method:
return "method";
case element_filter_t::filtered_type::enum_:
return "enum";
case element_filter_t::filtered_type::concept_:
return "concept_";
case element_filter_t::filtered_type::package:
return "package";
default:
assert(false);
return "";
}
}

std::string to_string(const method_arguments ma)
{
switch (ma) {
Expand Down
22 changes: 20 additions & 2 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ struct runtime_config;
*/
namespace config {

struct element_filter_t {
enum class filtered_type {
any,
function,
class_,
method,
enum_,
concept_,
package
};

filtered_type type{filtered_type::any};
common::string_or_regex name;
};

std::string to_string(element_filter_t::filtered_type ft);

/*! Select how the method arguments should be rendered */
enum class method_arguments {
full, /*! Full */
Expand Down Expand Up @@ -250,7 +267,7 @@ struct filter {
* - r: ".*Enum.*"
* ```
*/
std::vector<common::string_or_regex> elements;
std::vector<element_filter_t> elements;

/*! @brief Element types filter
*
Expand Down Expand Up @@ -850,6 +867,8 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const package_diagram &c);

YAML::Emitter &operator<<(YAML::Emitter &out, const layout_hint &c);

YAML::Emitter &operator<<(YAML::Emitter &out, const element_filter_t &ef);

#ifdef _MSC_VER
YAML::Emitter &operator<<(YAML::Emitter &out, const std::filesystem::path &p);

Expand Down Expand Up @@ -886,5 +905,4 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const access_t &r);
YAML::Emitter &operator<<(YAML::Emitter &out, const diagram_t &d);
/** @} */ // end of yaml_emitters
} // namespace common::model

} // namespace clanguml
8 changes: 7 additions & 1 deletion src/config/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,16 @@ const std::string schema_str = R"(
context_filter_t:
- regex_or_string_t
- context_filter_match_t
element_typed_filter_t:
type: string
name: regex_or_string_t
element_filter_t:
- regex_or_string_t
- element_typed_filter_t
filter_t:
namespaces: !optional [regex_or_string_t]
modules: !optional [regex_or_string_t]
elements: !optional [regex_or_string_t]
elements: !optional [element_filter_t]
element_types: !optional [element_types_filter_t]
relationships: !optional [relationship_filter_t]
access: !optional [access_filter_t]
Expand Down
47 changes: 47 additions & 0 deletions src/config/yaml_decoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ using clanguml::config::config;
using clanguml::config::context_config;
using clanguml::config::context_direction_t;
using clanguml::config::diagram_template;
using clanguml::config::element_filter_t;
using clanguml::config::filter;
using clanguml::config::generate_links_config;
using clanguml::config::git_config;
Expand Down Expand Up @@ -530,6 +531,52 @@ template <> struct convert<namespace_or_regex> {
}
};

template <> struct convert<element_filter_t> {
static bool decode(const Node &node, element_filter_t &rhs)
{
using namespace std::string_literals;
if (node.IsMap()) {
if (has_key(node, "r")) {
rhs.type = element_filter_t::filtered_type::any;
auto pattern = node["r"].as<std::string>();
auto rx = std::regex(pattern);
rhs.name = string_or_regex(std::move(rx), std::move(pattern));
}
else if (has_key(node, "type")) {
rhs.type = element_filter_t::filtered_type::any;
if (node["type"].as<std::string>() == "class")
rhs.type = element_filter_t::filtered_type::class_;
else if (node["type"].as<std::string>() == "enum")
rhs.type = element_filter_t::filtered_type::enum_;
else if (node["type"].as<std::string>() == "function")
rhs.type = element_filter_t::filtered_type::function;
else if (node["type"].as<std::string>() == "method")
rhs.type = element_filter_t::filtered_type::method;
else if (node["type"].as<std::string>() == "concept")
rhs.type = element_filter_t::filtered_type::concept_;
else if (node["type"].as<std::string>() == "concept")
rhs.type = element_filter_t::filtered_type::concept_;

auto name = node["name"];
if (name.IsMap() && has_key(name, "r")) {
auto pattern = name["r"].as<std::string>();
auto rx = std::regex(pattern);
rhs.name =
string_or_regex(std::move(rx), std::move(pattern));
}
else
rhs.name = name.as<std::string>();
}
}
else {
rhs.type = element_filter_t::filtered_type::any;
rhs.name = string_or_regex{node.as<std::string>()};
}

return true;
}
};

//
// filter Yaml decoder
//
Expand Down
9 changes: 9 additions & 0 deletions src/config/yaml_emitters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,13 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const package_diagram &c)
return out;
}

YAML::Emitter &operator<<(YAML::Emitter &out, const element_filter_t &ef)
{
out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << to_string(ef.type);
out << YAML::Key << "name" << YAML::Value << ef.name;
out << YAML::EndMap;

return out;
}
} // namespace clanguml::config
12 changes: 12 additions & 0 deletions tests/test_config_data/filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ diagrams:
exclude:
elements:
- ns1::ns2::ClassZ
regex_typed_elements_test:
type: class
include:
elements:
- type: class
name: 'MyTypeClass'
- type: class
name:
r: 'MyType.+'
exclude:
elements:
- ns1::ns2::ClassZ
regex_namespace_test:
type: class
include:
Expand Down
33 changes: 33 additions & 0 deletions tests/test_filters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "doctest/doctest.h"

#include "class_diagram/model/class.h"
#include "class_diagram/model/enum.h"
#include "cli/cli_handler.h"
#include "common/model/filters/diagram_filter_factory.h"
#include "common/model/source_file.h"
Expand Down Expand Up @@ -218,6 +219,38 @@ TEST_CASE("Test elements regexp filter")
CHECK(filter.should_include(c));
}

TEST_CASE("Test typed elements filter")
{
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_method;
using clanguml::class_diagram::model::enum_;
using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::namespace_;
using clanguml::common::model::package;
using clanguml::common::model::source_file;

auto cfg = clanguml::config::load("./test_config_data/filters.yml");

auto &config = *cfg.diagrams["regex_typed_elements_test"];
clanguml::class_diagram::model::diagram diagram;

auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;

class_ c{{}};

c.set_name("MyTypeClass");

CHECK(filter.should_include(c));

enum_ e{{}};
e.set_name("MyTypeClass");

CHECK(!filter.should_include(e));
}

TEST_CASE("Test namespaces regexp filter")
{
using clanguml::class_diagram::model::class_;
Expand Down

0 comments on commit 7704192

Please sign in to comment.