import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const dir = path.join(__dirname, '..', 'content', 'resources'); let fixed = 0; for (const f of fs.readdirSync(dir).filter(f => f.endsWith('.mdx'))) { const filepath = path.join(dir, f); const original = fs.readFileSync(filepath, 'utf8'); // Split frontmatter from content const secondDash = original.indexOf('---', 4); if (secondDash === -1) continue; let frontmatter = original.substring(0, secondDash + 3); let content = original.substring(secondDash + 3); // === Fix body content === // Remove BACK TO POSTS and OPEN PAGE AS PDF content = content.replace(/\[\s*\*?\*?\s*BACK TO POSTS\s*\*?\*?\s*\]\([^)]*\)/gi, ''); content = content.replace(/\*?\*?\s*BACK TO POSTS\s*\*?\*?/gi, ''); content = content.replace(/\|?\s*\[?\s*\*?\*?\s*OPEN PAGE AS PDF\s*\*?\*?\s*\]?\s*\([^)]*\)/gi, ''); // Remove CSS block definitions content = content.replace(/#block-[a-zA-Z0-9_-]+ \{[^}]*?\}/g, ''); // Remove --> artifacts content = content.replace(/^-->\s*$/gm, ''); // Escape ALL < that aren't part of: // 1. Markdown images: ![...](...) - these don't have < // 2. iframe tags: // 3. Already escaped: \< // Strategy: protect safe tags, escape everything else, restore safe tags // Temporarily replace safe tags with placeholders const safeTags = []; content = content.replace(/<(\/?)iframe([^>]*)>/gi, (match) => { safeTags.push(match); return `__SAFE_TAG_${safeTags.length - 1}__`; }); content = content.replace(/<(\/?)video([^>]*)>/gi, (match) => { safeTags.push(match); return `__SAFE_TAG_${safeTags.length - 1}__`; }); content = content.replace(/]*)>/gi, (match) => { safeTags.push(match); return `__SAFE_TAG_${safeTags.length - 1}__`; }); // Now escape all remaining < and > that aren't in image markdown // Split by lines to handle image markdown const lines = content.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Skip lines that are image markdown if (line.trim().startsWith('![')) continue; // Skip lines that only contain safe tag placeholders if (line.trim().match(/^__SAFE_TAG_\d+__$/)) continue; // Escape < and > that aren't already escaped or part of placeholders lines[i] = line.replace(/<(?!_SAFE_TAG)/g, (match, offset) => { // Check if already escaped if (offset > 0 && line[offset - 1] === '\\') return match; return '<'; }); lines[i] = lines[i].replace(/>(?!_)/g, (match, offset) => { const before = lines[i].substring(0, offset); // Don't escape if it's after a safe tag placeholder if (before.match(/__SAFE_TAG_\d+$/)) return match; // Don't escape if already escaped if (offset > 0 && lines[i][offset - 1] === '\\') return match; // Don't escape markdown blockquotes at start of line if (before.match(/^\s*$/)) return match; return '>'; }); } content = lines.join('\n'); // Restore safe tags for (let i = 0; i < safeTags.length; i++) { content = content.replace(`__SAFE_TAG_${i}__`, safeTags[i]); } // Clean excessive blank lines content = content.replace(/\n{3,}/g, '\n\n'); // === Fix frontmatter excerpt === const excerptMatch = frontmatter.match(/^excerpt: "(.*)"$/m); if (excerptMatch) { let excerpt = excerptMatch[1]; excerpt = excerpt.replace(/\*?\*?BACK TO POSTS\*?\*?/gi, ''); excerpt = excerpt.replace(/!\[[^\]]*\]\([^)]*\)/g, ''); excerpt = excerpt.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1'); excerpt = excerpt.replace(/\*\*/g, ''); excerpt = excerpt.replace(/#block-[^\s]+ \{[^}]*?\}/g, ''); excerpt = excerpt.replace(/\s*\|\s*/g, ' '); excerpt = excerpt.replace(/\s+/g, ' ').trim(); excerpt = excerpt.substring(0, 250); frontmatter = frontmatter.replace(excerptMatch[0], `excerpt: "${excerpt}"`); } const result = frontmatter + content; if (result !== original) { fs.writeFileSync(filepath, result); fixed++; } } console.log(`Fixed ${fixed} files`);