Skip to content

Commit 145508b

Browse files
committed
feat(console): support variadic argument
1 parent 0b86c3d commit 145508b

File tree

6 files changed

+81
-0
lines changed

6 files changed

+81
-0
lines changed

packages/console/src/ConsoleInputBuilder.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ public function build(): array
2626
$argumentDefinitions = $this->command->getArgumentDefinitions();
2727

2828
foreach ($argumentDefinitions as $argumentDefinition) {
29+
if ($argumentDefinition->isVariadic) {
30+
$arguments = $this->argumentBag->findForVariadicArgument($argumentDefinition);
31+
32+
if ($arguments === []) {
33+
$invalidArguments[] = $argumentDefinition;
34+
} else {
35+
$validArguments = [...$validArguments, ...$arguments];
36+
}
37+
38+
continue;
39+
}
40+
2941
$argument = $argumentDefinition->type === 'array'
3042
? $this->argumentBag->findArrayFor($argumentDefinition)
3143
: $this->argumentBag->findFor($argumentDefinition);

packages/console/src/Input/ConsoleArgumentBag.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ public function findArrayFor(ConsoleArgumentDefinition $argumentDefinition): Con
129129
);
130130
}
131131

132+
/**
133+
* @return list<ConsoleInputArgument>
134+
*/
135+
public function findForVariadicArgument(ConsoleArgumentDefinition $argumentDefinition): array
136+
{
137+
$arguments = [];
138+
139+
foreach ($this->arguments as $argument) {
140+
if ($argument->position >= $argumentDefinition->position) {
141+
$arguments[] = new ConsoleInputArgument(
142+
name: $argumentDefinition->name,
143+
position: $argument->position,
144+
value: $this->resolveArgumentValue($argumentDefinition, $argument)->value,
145+
);
146+
}
147+
}
148+
149+
return $arguments;
150+
}
151+
132152
public function add(ConsoleInputArgument $argument): self
133153
{
134154
$this->arguments[] = $argument;

packages/console/src/Input/ConsoleArgumentDefinition.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public function __construct(
1818
public mixed $default,
1919
public bool $hasDefault,
2020
public int $position,
21+
public bool $isVariadic = false,
2122
public ?string $description = null,
2223
public array $aliases = [],
2324
public ?string $help = null,
@@ -36,6 +37,7 @@ public static function fromParameter(ParameterReflector $parameter): ConsoleArgu
3637
default: $default,
3738
hasDefault: $parameter->isDefaultValueAvailable(),
3839
position: $parameter->getPosition(),
40+
isVariadic: $type->isVariadic,
3941
description: $attribute?->description,
4042
aliases: $attribute->aliases ?? [],
4143
help: $attribute?->help,

packages/reflection/src/TypeReflector.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@
5353

5454
private bool $isNullable;
5555

56+
public bool $isVariadic;
57+
5658
public function __construct(
5759
private PHPReflector|PHPReflectionType|string $reflector,
5860
) {
5961
$this->definition = $this->resolveDefinition($this->reflector);
6062
$this->isNullable = $this->resolveIsNullable($this->reflector);
6163
$this->cleanDefinition = str_replace('?', '', $this->definition);
64+
$this->isVariadic = $this->reflector instanceof PHPReflectionParameter && $this->reflector->isVariadic();
6265
}
6366

6467
public function asClass(): ClassReflector

tests/Integration/Console/ConsoleArgumentBagTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Tempest\Console\Exceptions\InvalidEnumArgument;
99
use Tempest\Console\Input\ConsoleArgumentBag;
1010
use Tempest\Console\Input\ConsoleArgumentDefinition;
11+
use Tempest\Console\Input\ConsoleInputArgument;
1112
use Tests\Tempest\Integration\Console\Fixtures\TestStringEnum;
1213
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1314

@@ -190,4 +191,28 @@ public function test_name_mapping(): void
190191
->assertSee('foo')
191192
->assertSee('true');
192193
}
194+
195+
public function test_variadic_argument(): void
196+
{
197+
$argv = [
198+
'tempest',
199+
'command-with-variadic-argument',
200+
'foo',
201+
'bar',
202+
'--input=baz',
203+
];
204+
205+
$bag = new ConsoleArgumentBag($argv);
206+
207+
$definition = new ConsoleArgumentDefinition(
208+
name: 'input2',
209+
type: 'bool',
210+
default: null,
211+
hasDefault: false,
212+
position: 0,
213+
isVariadic: true,
214+
);
215+
216+
$this->assertSame(['foo', 'bar', 'baz'], array_map(static fn (ConsoleInputArgument $argument): string => $argument->value, $bag->findForVariadicArgument($definition)));
217+
}
193218
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Tempest\Integration\Console\Fixtures;
6+
7+
use Tempest\Console\ConsoleCommand;
8+
use Tempest\Console\HasConsole;
9+
10+
final readonly class VariadicCommand
11+
{
12+
use HasConsole;
13+
14+
#[ConsoleCommand('command-with-variadic-argument')]
15+
public function __invoke(string ...$input): void
16+
{
17+
$this->writeln(json_encode($input));
18+
}
19+
}

0 commit comments

Comments
 (0)