import nunjucks, {Environment} from "nunjucks"; import config from "config"; import {Express, Router} from "express"; import ApplicationComponent from "../ApplicationComponent"; import Controller from "../Controller"; import {ServerError} from "../HttpError"; import * as querystring from "querystring"; import {ParsedUrlQueryInput} from "querystring"; import * as util from "util"; import * as path from "path"; export default class NunjucksComponent extends ApplicationComponent { private readonly viewsPath: string[]; private env?: Environment; public constructor(viewsPath: string[] = ['views']) { super(); this.viewsPath = viewsPath; } public async start(app: Express): Promise { let coreVersion = 'unknown'; try { coreVersion = require('../../package.json').version; } catch (e) { try { coreVersion = require('../package.json').version; } catch (e) { } } this.env = 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?: { [p: string]: string } | [], query?: ParsedUrlQueryInput, absolute?: boolean) => { const path = Controller.route(route, params, query, absolute); if (path === null) throw new ServerError(`Route ${route} not found.`); return path; }) .addGlobal('app_version', this.app!.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.env.express(app); app.set('view engine', 'njk'); } public async init(router: Router): Promise { router.use((req, res, next) => { req.env = this.env!; res.locals.url = req.url; res.locals.params = req.params; res.locals.query = req.query; res.locals.body = req.body; next(); }); } public getEnv(): Environment | undefined { return this.env; } }