import fs from 'fs' import path from 'path' import { Router } from 'express' import mongoose from 'mongoose' import pkg from '../package.json' import './utils/mongoose' import { ErrorLog } from './models/ErrorLog' const folderPath = path.resolve(__dirname, './routers') const folders = fs.readdirSync(folderPath) // Определение типов interface FileInfo { path: string; type: 'file'; endpoints: number; } interface DirectoryInfo { path: string; type: 'directory'; endpoints: number; children: (FileInfo | DirectoryInfo)[]; } interface DirScanResult { items: (FileInfo | DirectoryInfo)[]; totalEndpoints: number; } // Функция для поиска эндпоинтов в файлах function countEndpoints(filePath) { if (!fs.existsSync(filePath) || !filePath.endsWith('.js') && !filePath.endsWith('.ts')) { return 0; } try { const content = fs.readFileSync(filePath, 'utf8'); const httpMethods = ['get', 'post', 'put', 'delete', 'patch']; return httpMethods.reduce((count, method) => { const regex = new RegExp(`router\\.${method}\\(`, 'gi'); const matches = content.match(regex) || []; return count + matches.length; }, 0); } catch (err) { return 0; } } // Функция для рекурсивного обхода директорий function getAllDirs(dir, basePath = ''): DirScanResult { const items: (FileInfo | DirectoryInfo)[] = []; let totalEndpoints = 0; try { const dirItems = fs.readdirSync(dir); for (const item of dirItems) { const itemPath = path.join(dir, item); const relativePath = path.join(basePath, item); const stat = fs.statSync(itemPath); if (stat.isDirectory()) { const dirResult = getAllDirs(itemPath, relativePath); totalEndpoints += dirResult.totalEndpoints; items.push({ path: relativePath, type: 'directory', endpoints: dirResult.totalEndpoints, children: dirResult.items }); } else { const fileEndpoints = countEndpoints(itemPath); totalEndpoints += fileEndpoints; items.push({ path: relativePath, type: 'file', endpoints: fileEndpoints }); } } } catch (err) { console.error(`Ошибка при чтении директории ${dir}:`, err); } return { items, totalEndpoints }; } // Функция для генерации HTML-списка директорий function generateDirList(dirs: (FileInfo | DirectoryInfo)[], level = 0) { if (dirs.length === 0) return ''; const indent = level * 20; return `
Нет зарегистрированных ошибок
'; } // Создаем JavaScript для клиентской части const clientScript = ` document.addEventListener('DOMContentLoaded', function() { // Директории document.querySelectorAll('.dir-item[data-expandable="true"]').forEach(item => { item.addEventListener('click', function(e) { const subdirectory = this.nextElementSibling; const isExpanded = this.classList.toggle('expanded'); if (isExpanded) { subdirectory.style.display = 'block'; this.querySelector('.expand-icon').textContent = '▼'; } else { subdirectory.style.display = 'none'; this.querySelector('.expand-icon').textContent = '▶'; } e.stopPropagation(); }); }); // Модальное окно const modal = document.getElementById('fileModal'); const closeBtn = document.querySelector('.close-modal'); const fileContent = document.getElementById('fileContent'); const fileLoader = document.getElementById('fileLoader'); const modalFileName = document.getElementById('modalFileName'); // Закрытие модального окна closeBtn.addEventListener('click', function() { modal.style.display = 'none'; }); window.addEventListener('click', function(event) { if (event.target == modal) { modal.style.display = 'none'; } }); // Обработчик для файлов document.querySelectorAll('.file-item').forEach(item => { item.addEventListener('click', async function() { const filePath = this.getAttribute('data-path'); if (!filePath) return; // Показываем модальное окно и лоадер modal.style.display = 'block'; fileContent.style.display = 'none'; fileLoader.style.display = 'block'; modalFileName.textContent = 'Загрузка...'; try { const response = await fetch('/file-content?path=' + encodeURIComponent(filePath)); if (!response.ok) { throw new Error('Ошибка при загрузке файла'); } const data = await response.json(); // Отображаем содержимое файла fileLoader.style.display = 'none'; fileContent.style.display = 'block'; fileContent.textContent = data.content; modalFileName.textContent = data.fileName; // Подсветка синтаксиса const extensionMap = { 'js': 'javascript', 'ts': 'typescript', 'json': 'json', 'css': 'css', 'html': 'xml', 'xml': 'xml', 'md': 'markdown', 'yaml': 'yaml', 'yml': 'yaml', 'sh': 'bash', 'bash': 'bash' }; const language = extensionMap[data.extension] || ''; if (language) { fileContent.className = 'language-' + language; hljs.highlightElement(fileContent); } } catch (error) { fileLoader.style.display = 'none'; fileContent.style.display = 'block'; fileContent.textContent = 'Ошибка при загрузке файла: ' + error.message; modalFileName.textContent = 'Ошибка'; } }); }); // Обработчик кнопки очистки ошибок const clearErrorsBtn = document.getElementById('clearErrorsBtn'); const successAction = document.getElementById('successAction'); clearErrorsBtn.addEventListener('click', async function() { try { const response = await fetch('/clear-old-errors', { method: 'POST', headers: { 'Content-Type': 'application/json', } }); if (!response.ok) { throw new Error('Ошибка при очистке старых ошибок'); } const data = await response.json(); // Показываем сообщение об успехе successAction.textContent = 'Удалено ' + data.deletedCount + ' записей'; successAction.style.display = 'block'; // Перезагружаем страницу через 2 секунды setTimeout(() => { window.location.reload(); }, 2000); } catch (error) { console.error('Ошибка:', error); alert('Произошла ошибка: ' + error.message); } }); }); `; res.send(`${count} документов