import test from "node:test"; import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; const postsDir = path.resolve("src/posts"); test("Content Contract: All posts in src/posts/ satisfy frontmatter schema", () => { if (!fs.existsSync(postsDir)) { fs.mkdirSync(postsDir, { recursive: true }); } const postFiles = fs.readdirSync(postsDir).filter((f) => f.endsWith(".md")); if (postFiles.length === 0) { // When posts are decoupled and mounted externally or ingested via API return; } for (const file of postFiles) { const filePath = path.join(postsDir, file); const content = fs.readFileSync(filePath, "utf-8"); // 1. Filename Convention: YYYY-MM-DD-slug.md assert.match( file, /^\d{4}-\d{2}-\d{2}-[a-z0-9-]+\.md$/, `Post filename '${file}' must follow 'YYYY-MM-DD-slug.md' naming standard` ); // 2. YAML Frontmatter Boundary check assert.match( content, /^---\n([\s\S]*?)\n---/, `Post '${file}' must start with valid YAML frontmatter delimiters` ); // Extract frontmatter block const fmMatch = content.match(/^---\n([\s\S]*?)\n---/); const fmText = fmMatch[1]; // 3. Title Invariant assert.match( fmText, /title:\s*"[^"]{5,}"/, `Post '${file}' must contain a valid title of at least 5 characters` ); // 4. Date Invariant (ISO Format) assert.match( fmText, /date:\s*\d{4}-\d{2}-\d{2}/, `Post '${file}' must define an ISO date (YYYY-MM-DD)` ); // 5. Layout Invariant assert.match( fmText, /layout:\s*layouts\/post\.njk/, `Post '${file}' must specify 'layout: layouts/post.njk'` ); // 6. Tags Invariant assert.match( fmText, /tags:\s*\n(\s+-\s+[a-z0-9-]+\n)+/, `Post '${file}' must specify a non-empty YAML tags list` ); // 7. Excerpt Invariant assert.match( fmText, /excerpt:\s*"[^"]{20,}"/, `Post '${file}' must provide a substantive excerpt of at least 20 characters` ); } });