249 lines
7.2 KiB
Plaintext
249 lines
7.2 KiB
Plaintext
|
|
#!/usr/bin/env php
|
||
|
|
<?php
|
||
|
|
|
||
|
|
use OpenApi\Analysers\AttributeAnnotationFactory;
|
||
|
|
use OpenApi\Analysers\DocBlockAnnotationFactory;
|
||
|
|
use OpenApi\Analysers\ReflectionAnalyser;
|
||
|
|
use OpenApi\Analysers\TokenAnalyser;
|
||
|
|
use OpenApi\Annotations\OpenApi;
|
||
|
|
use OpenApi\Generator;
|
||
|
|
use OpenApi\Util;
|
||
|
|
use OpenApi\Loggers\ConsoleLogger;
|
||
|
|
|
||
|
|
if (class_exists(Generator::class) === false) {
|
||
|
|
if (file_exists(__DIR__.'/../vendor/autoload.php')) { // cloned / dev environment?
|
||
|
|
require_once(__DIR__.'/../vendor/autoload.php');
|
||
|
|
} else {
|
||
|
|
require_once(realpath(__DIR__.'/../../../').'/autoload.php');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
error_reporting(E_ALL);
|
||
|
|
|
||
|
|
// Possible options and their default values.
|
||
|
|
$options = [
|
||
|
|
'config' => [],
|
||
|
|
'legacy' => false,
|
||
|
|
'output' => false,
|
||
|
|
'format' => 'auto',
|
||
|
|
'exclude' => [],
|
||
|
|
'pattern' => '*.php',
|
||
|
|
'bootstrap' => [],
|
||
|
|
'help' => false,
|
||
|
|
'debug' => false,
|
||
|
|
'processor' => [],
|
||
|
|
'version' => null,
|
||
|
|
];
|
||
|
|
$aliases = [
|
||
|
|
'c' => 'config',
|
||
|
|
'l' => 'legacy',
|
||
|
|
'o' => 'output',
|
||
|
|
'e' => 'exclude',
|
||
|
|
'n' => 'pattern',
|
||
|
|
'b' => 'bootstrap',
|
||
|
|
'h' => 'help',
|
||
|
|
'd' => 'debug',
|
||
|
|
'p' => 'processor',
|
||
|
|
'f' => 'format'
|
||
|
|
];
|
||
|
|
$needsArgument = [
|
||
|
|
'config',
|
||
|
|
'output',
|
||
|
|
'format',
|
||
|
|
'exclude',
|
||
|
|
'pattern',
|
||
|
|
'bootstrap',
|
||
|
|
'processor',
|
||
|
|
'version',
|
||
|
|
];
|
||
|
|
$paths = [];
|
||
|
|
$error = false;
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Parse cli arguments
|
||
|
|
for ($i = 1; $i < $argc; $i++) {
|
||
|
|
$arg = $argv[$i];
|
||
|
|
if (substr($arg, 0, 2) === '--') { // longopt
|
||
|
|
$option = substr($arg, 2);
|
||
|
|
} elseif ($arg[0] === '-') { // shortopt
|
||
|
|
if (array_key_exists(substr($arg, 1), $aliases)) {
|
||
|
|
$option = $aliases[$arg[1]];
|
||
|
|
} else {
|
||
|
|
throw new Exception('Unknown option: "' . $arg . '"');
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$paths[] = $arg;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (array_key_exists($option, $options) === false) {
|
||
|
|
throw new Exception('Unknown option: "' . $arg . '"');
|
||
|
|
}
|
||
|
|
if (in_array($option, $needsArgument)) {
|
||
|
|
if (empty($argv[$i + 1]) || $argv[$i + 1][0] === '-') {
|
||
|
|
throw new Exception('Missing argument for "' . $arg . '"');
|
||
|
|
}
|
||
|
|
if (is_array($options[$option])) {
|
||
|
|
$options[$option][] = $argv[$i + 1];
|
||
|
|
} else {
|
||
|
|
$options[$option] = $argv[$i + 1];
|
||
|
|
}
|
||
|
|
$i++;
|
||
|
|
} else {
|
||
|
|
$options[$option] = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
$error = $e->getMessage();
|
||
|
|
}
|
||
|
|
|
||
|
|
$logger = new ConsoleLogger($options['debug']);
|
||
|
|
|
||
|
|
if (!$error && $options['bootstrap']) {
|
||
|
|
foreach ($options['bootstrap'] as $bootstrap) {
|
||
|
|
$filenames = glob($bootstrap);
|
||
|
|
if (false === $filenames) {
|
||
|
|
$error = 'Invalid `--bootstrap` value: "' . $bootstrap . '"';
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
foreach ($filenames as $filename) {
|
||
|
|
if ($options['debug']) {
|
||
|
|
$logger->debug('Bootstrapping: ' . $filename);
|
||
|
|
}
|
||
|
|
require_once($filename);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (count($paths) === 0) {
|
||
|
|
$error = 'Specify at least one path.';
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($options['help'] === false && $error) {
|
||
|
|
$logger->error('', ['prefix' => '']);
|
||
|
|
$logger->error($error);
|
||
|
|
// Show help
|
||
|
|
$options['help'] = true;
|
||
|
|
}
|
||
|
|
$defaultVersion = OpenApi::DEFAULT_VERSION;
|
||
|
|
if ($options['help']) {
|
||
|
|
$help = <<<EOF
|
||
|
|
|
||
|
|
Usage: openapi [--option value] [/path/to/project ...]
|
||
|
|
|
||
|
|
Options:
|
||
|
|
--config (-c) Generator config
|
||
|
|
ex: -c operationId.hash=false
|
||
|
|
--legacy (-l) Use legacy TokenAnalyser; default is the new ReflectionAnalyser
|
||
|
|
--output (-o) Path to store the generated documentation.
|
||
|
|
ex: --output openapi.yaml
|
||
|
|
--exclude (-e) Exclude path(s).
|
||
|
|
ex: --exclude vendor,library/Zend
|
||
|
|
--pattern (-n) Pattern of files to scan.
|
||
|
|
ex: --pattern "*.php" or --pattern "/\.(phps|php)$/"
|
||
|
|
--bootstrap (-b) Bootstrap php file(s) for defining constants, etc.
|
||
|
|
ex: --bootstrap config/constants.php
|
||
|
|
--processor (-p) Register an additional processor.
|
||
|
|
--format (-f) Force yaml or json.
|
||
|
|
--debug (-d) Show additional error information.
|
||
|
|
--version The OpenAPI version; defaults to {$defaultVersion}.
|
||
|
|
--help (-h) Display this help message.
|
||
|
|
|
||
|
|
|
||
|
|
EOF;
|
||
|
|
$logger->info($help);
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
$errorTypes = [
|
||
|
|
E_ERROR => 'Error',
|
||
|
|
E_WARNING => 'Warning',
|
||
|
|
E_PARSE => 'Parser error',
|
||
|
|
E_NOTICE => 'Notice',
|
||
|
|
E_STRICT => 'Strict',
|
||
|
|
E_DEPRECATED => 'Deprecated',
|
||
|
|
E_CORE_ERROR => 'Error(Core)',
|
||
|
|
E_CORE_WARNING => 'Warning(Core)',
|
||
|
|
E_COMPILE_ERROR => 'Error(compile)',
|
||
|
|
E_COMPILE_WARNING => 'Warning(Compile)',
|
||
|
|
E_RECOVERABLE_ERROR => 'Error(Recoverable)',
|
||
|
|
E_USER_ERROR => 'Error',
|
||
|
|
E_USER_WARNING => 'Warning',
|
||
|
|
E_USER_NOTICE => 'Notice',
|
||
|
|
E_USER_DEPRECATED => 'Deprecated',
|
||
|
|
];
|
||
|
|
set_error_handler(function ($errno, $errstr, $file, $line) use ($errorTypes, $options, $logger) {
|
||
|
|
if (!(error_reporting() & $errno)) {
|
||
|
|
// This error code is not included in error_reporting
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
$type = array_key_exists($errno, $errorTypes) ? $errorTypes[$errno] : 'Error';
|
||
|
|
if ($type === 'Deprecated') {
|
||
|
|
$logger->info($errstr, ['prefix' => $type . ': ']);
|
||
|
|
} else {
|
||
|
|
$logger->error($errstr, ['prefix' => $type . ': ']);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($options['debug']) {
|
||
|
|
$logger->info(' in '.$file.' on line '.$line);
|
||
|
|
}
|
||
|
|
if (substr($type, 0, 5) === 'Error') {
|
||
|
|
exit($errno);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
set_exception_handler(function ($exception) use ($logger) {
|
||
|
|
$logger->error($exception);
|
||
|
|
exit($exception->getCode() ?: 1);
|
||
|
|
});
|
||
|
|
|
||
|
|
$exclude = null;
|
||
|
|
if ($options['exclude']) {
|
||
|
|
$exclude = $options['exclude'];
|
||
|
|
if (strpos($exclude[0], ',') !== false) {
|
||
|
|
$exploded = explode(',', $exclude[0]);
|
||
|
|
$logger->error('Comma-separated exclude paths are deprecated, use multiple --exclude statements: --exclude '.$exploded[0].' --exclude '.$exploded[1]);
|
||
|
|
$exclude[0] = array_shift($exploded);
|
||
|
|
$exclude = array_merge($exclude, $exploded);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$pattern = "*.php";
|
||
|
|
if ($options['pattern']) {
|
||
|
|
$pattern = $options['pattern'];
|
||
|
|
}
|
||
|
|
|
||
|
|
$generator = new Generator($logger);
|
||
|
|
foreach ($options["processor"] as $processor) {
|
||
|
|
$class = '\OpenApi\Processors\\'.$processor;
|
||
|
|
if (class_exists($class)) {
|
||
|
|
$processor = new $class();
|
||
|
|
} elseif (class_exists($processor)) {
|
||
|
|
$processor = new $processor();
|
||
|
|
}
|
||
|
|
$generator->getProcessorPipeline()->add($processor);
|
||
|
|
}
|
||
|
|
|
||
|
|
$analyser = $options['legacy']
|
||
|
|
? new TokenAnalyser()
|
||
|
|
: new ReflectionAnalyser([new DocBlockAnnotationFactory(), new AttributeAnnotationFactory()]);
|
||
|
|
|
||
|
|
$openapi = $generator
|
||
|
|
->setVersion($options['version'])
|
||
|
|
->setConfig($options['config'])
|
||
|
|
->setAnalyser($analyser)
|
||
|
|
->generate(Util::finder($paths, $exclude, $pattern));
|
||
|
|
|
||
|
|
if ($options['output'] === false) {
|
||
|
|
if (strtolower($options['format']) === 'json') {
|
||
|
|
echo $openapi->toJson();
|
||
|
|
} else {
|
||
|
|
echo $openapi->toYaml();
|
||
|
|
}
|
||
|
|
echo "\n";
|
||
|
|
} else {
|
||
|
|
if (is_dir($options['output'])) {
|
||
|
|
$options['output'] .= '/openapi.yaml';
|
||
|
|
}
|
||
|
|
$openapi->saveAs($options['output'], $options['format']);
|
||
|
|
}
|
||
|
|
exit($logger->loggedMessageAboveNotice() ? 1 : 0);
|