Implements Option C (Hybrid) solution to prevent outdated documentation: New Features: - Pre-commit git hook that validates documentation before every commit - npm run docs:check - Validates README against current project state - npm run docs:sync - Automatically updates NPM Scripts section in README What gets checked: - NPM Scripts in package.json vs README - API routes in app/api/* vs README - App structure (directories in app/) vs README - Components vs README - Scripts vs README Workflow: 1. Make code changes 2. git commit triggers pre-commit hook 3. Hook warns if documentation is outdated 4. Run docs:sync to auto-update or edit manually 5. Commit with updated README Benefits: - No more forgetting to update README - Non-blocking (can use --no-verify if needed) - Automatic NPM scripts synchronization - Clear warnings show exactly what needs updating Scripts added: - scripts/check-docs.js - Validation script - scripts/sync-docs.js - Synchronization script - .git/hooks/pre-commit - Git hook (not tracked) Documentation: - Added complete workflow section in README - Examples and usage tips included 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
162 lines
4.4 KiB
JavaScript
Executable File
162 lines
4.4 KiB
JavaScript
Executable File
#!/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);
|
|
}
|