'use strict'; // PHP file parsers for controllers, Eloquent models, migrations, middleware, // and Blade views. Split out of parser.js for size. const fs = require('fs'); const path = require('path'); function tryRead(p) { try { return fs.readFileSync(p, 'utf8'); } catch { return null; } } function listPhp(dir) { if (!fs.existsSync(dir)) return []; return fs.readdirSync(dir) .filter(f => f.endsWith('.php')) .map(f => path.join(dir, f)); } // Parse a controller PHP file: class name + public methods. function parseController(file) { const src = tryRead(file) || ''; const cls = (src.match(/class\s+([A-Za-z0-9_]+)/) || [])[1] || path.basename(file, '.php'); const methods = []; const re = /public\s+function\s+([A-Za-z0-9_]+)\s*\(/g; let m; while ((m = re.exec(src))) methods.push(m[1]); return { file, class: cls, methods }; } // Parse an Eloquent model: class name + table + fillable. function parseModel(file) { const src = tryRead(file) || ''; const cls = (src.match(/class\s+([A-Za-z0-9_]+)/) || [])[1] || path.basename(file, '.php'); const table = (src.match(/protected\s+\\\$table\s*=\s*['"]([^'"]+)['"]/) || [])[1]; const fillableMatch = src.match(/protected\s+\\\$fillable\s*=\s*\[([^\]]*)\]/); let fillable = []; if (fillableMatch) { fillable = fillableMatch[1].match(/['"]([A-Za-z0-9_]+)['"]/g) || []; fillable = fillable.map(s => s.replace(/^['"]|['"]$/g, '')); } return { file, class: cls, table: table || cls.toLowerCase() + 's', fillable }; } // Parse a migration: table name from Schema::create('x', ...) + columns. function parseMigration(file) { const src = tryRead(file) || ''; const m = src.match(/Schema::create\s*\(\s*['"]([A-Za-z0-9_]+)['"]/); if (!m) return null; const table = m[1]; const cols = []; const colRe = /\\\$table->([a-zA-Z]+)\s*\(\s*['"]([A-Za-z0-9_]+)['"]/g; let cm; while ((cm = colRe.exec(src))) { cols.push({ type: cm[1], name: cm[2] }); } return { file, table, cols }; } // Parse a middleware class: class name. function parseMiddleware(file) { const src = tryRead(file) || ''; const cls = (src.match(/class\s+([A-Za-z0-9_]+)/) || [])[1] || path.basename(file, '.php'); return { file, class: cls }; } // List Blade views (recursive). function listBlade(dir, base) { base = base || dir; const out = []; if (!fs.existsSync(dir)) return out; for (const e of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, e.name); if (e.isDirectory()) out.push(...listBlade(full, base)); else if (e.name.endsWith('.blade.php')) { const rel = path.relative(base, full).replace(/\.blade\.php$/, '').replace(/\//g, '.'); out.push({ file: full, name: rel }); } } return out; } module.exports = { tryRead, listPhp, parseController, parseModel, parseMigration, parseMiddleware, listBlade, };