feat: implement core console interfaces and attributes

This commit is contained in:
Funky Waddle 2026-02-21 19:12:38 -06:00
parent 7cb01ed6ab
commit 62af4cea9e
15 changed files with 312 additions and 0 deletions

17
src/Attributes/Arg.php Normal file
View file

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Arg
{
public function __construct(
public string $name,
public string $description = ''
) {
}
}

17
src/Attributes/Cmd.php Normal file
View file

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS)]
class Cmd
{
public function __construct(
public string $name,
public string $description = ''
) {
}
}

View file

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Attributes;
use Phred\ConsoleContracts\CommandInterface;
use ReflectionClass;
/**
* Helper trait to surface PHP 8 attributes (Cmd/Arg/Opt) via CommandInterface methods.
*
* Usage:
* class MyCommand implements CommandInterface { use HasAttributes; ... }
*
* Note: Methods are provided here; consuming class may override any for custom behavior.
*/
trait HasAttributes
{
public function getName(): string
{
$ref = new ReflectionClass($this);
$attr = $ref->getAttributes(Cmd::class)[0] ?? null;
if ($attr === null) {
return '';
}
/** @var Cmd $meta */
$meta = $attr->newInstance();
return $meta->name;
}
public function getDescription(): string
{
$ref = new ReflectionClass($this);
$attr = $ref->getAttributes(Cmd::class)[0] ?? null;
if ($attr === null) {
return '';
}
/** @var Cmd $meta */
$meta = $attr->newInstance();
return $meta->description;
}
/**
* @return array<string,string>
*/
public function getArguments(): array
{
$ref = new ReflectionClass($this);
$attrs = $ref->getAttributes(Arg::class);
$out = [];
foreach ($attrs as $attr) {
/** @var Arg $a */
$a = $attr->newInstance();
$out[$a->name] = $a->description;
}
return $out;
}
/**
* @return array<string,string>
*/
public function getOptions(): array
{
$ref = new ReflectionClass($this);
$attrs = $ref->getAttributes(Opt::class);
$out = [];
foreach ($attrs as $attr) {
/** @var Opt $o */
$o = $attr->newInstance();
$out[$o->name] = $o->description;
}
return $out;
}
}

17
src/Attributes/Opt.php Normal file
View file

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Opt
{
public function __construct(
public string $name,
public string $description = ''
) {
}
}

24
src/CommandInterface.php Normal file
View file

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts;
interface CommandInterface
{
public function getName(): string;
public function getDescription(): string;
/**
* @return array<string,string> Name => Description
*/
public function getArguments(): array;
/**
* @return array<string,string> Name => Description
*/
public function getOptions(): array;
public function execute(InputInterface $input, OutputInterface $output): int;
}

View file

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts;
interface ConsoleExceptionInterface extends \Throwable
{
}

View file

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts;
interface ConsoleMiddlewareInterface
{
public function handle(
CommandInterface $command,
InputInterface $input,
OutputInterface $output,
callable $next
): int;
}

19
src/ExitCode.php Normal file
View file

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts;
final class ExitCode
{
public const OK = 0; // Successful termination
public const FAILURE = 1; // Generic/legacy failure (non-sysexits)
public const USAGE = 64; // Command line usage error
public const DATAERR = 65; // Data format error
public const NOINPUT = 66; // Cannot open input
public const UNAVAILABLE = 69; // Service unavailable
public const SOFTWARE = 70; // Internal software error
public const IOERR = 74; // Input/output error
public const PERM = 77; // Permission denied
public const CONFIG = 78; // Configuration error
}

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Helpers;
interface MarkdownConverterInterface
{
public function convert(string $markdown): string;
public function convertFile(string $path): string;
}

View file

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Helpers;
interface ProgressBarInterface
{
public function start(int $max = 0): void;
public function advance(int $step = 1): void;
public function finish(): void;
}

View file

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts\Helpers;
interface TableInterface
{
/**
* @param array<string> $headers
*/
public function setHeaders(array $headers): void;
/**
* @param array<mixed> $row
*/
public function addRow(array $row): void;
public function render(): void;
}

14
src/InputInterface.php Normal file
View file

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
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;
}

View file

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
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;
/**
* @param array<string|int, mixed> $choices
*/
public function choice(string $question, array $choices, mixed $default = null): mixed;
}

26
src/OutputInterface.php Normal file
View file

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
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;
}

14
src/Verbosity.php Normal file
View file

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Phred\ConsoleContracts;
final class Verbosity
{
public const QUIET = 0;
public const NORMAL = 1;
public const VERBOSE = 2;
public const VERY_VERBOSE = 3;
public const DEBUG = 4;
}