Skip to content

Commit 3a560e2

Browse files
fix: reserve and only remove placeholder index.md
1 parent 7ad04ad commit 3a560e2

7 files changed

Lines changed: 81 additions & 14 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
uses: actions/checkout@v6
125125

126126
- name: Set up pixi
127-
uses: prefix-dev/setup-pixi@v0.9.5
127+
uses: prefix-dev/setup-pixi@v0.9.6
128128
with:
129129
pixi-version: v0.67.2
130130
cache: true

pixi.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ build-backend = "uv_build"
7171
module-name = "afterpython"
7272
module-root = "src"
7373

74-
[tool.uv.sources]
75-
afterpython = { path = ".", editable = true }
74+
# [tool.uv.sources]
75+
# afterpython = { path = ".", editable = true }
7676

7777
[tool.pyright]
7878
typeCheckingMode = "basic"

src/afterpython/builders/index_md.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,50 @@
11
import click
22

33
import afterpython as ap
4-
from afterpython.const import CONTENT_TYPES
4+
from afterpython.const import CONTENT_TYPES, PLACEHOLDER_INDEX_MARKER
5+
6+
7+
def _legacy_placeholder_content(content_type: str) -> str:
8+
return f"""---
9+
title: ← {content_type.capitalize()}
10+
---
11+
12+
This is a placeholder index page. The actual {content_type} landing page is rendered by SvelteKit.
13+
"""
14+
15+
16+
def _legacy_welcome_content(content_type: str) -> str:
17+
return f"""# Welcome to AfterPython
18+
19+
Welcome to your project's {content_type}! This is a starter page to help you get started.
20+
21+
## Getting Started
22+
23+
Replace this placeholder content with your own. Here's what you can do:
24+
25+
- Creating new `.md` or `.ipynb` files in the `afterpython/{content_type}/` directory
26+
- Writing in MyST Markdown format
27+
- Adding images to the `afterpython/static/` directory and referencing them
28+
29+
## Resources
30+
31+
- [AfterPython's Project Website](https://afterpython.afterpython.org)
32+
- [MyST Markdown Guide](https://mystmd.org)
33+
34+
Start building your amazing project! 🚀
35+
"""
36+
37+
38+
def _is_afterpython_placeholder_index(index_md, content_type: str) -> bool:
39+
"""Return True only for non-doc index.md files generated by AfterPython."""
40+
content = index_md.read_text(encoding="utf-8", errors="ignore")
41+
normalized_content = content.strip()
42+
43+
return (
44+
PLACEHOLDER_INDEX_MARKER in content
45+
or normalized_content == _legacy_placeholder_content(content_type).strip()
46+
or normalized_content == _legacy_welcome_content(content_type).strip()
47+
)
548

649

750
def create_placeholder_index_md_files():
@@ -71,10 +114,23 @@ def delete_placeholder_index_md_files():
71114
myst_yml_path = content_path / "myst.yml"
72115
index_md = content_path / "index.md"
73116

74-
# Delete index.md from source
117+
# Delete index.md from source only when it is an AfterPython-generated placeholder.
75118
if index_md.exists():
119+
if not _is_afterpython_placeholder_index(index_md, content_type):
120+
raise click.ClickException(
121+
f"Found existing 'afterpython/{content_type}/index.md'.\n"
122+
f"\n"
123+
f"'afterpython/{content_type}/index.md' is reserved for internal use by AfterPython.\n"
124+
f"The '/{content_type}' route is owned by the SvelteKit listing page,\n"
125+
f"so user-authored non-doc index.md files are not supported.\n"
126+
f"\n"
127+
f"Please rename this file to something else "
128+
f"(e.g., '{content_type}_intro.md') and update the reference in "
129+
f"afterpython/{content_type}/myst.yml."
130+
)
131+
76132
index_md.unlink()
77-
click.echo(f"Deleted: {index_md}")
133+
click.echo(f"Deleted placeholder: {index_md}")
78134

79135
# Delete index.html from build output
80136
index_html = content_path / "_build" / "html" / "index.html"

src/afterpython/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
NODEENV_VERSION = "24.11.0"
44
CONTENT_TYPES: set[tContentType] = {"doc", "blog", "tutorial", "example", "guide"}
5+
PLACEHOLDER_INDEX_MARKER = "<!-- afterpython:placeholder-index -->"

src/afterpython/templates/ci-workflow-template.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
uses: actions/checkout@v6
125125

126126
- name: Set up pixi
127-
uses: prefix-dev/setup-pixi@v0.9.5
127+
uses: prefix-dev/setup-pixi@v0.9.6
128128
with:
129129
pixi-version: v0.67.2
130130
cache: true

src/afterpython/tools/myst.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99

1010
import subprocess
1111

12+
import click
13+
1214
import afterpython as ap
1315
from afterpython._io.yaml import read_yaml, write_yaml
16+
from afterpython.const import PLACEHOLDER_INDEX_MARKER
1417
from afterpython.utils import deep_merge
1518

1619

@@ -113,7 +116,7 @@ def _write_index_file(content_type: tContentType):
113116
Note: This only creates the file. TOC modification is handled by the build process.
114117
115118
Raises:
116-
FileExistsError: If index.md already exists (users shouldn't create this file).
119+
click.ClickException: If a non-placeholder index.md already exists.
117120
"""
118121
if content_type == "doc":
119122
return # Doc doesn't need a placeholder index.md
@@ -123,22 +126,29 @@ def _write_index_file(content_type: tContentType):
123126

124127
# Check if user created an index.md file
125128
if index_file.exists():
126-
raise FileExistsError(
129+
existing_content = index_file.read_text(encoding="utf-8", errors="ignore")
130+
if PLACEHOLDER_INDEX_MARKER in existing_content:
131+
return index_file
132+
133+
raise click.ClickException(
127134
f"\n"
128-
f"Found existing 'index.md' in afterpython/{content_type}/\n"
135+
f"Found existing 'afterpython/{content_type}/index.md'\n"
129136
f"\n"
130-
f"The 'index.md' file is reserved for internal use by AfterPython.\n"
137+
f"'afterpython/{content_type}/index.md' is reserved for internal use by AfterPython.\n"
131138
f"MyST treats the first file in TOC as index, which would conflict with\n"
132-
f"SvelteKit (project-website-template)'s landing page route (/{content_type}).\n"
139+
f"the SvelteKit listing page route '/{content_type}', which is owned by\n"
140+
f"AfterPython's project website.\n"
133141
f"\n"
134142
f"Please rename your file to something else (e.g., '{content_type}_intro.md')\n"
135-
f"and update the reference in afterpython/{content_type}/myst.yml"
143+
f"and update the reference in afterpython/{content_type}/myst.yml."
136144
)
137145

138146
index_content = f"""---
139147
title: ← {content_type.capitalize()}
140148
---
141149
150+
{PLACEHOLDER_INDEX_MARKER}
151+
142152
This is a placeholder index page. The actual {content_type} landing page is rendered by SvelteKit.
143153
"""
144154
index_file.write_text(index_content)

0 commit comments

Comments
 (0)