Skip to content

Commit 258b670

Browse files
pdmackclaude
andcommitted
fix(ci): use code-block-aware MDX sanitization in Fern workflows
Blind sed escaping of {, }, < corrupts content inside fenced code blocks — bash scripts with ${VAR}, Go templates with {{.Field}}, and JSON all render with visible backslash escapes on the published site. Replace with awk that tracks fence state and skips inline code spans. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 644d961 commit 258b670

2 files changed

Lines changed: 42 additions & 12 deletions

File tree

.github/workflows/fern-docs-preview-build.yml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,27 @@ jobs:
6868
if git show-ref --verify --quiet "refs/tags/${version}"; then
6969
mkdir -p "fern/versions/${version}-content"
7070
git archive "refs/tags/${version}" -- docs/ | tar -x --strip-components=1 -C "fern/versions/${version}-content"
71-
find "fern/versions/${version}-content" -name '*.md' -print0 | xargs -0 sed -i \
72-
-e 's/{/\\{/g' \
73-
-e 's/}/\\}/g' \
74-
-e 's/</\&lt;/g'
71+
# Escape {, }, < for MDX — but only outside fenced code blocks and inline code spans
72+
find "fern/versions/${version}-content" -name '*.md' -print0 | while IFS= read -r -d '' f; do
73+
awk '
74+
/^````*/ || /^~~~~*/ { fence = !fence; print; next }
75+
fence { print; next }
76+
{
77+
n = split($0, p, "`")
78+
out = ""
79+
for (i = 1; i <= n; i++) {
80+
if (i % 2 == 1) {
81+
gsub(/{/, "\\{", p[i])
82+
gsub(/}/, "\\}", p[i])
83+
gsub(/</, "\\&lt;", p[i])
84+
}
85+
out = out p[i]
86+
if (i < n) out = out "`"
87+
}
88+
print out
89+
}
90+
' "$f" > "${f}.tmp" && mv "${f}.tmp" "$f"
91+
done
7592
echo "Extracted docs from $version"
7693
else
7794
echo "::warning::Tag $version not found — skipping content checkout"

.github/workflows/publish-fern-docs.yml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,27 @@ jobs:
184184
if git show-ref --verify --quiet "refs/tags/${version}"; then
185185
mkdir -p "fern/versions/${version}-content"
186186
git archive "refs/tags/${version}" -- docs/ | tar -x --strip-components=1 -C "fern/versions/${version}-content"
187-
# Sanitize frozen markdown for Fern's MDX parser.
188-
# Versioned content gets strict MDX parsing; escape all bare
189-
# { } and < so nothing is interpreted as JSX. Markdown renders
190-
# &lt; as < and \{ as { so the output is visually identical.
191-
find "fern/versions/${version}-content" -name '*.md' -print0 | xargs -0 sed -i \
192-
-e 's/{/\\{/g' \
193-
-e 's/}/\\}/g' \
194-
-e 's/</\&lt;/g'
187+
# Escape {, }, < for MDX — but only outside fenced code blocks and inline code spans
188+
find "fern/versions/${version}-content" -name '*.md' -print0 | while IFS= read -r -d '' f; do
189+
awk '
190+
/^````*/ || /^~~~~*/ { fence = !fence; print; next }
191+
fence { print; next }
192+
{
193+
n = split($0, p, "`")
194+
out = ""
195+
for (i = 1; i <= n; i++) {
196+
if (i % 2 == 1) {
197+
gsub(/{/, "\\{", p[i])
198+
gsub(/}/, "\\}", p[i])
199+
gsub(/</, "\\&lt;", p[i])
200+
}
201+
out = out p[i]
202+
if (i < n) out = out "`"
203+
}
204+
print out
205+
}
206+
' "$f" > "${f}.tmp" && mv "${f}.tmp" "$f"
207+
done
195208
echo "Extracted docs from $version"
196209
else
197210
echo "::error::Tag $version not found — cannot pin frozen docs content"

0 commit comments

Comments
 (0)