src/Documentation/ApiGen.php
<?php
declare(strict_types=1);
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Deployer\Documentation;
class ApiGen
{
/**
* @var array
*/
private $fns = [];
public function parse(string $source): void
{
$comment = '';
$params = '';
$source = str_replace("\r\n", "\n", $source);
$state = 'root';
foreach (explode("\n", $source) as $lineNumber => $line) {
switch ($state) {
case 'root':
if (str_starts_with($line, '/**')) {
$state = 'comment';
break;
}
if (str_starts_with($line, 'function')) {
$signature = preg_replace('/^function\s+/', '', $line);
$funcName = preg_replace('/\(.+$/', '', $signature);
$this->fns[] = [
'comment' => $comment,
'params' => $params,
'funcName' => $funcName,
'signature' => $signature,
];
$comment = '';
$params = '';
break;
}
break;
case 'comment':
if (str_ends_with($line, '*/')) {
$state = 'root';
break;
}
if (preg_match('/^\s\*\s@param\s(?<type>.+?)\$(?<name>.+?)\s(?<comment>.+)$/', $line, $matches)) {
if (empty($params)) {
$params = "| Argument | Type | Comment |\n|---|---|---|\n";
}
$type = implode(' or ', array_map(function ($t) {
$t = trim($t, ' ');
return "`$t`";
}, explode('|', $matches['type'])));
$params .= "| `\${$matches['name']}` | $type | {$matches['comment']} |\n";
break;
}
if (str_starts_with($line, ' * @')) {
break;
}
$comment .= preg_replace('/^\s\*\s?/', '', $line) . "\n";
break;
}
}
}
public function markdown(): string
{
$output = <<<MD
<!-- DO NOT EDIT THIS FILE! -->
<!-- Instead edit src/functions.php -->
<!-- Then run bin/docgen -->
# API Reference
MD;
foreach ($this->fns as $fn) {
[
'comment' => $comment,
'params' => $params,
'funcName' => $funcName,
'signature' => $signature,
] = $fn;
if (!empty($params)) {
$params = "\n$params";
}
$output .= <<<MD
## $funcName()
```php
$signature
```
$comment
$params
MD;
}
return $output;
}
}