|
26 | 26 | ``` |
27 | 27 | <!-- /snippet-source --> |
28 | 28 |
|
| 29 | +Path-less region markers (for src/ files only): |
| 30 | +
|
| 31 | + <!-- snippet-source #region_name --> |
| 32 | + ```python |
| 33 | + # content replaced by script |
| 34 | + ``` |
| 35 | + <!-- /snippet-source --> |
| 36 | +
|
| 37 | + The companion file path is derived from the target file's location: |
| 38 | + src/mcp/foo/bar.py → examples/snippets/docstrings/mcp/foo/bar.py |
| 39 | +
|
29 | 40 | The code fence language is inferred from the source file extension. |
30 | 41 |
|
31 | 42 | Region markers in example files: |
|
36 | 47 |
|
37 | 48 | Path resolution: |
38 | 49 | - All paths are relative to the repository root |
| 50 | +- Path-less markers (#region) resolve via: src/X → COMPANION_BASE/X |
39 | 51 |
|
40 | 52 | Usage: |
41 | 53 | uv run python scripts/sync_snippets.py # Sync all snippets |
|
64 | 76 | REGION_START_PATTERN = re.compile(r"^(?P<indent>\s*)# region (?P<name>\S+)\s*$") |
65 | 77 | REGION_END_PATTERN = re.compile(r"^\s*# endregion (?P<name>\S+)\s*$") |
66 | 78 |
|
| 79 | +# Base directory for companion example files (relative to repo root). |
| 80 | +COMPANION_BASE = Path("examples/snippets/docstrings") |
| 81 | + |
| 82 | +# Source prefix stripped when deriving companion paths. |
| 83 | +SOURCE_PREFIX = Path("src") |
| 84 | + |
67 | 85 |
|
68 | 86 | def find_repo_root() -> Path: |
69 | 87 | """Find the repository root by looking for pyproject.toml.""" |
@@ -148,6 +166,28 @@ def __init__(self, repo_root: Path) -> None: |
148 | 166 | self._file_cache: dict[str, str] = {} |
149 | 167 | self._region_cache: dict[str, str] = {} |
150 | 168 |
|
| 169 | + def derive_companion_path(self, target_file: Path) -> str: |
| 170 | + """Derive the companion example file path from a source file path. |
| 171 | +
|
| 172 | + Maps src/mcp/X → examples/snippets/docstrings/mcp/X |
| 173 | + """ |
| 174 | + rel = target_file.relative_to(self.repo_root) |
| 175 | + try: |
| 176 | + sub = rel.relative_to(SOURCE_PREFIX) |
| 177 | + except ValueError: |
| 178 | + raise ValueError( |
| 179 | + f"Cannot derive companion path for {rel}: " |
| 180 | + f"path-less #region markers are only supported in {SOURCE_PREFIX}/ files" |
| 181 | + ) from None |
| 182 | + return str(COMPANION_BASE / sub) |
| 183 | + |
| 184 | + def resolve_source_ref(self, source_ref: str, target_file: Path) -> str: |
| 185 | + """Resolve a source reference, expanding path-less #region markers.""" |
| 186 | + if source_ref.startswith("#"): |
| 187 | + companion = self.derive_companion_path(target_file) |
| 188 | + return f"{companion}{source_ref}" |
| 189 | + return source_ref |
| 190 | + |
151 | 191 | def get_file_content(self, resolved_path: Path) -> str: |
152 | 192 | """Get file content, using cache.""" |
153 | 193 | key = str(resolved_path) |
@@ -188,15 +228,16 @@ def replace_snippet(match: re.Match[str]) -> str: |
188 | 228 | source_ref = match.group("source") |
189 | 229 |
|
190 | 230 | try: |
191 | | - code = self.get_source_content(source_ref) |
| 231 | + resolved_ref = self.resolve_source_ref(source_ref, file_path) |
| 232 | + code = self.get_source_content(resolved_ref) |
192 | 233 | except (FileNotFoundError, ValueError) as e: |
193 | 234 | result.errors.append(f"{file_path}: {e}") |
194 | 235 | return match.group(0) |
195 | 236 |
|
196 | 237 | result.snippets_processed += 1 |
197 | 238 |
|
198 | 239 | # Infer language from file extension |
199 | | - raw_path = source_ref.split("#")[0] |
| 240 | + raw_path = resolved_ref.split("#")[0] |
200 | 241 | ext = Path(raw_path).suffix.lstrip(".") |
201 | 242 | lang = {"py": "python", "yml": "yaml"}.get(ext, ext) |
202 | 243 |
|
|
0 commit comments