Merge pull request 'feat(review): 新增 API 文件稽核技能,第 5 組擴充註解的條列、導向與標示規則' (#11) from feat/api-doc-audit/main into develop
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-review",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組",
|
||||
"skills": "./skills",
|
||||
"author": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-review",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組",
|
||||
"skills": "./skills"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
||||
|
||||
對 git diff 進行六組壞味道審查,每組一個 sub agent 平行執行;回報 `檔案:行號`、嚴重度、建議重構手法,修正與否由呼叫端決定。第 2 組同時擋「文件編號夾帶」:註解只寫「為什麼這樣寫」,議題編號、wiki 頁編號、工作包編號、commit hash、`@` 提及、外部文件連結一律不進註解,清單看 `references/comment-scope.md`。diff 是空的就直接回報「無發現」,不開任何 sub agent;六組全部回覆才進入彙整,沒東西可報的那組也要回「無發現」。安全性與 bug 審查交給 CLI 內建 review,不重複。
|
||||
|
||||
### `api-doc`
|
||||
|
||||
稽核 API 專案的 Swagger 文件:每個可能回傳的 HTTP 狀態碼都要宣告回覆類型,每個輸入與輸出都要有說明與真實資料範例,並沿著巢狀資料模型逐層遞迴。控制器改完或實作完成時執行,例如由 `jsc-sdlc:implement` 呼叫,與 `jsc-review:code-review` 並列為兩關收尾稽核。先跑 `tools/swagger-detect.sh` 偵測,套件與掛接設定要雙重命中才算支援;只裝套件沒掛接就回報未啟用並停手,不開任何 sub agent。原始碼的註解契約歸 `jsc-review:code-review` 第 5 組,這支只管 Swagger 文件屬性與範例,兩支不重複回報。回報 `檔案:行號`、嚴重度與建議修法,本技能不改程式碼。
|
||||
|
||||
<!-- JSC-SKILLS:END -->
|
||||
|
||||
## 參考
|
||||
@@ -37,6 +41,12 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
||||
| `references/smells.md` | 六組壞味道完整清單:定義、偵測訊號、建議重構手法、嚴重度分級;範例資料必須去識別化 |
|
||||
| `references/comment-scope.md` | 程式碼註解內容界線:禁止寫進註解的文件編號清單、允許項目與白名單、命中時的改法 |
|
||||
|
||||
## 工具
|
||||
|
||||
| 檔案 | 用途 |
|
||||
| --- | --- |
|
||||
| `tools/swagger-detect.sh` | 判斷專案有沒有真的啟用 Swagger。套件與設定雙重確認,缺一不算支援。輸出 `support=`、`stack=`、`package=`、`config=`;結束碼 0 支援、1 不支援、2 參數或路徑錯誤 |
|
||||
|
||||
## 相關 domain
|
||||
|
||||
- [`jsc-sdlc`](https://gitea.jsc.idv.tw/plugins/sdlc):實作階段完成後呼叫本審查
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-review",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"description": "程式碼審查:Refactoring 壞味道六組 + 註解規範 + 淺模組",
|
||||
"skills": "./skills/"
|
||||
}
|
||||
|
||||
+46
-7
@@ -122,9 +122,9 @@
|
||||
|
||||
### 5.1 方法描述
|
||||
|
||||
- **定義**:每個公開方法要有一句話描述,並標明所屬層級:**顯示層、邏輯層、存取層**。
|
||||
- **偵測訊號**:公開方法無描述;描述未標層級;描述與方法實際行為不符。
|
||||
- **建議重構手法**:補上單句描述與層級標記;若一個方法橫跨多層,先依 Split Phase 拆分再各自標註。
|
||||
- **定義**:每個公開方法要有一句話描述,並標明所屬層級:**顯示層、邏輯層、存取層**。描述後面要接**條列式的處理步驟與規則**,讀註解就知道這個方法做了哪幾件事、依哪些規則做。
|
||||
- **偵測訊號**:公開方法無描述;描述未標層級;描述與方法實際行為不符;描述只有一句話,方法內部卻有多段流程或多條判斷規則,註解裡找不到對應的條列;條列步驟與程式碼實際順序對不上。
|
||||
- **建議重構手法**:補上單句描述與層級標記,再把處理流程拆成條列步驟、把判斷條件寫成條列規則;若一個方法橫跨多層,先依 Split Phase 拆分再各自標註;條列長到十項以上,代表方法本身太肥,同時列 1.2 並建議 Extract Function。
|
||||
|
||||
### 5.2 輸入參數說明
|
||||
|
||||
@@ -134,9 +134,9 @@
|
||||
|
||||
### 5.3 輸出說明
|
||||
|
||||
- **定義**:輸出(回傳值)要說明回傳的資料內容概要。
|
||||
- **偵測訊號**:無回傳說明;未說明 null、空集合、錯誤時的回傳;回傳布林但未說明 true/false 意義。
|
||||
- **建議重構手法**:補回傳內容概要與邊界情況說明。
|
||||
- **定義**:輸出(回傳值)要說明回傳的資料內容概要。回傳值是自訂資料模型,而註解格式支援導向時(XML 的 `<see cref>`、JSDoc 的 `{@link}`),說明要附上該資料模型的檔案連結,讀的人一鍵就跳到定義。
|
||||
- **偵測訊號**:無回傳說明;未說明 null、空集合、錯誤時的回傳;回傳布林但未說明 true/false 意義;回傳自訂資料模型卻只寫型別名稱純文字,沒有 `<see cref>` 或 `{@link}` 導向。
|
||||
- **建議重構手法**:補回傳內容概要與邊界情況說明;自訂資料模型改用註解格式的導向標籤指到型別定義,泛型集合指到元素型別。
|
||||
|
||||
### 5.4 輸入與輸出範例
|
||||
|
||||
@@ -150,6 +150,35 @@
|
||||
- **偵測訊號**:DTO/ViewModel 僅頂層有註解;內層類別、集合元素型別的欄位無說明或無範例。
|
||||
- **建議重構手法**:逐層補齊 5.1–5.4;巢狀過深(≥ 3 層)時同時評估 Extract Class 是否被濫用。
|
||||
|
||||
### 5.6 內含功能的導向連結
|
||||
|
||||
- **定義**:一個功能內部呼叫了其他功能時,註解要交代呼叫了誰、為什麼呼叫。註解格式支援導向就用導向標籤(XML 的 `<see cref>`、JSDoc 的 `{@link}`),讓 IDE 直接跳過去。
|
||||
- **偵測訊號**:方法內呼叫其他公開方法或服務,註解卻完全沒提;提了但只寫純文字方法名,沒有 `<see cref>` 或 `{@link}`;寫了連結卻沒寫用途,讀的人還是要自己點進去猜。
|
||||
- **建議重構手法**:在條列步驟裡把被呼叫的功能改成導向標籤,後面接一句用途;被呼叫的功能多到列不完,代表這個方法在當協調中心,同時列 1.2 或 3.1 評估職責搬移。
|
||||
- **注意**:註解格式不支援導向(例如純 `//` 行註解)就只寫用途,不硬造連結字串。
|
||||
|
||||
### 5.7 XML 註解標籤排版
|
||||
|
||||
- **定義**:註解採 XML 格式時,起始標籤與結束標籤**各自獨立一行**,內容夾在中間。這樣多行內容、條列與巢狀標籤才排得整齊,diff 也只動到真正改的那幾行。
|
||||
- **偵測訊號**:起始標籤、內容、結束標籤擠在同一行(例:`/// <summary>取得訂單</summary>`);結束標籤跟在內容尾巴後面沒有換行(例:`/// 取得訂單</summary>`);`<param>`、`<returns>`、`<remarks>`、`<example>` 同樣擠成一行;巢狀標籤(`<list>` 內含 `<item>`)沒有逐層換行與縮排。
|
||||
- **建議重構手法**:把每個標籤拆成三行——起始標籤一行、內容一行或多行、結束標籤一行;巢狀標籤逐層縮排;`<param>` 這類帶屬性的標籤,屬性留在起始標籤那一行。
|
||||
- **注意**:只針對 XML 格式註解。JSDoc、docstring 沒有結束標籤,不適用本項。
|
||||
|
||||
### 5.8 專有名詞與變數標示
|
||||
|
||||
- **定義**:註解裡提到程式碼元素時,要用該語言註解格式的標示語法標起來,不能混在純文字裡。標示的目的是讓 IDE 與文件產生工具讀得懂,並在文件上呈現成程式碼樣式。
|
||||
- **偵測訊號**:XML 註解裡直接以純文字寫參數名、型別名、成員名或程式碼字面;JSDoc 或 docstring 裡以純文字寫變數名與型別名,沒有加反引號;標錯類別(例如拿 `<c>` 標參數名、拿 `<paramref>` 標型別)。
|
||||
- **建議重構手法**:依語言慣例補標示。
|
||||
|
||||
| 註解格式 | 對象 | 標示語法 |
|
||||
| --- | --- | --- |
|
||||
| XML | 變數、參數 | `<paramref name="orderId" />` |
|
||||
| XML | 型別、成員 | `<see cref="OrderService.GetOrder" />` |
|
||||
| XML | 程式碼字面、列舉值 | `<c>null</c>` |
|
||||
| JSDoc、docstring | 變數、型別、程式碼字面 | 反引號 `` `orderId` `` |
|
||||
|
||||
- **注意**:標示規則跟著語言慣例走,不是跟著個人喜好走。IDE 的跳轉與文件工具的交叉引用都靠這些標籤,標錯等於沒標。
|
||||
|
||||
## 第 6 組:淺模組(Shallow Module)
|
||||
|
||||
- **定義**:介面複雜度相對於功能深度過高的模組——使用它要懂的事,跟自己寫差不多(出自《A Philosophy of Software Design》:好模組要「介面簡單、實作深」)。
|
||||
@@ -162,4 +191,14 @@
|
||||
| --- | --- | --- |
|
||||
| 高 | 會造成錯誤或已阻礙修改 | 吞掉異常、重複程式碼改漏、死碼誤導 |
|
||||
| 中 | 持續增加維護成本 | 巨型類別、臃腫函式、巢狀地獄、Couplers 全組 |
|
||||
| 低 | 可讀性與一致性 | 命名、魔術數字、註解缺漏、文件編號夾帶、淺模組 |
|
||||
| 低 | 可讀性與一致性 | 命名、魔術數字、註解缺漏、文件編號夾帶、淺模組、XML 標籤排版、專有名詞未標示 |
|
||||
|
||||
第 5 組新增項目的級別另外標明,避免全部壓在「註解缺漏」一句話裡:
|
||||
|
||||
| 項目 | 級別 | 理由 |
|
||||
| --- | --- | --- |
|
||||
| 5.1 缺條列式步驟與規則 | 中 | 讀的人要重讀整個實作才知道規則,維護成本直接上升 |
|
||||
| 5.3 回傳值缺資料模型連結 | 低 | 型別名稱還查得到,只是多花幾秒 |
|
||||
| 5.6 缺內含功能的導向連結 | 低 | 同上,影響的是查找速度 |
|
||||
| 5.7 XML 標籤排版擠在同一行 | 低 | 純排版,不影響語意 |
|
||||
| 5.8 專有名詞未標示或標錯 | 低 | 影響 IDE 跳轉與文件呈現,不影響執行 |
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: api-doc
|
||||
description: Audit an API project's Swagger/OpenAPI documentation: every returnable HTTP status code declares a response type, and every input and output carries a description plus a real data example, recursively down nested data models. Run after controller work or an implementation is complete, e.g. from jsc-sdlc implement, next to jsc-review:code-review. Detection runs first via tools/swagger-detect.sh; without both the Swagger package and its wiring, report unsupported and stop. The source comment contract belongs to jsc-review:code-review group 5; this skill covers Swagger document attributes only. Findings carry file:line, severity, and the fix; this skill never modifies code.
|
||||
---
|
||||
|
||||
# api-doc
|
||||
|
||||
Audit whether an API project's Swagger (OpenAPI) documentation is complete enough for a caller to integrate against it without reading the implementation.
|
||||
|
||||
## When to run
|
||||
|
||||
1. **After controller work is complete**: one controller or one related group of controllers is done.
|
||||
2. **When an implementation is complete**: all todos of a work package that touched API endpoints are done. This is the call site in `jsc-sdlc:implement`, right next to `jsc-review:code-review`.
|
||||
3. **Never on a project without Swagger**: step 1 below decides this in code, not by judgment.
|
||||
|
||||
## Division of labor
|
||||
|
||||
- This skill covers **Swagger document attributes only**: response type declarations, Swagger parameter descriptions, and Swagger examples.
|
||||
- The comment contract — method description, layer tag, parameter description, return description, examples, nested-structure comments — belongs to `jsc-review:code-review` group 5 (`references/smells.md` 5.1 to 5.8). Never report the same gap twice; when a nested model already fails 5.5, leave it to `code-review`.
|
||||
- Security, logic bugs, and test coverage belong to the CLI's built-in review.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Detect Swagger support: run `tools/swagger-detect.sh {project path}` (defaults to the current directory). The script confirms package **and** wiring, so an installed-but-never-enabled project comes back unsupported. Read its exit code: `0` supported, `1` unsupported, `2` bad argument or missing path. Completion condition: the exit code and the `support=`, `stack=`, `package=`, `config=` lines are captured.
|
||||
2. On exit code `1`, report the literal 「本專案未啟用 Swagger 文件,略過 API 文件稽核」 plus the `stack=` and `package=` lines the script printed, and stop. Spawn no sub agent. On exit code `2`, report the script's error message verbatim and stop; the caller supplies a valid project path and re-runs. Completion condition: the run has ended with an honest reason, or exit code `0` moved it to step 3.
|
||||
3. List the audit scope: every controller in the project, or only the controllers touched by `git diff` when the caller asked for a scoped run. Completion condition: the controller list is non-empty and reported; an empty list ends the run with the literal 「無發現」.
|
||||
4. Audit in three aspects, and every aspect **MUST run as a sub agent**; the three may run in parallel:
|
||||
|
||||
| Aspect | Scope |
|
||||
| --- | --- |
|
||||
| 1 Status codes | For every action, every HTTP status code it can actually return — success, validation failure, authorization failure, not found, server error — has a declared response type and body schema (`ProducesResponseType`, `@ApiResponse`, FastAPI `responses=`, drf-spectacular `@extend_schema`). A status code the code can produce but the document never declares is a finding; so is a declared status code the code can never produce |
|
||||
| 2 Parameter description and example | Every input parameter and every output field has a description and an example. Examples come from real project data first — query the project's database, seed data, or fixtures. Only when real data is unreachable, derive an example by logic and mark it as a derived value in the document itself |
|
||||
| 3 Recursive data model | When a parameter or return value is a data model, aspect 2 applies to every one of its properties. A model containing another model recurses to the innermost layer. Walk in from the controller and follow the input and output types down |
|
||||
|
||||
Instructions for each sub agent: read only, change nothing; report each finding as `file:line`, the aspect, severity, one sentence of evidence, and the concrete fix (which attribute to add, on which member). Findings are reported in Traditional Chinese.
|
||||
|
||||
Completion condition: all three aspects have returned — an aspect with nothing to report still returns 「無發現」 for itself.
|
||||
5. Merge the three aspects' findings: deduplicate by location, then sort by severity. Start this step only once all three have returned. Completion condition: every finding appears exactly once, ordered 高 → 中 → 低.
|
||||
6. Report the finding list. **This skill never modifies code**; the caller decides what to fix. Completion condition: the report is handed to the caller and the fix decision is left to them.
|
||||
|
||||
## Severity
|
||||
|
||||
The 高、中、低 scale is the one in `references/smells.md`. Map this skill's findings onto it:
|
||||
|
||||
| Finding | Severity |
|
||||
| --- | --- |
|
||||
| A returnable status code has no declared response type | 高 |
|
||||
| A declared response type does not match the body the code returns | 高 |
|
||||
| An input or output has no description | 中 |
|
||||
| A data model property is missing from the recursive walk entirely | 中 |
|
||||
| A placeholder example while real data was reachable | 低 |
|
||||
| A derived example that is not marked as derived | 低 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Examples taken from a database must be de-identified. Never put personal data into a Swagger document.
|
||||
- 「推導值」 is the literal marker for a derived example; keep it in the document text so the next reader knows the value was never observed.
|
||||
- When there are no findings, report the literal 「無發現」 explicitly; never leave the report empty.
|
||||
@@ -16,6 +16,7 @@ Review changed code against `references/smells.md` (from the book *Refactoring*)
|
||||
|
||||
- This skill covers the *Refactoring* smells, the comment contract (group 5), and shallow modules (group 6).
|
||||
- Security, logic bugs, and test coverage belong to the CLI's built-in review (e.g. claude's `/security-review`); do not duplicate them.
|
||||
- Swagger document auditing belongs to `jsc-review:api-doc`: response type declarations per HTTP status code, Swagger parameter descriptions, and Swagger examples down the nested data models. Group 5 here covers the source comment contract only; the two never report the same gap twice.
|
||||
|
||||
## Steps
|
||||
|
||||
@@ -28,7 +29,7 @@ Review changed code against `references/smells.md` (from the book *Refactoring*)
|
||||
| 2 Obscurity | smells.md group 2, including 2.5 document reference leak — comments carrying issue ids, wiki page ids, work package ids, commit hashes, @ mentions, or external document links; the full banned and allowed lists live in `references/comment-scope.md` |
|
||||
| 3 Couplers | smells.md group 3 |
|
||||
| 4 Dispensables & Others | smells.md group 4 |
|
||||
| 5 Comment contract | smells.md group 5 |
|
||||
| 5 Comment contract | smells.md group 5, 5.1 to 5.8 — including 5.6 navigation links to the functions a method calls, 5.7 XML comment tag layout (opening and closing tag each on its own line), and 5.8 code-element markup by language convention (`<paramref>`, `<see cref>`, `<c>` in XML; backticks in JSDoc and docstrings) |
|
||||
| 6 Shallow Module | smells.md group 6 |
|
||||
|
||||
Instructions for each sub agent: read only, change nothing; check every changed line and its enclosing function or class against the group's definitions and detection signals in smells.md; report each finding as `file:line`, smell name, severity (高、中、低 per the smells.md scale), one sentence of evidence, and the suggested refactoring. Findings are reported in Traditional Chinese.
|
||||
|
||||
Executable
+170
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env sh
|
||||
# swagger-detect.sh — 判斷一個專案有沒有真的啟用 Swagger(OpenAPI)文件。
|
||||
# 用法:swagger-detect.sh [專案路徑](預設目前目錄)
|
||||
#
|
||||
# 規則(雙重確認,缺一不算支援):
|
||||
# 1. 套件:在套件宣告檔裡找得到已知的 Swagger 套件。
|
||||
# 2. 設定:在原始碼裡找得到實際把 Swagger 接上去的呼叫或裝飾子。
|
||||
# 只找到套件不算支援。裝了沒啟用的專案很常見,只看套件會誤判,
|
||||
# 讓 api-doc 稽核跑在一個根本產不出文件的專案上。
|
||||
# 設定關鍵字一律挑「接線動作」,不挑 import 或 require。光是引入套件
|
||||
# 不代表文件真的掛上去了。
|
||||
#
|
||||
# 涵蓋範圍:
|
||||
# dotnet 套件 Swashbuckle.AspNetCore、NSwag.AspNetCore
|
||||
# 設定 AddSwaggerGen、UseSwagger、AddOpenApiDocument、UseOpenApi
|
||||
# nodejs 套件 swagger-ui-express、@nestjs/swagger、fastify-swagger(含 @fastify/swagger)
|
||||
# 設定 SwaggerModule.setup、swaggerUi.setup、swaggerUi.serve、
|
||||
# register 進 fastify 的 swagger 外掛
|
||||
# python 套件 fastapi、flasgger、drf-spectacular
|
||||
# 設定 FastAPI( 建立 app、Swagger( 掛上 flasgger、SPECTACULAR_SETTINGS、
|
||||
# SpectacularAPIView
|
||||
#
|
||||
# 輸出(純文字,一行一個 key=value,呼叫端逐行讀就好):
|
||||
# 第一行永遠是 support=yes 或 support=no。
|
||||
# 之後每一組偵測到套件的技術棧輸出三行:
|
||||
# stack=dotnet|nodejs|python
|
||||
# package=命中的套件名,多個以半形逗號相連
|
||||
# config=命中的設定關鍵字,多個以半形逗號相連;沒命中就是空字串
|
||||
# 一個套件都沒找到時只有 support=no 一行。
|
||||
# 範例:
|
||||
# support=yes
|
||||
# stack=dotnet
|
||||
# package=Swashbuckle.AspNetCore
|
||||
# config=AddSwaggerGen,UseSwagger
|
||||
#
|
||||
# 結束碼:
|
||||
# 0 支援(至少一個技術棧同時命中套件與設定)
|
||||
# 1 不支援(沒有任何技術棧同時命中)
|
||||
# 2 參數個數不對、專案路徑不存在,或環境缺 grep
|
||||
#
|
||||
# 護欄:
|
||||
# 掃描一律跳過 node_modules、.git、bin、obj、dist、build、venv、.venv、
|
||||
# __pycache__、packages、vendor,避免把相依套件自己的原始碼當成專案設定。
|
||||
# 錯誤訊息一律印繁中到 stderr,正常輸出只走 stdout。
|
||||
set -u
|
||||
|
||||
if [ "$#" -gt 1 ]; then
|
||||
echo "用法:swagger-detect.sh [專案路徑]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
DIR="${1:-.}"
|
||||
|
||||
[ -d "$DIR" ] || { echo "錯誤:找不到專案路徑 $DIR。請確認路徑後重試。" >&2; exit 2; }
|
||||
command -v grep >/dev/null 2>&1 || { echo "錯誤:環境缺 grep,無法掃描。" >&2; exit 2; }
|
||||
|
||||
EX1=--exclude-dir=node_modules
|
||||
EX2=--exclude-dir=.git
|
||||
EX3=--exclude-dir=bin
|
||||
EX4=--exclude-dir=obj
|
||||
EX5=--exclude-dir=dist
|
||||
EX6=--exclude-dir=build
|
||||
EX7=--exclude-dir=venv
|
||||
EX8=--exclude-dir=.venv
|
||||
EX9=--exclude-dir=__pycache__
|
||||
EX10=--exclude-dir=packages
|
||||
EX11=--exclude-dir=vendor
|
||||
|
||||
# scan <延伸正規表示式> <副檔名樣式…>:命中回 0,沒命中回 1。
|
||||
scan() {
|
||||
pattern="$1"
|
||||
shift
|
||||
for inc in "$@"; do
|
||||
if grep -R -l -E -i \
|
||||
"$EX1" "$EX2" "$EX3" "$EX4" "$EX5" "$EX6" \
|
||||
"$EX7" "$EX8" "$EX9" "$EX10" "$EX11" \
|
||||
--include="$inc" -e "$pattern" "$DIR" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# append <既有清單> <新項目>:以半形逗號相連後印出。
|
||||
append() {
|
||||
if [ -z "$1" ]; then
|
||||
printf '%s' "$2"
|
||||
else
|
||||
printf '%s,%s' "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
SUPPORT=no
|
||||
RECORDS=""
|
||||
|
||||
# collect <技術棧> <套件清單> <設定清單>:有套件才留紀錄,兩者都有才算支援。
|
||||
collect() {
|
||||
[ -n "$2" ] || return 0
|
||||
RECORDS="${RECORDS}stack=$1
|
||||
package=$2
|
||||
config=$3
|
||||
"
|
||||
[ -n "$3" ] && SUPPORT=yes
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── dotnet ────────────────────────────────────────────────────────────────
|
||||
DOTNET_PKG=""
|
||||
DOTNET_CFG=""
|
||||
for pkg in 'Swashbuckle\.AspNetCore:Swashbuckle.AspNetCore' 'NSwag\.AspNetCore:NSwag.AspNetCore'; do
|
||||
if scan "${pkg%%:*}" '*.csproj' '*.fsproj' '*.vbproj' '*.props' 'packages.config'; then
|
||||
DOTNET_PKG=$(append "$DOTNET_PKG" "${pkg##*:}")
|
||||
fi
|
||||
done
|
||||
if [ -n "$DOTNET_PKG" ]; then
|
||||
for cfg in AddSwaggerGen UseSwagger AddOpenApiDocument UseOpenApi; do
|
||||
if scan "$cfg" '*.cs' '*.fs' '*.vb'; then
|
||||
DOTNET_CFG=$(append "$DOTNET_CFG" "$cfg")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
collect dotnet "$DOTNET_PKG" "$DOTNET_CFG"
|
||||
|
||||
# ── nodejs ────────────────────────────────────────────────────────────────
|
||||
NODE_PKG=""
|
||||
NODE_CFG=""
|
||||
for pkg in swagger-ui-express @nestjs/swagger fastify-swagger @fastify/swagger; do
|
||||
if scan "\"$pkg\"" 'package.json'; then
|
||||
NODE_PKG=$(append "$NODE_PKG" "$pkg")
|
||||
fi
|
||||
done
|
||||
if [ -n "$NODE_PKG" ]; then
|
||||
# 每一項都是「接線動作」:掛路由或註冊外掛,不是 import。
|
||||
for cfg in 'SwaggerModule\.setup:SwaggerModule.setup' \
|
||||
'swaggerUi\.setup:swaggerUi.setup' \
|
||||
'swaggerUi\.serve:swaggerUi.serve' \
|
||||
'register\(.*swagger:register(swagger)'; do
|
||||
if scan "${cfg%%:*}" '*.js' '*.mjs' '*.cjs' '*.ts'; then
|
||||
NODE_CFG=$(append "$NODE_CFG" "${cfg##*:}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
collect nodejs "$NODE_PKG" "$NODE_CFG"
|
||||
|
||||
# ── python ────────────────────────────────────────────────────────────────
|
||||
PY_PKG=""
|
||||
PY_CFG=""
|
||||
for pkg in fastapi flasgger drf-spectacular; do
|
||||
if scan "$pkg" 'requirements*.txt' 'pyproject.toml' 'Pipfile' 'setup.py' 'setup.cfg'; then
|
||||
PY_PKG=$(append "$PY_PKG" "$pkg")
|
||||
fi
|
||||
done
|
||||
if [ -n "$PY_PKG" ]; then
|
||||
for cfg in 'FastAPI\(:FastAPI(' \
|
||||
'Swagger\(:Swagger(' \
|
||||
'SPECTACULAR_SETTINGS:SPECTACULAR_SETTINGS' \
|
||||
'SpectacularAPIView:SpectacularAPIView'; do
|
||||
if scan "${cfg%%:*}" '*.py'; then
|
||||
PY_CFG=$(append "$PY_CFG" "${cfg##*:}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
collect python "$PY_PKG" "$PY_CFG"
|
||||
|
||||
# ── 輸出 ──────────────────────────────────────────────────────────────────
|
||||
echo "support=$SUPPORT"
|
||||
[ -n "$RECORDS" ] && printf '%s' "$RECORDS"
|
||||
|
||||
[ "$SUPPORT" = yes ] && exit 0
|
||||
exit 1
|
||||
Reference in New Issue
Block a user