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