#AI
zhou zhou
3 天以前 e6369c9b64a82eeada6b6f0658d2ae786787e101
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python3
"""Locate likely RSF backend files for a feature/module keyword.
 
Usage:
    python skills/rsf-server-maintainer/scripts/locate_module.py basStation
    python skills/rsf-server-maintainer/scripts/locate_module.py order --repo C:/env/code/wms-master/rsf-server
"""
 
from __future__ import annotations
 
import argparse
import re
from pathlib import Path
from typing import Iterable, List, Tuple
 
 
def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Locate related controller/service/mapper/entity/XML files by keyword.")
    parser.add_argument("keyword", help="Module keyword, for example: basStation, order, user")
    parser.add_argument(
        "--repo",
        default=str(Path(__file__).resolve().parents[3]),
        help="Path to rsf-server repository root (default: auto-detect from script location)",
    )
    parser.add_argument(
        "--limit",
        type=int,
        default=80,
        help="Max results per section (default: 80)",
    )
    return parser.parse_args()
 
 
def normalize_keyword(value: str) -> str:
    return value.strip().lower()
 
 
def collect_files(root: Path, patterns: Iterable[str]) -> List[Path]:
    files: List[Path] = []
    for pattern in patterns:
        files.extend(root.glob(pattern))
    return [p for p in files if p.is_file()]
 
 
def find_name_matches(files: Iterable[Path], keyword: str) -> List[Path]:
    matches = []
    for file in files:
        text = str(file).lower()
        if keyword in text:
            matches.append(file)
    return sorted(set(matches))
 
 
def find_line_matches(files: Iterable[Path], keyword: str, pattern: re.Pattern[str]) -> List[Tuple[Path, int, str]]:
    out: List[Tuple[Path, int, str]] = []
    for file in files:
        try:
            content = file.read_text(encoding="utf-8", errors="ignore").splitlines()
        except OSError:
            continue
        for index, line in enumerate(content, start=1):
            lower = line.lower()
            if keyword in lower and pattern.search(line):
                out.append((file, index, line.strip()))
    return out
 
 
def print_file_section(title: str, repo: Path, files: List[Path], limit: int) -> None:
    print(f"\n[{title}] {len(files)}")
    for path in files[:limit]:
        rel = path.relative_to(repo)
        print(f"  - {rel.as_posix()}")
    if len(files) > limit:
        print(f"  ... ({len(files) - limit} more)")
 
 
def print_line_section(title: str, repo: Path, rows: List[Tuple[Path, int, str]], limit: int) -> None:
    print(f"\n[{title}] {len(rows)}")
    for file, line_no, line in rows[:limit]:
        rel = file.relative_to(repo)
        print(f"  - {rel.as_posix()}:{line_no}: {line}")
    if len(rows) > limit:
        print(f"  ... ({len(rows) - limit} more)")
 
 
def main() -> int:
    args = parse_args()
    repo = Path(args.repo).resolve()
    keyword = normalize_keyword(args.keyword)
 
    if not keyword:
        raise SystemExit("keyword must not be empty")
 
    java_root = repo / "src/main/java/com/vincent/rsf/server"
    mapper_root = repo / "src/main/resources/mapper"
 
    if not java_root.exists() or not mapper_root.exists():
        raise SystemExit(f"Invalid repo root for rsf-server: {repo}")
 
    java_files = collect_files(
        repo,
        [
            "src/main/java/com/vincent/rsf/server/**/*.java",
            "src/main/resources/mapper/**/*.xml",
        ],
    )
 
    name_matches = find_name_matches(java_files, keyword)
 
    controller_files = collect_files(repo, ["src/main/java/com/vincent/rsf/server/**/controller/**/*.java"])
    mapping_pattern = re.compile(r"@(RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping)")
    authority_pattern = re.compile(r"@PreAuthorize")
 
    endpoint_rows = find_line_matches(controller_files, keyword, mapping_pattern)
    authority_rows = find_line_matches(controller_files, keyword, authority_pattern)
 
    print(f"repo: {repo}")
    print(f"keyword: {keyword}")
 
    print_file_section("Path matches", repo, name_matches, args.limit)
    print_line_section("Endpoint annotation matches", repo, endpoint_rows, args.limit)
    print_line_section("Authority annotation matches", repo, authority_rows, args.limit)
 
    return 0
 
 
if __name__ == "__main__":
    raise SystemExit(main())