UNPKG

1.96 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 *
36 * @return {String} input Replaced Input
37 */
38function placeholders (input, ctx, settings) {
39 // Since we are matching multiple sets of delimiters, we need to run a loop
40 // here to match each one.
41 for (let i = 0; i < settings.length; i++) {
42 const matches = input.match(settings[i].regexp)
43
44 if (!matches) continue
45
46 const delimiters = settings[i].text
47
48 for (let j = 0; j < matches.length; j++) {
49 const match = matches[j]
50
51 const expression = match.substring(delimiters[0].length, match.length - delimiters[1].length).trim()
52
53 // If expression has non-word characters then use VM
54 let value
55
56 if (/\W+/.test(expression)) {
57 value = vm.runInContext(expression, ctx)
58 } else if (Object.prototype.hasOwnProperty.call(ctx, expression)) {
59 value = ctx[expression]
60 }
61
62 // Escape html if necessary
63 if (settings[i].escape && typeof value === 'string') {
64 value = escapeHTML(value)
65 }
66
67 // Stringify if value object
68 if (typeof value === 'object') {
69 value = JSON.stringify(value)
70 }
71
72 // Replace placeholder on evaluated value
73 input = input.replace(match, value)
74 }
75 }
76
77 return input
78}
79
80/**
81 * @module placeholders
82 *
83 * @requires vm
84 *
85 * @type {Function}
86 */
87module.exports = placeholders