#!/usr/bin/env tsx /** * Fix missing whitespace in MDX files by comparing with TSX originals */ import * as fs from 'fs'; import * as path from 'path'; // Mapping of TSX component names to MDX slugs const TSX_TO_MDX_MAP: Record = { 'PageSpeedFails': 'why-pagespeed-fails', 'SlowLoadingDebt': 'slow-loading-costs-customers', 'AgencySlowdown': 'why-agencies-are-slow', 'WordPressPlugins': 'hidden-costs-of-wordpress-plugins', 'WebsiteStability': 'why-websites-break-after-updates', 'CookieFreeDesign': 'website-without-cookie-banners', 'LocalCloud': 'no-us-cloud-platforms', 'GDPRSystem': 'gdpr-conformity-system-approach', 'VendorLockIn': 'builder-systems-threaten-independence', 'PrivacyAnalytics': 'analytics-without-tracking', 'GreenIT': 'green-it-sustainable-web', 'FixedPrice': 'fixed-price-digital-projects', 'BuildFirst': 'build-first-digital-architecture', 'MaintenanceNoCMS': 'maintenance-for-headless-systems', 'Longevity': 'digital-longevity-architecture', 'CleanCode': 'clean-code-for-business-value', 'ResponsiveDesign': 'responsive-design-high-fidelity', 'HostingOps': 'professional-hosting-operations', 'NoTemplates': 'why-no-templates-matter', 'CRMSync': 'crm-synchronization-headless', }; const TSX_BASE = path.join(process.cwd(), 'src/components/blog/posts'); const MDX_BASE = path.join(process.cwd(), 'content/blog'); function findTsxFile(componentName: string): string | null { for (const group of ['Group1', 'Group2', 'Group3', 'Group4']) { const tsxPath = path.join(TSX_BASE, group, `${componentName}.tsx`); if (fs.existsSync(tsxPath)) { return tsxPath; } } return null; } function fixWhitespace() { let totalFixed = 0; for (const [tsxName, mdxSlug] of Object.entries(TSX_TO_MDX_MAP)) { const tsxPath = findTsxFile(tsxName); const mdxPath = path.join(MDX_BASE, `${mdxSlug}.mdx`); if (!tsxPath || !fs.existsSync(mdxPath)) { console.log(`⚠️ Skipping ${tsxName}: files not found`); continue; } const tsxContent = fs.readFileSync(tsxPath, 'utf-8'); let mdxContent = fs.readFileSync(mdxPath, 'utf-8'); // Count occurrences of {" "} in both files const tsxSpaces = (tsxContent.match(/\{" "\}/g) || []).length; const mdxSpacesBefore = (mdxContent.match(/\{" "\}/g) || []).length; if (tsxSpaces === 0) { console.log(`✓ ${mdxSlug}: No whitespace needed`); continue; } // Extract all lines with {" "} from TSX const tsxLines = tsxContent.split('\n'); const spacedLines: Array<{ lineNum: number; content: string }> = []; tsxLines.forEach((line, idx) => { if (line.includes('{" "}')) { spacedLines.push({ lineNum: idx, content: line.trim() }); } }); // For each spaced line in TSX, find similar content in MDX and add {" "} let fixCount = 0; for (const { content } of spacedLines) { // Extract the text pattern before {" "} const match = content.match(/(.+?)\{" "\}/); if (!match) continue; const textBefore = match[1].trim(); // Find this pattern in MDX without the space const searchPattern = new RegExp( textBefore.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(?!\\{" "\\})', 'g' ); const newMdxContent = mdxContent.replace(searchPattern, (matched) => { // Only add {" "} if it's not already there and if it's followed by a tag if (mdxContent.indexOf(matched + '{" "}') === -1 && mdxContent.indexOf(matched) < mdxContent.indexOf('<', mdxContent.indexOf(matched))) { fixCount++; return matched + '{" "}'; } return matched; }); mdxContent = newMdxContent; } const mdxSpacesAfter = (mdxContent.match(/\{" "\}/g) || []).length; if (fixCount > 0) { fs.writeFileSync(mdxPath, mdxContent, 'utf-8'); console.log(`✓ ${mdxSlug}: Fixed ${fixCount} whitespace issues (${mdxSpacesBefore} → ${mdxSpacesAfter})`); totalFixed += fixCount; } else { console.log(`✓ ${mdxSlug}: Already correct (${mdxSpacesBefore} spaces)`); } } console.log(`\n✅ Total whitespace fixes: ${totalFixed}`); } fixWhitespace();