|
50 | 50 | /** Used to detect delimiter values that should be processed by `tokenizeEvaluate` */ |
51 | 51 | varreComplexDelimiter=/[-+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/; |
52 | 52 |
|
53 | | -/** Used to match code generated in place of template delimiters */ |
54 | | -varreDelimiterCodeLeading=/^';\n/, |
55 | | -reDelimiterCodeMiddle=/^'\+\n/, |
56 | | -reDelimiterCodeTrailing=/(?:__p\+='|\+\n')$/; |
57 | | - |
58 | 53 | /** Used to match empty string literals in compiled template source */ |
59 | 54 | varreEmptyStringLeading=/\b__p\+='';/g, |
60 | | -reEmptyStringMiddle=/\b(__p\+?=)''\+/g, |
61 | | -reEmptyStringTrailing=/(__w?e\(.*?\)|\b__w?t\))\+\n'';/g; |
| 55 | +reEmptyStringMiddle=/\b(__p\+=)''\+/g, |
| 56 | +reEmptyStringTrailing=/(__e\(.*?\)|\b__t\))\+\n'';/g; |
62 | 57 |
|
63 | 58 | /** Used to insert the data object variable into compiled template source */ |
64 | 59 | varreInsertVariable=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g; |
|
672 | 667 | varindex=tokenized.length; |
673 | 668 | if(value){ |
674 | 669 | tokenized[index]="';\n"+value+";\n__p += '" |
675 | | -} |
676 | | -elseif(escapeValue){ |
677 | | -tokenized[index]="' +\n__we("+escapeValue+") +\n'"; |
678 | | -} |
679 | | -elseif(interpolateValue){ |
680 | | -tokenized[index]="' +\n((__wt = ("+interpolateValue+")) == null ? '' : __wt) +\n'"; |
| 670 | +}elseif(escapeValue){ |
| 671 | +tokenized[index]="' +\n__e("+escapeValue+") +\n'"; |
| 672 | +}elseif(interpolateValue){ |
| 673 | +tokenized[index]="' +\n((__t = ("+interpolateValue+")) == null ? '' : __t) +\n'"; |
681 | 674 | } |
682 | 675 | returntoken+index; |
683 | 676 | } |
|
3307 | 3300 | // https://github.com/olado/doT |
3308 | 3301 | options||(options={}); |
3309 | 3302 |
|
3310 | | -varendIndex, |
3311 | | -isEvaluating, |
3312 | | -startIndex, |
| 3303 | +varisEvaluating, |
3313 | 3304 | result, |
3314 | | -useWith, |
3315 | 3305 | escapeDelimiter=options.escape, |
3316 | 3306 | evaluateDelimiter=options.evaluate, |
3317 | 3307 | interpolateDelimiter=options.interpolate, |
|
3337 | 3327 | text=text.replace(interpolateDelimiter,tokenizeInterpolate); |
3338 | 3328 | } |
3339 | 3329 | if(evaluateDelimiter!=lastEvaluateDelimiter){ |
| 3330 | +// generate `reEvaluateDelimiter` to match `_.templateSettings.evaluate` |
| 3331 | +// and internal `<e%- %>`, `<e%= %>` delimiters |
3340 | 3332 | lastEvaluateDelimiter=evaluateDelimiter; |
3341 | 3333 | reEvaluateDelimiter=RegExp( |
3342 | 3334 | (evaluateDelimiter ?evaluateDelimiter.source :'($^)')+ |
3343 | 3335 | '|<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>' |
3344 | 3336 | ,'g'); |
3345 | 3337 | } |
3346 | | -startIndex=tokenized.length; |
| 3338 | +isEvaluating=tokenized.length; |
3347 | 3339 | text=text.replace(reEvaluateDelimiter,tokenizeEvaluate); |
3348 | | -endIndex=tokenized.length-1; |
3349 | | -isEvaluating=startIndex<=endIndex; |
3350 | | - |
3351 | | -// if `options.variable` is not specified and the template contains "evaluate" |
3352 | | -// delimiters, inject a with-statement around all "evaluate" delimiters to |
3353 | | -// add the data object to the top of the scope chain |
3354 | | -if(!variable){ |
3355 | | -variable=settings.variable||lastVariable||'obj'; |
3356 | | -useWith=isEvaluating; |
3357 | | - |
3358 | | -if(useWith){ |
3359 | | -tokenized[startIndex]="';\n__with ("+variable+') {\n'+tokenized[startIndex] |
3360 | | -.replace(reDelimiterCodeLeading,'') |
3361 | | -.replace(reDelimiterCodeMiddle,'__p += '); |
3362 | | - |
3363 | | -tokenized[endIndex]=tokenized[endIndex] |
3364 | | -.replace(reDelimiterCodeTrailing,'')+"\n}__\n__p += '"; |
3365 | | -} |
3366 | | -} |
3367 | | - |
3368 | | -varstrInsertVariable='$&'+variable+'.', |
3369 | | -strDoubleVariable='$1__d'; |
| 3340 | +isEvaluating=isEvaluating!=tokenized.length; |
3370 | 3341 |
|
3371 | 3342 | // escape characters that cannot be included in string literals and |
3372 | 3343 | // detokenize delimiter code snippets |
3373 | | -text="__p = '"+text |
| 3344 | +text="__p+= '"+text |
3374 | 3345 | .replace(reUnescapedString,escapeStringChar) |
3375 | 3346 | .replace(reToken,detokenize)+"';\n"; |
3376 | 3347 |
|
3377 | 3348 | // clear stored code snippets |
3378 | 3349 | tokenized.length=0; |
3379 | 3350 |
|
3380 | | -// find the start and end indexes of the with-statement |
3381 | | -if(useWith){ |
3382 | | -startIndex=text.indexOf('__with'); |
3383 | | -endIndex=text.indexOf('}__',startIndex+10); |
3384 | | -} |
3385 | | -// memoize `reDoubleVariable` |
3386 | | -if(variable!=lastVariable){ |
3387 | | -lastVariable=variable; |
3388 | | -reDoubleVariable=RegExp('([(\\s])'+variable+'\\.'+variable+'\\b','g'); |
3389 | | -} |
3390 | | -// prepend data object references to property names outside of the with-statement |
3391 | | -text=(useWith ?text.slice(0,startIndex) :text) |
3392 | | -.replace(reInsertVariable,strInsertVariable) |
3393 | | -.replace(reDoubleVariable,strDoubleVariable)+ |
3394 | | -(useWith |
3395 | | - ?text.slice(startIndex+2,endIndex+1)+ |
3396 | | -text.slice(endIndex+3) |
3397 | | -.replace(reInsertVariable,strInsertVariable) |
3398 | | -.replace(reDoubleVariable,strDoubleVariable) |
3399 | | - :'' |
3400 | | -); |
| 3351 | +// if `options.variable` is not specified and the template contains "evaluate" |
| 3352 | +// delimiters, wrap a with-statement around the generated code to add the |
| 3353 | +// data object to the top of the scope chain |
| 3354 | +if(!variable){ |
| 3355 | +variable=settings.variable||lastVariable||'obj'; |
| 3356 | + |
| 3357 | +if(isEvaluating){ |
| 3358 | +text='with ('+variable+') {\n'+text+'\n}\n'; |
| 3359 | +} |
| 3360 | +else{ |
| 3361 | +if(variable!=lastVariable){ |
| 3362 | +// generate `reDoubleVariable` to match references like `obj.obj` inside |
| 3363 | +// transformed "escape" and "interpolate" delimiters |
| 3364 | +lastVariable=variable; |
| 3365 | +reDoubleVariable=RegExp('(\\(\\s*)'+variable+'\\.'+variable+'\\b','g'); |
| 3366 | +} |
| 3367 | +// avoid a with-statement by prepending data object references to property names |
| 3368 | +text=text |
| 3369 | +.replace(reInsertVariable,'$&'+variable+'.') |
| 3370 | +.replace(reDoubleVariable,'$1__d'); |
| 3371 | +} |
| 3372 | +} |
3401 | 3373 |
|
3402 | 3374 | // cleanup code by stripping empty strings |
3403 | | -text=(isEvaluating ?text.replace(reEmptyStringLeading,'') :text) |
| 3375 | +text=(isEvaluating ?text.replace(reEmptyStringLeading,'') :text) |
3404 | 3376 | .replace(reEmptyStringMiddle,'$1') |
3405 | 3377 | .replace(reEmptyStringTrailing,'$1;'); |
3406 | 3378 |
|
3407 | 3379 | // frame code as the function body |
3408 | 3380 | text='function('+variable+') {\n'+ |
3409 | 3381 | variable+' || ('+variable+' = {});\n'+ |
3410 | | -'var __p, __t, __wt'+ |
3411 | | -', __d = '+variable+'.'+variable+' || '+variable+ |
3412 | | -', __e = _.escape, __we = __e'+ |
| 3382 | +'var __t, __p = \'\', __e = _.escape'+ |
3413 | 3383 | (isEvaluating |
3414 | 3384 | ?', __j = Array.prototype.join;\n'+ |
3415 | 3385 | 'function print() { __p += __j.call(arguments, \'\') }\n' |
3416 | | - :';\n' |
| 3386 | + :', __d = '+variable+'.'+variable+' || '+variable+';\n' |
3417 | 3387 | )+ |
3418 | 3388 | text+ |
3419 | 3389 | 'return __p\n}'; |
|