Created
June 1, 2020 08:08
-
-
Save yoosefi/ba560f54677169fe68ca0a3c699d03c6 to your computer and use it in GitHub Desktop.
generate php magic method annotations
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
#!/usr/bin/php | |
<?php | |
const ALIASES = [ | |
'at' => 'iso8601', | |
'description' => 'text', | |
'on' => 'date', | |
'quantity' => 'qty', | |
]; | |
array_shift($argv); | |
sort($argv); | |
// $name => $argName | |
$get = []; | |
$has = []; | |
$set = []; | |
$select = []; // object arrays only | |
foreach ($argv as $field) { | |
// parse the name | |
$words = explode('_', preg_replace('/[^a-z0-9_]/i', '', $field)); | |
$lastWord = $words[count($words) - 1]; | |
$argName = ALIASES[$lastWord] ?? $lastWord; | |
$studly = implode('', array_map('ucwords', $words)); | |
// parse the type | |
$depends = strpos($field, '@') !== false; | |
$nullable = strpos($field, '?') !== false; | |
if (strpos($field, '.')) { | |
$type = 'bool'; | |
} | |
elseif (strpos($field, '##')) { | |
$type = 'int'; | |
} | |
elseif (strpos($field, '#')) { | |
$type = 'number'; | |
} | |
else { | |
$type = 'string'; | |
} | |
$readonly = strpos($field, '-'); | |
// process composites | |
if ($object = strpos($field, '{}')) { | |
$type = $studly; | |
} | |
if (strpos($field, '[]')) { | |
if ($object) { | |
$type = preg_replace('/(s|ies)$/', '', $type); | |
$eachName = preg_replace('/(s|ies)$/', '', $argName); | |
$select['select' . $studly] = [$type . '[]', $type, $eachName]; | |
} | |
$type .= '[]'; | |
$has['has' . $studly] = 'has' . $studly; | |
} | |
$get[$type === 'bool' ? 'is' . $studly : 'get' . $studly] = [ | |
($nullable ? 'null|' . $type : $type), | |
$readonly | |
]; | |
if (!$readonly) { | |
$set['set' . $studly] = [ | |
$nullable ? '?' . $type : $type, | |
$argName, | |
$depends | |
]; | |
} | |
} | |
/** | |
* The right-side tab padding. | |
* | |
* @param array $names | |
* @param int $start chars to the starting boundary | |
* @return int | |
*/ | |
function rpad (array $names, int $start = 0): int { | |
$len = $realLen = max(array_map('strlen', $names)); | |
// if the name stops on a tab, add a space. | |
if (0 === ($start + $len) % 4) { | |
$len++; | |
} | |
// pad to the nearest tab from the start | |
$pad = $start + ceil($len / 4) * 4; | |
// weird hack for negative start position that i don't understand. | |
if ($realLen >= $pad) { | |
$pad += 4; | |
} | |
return $pad; | |
} | |
function ruler () { | |
// -123456789-123456789-123456789-123456789-123456789-123456789- | |
//echo " * | | | | | | | | | | | | | | |\n"; | |
} | |
echo "/**\n"; | |
if ($get) { | |
$tPad = rpad(array_column($get, 0), 1); // longType starts 1 char before tab | |
$mPad = rpad(array_keys($get)); | |
ruler(); | |
foreach ($get as $method => [$longType, $readonly]) { | |
echo sprintf(" * @method %-{$tPad}s%-{$mPad}s()", $longType, $method); | |
if ($readonly) { | |
echo ' read-only'; | |
} | |
echo "\n"; | |
} | |
} | |
if ($has) { | |
echo " *\n"; | |
$mPad = rpad(array_keys($has)); // starts on tab | |
ruler(); | |
foreach ($has as $method) { | |
echo sprintf(" * @method bool %-{$mPad}s()\n", $method); | |
} | |
} | |
if ($set) { | |
echo " *\n"; | |
$mPad = rpad(array_keys($set), -1); // starts 1 char after tab | |
ruler(); | |
foreach ($set as $method => [$type, $arg, $depends]) { | |
echo sprintf(" * @method \$this %-{$mPad}s(%s %s)", $method, $type, "\${$arg}"); | |
if ($depends) { | |
echo ' @depends '; | |
} | |
echo "\n"; | |
} | |
} | |
if ($select) { | |
echo " *\n"; | |
$tPad = rpad(array_column($select, 0), 1); // type starts 1 char before tab | |
$mPad = rpad(array_keys($select)); | |
ruler(); | |
foreach ($select as $method => [$type, $eachType, $eachName]) { | |
echo sprintf( | |
" * @method %-{$tPad}s%-{$mPad}s(callable \$filter) `fn( {$eachType} \${$eachName} ): bool`\n", | |
$type, $method | |
); | |
} | |
} | |
echo " */\n"; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment