Files
backend/add_skybtn.py
34047007@qq.com a6cd99a4ca
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
feat: initial commit - oncology literature search platform
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.
2026-07-27 07:59:18 +08:00

142 lines
4.8 KiB
Python

import re
import os
import sys
def is_text_prop(tag_str):
"""Check if the NButton tag has the `text` prop (bare, :text, or v-bind:text)."""
# Remove attribute values to avoid false positives
cleaned = re.sub(r'"[^"]*"', '', tag_str)
cleaned = re.sub(r"'[^']*'", '', cleaned)
return bool(re.search(r'(?:^|[\s>])(?::text|v-bind:text|text)(?=[\s=>/]|$)', cleaned))
def has_dynamic_class(tag_str):
"""Check if the tag uses :class or v-bind:class (dynamic class binding)."""
cleaned = re.sub(r'"[^"]*"', '', tag_str)
cleaned = re.sub(r"'[^']*'", '', cleaned)
return bool(re.search(r'(?::class|v-bind:class)\s*=', cleaned))
def has_skybtn_class(tag_str):
"""Check if the tag already has sky-btn in its class attribute value."""
for m in re.finditer(r'class\s*=\s*"([^"]*)"', tag_str):
if 'sky-btn' in m.group(1):
return True
for m in re.finditer(r"class\s*=\s*'([^']*)'", tag_str):
if 'sky-btn' in m.group(1):
return True
return False
def add_skybtn_to_tag(tag_str):
"""Add class="sky-btn" or append sky-btn to existing class."""
# Check for existing class="..."
m = re.search(r'class\s*=\s*"([^"]*)"', tag_str)
if m:
old_class = m.group(1).strip()
new_class = (old_class + ' sky-btn') if old_class else 'sky-btn'
return tag_str[:m.start(1)] + new_class + tag_str[m.end(1):]
# Check for existing class='...'
m = re.search(r"class\s*=\s*'([^']*)'", tag_str)
if m:
old_class = m.group(1).strip()
new_class = (old_class + ' sky-btn') if old_class else 'sky-btn'
return tag_str[:m.start(1)] + new_class + tag_str[m.end(1):]
# No class attribute, add before closing >
# Find the outermost > that closes the tag
if tag_str.rstrip().endswith('/>'):
insert_pos = tag_str.rstrip().rfind('/>')
prefix = tag_str[:insert_pos].rstrip()
suffix = tag_str[insert_pos:]
return prefix + ' class="sky-btn" ' + suffix.lstrip()
else:
insert_pos = tag_str.rstrip().rfind('>')
prefix = tag_str[:insert_pos].rstrip()
suffix = tag_str[insert_pos:]
return prefix + ' class="sky-btn"' + suffix
def process_vue_file(filepath):
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
print(f" Error reading {filepath}: {e}", file=sys.stderr)
return False
# Find the template section
template_start_match = re.search(r'<template>', content)
if not template_start_match:
return False
template_end_match = re.search(r'</template>', content)
if not template_end_match:
return False
template_start = template_start_match.start()
template_end = template_end_match.end()
template_section = content[template_start:template_end]
before = content[:template_start]
after = content[template_end:]
# Match NButton/n-button opening tags with attribute-aware regex
tag_pattern = r'<([Nn]-[Bb]utton)\b((?:[^>"\']|"[^"]*"|\'[^\']*\')*)\s*/?>'
modified_sections = []
last_end = 0
modified_count = 0
for m in re.finditer(tag_pattern, template_section):
modified_sections.append(template_section[last_end:m.start()])
full_match = m.group(0)
if is_text_prop(full_match):
modified_sections.append(full_match)
elif has_dynamic_class(full_match):
modified_sections.append(full_match)
elif has_skybtn_class(full_match):
modified_sections.append(full_match)
else:
new_tag = add_skybtn_to_tag(full_match)
modified_sections.append(new_tag)
modified_count += 1
last_end = m.end()
modified_sections.append(template_section[last_end:])
if modified_count > 0:
new_template_section = ''.join(modified_sections)
new_content = before + new_template_section + after
with open(filepath, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f" Modified ({modified_count} changes): {os.path.relpath(filepath, os.getcwd())}")
return True
return False
def main():
cwd = os.getcwd()
print(f"Working directory: {cwd}")
vue_files = []
for root, dirs, files in os.walk(os.path.join(cwd, 'frontend', 'src')):
for f in files:
if f.endswith('.vue'):
vue_files.append(os.path.join(root, f))
print(f"Found {len(vue_files)} Vue files")
changed_files = []
for filepath in sorted(vue_files):
if process_vue_file(filepath):
changed_files.append(filepath)
print(f"\nTotal files modified: {len(changed_files)}")
for fp in changed_files:
print(f" {os.path.relpath(fp, cwd)}")
return len(changed_files)
if __name__ == '__main__':
main()