- Add 26 documentation files including test reports, deployment guides, and troubleshooting documentation - Include 3 CSV data files for trainer imports and user registration tracking - Add 43 JavaScript test files covering mobile optimization, Safari compatibility, and E2E testing - Include 18 PHP utility files for debugging, geocoding, and data analysis - Add 12 shell scripts for deployment verification, user management, and database operations - Update .gitignore with whitelist patterns for development files, documentation, and CSV data 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
263 lines
No EOL
8.8 KiB
JavaScript
Executable file
263 lines
No EOL
8.8 KiB
JavaScript
Executable file
#!/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 }; |