(article_path: Path, target: str, *, staged: bool, root: Path)
| 257 | |
| 258 | |
| 259 | def local_image_issue(article_path: Path, target: str, *, staged: bool, root: Path) -> str | None: |
| 260 | split = urlsplit(target) |
| 261 | if split.scheme == "file": |
| 262 | return "uses a file:// image URL; use a repo-relative path or remote URL" |
| 263 | if split.scheme: |
| 264 | return f"uses unsupported image URL scheme: {split.scheme}" |
| 265 | |
| 266 | path_text = unquote(split.path) |
| 267 | if not path_text: |
| 268 | return "image target is empty" |
| 269 | if "\0" in path_text: |
| 270 | return "image target contains a null byte" |
| 271 | if looks_like_local_absolute_path(path_text): |
| 272 | return "uses an absolute local filesystem path; use a repo-relative image path" |
| 273 | |
| 274 | candidate = root / path_text.lstrip("/") if path_text.startswith("/") else article_path.parent / path_text |
| 275 | relative = repo_relative(candidate, root) |
| 276 | if relative is None: |
| 277 | return "local image points outside the repository" |
| 278 | |
| 279 | if staged: |
| 280 | if index_has_file(relative): |
| 281 | return None |
| 282 | if candidate.exists(): |
| 283 | return f"local image exists but is not staged: {relative.as_posix()}" |
| 284 | return f"local image file not found: {relative.as_posix()}" |
| 285 | |
| 286 | if not candidate.is_file(): |
| 287 | return f"local image file not found: {relative.as_posix()}" |
| 288 | return None |
| 289 | |
| 290 | |
| 291 | def remote_image_issue(url: str, timeout: float) -> str | None: |
no test coverage detected