Files
longbridge__developers/script/audit_api_docs.py
Sunli 5accb00f24 docs: Longbridge SDK docs update (branding, 4.0.0, Go examples) (#356)
## Summary
- **Branding & version**: SDK 页与文档统一为 longbridge 品牌、版本 4.0.0,修正仓库与包地址
- **Getting started**: 更新 API Host、OAuth 示例与 4.0.0,修正 typo(开发中 → 开发者)
- **Request examples**: 为所有 API 请求示例补充多语言
tabs(Python/Node/Java/Rust/C++),并增加 Go SDK 示例(en / zh-CN / zh-HK)
- **Dependencies**: 更新 package.json 与 bun.lock

Made with [Cursor](https://cursor.com)
2026-03-11 11:34:49 +08:00

118 lines
3.7 KiB
Python

#!/usr/bin/env python3
import re
import json
import requests
from pathlib import Path
from collections import defaultdict
ROOT = Path(__file__).resolve().parents[1]
DOCS = ROOT / 'docs'
LOCALES = ['en', 'zh-CN', 'zh-HK']
METHOD_RE = re.compile(r'HTTP Method</td><td>\s*([^<\n]+)', re.I)
URL_RE = re.compile(r'HTTP URL</td><td>\s*([^<\n]+)', re.I)
TITLE_RE = re.compile(r'^title:\s*(.+)$', re.M)
def collect(locale):
rows = []
for p in (DOCS / locale / 'docs').rglob('*.md'):
txt = p.read_text(encoding='utf-8')
m = METHOD_RE.search(txt)
u = URL_RE.search(txt)
if not (m and u):
continue
title = (TITLE_RE.search(txt).group(1).strip().strip('"\'') if TITLE_RE.search(txt) else p.stem)
rows.append({
'locale': locale,
'method': m.group(1).strip().upper(),
'path': u.group(1).strip(),
'title': title,
'file': str(p.relative_to(ROOT)).replace('\\', '/'),
})
return rows
def check_endpoint(base, method, path):
url = base.rstrip('/') + path
try:
r = requests.request(method, url, timeout=5)
return {'status': r.status_code, 'code': None, 'message': None}
except Exception as e:
return {'status': None, 'error': str(e)}
def main():
all_rows = []
for lc in LOCALES:
all_rows.extend(collect(lc))
by_key = defaultdict(list)
for r in all_rows:
by_key[(r['method'], r['path'])].append(r)
keys = sorted(by_key.keys())
# locale parity
missing = []
for k in keys:
exists = {x['locale'] for x in by_key[k]}
for lc in LOCALES:
if lc not in exists:
missing.append({'method': k[0], 'path': k[1], 'missing_locale': lc})
# runtime existence check (non-404 means route exists)
runtime = []
for method, path in keys:
prod = check_endpoint('https://openapi.longbridge.com', method, path)
test = check_endpoint('https://openapi.longbridge.com', method, path)
runtime.append({
'method': method,
'path': path,
'prod_status': prod.get('status'),
'test_status': test.get('status')
})
out = {
'total_unique_http_apis': len(keys),
'apis': runtime,
'locale_missing': missing,
}
out_dir = ROOT / 'openapi' / 'audit'
out_dir.mkdir(parents=True, exist_ok=True)
(out_dir / 'api-audit.json').write_text(json.dumps(out, indent=2, ensure_ascii=False) + '\n', encoding='utf-8')
md = []
md.append('# API Docs Audit')
md.append('')
md.append(f'- Total unique HTTP APIs in docs: **{len(keys)}**')
md.append(f'- Locale parity gaps: **{len(missing)}**')
md.append('')
md.append('## Runtime route check (non-404 = endpoint exists)')
md.append('')
md.append('| Method | Path | openapi.longbridge.com | openapi.longbridge.com |')
md.append('| --- | --- | --- | --- |')
for r in runtime:
md.append(f"| `{r['method']}` | `{r['path']}` | `{r['prod_status']}` | `{r['test_status']}` |")
md.append('')
if missing:
md.append('## Locale parity gaps')
md.append('')
md.append('| Method | Path | Missing Locale |')
md.append('| --- | --- | --- |')
for m in missing:
md.append(f"| `{m['method']}` | `{m['path']}` | `{m['missing_locale']}` |")
else:
md.append('## Locale parity gaps')
md.append('')
md.append('No locale gaps found for currently documented HTTP APIs.')
(out_dir / 'api-audit.md').write_text('\n'.join(md) + '\n', encoding='utf-8')
print('wrote', out_dir / 'api-audit.json')
print('wrote', out_dir / 'api-audit.md')
if __name__ == '__main__':
main()