Skip to content

Commit 5de34e3

Browse files
committed
fix: inject YAML from .qmd into generated .md so metadata header is always preserved
Made-with: Cursor
1 parent f26053a commit 5de34e3

2 files changed

Lines changed: 87 additions & 3 deletions

File tree

.makim.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ groups:
2626
find "$SEARCH_DIR" -name "*.qmd" -exec sh -c \
2727
'dir=$(dirname "$0"); base=$(basename "$0" .qmd); (cd "$dir" && quarto render "$base.qmd" --to gfm)' {} \;
2828
29-
# 3) Remove console colors from generated md files
30-
find "$SEARCH_DIR" -name \
31-
"index.md" -exec sh -c \
29+
# 3) Ensure generated index.md have YAML from .qmd (Quarto may drop it)
30+
python scripts/inject-qmd-yaml-into-md.py
31+
32+
# 4) Remove console colors from generated md files
33+
find "$SEARCH_DIR" -name "index.md" -exec sh -c \
3234
'cat "$(dirname "$0")/index.md" | python scripts/clean-output.py > "$(dirname "$0")/temp_index.md" && mv "$(dirname "$0")/temp_index.md" "$(dirname "$0")/index.md"' {} \;
3335
3436
build:

scripts/inject-qmd-yaml-into-md.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Inject YAML front matter from index.qmd into Quarto-generated index.md.
2+
3+
Quarto's GFM output sometimes omits or rewrites the YAML block. This script
4+
ensures each blog index.md has the exact front matter from the source index.qmd,
5+
so the blogging plugin and RSS get correct metadata (title, slug, date, etc.).
6+
7+
Run from repo root after 'quarto render' in the pre-build step.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
import re
13+
import sys
14+
from pathlib import Path
15+
16+
REPO_ROOT = Path(__file__).resolve().parents[1]
17+
BLOG_ROOT = REPO_ROOT / "pages" / "blog"
18+
19+
20+
def extract_yaml_from_qmd(path: Path) -> str:
21+
"""Return the YAML block (including --- fences) from a .qmd file.
22+
Drops 'format:' so the .md has only blog metadata for mkdocs."""
23+
text = path.read_text(encoding="utf-8")
24+
if not text.strip().startswith("---"):
25+
return ""
26+
rest = text.split("\n", 1)[1]
27+
match = re.search(r"^---\s*$", rest, re.MULTILINE)
28+
if not match:
29+
return ""
30+
raw = rest[: match.start()].rstrip()
31+
# Drop format: / gfm: / variant: lines (Quarto-only)
32+
lines = []
33+
skip = 0
34+
for line in raw.split("\n"):
35+
if skip > 0:
36+
skip -= 1
37+
continue
38+
if line.strip().startswith("format:"):
39+
skip = 2
40+
continue
41+
lines.append(line)
42+
yaml_body = "\n".join(lines).rstrip()
43+
return "---\n" + yaml_body + "\n---"
44+
45+
46+
def extract_body_from_quartos_md(text: str) -> str:
47+
"""Return the body of the doc (from first ## heading to end). Quarto GFM
48+
outputs: # Title\nAuthor\nDate\n\n## First section..."""
49+
lines = text.splitlines()
50+
for i, line in enumerate(lines):
51+
if line.strip().startswith("##"):
52+
return "\n".join(lines[i:])
53+
return "\n".join(lines)
54+
55+
56+
def process_post_dir(dir_path: Path) -> None:
57+
"""Inject YAML from index.qmd into index.md in the given blog post dir."""
58+
qmd_path = dir_path / "index.qmd"
59+
md_path = dir_path / "index.md"
60+
if not qmd_path.exists() or not md_path.exists():
61+
return
62+
yaml_block = extract_yaml_from_qmd(qmd_path)
63+
if not yaml_block:
64+
return
65+
md_content = md_path.read_text(encoding="utf-8")
66+
body = extract_body_from_quartos_md(md_content)
67+
new_md = yaml_block + "\n\n" + body
68+
md_path.write_text(new_md, encoding="utf-8")
69+
70+
71+
def main() -> None:
72+
if not BLOG_ROOT.exists():
73+
print(f"[EE] Blog root not found: {BLOG_ROOT}", file=sys.stderr)
74+
sys.exit(1)
75+
for dir_path in BLOG_ROOT.iterdir():
76+
if dir_path.is_dir():
77+
process_post_dir(dir_path)
78+
print("[II] Injected YAML from .qmd into generated .md files.")
79+
80+
81+
if __name__ == "__main__":
82+
main()

0 commit comments

Comments
 (0)