Extended context filter config schema to accept optional radius parameter
This commit is contained in:
@@ -534,39 +534,35 @@ tvl::value_t access_filter::match(
|
||||
[&a](const auto &access) { return a == access; });
|
||||
}
|
||||
|
||||
context_filter::context_filter(filter_t type,
|
||||
std::vector<common::string_or_regex> context, unsigned radius)
|
||||
context_filter::context_filter(
|
||||
filter_t type, std::vector<config::context_config> context, unsigned radius)
|
||||
: filter_visitor{type}
|
||||
, radius_{radius}
|
||||
, context_{std::move(context)}
|
||||
{
|
||||
}
|
||||
|
||||
void context_filter::initialize(const diagram &d) const
|
||||
void context_filter::initialize_effective_context(
|
||||
const diagram &d, unsigned idx) const
|
||||
{
|
||||
if (initialized_)
|
||||
return;
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
bool effective_context_extended{true};
|
||||
|
||||
auto &effective_context = effective_contexts_[idx];
|
||||
|
||||
// First add to effective context all elements matching context_
|
||||
for (const auto &c : context_) {
|
||||
const auto &context = context_.at(idx);
|
||||
const auto &context_matches =
|
||||
static_cast<const class_diagram::model::diagram &>(d)
|
||||
.find<class_diagram::model::class_>(c);
|
||||
.find<class_diagram::model::class_>(context.pattern);
|
||||
|
||||
for (const auto &maybe_match : context_matches) {
|
||||
if (maybe_match)
|
||||
effective_context_.emplace(maybe_match.value().id());
|
||||
}
|
||||
effective_context.emplace(maybe_match.value().id());
|
||||
}
|
||||
|
||||
// Now repeat radius times - extend the effective context with elements
|
||||
// matching in direct relationship to what is in context
|
||||
auto radius_counter = radius_;
|
||||
decltype(effective_context_) current_iteration_context;
|
||||
auto radius_counter = context.radius;
|
||||
std::set<clanguml::common::id_t> current_iteration_context;
|
||||
|
||||
while (radius_counter > 0 && effective_context_extended) {
|
||||
// If at any iteration the effective context was not extended - we
|
||||
@@ -581,13 +577,13 @@ void context_filter::initialize(const diagram &d) const
|
||||
// Return a positive match if the element e is in a direct
|
||||
// relationship with any of the effective context elements ...
|
||||
for (const relationship &rel : c.get().relationships()) {
|
||||
for (const auto &ec : effective_context_) {
|
||||
for (const auto &ec : effective_context) {
|
||||
if (d.should_include(rel.type()) && rel.destination() == ec)
|
||||
current_iteration_context.emplace(c.get().id());
|
||||
}
|
||||
}
|
||||
// ... or vice-versa
|
||||
for (const auto &ec : effective_context_) {
|
||||
for (const auto &ec : effective_context) {
|
||||
const auto &maybe_class =
|
||||
static_cast<const class_diagram::model::diagram &>(d)
|
||||
.find<class_diagram::model::class_>(ec);
|
||||
@@ -608,7 +604,7 @@ void context_filter::initialize(const diagram &d) const
|
||||
// effective context...
|
||||
for (const class_diagram::model::class_parent &p :
|
||||
c.get().parents()) {
|
||||
for (const auto &ec : effective_context_) {
|
||||
for (const auto &ec : effective_context) {
|
||||
const auto &maybe_parent =
|
||||
static_cast<const class_diagram::model::diagram &>(d)
|
||||
.find<class_diagram::model::class_>(ec);
|
||||
@@ -622,7 +618,7 @@ void context_filter::initialize(const diagram &d) const
|
||||
}
|
||||
|
||||
// .. or vice-versa
|
||||
for (const auto &ec : effective_context_) {
|
||||
for (const auto &ec : effective_context) {
|
||||
const auto &maybe_child =
|
||||
static_cast<const class_diagram::model::diagram &>(d)
|
||||
.find<class_diagram::model::class_>(ec);
|
||||
@@ -637,15 +633,29 @@ void context_filter::initialize(const diagram &d) const
|
||||
}
|
||||
|
||||
for (auto id : current_iteration_context) {
|
||||
if (effective_context_.count(id) == 0) {
|
||||
if (effective_context.count(id) == 0) {
|
||||
// Found new element to add to context
|
||||
effective_context_.emplace(id);
|
||||
effective_context.emplace(id);
|
||||
effective_context_extended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context_filter::initialize(const diagram &d) const
|
||||
{
|
||||
if (initialized_)
|
||||
return;
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
// Prepare effective_contexts_
|
||||
for (auto i = 0U; i < context_.size(); i++) {
|
||||
effective_contexts_.push_back({});
|
||||
initialize_effective_context(d, i);
|
||||
}
|
||||
}
|
||||
|
||||
tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
||||
{
|
||||
if (d.type() != diagram_t::kClass)
|
||||
@@ -658,11 +668,14 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
||||
|
||||
initialize(d);
|
||||
|
||||
if (effective_context_.empty())
|
||||
if (std::all_of(effective_contexts_.begin(), effective_contexts_.end(),
|
||||
[](const auto &ec) { return ec.empty(); }))
|
||||
return {};
|
||||
|
||||
if (effective_context_.count(e.id()) > 0)
|
||||
for (const auto &ec : effective_contexts_) {
|
||||
if (ec.count(e.id()) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ private:
|
||||
* to any of the elements specified in context.
|
||||
*/
|
||||
struct context_filter : public filter_visitor {
|
||||
context_filter(filter_t type, std::vector<common::string_or_regex> context,
|
||||
context_filter(filter_t type, std::vector<config::context_config> context,
|
||||
unsigned radius = 1);
|
||||
|
||||
~context_filter() override = default;
|
||||
@@ -457,15 +457,15 @@ struct context_filter : public filter_visitor {
|
||||
private:
|
||||
void initialize(const diagram &d) const;
|
||||
|
||||
const unsigned radius_;
|
||||
void initialize_effective_context(const diagram &d, unsigned idx) const;
|
||||
|
||||
std::vector<common::string_or_regex> context_;
|
||||
std::vector<config::context_config> context_;
|
||||
|
||||
/*!
|
||||
* Represents all elements which should belong to the diagram based
|
||||
* on this filter. It is populated by the initialize() method.
|
||||
*/
|
||||
mutable std::set<clanguml::common::id_t> effective_context_;
|
||||
mutable std::vector<std::set<clanguml::common::id_t>> effective_contexts_;
|
||||
|
||||
/*! Flag to mark whether the filter context has been computed */
|
||||
mutable bool initialized_{false};
|
||||
|
||||
@@ -141,6 +141,11 @@ struct mermaid {
|
||||
void append(const mermaid &r);
|
||||
};
|
||||
|
||||
struct context_config {
|
||||
common::string_or_regex pattern;
|
||||
unsigned radius{0};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Definition of diagram template
|
||||
*/
|
||||
@@ -316,9 +321,13 @@ struct filter {
|
||||
* include:
|
||||
* context:
|
||||
* - ns1::ns2::ClassA
|
||||
* - r: ns1::ns2::ClassB<.*>
|
||||
* - match:
|
||||
* pattern: ns1::ns2::ClassA
|
||||
* radius: 3
|
||||
* ```
|
||||
*/
|
||||
std::vector<common::string_or_regex> context;
|
||||
std::vector<context_config> context;
|
||||
|
||||
/*! @brief Paths filter
|
||||
*
|
||||
|
||||
@@ -112,6 +112,13 @@ types:
|
||||
- function
|
||||
- function_template
|
||||
- lambda
|
||||
context_filter_match_t:
|
||||
match:
|
||||
radius: int
|
||||
pattern: regex_or_string_t
|
||||
context_filter_t:
|
||||
- regex_or_string_t
|
||||
- context_filter_match_t
|
||||
filter_t:
|
||||
namespaces: !optional [regex_or_string_t]
|
||||
elements: !optional [regex_or_string_t]
|
||||
@@ -123,7 +130,7 @@ types:
|
||||
specializations: !optional [regex_or_string_t]
|
||||
dependants: !optional [regex_or_string_t]
|
||||
dependencies: !optional [regex_or_string_t]
|
||||
context: !optional [regex_or_string_t]
|
||||
context: !optional [context_filter_t]
|
||||
paths: !optional [string]
|
||||
method_types: !optional [method_type_filter_t]
|
||||
callee_types: !optional [callee_type_filter_t]
|
||||
|
||||
@@ -33,6 +33,7 @@ using clanguml::common::model::relationship_t;
|
||||
using clanguml::config::callee_type;
|
||||
using clanguml::config::class_diagram;
|
||||
using clanguml::config::config;
|
||||
using clanguml::config::context_config;
|
||||
using clanguml::config::diagram_template;
|
||||
using clanguml::config::filter;
|
||||
using clanguml::config::generate_links_config;
|
||||
@@ -419,6 +420,23 @@ template <> struct convert<string_or_regex> {
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct convert<context_config> {
|
||||
static bool decode(const Node &node, context_config &rhs)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
if (node.IsMap() && has_key(node, "match")) {
|
||||
rhs.radius = node["match"]["radius"].as<unsigned>();
|
||||
rhs.pattern = node["match"]["radius"].as<string_or_regex>();
|
||||
}
|
||||
else {
|
||||
rhs.radius = 1;
|
||||
rhs.pattern = node.as<string_or_regex>();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct convert<namespace_or_regex> {
|
||||
static bool decode(const Node &node, namespace_or_regex &rhs)
|
||||
{
|
||||
|
||||
@@ -104,6 +104,19 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const package_type_t &r)
|
||||
return out;
|
||||
}
|
||||
|
||||
YAML::Emitter &operator<<(YAML::Emitter &out, const context_config &c)
|
||||
{
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "match";
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "radius" << YAML::Value << c.radius;
|
||||
out << YAML::Key << "pattern" << YAML::Value << c.pattern;
|
||||
out << YAML::EndMap;
|
||||
out << YAML::EndMap;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
||||
{
|
||||
out << YAML::BeginMap;
|
||||
|
||||
Reference in New Issue
Block a user