#!/usr/bin/env php 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 = << '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\Generator::scan(OpenApi\Util::finder($paths, $exclude, $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);