blob: 18a48bff6e9a803af57f684b9e5674c29edb6ba3 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001var template = require("./index")
2
3var whitespaceRegex = /["'\\\n\r\u2028\u2029]/g
4var nargs = /\{[0-9a-zA-Z]+\}/g
5
6var replaceTemplate =
7" var args\n" +
8" var result\n" +
9" if (arguments.length === 1 && typeof arguments[0] === \"object\") {\n" +
10" args = arguments[0]\n" +
11" } else {\n" +
12" args = arguments" +
13" }\n\n" +
14" if (!args || !(\"hasOwnProperty\" in args)) {\n" +
15" args = {}\n" +
16" }\n\n" +
17" return {0}"
18
19var literalTemplate = "\"{0}\""
20var argTemplate = "(result = args.hasOwnProperty(\"{0}\") ? " +
21 "args[\"{0}\"] : null, \n " +
22 "(result === null || result === undefined) ? \"\" : result)"
23
24module.exports = compile
25
26function compile(string, inline) {
27 var replacements = string.match(nargs)
28 var interleave = string.split(nargs)
29 var replace = []
30
31 for (var i = 0; i < interleave.length; i++) {
32 var current = interleave[i];
33 var replacement = replacements[i];
34 var escapeLeft = current.charAt(current.length - 1)
35 var escapeRight = (interleave[i + 1] || "").charAt(0)
36
37 if (replacement) {
38 replacement = replacement.substring(1, replacement.length - 1)
39 }
40
41 if (escapeLeft === "{" && escapeRight === "}") {
42 replace.push(current + replacement)
43 } else {
44 replace.push(current);
45 if (replacement) {
46 replace.push({ name: replacement })
47 }
48 }
49 }
50
51 var prev = [""]
52
53 for (var j = 0; j < replace.length; j++) {
54 var curr = replace[j]
55
56 if (String(curr) === curr) {
57 var top = prev[prev.length - 1]
58
59 if (String(top) === top) {
60 prev[prev.length - 1] = top + curr
61 } else {
62 prev.push(curr)
63 }
64 } else {
65 prev.push(curr)
66 }
67 }
68
69 replace = prev
70
71 if (inline) {
72 for (var k = 0; k < replace.length; k++) {
73 var token = replace[k]
74
75 if (String(token) === token) {
76 replace[k] = template(literalTemplate, escape(token))
77 } else {
78 replace[k] = template(argTemplate, escape(token.name))
79 }
80 }
81
82 var replaceCode = replace.join(" +\n ")
83 var compiledSource = template(replaceTemplate, replaceCode)
84 return new Function(compiledSource)
85 }
86
87 return function template() {
88 var args
89
90 if (arguments.length === 1 && typeof arguments[0] === "object") {
91 args = arguments[0]
92 } else {
93 args = arguments
94 }
95
96 if (!args || !("hasOwnProperty" in args)) {
97 args = {}
98 }
99
100 var result = []
101
102 for (var i = 0; i < replace.length; i++) {
103 if (i % 2 === 0) {
104 result.push(replace[i])
105 } else {
106 var argName = replace[i].name
107 var arg = args.hasOwnProperty(argName) ? args[argName] : null
108 if (arg !== null || arg !== undefined) {
109 result.push(arg)
110 }
111 }
112 }
113
114 return result.join("")
115 }
116}
117
118function escape(string) {
119 string = '' + string;
120
121 return string.replace(whitespaceRegex, escapedWhitespace);
122}
123
124function escapedWhitespace(character) {
125 // Escape all characters not included in SingleStringCharacters and
126 // DoubleStringCharacters on
127 // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
128 switch (character) {
129 case '"':
130 case "'":
131 case '\\':
132 return '\\' + character
133 // Four possible LineTerminator characters need to be escaped:
134 case '\n':
135 return '\\n'
136 case '\r':
137 return '\\r'
138 case '\u2028':
139 return '\\u2028'
140 case '\u2029':
141 return '\\u2029'
142 }
143}