Files
yaze/src/cli/service/resources/command_context.h
scawful 31d0337b11 feat(command-abstraction): refactor CLI command architecture and introduce new documentation
- Implemented a Command Abstraction Layer to eliminate ~1300 lines of duplicated code across tool commands, enhancing maintainability and consistency.
- Established a unified structure for argument parsing, ROM loading, and output formatting across all commands.
- Added comprehensive documentation, including a Command Abstraction Guide with migration checklists and testing strategies.
- Introduced better testing capabilities for command components, making them AI-friendly and easier to validate.
- Removed legacy command classes and integrated new command handlers for improved functionality.

Benefits:
- Streamlined command handling and improved code quality.
- Enhanced developer experience with clear documentation and testing strategies.
- Maintained backward compatibility with no breaking changes to existing command interfaces.
2025-10-10 22:24:20 -04:00

211 lines
4.7 KiB
C++

#ifndef YAZE_SRC_CLI_SERVICE_RESOURCES_COMMAND_CONTEXT_H_
#define YAZE_SRC_CLI_SERVICE_RESOURCES_COMMAND_CONTEXT_H_
#include <optional>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "app/rom.h"
namespace yaze {
namespace cli {
namespace resources {
/**
* @class CommandContext
* @brief Encapsulates common context for CLI command execution
*
* Provides unified ROM loading, argument parsing, and common options
* management to reduce duplication across command handlers.
*/
class CommandContext {
public:
/**
* @brief Configuration for command context
*/
struct Config {
std::optional<std::string> rom_path;
bool use_mock_rom = false;
std::string format = "json"; // "json" or "text"
bool verbose = false;
// ROM context can be provided externally (e.g., from Agent class)
Rom* external_rom_context = nullptr;
};
explicit CommandContext(const Config& config);
~CommandContext() = default;
/**
* @brief Initialize the context and load ROM if needed
*/
absl::Status Initialize();
/**
* @brief Get the ROM instance (loads if not already loaded)
*/
absl::StatusOr<Rom*> GetRom();
/**
* @brief Get the output format ("json" or "text")
*/
const std::string& GetFormat() const { return config_.format; }
/**
* @brief Check if verbose mode is enabled
*/
bool IsVerbose() const { return config_.verbose; }
/**
* @brief Ensure resource labels are loaded
*/
absl::Status EnsureLabelsLoaded(Rom* rom);
private:
Config config_;
Rom rom_storage_; // Owned ROM if loaded from file
Rom* active_rom_ = nullptr; // Points to either rom_storage_ or external_rom_context
bool initialized_ = false;
};
/**
* @class ArgumentParser
* @brief Utility for parsing common CLI argument patterns
*/
class ArgumentParser {
public:
explicit ArgumentParser(const std::vector<std::string>& args);
/**
* @brief Parse a named argument (e.g., --format=json or --format json)
*/
std::optional<std::string> GetString(const std::string& name) const;
/**
* @brief Parse an integer argument (supports hex with 0x prefix)
*/
absl::StatusOr<int> GetInt(const std::string& name) const;
/**
* @brief Parse a hex integer argument
*/
absl::StatusOr<int> GetHex(const std::string& name) const;
/**
* @brief Check if a flag is present
*/
bool HasFlag(const std::string& name) const;
/**
* @brief Get all remaining positional arguments
*/
std::vector<std::string> GetPositional() const;
/**
* @brief Validate that required arguments are present
*/
absl::Status RequireArgs(const std::vector<std::string>& required) const;
private:
std::vector<std::string> args_;
std::optional<std::string> FindArgValue(const std::string& name) const;
};
/**
* @class OutputFormatter
* @brief Utility for consistent output formatting across commands
*/
class OutputFormatter {
public:
enum class Format {
kJson,
kText
};
explicit OutputFormatter(Format format) : format_(format) {}
/**
* @brief Create formatter from string ("json" or "text")
*/
static absl::StatusOr<OutputFormatter> FromString(const std::string& format);
/**
* @brief Start a JSON object or text section
*/
void BeginObject(const std::string& title = "");
/**
* @brief End a JSON object or text section
*/
void EndObject();
/**
* @brief Add a key-value pair
*/
void AddField(const std::string& key, const std::string& value);
void AddField(const std::string& key, int value);
void AddField(const std::string& key, uint64_t value);
void AddField(const std::string& key, bool value);
/**
* @brief Add a hex-formatted field
*/
void AddHexField(const std::string& key, uint64_t value, int width = 2);
/**
* @brief Begin an array
*/
void BeginArray(const std::string& key);
/**
* @brief End an array
*/
void EndArray();
/**
* @brief Add an item to current array
*/
void AddArrayItem(const std::string& item);
/**
* @brief Get the formatted output
*/
std::string GetOutput() const;
/**
* @brief Print the formatted output to stdout
*/
void Print() const;
/**
* @brief Check if using JSON format
*/
bool IsJson() const { return format_ == Format::kJson; }
/**
* @brief Check if using text format
*/
bool IsText() const { return format_ == Format::kText; }
private:
Format format_;
std::string buffer_;
int indent_level_ = 0;
bool first_field_ = true;
bool in_array_ = false;
int array_item_count_ = 0;
void AddIndent();
std::string EscapeJson(const std::string& str) const;
};
} // namespace resources
} // namespace cli
} // namespace yaze
#endif // YAZE_SRC_CLI_SERVICE_RESOURCES_COMMAND_CONTEXT_H_