import nunjucks, {Environment} from "nunjucks"; import config from "config"; import {Express, NextFunction, Request, Response, Router} from "express"; import ApplicationComponent from "../ApplicationComponent"; import Controller, {RouteParams} from "../Controller"; import * as querystring from "querystring"; import {ParsedUrlQueryInput} from "querystring"; import * as util from "util"; import * as path from "path"; import * as fs from "fs"; import {log} from "../Logger"; import Middleware from "../Middleware"; export default class NunjucksComponent extends ApplicationComponent { private readonly viewsPath: string[]; private environment?: Environment; public constructor(viewsPath: string[] = ['views']) { super(); this.viewsPath = viewsPath; } public async start(app: Express): Promise { let coreVersion = 'unknown'; const file = fs.existsSync(path.join(__dirname, '../../package.json')) ? path.join(__dirname, '../../package.json') : path.join(__dirname, '../package.json'); try { coreVersion = JSON.parse(fs.readFileSync(file).toString()).version; } catch (e) { log.warn('Couldn\'t determine coreVersion.', e); } this.environment = new nunjucks.Environment([ ...this.viewsPath.map(path => new nunjucks.FileSystemLoader(path)), new nunjucks.FileSystemLoader(path.join(__dirname, '../../../views')), new nunjucks.FileSystemLoader(path.join(__dirname, '../views')), ], { autoescape: true, noCache: !config.get('view.cache'), throwOnUndefined: true, }) .addGlobal('route', ( route: string, params: RouteParams = [], query: ParsedUrlQueryInput = {}, absolute: boolean = false, ): string => { return Controller.route(route, params, query, absolute); }) .addGlobal('app_version', this.getApp().getVersion()) .addGlobal('core_version', coreVersion) .addGlobal('querystring', querystring) .addGlobal('app', config.get('app')) .addFilter('dump', (val) => { return util.inspect(val); }) .addFilter('hex', (v: number) => { return v.toString(16); }); this.environment.express(app); app.set('view engine', 'njk'); } public async init(_router: Router): Promise { this.use(NunjucksMiddleware); } public getEnvironment(): Environment { if (!this.environment) throw new Error('Environment not initialized.'); return this.environment; } } export class NunjucksMiddleware extends Middleware { private env?: Environment; protected async handle(req: Request, res: Response, next: NextFunction): Promise { this.env = this.app.as(NunjucksComponent).getEnvironment(); res.locals.url = req.url; res.locals.params = req.params; res.locals.query = req.query; res.locals.body = req.body; next(); } public getEnvironment(): Environment { if (!this.env) throw new Error('Environment not initialized.'); return this.env; } }