#!/usr/bin/env node /** * Comprehensive CSS Fix - Restore all CSS files to valid syntax */ const fs = require('fs'); const path = require('path'); const CSS_DIR = './assets/css'; // CSS files that need fixing const cssFiles = [ 'hvac-common.css', 'hvac-dashboard.css', 'hvac-registration.css', 'hvac-event-summary.css', 'hvac-email-attendees.css', 'hvac-event-registration.css', 'hvac-certificate-reports.css', 'hvac-email-templates.css', 'hvac-master-dashboard.css', 'hvac-communication-templates.css' ]; function fixCSSContent(content, fileName) { console.log(`\nšŸ”§ Processing ${fileName}...`); // Step 1: Remove duplicate semicolons and fix malformed lines content = content.replace(/;\s*;+/g, ';'); content = content.replace(/;\s*\n\s*;/g, ';\n'); // Step 2: Fix duplicate vendor prefixes content = content.replace(/-webkit--webkit-/g, '-webkit-'); content = content.replace(/-moz--moz-/g, '-moz-'); content = content.replace(/-ms--ms-/g, '-ms-'); content = content.replace(/-o--o-/g, '-o-'); // Step 3: Fix multiple consecutive vendor prefixes content = content.replace(/(-webkit-){2,}/g, '-webkit-'); content = content.replace(/(-moz-){2,}/g, '-moz-'); content = content.replace(/(-ms-){2,}/g, '-ms-'); content = content.replace(/(-o-){2,}/g, '-o-'); // Step 4: Fix border-radius with excessive prefixes content = content.replace(/-webkit-webkit-webkit-webkit-webkit-webkit-border-radius:/g, '-webkit-border-radius:'); content = content.replace(/-webkit-webkit-border-radius:/g, '-webkit-border-radius:'); content = content.replace(/border-radius:\s*([^;]+);\s*border-radius:\s*([^;]+);/g, 'border-radius: $1;'); // Step 5: Fix box-shadow with excessive prefixes content = content.replace(/-webkit-webkit-webkit-box-shadow:/g, '-webkit-box-shadow:'); content = content.replace(/-webkit-webkit-box-shadow:/g, '-webkit-box-shadow:'); // Step 6: Fix malformed transform properties content = content.replace(/text--webkit-transform:/g, 'text-transform:'); content = content.replace(/text--moz-transform:/g, 'text-transform:'); content = content.replace(/text--ms-transform:/g, 'text-transform:'); // Step 7: Fix CSS custom property issues content = content.replace(/--hvac--webkit-border-radius:/g, '--hvac-border-radius:'); // Step 8: Clean up duplicate fallback comments content = content.replace(/\/\* IE fallback \*\/;\s*\/\* IE fallback \*\/;/g, ' /* IE fallback */'); content = content.replace(/\/\* IE fallback \*\/;\s*\n\s*([^:]+): ([^;]+); \/\* IE fallback \*\/;/g, '$1: $2; /* IE fallback */'); // Step 9: Fix broken rule structures let rules = []; let currentRule = ''; let braceCount = 0; let inComment = false; let inString = false; let stringChar = ''; for (let i = 0; i < content.length; i++) { const char = content[i]; const prevChar = i > 0 ? content[i - 1] : ''; const nextChar = i < content.length - 1 ? content[i + 1] : ''; // Handle comments if (!inString && char === '/' && nextChar === '*') { inComment = true; currentRule += char; continue; } if (!inString && inComment && char === '*' && nextChar === '/') { inComment = false; currentRule += char; continue; } // Handle strings if (!inComment && (char === '"' || char === "'") && prevChar !== '\\') { if (!inString) { inString = true; stringChar = char; } else if (char === stringChar) { inString = false; stringChar = ''; } } currentRule += char; // Count braces if (!inComment && !inString) { if (char === '{') { braceCount++; } else if (char === '}') { braceCount--; // Complete rule found if (braceCount === 0 && currentRule.trim()) { rules.push(currentRule.trim()); currentRule = ''; } } } } // Add any remaining content if (currentRule.trim()) { // If we have unclosed braces, try to close them while (braceCount > 0) { currentRule += '\n}'; braceCount--; } rules.push(currentRule.trim()); } // Step 10: Reconstruct the CSS with proper formatting let fixedCSS = ''; const headerComments = []; const rootRules = []; const mediaQueries = []; const keyframes = []; const normalRules = []; for (const rule of rules) { if (rule.startsWith('/*') && !rule.includes('{')) { headerComments.push(rule); } else if (rule.startsWith(':root')) { rootRules.push(rule); } else if (rule.startsWith('@media')) { mediaQueries.push(rule); } else if (rule.startsWith('@keyframes')) { keyframes.push(rule); } else { normalRules.push(rule); } } // Rebuild in proper order if (headerComments.length > 0) { fixedCSS += headerComments.join('\n') + '\n\n'; } if (rootRules.length > 0) { fixedCSS += rootRules.join('\n\n') + '\n\n'; } if (normalRules.length > 0) { fixedCSS += normalRules.join('\n\n') + '\n\n'; } if (keyframes.length > 0) { fixedCSS += keyframes.join('\n\n') + '\n\n'; } if (mediaQueries.length > 0) { fixedCSS += mediaQueries.join('\n\n') + '\n'; } // Final cleanup fixedCSS = fixedCSS.replace(/\n{3,}/g, '\n\n'); fixedCSS = fixedCSS.trim() + '\n'; return fixedCSS; } function validateCSS(content) { const openBraces = (content.match(/{/g) || []).length; const closeBraces = (content.match(/}/g) || []).length; const hasRoot = content.includes(':root'); const hasRules = content.match(/\.[a-zA-Z][\w-]*\s*{/) || content.match(/#[a-zA-Z][\w-]*\s*{/) || content.match(/[a-zA-Z]+\s*{/); return { balanced: openBraces === closeBraces, openBraces, closeBraces, hasRoot, hasRules: !!hasRules, valid: openBraces === closeBraces && openBraces > 0 }; } function main() { console.log('HVAC Community Events - Comprehensive CSS Fix'); console.log('='.repeat(60)); if (!fs.existsSync(CSS_DIR)) { console.error(`CSS directory not found: ${CSS_DIR}`); process.exit(1); } let totalFixed = 0; let totalErrors = 0; for (const file of cssFiles) { const filePath = path.join(CSS_DIR, file); if (!fs.existsSync(filePath)) { console.log(`āš ļø File not found: ${file}`); continue; } try { // Read the corrupted content let content = fs.readFileSync(filePath, 'utf8'); // Validate before const beforeValidation = validateCSS(content); console.log(` Before: ${beforeValidation.openBraces} open, ${beforeValidation.closeBraces} close braces`); // Fix the content content = fixCSSContent(content, file); // Validate after const afterValidation = validateCSS(content); console.log(` After: ${afterValidation.openBraces} open, ${afterValidation.closeBraces} close braces`); if (afterValidation.valid) { // Write the fixed content fs.writeFileSync(filePath, content, 'utf8'); console.log(` āœ… Fixed and saved`); totalFixed++; } else { console.log(` āŒ Still has issues - needs manual review`); totalErrors++; // Save to a .fixed file for manual review fs.writeFileSync(filePath + '.fixed', content, 'utf8'); console.log(` šŸ’¾ Saved partially fixed version to ${file}.fixed`); } } catch (error) { console.error(` āŒ Error processing ${file}:`, error.message); totalErrors++; } } console.log('\n' + '='.repeat(60)); console.log(`āœ… Successfully fixed: ${totalFixed} files`); if (totalErrors > 0) { console.log(`āš ļø Errors encountered: ${totalErrors} files`); console.log('\nFiles with .fixed extension need manual review.'); } console.log('\nNext steps:'); console.log('1. Review the fixed CSS files'); console.log('2. Test in browser for visual issues'); console.log('3. Run CSS validation tools'); } if (require.main === module) { main(); } module.exports = { fixCSSContent, validateCSS };