This commit is contained in:
2022-10-23 01:39:27 +02:00
parent 8c17aab483
commit 1929b84685
4130 changed files with 479334 additions and 0 deletions

557
vendor/corneltek/getoptionkit/src/Option.php vendored Executable file
View File

@@ -0,0 +1,557 @@
<?php
/*
* This file is part of the GetOptionKit package.
*
* (c) Yo-An Lin <cornelius.howl@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*/
namespace GetOptionKit;
use Exception;
use LogicException;
use InvalidArgumentException;
use GetOptionKit\Exception\InvalidOptionValueException;
class Option
{
public $short;
public $long;
/**
* @var string the description of this option
*/
public $desc;
/**
* @var string The option key
*/
public $key; /* key to store values */
public $value;
public $type;
public $valueName; /* name for the value place holder, for printing */
public $isa;
public $isaOption;
public $validValues;
public $suggestions;
public $defaultValue;
public $incremental = false;
/**
* @var Closure The filter closure of the option value.
*/
public $filter;
public $validator;
public $multiple = false;
public $optional = false;
public $required = false;
public $flag = false;
/**
* @var callable trigger callback after value is set.
*/
protected $trigger;
public function __construct($spec)
{
$this->initFromSpecString($spec);
}
/**
* Build spec attributes from spec string.
*
* @param string $specString
*/
protected function initFromSpecString($specString)
{
$pattern = '/
(
(?:[a-zA-Z0-9-]+)
(?:
\|
(?:[a-zA-Z0-9-]+)
)?
)
# option attribute operators
([:+?])?
# value types
(?:=(boolean|string|number|date|file|dir|url|email|ip|ipv6|ipv4))?
/x';
$ret = preg_match($pattern, $specString, $regs);
if ($ret === false || $ret === 0) {
throw new Exception('Incorrect spec string');
}
$orig = $regs[0];
$name = $regs[1];
$attributes = isset($regs[2]) ? $regs[2] : null;
$type = isset($regs[3]) ? $regs[3] : null;
$short = null;
$long = null;
// check long,short option name.
if (strpos($name, '|') !== false) {
list($short, $long) = explode('|', $name);
} else if (strlen($name) === 1) {
$short = $name;
} else if (strlen($name) > 1) {
$long = $name;
}
$this->short = $short;
$this->long = $long;
// option is required.
if (strpos($attributes, ':') !== false) {
$this->required();
} else if (strpos($attributes, '+') !== false) {
// option with multiple value
$this->multiple();
} else if (strpos($attributes, '?') !== false) {
// option is optional.(zero or one value)
$this->optional();
} else {
$this->flag();
}
if ($type) {
$this->isa($type);
}
}
/*
* get the option key for result key mapping.
*/
public function getId()
{
return $this->key ?: $this->long ?: $this->short;
}
/**
* To make -v, -vv, -vvv works.
*/
public function incremental()
{
$this->incremental = true;
return $this;
}
public function required()
{
$this->required = true;
return $this;
}
/**
* Set default value
*
* @param mixed|Closure $value
*/
public function defaultValue($value)
{
$this->defaultValue = $value;
return $this;
}
public function multiple()
{
$this->multiple = true;
$this->value = array(); # for value pushing
return $this;
}
public function optional()
{
$this->optional = true;
return $this;
}
public function flag()
{
$this->flag = true;
return $this;
}
public function trigger(callable $trigger)
{
$this->trigger = $trigger;
return $this;
}
public function isIncremental()
{
return $this->incremental;
}
public function isFlag()
{
return $this->flag;
}
public function isMultiple()
{
return $this->multiple;
}
public function isRequired()
{
return $this->required;
}
public function isOptional()
{
return $this->optional;
}
public function isTypeNumber()
{
return $this->isa == 'number';
}
public function isType($type)
{
return $this->isa === $type;
}
public function getTypeClass()
{
$class = 'GetOptionKit\\ValueType\\'.ucfirst($this->isa).'Type';
if (class_exists($class, true)) {
return new $class($this->isaOption);
}
throw new Exception("Type class '$class' not found.");
}
public function testValue($value)
{
$type = $this->getTypeClass();
return $type->test($value);
}
protected function _preprocessValue($value)
{
$val = $value;
if ($isa = ucfirst($this->isa)) {
$type = $this->getTypeClass();
if ($type->test($value)) {
$val = $type->parse($value);
} else {
if (strtolower($isa) === 'regex') {
$isa .= '('.$this->isaOption.')';
}
throw new InvalidOptionValueException("Invalid value for {$this->renderReadableSpec(false)}. Requires a type $isa.");
}
}
// check pre-filter for option value
if ($this->filter) {
$val = call_user_func($this->filter, $val);
}
// check validValues
if ($validValues = $this->getValidValues()) {
if (!in_array($value, $validValues)) {
throw new InvalidOptionValueException('valid values are: '.implode(', ', $validValues));
}
}
if (!$this->validate($value)[0]) {
throw new InvalidOptionValueException('option is invalid');
}
return $val;
}
protected function callTrigger()
{
if ($this->trigger) {
if ($ret = call_user_func($this->trigger, $this->value)) {
$this->value = $ret;
}
}
}
/*
* set option value
*/
public function setValue($value)
{
$this->value = $this->_preprocessValue($value);
$this->callTrigger();
}
/**
* This method is for incremental option.
*/
public function increaseValue()
{
if (!$this->value) {
$this->value = 1;
} else {
++$this->value;
}
$this->callTrigger();
}
/**
* push option value, when the option accept multiple values.
*
* @param mixed
*/
public function pushValue($value)
{
$value = $this->_preprocessValue($value);
$this->value[] = $value;
$this->callTrigger();
}
public function desc($desc)
{
$this->desc = $desc;
}
/**
* valueName is for option value hinting:.
*
* --name=<name>
*/
public function valueName($name)
{
$this->valueName = $name;
return $this;
}
public function renderValueHint()
{
$n = null;
if ($this->valueName) {
$n = $this->valueName;
} else if ($values = $this->getValidValues()) {
$n = '('.implode(',', $values).')';
} else if ($values = $this->getSuggestions()) {
$n = '['.implode(',', $values).']';
} else if ($val = $this->getDefaultValue()) {
// This allows for `0` and `false` values to be displayed also.
if ((is_scalar($val) && strlen((string) $val)) || is_bool($val)) {
if (is_bool($val)) {
$n = ($val ? 'true' : 'false');
} else {
$n = $val;
}
}
}
if (!$n && $this->isa !== null) {
$n = '<'.$this->isa.'>';
}
if ($this->isRequired()) {
return sprintf('=%s', $n);
} else if ($this->isOptional() || $this->defaultValue) {
return sprintf('[=%s]', $n);
} else if ($n) {
return '='.$n;
}
return '';
}
public function getDefaultValue()
{
if (is_callable($this->defaultValue)) {
return $this->defaultValue;
}
return $this->defaultValue;
}
public function getValue()
{
if (null !== $this->value) {
if (is_callable($this->value)) {
return call_user_func($this->value);
}
return $this->value;
}
return $this->getDefaultValue();
}
/**
* get readable spec for printing.
*
* @param string $renderHint render also value hint
*/
public function renderReadableSpec($renderHint = true)
{
$c1 = '';
if ($this->short && $this->long) {
$c1 = sprintf('-%s, --%s', $this->short, $this->long);
} else if ($this->short) {
$c1 = sprintf('-%s', $this->short);
} else if ($this->long) {
$c1 = sprintf('--%s', $this->long);
}
if ($renderHint) {
return $c1.$this->renderValueHint();
}
return $c1;
}
public function __toString()
{
$c1 = $this->renderReadableSpec();
$return = '';
$return .= sprintf('* key:%-8s spec:%s desc:%s', $this->getId(), $c1, $this->desc)."\n";
$val = $this->getValue();
if (is_array($val)) {
$return .= ' value => ' . join(',', array_map(function($v) { return var_export($v, true); }, $val))."\n";
} else {
$return .= sprintf(' value => %s', $val)."\n";
}
return $return;
}
/**
* Value Type Setters.
*
* @param string $type the value type, valid values are 'number', 'string',
* 'file', 'boolean', you can also use your own value type name.
* @param mixed $option option(s) for value type class (optionnal)
*/
public function isa($type, $option = null)
{
// "bool" was kept for backward compatibility
if ($type === 'bool') {
$type = 'boolean';
}
$this->isa = $type;
$this->isaOption = $option;
return $this;
}
/**
* Assign validValues to member value.
*/
public function validValues($values)
{
$this->validValues = $values;
return $this;
}
/**
* Assign suggestions.
*
* @param Closure|array
*/
public function suggestions($suggestions)
{
$this->suggestions = $suggestions;
return $this;
}
/**
* Return valud values array.
*
* @return string[] or nil
*/
public function getValidValues()
{
if ($this->validValues) {
if (is_callable($this->validValues)) {
return call_user_func($this->validValues);
}
return $this->validValues;
}
return;
}
/**
* Return suggestions.
*
* @return string[] or nil
*/
public function getSuggestions()
{
if ($this->suggestions) {
if (is_callable($this->suggestions)) {
return call_user_func($this->suggestions);
}
return $this->suggestions;
}
return;
}
public function validate($value)
{
if ($this->validator) {
$ret = call_user_func($this->validator, $value);
if (is_array($ret)) {
return $ret;
} else if ($ret === false) {
return array(false, "Invalid value: $value");
} else if ($ret === true) {
return array(true, 'Successfully validated.');
}
throw new InvalidArgumentException('Invalid return value from the validator.');
}
return array(true);
}
public function validator($cb)
{
$this->validator = $cb;
return $this;
}
/**
* Set up a filter function for the option value.
*
* todo: add "callable" type hint later.
*/
public function filter($cb)
{
$this->filter = $cb;
return $this;
}
}