UNPKG

2.4 kBJavaScriptView Raw
1'use strict'
2
3const { resolve } = require('path')
4const debug = require('debug')('koa-views')
5const consolidate = require('consolidate')
6const send = require('koa-send')
7const getPaths = require('get-paths')
8const pretty = require('pretty')
9
10module.exports = viewsMiddleware
11
12const bigIntReplacer = () => {
13 const seen = new WeakSet()
14 return (key, value) => {
15 if (typeof value === 'bigint') return value.toString()
16
17 if (typeof value === 'object' && value !== null) {
18 if (seen.has(value)) {
19 return
20 }
21 seen.add(value)
22 }
23
24 return value
25 }
26}
27
28function viewsMiddleware(
29 path,
30 { autoRender = true, engineSource = consolidate, extension = 'html', options = {}, map } = {}
31) {
32 return function views(ctx, next) {
33 function render(relPath, locals = {}) {
34 if (!ctx) ctx = this
35
36 return getPaths(path, relPath, extension).then(paths => {
37 const suffix = paths.ext
38 const state = Object.assign(locals, options, ctx.state || {})
39 // deep copy partials
40 state.partials = Object.assign(Object.create(null), options.partials || {})
41 if (debug.enabled) debug('render `%s` with %s', paths.rel, JSON.stringify(state, bigIntReplacer()))
42 ctx.type = 'text/html'
43
44 if (isHtml(suffix) && !map) {
45 return send(ctx, paths.rel, {
46 root: path
47 })
48 } else {
49 const engineName = map && map[suffix] ? map[suffix] : suffix
50
51 const render = engineSource[engineName]
52
53 if (!engineName || !render)
54 return Promise.reject(
55 new Error(`Engine not found for the ".${suffix}" file extension`)
56 )
57
58 return render(resolve(path, paths.rel), state).then(html => {
59 // since pug has deprecated `pretty` option
60 // we'll use the `pretty` package in the meanwhile
61 if (locals.pretty) {
62 debug('using `pretty` package to beautify HTML')
63 html = pretty(html)
64 }
65
66 if (autoRender) {
67 ctx.body = html
68 } else {
69 return Promise.resolve(html)
70 }
71 })
72 }
73 })
74 }
75
76 // Use to extends app.context
77 if (!ctx) return render
78
79 if (ctx.render) return next()
80
81 ctx.response.render = ctx.render = render
82
83 return next()
84 }
85}
86
87function isHtml(ext) {
88 return ext === 'html'
89}