mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-11 19:37:49 +00:00
Fix template regressions. [Closes #44]
Former-commit-id: 15e98d86c290fea74780822b49b5d71e54064e01
This commit is contained in:
102
lodash.js
102
lodash.js
@@ -50,15 +50,10 @@
|
|||||||
/** Used to detect delimiter values that should be processed by `tokenizeEvaluate` */
|
/** Used to detect delimiter values that should be processed by `tokenizeEvaluate` */
|
||||||
var reComplexDelimiter = /[-+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/;
|
var reComplexDelimiter = /[-+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/;
|
||||||
|
|
||||||
/** Used to match code generated in place of template delimiters */
|
|
||||||
var reDelimiterCodeLeading = /^';\n/,
|
|
||||||
reDelimiterCodeMiddle = /^' \+\n/,
|
|
||||||
reDelimiterCodeTrailing = /(?:__p \+= '|\+\n')$/;
|
|
||||||
|
|
||||||
/** Used to match empty string literals in compiled template source */
|
/** Used to match empty string literals in compiled template source */
|
||||||
var reEmptyStringLeading = /\b__p \+= '';/g,
|
var reEmptyStringLeading = /\b__p \+= '';/g,
|
||||||
reEmptyStringMiddle = /\b(__p \+?=) '' \+/g,
|
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
|
||||||
reEmptyStringTrailing = /(__w?e\(.*?\)|\b__w?t\)) \+\n'';/g;
|
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
|
||||||
|
|
||||||
/** Used to insert the data object variable into compiled template source */
|
/** Used to insert the data object variable into compiled template source */
|
||||||
var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g;
|
var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g;
|
||||||
@@ -672,12 +667,10 @@
|
|||||||
var index = tokenized.length;
|
var index = tokenized.length;
|
||||||
if (value) {
|
if (value) {
|
||||||
tokenized[index] = "';\n" + value + ";\n__p += '"
|
tokenized[index] = "';\n" + value + ";\n__p += '"
|
||||||
}
|
} else if (escapeValue) {
|
||||||
else if (escapeValue) {
|
tokenized[index] = "' +\n__e(" + escapeValue + ") +\n'";
|
||||||
tokenized[index] = "' +\n__we(" + escapeValue + ") +\n'";
|
} else if (interpolateValue) {
|
||||||
}
|
tokenized[index] = "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
|
||||||
else if (interpolateValue) {
|
|
||||||
tokenized[index] = "' +\n((__wt = (" + interpolateValue + ")) == null ? '' : __wt) +\n'";
|
|
||||||
}
|
}
|
||||||
return token + index;
|
return token + index;
|
||||||
}
|
}
|
||||||
@@ -3307,11 +3300,8 @@
|
|||||||
// https://github.com/olado/doT
|
// https://github.com/olado/doT
|
||||||
options || (options = {});
|
options || (options = {});
|
||||||
|
|
||||||
var endIndex,
|
var isEvaluating,
|
||||||
isEvaluating,
|
|
||||||
startIndex,
|
|
||||||
result,
|
result,
|
||||||
useWith,
|
|
||||||
escapeDelimiter = options.escape,
|
escapeDelimiter = options.escape,
|
||||||
evaluateDelimiter = options.evaluate,
|
evaluateDelimiter = options.evaluate,
|
||||||
interpolateDelimiter = options.interpolate,
|
interpolateDelimiter = options.interpolate,
|
||||||
@@ -3337,83 +3327,63 @@
|
|||||||
text = text.replace(interpolateDelimiter, tokenizeInterpolate);
|
text = text.replace(interpolateDelimiter, tokenizeInterpolate);
|
||||||
}
|
}
|
||||||
if (evaluateDelimiter != lastEvaluateDelimiter) {
|
if (evaluateDelimiter != lastEvaluateDelimiter) {
|
||||||
|
// generate `reEvaluateDelimiter` to match `_.templateSettings.evaluate`
|
||||||
|
// and internal `<e%- %>`, `<e%= %>` delimiters
|
||||||
lastEvaluateDelimiter = evaluateDelimiter;
|
lastEvaluateDelimiter = evaluateDelimiter;
|
||||||
reEvaluateDelimiter = RegExp(
|
reEvaluateDelimiter = RegExp(
|
||||||
(evaluateDelimiter ? evaluateDelimiter.source : '($^)') +
|
(evaluateDelimiter ? evaluateDelimiter.source : '($^)') +
|
||||||
'|<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>'
|
'|<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>'
|
||||||
, 'g');
|
, 'g');
|
||||||
}
|
}
|
||||||
startIndex = tokenized.length;
|
isEvaluating = tokenized.length;
|
||||||
text = text.replace(reEvaluateDelimiter, tokenizeEvaluate);
|
text = text.replace(reEvaluateDelimiter, tokenizeEvaluate);
|
||||||
endIndex = tokenized.length - 1;
|
isEvaluating = isEvaluating != tokenized.length;
|
||||||
isEvaluating = startIndex <= endIndex;
|
|
||||||
|
|
||||||
// if `options.variable` is not specified and the template contains "evaluate"
|
|
||||||
// delimiters, inject a with-statement around all "evaluate" delimiters to
|
|
||||||
// add the data object to the top of the scope chain
|
|
||||||
if (!variable) {
|
|
||||||
variable = settings.variable || lastVariable || 'obj';
|
|
||||||
useWith = isEvaluating;
|
|
||||||
|
|
||||||
if (useWith) {
|
|
||||||
tokenized[startIndex] = "';\n__with (" + variable + ') {\n' + tokenized[startIndex]
|
|
||||||
.replace(reDelimiterCodeLeading, '')
|
|
||||||
.replace(reDelimiterCodeMiddle, '__p += ');
|
|
||||||
|
|
||||||
tokenized[endIndex] = tokenized[endIndex]
|
|
||||||
.replace(reDelimiterCodeTrailing, '') + "\n}__\n__p += '";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var strInsertVariable = '$&' + variable + '.',
|
|
||||||
strDoubleVariable = '$1__d';
|
|
||||||
|
|
||||||
// escape characters that cannot be included in string literals and
|
// escape characters that cannot be included in string literals and
|
||||||
// detokenize delimiter code snippets
|
// detokenize delimiter code snippets
|
||||||
text = "__p = '" + text
|
text = "__p += '" + text
|
||||||
.replace(reUnescapedString, escapeStringChar)
|
.replace(reUnescapedString, escapeStringChar)
|
||||||
.replace(reToken, detokenize) + "';\n";
|
.replace(reToken, detokenize) + "';\n";
|
||||||
|
|
||||||
// clear stored code snippets
|
// clear stored code snippets
|
||||||
tokenized.length = 0;
|
tokenized.length = 0;
|
||||||
|
|
||||||
// find the start and end indexes of the with-statement
|
// if `options.variable` is not specified and the template contains "evaluate"
|
||||||
if (useWith) {
|
// delimiters, wrap a with-statement around the generated code to add the
|
||||||
startIndex = text.indexOf('__with');
|
// data object to the top of the scope chain
|
||||||
endIndex = text.indexOf('}__', startIndex + 10);
|
if (!variable) {
|
||||||
|
variable = settings.variable || lastVariable || 'obj';
|
||||||
|
|
||||||
|
if (isEvaluating) {
|
||||||
|
text = 'with (' + variable + ') {\n' + text + '\n}\n';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (variable != lastVariable) {
|
||||||
|
// generate `reDoubleVariable` to match references like `obj.obj` inside
|
||||||
|
// transformed "escape" and "interpolate" delimiters
|
||||||
|
lastVariable = variable;
|
||||||
|
reDoubleVariable = RegExp('(\\(\\s*)' + variable + '\\.' + variable + '\\b', 'g');
|
||||||
|
}
|
||||||
|
// avoid a with-statement by prepending data object references to property names
|
||||||
|
text = text
|
||||||
|
.replace(reInsertVariable, '$&' + variable + '.')
|
||||||
|
.replace(reDoubleVariable, '$1__d');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// memoize `reDoubleVariable`
|
|
||||||
if (variable != lastVariable) {
|
|
||||||
lastVariable = variable;
|
|
||||||
reDoubleVariable = RegExp('([(\\s])' + variable + '\\.' + variable + '\\b', 'g');
|
|
||||||
}
|
|
||||||
// prepend data object references to property names outside of the with-statement
|
|
||||||
text = (useWith ? text.slice(0, startIndex) : text)
|
|
||||||
.replace(reInsertVariable, strInsertVariable)
|
|
||||||
.replace(reDoubleVariable, strDoubleVariable) +
|
|
||||||
(useWith
|
|
||||||
? text.slice(startIndex + 2, endIndex + 1) +
|
|
||||||
text.slice(endIndex + 3)
|
|
||||||
.replace(reInsertVariable, strInsertVariable)
|
|
||||||
.replace(reDoubleVariable, strDoubleVariable)
|
|
||||||
: ''
|
|
||||||
);
|
|
||||||
|
|
||||||
// cleanup code by stripping empty strings
|
// cleanup code by stripping empty strings
|
||||||
text = (isEvaluating ? text.replace(reEmptyStringLeading, '') : text)
|
text = ( isEvaluating ? text.replace(reEmptyStringLeading, '') : text)
|
||||||
.replace(reEmptyStringMiddle, '$1')
|
.replace(reEmptyStringMiddle, '$1')
|
||||||
.replace(reEmptyStringTrailing, '$1;');
|
.replace(reEmptyStringTrailing, '$1;');
|
||||||
|
|
||||||
// frame code as the function body
|
// frame code as the function body
|
||||||
text = 'function(' + variable + ') {\n' +
|
text = 'function(' + variable + ') {\n' +
|
||||||
variable + ' || (' + variable + ' = {});\n' +
|
variable + ' || (' + variable + ' = {});\n' +
|
||||||
'var __p, __t, __wt' +
|
'var __t, __p = \'\', __e = _.escape' +
|
||||||
', __d = ' + variable + '.' + variable + ' || ' + variable +
|
|
||||||
', __e = _.escape, __we = __e' +
|
|
||||||
(isEvaluating
|
(isEvaluating
|
||||||
? ', __j = Array.prototype.join;\n' +
|
? ', __j = Array.prototype.join;\n' +
|
||||||
'function print() { __p += __j.call(arguments, \'\') }\n'
|
'function print() { __p += __j.call(arguments, \'\') }\n'
|
||||||
: ';\n'
|
: ', __d = ' + variable + '.' + variable + ' || ' + variable + ';\n'
|
||||||
) +
|
) +
|
||||||
text +
|
text +
|
||||||
'return __p\n}';
|
'return __p\n}';
|
||||||
|
|||||||
25
test/test.js
25
test/test.js
@@ -771,9 +771,32 @@
|
|||||||
var compiled = _.template(key),
|
var compiled = _.template(key),
|
||||||
data = { 'a': 1, 'b': 2 };
|
data = { 'a': 1, 'b': 2 };
|
||||||
|
|
||||||
equal(compiled(data), value);
|
equal(compiled(data), value, key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should allow referencing variables declared in "evaluate" delimiters from other delimiters', function() {
|
||||||
|
var compiled = _.template('<% var b = a; %><%= b.value %>'),
|
||||||
|
data = { 'a': { 'value': 1 } };
|
||||||
|
|
||||||
|
equal(compiled(data), '1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should work when passing `options.variable`', function() {
|
||||||
|
var compiled = _.template(
|
||||||
|
'<% _.forEach( data.a, function( value ) { %>' +
|
||||||
|
'<%= value.valueOf() %>' +
|
||||||
|
'<% }) %>', null, { 'variable': 'data' }
|
||||||
|
);
|
||||||
|
|
||||||
|
var data = { 'a': [1, 2, 3] };
|
||||||
|
|
||||||
|
try {
|
||||||
|
equal(compiled(data), '123');
|
||||||
|
} catch(e) {
|
||||||
|
ok(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|||||||
Reference in New Issue
Block a user