docs: add project milestones, specs, and notes
This commit is contained in:
parent
621fd7e25b
commit
c06e557620
25
MILESTONES.md
Normal file
25
MILESTONES.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# ConsoleContracts Milestones
|
||||||
|
|
||||||
|
This document defines the implementation milestones for the `getphred/console-contracts` package.
|
||||||
|
|
||||||
|
## 1. Project Infrastructure
|
||||||
|
- [x] Initialize repository and `composer.json` with zero runtime dependencies.
|
||||||
|
- [x] Configure PHPUnit and static analysis (PHPStan).
|
||||||
|
- [x] Set up GitHub Actions for continuous integration.
|
||||||
|
|
||||||
|
## 2. Core Interfaces
|
||||||
|
- [x] Implement `CommandInterface` and metadata methods.
|
||||||
|
- [x] Implement `InputInterface` for argument and option access.
|
||||||
|
- [x] Implement `OutputInterface` with verbosity and semantic methods.
|
||||||
|
- [x] Implement `ConsoleMiddlewareInterface` for execution wrapping.
|
||||||
|
- [x] Implement `ConsoleExceptionInterface` for standardized errors.
|
||||||
|
|
||||||
|
## 3. Standardized Constants
|
||||||
|
- [x] Implement `Verbosity` level constants.
|
||||||
|
- [x] Implement `ExitCode` semantic constants (sysexits.h).
|
||||||
|
|
||||||
|
## 4. Helper & DX Contracts
|
||||||
|
- [x] Implement `InteractionInterface` for portable interactivity.
|
||||||
|
- [x] Implement `ProgressBarInterface`, `TableInterface`, and `MarkdownConverterInterface`.
|
||||||
|
- [x] Implement PHP 8 Attributes (`#[Cmd]`, `#[Arg]`, `#[Opt]`).
|
||||||
|
- [x] Implement `HasAttributes` trait for attribute-to-interface bridging.
|
||||||
270
NOTES.md
Normal file
270
NOTES.md
Normal file
|
|
@ -0,0 +1,270 @@
|
||||||
|
# ConsoleContracts: Phred Console Interfaces
|
||||||
|
|
||||||
|
ConsoleContracts provides a minimal, framework-agnostic set of interfaces for building CLI tools. It is designed to be the foundation for the Tasker ecosystem, allowing library authors to define CLI commands without depending on a heavy runner or a specific framework.
|
||||||
|
|
||||||
|
## Core Vision
|
||||||
|
- **Zero Dependencies**: The package must have zero runtime dependencies (other than PHP 8.2+).
|
||||||
|
- **Framework Agnostic**: Interfaces should not assume any specific runner (Tasker, Symfony, etc.).
|
||||||
|
- **Portable Commands**: Commands defined using these interfaces should be runnable in any environment that supports the Phred Console standard.
|
||||||
|
|
||||||
|
## Architectural Decisions
|
||||||
|
|
||||||
|
### 1. Command Interface
|
||||||
|
The `CommandInterface` is the primary contract for any CLI tool. It separates metadata (name, description, arguments, options) from execution logic.
|
||||||
|
|
||||||
|
#### CommandInterface
|
||||||
|
```php
|
||||||
|
namespace GetPhred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface CommandInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The unique name of the command (e.g., 'db:migrate').
|
||||||
|
*/
|
||||||
|
public function getName(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A brief description of what the command does.
|
||||||
|
*/
|
||||||
|
public function getDescription(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of arguments expected by the command.
|
||||||
|
* @return array<string, string> Name => Description
|
||||||
|
*/
|
||||||
|
public function getArguments(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of options available for the command.
|
||||||
|
* @return array<string, string> Name => Description
|
||||||
|
*/
|
||||||
|
public function getOptions(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the command logic.
|
||||||
|
*
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @return int Exit code (see ExitCode constants)
|
||||||
|
*/
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Input & Output Interfaces
|
||||||
|
To ensure portability, commands interact with the environment only through these interfaces.
|
||||||
|
|
||||||
|
#### InputInterface
|
||||||
|
```php
|
||||||
|
namespace GetPhred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface InputInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Retrieve the value of a specific argument.
|
||||||
|
*/
|
||||||
|
public function getArgument(string $name, mixed $default = null): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value of a specific option.
|
||||||
|
*/
|
||||||
|
public function getOption(string $name, mixed $default = null): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a specific option was provided.
|
||||||
|
*/
|
||||||
|
public function hasOption(string $name): bool;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### OutputInterface
|
||||||
|
A lean interface for writing messages to the console.
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace GetPhred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface OutputInterface
|
||||||
|
{
|
||||||
|
public function write(string $message): void;
|
||||||
|
public function writeln(string $message): void;
|
||||||
|
|
||||||
|
// Semantic output methods for common use cases
|
||||||
|
public function success(string $message): void;
|
||||||
|
public function error(string $message): void;
|
||||||
|
public function warning(string $message): void;
|
||||||
|
public function info(string $message): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the verbosity level of the output.
|
||||||
|
*/
|
||||||
|
public function setVerbosity(int $level): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current verbosity level.
|
||||||
|
*/
|
||||||
|
public function getVerbosity(): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Interactivity & Portability
|
||||||
|
Interactive features (asking questions, confirmation prompts) are moved to an optional `InteractionInterface`. This ensures that a command remains runnable in non-interactive environments (CI/CD) by providing a mock or fallback implementation of this interface.
|
||||||
|
|
||||||
|
#### InteractionInterface (Proposed)
|
||||||
|
```php
|
||||||
|
namespace GetPhred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface InteractionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Ask a simple question and return the answer.
|
||||||
|
*/
|
||||||
|
public function ask(string $question, string $default = null): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask for confirmation (yes/no).
|
||||||
|
*/
|
||||||
|
public function confirm(string $question, bool $default = true): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask for a sensitive value (input hidden).
|
||||||
|
*/
|
||||||
|
public function secret(string $question): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a list of choices and return the selected one.
|
||||||
|
*/
|
||||||
|
public function choice(string $question, array $choices, mixed $default = null): mixed;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Console Middleware
|
||||||
|
Middleware should be defined at the **contract level**. This allows for cross-cutting concerns (logging, locking, environment guards) to be implemented in a runner-agnostic way.
|
||||||
|
|
||||||
|
#### ConsoleMiddlewareInterface
|
||||||
|
```php
|
||||||
|
namespace GetPhred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface ConsoleMiddlewareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the command execution lifecycle.
|
||||||
|
*
|
||||||
|
* @param CommandInterface $command
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @param callable $next The next middleware or the command execution itself.
|
||||||
|
* @return int Exit code
|
||||||
|
*/
|
||||||
|
public function handle(
|
||||||
|
CommandInterface $command,
|
||||||
|
InputInterface $input,
|
||||||
|
OutputInterface $output,
|
||||||
|
callable $next
|
||||||
|
): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Constants & Standards
|
||||||
|
|
||||||
|
#### Verbosity Levels
|
||||||
|
Standardized verbosity levels to control output detail.
|
||||||
|
- `Verbosity::QUIET` (0)
|
||||||
|
- `Verbosity::NORMAL` (1)
|
||||||
|
- `Verbosity::VERBOSE` (2)
|
||||||
|
- `Verbosity::VERY_VERBOSE` (3)
|
||||||
|
- `Verbosity::DEBUG` (4)
|
||||||
|
|
||||||
|
#### Exit Codes
|
||||||
|
Strict adherence to `sysexits.h` via `ExitCode` constants (defined in Tasker but standardized here).
|
||||||
|
|
||||||
|
### 6. Exception Handling
|
||||||
|
A base `ConsoleExceptionInterface` should be defined to allow runners to catch and handle CLI-specific errors gracefully (e.g., CommandNotFound, InvalidArgument).
|
||||||
|
|
||||||
|
### 7. Lazy Loading Readiness
|
||||||
|
The `CommandInterface` is specifically designed to support lazy loading. By separating metadata retrieval (`getName()`, `getDescription()`, `getArguments()`, `getOptions()`) from the execution logic (`execute()`), runners can display help information or command lists without instantiating dependencies required only for the command's execution.
|
||||||
|
|
||||||
|
### 8. Metadata via Attributes (Optional)
|
||||||
|
To enhance the Developer Experience (DX), PHP 8 attributes are supported for defining command metadata. While the `CommandInterface` remains the primary contract, attributes provide a declarative way to satisfy the interface methods.
|
||||||
|
|
||||||
|
#### Attributes (Proposed)
|
||||||
|
- `#[Cmd(name: '...', description: '...')]`
|
||||||
|
- `#[Arg(name: '...', description: '...')]`
|
||||||
|
- `#[Opt(name: '...', description: '...')]`
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Phred\ConsoleContracts\Attributes\Cmd;
|
||||||
|
use Phred\ConsoleContracts\Attributes\Arg;
|
||||||
|
use Phred\ConsoleContracts\Attributes\Opt;
|
||||||
|
use Phred\ConsoleContracts\CommandInterface;
|
||||||
|
|
||||||
|
#[Cmd(name: 'db:migrate', description: 'Run database migrations')]
|
||||||
|
#[Arg(name: 'step', description: 'Number of migrations to run')]
|
||||||
|
#[Opt(name: 'force', description: 'Force the operation')]
|
||||||
|
class MigrateCommand implements CommandInterface
|
||||||
|
{
|
||||||
|
use HasAttributes; // A trait that handles the Reflection logic
|
||||||
|
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
// Logic here...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Implementation Strategy
|
||||||
|
The `ConsoleContracts` will provide an optional `HasAttributes` trait (or similar utility) that uses Reflection to read these attributes and return the appropriate values through the `getName()`, `getDescription()`, `getArguments()`, and `getOptions()` methods.
|
||||||
|
|
||||||
|
This approach is:
|
||||||
|
- **Attribute-Aware**: Modern, declarative DX.
|
||||||
|
- **Interface-Driven**: The runner only interacts with the `CommandInterface` methods.
|
||||||
|
- **Optional**: Developers can still override the methods manually without any attributes.
|
||||||
|
|
||||||
|
### 9. Output Formatting (Minimal Markup)
|
||||||
|
The `OutputInterface` should support a minimal, standardized set of markup tags to ensure consistent styling across different runners.
|
||||||
|
|
||||||
|
#### Core Tag Set (Fixed)
|
||||||
|
To ensure consistent behavior across all runners and bridges, the set of supported markup tags is **fixed**. Developers should NOT attempt to use custom tags, as bridges are only required to implement this standardized core set:
|
||||||
|
- `<success>...</success>`: Green text.
|
||||||
|
- `<info>...</info>`: Blue text.
|
||||||
|
- `<error>...</error>`: White text on a red background.
|
||||||
|
- `<warning>...</warning>`: Black text on a yellow background.
|
||||||
|
- `<comment>...</comment>`: Yellow text.
|
||||||
|
- `<b>...</b>`: Bold text.
|
||||||
|
- `<i>...</i>`: Italicized text.
|
||||||
|
- `<u>...</u>`: Underlined text.
|
||||||
|
|
||||||
|
#### Bridge Responsibility
|
||||||
|
Each bridge (e.g., `SymfonyBridge`, `LaminasBridge`) is responsible for translating this fixed set of Phred tags into the native formatting syntax of the underlying CLI tool.
|
||||||
|
- **SymfonyBridge**: Maps `<info>` to Symfony's `<info>` tag in its `Formatter`.
|
||||||
|
- **PhredBridge (Native)**: Translates tags into ANSI escape sequences (e.g., `\e[32m` for green).
|
||||||
|
|
||||||
|
This ensures that a command's output remains visually consistent whether it's running via Tasker or inside a Symfony application.
|
||||||
|
|
||||||
|
### 10. Helper Contracts (Optional)
|
||||||
|
Complex CLI components like **Progress Bars** and **Tables** are defined as separate, optional interfaces. This keeps the core `OutputInterface` lean and allows commands to only depend on the specific features they need.
|
||||||
|
|
||||||
|
#### ProgressBarInterface (Proposed)
|
||||||
|
Commands can inject this interface to display progress for long-running tasks.
|
||||||
|
- `start(int $max)`
|
||||||
|
- `advance(int $step = 1)`
|
||||||
|
- `finish()`
|
||||||
|
|
||||||
|
#### TableInterface (Proposed)
|
||||||
|
Commands can inject this interface to render tabular data.
|
||||||
|
- `setHeaders(array $headers)`
|
||||||
|
- `addRow(array $row)`
|
||||||
|
- `render()`
|
||||||
|
|
||||||
|
#### MarkdownConverterInterface (Proposed)
|
||||||
|
Commands can inject this interface to convert a string or a file containing Markdown into a string formatted with Phred's standardized markup tags.
|
||||||
|
- `convert(string $markdown): string`
|
||||||
|
- `convertFile(string $path): string`
|
||||||
|
|
||||||
|
### Implementation Strategy for Helpers
|
||||||
|
Like the `InteractionInterface`, these helpers are satisfied by the runner or bridge.
|
||||||
|
- **SymfonyBridge**: Maps these to Symfony's `ProgressBar` and `Table` helper classes. For Markdown, it could use an existing library or Symfony's native Markdown support.
|
||||||
|
- **Native (Tasker)**: Provides basic ANSI-based implementations and a lightweight regex-based Markdown parser.
|
||||||
|
|
||||||
|
## Brainstorming / Open Questions
|
||||||
|
(All current open questions have been resolved and moved to Architectural Decisions.)
|
||||||
173
SPECS.md
Normal file
173
SPECS.md
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
# ConsoleContracts Specification
|
||||||
|
|
||||||
|
This document defines the technical specifications for the `getphred/console-contracts` package. These interfaces and constants form the foundational standard for the Phred CLI ecosystem.
|
||||||
|
|
||||||
|
## 1. Namespace & Constants
|
||||||
|
|
||||||
|
**Namespace**: `Phred\ConsoleContracts`
|
||||||
|
|
||||||
|
### 1.1 Verbosity Levels
|
||||||
|
The `Verbosity` class (or final class with constants) defines the following levels:
|
||||||
|
- `Verbosity::QUIET = 0`
|
||||||
|
- `Verbosity::NORMAL = 1`
|
||||||
|
- `Verbosity::VERBOSE = 2`
|
||||||
|
- `Verbosity::VERY_VERBOSE = 3`
|
||||||
|
- `Verbosity::DEBUG = 4`
|
||||||
|
|
||||||
|
### 1.2 Exit Codes
|
||||||
|
The `ExitCode` class (or final class with constants) follows the `sysexits.h` standard:
|
||||||
|
- `ExitCode::OK = 0`
|
||||||
|
- `ExitCode::USAGE = 64`
|
||||||
|
- `ExitCode::DATAERR = 65`
|
||||||
|
- `ExitCode::NOINPUT = 66`
|
||||||
|
- `ExitCode::UNAVAILABLE = 69`
|
||||||
|
- `ExitCode::SOFTWARE = 70`
|
||||||
|
- `ExitCode::IOERR = 74`
|
||||||
|
- `ExitCode::PERM = 77`
|
||||||
|
- `ExitCode::CONFIG = 78`
|
||||||
|
|
||||||
|
## 2. Core Interfaces
|
||||||
|
|
||||||
|
### 2.1 CommandInterface
|
||||||
|
Defines the metadata and execution logic for a CLI command.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface CommandInterface
|
||||||
|
{
|
||||||
|
public function getName(): string;
|
||||||
|
public function getDescription(): string;
|
||||||
|
public function getArguments(): array;
|
||||||
|
public function getOptions(): array;
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 InputInterface
|
||||||
|
Provides access to command-line arguments and options.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface InputInterface
|
||||||
|
{
|
||||||
|
public function getArgument(string $name, mixed $default = null): mixed;
|
||||||
|
public function getOption(string $name, mixed $default = null): mixed;
|
||||||
|
public function hasOption(string $name): bool;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 OutputInterface
|
||||||
|
Standard interface for console output with semantic methods and verbosity control.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface OutputInterface
|
||||||
|
{
|
||||||
|
public function write(string $message): void;
|
||||||
|
public function writeln(string $message): void;
|
||||||
|
public function success(string $message): void;
|
||||||
|
public function info(string $message): void;
|
||||||
|
public function error(string $message): void;
|
||||||
|
public function warning(string $message): void;
|
||||||
|
public function comment(string $message): void;
|
||||||
|
public function setVerbosity(int $level): void;
|
||||||
|
public function getVerbosity(): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 InteractionInterface
|
||||||
|
Optional interface for interactive features.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface InteractionInterface
|
||||||
|
{
|
||||||
|
public function ask(string $question, ?string $default = null): string;
|
||||||
|
public function confirm(string $question, bool $default = true): bool;
|
||||||
|
public function secret(string $question): string;
|
||||||
|
public function choice(string $question, array $choices, mixed $default = null): mixed;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5 ConsoleMiddlewareInterface
|
||||||
|
Standardized interface for wrapping command execution.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface ConsoleMiddlewareInterface
|
||||||
|
{
|
||||||
|
public function handle(
|
||||||
|
CommandInterface $command,
|
||||||
|
InputInterface $input,
|
||||||
|
OutputInterface $output,
|
||||||
|
callable $next
|
||||||
|
): int;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.6 ConsoleExceptionInterface
|
||||||
|
Base interface for all console-related exceptions.
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts;
|
||||||
|
|
||||||
|
interface ConsoleExceptionInterface extends \Throwable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Helper Contracts (Optional)
|
||||||
|
|
||||||
|
### 3.1 ProgressBarInterface
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts\Helpers;
|
||||||
|
|
||||||
|
interface ProgressBarInterface
|
||||||
|
{
|
||||||
|
public function start(int $max = 0): void;
|
||||||
|
public function advance(int $step = 1): void;
|
||||||
|
public function finish(): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 TableInterface
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts\Helpers;
|
||||||
|
|
||||||
|
interface TableInterface
|
||||||
|
{
|
||||||
|
public function setHeaders(array $headers): void;
|
||||||
|
public function addRow(array $row): void;
|
||||||
|
public function render(): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 MarkdownConverterInterface
|
||||||
|
```php
|
||||||
|
namespace Phred\ConsoleContracts\Helpers;
|
||||||
|
|
||||||
|
interface MarkdownConverterInterface
|
||||||
|
{
|
||||||
|
public function convert(string $markdown): string;
|
||||||
|
public function convertFile(string $path): string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Attributes (Optional DX)
|
||||||
|
|
||||||
|
Defined in `Phred\ConsoleContracts\Attributes`:
|
||||||
|
|
||||||
|
- `Cmd`: `#[Cmd(string $name, string $description = '')]`
|
||||||
|
- `Arg`: `#[Arg(string $name, string $description = '')]`
|
||||||
|
- `Opt`: `#[Opt(string $name, string $description = '')]`
|
||||||
|
|
||||||
|
## 5. Output Formatting Standard
|
||||||
|
|
||||||
|
Bridges must translate the following tags:
|
||||||
|
- `<success>`: Green
|
||||||
|
- `<info>`: Blue
|
||||||
|
- `<error>`: White on Red
|
||||||
|
- `<warning>`: Black on Yellow
|
||||||
|
- `<comment>`: Yellow
|
||||||
|
- `<b>`: Bold
|
||||||
|
- `<i>`: Italic
|
||||||
|
- `<u>`: Underline
|
||||||
Loading…
Reference in a new issue