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'); // Known safe HTML/JSX tags that MDX should handle const safeTags = new Set([ 'iframe', 'video', 'source', 'br', 'hr', 'img', 'div', 'span', 'p', 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'strong', 'em', 'b', 'i', 'u', 'code', 'pre', 'blockquote', 'table', 'tr', 'td', 'th', 'thead', 'tbody', ]); 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 into frontmatter and content const fmEnd = original.indexOf('---', 4); if (fmEnd === -1) continue; const frontmatter = original.substring(0, fmEnd + 3); let content = original.substring(fmEnd + 3); // Escape angle brackets that look like HTML tags but aren't valid JSX // Match < followed by something that's not a known safe tag or / content = content.replace(/<(?!\/?(?:iframe|video|source|br|hr|img)\b)([^>]*?)>/g, (match, inner) => { // Keep markdown image syntax ![...](...) - these don't match since they start with ! // Keep valid looking JSX/HTML const tagName = inner.split(/[\s/]/)[0].toLowerCase(); if (safeTags.has(tagName) || tagName.startsWith('!--')) return match; // It's a stray angle bracket - escape it return `\\<${inner}\\>`; }); // Also escape bare < that aren't part of tags (like math: x < y) // But be careful not to double-escape content = content.replace(/([^\\])<([^/!a-zA-Z\\])/g, '$1\\<$2'); const result = frontmatter + content; if (result !== original) { fs.writeFileSync(filepath, result); fixed++; } } console.log(`Fixed JSX issues in ${fixed} files`);