Skip to content

Commit df8d27b

Browse files
committed
fix: next is option value check error
1 parent 6822123 commit df8d27b

7 files changed

+108
-43
lines changed

src/Concern/RuleParserTrait.php

-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ public function addOptsByRules(array $rules): void
124124
public function addOptByRule(string $name, array|string $rule): static
125125
{
126126
$this->optRules[$name] = $rule;
127-
128127
return $this;
129128
}
130129

src/FlagUtil.php

+10-16
Original file line numberDiff line numberDiff line change
@@ -122,27 +122,21 @@ public static function isOptionValue(mixed $val): bool
122122
return false;
123123
}
124124

125-
// if is: '', 0
126-
if (!$val) {
125+
// if is: '', 0 || is not option name
126+
if (!$val || $val[0] !== '-') {
127127
return true;
128128
}
129129

130-
// is not option name.
131-
if ($val[0] !== '-') {
132-
// ensure is option value.
133-
if (!str_contains($val, '=')) {
134-
return true;
135-
}
136-
137-
// is string value, but contains '='
138-
[$name,] = explode('=', $val, 2);
139-
140-
// named argument OR invalid: 'some = string'
141-
return false === self::isValidName($name);
130+
// ensure is option value.
131+
if (!str_contains($val, '=')) {
132+
return true;
142133
}
143134

144-
// is option name.
145-
return false;
135+
// is string value, but contains '='
136+
[$name,] = explode('=', $val, 2);
137+
138+
// named argument OR invalid: 'some = string'
139+
return false === self::isValidName($name);
146140
}
147141

148142
/**

src/Flags.php

+18-11
Original file line numberDiff line numberDiff line change
@@ -362,39 +362,46 @@ public function bindingArguments(): self
362362
}
363363

364364
// parse arguments
365-
$args = $this->parseRawArgs($this->rawArgs);
365+
$args = $this->parseRawArgs($remains = $this->rawArgs);
366366

367367
// collect argument values
368368
foreach ($this->arguments as $index => $arg) {
369-
if (!isset($args[$index])) {
369+
$name = $arg->getName();
370+
371+
if (isset($args[$name])) {
372+
$value = $args[$name];
373+
unset($args[$name]);
374+
} elseif (isset($args[$index])) {
375+
$value = $args[$index];
376+
unset($args[$index]);
377+
} else {
370378
if ($arg->isRequired()) {
371379
$mark = $arg->getNameMark();
372380
throw new FlagException("flag argument $mark is required");
373381
}
374382
continue;
375383
}
376384

377-
// collect all remain args
385+
// array: collect all remain args
378386
if ($arg->isArray()) {
379387
foreach ($args as $value) {
380388
$arg->setValue($value);
381389
}
382-
$args = [];
390+
$remains = $args = [];
383391
} else {
384-
$arg->setValue($args[$index]);
385-
unset($args[$index]);
392+
array_shift($remains);
393+
$arg->setValue($value);
386394
}
387395
}
388396

389-
if ($args) {
390-
$args = array_values($args);
391-
397+
if ($remains) {
398+
$remains = array_values($remains);
392399
if ($this->strictMatchArgs) {
393-
throw new FlagException(sprintf('unknown arguments (error: "%s").', implode(' ', $args)));
400+
throw new FlagException(sprintf('unknown arguments (error: "%s").', implode(' ', $remains)));
394401
}
395402
}
396403

397-
$this->remainArgs = $args;
404+
$this->remainArgs = $remains;
398405
return $this;
399406
}
400407

src/FlagsParser.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -498,13 +498,23 @@ public function popFirstRawArg(): string
498498
/**
499499
* @return array
500500
*/
501-
public function getInfo(): array
501+
public function getInfo(bool $more = false): array
502502
{
503-
return [
503+
$info = [
504504
'flags' => $this->flags,
505505
'rawArgs' => $this->rawArgs,
506506
'remainArgs' => $this->remainArgs,
507+
'opts' => $this->getOpts(),
508+
'args' => $this->getArgs(),
507509
];
510+
511+
if ($more) {
512+
$info['optRules'] = $this->getOptRules();
513+
$info['argRules'] = $this->getArgRules();
514+
$info['aliases'] = $this->getAliases();
515+
}
516+
517+
return $info;
508518
}
509519

510520
/**

src/SFlags.php

+16-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Toolkit\PFlag\Exception\FlagParseException;
1616
use Toolkit\Stdlib\OS;
1717
use Toolkit\Stdlib\Str;
18+
use function array_shift;
1819
use function array_values;
1920
use function count;
2021
use function current;
@@ -540,7 +541,7 @@ protected function setRealOptValue(string $name, mixed $value, array $define): v
540541
public function bindingArguments(): void
541542
{
542543
// parse arguments
543-
$args = $this->parseRawArgs($this->rawArgs);
544+
$args = $this->parseRawArgs($remains = $this->rawArgs);
544545

545546
// check and collect argument values
546547
foreach ($this->argDefines as $index => $define) {
@@ -550,36 +551,39 @@ public function bindingArguments(): void
550551
$required = $define['required'];
551552
$isArray = FlagType::isArray($define['type']);
552553

553-
if (!isset($args[$index])) {
554+
if (isset($args[$name])) {
555+
$value = $args[$name];
556+
unset($args[$name]);
557+
} elseif (isset($args[$index])) {
558+
$value = $args[$index];
559+
unset($args[$index]);
560+
} else {
554561
if ($required) {
555562
throw new FlagException("flag argument $mark is required");
556563
}
557564
continue;
558565
}
559566

560-
// collect value
567+
// array: collect all remain args
561568
if ($isArray) {
562-
// remain args
563569
foreach ($args as $arrValue) {
564570
$this->collectArgValue($arrValue, $index, true, $define);
565571
}
566-
$args = [];
572+
$remains = $args = [];
567573
} else {
568-
$value = $args[$index];
574+
array_shift($remains);
569575
$this->collectArgValue($value, $index, false, $define);
570-
unset($args[$index]);
571576
}
572577
}
573578

574-
if ($args) {
575-
$args = array_values($args);
576-
579+
if ($remains) {
580+
$remains = array_values($remains);
577581
if ($this->strictMatchArgs) {
578-
throw new FlagException(sprintf('unknown arguments (error: "%s").', implode(', ', $args)));
582+
throw new FlagException(sprintf('unknown arguments (error: "%s").', implode(', ', $remains)));
579583
}
580584
}
581585

582-
$this->remainArgs = $args;
586+
$this->remainArgs = $remains;
583587
}
584588

585589
/**

test/BaseFlagsTestCase.php

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Toolkit\PFlag\Flags;
1717
use Toolkit\PFlag\FlagsParser;
1818
use Toolkit\PFlag\SFlags;
19+
use Toolkit\Stdlib\Php;
20+
use function in_array;
1921

2022
/**
2123
* Class BaseTestCase
@@ -41,6 +43,14 @@ protected function runAndGetException(callable $cb, ...$args): Throwable
4143
return new RuntimeException('NO ERROR');
4244
}
4345

46+
public function assertArrayHasValue($needle, array $arr, string $message = ''): void
47+
{
48+
$has = in_array($needle, $arr, true);
49+
$msg = 'The array ' . Php::toString($arr) . ' should contains: ' . $needle;
50+
51+
$this->assertTrue($has, $message ?: $msg);
52+
}
53+
4454
/**
4555
* @param Closure $testFunc
4656
*/

test/FlagsParserTest.php

+42-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use InvalidArgumentException;
1313
use Toolkit\PFlag\Exception\FlagException;
1414
use Toolkit\PFlag\FlagsParser;
15+
use Toolkit\PFlag\FlagType;
1516
use function get_class;
1617

1718
/**
@@ -138,11 +139,21 @@ private function doCheckStopOnTwoHl(FlagsParser $fs): void
138139
$ok = $fs->parse(['--name', 'inhere', 'val0']);
139140
$this->assertTrue($ok);
140141
$this->assertSame('val0', $fs->getArg('arg0'));
141-
142142
$fs->resetResults();
143+
143144
$ok = $fs->parse(['--name', 'inhere', '--', '--val0']);
144145
$this->assertTrue($ok);
145146
$this->assertSame('--val0', $fs->getArg('arg0'));
147+
$fs->resetResults();
148+
149+
$ok = $fs->parse(["--", "-e", "dev", "-v", "port=3455"]);
150+
$this->assertTrue($ok);
151+
$this->assertNotEmpty($fs->getArgs());
152+
$this->assertSame('-e', $fs->getArg('arg0'));
153+
154+
$otherArgs = $fs->getRemainArgs();
155+
$this->assertArrayHasValue('port=3455', $otherArgs);
156+
$fs->resetResults();
146157
}
147158

148159
public function testStopOnFirstArg(): void
@@ -404,4 +415,34 @@ private function doCheckSetOptAndSetArg($fs): void
404415
$this->assertSame(FlagException::class, get_class($e));
405416
$this->assertSame("flag argument 'not-exist-arg' is undefined", $e->getMessage());
406417
}
418+
419+
public function testParse_opt_isKV(): void
420+
{
421+
foreach ($this->createParsers() as $fs) {
422+
$this->doTestParse_opt_isKV($fs);
423+
}
424+
}
425+
426+
public function doTestParse_opt_isKV(FlagsParser $fs): void
427+
{
428+
$fs->addOptsByRules([
429+
'env, e' => [
430+
'type' => FlagType::STRING,
431+
'required' => true,
432+
],
433+
'vars,var,v' => [
434+
'type' => FlagType::ARRAY,
435+
'desc' => 'can append some extra vars, format: KEY=VALUE',
436+
],
437+
]);
438+
439+
$flags = ['-e', 'dev', '--var', 'key0=val0', '-v', 'port=3445'];
440+
$fs->parse($flags);
441+
442+
$this->assertNotEmpty($fs->getOpts());
443+
$this->assertNotEmpty($fs->getInfo(true));
444+
$this->assertEquals('vars', $fs->resolveAlias('v'));
445+
$this->assertEquals('vars', $fs->resolveAlias('var'));
446+
$this->assertEquals(['key0=val0', 'port=3445'], $fs->getOpt('vars'));
447+
}
407448
}

0 commit comments

Comments
 (0)