yml-mvc-router
Version:
A configurable, Express-compatible routing module that maps routes from YAML to controllers following the MVC pattern
106 lines (90 loc) • 3.02 kB
JavaScript
const express = require('express');
const path = require('path');
const fs = require('fs');
const yaml = require('js-yaml');
const chokidar = require('chokidar');
const Parser = require('./parser');
const Builder = require('./builder');
const Resolver = require('./resolver');
const Executor = require('./executor');
const Assets = require('./assets');
const Inspector = require('./inspector');
/**
* Creates yml-mvc-router middleware
* @param {Object} options - Configuration options
* @returns {Function} Express middleware function
*/
function ymlRouter(options = {}) {
const config = {
routes: './routes/routes.yml',
controllers: './controllers',
middlewares: './middlewares',
views: './views',
assets: './public',
engine: 'ejs',
watch: process.env.NODE_ENV !== 'production',
devInspector: process.env.NODE_ENV !== 'production',
controllerExt: ['.js'],
resolveController: null,
plugins: [],
...options
};
// Resolve absolute paths
config.routes = path.resolve(config.routes);
config.controllers = path.resolve(config.controllers);
config.middlewares = path.resolve(config.middlewares);
config.views = path.resolve(config.views);
config.assets = path.resolve(config.assets);
const parser = new Parser(config);
const resolver = new Resolver(config);
const executor = new Executor(config);
const assets = new Assets(config);
const inspector = new Inspector(config);
let router = express.Router();
let routesMeta = [];
// Load and build routes initially
function buildRoutes() {
try {
if (!fs.existsSync(config.routes)) {
throw new Error(`Routes file not found: ${config.routes}`);
}
const yamlContent = fs.readFileSync(config.routes, 'utf8');
const parsedRoutes = parser.parse(yamlContent);
const builder = new Builder(config, resolver, executor, assets);
const result = builder.build(parsedRoutes);
router = result.router;
routesMeta = result.meta;
} catch (error) {
throw error;
}
}
// Initial build
buildRoutes();
// Watch for changes in development
if (config.watch) {
const watcher = chokidar.watch(config.routes);
watcher.on('change', () => {
console.log('[yml-mvc-router] Routes file changed, reloading...');
try {
buildRoutes();
console.log('[yml-mvc-router] Routes reloaded successfully');
} catch (error) {
console.error('[yml-mvc-router] Failed to reload routes:', error.message);
}
});
}
// Main middleware function
function middleware(req, res, next) {
// Add dev inspector route
if (config.devInspector && req.path === '/routes' && req.method === 'GET') {
return inspector.handle(req, res, routesMeta);
}
// Execute router
router(req, res, next);
}
// Attach metadata for debugging
middleware.getMeta = () => routesMeta;
middleware.getConfig = () => config;
return middleware;
}
module.exports = ymlRouter;