import fs from 'fs' import path from 'path' const repoRoot = process.cwd() const scanRoots = ['server'] const sourceExtensions = new Set(['.js', '.mjs', '.ts']) const publicWritePattern = /\b(writeFile|appendFile|copyFile|rename|mkdir)\s*\([^)]*(public[/\\](?:data|uploads)|['"`]public['"`]\s*,\s*['"`](?:data|uploads)['"`])/s function childPath(dir, name) { if (name !== path.basename(name) || name.includes('/') || name.includes('\\')) { throw new Error(`Ungueltiger Dateiname beim Scannen: ${name}`) } return `${dir}${path.sep}${name}` } function walk(dir) { const entries = fs.readdirSync(dir, { withFileTypes: true }) return entries.flatMap((entry) => { const fullPath = childPath(dir, entry.name) if (entry.isDirectory()) return walk(fullPath) return [fullPath] }) } const findings = [] for (const root of scanRoots) { const absoluteRoot = path.join(repoRoot, root) if (!fs.existsSync(absoluteRoot)) continue for (const filePath of walk(absoluteRoot)) { if (!sourceExtensions.has(path.extname(filePath))) continue const content = fs.readFileSync(filePath, 'utf8') if (!publicWritePattern.test(content)) continue const relativePath = path.relative(repoRoot, filePath) findings.push(relativePath) } } if (findings.length > 0) { console.error('Runtime-Schreibzugriffe nach public/data oder public/uploads gefunden:') for (const finding of findings) { console.error(`- ${finding}`) } console.error('Bitte stattdessen server/data bzw. server/data/public-data verwenden.') process.exit(1) } console.log('OK: keine serverseitigen Runtime-Schreibzugriffe nach public/data oder public/uploads gefunden.')