generated from cerbero90/skeleton
-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/cli' into develop
- Loading branch information
Showing
67 changed files
with
2,762 additions
and
158 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#!/usr/bin/env php | ||
|
||
<?php | ||
|
||
use function Cerbero\Enum\fail; | ||
use function Cerbero\Enum\path; | ||
use function Cerbero\Enum\setPathsByOptions; | ||
use function Cerbero\Enum\splitArgv; | ||
|
||
is_file($autoload = dirname(__DIR__, 1) . '/vendor/autoload.php') && require $autoload; | ||
is_file($autoload = dirname(__DIR__, 4) . '/vendor/autoload.php') && require $autoload; | ||
is_file($autoload = dirname(__DIR__, 4) . '/enums.php') && require $autoload; | ||
|
||
if (is_file($command = path(__DIR__ . '/../cli/' . ($argv[1] ?? null) . '.php'))) { | ||
try { | ||
[$arguments, $options] = splitArgv($argv); | ||
setPathsByOptions($options); | ||
|
||
$outcome = require $command; | ||
} catch (Throwable $e) { | ||
$outcome = fail($e->getMessage()); | ||
} | ||
|
||
exit($outcome ? 0 : 1); | ||
} | ||
|
||
require path(__DIR__ . '/../cli/help'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Cerbero\Enum\Enums; | ||
use Cerbero\Enum\Services\Annotator; | ||
|
||
use function Cerbero\Enum\enumOutcome; | ||
use function Cerbero\Enum\normalizeEnums; | ||
use function Cerbero\Enum\succeed; | ||
|
||
$enums = array_intersect(['--all', '-a'], $options) ? [...Enums::namespaces()] : normalizeEnums($arguments); | ||
|
||
if (empty($enums)) { | ||
return succeed('No enums to annotate.'); | ||
} | ||
|
||
$succeeded = true; | ||
$force = !! array_intersect(['--force', '-f'], $options); | ||
|
||
foreach ($enums as $enum) { | ||
$succeeded = enumOutcome($enum, fn() => (new Annotator($enum))->annotate($force)) && $succeeded; | ||
} | ||
|
||
return $succeeded; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
Annotate enums to ease IDE autocompletion. | ||
|
||
Usage: enum annotate enum1 [enum2 ...] | ||
|
||
Available options: | ||
|
||
-a, --all Whether all enums should be annotated | ||
-f, --force Whether existing annotations should be overwritten | ||
|
||
Examples: | ||
enum annotate App/Enums/MyEnum | ||
enum annotate "App\Enums\MyEnum" | ||
enum annotate App/Enums/MyEnum1 App/Enums/MyEnum2 | ||
enum annotate App/Enums/MyEnum --force | ||
enum annotate --all | ||
enum annotate --all --force | ||
|
||
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― | ||
|
||
Create a new enum. | ||
|
||
Usage: enum make enum case1 case2 | ||
|
||
Available options: | ||
|
||
--backed=VALUE How cases should be backed. VALUE is either: | ||
snake|camel|kebab|upper|lower|int0|int1|bitwise | ||
-f, --force Whether the existing enum should be overwritten | ||
-t, --typescript Whether the enum should be synced in TypeScript | ||
|
||
Examples: | ||
enum make App/Enums/MyEnum Case1 Case2 | ||
enum make "App\Enums\MyEnum" Case1 Case2 | ||
enum make App/Enums/MyEnum Case1=value1 Case2=value2 | ||
enum make App/Enums/MyEnum Case1 Case2 --backed=int1 | ||
enum make App/Enums/MyEnum Case1 Case2 --force | ||
enum make App/Enums/MyEnum Case1 Case2 --backed=bitwise --force | ||
enum make App/Enums/MyEnum Case1 Case2 --typescript | ||
|
||
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― | ||
|
||
Synchronize enums in TypeScript. | ||
|
||
Usage: enum ts enum1 [enum2 ...] | ||
|
||
Available options: | ||
|
||
-a, --all Whether all enums should be synchronized | ||
-f, --force Whether existing enums should be overwritten | ||
|
||
Examples: | ||
enum ts App/Enums/MyEnum | ||
enum ts "App\Enums\MyEnum" | ||
enum ts App/Enums/MyEnum1 App/Enums/MyEnum2 | ||
enum ts App/Enums/MyEnum --force | ||
enum ts --all | ||
enum ts --all --force |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Cerbero\Enum\Enums\Backed; | ||
use Cerbero\Enum\Services\Generator; | ||
|
||
use function Cerbero\Enum\enumOutcome; | ||
use function Cerbero\Enum\fail; | ||
use function Cerbero\Enum\option; | ||
use function Cerbero\Enum\runAnnotate; | ||
use function Cerbero\Enum\runTs; | ||
use function Cerbero\Enum\succeed; | ||
|
||
if (! $enum = strtr($arguments[0] ?? '', '/', '\\')) { | ||
return fail('The name of the enum is missing.'); | ||
} | ||
|
||
$force = !! array_intersect(['--force', '-f'], $options); | ||
|
||
if (enum_exists($enum) && ! $force) { | ||
return succeed("The enum {$enum} already exists."); | ||
} | ||
|
||
if (! $cases = array_slice($arguments, 1)) { | ||
return fail('The cases of the enum are missing.'); | ||
} | ||
|
||
try { | ||
$generator = new Generator($enum, $cases, option('backed', $options)); | ||
} catch (ValueError) { | ||
return fail('The option --backed supports only ' . implode(', ', Backed::names())); | ||
} | ||
|
||
$typeScript = !! array_intersect(['--typescript', '-t'], $options); | ||
|
||
return enumOutcome($enum, function () use ($generator, $enum, $force, $typeScript) { | ||
return $generator->generate($force) | ||
&& runAnnotate($enum, $force) | ||
&& ($typeScript ? runTs($enum, $force) : true); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Cerbero\Enum\Enums; | ||
use Cerbero\Enum\Services\TypeScript; | ||
|
||
use function Cerbero\Enum\enumOutcome; | ||
use function Cerbero\Enum\normalizeEnums; | ||
use function Cerbero\Enum\succeed; | ||
|
||
$enums = array_intersect(['--all', '-a'], $options) ? [...Enums::namespaces()] : normalizeEnums($arguments); | ||
|
||
if (empty($enums)) { | ||
return succeed('No enums to synchronize.'); | ||
} | ||
|
||
$succeeded = true; | ||
$force = !! array_intersect(['--force', '-f'], $options); | ||
|
||
foreach ($enums as $enum) { | ||
$succeeded = enumOutcome($enum, fn() => (new TypeScript($enum))->sync($force)) && $succeeded; | ||
} | ||
|
||
return $succeeded; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Cerbero\Enum; | ||
|
||
use Closure; | ||
use Throwable; | ||
|
||
/** | ||
* Print out the given success message. | ||
*/ | ||
function succeed(string $message): bool | ||
{ | ||
fwrite(STDOUT, "\e[38;2;38;220;38m{$message}\e[0m" . PHP_EOL); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Print out the given error message. | ||
*/ | ||
function fail(string $message): bool | ||
{ | ||
fwrite(STDERR, "\e[38;2;220;38;38m{$message}\e[0m" . PHP_EOL); | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Split the given argv into arguments and options. | ||
* | ||
* @param string[] $argv | ||
* @return list<string[]> | ||
*/ | ||
function splitArgv(array $argv): array | ||
{ | ||
$arguments = $options = []; | ||
|
||
foreach (array_slice($argv, 2) as $item) { | ||
if (str_starts_with($item, '-')) { | ||
$options[] = $item; | ||
} else { | ||
$arguments[] = $item; | ||
} | ||
} | ||
|
||
return [$arguments, $options]; | ||
} | ||
|
||
/** | ||
* Set enum paths from the given options. | ||
* | ||
* @param string[] $options | ||
*/ | ||
function setPathsByOptions(array $options): void | ||
{ | ||
if ($basePath = option('base-path', $options)) { | ||
Enums::setBasePath($basePath); | ||
} | ||
|
||
if ($paths = option('paths', $options)) { | ||
Enums::setPaths(...explode(',', $paths)); | ||
} | ||
} | ||
|
||
/** | ||
* Retrieve the value of the given option. | ||
* | ||
* @param string[] $options | ||
*/ | ||
function option(string $name, array $options): ?string | ||
{ | ||
$prefix = "--{$name}="; | ||
|
||
foreach ($options as $option) { | ||
if (str_starts_with($option, $prefix)) { | ||
$segments = explode('=', $option, limit: 2); | ||
|
||
return $segments[1] === '' ? null : $segments[1]; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Retrieve the normalized namespaces of the given enums. | ||
* | ||
* @param list<string> $enums | ||
* @return list<class-string<\UnitEnum>> | ||
*/ | ||
function normalizeEnums(array $enums): array | ||
{ | ||
$namespaces = array_map(fn(string $enum) => strtr($enum, '/', '\\'), $enums); | ||
|
||
return array_unique(array_filter($namespaces, 'enum_exists')); | ||
} | ||
|
||
/** | ||
* Print out the outcome of the given enum operation. | ||
* | ||
* @param class-string<\UnitEnum> $namespace | ||
* @param Closure(): bool $callback | ||
*/ | ||
function enumOutcome(string $enum, Closure $callback): bool | ||
{ | ||
$error = null; | ||
|
||
try { | ||
$succeeded = $callback(); | ||
} catch (Throwable $e) { | ||
$succeeded = false; | ||
$error = "\e[38;2;220;38;38m{$e?->getMessage()}\e[0m"; | ||
} | ||
|
||
if ($succeeded) { | ||
fwrite(STDOUT, "\e[48;2;163;230;53m\e[38;2;63;98;18m\e[1m DONE \e[0m {$enum}" . PHP_EOL . PHP_EOL); | ||
} else { | ||
fwrite(STDERR, "\e[48;2;248;113;113m\e[38;2;153;27;27m\e[1m FAIL \e[0m {$enum} {$error}" . PHP_EOL . PHP_EOL); | ||
} | ||
|
||
return $succeeded; | ||
} | ||
|
||
/** | ||
* Annotate the given enum within a new process. | ||
* | ||
* @param class-string<\UnitEnum> $enum | ||
*/ | ||
function runAnnotate(string $enum, bool $force = false): bool | ||
{ | ||
// Once an enum is loaded, PHP accesses it from the memory and not from the disk. | ||
// Since we are writing on the disk, the enum in memory might get out of sync. | ||
// To ensure that the annotations reflect the current content of such enum, | ||
// we spin a new process to load in memory the latest state of the enum. | ||
ob_start(); | ||
|
||
$succeeded = cli("annotate \"{$enum}\"" . ($force ? ' --force' : '')); | ||
|
||
ob_end_clean(); | ||
|
||
return $succeeded; | ||
} | ||
|
||
/** | ||
* Run the enum CLI in a new process. | ||
*/ | ||
function cli(string $command, ?int &$status = null): bool | ||
{ | ||
$cmd = vsprintf('"%s" "%s" %s 2>&1', [ | ||
PHP_BINARY, | ||
path(__DIR__ . '/../bin/enum'), | ||
$command, | ||
]); | ||
|
||
return passthru($cmd, $status) === null; | ||
} | ||
|
||
/** | ||
* Synchronize the given enum in TypeScript within a new process. | ||
* | ||
* @param class-string<\UnitEnum> $enum | ||
*/ | ||
function runTs(string $enum, bool $force = false): bool | ||
{ | ||
// Once an enum is loaded, PHP accesses it from the memory and not from the disk. | ||
// Since we are writing on the disk, the enum in memory might get out of sync. | ||
// To make sure that we are synchronizing the current content of such enum, | ||
// we spin a new process to load in memory the latest state of the enum. | ||
ob_start(); | ||
|
||
$succeeded = cli("ts \"{$enum}\"" . ($force ? ' --force' : '')); | ||
|
||
ob_end_clean(); | ||
|
||
return $succeeded; | ||
} |
Oops, something went wrong.