From 7d08c735ef407de22f2ed56091330ecae3f03de9 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Tue, 28 Oct 2025 11:35:36 +0000 Subject: [PATCH] no message --- app/Http/Controllers/Api/apidoc.md | 378 ++++++++++++++++++++++++++++ app/Http/Controllers/Api/apidoc.php | 186 +++++++++----- cmd | 1 + 3 files changed, 496 insertions(+), 69 deletions(-) create mode 100644 app/Http/Controllers/Api/apidoc.md diff --git a/app/Http/Controllers/Api/apidoc.md b/app/Http/Controllers/Api/apidoc.md new file mode 100644 index 000000000..bab99fcb4 --- /dev/null +++ b/app/Http/Controllers/Api/apidoc.md @@ -0,0 +1,378 @@ +# apiDoc 参数标签说明(完整速查) + +apiDoc 使用内联注释为 RESTful API 自动生成文档。 +以下为所有官方支持的参数与其说明。 + +--- + +## @api +**定义 API 方法的基本信息** + +```js +@api {method} path title +``` + +- **method**:请求方法,如 `GET`、`POST`、`PUT`、`DELETE` 等 +- **path**:请求路径,例如 `/user/:id` +- **title**:简短标题(显示在文档中) + +📘 示例: +```js +@api {get} /user/:id Get user info +``` + +--- + +## @apiBody +**定义请求体参数** + +```js +@apiBody [{type}] [field=defaultValue] [description] +``` + +- `{type}` 参数类型(如 String, Number, Object, String[]) +- `[field]` 可选字段(方括号表示可选) +- `=defaultValue` 默认值 +- `description` 参数说明 + +📘 示例: +```js +@apiBody {String} lastname Mandatory Lastname. +@apiBody {Object} [address] Optional address object. +@apiBody {String} [address[city]] Optional city. +``` + +--- + +## @apiDefine +**定义可复用的文档块** + +```js +@apiDefine name [title] [description] +``` + +- `name`:唯一标识 +- `title`:简短标题 +- `description`:多行描述 + +📘 示例: +```js +@apiDefine MyError +@apiError UserNotFound The id of the User was not found. +``` + +--- + +## @apiDeprecated +**标记接口为弃用状态** + +```js +@apiDeprecated [text] +``` + +- `text`:提示文本,可带链接到新方法 + +📘 示例: +```js +@apiDeprecated use now (#User:GetDetails) +``` + +--- + +## @apiDescription +**描述接口详细说明** + +```js +@apiDescription text +``` + +📘 示例: +```js +@apiDescription This is the Description. +It is multiline capable. +``` + +--- + +## @apiError +**定义错误返回参数** + +```js +@apiError [(group)] [{type}] field [description] +``` + +📘 示例: +```js +@apiError UserNotFound The id of the User was not found. +``` + +--- + +## @apiErrorExample +**定义错误返回示例** + +```js +@apiErrorExample [{type}] [title] +example +``` + +📘 示例: +```js +@apiErrorExample {json} Error-Response: + HTTP/1.1 404 Not Found + { "error": "UserNotFound" } +``` + +--- + +## @apiExample +**定义接口使用示例** + +```js +@apiExample [{type}] title +example +``` + +📘 示例: +```js +@apiExample {curl} Example usage: + curl -i http://localhost/user/4711 +``` + +--- + +## @apiGroup +**定义所属分组** + +```js +@apiGroup name +``` + +📘 示例: +```js +@apiGroup User +``` + +--- + +## @apiHeader +**定义请求头参数** + +```js +@apiHeader [(group)] [{type}] [field=defaultValue] [description] +``` + +📘 示例: +```js +@apiHeader {String} access-key Users unique access-key. +``` + +--- + +## @apiHeaderExample +**定义请求头示例** + +```js +@apiHeaderExample [{type}] [title] +example +``` + +📘 示例: +```js +@apiHeaderExample {json} Header-Example: + { + "Accept-Encoding": "gzip, deflate" + } +``` + +--- + +## @apiIgnore +**忽略当前文档块** + +```js +@apiIgnore [hint] +``` + +📘 示例: +```js +@apiIgnore Not finished method +``` + +--- + +## @apiName +**定义接口唯一名称** + +```js +@apiName name +``` + +📘 示例: +```js +@apiName GetUser +``` + +--- + +## @apiParam +**定义请求参数** + +```js +@apiParam [(group)] [{type}] [field=defaultValue] [description] +``` + +📘 示例: +```js +@apiParam {Number} id Users unique ID. +@apiParam {String} [firstname] Optional firstname. +@apiParam {String} country="DE" Mandatory with default. +``` + +--- + +## @apiParamExample +**定义参数请求示例** + +```js +@apiParamExample [{type}] [title] +example +``` + +📘 示例: +```js +@apiParamExample {json} Request-Example: + { "id": 4711 } +``` + +--- + +## @apiPermission +**定义权限要求** + +```js +@apiPermission name +``` + +📘 示例: +```js +@apiPermission admin +``` + +--- + +## @apiPrivate +**标记接口为私有(可过滤)** + +```js +@apiPrivate +``` + +--- + +## @apiQuery +**定义查询参数(?query)** + +```js +@apiQuery [{type}] [field=defaultValue] [description] +``` + +📘 示例: +```js +@apiQuery {Number} id Users unique ID. +@apiQuery {String} [sort="asc"] Sort order. +``` + +--- + +## @apiSampleRequest +**定义接口测试请求 URL** + +```js +@apiSampleRequest url +``` + +📘 示例: +```js +@apiSampleRequest http://test.github.com/some_path/ +``` + +--- + +## @apiSuccess +**定义成功返回参数** + +```js +@apiSuccess [(group)] [{type}] field [description] +``` + +📘 示例: +```js +@apiSuccess {String} firstname Firstname of the User. +@apiSuccess {String} lastname Lastname of the User. +``` + +--- + +## @apiSuccessExample +**定义成功返回示例** + +```js +@apiSuccessExample [{type}] [title] +example +``` + +📘 示例: +```js +@apiSuccessExample {json} Success-Response: + HTTP/1.1 200 OK + { "firstname": "John", "lastname": "Doe" } +``` + +--- + +## @apiUse +**引用定义块(@apiDefine)** + +```js +@apiUse name +``` + +📘 示例: +```js +@apiDefine MySuccess +@apiSuccess {String} firstname User firstname. + +@apiUse MySuccess +``` + +--- + +## @apiVersion +**定义接口版本** + +```js +@apiVersion version +``` + +📘 示例: +```js +@apiVersion 1.6.2 +``` + +--- + +# 附录:常用标签速查表 + +| 标签 | 作用 | 示例 | +|------|------|------| +| `@api` | 定义接口 | `@api {get} /user/:id` | +| `@apiName` | 唯一名称 | `@apiName GetUser` | +| `@apiGroup` | 所属分组 | `@apiGroup User` | +| `@apiParam` | 请求参数 | `@apiParam {Number} id Users unique ID.` | +| `@apiBody` | 请求体参数 | `@apiBody {String} name Username.` | +| `@apiQuery` | 查询参数 | `@apiQuery {String} keyword Search term.` | +| `@apiHeader` | Header 参数 | `@apiHeader {String} token Auth token.` | +| `@apiSuccess` | 成功返回字段 | `@apiSuccess {String} name Username.` | +| `@apiError` | 错误返回字段 | `@apiError NotFound User not found.` | +| `@apiVersion` | 版本号 | `@apiVersion 1.0.0` | diff --git a/app/Http/Controllers/Api/apidoc.php b/app/Http/Controllers/Api/apidoc.php index f0ed9ab97..82007855d 100755 --- a/app/Http/Controllers/Api/apidoc.php +++ b/app/Http/Controllers/Api/apidoc.php @@ -1,89 +1,137 @@ $text) { - if (in_array(strtolower($matchs[1][$key]), array('get', 'post'))) { - $expl = explode(" ", __sRemove($text)); - $end = $expl[1]; - if ($expl[2]) { - $end = ''; - foreach ($expl AS $k=>$v) { if ($k >= 2) { $end.= " ".$v; } } - } - $newtext = "* @api {".$matchs[1][$key]."} ".$expl[0]." ".__zeroFill($i, 2).". ".trim($end); - $content = str_replace("* @api {".$matchs[1][$key]."} ".$text, $newtext, $content); - $i++; - // - echo $newtext; - echo "\r\n"; - } - } - if ($i > 1) { - file_put_contents($fillPath, $content); - } - } -} -echo "Success \n"; +const NUMBER_WIDTH = 2; -/** ************************************************************** */ -/** ************************************************************** */ -/** ************************************************************** */ +$isRestore = isset($argv[1]) && strtolower($argv[1]) === 'restore'; -/** - * 替换所有空格 - * @param $str - * @return mixed - */ -function __sRemove($str) { - $str = str_replace(" ", " ", $str); - if (__strExists($str, " ")) { - return __sRemove($str); - } - return $str; +$basePath = dirname(__FILE__) . '/'; +$controllerFiles = glob($basePath . '*Controller.php'); + +if (!$controllerFiles) { + echo "No Controller.php files found\n"; + exit(0); } +foreach ($controllerFiles as $filePath) { + $original = file_get_contents($filePath); + [$updated, $linesChanged] = processFile($original, $isRestore); + + if (count($linesChanged) === 0) { + continue; + } + + file_put_contents($filePath, $updated); + + foreach ($linesChanged as $line) { + echo $line . "\n"; + } +} + +echo $isRestore ? "Restore Success \n" : "Success \n"; + /** - * 是否包含字符 - * @param $string - * @param $find - * @return bool + * 处理单个文件内容 + * + * @param string $content + * @param bool $restore + * @return array{string, array} */ -function __strExists($string, $find) +function processFile(string $content, bool $restore): array { - return str_contains($string, $find); + $lineChanges = []; + $counter = 1; + + $pattern = '/\* @api \{([^\}]+)\}\s+([^\s]+)([^\r\n]*)(\r?\n)/'; + + $updated = preg_replace_callback( + $pattern, + function (array $matches) use ($restore, &$counter, &$lineChanges) { + $method = trim($matches[1]); + if (!in_array(strtolower($method), ['get', 'post'], true)) { + return $matches[0]; + } + + $endpoint = trim($matches[2]); + $suffix = normalizeDescription(stripExistingNumbering($matches[3])); + + if (!$restore) { + $numberedSuffix = formatNumber($counter) . '.'; + if ($suffix !== '') { + $numberedSuffix .= ' ' . $suffix; + } + $counter++; + } else { + $numberedSuffix = $suffix; + } + + $newLine = renderAnnotation($method, $endpoint, $numberedSuffix); + + if ($newLine !== rtrim($matches[0], "\r\n")) { + $lineChanges[] = $newLine; + } + + return $newLine . $matches[4]; + }, + $content + ); + + if ($updated === null) { + return [$content, []]; + } + + return [$updated, $lineChanges]; } /** - * @param string $str 补零 - * @param int $length - * @param int $after - * @return bool|string + * 生成格式化后的注释行 */ -function __zeroFill($str, $length = 0, $after = 1) { - if (strlen($str) >= $length) { - return $str; +function renderAnnotation(string $method, string $endpoint, string $suffix = ''): string +{ + $line = "* @api {" . $method . "} " . $endpoint; + + if ($suffix !== '') { + if ($suffix[0] !== ' ') { + $line .= ' '; + } + $line .= $suffix; } - $_str = ''; - for ($i = 0; $i < $length; $i++) { - $_str .= '0'; - } - if ($after) { - $_ret = substr($_str . $str, $length * -1); - } else { - $_ret = substr($str . $_str, 0, $length); - } - return $_ret; + + return $line; +} + +/** + * 移除已有编号部分 + */ +function stripExistingNumbering(string $text): string +{ + $trimmed = ltrim($text); + $pattern = '/^\d+\.\s*/'; + return preg_replace($pattern, '', $trimmed) ?? $trimmed; +} + +/** + * 压缩多余空格 + */ +function normalizeDescription(string $text): string +{ + $text = trim($text); + if ($text === '') { + return ''; + } + + return preg_replace('/\s+/', ' ', $text) ?? $text; +} + +/** + * 生成固定宽度的数字 + */ +function formatNumber(int $number): string +{ + return str_pad((string) $number, NUMBER_WIDTH, '0', STR_PAD_LEFT); } diff --git a/cmd b/cmd index c5fbe0a06..d771a0270 100755 --- a/cmd +++ b/cmd @@ -805,6 +805,7 @@ case "$1" in shift 1 container_exec php "php app/Http/Controllers/Api/apidoc.php" docker run -it --rm -v ${WORK_DIR}:/home/node/apidoc kuaifan/apidoc -i app/Http/Controllers/Api -o public/docs + container_exec php "php app/Http/Controllers/Api/apidoc.php restore" ;; "debug") shift 1