OncoLit: a multi-tenant oncology literature search, feed, and collaboration platform. Built with FastAPI + Vue 3 + PostgreSQL. Includes PubMed pipeline, drug approvals, AI summaries, and systematic review tools.
166 lines
4.9 KiB
Python
166 lines
4.9 KiB
Python
"""
|
|
Find sky-btn NButton tags that still lack <template #icon>.
|
|
Writes report to a file to avoid terminal encoding issues.
|
|
"""
|
|
import re, os, sys
|
|
|
|
SRC = 'd:/ClaudeCode/frontend/src'
|
|
OUT = 'd:/ClaudeCode/frontend/src/sky_btn_report.txt'
|
|
|
|
def find_sky_btn_gaps(content):
|
|
template_start = content.find('<template>')
|
|
if template_start < 0:
|
|
m = re.search(r'<template\b[^>]*>', content)
|
|
if not m:
|
|
return []
|
|
template_start = m.start()
|
|
template_end = content.rfind('</template>')
|
|
if template_end < 0:
|
|
return []
|
|
template_end += len('</template>')
|
|
|
|
template = content[template_start:template_end]
|
|
results = []
|
|
|
|
for m in re.finditer(r'<[Nn][-]?[Bb]utton\b', template):
|
|
tag_start = m.start()
|
|
in_dq = False
|
|
in_sq = False
|
|
for i in range(tag_start):
|
|
ch = template[i]
|
|
if ch == '\\':
|
|
continue
|
|
if ch == '"' and not in_sq:
|
|
in_dq = not in_dq
|
|
elif ch == "'" and not in_dq:
|
|
in_sq = not in_sq
|
|
if in_dq or in_sq:
|
|
continue
|
|
|
|
pos = m.end()
|
|
in_dq = False
|
|
in_sq = False
|
|
tag_end = -1
|
|
while pos < len(template):
|
|
ch = template[pos]
|
|
if ch == '\\':
|
|
pos += 2
|
|
continue
|
|
if ch == '"' and not in_sq:
|
|
in_dq = not in_dq
|
|
elif ch == "'" and not in_dq:
|
|
in_sq = not in_sq
|
|
elif ch == '>' and not in_dq and not in_sq:
|
|
tag_end = pos + 1
|
|
break
|
|
pos += 1
|
|
if tag_end < 0:
|
|
continue
|
|
|
|
tag_text = template[tag_start:tag_end]
|
|
if 'sky-btn' not in tag_text:
|
|
continue
|
|
|
|
# Check if already has icon template
|
|
if '/>' in tag_text:
|
|
continue
|
|
rest = template[tag_end:]
|
|
# find matching close
|
|
depth = 0
|
|
p = 0
|
|
while p < len(rest):
|
|
if re.match(r'<[Nn][-]?[Bb]utton\b', rest[p:]):
|
|
depth += 1
|
|
p += 1
|
|
continue
|
|
cm = re.match(r'</[Nn][-]?[Bb]utton\s*>', rest[p:])
|
|
if cm:
|
|
if depth == 0:
|
|
break
|
|
depth -= 1
|
|
p += cm.end()
|
|
continue
|
|
p += 1
|
|
content_before_close = rest[:p]
|
|
if re.search(r'<template\s+#icon\b', content_before_close):
|
|
continue
|
|
if re.search(r'<template\s+v-slot:icon\b', content_before_close):
|
|
continue
|
|
|
|
# text prop
|
|
stripped = re.sub(r'"[^"]*"', '', tag_text)
|
|
stripped = re.sub(r"'[^']*'", '', stripped)
|
|
has_text_prop = False
|
|
for tp in re.finditer(r'\btext\b', stripped):
|
|
pre = stripped[tp.start()-1] if tp.start() > 0 else ' '
|
|
if pre in (' ', '\t', '\n', '\r', '>'):
|
|
has_text_prop = True
|
|
break
|
|
if has_text_prop:
|
|
continue
|
|
|
|
if re.search(r'\bsize\s*=\s*"(tiny|mini)"', tag_text):
|
|
continue
|
|
|
|
qm = re.search(r'\bquaternary\b', tag_text)
|
|
if qm and (qm.start() == 0 or tag_text[qm.start()-1] != ':'):
|
|
continue
|
|
|
|
# Extract text
|
|
if '/>' in tag_text:
|
|
continue
|
|
depth = 0
|
|
p = 0
|
|
while p < len(rest):
|
|
if re.match(r'<[Nn][-]?[Bb]utton\b', rest[p:]):
|
|
depth += 1
|
|
p += 1
|
|
continue
|
|
cm = re.match(r'</[Nn][-]?[Bb]utton\s*>', rest[p:])
|
|
if cm:
|
|
if depth == 0:
|
|
break
|
|
depth -= 1
|
|
p += cm.end()
|
|
continue
|
|
p += 1
|
|
text = re.sub(r'<[^>]+>', '', rest[:p]).strip()
|
|
if not text:
|
|
continue
|
|
|
|
results.append((tag_start, tag_text, text))
|
|
|
|
return results
|
|
|
|
|
|
def main():
|
|
lines = []
|
|
total_gaps = 0
|
|
for root, dirs, files in os.walk(SRC):
|
|
for f in sorted(files):
|
|
if not f.endswith('.vue'):
|
|
continue
|
|
filepath = os.path.join(root, f)
|
|
with open(filepath, 'r', encoding='utf-8') as fh:
|
|
content = fh.read()
|
|
if 'sky-btn' not in content:
|
|
continue
|
|
gaps = find_sky_btn_gaps(content)
|
|
if gaps:
|
|
rel = os.path.relpath(filepath, SRC)
|
|
lines.append(f'\n{rel} ({len(gaps)} buttons):')
|
|
total_gaps += len(gaps)
|
|
for _, tag_text, btn_text in gaps:
|
|
lines.append(f' btn_text="{btn_text}"')
|
|
lines.append(f' tag_text={tag_text[:80]}')
|
|
lines.append('')
|
|
|
|
lines.insert(0, f'Total buttons without icons: {total_gaps}')
|
|
report = '\n'.join(lines)
|
|
with open(OUT, 'w', encoding='utf-8') as f:
|
|
f.write(report)
|
|
print(f'Report written to {OUT}')
|
|
|
|
if __name__ == '__main__':
|
|
main()
|