You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.7 KiB
110 lines
2.7 KiB
<?php
|
|
|
|
namespace EE_CLI;
|
|
|
|
/**
|
|
* Generate a synopsis from a command's PHPdoc arguments.
|
|
* Turns something like "<object-id>..."
|
|
* into [ optional=>false, type=>positional, repeating=>true, name=>object-id ]
|
|
*/
|
|
class SynopsisParser {
|
|
|
|
/**
|
|
* @param string A synopsis
|
|
* @return array List of parameters
|
|
*/
|
|
public static function parse( $synopsis ) {
|
|
$tokens = array_filter( preg_split( '/[\s\t]+/', $synopsis ) );
|
|
|
|
$params = array();
|
|
foreach ( $tokens as $token ) {
|
|
$param = self::classify_token( $token );
|
|
|
|
// Some types of parameters shouldn't be mandatory
|
|
if ( isset( $param['optional'] ) && !$param['optional'] ) {
|
|
if ( 'flag' === $param['type'] || ( 'assoc' === $param['type'] && $param['value']['optional'] ) ) {
|
|
$param['type'] = 'unknown';
|
|
}
|
|
}
|
|
|
|
$param['token'] = $token;
|
|
$params[] = $param;
|
|
}
|
|
|
|
return $params;
|
|
}
|
|
|
|
/**
|
|
* Classify argument attributes based on its syntax.
|
|
*
|
|
* @param string $token
|
|
* @return array $param
|
|
*/
|
|
private static function classify_token( $token ) {
|
|
$param = array();
|
|
|
|
list( $param['optional'], $token ) = self::is_optional( $token );
|
|
list( $param['repeating'], $token ) = self::is_repeating( $token );
|
|
|
|
$p_name = '([a-z-_]+)';
|
|
$p_value = '([a-zA-Z-_|,]+)';
|
|
|
|
if ( '--<field>=<value>' === $token ) {
|
|
$param['type'] = 'generic';
|
|
} elseif ( preg_match( "/^<($p_value)>$/", $token, $matches ) ) {
|
|
$param['type'] = 'positional';
|
|
$param['name'] = $matches[1];
|
|
} elseif ( preg_match( "/^--(?:\\[no-\\])?$p_name/", $token, $matches ) ) {
|
|
$param['name'] = $matches[1];
|
|
|
|
$value = substr( $token, strlen( $matches[0] ) );
|
|
|
|
// substr returns false <= PHP 5.6, and '' PHP 7+
|
|
if ( false === $value || '' === $value ) {
|
|
$param['type'] = 'flag';
|
|
} else {
|
|
$param['type'] = 'assoc';
|
|
|
|
list( $param['value']['optional'], $value ) = self::is_optional( $value );
|
|
|
|
if ( preg_match( "/^=<$p_value>$/", $value, $matches ) ) {
|
|
$param['value']['name'] = $matches[1];
|
|
} else {
|
|
$param = array( 'type' => 'unknown' );
|
|
}
|
|
}
|
|
} else {
|
|
$param['type'] = 'unknown';
|
|
}
|
|
|
|
return $param;
|
|
}
|
|
|
|
/**
|
|
* An optional parameter is surrounded by square brackets.
|
|
*
|
|
* @param string $token
|
|
* @return array
|
|
*/
|
|
private static function is_optional( $token ) {
|
|
if ( '[' == substr( $token, 0, 1 ) && ']' == substr( $token, -1 ) ) {
|
|
return array( true, substr( $token, 1, -1 ) );
|
|
} else {
|
|
return array( false, $token );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A repeating parameter is followed by an ellipsis.
|
|
*
|
|
* @param string $token
|
|
* @return array
|
|
*/
|
|
private static function is_repeating( $token ) {
|
|
if ( '...' === substr( $token, -3 ) ) {
|
|
return array( true, substr( $token, 0, -3 ) );
|
|
} else {
|
|
return array( false, $token );
|
|
}
|
|
}
|
|
}
|
|
|