Source: serverSetup/nunjucks.js

import nunjucks from 'nunjucks'
import config from '../../config/index.js'
import addFilters from '../filters/filters.js'
import logger from '../utils/logger.js'
import * as customRenderer from '../utils/custom-renderer.js'
import * as schemas from '../routes/schemas.js'
import * as v from 'valibot'

/**
 * We wanto to override nunjucks.render() with a function that
 * validates the params against a schema.
 */
const proto = {
  render (name, context) {
    const schema = schemas.templateSchema.get(name)
    logger.info(`rendering: ${name} with schema=<${schema ? 'defined' : 'any'}>`)
    return customRenderer.render(nunjucks, name, schema ?? v.any(), context)
  },
  renderString (string, context) {
    return nunjucks.renderString(string, context)
  },
  configure (paths, options) {
    return nunjucks.configure(paths, options)
  }
}

/**
 * Setup Nunjucks template engine with custom configuration
 * @param {Object} config - Configuration object
 * @param {Object} [config.app] - Express application instance
 * @param {Object} config.datasetNameMapping - Dataset name mapping object
 * @returns {Object} Configured Nunjucks instance
 */
export function setupNunjucks (opts) {
  const { app, datasetNameMapping } = opts
  const options = { dev: true, noCache: true, watch: true }
  if (app) {
    options.express = app
  }

  const customNunjucks = Object.create(proto)
  const nunjucksEnv = customNunjucks.configure([
    'src/views',
    'src/views/check',
    'src/views/submit',
    'node_modules/govuk-frontend/dist/',
    'node_modules/@x-govuk/govuk-prototype-components/'
  ], options)

  if (app) {
    app.set('view engine', 'html')
    app.use((req, res, next) => {
      const sanitizedPath = req.path.replace(/[<>'"]/g, '')
      nunjucksEnv.addGlobal('currentPath', sanitizedPath)
      next()
    })
  }

  const globalValues = {
    serviceName: config.serviceNames.submit,
    dataDesignUrl: config.dataDesignUrl,
    mainWebsiteUrl: config.mainWebsiteUrl,
    govukRebrand: true,
    ...config.templateContent
  }

  if ('smartlook' in config) {
    globalValues.smartlookKey = config.smartlook.key
    globalValues.smartlookRegion = config.smartlook.region
  }

  if ('googleAnalytics' in config) {
    globalValues.googleAnalyticsMeasurementId = config.googleAnalytics.measurementId

    if (app) {
      app.use((req, res, next) => {
        nunjucksEnv.addGlobal('cookiesAccepted', req.cookies.cookies_preferences_set === 'true')
        next()
      })
    }
  }

  Object.keys(globalValues).forEach((key) => {
    nunjucksEnv.addGlobal(key, globalValues[key])
  })
  addFilters(nunjucksEnv, { datasetNameMapping })

  return customNunjucks
}