-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex_md.py
More file actions
147 lines (113 loc) · 5.88 KB
/
Copy pathindex_md.py
File metadata and controls
147 lines (113 loc) · 5.88 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import click
import afterpython as ap
from afterpython.const import CONTENT_TYPES, PLACEHOLDER_INDEX_MARKER
def _placeholder_content(content_type: str) -> str:
"""Current placeholder body. Marker is an HTML comment so it embeds invisibly;
_is_afterpython_placeholder_index keys off it to tell our files apart from
user-authored ones."""
return f"""{PLACEHOLDER_INDEX_MARKER}
# Welcome to AfterPython
Welcome to your project's {content_type}! This is a starter page to help you get started.
## Getting Started
Replace this placeholder content with your own. Here's what you can do:
- Creating new `.md` or `.ipynb` files in the `afterpython/{content_type}/` directory
- Writing in MyST Markdown format
- Adding images to the `afterpython/static/` directory and referencing them
## Resources
- [AfterPython's Project Website](https://afterpython.afterpython.org)
- [MyST Markdown Guide](https://mystmd.org)
Start building your amazing project! 🚀
"""
def _legacy_placeholder_content(content_type: str) -> str:
"""Frozen fingerprint of the arrow-stub placeholder written between commits
49f30c1 and 3a560e2 (no marker). Kept solely so projects built in that window
are still recognized as ours and cleaned up rather than blocking with the
'reserved' error. Do not edit — that would break recognition."""
return f"""---
title: ← {content_type.capitalize()}
---
This is a placeholder index page. The actual {content_type} landing page is rendered by SvelteKit.
"""
def _is_afterpython_placeholder_index(index_md, content_type: str) -> bool:
"""Return True only for non-doc index.md files generated by AfterPython."""
content = index_md.read_text(encoding="utf-8", errors="ignore")
normalized_content = content.strip()
return (
PLACEHOLDER_INDEX_MARKER in content
or normalized_content == _legacy_placeholder_content(content_type).strip()
)
def create_placeholder_index_md_files():
"""Create placeholder index.md files for non-doc content types.
Without these placeholders, MyST treats the first file in TOC as index,
causing it to use routes like /blog instead of /blog/blog1. These routes
are reserved for SvelteKit landing pages. Placeholders ensure all actual
content files get proper slugs and are deleted post-build.
"""
from afterpython._io.yaml import read_yaml, write_yaml
from afterpython.tools.myst import _write_index_file
for content_type in CONTENT_TYPES:
if content_type == "doc":
continue # Doc doesn't need a placeholder index.md
content_path = ap.paths.afterpython_path / content_type
if not content_path.exists():
click.echo(
f"No content found in {content_path}, skip creating placeholder index.md"
)
continue
myst_yml_path = content_path / "myst.yml"
if not myst_yml_path.exists():
click.echo(
f"No myst.yml found in {content_path}, skip creating placeholder index.md"
)
continue
_write_index_file(content_type)
# Prepend index.md to TOC in myst.yml (skip if already first).
myst_data = read_yaml(myst_yml_path) or {}
toc = myst_data.get("project", {}).get("toc", [])
if not toc or toc[0].get("file") != "index.md":
myst_data.setdefault("project", {})["toc"] = [{"file": "index.md"}, *toc]
write_yaml(myst_yml_path, myst_data)
click.echo(f"Added index.md to TOC in {myst_yml_path}")
def delete_placeholder_index_md_files():
"""Delete placeholder index.md and built index.html for non-doc content types.
These files were created pre-build to ensure proper slug generation. Now that
MyST has built the content with correct slugs, we delete them so SvelteKit
can own the landing page routes (/blog, /tutorial, etc.) in the project website.
"""
from afterpython._io.yaml import read_yaml, write_yaml
for content_type in CONTENT_TYPES:
if content_type == "doc":
continue # Doc doesn't need a placeholder index.md
content_path = ap.paths.afterpython_path / content_type
myst_yml_path = content_path / "myst.yml"
index_md = content_path / "index.md"
# Delete index.md from source only when it is an AfterPython-generated placeholder.
if index_md.exists():
if not _is_afterpython_placeholder_index(index_md, content_type):
raise click.ClickException(
f"Found existing 'afterpython/{content_type}/index.md'.\n"
f"\n"
f"'afterpython/{content_type}/index.md' is reserved for internal use by AfterPython.\n"
f"The '/{content_type}' route is owned by the SvelteKit listing page,\n"
f"so user-authored non-doc index.md files are not supported.\n"
f"\n"
f"Please rename this file to something else "
f"(e.g., '{content_type}_intro.md') and update the reference in "
f"afterpython/{content_type}/myst.yml."
)
index_md.unlink()
click.echo(f"Deleted placeholder: {index_md}")
# Delete index.html from build output
index_html = content_path / "_build" / "html" / "index.html"
if index_html.exists():
index_html.unlink()
click.echo(f"Deleted: {index_html}")
# Remove index.md from TOC in myst.yml
if myst_yml_path.exists():
myst_data = read_yaml(myst_yml_path) or {}
toc = myst_data.get("project", {}).get("toc", [])
# Remove index.md from TOC if it's the first entry
if toc and toc[0].get("file") == "index.md":
myst_data["project"]["toc"] = toc[1:]
write_yaml(myst_yml_path, myst_data)
click.echo(f"Removed index.md from TOC in {myst_yml_path}")