Normalize a CLI target into a repo-relative POSIX-style path/pattern. Examples -------- .\\docs\\a.md -> docs/a.md ./docs/a.md -> docs/a.md docs\\gui\\ -> docs/gui /abs/path/in/repo/a.md -> docs/a.md (if inside repo)
(spec: str, repo_root: Path)
| 218 | # Helpers |
| 219 | # ----------------------------- |
| 220 | def normalize_target_spec(spec: str, repo_root: Path) -> str: |
| 221 | """ |
| 222 | Normalize a CLI target into a repo-relative POSIX-style path/pattern. |
| 223 | |
| 224 | Examples |
| 225 | -------- |
| 226 | .\\docs\\a.md -> docs/a.md |
| 227 | ./docs/a.md -> docs/a.md |
| 228 | docs\\gui\\ -> docs/gui |
| 229 | /abs/path/in/repo/a.md -> docs/a.md (if inside repo) |
| 230 | """ |
| 231 | s = spec.strip() |
| 232 | if not s: |
| 233 | return s |
| 234 | |
| 235 | # Normalize slashes first so Windows-style input works everywhere |
| 236 | s = s.replace("\\", "/") |
| 237 | |
| 238 | # Strip leading ./ repeatedly |
| 239 | while s.startswith("./"): |
| 240 | s = s[2:] |
| 241 | |
| 242 | # If absolute and inside repo, make it repo-relative |
| 243 | p = Path(s) |
| 244 | if p.is_absolute(): |
| 245 | try: |
| 246 | s = str(p.resolve().relative_to(repo_root)).replace(os.sep, "/") |
| 247 | except ValueError: |
| 248 | # Outside repo: keep normalized absolute text so it can fail validation cleanly |
| 249 | s = str(p).replace(os.sep, "/") |
| 250 | |
| 251 | # Collapse repeated slashes |
| 252 | s = re.sub(r"/+", "/", s) |
| 253 | |
| 254 | # Remove trailing slash for canonical matching |
| 255 | if len(s) > 1: |
| 256 | s = s.rstrip("/") |
| 257 | |
| 258 | return s |
| 259 | |
| 260 | |
| 261 | def compile_target_specs(targets: list[str] | None, repo_root: Path) -> list[TargetSpec] | None: |
no outgoing calls
no test coverage detected