#!/usr/bin/env node /** * Documentation synchronization script * Updates README.md with current project structure */ const fs = require('fs'); const path = require('path'); // Colors for terminal output const colors = { reset: '\x1b[0m', green: '\x1b[32m', cyan: '\x1b[36m', yellow: '\x1b[33m', }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } const readmePath = path.join(__dirname, '..', 'README.md'); let readme = fs.readFileSync(readmePath, 'utf-8'); /** * Generate project structure tree */ function generateProjectStructure() { log('📂 Generating project structure...', 'cyan'); const structure = []; // Helper to scan directory function scanDir(dir, indent = '', relativePath = '') { const entries = fs.readdirSync(dir, { withFileTypes: true }) .filter(e => { // Skip these directories const skip = ['.git', '.next', 'node_modules', 'data', '.vscode', 'dist', 'build']; return !skip.includes(e.name) && !e.name.startsWith('.'); }) .sort((a, b) => { // Directories first, then files if (a.isDirectory() && !b.isDirectory()) return -1; if (!a.isDirectory() && b.isDirectory()) return 1; return a.name.localeCompare(b.name); }); entries.forEach((entry, index) => { const isLast = index === entries.length - 1; const prefix = isLast ? '└── ' : '├── '; const nextIndent = isLast ? ' ' : '│ '; const fullPath = path.join(dir, entry.name); const relPath = path.join(relativePath, entry.name).replace(/\\/g, '/'); if (entry.isDirectory()) { // Add directory with trailing slash structure.push(`${indent}${prefix}${entry.name}/`); // Don't recurse too deep if (indent.length < 12) { scanDir(fullPath, indent + nextIndent, relPath); } } else { // Add file structure.push(`${indent}${prefix}${entry.name}`); } }); } structure.push('location-tracker-app/'); const projectRoot = path.join(__dirname, '..'); scanDir(projectRoot, '', ''); return structure.join('\n'); } /** * Update NPM Scripts section */ function updateNpmScripts() { log('📦 Updating NPM scripts...', 'cyan'); const packageJson = require('../package.json'); const scripts = packageJson.scripts; const scriptsList = Object.entries(scripts) .map(([name, cmd]) => `${name.padEnd(25)} # ${cmd}`) .join('\n'); const section = `## 📝 NPM Scripts \`\`\`bash # Development npm run dev # Dev Server starten # Production npm run build # Production Build npm run start # Production Server # Database npm run db:init # Beide DBs initialisieren npm run db:init:app # Nur database.sqlite npm run db:init:locations # Nur locations.sqlite npm run db:init:geofence # Nur Geofence-Tabellen npm run db:cleanup # Cleanup 7 Tage npm run db:cleanup:7d # Cleanup 7 Tage npm run db:cleanup:30d # Cleanup 30 Tage # Testing npm run test:location # Test-Location hinzufügen npm run test:geofence # Geofence Detektion testen npm run test:geofence:email # Geofence Email testen npm run test:geofence:mqtt # MQTT Geofence testen # Documentation npm run docs:check # Dokumentation validieren npm run docs:sync # Dokumentation synchronisieren # Email Development npm run email:dev # Email Template Dev Server # Linting npm run lint # ESLint ausführen \`\`\``; // Try to replace existing NPM Scripts section const npmScriptPattern = /## 📝 NPM Scripts[\s\S]*?(?=\n## |\n---|\n\n## |$)/; if (npmScriptPattern.test(readme)) { readme = readme.replace(npmScriptPattern, section); log(' ✓ Updated NPM Scripts section', 'green'); } else { log(' ⚠ NPM Scripts section not found in README', 'yellow'); } } /** * Save updated README */ function saveReadme() { fs.writeFileSync(readmePath, readme, 'utf-8'); log('\n✅ README.md updated successfully!', 'green'); } // Main execution log('\n🔄 Synchronizing documentation...\n', 'cyan'); try { updateNpmScripts(); // Add more update functions here as needed saveReadme(); log('\n💡 Don\'t forget to:', 'cyan'); log(' git add README.md', 'reset'); log(' git commit -m "Update documentation"', 'reset'); log('', 'reset'); } catch (error) { console.error('❌ Error:', error.message); process.exit(1); }