mustache-js-rails 4.1.0 → 4.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdaacb9d86224bfaad91faadf214d54fba2aff3061782daa0f94db8699337a00
4
- data.tar.gz: 43565772ac94156221a0ba5b35bd2f3993e667db3e8502ee78b0b370e7ef8b23
3
+ metadata.gz: 608492ca76157606a99755d687f1f2eb8d5afa0ed7e4b64628509e3c50dd662f
4
+ data.tar.gz: 3b25eadfbab5a5d9729d470fb429a06b0423c94ed8bb7f7ba1a502fbd34a624d
5
5
  SHA512:
6
- metadata.gz: ff21d26afa01b0542780f8ce26dc0e796c165e797e57a659ede1d1ff20b38b1456bbb297b5208938076680101880dccdf3a0b776772405586d34ef0ede087d5c
7
- data.tar.gz: 204506a54896719b4a81cf4baaeefe3422523b766c31dcd1c34f4d7d2d43158f9897061b558c8d5d72a1c704b231bd6035c7730c9961c84e49ad3d1f10acc3f3
6
+ metadata.gz: 8a640c2ea766c6bda447fb91cce601cd30f97deed450c2dced8be27ad4fbe9fc3b6dd307c4d62f76bc016c9662464ab1646f3d58c57b3e29d25244b19bd1dc7c
7
+ data.tar.gz: '0369c41d8fb4b92d64a33a1dc64d8dd23a77aad510d1893b5dd648c1baceb0d5a06f590b488210fe5f1529e879231ee385e62bb4f85d3421b6e14d723c6838ec'
data/README.md CHANGED
@@ -9,7 +9,7 @@ and [mustache jQuery integration](https://github.com/jonnyreeves/jquery-Mustache
9
9
 
10
10
  Integrated versions are:
11
11
 
12
- * mustache.js - <b id="mustache-js-version">4.1.0</b>
12
+ * mustache.js - <b id="mustache-js-version">4.2.0</b>
13
13
  * jQuery mustache - <b id="jquery-mustache-js-version">0.2.8</b>
14
14
 
15
15
  ### Installation
@@ -1,3 +1,3 @@
1
1
  module MustacheJsRails
2
- VERSION = "4.1.0"
2
+ VERSION = "4.1.0.1"
3
3
  end
@@ -1,773 +1,764 @@
1
- // This file has been generated from mustache.mjs
2
- (function (global, factory) {
3
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
- typeof define === 'function' && define.amd ? define(factory) :
5
- (global = global || self, global.Mustache = factory());
6
- }(this, (function () { 'use strict';
7
-
8
- /*!
9
- * mustache.js - Logic-less {{mustache}} templates with JavaScript
10
- * http://github.com/janl/mustache.js
11
- */
12
-
13
- var objectToString = Object.prototype.toString;
14
- var isArray = Array.isArray || function isArrayPolyfill (object) {
15
- return objectToString.call(object) === '[object Array]';
16
- };
17
-
18
- function isFunction (object) {
19
- return typeof object === 'function';
20
- }
21
-
22
- /**
23
- * More correct typeof string handling array
24
- * which normally returns typeof 'object'
25
- */
26
- function typeStr (obj) {
27
- return isArray(obj) ? 'array' : typeof obj;
28
- }
1
+ /*!
2
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
3
+ * http://github.com/janl/mustache.js
4
+ */
5
+
6
+ var objectToString = Object.prototype.toString;
7
+ var isArray = Array.isArray || function isArrayPolyfill (object) {
8
+ return objectToString.call(object) === '[object Array]';
9
+ };
10
+
11
+ function isFunction (object) {
12
+ return typeof object === 'function';
13
+ }
14
+
15
+ /**
16
+ * More correct typeof string handling array
17
+ * which normally returns typeof 'object'
18
+ */
19
+ function typeStr (obj) {
20
+ return isArray(obj) ? 'array' : typeof obj;
21
+ }
22
+
23
+ function escapeRegExp (string) {
24
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
25
+ }
26
+
27
+ /**
28
+ * Null safe way of checking whether or not an object,
29
+ * including its prototype, has a given property
30
+ */
31
+ function hasProperty (obj, propName) {
32
+ return obj != null && typeof obj === 'object' && (propName in obj);
33
+ }
34
+
35
+ /**
36
+ * Safe way of detecting whether or not the given thing is a primitive and
37
+ * whether it has the given property
38
+ */
39
+ function primitiveHasOwnProperty (primitive, propName) {
40
+ return (
41
+ primitive != null
42
+ && typeof primitive !== 'object'
43
+ && primitive.hasOwnProperty
44
+ && primitive.hasOwnProperty(propName)
45
+ );
46
+ }
47
+
48
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
49
+ // See https://github.com/janl/mustache.js/issues/189
50
+ var regExpTest = RegExp.prototype.test;
51
+ function testRegExp (re, string) {
52
+ return regExpTest.call(re, string);
53
+ }
54
+
55
+ var nonSpaceRe = /\S/;
56
+ function isWhitespace (string) {
57
+ return !testRegExp(nonSpaceRe, string);
58
+ }
59
+
60
+ var entityMap = {
61
+ '&': '&amp;',
62
+ '<': '&lt;',
63
+ '>': '&gt;',
64
+ '"': '&quot;',
65
+ "'": '&#39;',
66
+ '/': '&#x2F;',
67
+ '`': '&#x60;',
68
+ '=': '&#x3D;'
69
+ };
70
+
71
+ function escapeHtml (string) {
72
+ return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
73
+ return entityMap[s];
74
+ });
75
+ }
76
+
77
+ var whiteRe = /\s*/;
78
+ var spaceRe = /\s+/;
79
+ var equalsRe = /\s*=/;
80
+ var curlyRe = /\s*\}/;
81
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
82
+
83
+ /**
84
+ * Breaks up the given `template` string into a tree of tokens. If the `tags`
85
+ * argument is given here it must be an array with two string values: the
86
+ * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
87
+ * course, the default is to use mustaches (i.e. mustache.tags).
88
+ *
89
+ * A token is an array with at least 4 elements. The first element is the
90
+ * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
91
+ * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
92
+ * all text that appears outside a symbol this element is "text".
93
+ *
94
+ * The second element of a token is its "value". For mustache tags this is
95
+ * whatever else was inside the tag besides the opening symbol. For text tokens
96
+ * this is the text itself.
97
+ *
98
+ * The third and fourth elements of the token are the start and end indices,
99
+ * respectively, of the token in the original template.
100
+ *
101
+ * Tokens that are the root node of a subtree contain two more elements: 1) an
102
+ * array of tokens in the subtree and 2) the index in the original template at
103
+ * which the closing tag for that section begins.
104
+ *
105
+ * Tokens for partials also contain two more elements: 1) a string value of
106
+ * indendation prior to that tag and 2) the index of that tag on that line -
107
+ * eg a value of 2 indicates the partial is the third tag on this line.
108
+ */
109
+ function parseTemplate (template, tags) {
110
+ if (!template)
111
+ return [];
112
+ var lineHasNonSpace = false;
113
+ var sections = []; // Stack to hold section tokens
114
+ var tokens = []; // Buffer to hold the tokens
115
+ var spaces = []; // Indices of whitespace tokens on the current line
116
+ var hasTag = false; // Is there a {{tag}} on the current line?
117
+ var nonSpace = false; // Is there a non-space char on the current line?
118
+ var indentation = ''; // Tracks indentation for tags that use it
119
+ var tagIndex = 0; // Stores a count of number of tags encountered on a line
120
+
121
+ // Strips all whitespace tokens array for the current line
122
+ // if there was a {{#tag}} on it and otherwise only space.
123
+ function stripSpace () {
124
+ if (hasTag && !nonSpace) {
125
+ while (spaces.length)
126
+ delete tokens[spaces.pop()];
127
+ } else {
128
+ spaces = [];
129
+ }
29
130
 
30
- function escapeRegExp (string) {
31
- return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
131
+ hasTag = false;
132
+ nonSpace = false;
32
133
  }
33
134
 
34
- /**
35
- * Null safe way of checking whether or not an object,
36
- * including its prototype, has a given property
37
- */
38
- function hasProperty (obj, propName) {
39
- return obj != null && typeof obj === 'object' && (propName in obj);
40
- }
135
+ var openingTagRe, closingTagRe, closingCurlyRe;
136
+ function compileTags (tagsToCompile) {
137
+ if (typeof tagsToCompile === 'string')
138
+ tagsToCompile = tagsToCompile.split(spaceRe, 2);
41
139
 
42
- /**
43
- * Safe way of detecting whether or not the given thing is a primitive and
44
- * whether it has the given property
45
- */
46
- function primitiveHasOwnProperty (primitive, propName) {
47
- return (
48
- primitive != null
49
- && typeof primitive !== 'object'
50
- && primitive.hasOwnProperty
51
- && primitive.hasOwnProperty(propName)
52
- );
53
- }
140
+ if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
141
+ throw new Error('Invalid tags: ' + tagsToCompile);
54
142
 
55
- // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
56
- // See https://github.com/janl/mustache.js/issues/189
57
- var regExpTest = RegExp.prototype.test;
58
- function testRegExp (re, string) {
59
- return regExpTest.call(re, string);
143
+ openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
144
+ closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
145
+ closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
60
146
  }
61
147
 
62
- var nonSpaceRe = /\S/;
63
- function isWhitespace (string) {
64
- return !testRegExp(nonSpaceRe, string);
65
- }
148
+ compileTags(tags || mustache.tags);
66
149
 
67
- var entityMap = {
68
- '&': '&amp;',
69
- '<': '&lt;',
70
- '>': '&gt;',
71
- '"': '&quot;',
72
- "'": '&#39;',
73
- '/': '&#x2F;',
74
- '`': '&#x60;',
75
- '=': '&#x3D;'
76
- };
150
+ var scanner = new Scanner(template);
77
151
 
78
- function escapeHtml (string) {
79
- return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
80
- return entityMap[s];
81
- });
82
- }
152
+ var start, type, value, chr, token, openSection;
153
+ while (!scanner.eos()) {
154
+ start = scanner.pos;
83
155
 
84
- var whiteRe = /\s*/;
85
- var spaceRe = /\s+/;
86
- var equalsRe = /\s*=/;
87
- var curlyRe = /\s*\}/;
88
- var tagRe = /#|\^|\/|>|\{|&|=|!/;
156
+ // Match any text between tags.
157
+ value = scanner.scanUntil(openingTagRe);
89
158
 
90
- /**
91
- * Breaks up the given `template` string into a tree of tokens. If the `tags`
92
- * argument is given here it must be an array with two string values: the
93
- * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
94
- * course, the default is to use mustaches (i.e. mustache.tags).
95
- *
96
- * A token is an array with at least 4 elements. The first element is the
97
- * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
98
- * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
99
- * all text that appears outside a symbol this element is "text".
100
- *
101
- * The second element of a token is its "value". For mustache tags this is
102
- * whatever else was inside the tag besides the opening symbol. For text tokens
103
- * this is the text itself.
104
- *
105
- * The third and fourth elements of the token are the start and end indices,
106
- * respectively, of the token in the original template.
107
- *
108
- * Tokens that are the root node of a subtree contain two more elements: 1) an
109
- * array of tokens in the subtree and 2) the index in the original template at
110
- * which the closing tag for that section begins.
111
- *
112
- * Tokens for partials also contain two more elements: 1) a string value of
113
- * indendation prior to that tag and 2) the index of that tag on that line -
114
- * eg a value of 2 indicates the partial is the third tag on this line.
115
- */
116
- function parseTemplate (template, tags) {
117
- if (!template)
118
- return [];
119
- var lineHasNonSpace = false;
120
- var sections = []; // Stack to hold section tokens
121
- var tokens = []; // Buffer to hold the tokens
122
- var spaces = []; // Indices of whitespace tokens on the current line
123
- var hasTag = false; // Is there a {{tag}} on the current line?
124
- var nonSpace = false; // Is there a non-space char on the current line?
125
- var indentation = ''; // Tracks indentation for tags that use it
126
- var tagIndex = 0; // Stores a count of number of tags encountered on a line
127
-
128
- // Strips all whitespace tokens array for the current line
129
- // if there was a {{#tag}} on it and otherwise only space.
130
- function stripSpace () {
131
- if (hasTag && !nonSpace) {
132
- while (spaces.length)
133
- delete tokens[spaces.pop()];
134
- } else {
135
- spaces = [];
136
- }
159
+ if (value) {
160
+ for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
161
+ chr = value.charAt(i);
137
162
 
138
- hasTag = false;
139
- nonSpace = false;
140
- }
141
-
142
- var openingTagRe, closingTagRe, closingCurlyRe;
143
- function compileTags (tagsToCompile) {
144
- if (typeof tagsToCompile === 'string')
145
- tagsToCompile = tagsToCompile.split(spaceRe, 2);
146
-
147
- if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
148
- throw new Error('Invalid tags: ' + tagsToCompile);
149
-
150
- openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
151
- closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
152
- closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
153
- }
154
-
155
- compileTags(tags || mustache.tags);
156
-
157
- var scanner = new Scanner(template);
158
-
159
- var start, type, value, chr, token, openSection;
160
- while (!scanner.eos()) {
161
- start = scanner.pos;
162
-
163
- // Match any text between tags.
164
- value = scanner.scanUntil(openingTagRe);
165
-
166
- if (value) {
167
- for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
168
- chr = value.charAt(i);
169
-
170
- if (isWhitespace(chr)) {
171
- spaces.push(tokens.length);
172
- indentation += chr;
173
- } else {
174
- nonSpace = true;
175
- lineHasNonSpace = true;
176
- indentation += ' ';
177
- }
178
-
179
- tokens.push([ 'text', chr, start, start + 1 ]);
180
- start += 1;
181
-
182
- // Check for whitespace on the current line.
183
- if (chr === '\n') {
184
- stripSpace();
185
- indentation = '';
186
- tagIndex = 0;
187
- lineHasNonSpace = false;
188
- }
163
+ if (isWhitespace(chr)) {
164
+ spaces.push(tokens.length);
165
+ indentation += chr;
166
+ } else {
167
+ nonSpace = true;
168
+ lineHasNonSpace = true;
169
+ indentation += ' ';
189
170
  }
190
- }
191
-
192
- // Match the opening tag.
193
- if (!scanner.scan(openingTagRe))
194
- break;
195
-
196
- hasTag = true;
197
-
198
- // Get the tag type.
199
- type = scanner.scan(tagRe) || 'name';
200
- scanner.scan(whiteRe);
201
-
202
- // Get the tag value.
203
- if (type === '=') {
204
- value = scanner.scanUntil(equalsRe);
205
- scanner.scan(equalsRe);
206
- scanner.scanUntil(closingTagRe);
207
- } else if (type === '{') {
208
- value = scanner.scanUntil(closingCurlyRe);
209
- scanner.scan(curlyRe);
210
- scanner.scanUntil(closingTagRe);
211
- type = '&';
212
- } else {
213
- value = scanner.scanUntil(closingTagRe);
214
- }
215
-
216
- // Match the closing tag.
217
- if (!scanner.scan(closingTagRe))
218
- throw new Error('Unclosed tag at ' + scanner.pos);
219
-
220
- if (type == '>') {
221
- token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
222
- } else {
223
- token = [ type, value, start, scanner.pos ];
224
- }
225
- tagIndex++;
226
- tokens.push(token);
227
-
228
- if (type === '#' || type === '^') {
229
- sections.push(token);
230
- } else if (type === '/') {
231
- // Check section nesting.
232
- openSection = sections.pop();
233
-
234
- if (!openSection)
235
- throw new Error('Unopened section "' + value + '" at ' + start);
236
-
237
- if (openSection[1] !== value)
238
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
239
- } else if (type === 'name' || type === '{' || type === '&') {
240
- nonSpace = true;
241
- } else if (type === '=') {
242
- // Set the tags for the next time around.
243
- compileTags(value);
244
- }
245
- }
246
-
247
- stripSpace();
248
-
249
- // Make sure there are no open sections when we're done.
250
- openSection = sections.pop();
251
-
252
- if (openSection)
253
- throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
254
-
255
- return nestTokens(squashTokens(tokens));
256
- }
257
-
258
- /**
259
- * Combines the values of consecutive text tokens in the given `tokens` array
260
- * to a single token.
261
- */
262
- function squashTokens (tokens) {
263
- var squashedTokens = [];
264
171
 
265
- var token, lastToken;
266
- for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
267
- token = tokens[i];
172
+ tokens.push([ 'text', chr, start, start + 1 ]);
173
+ start += 1;
268
174
 
269
- if (token) {
270
- if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
271
- lastToken[1] += token[1];
272
- lastToken[3] = token[3];
273
- } else {
274
- squashedTokens.push(token);
275
- lastToken = token;
175
+ // Check for whitespace on the current line.
176
+ if (chr === '\n') {
177
+ stripSpace();
178
+ indentation = '';
179
+ tagIndex = 0;
180
+ lineHasNonSpace = false;
276
181
  }
277
182
  }
278
183
  }
279
184
 
280
- return squashedTokens;
281
- }
282
-
283
- /**
284
- * Forms the given array of `tokens` into a nested tree structure where
285
- * tokens that represent a section have two additional items: 1) an array of
286
- * all tokens that appear in that section and 2) the index in the original
287
- * template that represents the end of that section.
288
- */
289
- function nestTokens (tokens) {
290
- var nestedTokens = [];
291
- var collector = nestedTokens;
292
- var sections = [];
293
-
294
- var token, section;
295
- for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
296
- token = tokens[i];
297
-
298
- switch (token[0]) {
299
- case '#':
300
- case '^':
301
- collector.push(token);
302
- sections.push(token);
303
- collector = token[4] = [];
304
- break;
305
- case '/':
306
- section = sections.pop();
307
- section[5] = token[2];
308
- collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
309
- break;
310
- default:
311
- collector.push(token);
312
- }
185
+ // Match the opening tag.
186
+ if (!scanner.scan(openingTagRe))
187
+ break;
188
+
189
+ hasTag = true;
190
+
191
+ // Get the tag type.
192
+ type = scanner.scan(tagRe) || 'name';
193
+ scanner.scan(whiteRe);
194
+
195
+ // Get the tag value.
196
+ if (type === '=') {
197
+ value = scanner.scanUntil(equalsRe);
198
+ scanner.scan(equalsRe);
199
+ scanner.scanUntil(closingTagRe);
200
+ } else if (type === '{') {
201
+ value = scanner.scanUntil(closingCurlyRe);
202
+ scanner.scan(curlyRe);
203
+ scanner.scanUntil(closingTagRe);
204
+ type = '&';
205
+ } else {
206
+ value = scanner.scanUntil(closingTagRe);
313
207
  }
314
208
 
315
- return nestedTokens;
316
- }
209
+ // Match the closing tag.
210
+ if (!scanner.scan(closingTagRe))
211
+ throw new Error('Unclosed tag at ' + scanner.pos);
317
212
 
318
- /**
319
- * A simple string scanner that is used by the template parser to find
320
- * tokens in template strings.
321
- */
322
- function Scanner (string) {
323
- this.string = string;
324
- this.tail = string;
325
- this.pos = 0;
213
+ if (type == '>') {
214
+ token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
215
+ } else {
216
+ token = [ type, value, start, scanner.pos ];
217
+ }
218
+ tagIndex++;
219
+ tokens.push(token);
220
+
221
+ if (type === '#' || type === '^') {
222
+ sections.push(token);
223
+ } else if (type === '/') {
224
+ // Check section nesting.
225
+ openSection = sections.pop();
226
+
227
+ if (!openSection)
228
+ throw new Error('Unopened section "' + value + '" at ' + start);
229
+
230
+ if (openSection[1] !== value)
231
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
232
+ } else if (type === 'name' || type === '{' || type === '&') {
233
+ nonSpace = true;
234
+ } else if (type === '=') {
235
+ // Set the tags for the next time around.
236
+ compileTags(value);
237
+ }
326
238
  }
327
239
 
328
- /**
329
- * Returns `true` if the tail is empty (end of string).
330
- */
331
- Scanner.prototype.eos = function eos () {
332
- return this.tail === '';
333
- };
240
+ stripSpace();
334
241
 
335
- /**
336
- * Tries to match the given regular expression at the current position.
337
- * Returns the matched text if it can match, the empty string otherwise.
338
- */
339
- Scanner.prototype.scan = function scan (re) {
340
- var match = this.tail.match(re);
242
+ // Make sure there are no open sections when we're done.
243
+ openSection = sections.pop();
341
244
 
342
- if (!match || match.index !== 0)
343
- return '';
245
+ if (openSection)
246
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
344
247
 
345
- var string = match[0];
248
+ return nestTokens(squashTokens(tokens));
249
+ }
346
250
 
347
- this.tail = this.tail.substring(string.length);
348
- this.pos += string.length;
251
+ /**
252
+ * Combines the values of consecutive text tokens in the given `tokens` array
253
+ * to a single token.
254
+ */
255
+ function squashTokens (tokens) {
256
+ var squashedTokens = [];
349
257
 
350
- return string;
351
- };
258
+ var token, lastToken;
259
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
260
+ token = tokens[i];
352
261
 
353
- /**
354
- * Skips all text until the given regular expression can be matched. Returns
355
- * the skipped string, which is the entire tail if no match can be made.
356
- */
357
- Scanner.prototype.scanUntil = function scanUntil (re) {
358
- var index = this.tail.search(re), match;
262
+ if (token) {
263
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
264
+ lastToken[1] += token[1];
265
+ lastToken[3] = token[3];
266
+ } else {
267
+ squashedTokens.push(token);
268
+ lastToken = token;
269
+ }
270
+ }
271
+ }
359
272
 
360
- switch (index) {
361
- case -1:
362
- match = this.tail;
363
- this.tail = '';
273
+ return squashedTokens;
274
+ }
275
+
276
+ /**
277
+ * Forms the given array of `tokens` into a nested tree structure where
278
+ * tokens that represent a section have two additional items: 1) an array of
279
+ * all tokens that appear in that section and 2) the index in the original
280
+ * template that represents the end of that section.
281
+ */
282
+ function nestTokens (tokens) {
283
+ var nestedTokens = [];
284
+ var collector = nestedTokens;
285
+ var sections = [];
286
+
287
+ var token, section;
288
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
289
+ token = tokens[i];
290
+
291
+ switch (token[0]) {
292
+ case '#':
293
+ case '^':
294
+ collector.push(token);
295
+ sections.push(token);
296
+ collector = token[4] = [];
364
297
  break;
365
- case 0:
366
- match = '';
298
+ case '/':
299
+ section = sections.pop();
300
+ section[5] = token[2];
301
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
367
302
  break;
368
303
  default:
369
- match = this.tail.substring(0, index);
370
- this.tail = this.tail.substring(index);
304
+ collector.push(token);
371
305
  }
372
-
373
- this.pos += match.length;
374
-
375
- return match;
376
- };
377
-
378
- /**
379
- * Represents a rendering context by wrapping a view object and
380
- * maintaining a reference to the parent context.
381
- */
382
- function Context (view, parentContext) {
383
- this.view = view;
384
- this.cache = { '.': this.view };
385
- this.parent = parentContext;
386
306
  }
387
307
 
388
- /**
389
- * Creates a new context using the given view with this context
390
- * as the parent.
391
- */
392
- Context.prototype.push = function push (view) {
393
- return new Context(view, this);
394
- };
395
-
396
- /**
397
- * Returns the value of the given name in this context, traversing
398
- * up the context hierarchy if the value is absent in this context's view.
399
- */
400
- Context.prototype.lookup = function lookup (name) {
401
- var cache = this.cache;
402
-
403
- var value;
404
- if (cache.hasOwnProperty(name)) {
405
- value = cache[name];
406
- } else {
407
- var context = this, intermediateValue, names, index, lookupHit = false;
408
-
409
- while (context) {
410
- if (name.indexOf('.') > 0) {
411
- intermediateValue = context.view;
412
- names = name.split('.');
413
- index = 0;
414
-
415
- /**
416
- * Using the dot notion path in `name`, we descend through the
417
- * nested objects.
418
- *
419
- * To be certain that the lookup has been successful, we have to
420
- * check if the last object in the path actually has the property
421
- * we are looking for. We store the result in `lookupHit`.
422
- *
423
- * This is specially necessary for when the value has been set to
424
- * `undefined` and we want to avoid looking up parent contexts.
425
- *
426
- * In the case where dot notation is used, we consider the lookup
427
- * to be successful even if the last "object" in the path is
428
- * not actually an object but a primitive (e.g., a string, or an
429
- * integer), because it is sometimes useful to access a property
430
- * of an autoboxed primitive, such as the length of a string.
431
- **/
432
- while (intermediateValue != null && index < names.length) {
433
- if (index === names.length - 1)
434
- lookupHit = (
435
- hasProperty(intermediateValue, names[index])
436
- || primitiveHasOwnProperty(intermediateValue, names[index])
437
- );
438
-
439
- intermediateValue = intermediateValue[names[index++]];
440
- }
441
- } else {
442
- intermediateValue = context.view[name];
443
-
444
- /**
445
- * Only checking against `hasProperty`, which always returns `false` if
446
- * `context.view` is not an object. Deliberately omitting the check
447
- * against `primitiveHasOwnProperty` if dot notation is not used.
448
- *
449
- * Consider this example:
450
- * ```
451
- * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"})
452
- * ```
453
- *
454
- * If we were to check also against `primitiveHasOwnProperty`, as we do
455
- * in the dot notation case, then render call would return:
456
- *
457
- * "The length of a football field is 9."
458
- *
459
- * rather than the expected:
460
- *
461
- * "The length of a football field is 100 yards."
462
- **/
463
- lookupHit = hasProperty(context.view, name);
464
- }
308
+ return nestedTokens;
309
+ }
310
+
311
+ /**
312
+ * A simple string scanner that is used by the template parser to find
313
+ * tokens in template strings.
314
+ */
315
+ function Scanner (string) {
316
+ this.string = string;
317
+ this.tail = string;
318
+ this.pos = 0;
319
+ }
320
+
321
+ /**
322
+ * Returns `true` if the tail is empty (end of string).
323
+ */
324
+ Scanner.prototype.eos = function eos () {
325
+ return this.tail === '';
326
+ };
327
+
328
+ /**
329
+ * Tries to match the given regular expression at the current position.
330
+ * Returns the matched text if it can match, the empty string otherwise.
331
+ */
332
+ Scanner.prototype.scan = function scan (re) {
333
+ var match = this.tail.match(re);
334
+
335
+ if (!match || match.index !== 0)
336
+ return '';
337
+
338
+ var string = match[0];
339
+
340
+ this.tail = this.tail.substring(string.length);
341
+ this.pos += string.length;
342
+
343
+ return string;
344
+ };
345
+
346
+ /**
347
+ * Skips all text until the given regular expression can be matched. Returns
348
+ * the skipped string, which is the entire tail if no match can be made.
349
+ */
350
+ Scanner.prototype.scanUntil = function scanUntil (re) {
351
+ var index = this.tail.search(re), match;
352
+
353
+ switch (index) {
354
+ case -1:
355
+ match = this.tail;
356
+ this.tail = '';
357
+ break;
358
+ case 0:
359
+ match = '';
360
+ break;
361
+ default:
362
+ match = this.tail.substring(0, index);
363
+ this.tail = this.tail.substring(index);
364
+ }
465
365
 
466
- if (lookupHit) {
467
- value = intermediateValue;
468
- break;
366
+ this.pos += match.length;
367
+
368
+ return match;
369
+ };
370
+
371
+ /**
372
+ * Represents a rendering context by wrapping a view object and
373
+ * maintaining a reference to the parent context.
374
+ */
375
+ function Context (view, parentContext) {
376
+ this.view = view;
377
+ this.cache = { '.': this.view };
378
+ this.parent = parentContext;
379
+ }
380
+
381
+ /**
382
+ * Creates a new context using the given view with this context
383
+ * as the parent.
384
+ */
385
+ Context.prototype.push = function push (view) {
386
+ return new Context(view, this);
387
+ };
388
+
389
+ /**
390
+ * Returns the value of the given name in this context, traversing
391
+ * up the context hierarchy if the value is absent in this context's view.
392
+ */
393
+ Context.prototype.lookup = function lookup (name) {
394
+ var cache = this.cache;
395
+
396
+ var value;
397
+ if (cache.hasOwnProperty(name)) {
398
+ value = cache[name];
399
+ } else {
400
+ var context = this, intermediateValue, names, index, lookupHit = false;
401
+
402
+ while (context) {
403
+ if (name.indexOf('.') > 0) {
404
+ intermediateValue = context.view;
405
+ names = name.split('.');
406
+ index = 0;
407
+
408
+ /**
409
+ * Using the dot notion path in `name`, we descend through the
410
+ * nested objects.
411
+ *
412
+ * To be certain that the lookup has been successful, we have to
413
+ * check if the last object in the path actually has the property
414
+ * we are looking for. We store the result in `lookupHit`.
415
+ *
416
+ * This is specially necessary for when the value has been set to
417
+ * `undefined` and we want to avoid looking up parent contexts.
418
+ *
419
+ * In the case where dot notation is used, we consider the lookup
420
+ * to be successful even if the last "object" in the path is
421
+ * not actually an object but a primitive (e.g., a string, or an
422
+ * integer), because it is sometimes useful to access a property
423
+ * of an autoboxed primitive, such as the length of a string.
424
+ **/
425
+ while (intermediateValue != null && index < names.length) {
426
+ if (index === names.length - 1)
427
+ lookupHit = (
428
+ hasProperty(intermediateValue, names[index])
429
+ || primitiveHasOwnProperty(intermediateValue, names[index])
430
+ );
431
+
432
+ intermediateValue = intermediateValue[names[index++]];
469
433
  }
470
-
471
- context = context.parent;
434
+ } else {
435
+ intermediateValue = context.view[name];
436
+
437
+ /**
438
+ * Only checking against `hasProperty`, which always returns `false` if
439
+ * `context.view` is not an object. Deliberately omitting the check
440
+ * against `primitiveHasOwnProperty` if dot notation is not used.
441
+ *
442
+ * Consider this example:
443
+ * ```
444
+ * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"})
445
+ * ```
446
+ *
447
+ * If we were to check also against `primitiveHasOwnProperty`, as we do
448
+ * in the dot notation case, then render call would return:
449
+ *
450
+ * "The length of a football field is 9."
451
+ *
452
+ * rather than the expected:
453
+ *
454
+ * "The length of a football field is 100 yards."
455
+ **/
456
+ lookupHit = hasProperty(context.view, name);
472
457
  }
473
458
 
474
- cache[name] = value;
475
- }
476
-
477
- if (isFunction(value))
478
- value = value.call(this.view);
479
-
480
- return value;
481
- };
482
-
483
- /**
484
- * A Writer knows how to take a stream of tokens and render them to a
485
- * string, given a context. It also maintains a cache of templates to
486
- * avoid the need to parse the same template twice.
487
- */
488
- function Writer () {
489
- this.templateCache = {
490
- _cache: {},
491
- set: function set (key, value) {
492
- this._cache[key] = value;
493
- },
494
- get: function get (key) {
495
- return this._cache[key];
496
- },
497
- clear: function clear () {
498
- this._cache = {};
459
+ if (lookupHit) {
460
+ value = intermediateValue;
461
+ break;
499
462
  }
500
- };
501
- }
502
463
 
503
- /**
504
- * Clears all cached templates in this writer.
505
- */
506
- Writer.prototype.clearCache = function clearCache () {
507
- if (typeof this.templateCache !== 'undefined') {
508
- this.templateCache.clear();
464
+ context = context.parent;
509
465
  }
510
- };
511
466
 
512
- /**
513
- * Parses and caches the given `template` according to the given `tags` or
514
- * `mustache.tags` if `tags` is omitted, and returns the array of tokens
515
- * that is generated from the parse.
516
- */
517
- Writer.prototype.parse = function parse (template, tags) {
518
- var cache = this.templateCache;
519
- var cacheKey = template + ':' + (tags || mustache.tags).join(':');
520
- var isCacheEnabled = typeof cache !== 'undefined';
521
- var tokens = isCacheEnabled ? cache.get(cacheKey) : undefined;
522
-
523
- if (tokens == undefined) {
524
- tokens = parseTemplate(template, tags);
525
- isCacheEnabled && cache.set(cacheKey, tokens);
526
- }
527
- return tokens;
528
- };
529
-
530
- /**
531
- * High-level method that is used to render the given `template` with
532
- * the given `view`.
533
- *
534
- * The optional `partials` argument may be an object that contains the
535
- * names and templates of partials that are used in the template. It may
536
- * also be a function that is used to load partial templates on the fly
537
- * that takes a single argument: the name of the partial.
538
- *
539
- * If the optional `config` argument is given here, then it should be an
540
- * object with a `tags` attribute or an `escape` attribute or both.
541
- * If an array is passed, then it will be interpreted the same way as
542
- * a `tags` attribute on a `config` object.
543
- *
544
- * The `tags` attribute of a `config` object must be an array with two
545
- * string values: the opening and closing tags used in the template (e.g.
546
- * [ "<%", "%>" ]). The default is to mustache.tags.
547
- *
548
- * The `escape` attribute of a `config` object must be a function which
549
- * accepts a string as input and outputs a safely escaped string.
550
- * If an `escape` function is not provided, then an HTML-safe string
551
- * escaping function is used as the default.
552
- */
553
- Writer.prototype.render = function render (template, view, partials, config) {
554
- var tags = this.getConfigTags(config);
555
- var tokens = this.parse(template, tags);
556
- var context = (view instanceof Context) ? view : new Context(view, undefined);
557
- return this.renderTokens(tokens, context, partials, template, config);
558
- };
467
+ cache[name] = value;
468
+ }
559
469
 
560
- /**
561
- * Low-level method that renders the given array of `tokens` using
562
- * the given `context` and `partials`.
563
- *
564
- * Note: The `originalTemplate` is only ever used to extract the portion
565
- * of the original template that was contained in a higher-order section.
566
- * If the template doesn't use higher-order sections, this argument may
567
- * be omitted.
568
- */
569
- Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, config) {
570
- var buffer = '';
571
-
572
- var token, symbol, value;
573
- for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
574
- value = undefined;
575
- token = tokens[i];
576
- symbol = token[0];
577
-
578
- if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config);
579
- else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config);
580
- else if (symbol === '>') value = this.renderPartial(token, context, partials, config);
581
- else if (symbol === '&') value = this.unescapedValue(token, context);
582
- else if (symbol === 'name') value = this.escapedValue(token, context, config);
583
- else if (symbol === 'text') value = this.rawValue(token);
584
-
585
- if (value !== undefined)
586
- buffer += value;
470
+ if (isFunction(value))
471
+ value = value.call(this.view);
472
+
473
+ return value;
474
+ };
475
+
476
+ /**
477
+ * A Writer knows how to take a stream of tokens and render them to a
478
+ * string, given a context. It also maintains a cache of templates to
479
+ * avoid the need to parse the same template twice.
480
+ */
481
+ function Writer () {
482
+ this.templateCache = {
483
+ _cache: {},
484
+ set: function set (key, value) {
485
+ this._cache[key] = value;
486
+ },
487
+ get: function get (key) {
488
+ return this._cache[key];
489
+ },
490
+ clear: function clear () {
491
+ this._cache = {};
587
492
  }
588
-
589
- return buffer;
590
493
  };
494
+ }
495
+
496
+ /**
497
+ * Clears all cached templates in this writer.
498
+ */
499
+ Writer.prototype.clearCache = function clearCache () {
500
+ if (typeof this.templateCache !== 'undefined') {
501
+ this.templateCache.clear();
502
+ }
503
+ };
504
+
505
+ /**
506
+ * Parses and caches the given `template` according to the given `tags` or
507
+ * `mustache.tags` if `tags` is omitted, and returns the array of tokens
508
+ * that is generated from the parse.
509
+ */
510
+ Writer.prototype.parse = function parse (template, tags) {
511
+ var cache = this.templateCache;
512
+ var cacheKey = template + ':' + (tags || mustache.tags).join(':');
513
+ var isCacheEnabled = typeof cache !== 'undefined';
514
+ var tokens = isCacheEnabled ? cache.get(cacheKey) : undefined;
515
+
516
+ if (tokens == undefined) {
517
+ tokens = parseTemplate(template, tags);
518
+ isCacheEnabled && cache.set(cacheKey, tokens);
519
+ }
520
+ return tokens;
521
+ };
522
+
523
+ /**
524
+ * High-level method that is used to render the given `template` with
525
+ * the given `view`.
526
+ *
527
+ * The optional `partials` argument may be an object that contains the
528
+ * names and templates of partials that are used in the template. It may
529
+ * also be a function that is used to load partial templates on the fly
530
+ * that takes a single argument: the name of the partial.
531
+ *
532
+ * If the optional `config` argument is given here, then it should be an
533
+ * object with a `tags` attribute or an `escape` attribute or both.
534
+ * If an array is passed, then it will be interpreted the same way as
535
+ * a `tags` attribute on a `config` object.
536
+ *
537
+ * The `tags` attribute of a `config` object must be an array with two
538
+ * string values: the opening and closing tags used in the template (e.g.
539
+ * [ "<%", "%>" ]). The default is to mustache.tags.
540
+ *
541
+ * The `escape` attribute of a `config` object must be a function which
542
+ * accepts a string as input and outputs a safely escaped string.
543
+ * If an `escape` function is not provided, then an HTML-safe string
544
+ * escaping function is used as the default.
545
+ */
546
+ Writer.prototype.render = function render (template, view, partials, config) {
547
+ var tags = this.getConfigTags(config);
548
+ var tokens = this.parse(template, tags);
549
+ var context = (view instanceof Context) ? view : new Context(view, undefined);
550
+ return this.renderTokens(tokens, context, partials, template, config);
551
+ };
552
+
553
+ /**
554
+ * Low-level method that renders the given array of `tokens` using
555
+ * the given `context` and `partials`.
556
+ *
557
+ * Note: The `originalTemplate` is only ever used to extract the portion
558
+ * of the original template that was contained in a higher-order section.
559
+ * If the template doesn't use higher-order sections, this argument may
560
+ * be omitted.
561
+ */
562
+ Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, config) {
563
+ var buffer = '';
564
+
565
+ var token, symbol, value;
566
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
567
+ value = undefined;
568
+ token = tokens[i];
569
+ symbol = token[0];
570
+
571
+ if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config);
572
+ else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config);
573
+ else if (symbol === '>') value = this.renderPartial(token, context, partials, config);
574
+ else if (symbol === '&') value = this.unescapedValue(token, context);
575
+ else if (symbol === 'name') value = this.escapedValue(token, context, config);
576
+ else if (symbol === 'text') value = this.rawValue(token);
577
+
578
+ if (value !== undefined)
579
+ buffer += value;
580
+ }
591
581
 
592
- Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate, config) {
593
- var self = this;
594
- var buffer = '';
595
- var value = context.lookup(token[1]);
596
-
597
- // This function is used to render an arbitrary template
598
- // in the current context by higher-order sections.
599
- function subRender (template) {
600
- return self.render(template, context, partials, config);
601
- }
602
-
603
- if (!value) return;
604
-
605
- if (isArray(value)) {
606
- for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
607
- buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config);
608
- }
609
- } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
610
- buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config);
611
- } else if (isFunction(value)) {
612
- if (typeof originalTemplate !== 'string')
613
- throw new Error('Cannot use higher-order sections without the original template');
614
-
615
- // Extract the portion of the original template that the section contains.
616
- value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
617
-
618
- if (value != null)
619
- buffer += value;
620
- } else {
621
- buffer += this.renderTokens(token[4], context, partials, originalTemplate, config);
622
- }
623
- return buffer;
624
- };
582
+ return buffer;
583
+ };
625
584
 
626
- Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate, config) {
627
- var value = context.lookup(token[1]);
585
+ Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate, config) {
586
+ var self = this;
587
+ var buffer = '';
588
+ var value = context.lookup(token[1]);
628
589
 
629
- // Use JavaScript's definition of falsy. Include empty arrays.
630
- // See https://github.com/janl/mustache.js/issues/186
631
- if (!value || (isArray(value) && value.length === 0))
632
- return this.renderTokens(token[4], context, partials, originalTemplate, config);
633
- };
590
+ // This function is used to render an arbitrary template
591
+ // in the current context by higher-order sections.
592
+ function subRender (template) {
593
+ return self.render(template, context, partials, config);
594
+ }
634
595
 
635
- Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) {
636
- var filteredIndentation = indentation.replace(/[^ \t]/g, '');
637
- var partialByNl = partial.split('\n');
638
- for (var i = 0; i < partialByNl.length; i++) {
639
- if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) {
640
- partialByNl[i] = filteredIndentation + partialByNl[i];
641
- }
642
- }
643
- return partialByNl.join('\n');
644
- };
596
+ if (!value) return;
645
597
 
646
- Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
647
- if (!partials) return;
648
- var tags = this.getConfigTags(config);
649
-
650
- var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
651
- if (value != null) {
652
- var lineHasNonSpace = token[6];
653
- var tagIndex = token[5];
654
- var indentation = token[4];
655
- var indentedValue = value;
656
- if (tagIndex == 0 && indentation) {
657
- indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
658
- }
659
- var tokens = this.parse(indentedValue, tags);
660
- return this.renderTokens(tokens, context, partials, indentedValue, config);
598
+ if (isArray(value)) {
599
+ for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
600
+ buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config);
661
601
  }
662
- };
602
+ } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
603
+ buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config);
604
+ } else if (isFunction(value)) {
605
+ if (typeof originalTemplate !== 'string')
606
+ throw new Error('Cannot use higher-order sections without the original template');
663
607
 
664
- Writer.prototype.unescapedValue = function unescapedValue (token, context) {
665
- var value = context.lookup(token[1]);
666
- if (value != null)
667
- return value;
668
- };
608
+ // Extract the portion of the original template that the section contains.
609
+ value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
669
610
 
670
- Writer.prototype.escapedValue = function escapedValue (token, context, config) {
671
- var escape = this.getConfigEscape(config) || mustache.escape;
672
- var value = context.lookup(token[1]);
673
611
  if (value != null)
674
- return (typeof value === 'number' && escape === mustache.escape) ? String(value) : escape(value);
675
- };
676
-
677
- Writer.prototype.rawValue = function rawValue (token) {
678
- return token[1];
679
- };
680
-
681
- Writer.prototype.getConfigTags = function getConfigTags (config) {
682
- if (isArray(config)) {
683
- return config;
684
- }
685
- else if (config && typeof config === 'object') {
686
- return config.tags;
687
- }
688
- else {
689
- return undefined;
690
- }
691
- };
692
-
693
- Writer.prototype.getConfigEscape = function getConfigEscape (config) {
694
- if (config && typeof config === 'object' && !isArray(config)) {
695
- return config.escape;
696
- }
697
- else {
698
- return undefined;
612
+ buffer += value;
613
+ } else {
614
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate, config);
615
+ }
616
+ return buffer;
617
+ };
618
+
619
+ Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate, config) {
620
+ var value = context.lookup(token[1]);
621
+
622
+ // Use JavaScript's definition of falsy. Include empty arrays.
623
+ // See https://github.com/janl/mustache.js/issues/186
624
+ if (!value || (isArray(value) && value.length === 0))
625
+ return this.renderTokens(token[4], context, partials, originalTemplate, config);
626
+ };
627
+
628
+ Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) {
629
+ var filteredIndentation = indentation.replace(/[^ \t]/g, '');
630
+ var partialByNl = partial.split('\n');
631
+ for (var i = 0; i < partialByNl.length; i++) {
632
+ if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) {
633
+ partialByNl[i] = filteredIndentation + partialByNl[i];
699
634
  }
700
- };
701
-
702
- var mustache = {
703
- name: 'mustache.js',
704
- version: '4.1.0',
705
- tags: [ '{{', '}}' ],
706
- clearCache: undefined,
707
- escape: undefined,
708
- parse: undefined,
709
- render: undefined,
710
- Scanner: undefined,
711
- Context: undefined,
712
- Writer: undefined,
713
- /**
714
- * Allows a user to override the default caching strategy, by providing an
715
- * object with set, get and clear methods. This can also be used to disable
716
- * the cache by setting it to the literal `undefined`.
717
- */
718
- set templateCache (cache) {
719
- defaultWriter.templateCache = cache;
720
- },
721
- /**
722
- * Gets the default or overridden caching object from the default writer.
723
- */
724
- get templateCache () {
725
- return defaultWriter.templateCache;
635
+ }
636
+ return partialByNl.join('\n');
637
+ };
638
+
639
+ Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
640
+ if (!partials) return;
641
+ var tags = this.getConfigTags(config);
642
+
643
+ var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
644
+ if (value != null) {
645
+ var lineHasNonSpace = token[6];
646
+ var tagIndex = token[5];
647
+ var indentation = token[4];
648
+ var indentedValue = value;
649
+ if (tagIndex == 0 && indentation) {
650
+ indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
726
651
  }
727
- };
728
-
729
- // All high-level mustache.* functions use this writer.
730
- var defaultWriter = new Writer();
652
+ var tokens = this.parse(indentedValue, tags);
653
+ return this.renderTokens(tokens, context, partials, indentedValue, config);
654
+ }
655
+ };
731
656
 
732
- /**
733
- * Clears all cached templates in the default writer.
734
- */
735
- mustache.clearCache = function clearCache () {
736
- return defaultWriter.clearCache();
737
- };
657
+ Writer.prototype.unescapedValue = function unescapedValue (token, context) {
658
+ var value = context.lookup(token[1]);
659
+ if (value != null)
660
+ return value;
661
+ };
662
+
663
+ Writer.prototype.escapedValue = function escapedValue (token, context, config) {
664
+ var escape = this.getConfigEscape(config) || mustache.escape;
665
+ var value = context.lookup(token[1]);
666
+ if (value != null)
667
+ return (typeof value === 'number' && escape === mustache.escape) ? String(value) : escape(value);
668
+ };
669
+
670
+ Writer.prototype.rawValue = function rawValue (token) {
671
+ return token[1];
672
+ };
673
+
674
+ Writer.prototype.getConfigTags = function getConfigTags (config) {
675
+ if (isArray(config)) {
676
+ return config;
677
+ }
678
+ else if (config && typeof config === 'object') {
679
+ return config.tags;
680
+ }
681
+ else {
682
+ return undefined;
683
+ }
684
+ };
738
685
 
686
+ Writer.prototype.getConfigEscape = function getConfigEscape (config) {
687
+ if (config && typeof config === 'object' && !isArray(config)) {
688
+ return config.escape;
689
+ }
690
+ else {
691
+ return undefined;
692
+ }
693
+ };
694
+
695
+ var mustache = {
696
+ name: 'mustache.js',
697
+ version: '4.2.0',
698
+ tags: [ '{{', '}}' ],
699
+ clearCache: undefined,
700
+ escape: undefined,
701
+ parse: undefined,
702
+ render: undefined,
703
+ Scanner: undefined,
704
+ Context: undefined,
705
+ Writer: undefined,
739
706
  /**
740
- * Parses and caches the given template in the default writer and returns the
741
- * array of tokens it contains. Doing this ahead of time avoids the need to
742
- * parse templates on the fly as they are rendered.
707
+ * Allows a user to override the default caching strategy, by providing an
708
+ * object with set, get and clear methods. This can also be used to disable
709
+ * the cache by setting it to the literal `undefined`.
743
710
  */
744
- mustache.parse = function parse (template, tags) {
745
- return defaultWriter.parse(template, tags);
746
- };
747
-
711
+ set templateCache (cache) {
712
+ defaultWriter.templateCache = cache;
713
+ },
748
714
  /**
749
- * Renders the `template` with the given `view`, `partials`, and `config`
750
- * using the default writer.
715
+ * Gets the default or overridden caching object from the default writer.
751
716
  */
752
- mustache.render = function render (template, view, partials, config) {
753
- if (typeof template !== 'string') {
754
- throw new TypeError('Invalid template! Template should be a "string" ' +
755
- 'but "' + typeStr(template) + '" was given as the first ' +
756
- 'argument for mustache#render(template, view, partials)');
757
- }
758
-
759
- return defaultWriter.render(template, view, partials, config);
760
- };
717
+ get templateCache () {
718
+ return defaultWriter.templateCache;
719
+ }
720
+ };
721
+
722
+ // All high-level mustache.* functions use this writer.
723
+ var defaultWriter = new Writer();
724
+
725
+ /**
726
+ * Clears all cached templates in the default writer.
727
+ */
728
+ mustache.clearCache = function clearCache () {
729
+ return defaultWriter.clearCache();
730
+ };
731
+
732
+ /**
733
+ * Parses and caches the given template in the default writer and returns the
734
+ * array of tokens it contains. Doing this ahead of time avoids the need to
735
+ * parse templates on the fly as they are rendered.
736
+ */
737
+ mustache.parse = function parse (template, tags) {
738
+ return defaultWriter.parse(template, tags);
739
+ };
740
+
741
+ /**
742
+ * Renders the `template` with the given `view`, `partials`, and `config`
743
+ * using the default writer.
744
+ */
745
+ mustache.render = function render (template, view, partials, config) {
746
+ if (typeof template !== 'string') {
747
+ throw new TypeError('Invalid template! Template should be a "string" ' +
748
+ 'but "' + typeStr(template) + '" was given as the first ' +
749
+ 'argument for mustache#render(template, view, partials)');
750
+ }
761
751
 
762
- // Export the escaping function so that the user may override it.
763
- // See https://github.com/janl/mustache.js/issues/244
764
- mustache.escape = escapeHtml;
752
+ return defaultWriter.render(template, view, partials, config);
753
+ };
765
754
 
766
- // Export these mainly for testing, but also for advanced usage.
767
- mustache.Scanner = Scanner;
768
- mustache.Context = Context;
769
- mustache.Writer = Writer;
755
+ // Export the escaping function so that the user may override it.
756
+ // See https://github.com/janl/mustache.js/issues/244
757
+ mustache.escape = escapeHtml;
770
758
 
771
- return mustache;
759
+ // Export these mainly for testing, but also for advanced usage.
760
+ mustache.Scanner = Scanner;
761
+ mustache.Context = Context;
762
+ mustache.Writer = Writer;
772
763
 
773
- })));
764
+ export default mustache;