@axway/api-builder-runtime
Version:
API Builder Runtime
114 lines (106 loc) • 3.35 kB
JavaScript
const fs = require('fs');
const path = require('path');
const express = require('express');
class RenderEngineManager {
constructor(app, { appDir, logger }) {
this._app = app;
this._logger = logger;
this._renderers = {};
this._cache = {};
if (appDir) {
this._webDirectory = path.join(appDir, 'web');
this._viewsDirectory = path.join(this._webDirectory, 'views');
this._routesDirectory = path.join(this._webDirectory, 'routes');
this._publicDirectory = path.join(this._webDirectory, 'public');
}
}
/**
* Enables the static `./public` directory on the express app. This is an
* internal method to be used by unit-tests only.
* @private
*/
registerPublicStatic() {
const logger = this._logger;
if (this._publicDirectory && fs.existsSync(this._publicDirectory)) {
logger.debug('serve public files:', this._publicDirectory);
this._app.use(express.static(this._publicDirectory));
}
}
registerRenderers() {
const logger = this._logger;
if (!this._viewsDirectory || !fs.existsSync(this._viewsDirectory)) {
logger.debug('No views directory, disabling');
} else {
this._app.set('views', this._viewsDirectory);
}
const dir = path.join(__dirname, '..', 'engines');
const engines = fs.readdirSync(dir);
for (const engineType of engines) {
const engine = require(path.join(dir, engineType));
logger.trace('Registering render engine:', engineType);
if (engine.createRenderer) {
this.registerRendererEngine(engine);
}
}
// we monkey patch express to make it easy to switch between different
// templating engines without forcing us to register a default one
const originalRender = this._app.render;
this._app.render = (view, data, callback) => {
let ext = path.extname(view);
if (!ext || ext === view) {
// no extension, search for it
const keys = Object.keys(this._renderers);
let found = false;
for (let c = 0; c < keys.length; c++) {
ext = keys[c];
const fn = path.join(this._viewsDirectory, `${view}.${ext}`);
// we found a template for a specific engine, append the
// extension to trick express into using this specific
// engine
if (fs.existsSync(fn)) {
view += '.' + ext;
found = true;
break;
}
}
if (!found) {
return callback(new Error(`Unable to find layout "${view}"`));
}
}
return originalRender.call(this._app, view, data, callback);
};
}
registerRendererEngine(engine) {
this._createRenderer(engine);
this._renderers[engine.extension] = engine;
}
getRendererEngine(extension) {
// in case they supplied a .
return this._renderers[extension]
|| this._renderers[extension.substring(1)];
}
_createRenderer(engine) {
const { extension: ext } = engine;
const cacheable = this._app.enabled('view cache');
this._app.engine(ext, (filePath, options, callback) => {
let entry = this._cache[filePath];
if (!entry || !cacheable) {
const file = engine.skipread
? null
: fs.readFileSync(filePath).toString();
entry = engine.createRenderer(file, filePath, this._app);
if (cacheable) {
this._cache[filePath] = entry;
}
}
if (entry.length === 3) {
entry(filePath, options, callback);
} else {
callback(null, entry(options));
}
});
}
}
module.exports = {
RenderEngineManager
};