Files
mintel.me/apps/web/scripts/fix-mdx-whitespace.ts

124 lines
4.5 KiB
TypeScript

#!/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<string, string> = {
'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();