refactor(docs): enhance frontmatter handling in DocPage (#2448)

Replace compile-time-only 'as string' casts with runtime String() conversions
and instanceof Date check. gray-matter parses unquoted YAML dates as Date
objects, causing 'Objects are not valid as a React child' crashes on docs pages.

Co-authored-by: Mr. Meowgi <ovehbe@users.noreply.github.com>
This commit is contained in:
Mr. Meowgi
2026-05-20 19:15:01 -03:00
committed by diegosouzapw
parent 140b4fed21
commit 3b3d82ce13
2 changed files with 54 additions and 3 deletions

View File

@@ -190,9 +190,13 @@ export default async function DocPage({ params }: { params: Promise<{ slug: stri
}
const fileContent = fs.readFileSync(sourceAbs, "utf8");
const { content, data: frontmatter } = matter(fileContent);
pageTitle = (frontmatter.title as string) || item.title;
version = (frontmatter.version as string) || null;
lastUpdated = (frontmatter.lastUpdated as string) || null;
pageTitle = String(frontmatter.title || item.title);
version = frontmatter.version ? String(frontmatter.version) : null;
lastUpdated = frontmatter.lastUpdated
? frontmatter.lastUpdated instanceof Date
? frontmatter.lastUpdated.toISOString().slice(0, 10)
: String(frontmatter.lastUpdated)
: null;
mermaidCharts = extractMermaidCharts(content);
headings = extractHeadings(content);
htmlContent = renderMarkdown(content);

View File

@@ -258,6 +258,53 @@ test("SEARCH_INDEX entries have non-empty content", () => {
}
});
// ──────────────────────────────────────────────
// Frontmatter type coercion (gray-matter parses
// unquoted YAML dates as Date, numbers as Number)
// ──────────────────────────────────────────────
test("gray-matter parses unquoted YAML date as Date object", async () => {
const matter = (await import("gray-matter")).default;
const { data } = matter("---\nlastUpdated: 2026-05-13\n---\nBody");
assert.ok(data.lastUpdated instanceof Date, "unquoted YAML date should be a Date instance");
});
test("gray-matter keeps semver-like version as string", async () => {
const matter = (await import("gray-matter")).default;
const { data } = matter("---\nversion: 3.8.0\n---\nBody");
assert.equal(typeof data.version, "string", "3.8.0 stays a string (two dots = not a number)");
});
test("gray-matter parses single-dot version as number", async () => {
const matter = (await import("gray-matter")).default;
const { data } = matter("---\nversion: 3.8\n---\nBody");
assert.equal(typeof data.version, "number", "3.8 is parsed as a float");
});
test("frontmatter Date coercion produces YYYY-MM-DD string", () => {
const d = new Date("2026-05-13T00:00:00.000Z");
const result = d instanceof Date ? d.toISOString().slice(0, 10) : String(d);
assert.equal(result, "2026-05-13");
});
test("frontmatter String() coercion handles number version", () => {
const version = 3.8;
const result = version ? String(version) : null;
assert.equal(result, "3.8");
assert.equal(typeof result, "string");
});
test("frontmatter falsy values fall back correctly", () => {
const title = String(undefined || "Fallback Title");
assert.equal(title, "Fallback Title");
const emptyTitle = String("" || "Fallback Title");
assert.equal(emptyTitle, "Fallback Title");
const version = null ? String(null) : null;
assert.equal(version, null);
});
// ──────────────────────────────────────────────
// Mermaid extraction
// ──────────────────────────────────────────────