From f7feece4cd830f7e348a50f2c9511661d9e31cd6 Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Mon, 17 Nov 2025 11:02:37 +0100 Subject: [PATCH 1/3] MINIFICPP-2712 Generate modular docs --- minifi_main/AgentDocs.cpp | 213 ++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 68 deletions(-) diff --git a/minifi_main/AgentDocs.cpp b/minifi_main/AgentDocs.cpp index ff37268c94..cea80ccd5a 100644 --- a/minifi_main/AgentDocs.cpp +++ b/minifi_main/AgentDocs.cpp @@ -34,7 +34,9 @@ #include "range/v3/range/conversion.hpp" #include "range/v3/view/join.hpp" #include "range/v3/view/transform.hpp" +#include "utils/RegexUtils.h" #include "utils/StringUtils.h" +#include "utils/file/FileUtils.h" namespace { @@ -42,33 +44,24 @@ namespace minifi = org::apache::nifi::minifi; std::string formatName(std::string_view name_view, bool is_required) { std::string name{name_view}; - if (is_required) { - return "**" + name + "**"; - } else { - return name; - } + if (is_required) { return "**" + name + "**"; } + return name; } std::string formatAllowedValues(const minifi::core::Property& property) { - if (property.getValidator().getEquivalentNifiStandardValidatorName() == minifi::core::StandardPropertyValidators::BOOLEAN_VALIDATOR.getEquivalentNifiStandardValidatorName()) { + if (property.getValidator().getEquivalentNifiStandardValidatorName() == + minifi::core::StandardPropertyValidators::BOOLEAN_VALIDATOR.getEquivalentNifiStandardValidatorName()) { return "true
false"; - } else { - const auto allowed_values = property.getAllowedValues(); - return allowed_values - | ranges::views::join(std::string_view{"
"}) - | ranges::to(); } + const auto allowed_values = property.getAllowedValues(); + return allowed_values | ranges::views::join(std::string_view{"
"}) | ranges::to(); } std::string formatDescription(std::string_view description_view, bool is_sensitive = false, bool supports_expression_language = false) { std::string description{description_view}; minifi::utils::string::replaceAll(description, "\n", "
"); - if (is_sensitive) { - description += "
**Sensitive Property: true**"; - } - if (supports_expression_language) { - description += "
**Supports Expression Language: true**"; - } + if (is_sensitive) { description += "
**Sensitive Property: true**"; } + if (supports_expression_language) { description += "
**Supports Expression Language: true**"; } return description; } @@ -103,7 +96,7 @@ void writeHeader(std::ostream& docs, const std::vector& key_value) { return minifi::utils::string::toLower(key_value.first); -}; +} -} // namespace +void writeProcessor(std::ostream& os, const std::string_view name, const minifi::ClassDescription& documentation) { + writeName(os, name); + writeDescription(os, documentation); + writeProperties(os, documentation); + writeDynamicProperties(os, documentation); + writeRelationships(os, documentation); + writeOutputAttributes(os, documentation); +} -namespace org::apache::nifi::minifi::docs { +void writeControllerService(std::ostream& os, const std::string_view name, const minifi::ClassDescription& documentation) { + writeName(os, name); + writeDescription(os, documentation); + writeProperties(os, documentation); +} -void AgentDocs::generate(const std::filesystem::path& docs_dir) { - std::vector> controller_services; - std::vector> processors; - std::vector> parameter_providers; +void writeParameterProvider(std::ostream& os, const std::string_view name, const minifi::ClassDescription& documentation) { + writeName(os, name); + writeDescription(os, documentation); + writeProperties(os, documentation); +} - for (const auto& [bundle_id, components]: ClassDescriptionRegistry::getClassDescriptions()) { - for (const auto &controller_service_description : components.controller_services) { +class MonolithDocumentation { + public: + explicit MonolithDocumentation() { + for (const auto& [bundle_id, component]: minifi::ClassDescriptionRegistry::getClassDescriptions()) { + addComponents(component); + } + sort(); + } + + void write(const std::filesystem::path& docs_dir) { + std::ofstream controllers_md(docs_dir / "CONTROLLERS.md"); + writeControllers(controllers_md); + + std::ofstream processors_md(docs_dir / "PROCESSORS.md"); + writeProcessors(processors_md); + + std::ofstream parameter_providers_md(docs_dir / "PARAMETER_PROVIDERS.md"); + writeParameterProviders(parameter_providers_md); + } + + private: + void addComponents(const minifi::Components& components) { + for (const auto& controller_service_description: components.controller_services) { controller_services.emplace_back(extractClassName(controller_service_description.full_name_), controller_service_description); } - for (const auto &processor_description : components.processors) { + for (const auto& processor_description: components.processors) { processors.emplace_back(extractClassName(processor_description.full_name_), processor_description); } - for (const auto& parameter_provider_description : components.parameter_providers) { + for (const auto& parameter_provider_description: components.parameter_providers) { parameter_providers.emplace_back(extractClassName(parameter_provider_description.full_name_), parameter_provider_description); } } - std::ranges::sort(controller_services, std::less(), lowercaseFirst); - std::ranges::sort(processors, std::less(), lowercaseFirst); - std::ranges::sort(parameter_providers, std::less(), lowercaseFirst); - std::ofstream controllers_md(docs_dir / "CONTROLLERS.md"); - writeHeader(controllers_md, controller_services); - for (const auto& [name, documentation] : controller_services) { - writeName(controllers_md, name); - writeDescription(controllers_md, documentation); - writeProperties(controllers_md, documentation); + void sort() { + std::ranges::sort(controller_services, std::less(), lowercaseFirst); + std::ranges::sort(processors, std::less(), lowercaseFirst); + std::ranges::sort(parameter_providers, std::less(), lowercaseFirst); } - std::ofstream processors_md(docs_dir / "PROCESSORS.md"); - writeHeader(processors_md, processors); - for (const auto& [name, documentation] : processors) { - writeName(processors_md, name); - writeDescription(processors_md, documentation); - writeProperties(processors_md, documentation); - writeDynamicProperties(processors_md, documentation); - writeRelationships(processors_md, documentation); - writeOutputAttributes(processors_md, documentation); + void writeControllers(std::ostream& os) { + writeHeader(os, controller_services); + for (const auto& [name, documentation]: controller_services) { + writeControllerService(os, name, documentation); + } } - std::ofstream parameter_providers_md(docs_dir / "PARAMETER_PROVIDERS.md"); - writeHeader(parameter_providers_md, parameter_providers); - for (const auto& [name, documentation] : parameter_providers) { - writeName(parameter_providers_md, name); - writeDescription(parameter_providers_md, documentation); - writeProperties(parameter_providers_md, documentation); + void writeProcessors(std::ostream& os) { + writeHeader(os, processors); + for (const auto& [name, documentation]: processors) { + writeProcessor(os, name, documentation); + } } + + void writeParameterProviders(std::ostream& os) { + writeHeader(os, parameter_providers); + for (const auto& [name, documentation]: parameter_providers) { + writeParameterProvider(os, name, documentation); + } + } + + std::vector> controller_services; + std::vector> processors; + std::vector> parameter_providers; +}; + +class ModularDocumentation { + public: + static void write(const std::filesystem::path& docs_dir) { + for (const auto& [bundle_id, component]: minifi::ClassDescriptionRegistry::getClassDescriptions()) { + writeModule(docs_dir, bundle_id.name, component); + } + } + + private: + static void writeComponentParts(std::ostream& os, const std::vector& class_descriptions, const std::string_view h3) { + if (!class_descriptions.empty()) { + os << fmt::format("### {}\n\n", h3); + for (const auto& class_description: class_descriptions) { + const auto name = extractClassName(class_description.full_name_); + os << "- [" << name << "](#" << name << ")\n"; + } + } + } + + static void writeToC(std::ostream& os, const minifi::Components& components) { + os << "\n\n## Table of Contents\n\n"; + writeComponentParts(os, components.processors, "Processors"); + writeComponentParts(os, components.controller_services, "Controller Services"); + writeComponentParts(os, components.parameter_providers, "Parameter Providers"); + } + + static void writeModule(const std::filesystem::path& docs_dir, const std::string_view module_name, const minifi::Components& components) { + minifi::utils::file::create_dir(docs_dir / "modules"); + std::ofstream os(docs_dir / "modules" / (std::string(module_name) + ".md")); + os << APACHE_LICENSE; + + writeToC(os, components); + + for (const auto& processor: components.processors) { + writeProcessor(os, extractClassName(processor.full_name_), processor); + } + + for (const auto& controller_service: components.controller_services) { + writeControllerService(os, extractClassName(controller_service.full_name_), controller_service); + } + + for (const auto& parameter_provider_description: components.parameter_providers) { + writeParameterProvider(os, extractClassName(parameter_provider_description.full_name_), parameter_provider_description); + } + } +}; +} // namespace + +namespace org::apache::nifi::minifi::docs { + +void AgentDocs::generate(const std::filesystem::path& docs_dir) { + MonolithDocumentation monolith_docs; + monolith_docs.write(docs_dir); + + ModularDocumentation::write(docs_dir); } } // namespace org::apache::nifi::minifi::docs From 996b131531a43fd5e55954cdfb35048f7bd9dde4 Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Fri, 6 Feb 2026 13:55:52 +0100 Subject: [PATCH 2/3] review changes --- minifi_main/AgentDocs.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/minifi_main/AgentDocs.cpp b/minifi_main/AgentDocs.cpp index cea80ccd5a..3ce243ca8a 100644 --- a/minifi_main/AgentDocs.cpp +++ b/minifi_main/AgentDocs.cpp @@ -34,7 +34,6 @@ #include "range/v3/range/conversion.hpp" #include "range/v3/view/join.hpp" #include "range/v3/view/transform.hpp" -#include "utils/RegexUtils.h" #include "utils/StringUtils.h" #include "utils/file/FileUtils.h" @@ -197,12 +196,12 @@ class MonolithDocumentation { void write(const std::filesystem::path& docs_dir) { std::ofstream controllers_md(docs_dir / "CONTROLLERS.md"); - writeControllers(controllers_md); - std::ofstream processors_md(docs_dir / "PROCESSORS.md"); - writeProcessors(processors_md); - std::ofstream parameter_providers_md(docs_dir / "PARAMETER_PROVIDERS.md"); + gsl_Assert(controllers_md && processors_md && parameter_providers_md); + + writeControllers(controllers_md); + writeProcessors(processors_md); writeParameterProviders(parameter_providers_md); } @@ -278,8 +277,10 @@ class ModularDocumentation { } static void writeModule(const std::filesystem::path& docs_dir, const std::string_view module_name, const minifi::Components& components) { - minifi::utils::file::create_dir(docs_dir / "modules"); + const auto dir_creation_result = minifi::utils::file::create_dir(docs_dir / "modules"); + gsl_Assert(dir_creation_result == 0); std::ofstream os(docs_dir / "modules" / (std::string(module_name) + ".md")); + gsl_Assert(os); os << APACHE_LICENSE; writeToC(os, components); From 3505ccf871a2020992147c1bff9ddb678aafc562 Mon Sep 17 00:00:00 2001 From: Martin Zink Date: Mon, 16 Feb 2026 16:40:03 +0100 Subject: [PATCH 3/3] sort modular components and skip empty modules --- minifi_main/AgentDocs.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/minifi_main/AgentDocs.cpp b/minifi_main/AgentDocs.cpp index 3ce243ca8a..03951a2f8e 100644 --- a/minifi_main/AgentDocs.cpp +++ b/minifi_main/AgentDocs.cpp @@ -253,12 +253,22 @@ class MonolithDocumentation { class ModularDocumentation { public: static void write(const std::filesystem::path& docs_dir) { - for (const auto& [bundle_id, component]: minifi::ClassDescriptionRegistry::getClassDescriptions()) { + for (auto& [bundle_id, component]: minifi::ClassDescriptionRegistry::getMutableClassDescriptions()) { + if (component.empty()) { + continue; + } + sortComponents(component); writeModule(docs_dir, bundle_id.name, component); } } private: + static void sortComponents(minifi::Components& components) { + std::ranges::sort(components.processors, {}, &minifi::ClassDescription::short_name_); + std::ranges::sort(components.controller_services, {}, &minifi::ClassDescription::short_name_); + std::ranges::sort(components.parameter_providers, {}, &minifi::ClassDescription::short_name_); + } + static void writeComponentParts(std::ostream& os, const std::vector& class_descriptions, const std::string_view h3) { if (!class_descriptions.empty()) { os << fmt::format("### {}\n\n", h3);