UNPKG

2.51 kBJavaScriptView Raw
1'use strict'
2
3const vm = require('vm')
4
5const htmlRegexp = /[&<>"']/g
6const htmlSymbols = {
7 '&': '&amp;',
8 '<': '&lt;',
9 '>': '&gt;',
10 '"': '&quot;',
11 '\'': '&#039;'
12}
13
14/**
15 * @description Escape HTML characters with their respective entities
16 *
17 * @method escapeHTML
18 *
19 * @param {String} unescaped Unsafe HTML
20 *
21 * @return {String} escaped Save HTML
22 */
23function escapeHTML (unescaped) {
24 return unescaped.replace(htmlRegexp, (match) => htmlSymbols[match])
25}
26
27/**
28 * @description Replace Expressions
29 *
30 * @method placeholders
31 *
32 * @param {String} input Input
33 * @param {Object} ctx Context
34 * @param {Array} settings Settings
35 * @param {Array} opts Options
36 *
37 * @return {String} input Replaced Input
38 */
39function placeholders (input, ctx, settings, opts) {
40 // Since we are matching multiple sets of delimiters, we need to run a loop
41 // here to match each one.
42 for (let i = 0; i < settings.length; i++) {
43 const matches = input.match(settings[i].regexp)
44
45 if (!matches) continue
46
47 const delimiters = settings[i].text
48
49 for (let j = 0; j < matches.length; j++) {
50 const match = matches[j]
51
52 const expression = match.substring(delimiters[0].length, match.length - delimiters[1].length).trim()
53
54 // If expression has non-word characters then use VM
55 let value
56
57 if (/\W+/.test(expression)) {
58 try {
59 value = vm.runInContext(expression, ctx)
60 } catch (error) {
61 if (opts.strictMode) {
62 throw new SyntaxError(error)
63 }
64 }
65 } else if (Object.prototype.hasOwnProperty.call(ctx, expression)) {
66 value = ctx[expression]
67 }
68
69 // Not found local
70 if (value === null || value === undefined) {
71 if (opts.missingLocal === undefined) {
72 if (opts.strictMode) {
73 throw new ReferenceError(`'${expression}' is not defined`)
74 }
75 } else if (typeof opts.missingLocal === 'string') {
76 value = opts.missingLocal.replace('{local}', match)
77 }
78 }
79 // Escape html if necessary
80 if (settings[i].escape && typeof value === 'string') {
81 value = escapeHTML(value)
82 } else if (typeof value === 'object') { // Stringify if value object
83 value = JSON.stringify(value)
84 }
85
86 // Replace placeholder on evaluated value
87 input = input.replace(match, value)
88 }
89 }
90
91 return input
92}
93
94/**
95 * @module placeholders
96 *
97 * @requires vm
98 *
99 * @type {Function}
100 */
101module.exports = placeholders