| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- #!/usr/bin/env php
- <?php
- use OpenApi\Logger;
- use OpenApi\Analysis;
- use const OpenApi\UNDEFINED;
- use const OpenApi\COLOR_RED;
- use const OpenApi\COLOR_YELLOW;
- use const OpenApi\COLOR_STOP;
- error_reporting(E_ALL);
- // Possible options and their default values.
- $options = [
- 'output' => false,
- 'format' => 'auto',
- 'exclude' => [],
- 'pattern' => '*.php',
- 'bootstrap' => false,
- 'help' => false,
- 'debug' => false,
- 'processor' => [],
- ];
- $aliases = [
- 'o' => 'output',
- 'e' => 'exclude',
- 'n' => 'pattern',
- 'b' => 'bootstrap',
- 'h' => 'help',
- 'd' => 'debug',
- 'p' => 'processor',
- 'f' => 'format'
- ];
- $needsArgument = [
- 'output',
- 'format',
- 'exclude',
- 'pattern',
- 'bootstrap',
- 'processor',
- ];
- $paths = [];
- $error = false;
- define('OpenApi\COLOR_RED', "\033[31m");
- define('OpenApi\COLOR_YELLOW', "\033[33m");
- define('OpenApi\COLOR_STOP', "\033[0m");
- 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();
- }
- if (!$error && $options['bootstrap']) {
- if (is_readable($options['bootstrap']) === false) {
- $error = 'Invalid `--bootstrap` value: "'.$options['bootstrap'].'"';
- } else {
- require_once($options['bootstrap']);
- }
- }
- if (count($paths) === 0) {
- $error = 'Specify at least one path.';
- }
- if ($options['help'] === false && $error) {
- error_log('');
- error_log(COLOR_RED.'Error: '.$error.COLOR_STOP);
- $options['help'] = true; // Show help
- }
- if ($options['help']) {
- $help = <<<EOF
- Usage: openapi [--option value] [/path/to/project ...]
- Options:
- --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 a php file for defining constants, etc.
- ex: --bootstrap config/constants.php
- --processor Register an additional processor.
- --format Force yaml or json.
- --debug Show additional error information.
- --help (-h) Display this help message.
- EOF;
- error_log($help);
- exit(1);
- }
- if (class_exists(Logger::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');
- }
- }
- $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) {
- if (!(error_reporting() & $errno)) {
- return; // This error code is not included in error_reporting
- }
- $type = array_key_exists($errno, $errorTypes) ? $errorTypes[$errno] : 'Error';
- $color = (substr($type, 0, 5) === 'Error') ? COLOR_RED: COLOR_YELLOW;
- error_log(COLOR_RED.$type. ': '.$errstr.COLOR_STOP);
- if ($options['debug']) {
- error_log(' in '.$file.' on line '.$line);
- }
- if (substr($type, 0, 5) === 'Error') {
- exit($errno);
- }
- });
- set_exception_handler(function ($exception) use ($options) {
- if ($options['debug']) {
- error_log($exception);
- } else {
- error_log(COLOR_RED.'Exception: '.$exception->getMessage().COLOR_STOP);
- // if ($options['debug']) {
- // error_log(' in '.$exception->getFile().' on line '.$exception->getLine());
- // }
- }
- exit($exception->getCode() ?: 1);
- });
- $exit = 0;
- Logger::getInstance()->log = function ($entry, $type) use ($options, &$exit) {
- $exit = 1;
- if ($type === E_USER_NOTICE) {
- $type = '';
- $color = COLOR_YELLOW;
- } else {
- $type = 'Warning: ';
- $color = COLOR_RED;
- }
- if ($entry instanceof Exception) {
- error_log(COLOR_RED."Error: " . $entry->getMessage().COLOR_STOP);
- if ($options['debug']) {
- error_log('Stack trace:'.PHP_EOL.$entry->getTraceAsString());
- }
- } else {
- error_log($color. $type . $entry.COLOR_STOP);
- if ($options['debug']) {
- // Show backtrace in debug mode
- $e = (string)(new Exception('trace'));
- $trace = explode("\n", substr($e, strpos($e, 'Stack trace:')));
- foreach ($trace as $i => $entry) {
- if ($i === 0) {
- error_log($entry);
- }
- if ($i <= 3) {
- continue;
- }
- preg_match('/#([0-9]+) (.*)$/', $entry, $match);
- error_log('#' .($match[1] - 2).' '.$match[2]);
- }
- }
- }
- };
- $exclude = null;
- if ($options['exclude']) {
- $exclude = $options['exclude'];
- if (strpos($exclude[0], ',') !== false) {
- $exploded = explode(',', $exclude[0]);
- error_log(COLOR_RED.'Comma-separated exclude paths are deprecated, use multiple --exclude statements: --exclude '.$exploded[0].' --exclude '.$exploded[1]).COLOR_STOP;
- $exclude[0] = array_shift($exploded);
- $exclude = array_merge($exclude, $exploded);
- }
- }
- $pattern = "*.php";
- if ($options['pattern']) {
- $pattern = $options['pattern'];
- }
- foreach ($options["processor"] as $processor) {
- $class = '\OpenApi\Processors\\'.$processor;
- if (class_exists($class)) {
- $processor = new $class();
- } elseif (class_exists($processor)) {
- $processor = new $processor();
- }
- Analysis::registerProcessor($processor);
- }
- $openapi = OpenApi\scan($paths, ['exclude' => $exclude, 'pattern' => $pattern]);
- if ($exit !== 0) {
- error_log('');
- }
- 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($exit);
|