8000 Optimize how with-statements are inserted into compiled templates. · lodash/lodash@a5fe1eb · GitHub
[go: up one dir, main page]

Skip to content

Commit a5fe1eb

Browse files
committed
Optimize how with-statements are inserted into compiled templates.
Former-commit-id: aabb0b1f8c6e910532464b7a007767801c00a640
1 parent 5afd37c commit a5fe1eb

File tree

1 file changed

+65
-35
lines changed

1 file changed

+65
-35
lines changed

lodash.js

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737
var oldDash = window._;
3838

3939
/** Used to match empty strings in compiled templates */
40-
var reEmptyStringEvaluate = /\b__p \+= '';/g,
41-
reEmptyStringInterpolate = /\b__p \+= '' \+/g,
42-
reEmptyStringHybrid = /\b__t\) \+\n'';/g;
40+
var reEmptyStringLeading = /\b__p \+= '';/g,
41+
reEmptyStringMiddle = /\b(__p \+?=) '' \+/g,
42+
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
4343

4444
/** Used to insert the data object variable into compiled templates */
4545
var reInsertVariable = /(?:__e|__t = )\(\s*(?![\s"']|this\.)/g;
@@ -3202,10 +3202,13 @@
32023202
// https://github.com/olado/doT
32033203
options || (options = {});
32043204

3205-
var isEscaping,
3205+
var endIndex,
3206+
isEscaping,
32063207
isEvaluating,
32073208
isInterpolating,
3209+
startIndex,
32083210
result,
3211+
useWith,
32093212
defaults = lodash.templateSettings,
32103213
escapeDelimiter = options.escape,
32113214
evaluateDelimiter = options.evaluate,
@@ -3222,7 +3225,6 @@
32223225
if (interpolateDelimiter == null) {
32233226
interpolateDelimiter = defaults.interpolate;
32243227
}
3225-
32263228
// tokenize delimiters to avoid escaping them
32273229
if (escapeDelimiter) {
32283230
isEscaping = text != (text = text.replace(escapeDelimiter, tokenizeEscape));
@@ -3231,55 +3233,83 @@
32313233
isInterpolating = text != (text = text.replace(interpolateDelimiter, tokenizeInterpolate));
32323234
}
32333235
if (evaluateDelimiter) {
3236+
startIndex = tokenized.length;
32343237
isEvaluating = text != (text = text.replace(evaluateDelimiter, tokenizeEvaluate));
3238+
endIndex = tokenized.length - 1;
3239+
}
3240+
3241+
// if `options.variable` is not specified and the template contains "evaluate"
3242+
// delimiters, inject a with-statement around all "evaluate" delimiters to
3243+
// add the data object to the top of the scope chain
3244+
if (!variable) {
3245+
variable = defaults.variable || lastVariable || 'obj';
3246+
useWith = isEvaluating;
3247+
3248+
if (useWith) {
3249+
tokenized[startIndex] =
3250+
tokenized[startIndex].slice(0, 3) +
3251+
'__with (' + variable + ') {\n' +
3252+
tokenized[startIndex].slice(3);
3253+
3254+
tokenized[endIndex] =
3255+
tokenized[endIndex].slice(0, -8) +
3256+
'}__\n' +
3257+
tokenized[endIndex].slice(-8);
3258+
}
32353259
}
3260+
// memoize `reDoubleVariable`
3261+
if (variable != lastVariable) {
3262+
lastVariable = variable;
3263+
reDoubleVariable = RegExp('( EDBE [(\\s])' + variable + '\\.' + variable + '\\b', 'g');
3264+
}
3265+
3266+
var strInsertVariable = '$&' + variable + '.',
3267+
strDoubleVariable = '$1__d';
32363268

32373269
// escape characters that cannot be included in string literals and
32383270
// detokenize delimiter code snippets
3239-
text = "__p='" + text
3271+
text = "__p = '" + text
32403272
.replace(reUnescapedString, escapeStringChar)
32413273
.replace(reToken, detokenize) + "';\n";
32423274

32433275
// clear stored code snippets
32443276
tokenized.length = 0;
32453277

3246-
// strip concating empty strings
3247-
if (isInterpolating) {
3248-
text = text.replace(reEmptyStringInterpolate, '__p \+=');
3249-
}
3250-
if (isEvaluating) {
3251-
text = text.replace(reEmptyStringEvaluate, '');
3252-
if (isInterpolating) {
3253-
text = text.replace(reEmptyStringHybrid, '__t);');
3254-
}
3255-
}
3278+
// find the start and end indexes of the with-statement
3279+
if (useWith) {
3280+
startIndex = text.indexOf('__with');
3281+
endIndex = text.indexOf('}__', startIndex + 12);
3282+
}
3283+
3284+
// inject data object references outside of the with-statement
3285+
text = (useWith ? text.slice(0, startIndex) : text)
3286+
.replace(reInsertVariable, strInsertVariable)
3287+
.replace(reDoubleVariable, strDoubleVariable) +
3288+
(useWith
3289+
? text.slice(startIndex + 2, endIndex + 1) +
3290+
text.slice(endIndex + 3)
3291+
.replace(reInsertVariable, strInsertVariable)
3292+
.replace(reDoubleVariable, strDoubleVariable)
3293+
: ''
3294+
);
32563295

3257-
if (!variable) {
3258-
variable = defaults.variable;
3259-
3260-
// if `options.variable` is not specified or the template contains "evaluate"
3261-
// delimiters, add the data object to the top of the scope chain
3262-
if (isEvaluating || !variable) {
3263-
text = 'with (' + variable + ' || {}) {\n' + text + '\n}\n';
3264-
}
3265-
// else insert data object references to avoid using a with-statement
3266-
else {
3267-
if (variable != lastVariable) {
3268-
lastVariable = variable;
3269-
reDoubleVariable = RegExp('([(\\s])(' + variable + '\\.' + variable + ')\\b', 'g');
3270-
}
3271-
text = text
3272-
.replace(reInsertVariable, '$&' + variable + '.')
3273-
.replace(reDoubleVariable, '$1($2 || ' + variable + ')');
3274-
}
3275-
}
3296+
// cleanup compiled code by stripping empty strings
3297+
text = (isEvaluating ? text.replace(reEmptyStringLeading, '') : text)
3298+
.replace(reEmptyStringMiddle, '$1')
3299+
.replace(reEmptyStringTrailing, '$1;');
32763300

3301+
// wrap function body
32773302
text = 'function(' + variable + ') {\n' +
3303+
(useWith
3304+
? variable + ' || (' + variable + ' = {});\n'
3305+
: ''
3306+
) +
32783307
'var __p' +
32793308
(isInterpolating
32803309
? ', __t'
32813310
: ''
32823311
) +
3312+
', __d = ' + variable + '.' + variable + ' || ' + variable +
32833313
(isEscaping
32843314
? ', __e = _.escape'
32853315
: ''

0 commit comments

Comments
 (0)
0