Merge pull request #171 from bkryza/add-configuration-file-validation
Add configuration file validation
This commit is contained in:
@@ -443,6 +443,7 @@ This project relies on the following great tools:
|
|||||||
* [spdlog](https://github.com/gabime/spdlog) - Fast C++ logging library
|
* [spdlog](https://github.com/gabime/spdlog) - Fast C++ logging library
|
||||||
* [Doxygen](https://www.doxygen.nl/) - C++ documentation generator
|
* [Doxygen](https://www.doxygen.nl/) - C++ documentation generator
|
||||||
* [Doxygen Awesome](https://jothepro.github.io/doxygen-awesome-css) - Doxygen CSS style
|
* [Doxygen Awesome](https://jothepro.github.io/doxygen-awesome-css) - Doxygen CSS style
|
||||||
|
* [miroir](https://gitlab.com/madyanov/miroir) - YAML schema validation library for C++
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ diagrams:
|
|||||||
- ../../tests/t00048/a_t00048.cc
|
- ../../tests/t00048/a_t00048.cc
|
||||||
- ../../tests/t00048/t00048.cc
|
- ../../tests/t00048/t00048.cc
|
||||||
using_namespace: clanguml::t00048
|
using_namespace: clanguml::t00048
|
||||||
parse_includes: true
|
|
||||||
include:
|
include:
|
||||||
namespaces:
|
namespaces:
|
||||||
- clanguml::t00048
|
- clanguml::t00048
|
||||||
|
|||||||
@@ -200,6 +200,13 @@ the configuration file to `clang-uml` using `stdin`, e.g.:
|
|||||||
yq 'explode(.)' .clang-uml | clang-uml --config -
|
yq 'explode(.)' .clang-uml | clang-uml --config -
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Schema validation error is thrown, but the configuration file is correct
|
||||||
|
Current version of `clang-uml` performs automatic configuration file
|
||||||
|
schema validation, and exits if the configuration file is invalid.
|
||||||
|
|
||||||
|
In case there is a bug in the schema validation, the schema validation
|
||||||
|
step can be skipped by providing `--no-validate` command line option.
|
||||||
|
|
||||||
## Class diagrams
|
## Class diagrams
|
||||||
|
|
||||||
### "fatal error: 'stddef.h' file not found"
|
### "fatal error: 'stddef.h' file not found"
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ cli_flow_t cli_handler::parse(int argc, const char **argv)
|
|||||||
"Skip metadata (e.g. clang-uml version) from diagrams");
|
"Skip metadata (e.g. clang-uml version) from diagrams");
|
||||||
app.add_flag("--print-start-from", print_start_from,
|
app.add_flag("--print-start-from", print_start_from,
|
||||||
"Print all possible 'start_from' values for a given diagram");
|
"Print all possible 'start_from' values for a given diagram");
|
||||||
|
app.add_flag("--no-validate", no_validate,
|
||||||
|
"Do not perform configuration file schema validation");
|
||||||
|
app.add_flag("--validate-only", validate_only,
|
||||||
|
"Perform configuration file schema validation and exit");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
app.parse(argc, argv);
|
app.parse(argc, argv);
|
||||||
@@ -245,7 +249,13 @@ cli_flow_t cli_handler::load_config()
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
config = clanguml::config::load(
|
config = clanguml::config::load(
|
||||||
config_path, paths_relative_to_pwd, no_metadata);
|
config_path, paths_relative_to_pwd, no_metadata, !no_validate);
|
||||||
|
if (validate_only) {
|
||||||
|
std::cout << "Configuration file " << config_path << " is valid.\n";
|
||||||
|
|
||||||
|
return cli_flow_t::kExit;
|
||||||
|
}
|
||||||
|
|
||||||
return cli_flow_t::kContinue;
|
return cli_flow_t::kContinue;
|
||||||
}
|
}
|
||||||
catch (std::runtime_error &e) {
|
catch (std::runtime_error &e) {
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ public:
|
|||||||
std::optional<std::string> show_template;
|
std::optional<std::string> show_template;
|
||||||
std::vector<clanguml::common::generator_type_t> generators{
|
std::vector<clanguml::common::generator_type_t> generators{
|
||||||
clanguml::common::generator_type_t::plantuml};
|
clanguml::common::generator_type_t::plantuml};
|
||||||
|
bool no_validate{false};
|
||||||
|
bool validate_only{false};
|
||||||
|
|
||||||
clanguml::config::config config;
|
clanguml::config::config config;
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,32 @@ std::string to_string(location_t cp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string to_string(package_type_t pt)
|
||||||
|
{
|
||||||
|
switch (pt) {
|
||||||
|
case package_type_t::kNamespace:
|
||||||
|
return "namespace";
|
||||||
|
case package_type_t::kDirectory:
|
||||||
|
return "directory";
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(member_order_t mo)
|
||||||
|
{
|
||||||
|
switch (mo) {
|
||||||
|
case member_order_t::lexical:
|
||||||
|
return "lexical";
|
||||||
|
case member_order_t::as_is:
|
||||||
|
return "as_is";
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void plantuml::append(const plantuml &r)
|
void plantuml::append(const plantuml &r)
|
||||||
{
|
{
|
||||||
before.insert(before.end(), r.before.begin(), r.before.end());
|
before.insert(before.end(), r.before.begin(), r.before.end());
|
||||||
|
|||||||
@@ -36,6 +36,10 @@
|
|||||||
|
|
||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
|
|
||||||
|
namespace cli {
|
||||||
|
struct runtime_config;
|
||||||
|
} // namespace cli
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configuration file related classes
|
* @brief Configuration file related classes
|
||||||
*
|
*
|
||||||
@@ -50,6 +54,8 @@ enum class method_arguments {
|
|||||||
none /*! Empty string between '(' and ')' */
|
none /*! Empty string between '(' and ')' */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string to_string(method_arguments ma);
|
||||||
|
|
||||||
/*! Types of methods, which can be used in diagram filters */
|
/*! Types of methods, which can be used in diagram filters */
|
||||||
enum class method_type {
|
enum class method_type {
|
||||||
constructor,
|
constructor,
|
||||||
@@ -84,6 +90,8 @@ enum class package_type_t {
|
|||||||
kDirectory /*!< From directories */
|
kDirectory /*!< From directories */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string to_string(package_type_t mt);
|
||||||
|
|
||||||
/*! How class methods and members should be ordered in diagrams */
|
/*! How class methods and members should be ordered in diagrams */
|
||||||
enum class member_order_t {
|
enum class member_order_t {
|
||||||
lexical, /*! Lexical order based on entire method or member signature
|
lexical, /*! Lexical order based on entire method or member signature
|
||||||
@@ -91,7 +99,7 @@ enum class member_order_t {
|
|||||||
as_is /*! As written in source code */
|
as_is /*! As written in source code */
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string to_string(method_arguments ma);
|
std::string to_string(member_order_t mt);
|
||||||
|
|
||||||
/*! Which comment parser should be used */
|
/*! Which comment parser should be used */
|
||||||
enum class comment_parser_t {
|
enum class comment_parser_t {
|
||||||
@@ -413,6 +421,8 @@ struct source_location {
|
|||||||
* @embed{inheritable_diagram_options_context_class.svg}
|
* @embed{inheritable_diagram_options_context_class.svg}
|
||||||
*/
|
*/
|
||||||
struct inheritable_diagram_options {
|
struct inheritable_diagram_options {
|
||||||
|
virtual ~inheritable_diagram_options() = default;
|
||||||
|
|
||||||
option<std::vector<std::string>> glob{"glob"};
|
option<std::vector<std::string>> glob{"glob"};
|
||||||
option<common::model::namespace_> using_namespace{"using_namespace"};
|
option<common::model::namespace_> using_namespace{"using_namespace"};
|
||||||
option<bool> include_relations_also_as_members{
|
option<bool> include_relations_also_as_members{
|
||||||
@@ -424,7 +434,7 @@ struct inheritable_diagram_options {
|
|||||||
"generate_method_arguments", method_arguments::full};
|
"generate_method_arguments", method_arguments::full};
|
||||||
option<bool> group_methods{"group_methods", true};
|
option<bool> group_methods{"group_methods", true};
|
||||||
option<member_order_t> member_order{
|
option<member_order_t> member_order{
|
||||||
"method_order", member_order_t::lexical};
|
"member_order", member_order_t::lexical};
|
||||||
option<bool> generate_packages{"generate_packages", false};
|
option<bool> generate_packages{"generate_packages", false};
|
||||||
option<package_type_t> package_type{
|
option<package_type_t> package_type{
|
||||||
"package_type", package_type_t::kNamespace};
|
"package_type", package_type_t::kNamespace};
|
||||||
@@ -466,7 +476,7 @@ struct inheritable_diagram_options {
|
|||||||
* @embed{diagram_config_hierarchy_class.svg}
|
* @embed{diagram_config_hierarchy_class.svg}
|
||||||
*/
|
*/
|
||||||
struct diagram : public inheritable_diagram_options {
|
struct diagram : public inheritable_diagram_options {
|
||||||
virtual ~diagram() = default;
|
~diagram() override = default;
|
||||||
|
|
||||||
virtual common::model::diagram_t type() const = 0;
|
virtual common::model::diagram_t type() const = 0;
|
||||||
|
|
||||||
@@ -616,13 +626,12 @@ struct config : public inheritable_diagram_options {
|
|||||||
* the configuration file or to the current
|
* the configuration file or to the current
|
||||||
* directory (`$PWD`)
|
* directory (`$PWD`)
|
||||||
* @param no_metadata Whether the diagram should skip metadata at the end
|
* @param no_metadata Whether the diagram should skip metadata at the end
|
||||||
|
* @param validate If true, perform schema validation
|
||||||
* @return Configuration instance
|
* @return Configuration instance
|
||||||
*/
|
*/
|
||||||
config load(const std::string &config_file,
|
config load(const std::string &config_file,
|
||||||
std::optional<bool> paths_relative_to_pwd = {},
|
std::optional<bool> paths_relative_to_pwd = {},
|
||||||
std::optional<bool> no_metadata = {});
|
std::optional<bool> no_metadata = {}, bool validate = true);
|
||||||
|
|
||||||
config load_plain(const std::string &config_file);
|
|
||||||
|
|
||||||
} // namespace config
|
} // namespace config
|
||||||
|
|
||||||
|
|||||||
295
src/config/schema.h
Normal file
295
src/config/schema.h
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/**
|
||||||
|
* @file src/config/schema.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 <string>
|
||||||
|
|
||||||
|
namespace clanguml::config {
|
||||||
|
|
||||||
|
const std::string schema_str = R"(
|
||||||
|
types:
|
||||||
|
map_t<K;V>: { $K: V }
|
||||||
|
comment_parser_t: !variant
|
||||||
|
- plain
|
||||||
|
- clang
|
||||||
|
diagram_type_t: !variant
|
||||||
|
- class
|
||||||
|
- sequence
|
||||||
|
- include
|
||||||
|
- package
|
||||||
|
generate_method_arguments_t: !variant
|
||||||
|
- full
|
||||||
|
- abbreviated
|
||||||
|
- none
|
||||||
|
generate_links_t:
|
||||||
|
link: string
|
||||||
|
tooltip: string
|
||||||
|
git_t:
|
||||||
|
branch: string
|
||||||
|
revision: string
|
||||||
|
commit: string
|
||||||
|
toplevel: string
|
||||||
|
layout_hint_key: !variant
|
||||||
|
- up
|
||||||
|
- left
|
||||||
|
- right
|
||||||
|
- down
|
||||||
|
- row
|
||||||
|
- column
|
||||||
|
- together
|
||||||
|
layout_hint_value: [string, [string]]
|
||||||
|
layout_hint_t: [map_t<layout_hint_key;layout_hint_value>]
|
||||||
|
layout_t: map_t<string;layout_hint_t>
|
||||||
|
package_type_t: !variant
|
||||||
|
- namespace
|
||||||
|
- directory
|
||||||
|
member_order_t: !variant
|
||||||
|
- lexical
|
||||||
|
- as_is
|
||||||
|
regex_t:
|
||||||
|
r: string
|
||||||
|
regex_or_string_t: [string, regex_t]
|
||||||
|
namespaces_filter_t:
|
||||||
|
namespaces: [regex_or_string_t]
|
||||||
|
elements_filter_t:
|
||||||
|
elements: [regex_or_string_t]
|
||||||
|
element_types_filter_t: !variant
|
||||||
|
- class
|
||||||
|
- enum
|
||||||
|
- concept
|
||||||
|
- method
|
||||||
|
- function
|
||||||
|
- function_template
|
||||||
|
- lambda
|
||||||
|
relationship_filter_t: !variant
|
||||||
|
- extension
|
||||||
|
- inheritance
|
||||||
|
- composition
|
||||||
|
- aggregation
|
||||||
|
- containment
|
||||||
|
- ownership
|
||||||
|
- association
|
||||||
|
- instantiation
|
||||||
|
- friendship
|
||||||
|
- alias
|
||||||
|
- dependency
|
||||||
|
- constraint
|
||||||
|
- none
|
||||||
|
access_filter_t: !variant
|
||||||
|
- public
|
||||||
|
- protected
|
||||||
|
- private
|
||||||
|
method_type_filter_t: !variant
|
||||||
|
- constructor
|
||||||
|
- destructor
|
||||||
|
- assignment
|
||||||
|
- operator
|
||||||
|
- defaulted
|
||||||
|
- deleted
|
||||||
|
- static
|
||||||
|
callee_type_filter_t: !variant
|
||||||
|
- constructor
|
||||||
|
- assignment
|
||||||
|
- operator
|
||||||
|
- defaulted
|
||||||
|
- static
|
||||||
|
- method
|
||||||
|
- function
|
||||||
|
- function_template
|
||||||
|
- lambda
|
||||||
|
filter_t:
|
||||||
|
namespaces: !optional [regex_or_string_t]
|
||||||
|
elements: !optional [regex_or_string_t]
|
||||||
|
element_types: !optional [element_types_filter_t]
|
||||||
|
relationships: !optional [relationship_filter_t]
|
||||||
|
access: !optional [access_filter_t]
|
||||||
|
subclasses: !optional [regex_or_string_t]
|
||||||
|
parents: !optional [regex_or_string_t]
|
||||||
|
specializations: !optional [regex_or_string_t]
|
||||||
|
dependants: !optional [regex_or_string_t]
|
||||||
|
dependencies: !optional [regex_or_string_t]
|
||||||
|
context: !optional [regex_or_string_t]
|
||||||
|
paths: !optional [string]
|
||||||
|
method_types: !optional [method_type_filter_t]
|
||||||
|
callee_types: !optional [callee_type_filter_t]
|
||||||
|
function_location_t:
|
||||||
|
function: string
|
||||||
|
marker_location_t:
|
||||||
|
marker: string
|
||||||
|
source_location_t:
|
||||||
|
- function_location_t
|
||||||
|
- marker_location_t
|
||||||
|
class_diagram_t:
|
||||||
|
type: !variant [class]
|
||||||
|
#
|
||||||
|
# Common options
|
||||||
|
#
|
||||||
|
__parent_path: !optional string
|
||||||
|
comment_parser: !optional comment_parser_t
|
||||||
|
debug_mode: !optional bool
|
||||||
|
exclude: !optional filter_t
|
||||||
|
generate_links: !optional generate_links_t
|
||||||
|
git: !optional git_t
|
||||||
|
glob: !optional [string]
|
||||||
|
include: !optional filter_t
|
||||||
|
plantuml: !optional
|
||||||
|
before: !optional [string]
|
||||||
|
after: !optional [string]
|
||||||
|
relative_to: !optional string
|
||||||
|
using_namespace: !optional [string, [string]]
|
||||||
|
generate_metadata: !optional bool
|
||||||
|
#
|
||||||
|
# Class diagram specific options
|
||||||
|
#
|
||||||
|
generate_method_arguments: !optional generate_method_arguments_t
|
||||||
|
generate_packages: !optional bool
|
||||||
|
package_type: !optional package_type_t
|
||||||
|
member_order: !optional member_order_t
|
||||||
|
group_methods: !optional bool
|
||||||
|
type_aliases: !optional map_t<string;string>
|
||||||
|
relationship_hints: !optional map_t<string;any>
|
||||||
|
include_relations_also_as_members: !optional bool
|
||||||
|
layout: !optional layout_t
|
||||||
|
sequence_diagram_t:
|
||||||
|
type: !variant [sequence]
|
||||||
|
#
|
||||||
|
# Common options
|
||||||
|
#
|
||||||
|
__parent_path: !optional string
|
||||||
|
comment_parser: !optional comment_parser_t
|
||||||
|
debug_mode: !optional bool
|
||||||
|
exclude: !optional filter_t
|
||||||
|
generate_links: !optional generate_links_t
|
||||||
|
git: !optional git_t
|
||||||
|
glob: !optional [string]
|
||||||
|
include: !optional filter_t
|
||||||
|
plantuml: !optional
|
||||||
|
before: !optional [string]
|
||||||
|
after: !optional [string]
|
||||||
|
relative_to: !optional string
|
||||||
|
using_namespace: !optional [string, [string]]
|
||||||
|
generate_metadata: !optional bool
|
||||||
|
#
|
||||||
|
# Sequence diagram specific options
|
||||||
|
#
|
||||||
|
generate_method_arguments: !optional generate_method_arguments_t
|
||||||
|
combine_free_functions_into_file_participants: !optional bool
|
||||||
|
generate_return_types: !optional bool
|
||||||
|
generate_condition_statements: !optional bool
|
||||||
|
participants_order: !optional [string]
|
||||||
|
start_from: !optional [source_location_t]
|
||||||
|
package_diagram_t:
|
||||||
|
type: !variant [package]
|
||||||
|
#
|
||||||
|
# Common options
|
||||||
|
#
|
||||||
|
__parent_path: !optional string
|
||||||
|
comment_parser: !optional comment_parser_t
|
||||||
|
debug_mode: !optional bool
|
||||||
|
exclude: !optional filter_t
|
||||||
|
generate_links: !optional generate_links_t
|
||||||
|
git: !optional git_t
|
||||||
|
glob: !optional [string]
|
||||||
|
include: !optional filter_t
|
||||||
|
plantuml: !optional
|
||||||
|
before: !optional [string]
|
||||||
|
after: !optional [string]
|
||||||
|
relative_to: !optional string
|
||||||
|
using_namespace: !optional [string, [string]]
|
||||||
|
generate_metadata: !optional bool
|
||||||
|
#
|
||||||
|
# Package diagram specific options
|
||||||
|
#
|
||||||
|
generate_packages: !optional bool
|
||||||
|
package_type: !optional package_type_t
|
||||||
|
layout: !optional layout_t
|
||||||
|
include_diagram_t:
|
||||||
|
type: !variant [include]
|
||||||
|
#
|
||||||
|
# Common options
|
||||||
|
#
|
||||||
|
__parent_path: !optional string
|
||||||
|
comment_parser: !optional comment_parser_t
|
||||||
|
debug_mode: !optional bool
|
||||||
|
exclude: !optional filter_t
|
||||||
|
generate_links: !optional generate_links_t
|
||||||
|
git: !optional git_t
|
||||||
|
glob: !optional [string]
|
||||||
|
include: !optional filter_t
|
||||||
|
plantuml: !optional
|
||||||
|
before: !optional [string]
|
||||||
|
after: !optional [string]
|
||||||
|
relative_to: !optional string
|
||||||
|
using_namespace: !optional [string, [string]]
|
||||||
|
generate_metadata: !optional bool
|
||||||
|
#
|
||||||
|
# Include diagram specific options
|
||||||
|
#
|
||||||
|
generate_system_headers: !optional bool
|
||||||
|
diagram_t:
|
||||||
|
- class_diagram_t
|
||||||
|
- sequence_diagram_t
|
||||||
|
- package_diagram_t
|
||||||
|
- include_diagram_t
|
||||||
|
diagram_template_t:
|
||||||
|
description: !optional string
|
||||||
|
type: diagram_type_t
|
||||||
|
template: string
|
||||||
|
diagram_templates_t: map_t<string;diagram_template_t>
|
||||||
|
|
||||||
|
root:
|
||||||
|
#
|
||||||
|
# Root options
|
||||||
|
#
|
||||||
|
compilation_database_dir: !optional string
|
||||||
|
output_directory: !optional string
|
||||||
|
add_compile_flags: !optional [string]
|
||||||
|
remove_compile_flags: !optional [string]
|
||||||
|
diagram_templates: !optional diagram_templates_t
|
||||||
|
diagrams: !required map_t<string;diagram_t>
|
||||||
|
#
|
||||||
|
# Common options
|
||||||
|
#
|
||||||
|
__parent_path: !optional string
|
||||||
|
comment_parser: !optional comment_parser_t
|
||||||
|
debug_mode: !optional bool
|
||||||
|
exclude: !optional filter_t
|
||||||
|
generate_links: !optional generate_links_t
|
||||||
|
git: !optional git_t
|
||||||
|
glob: !optional [string]
|
||||||
|
include: !optional filter_t
|
||||||
|
plantuml: !optional
|
||||||
|
before: !optional [string]
|
||||||
|
after: !optional [string]
|
||||||
|
relative_to: !optional string
|
||||||
|
using_namespace: !optional [string, [string]]
|
||||||
|
generate_metadata: !optional bool
|
||||||
|
#
|
||||||
|
# Inheritable custom options
|
||||||
|
#
|
||||||
|
include_relations_also_as_members: !optional bool
|
||||||
|
generate_method_arguments: !optional generate_method_arguments_t
|
||||||
|
combine_free_functions_into_file_participants: !optional bool
|
||||||
|
generate_return_types: !optional bool
|
||||||
|
generate_condition_statements: !optional bool
|
||||||
|
generate_packages: !optional bool
|
||||||
|
group_methods: !optional bool
|
||||||
|
package_type: !optional package_type_t
|
||||||
|
)";
|
||||||
|
|
||||||
|
} // namespace clanguml::config
|
||||||
@@ -16,8 +16,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cli/cli_handler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "diagram_templates.h"
|
#include "diagram_templates.h"
|
||||||
|
#include "schema.h"
|
||||||
|
|
||||||
|
#define MIROIR_IMPLEMENTATION
|
||||||
|
#define MIROIR_YAMLCPP_SPECIALIZATION
|
||||||
|
#include <miroir/miroir.hpp>
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
using clanguml::common::namespace_or_regex;
|
using clanguml::common::namespace_or_regex;
|
||||||
@@ -766,28 +772,13 @@ template <> struct convert<config> {
|
|||||||
|
|
||||||
auto diagrams = node["diagrams"];
|
auto diagrams = node["diagrams"];
|
||||||
|
|
||||||
assert(diagrams.Type() == NodeType::Map);
|
|
||||||
|
|
||||||
for (auto d : diagrams) {
|
for (auto d : diagrams) {
|
||||||
auto name = d.first.as<std::string>();
|
auto name = d.first.as<std::string>();
|
||||||
std::shared_ptr<clanguml::config::diagram> diagram_config{};
|
std::shared_ptr<clanguml::config::diagram> diagram_config{};
|
||||||
auto parent_path = node["__parent_path"].as<std::string>();
|
auto parent_path = node["__parent_path"].as<std::string>();
|
||||||
|
d.second.force_insert("__parent_path", parent_path);
|
||||||
|
|
||||||
if (has_key(d.second, "include!")) {
|
diagram_config = parse_diagram_config(d.second);
|
||||||
auto include_path = std::filesystem::path{parent_path};
|
|
||||||
include_path /= d.second["include!"].as<std::string>();
|
|
||||||
|
|
||||||
YAML::Node included_node =
|
|
||||||
YAML::LoadFile(include_path.string());
|
|
||||||
included_node.force_insert("__parent_path", parent_path);
|
|
||||||
|
|
||||||
diagram_config = parse_diagram_config(included_node);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
d.second.force_insert("__parent_path", parent_path);
|
|
||||||
diagram_config = parse_diagram_config(d.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diagram_config) {
|
if (diagram_config) {
|
||||||
diagram_config->name = name;
|
diagram_config->name = name;
|
||||||
diagram_config->inherit(rhs);
|
diagram_config->inherit(rhs);
|
||||||
@@ -841,9 +832,13 @@ void resolve_option_path(YAML::Node &doc, const std::string &option)
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
config load(const std::string &config_file,
|
config load(const std::string &config_file,
|
||||||
std::optional<bool> paths_relative_to_pwd, std::optional<bool> no_metadata)
|
std::optional<bool> paths_relative_to_pwd, std::optional<bool> no_metadata,
|
||||||
|
bool validate)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
auto schema = YAML::Load(clanguml::config::schema_str);
|
||||||
|
auto schema_validator = miroir::Validator<YAML::Node>(schema);
|
||||||
|
|
||||||
YAML::Node doc;
|
YAML::Node doc;
|
||||||
std::filesystem::path config_file_path{};
|
std::filesystem::path config_file_path{};
|
||||||
|
|
||||||
@@ -860,6 +855,8 @@ config load(const std::string &config_file,
|
|||||||
|
|
||||||
// Store the parent path of the config_file to properly resolve
|
// Store the parent path of the config_file to properly resolve
|
||||||
// the include files paths
|
// the include files paths
|
||||||
|
if (has_key(doc, "__parent_path"))
|
||||||
|
doc.remove("__parent_path");
|
||||||
if (config_file == "-") {
|
if (config_file == "-") {
|
||||||
config_file_path = std::filesystem::current_path();
|
config_file_path = std::filesystem::current_path();
|
||||||
doc.force_insert("__parent_path", config_file_path.string());
|
doc.force_insert("__parent_path", config_file_path.string());
|
||||||
@@ -914,6 +911,40 @@ config load(const std::string &config_file,
|
|||||||
doc["git"] = git_config;
|
doc["git"] = git_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve diagram includes
|
||||||
|
auto diagrams = doc["diagrams"];
|
||||||
|
|
||||||
|
assert(diagrams.Type() == YAML::NodeType::Map);
|
||||||
|
|
||||||
|
for (auto d : diagrams) {
|
||||||
|
auto name = d.first.as<std::string>();
|
||||||
|
std::shared_ptr<clanguml::config::diagram> diagram_config{};
|
||||||
|
auto parent_path = doc["__parent_path"].as<std::string>();
|
||||||
|
|
||||||
|
if (has_key(d.second, "include!")) {
|
||||||
|
auto include_path = std::filesystem::path{parent_path};
|
||||||
|
include_path /= d.second["include!"].as<std::string>();
|
||||||
|
|
||||||
|
YAML::Node included_node =
|
||||||
|
YAML::LoadFile(include_path.string());
|
||||||
|
|
||||||
|
diagrams[name] = included_node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validate) {
|
||||||
|
auto schema_errors = schema_validator.validate(doc);
|
||||||
|
|
||||||
|
if (!schema_errors.empty()) {
|
||||||
|
// print validation errors
|
||||||
|
for (const auto &err : schema_errors) {
|
||||||
|
LOG_ERROR("Schema error: {}", err.description());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw YAML::Exception({}, "Invalid configuration schema");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto d = doc.as<config>();
|
auto d = doc.as<config>();
|
||||||
|
|
||||||
d.initialize_diagram_templates();
|
d.initialize_diagram_templates();
|
||||||
@@ -929,25 +960,4 @@ config load(const std::string &config_file,
|
|||||||
"Cannot parse YAML file {}: {}", config_file, e.what()));
|
"Cannot parse YAML file {}: {}", config_file, e.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config load_plain(const std::string &config_file)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
YAML::Node doc;
|
|
||||||
std::filesystem::path config_file_path{};
|
|
||||||
|
|
||||||
doc = YAML::LoadFile(config_file);
|
|
||||||
|
|
||||||
auto d = doc.as<config>();
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
catch (YAML::BadFile &e) {
|
|
||||||
throw std::runtime_error(fmt::format(
|
|
||||||
"Could not open config file {}: {}", config_file, e.what()));
|
|
||||||
}
|
|
||||||
catch (YAML::Exception &e) {
|
|
||||||
throw std::runtime_error(fmt::format(
|
|
||||||
"Cannot parse YAML file {}: {}", config_file, e.what()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace clanguml::config
|
} // namespace clanguml::config
|
||||||
@@ -26,8 +26,10 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const string_or_regex &m)
|
|||||||
out << std::get<std::string>(m.value());
|
out << std::get<std::string>(m.value());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
out << YAML::BeginMap;
|
||||||
out << YAML::Key << "r" << YAML::Value
|
out << YAML::Key << "r" << YAML::Value
|
||||||
<< std::get<regex>(m.value()).pattern;
|
<< std::get<regex>(m.value()).pattern;
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@@ -39,8 +41,10 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const namespace_or_regex &m)
|
|||||||
out << std::get<common::model::namespace_>(m.value());
|
out << std::get<common::model::namespace_>(m.value());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
out << YAML::BeginMap;
|
||||||
out << YAML::Key << "r" << YAML::Value
|
out << YAML::Key << "r" << YAML::Value
|
||||||
<< std::get<regex>(m.value()).pattern;
|
<< std::get<regex>(m.value()).pattern;
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@@ -88,6 +92,18 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const callee_type &m)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YAML::Emitter &operator<<(YAML::Emitter &out, const member_order_t &r)
|
||||||
|
{
|
||||||
|
out << to_string(r);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
YAML::Emitter &operator<<(YAML::Emitter &out, const package_type_t &r)
|
||||||
|
{
|
||||||
|
out << to_string(r);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
||||||
{
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
@@ -267,32 +283,50 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const config &c)
|
|||||||
YAML::Emitter &operator<<(
|
YAML::Emitter &operator<<(
|
||||||
YAML::Emitter &out, const inheritable_diagram_options &c)
|
YAML::Emitter &out, const inheritable_diagram_options &c)
|
||||||
{
|
{
|
||||||
out << c.glob;
|
// Common options
|
||||||
out << c.using_namespace;
|
out << c.base_directory;
|
||||||
out << c.include_relations_also_as_members;
|
out << c.comment_parser;
|
||||||
out << c.include;
|
out << c.debug_mode;
|
||||||
out << c.exclude;
|
out << c.exclude;
|
||||||
out << c.puml;
|
|
||||||
out << c.generate_method_arguments;
|
|
||||||
out << c.generate_packages;
|
|
||||||
out << c.generate_links;
|
out << c.generate_links;
|
||||||
out << c.git;
|
out << c.git;
|
||||||
out << c.base_directory;
|
out << c.glob;
|
||||||
|
out << c.include;
|
||||||
|
out << c.puml;
|
||||||
out << c.relative_to;
|
out << c.relative_to;
|
||||||
out << c.generate_system_headers;
|
out << c.using_namespace;
|
||||||
if (c.relationship_hints) {
|
out << c.generate_metadata;
|
||||||
out << YAML::Key << "relationship_hints" << YAML::Value
|
|
||||||
<< c.relationship_hints();
|
if (dynamic_cast<const class_diagram *>(&c) != nullptr) {
|
||||||
|
out << c.generate_method_arguments;
|
||||||
|
out << c.generate_packages;
|
||||||
|
out << c.include_relations_also_as_members;
|
||||||
|
if (c.relationship_hints) {
|
||||||
|
out << YAML::Key << "relationship_hints" << YAML::Value
|
||||||
|
<< c.relationship_hints();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.type_aliases) {
|
||||||
|
out << YAML::Key << "type_aliases" << YAML::Value
|
||||||
|
<< c.type_aliases();
|
||||||
|
}
|
||||||
|
out << c.member_order;
|
||||||
|
out << c.package_type;
|
||||||
}
|
}
|
||||||
if (c.type_aliases) {
|
else if (dynamic_cast<const sequence_diagram *>(&c) != nullptr) {
|
||||||
out << YAML::Key << "type_aliases" << YAML::Value << c.type_aliases();
|
out << c.combine_free_functions_into_file_participants;
|
||||||
|
out << c.generate_condition_statements;
|
||||||
|
out << c.generate_method_arguments;
|
||||||
|
out << c.generate_return_types;
|
||||||
|
out << c.participants_order;
|
||||||
|
}
|
||||||
|
else if (dynamic_cast<const package_diagram *>(&c) != nullptr) {
|
||||||
|
out << c.generate_packages;
|
||||||
|
out << c.package_type;
|
||||||
|
}
|
||||||
|
else if (dynamic_cast<const include_diagram *>(&c) != nullptr) {
|
||||||
|
out << c.generate_system_headers;
|
||||||
}
|
}
|
||||||
out << c.comment_parser;
|
|
||||||
out << c.combine_free_functions_into_file_participants;
|
|
||||||
out << c.generate_return_types;
|
|
||||||
out << c.generate_condition_statements;
|
|
||||||
out << c.participants_order;
|
|
||||||
out << c.debug_mode;
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ diagrams:
|
|||||||
- ../../tests/t00048/a_t00048.cc
|
- ../../tests/t00048/a_t00048.cc
|
||||||
- ../../tests/t00048/t00048.cc
|
- ../../tests/t00048/t00048.cc
|
||||||
using_namespace: clanguml::t00048
|
using_namespace: clanguml::t00048
|
||||||
parse_includes: true
|
|
||||||
include:
|
include:
|
||||||
namespaces:
|
namespaces:
|
||||||
- clanguml::t00048
|
- clanguml::t00048
|
||||||
@@ -15,10 +15,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_RUNNER
|
||||||
|
#define CATCH_CONFIG_CONSOLE_WIDTH 512
|
||||||
#include "catch.h"
|
#include "catch.h"
|
||||||
|
|
||||||
|
#include "cli/cli_handler.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
@@ -339,4 +340,45 @@ TEST_CASE("Test config sequence inherited", "[unit-test]")
|
|||||||
CHECK(def.type() == clanguml::common::model::diagram_t::kSequence);
|
CHECK(def.type() == clanguml::common::model::diagram_t::kSequence);
|
||||||
CHECK(def.combine_free_functions_into_file_participants() == false);
|
CHECK(def.combine_free_functions_into_file_participants() == false);
|
||||||
CHECK(def.generate_return_types() == false);
|
CHECK(def.generate_return_types() == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test config full clang uml dump", "[unit-test]")
|
||||||
|
{
|
||||||
|
auto cfg =
|
||||||
|
clanguml::config::load("./test_config_data/clang_uml_config.yml");
|
||||||
|
|
||||||
|
CHECK(cfg.diagrams.size() == 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Main test function
|
||||||
|
///
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Catch::Session session;
|
||||||
|
using namespace Catch::clara;
|
||||||
|
|
||||||
|
bool debug_log{false};
|
||||||
|
auto cli = session.cli() |
|
||||||
|
Opt(debug_log, "debug_log")["-u"]["--debug-log"]("Enable debug logs");
|
||||||
|
|
||||||
|
session.cli(cli);
|
||||||
|
|
||||||
|
int returnCode = session.applyCommandLine(argc, argv);
|
||||||
|
if (returnCode != 0)
|
||||||
|
return returnCode;
|
||||||
|
|
||||||
|
clanguml::cli::cli_handler clih;
|
||||||
|
|
||||||
|
std::vector<const char *> argvv = {
|
||||||
|
"clang-uml", "--config", "./test_config_data/simple.yml"};
|
||||||
|
|
||||||
|
if (debug_log)
|
||||||
|
argvv.push_back("-vvv");
|
||||||
|
else
|
||||||
|
argvv.push_back("-q");
|
||||||
|
|
||||||
|
clih.handle_options(argvv.size(), argvv.data());
|
||||||
|
|
||||||
|
return session.run();
|
||||||
|
}
|
||||||
|
|||||||
1154
tests/test_config_data/clang_uml_config.yml
Normal file
1154
tests/test_config_data/clang_uml_config.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,11 @@ diagram_templates:
|
|||||||
description: Sequence diagram of the main() function
|
description: Sequence diagram of the main() function
|
||||||
type: sequence
|
type: sequence
|
||||||
template: |
|
template: |
|
||||||
main_sequence_diagram:
|
main_sequence_diagram:
|
||||||
type: sequence
|
type: sequence
|
||||||
glob: [ {{ glob }} ]
|
glob: [ {{ glob }} ]
|
||||||
start_from:
|
start_from:
|
||||||
- function: 'main(int,const char**)'
|
- function: 'main(int,const char**)'
|
||||||
diagrams:
|
diagrams:
|
||||||
diagram1:
|
diagram1:
|
||||||
type: class
|
type: class
|
||||||
@@ -28,7 +28,6 @@ diagrams:
|
|||||||
- src/**/*.h
|
- src/**/*.h
|
||||||
using_namespace:
|
using_namespace:
|
||||||
- clanguml
|
- clanguml
|
||||||
generate_method_arguments: full
|
|
||||||
layout:
|
layout:
|
||||||
ABCD:
|
ABCD:
|
||||||
- up: ABCD_SUBCLASS
|
- up: ABCD_SUBCLASS
|
||||||
|
|||||||
21
thirdparty/miroir/LICENSE
vendored
Normal file
21
thirdparty/miroir/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Roman Madyanov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
1152
thirdparty/miroir/miroir.hpp
vendored
Normal file
1152
thirdparty/miroir/miroir.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,9 +12,8 @@ include:
|
|||||||
subclasses:
|
subclasses:
|
||||||
- clanguml::common::model::decorated_element
|
- clanguml::common::model::decorated_element
|
||||||
- clanguml::common::model::source_location
|
- clanguml::common::model::source_location
|
||||||
include:
|
relationships:
|
||||||
relationships:
|
- inheritance
|
||||||
- inheritance
|
|
||||||
exclude:
|
exclude:
|
||||||
relationships:
|
relationships:
|
||||||
- dependency
|
- dependency
|
||||||
|
|||||||
Reference in New Issue
Block a user