You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
3.6 KiB

6 days ago
# -*- coding: utf-8 -*-
# bruno-sync 全量对账(票 04 t9):源码 tags 钥匙 vs 文档仓文件夹钥匙 双向差集
# 钥匙 = (METHOD, url, tag全路径/文档文件夹相对路径)
# 修正版:注解区扫描(@Operation 可在 mapping 之前或之后),覆盖四种盲区:
# @PreAuthorize 嵌套括号 / 裸字符串 tags / 无括号 @PostMapping / @Operation 在 @PostMapping 之后
import os, sys, io, re
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
REPO = r'D:\code\crm-backend-matt'
DOCS = r'D:\code\crm-api-docs'
MODS = ['crm-auth','crm-file','crm-lead','crm-opportunity','crm-rule','crm-preference','crm-dict']
BT = chr(96)
src = {}
for m in MODS:
base = os.path.join(REPO, m, 'src', 'main', 'java')
for dp, dns, fns in os.walk(base):
for fn in sorted(fns):
if not fn.endswith('Controller.java'):
continue
txt = open(os.path.join(dp, fn), encoding='utf-8').read()
mt = re.search(r'@RequestMapping\(\s*"([^"]+)"', txt)
cls_prefix = mt.group(1) if mt else ''
ct = re.search(r'@Tag\((?:[^()]*?)name\s*=\s*"([^"]+)"', txt) or re.search(r'@Tag\(\s*"([^"]+)"', txt)
cls_tag = ct.group(1) if ct else ''
for mm in re.finditer(r'@(Get|Post|Put|Delete|Patch)Mapping(?:\(([^)]*)\))?', txt):
verb, args = mm.group(1), mm.group(2) or ''
pm = re.search(r'"([^"]*)"', args)
path = pm.group(1) if pm else ''
wstart = max(0, mm.start() - 800)
pa = re.search(r'public\s', txt[mm.end():mm.end()+600])
bend = mm.end() + (pa.start() if pa else 600)
region = txt[wstart:bend]
gs = re.findall(r'@Operation\((?:[^()]|\([^()]*\))*\)', region)
g = gs[-1] if gs else ''
mtags = []
if g:
t = re.search(r'tags\s*=\s*(\{[^}]*\}|"[^"]+")', g, re.S)
if t:
mtags = re.findall(r'"([^"]+)"', t.group(1))
tags = mtags if mtags else ([cls_tag] if cls_tag else [])
url = cls_prefix + path
for t in tags:
src.setdefault((verb.upper(), url, t), []).append(fn)
doc = {}
for dp, dns, fns in os.walk(DOCS):
dns[:] = [d for d in dns if d.lower() != 'environments']
rel = os.path.relpath(dp, DOCS).replace('\\', '/')
tag = '' if rel == '.' else rel
for fn in sorted(fns):
if not fn.endswith('.bru') or fn in ('folder.bru', 'collection.bru'):
continue
txt = open(os.path.join(dp, fn), encoding='utf-8').read()
mv = re.search(r'^[ \t]*(get|post|put|delete|patch)[ \t]*\{', txt, re.M | re.I)
if not mv:
continue
verb = mv.group(1).upper()
ul = re.search(r'url:[^\n]*', txt)
if not ul:
continue
u = ul.group(0).split(':', 1)[1].strip()
if u.startswith(BT) and u.endswith(BT):
u = u[1:-1]
u = re.sub(r'\{\{[^}]*\}\}', '', u).strip()
u = re.sub(r'^https?://[^/\s]+', '', u).strip()
u = re.sub(r'^/crm-api(?=/api/)', '', u).strip()
u = u.split('?', 1)[0].strip()
doc.setdefault((verb, u, tag), []).append(fn)
miss_doc = sorted(set(src) - set(doc))
miss_src = sorted(set(doc) - set(src))
print('src keys:', len(src), '; doc keys:', len(doc))
print('--- doc-has-src-missing', len(miss_doc), '---')
for k in miss_doc:
print(' | '.join(k), ' <=', ','.join(src[k]))
print('--- src-has-doc-missing', len(miss_src), '---')
for k in miss_src:
print(' | '.join(k), ' <=', ','.join(doc[k]))