context-parser-handlebars
Advanced tools
Comparing version 1.0.1 to 1.0.2
{ | ||
"name": "context-parser-handlebars", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"licenses": [ | ||
@@ -5,0 +5,0 @@ { |
@@ -50,9 +50,5 @@ /* | ||
/* The flag is used to print out the char to console */ | ||
/* the flag is used to print out the char to console */ | ||
this._printChar = typeof printChar !== undefined? printChar : true; | ||
/* The flag is used to enable the output filter format as Handlebars 2.0.0 subexpression or not. */ | ||
this._enableSubexpression = true; | ||
this._handlebarsVersion = require('handlebars').VERSION; | ||
/* save the line number being processed */ | ||
@@ -63,4 +59,2 @@ this._lineNo = 1; | ||
debug("_printChar:"+this._printChar); | ||
debug("_enableSubexpression:"+this._enableSubexpression); | ||
debug("_handlebarsVersion:"+this._handlebarsVersion); | ||
} | ||
@@ -133,6 +127,4 @@ | ||
/* '{' 'space'* 'non-space'+ 'space'* 'non-{'* '}' */ | ||
ContextParserHandlebars.expressionRegExp = /^{\s*(\S+)\s*([^\}]*)?}/; | ||
/* '{' 'non-{,non-}'+ '}' and not follow by '}' */ | ||
ContextParserHandlebars.escapeExpressionRegExp = /^\{[^\}\{]+?\}(?!})/; | ||
/* '{{' '~'? 'space'* ('not space{}~'+) 'space'* ('not {}~'*) '~'? greedy '}}' and not follow by '}' */ | ||
ContextParserHandlebars.expressionRegExp = /^\{\{~?\s*([^\s\}\{~]+)\s*([^\}\{~]*)~??\}\}(?!})/; | ||
@@ -155,4 +147,3 @@ /** | ||
var firststr = "", | ||
obj = { | ||
var obj = { | ||
filter: '', | ||
@@ -163,20 +154,8 @@ isPrefixWithKnownFilter: false, | ||
/* | ||
* Substring the input string and match it | ||
* Note: the expected format is "{.*}". | ||
* it is isValidExpression and !isHandlebarsReservedExpression. | ||
*/ | ||
var str = input.slice(i); | ||
var j = str.indexOf('}'); | ||
str = str.slice(0, j+1); | ||
var m = ContextParserHandlebars.expressionRegExp.exec(str); | ||
if (m !== null) { | ||
var isReservedChar; | ||
if (m[1] !== undefined) { | ||
firststr = m[1]; | ||
isReservedChar = handlebarsUtil.isReservedChar(m[1][0]); | ||
/* special handling for {else} */ | ||
if (firststr === 'else') { | ||
if (m[1] !== undefined && m[2] !== undefined) { | ||
if (m[1] === 'else') { | ||
obj.isSingleIdentifier = false; | ||
@@ -186,15 +165,21 @@ obj.isPrefixWithKnownFilter = true; | ||
} | ||
if (isReservedChar) { | ||
if (m[1] === '^' && m[2] === '') { | ||
obj.isSingleIdentifier = false; | ||
obj.isPrefixWithKnownFilter = true; | ||
return obj; | ||
} | ||
} | ||
if (m[2] === undefined) { | ||
obj.isSingleIdentifier = true; | ||
} else { | ||
obj.filter = firststr; | ||
var k = this._knownFilters.indexOf(obj.filter); | ||
if (k !== -1) { | ||
obj.isPrefixWithKnownFilter = true; | ||
if (handlebarsUtil.isReservedChar(m[1], 0)) { | ||
obj.isSingleIdentifier = false; | ||
obj.isPrefixWithKnownFilter = false; | ||
return obj; | ||
} | ||
if (m[2] === '') { | ||
obj.isSingleIdentifier = true; | ||
} else { | ||
obj.filter = m[1]; | ||
var k = this._knownFilters.indexOf(obj.filter); | ||
if (k !== -1) { | ||
obj.isPrefixWithKnownFilter = true; | ||
} | ||
} | ||
} | ||
@@ -211,4 +196,3 @@ } | ||
* @param {string} input - The input string of HTML5 web page. | ||
* @param {integer} ptr - The index of the current character in the input string, it is pointing to the last brace of the open brace of the expression. | ||
* @param {string} extraInfo - The extra information for filters judgement. | ||
* @param {string} expressionInfo - The extra information for filters judgement. | ||
* @returns {Array} The Array of the customized filters. | ||
@@ -220,8 +204,6 @@ * | ||
*/ | ||
ContextParserHandlebars.prototype._addFilters = function(state, input, ptr, extraInfo) { | ||
ContextParserHandlebars.prototype._addFilters = function(state, input, expressionInfo) { | ||
/* transitent var */ | ||
var e, | ||
f, | ||
msg; | ||
var e, f, msg; | ||
@@ -231,4 +213,4 @@ /* return filters */ | ||
var attributeName = extraInfo.attributeName, | ||
attributeValue = extraInfo.attributeValue; | ||
var attributeName = expressionInfo.attributeName, | ||
attributeValue = expressionInfo.attributeValue; | ||
@@ -417,10 +399,5 @@ debug("_addFilters:state:"+state+",attrname:"+attributeName+",attrvalue:"+attributeValue); | ||
// validate the Handlebars template before analysis. | ||
// validate the Handlebars template before/after analysis. | ||
ContextParserHandlebars.prototype._validateTemplate = function(template) { | ||
var msg; | ||
if (!Handlebars.VERSION.match(/^2\./)) { | ||
msg = "[ERROR] ContextParserHandlebars: We support Handlebars 2.0 ONLY!"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
try { | ||
@@ -434,10 +411,159 @@ Handlebars.parse(template); | ||
// TODO: the current assumption is partial keeps in/out state the same (DATA state) | ||
ContextParserHandlebars.prototype._handlePartialTemplate = function() { | ||
// consume the raw expression. | ||
ContextParserHandlebars.prototype._handleRawExpression = function(input, i, len, state) { | ||
var msg; | ||
for(var j=i;j<len;++j) { | ||
if (input[j] === '}' && j+2<len && input[j+1] === '}' && input[j+2] === '}') { | ||
this.printChar('}}}'); | ||
/* advance the index pointer j to the char after the last brace of expression. */ | ||
j=j+3; | ||
/* update the Context Parser's state if it is raw expression */ | ||
this.state = state; | ||
/* for printCharWithState */ | ||
this.bytes[j] = input[j-1]; | ||
this.symbols[j] = this.lookupChar(input[j-1]); | ||
this.states[j] = state; | ||
return j; | ||
} | ||
this.printChar(input[j]); | ||
} | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}}' close brace of raw expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
}; | ||
// TODO: refactor the LOGIC #A into this function | ||
ContextParserHandlebars.prototype._handleBranchTemplate = function() { | ||
// consume the escape expression. | ||
ContextParserHandlebars.prototype._handleEscapeExpression = function(input, i, len, state) { | ||
var msg, | ||
str = '{{'; | ||
/* parse expression */ | ||
var extraExpressionInfo = this._parseExpression(input, i), | ||
isPrefixWithKnownFilter = extraExpressionInfo.isPrefixWithKnownFilter, | ||
filters = []; | ||
/* add filters if it is not prefix with known filter */ | ||
if (!isPrefixWithKnownFilter) { | ||
/* we suppress the escapeExpression of handlebars by changing the {{expression}} into {{{expression}}} */ | ||
str += '{'; | ||
/* get the customized filter based on the current HTML5 state before the Handlebars template expression. */ | ||
var expressionInfo = { | ||
'attributeName': this.getAttributeName(), | ||
'attributeValue': this.getAttributeValue(), | ||
}; | ||
filters = this._addFilters(state, input, expressionInfo); | ||
for(var k=filters.length-1;k>=0;--k) { | ||
if (extraExpressionInfo.isSingleIdentifier && k === 0) { | ||
str += filters[k] + " "; | ||
} else { | ||
str += filters[k] + " ("; | ||
} | ||
} | ||
} | ||
this.printChar(str); | ||
for(var j=i+2;j<len;++j) { | ||
if (input[j] === '}' && j+1 < len && input[j+1] === '}') { | ||
for(var l=filters.length-1;l>=0;--l) { | ||
if (extraExpressionInfo.isSingleIdentifier && l === 0) { | ||
} else { | ||
this.printChar(')'); | ||
} | ||
} | ||
/* advance the index pointer j to the char after the last brace of expression. */ | ||
this.printChar('}}'); | ||
j=j+2; | ||
/* we suppress the escapeExpression of handlebars by changing the {{expression}} into {{{expression}}} */ | ||
if (!isPrefixWithKnownFilter) { | ||
this.printChar('}'); | ||
} | ||
/* update the Context Parser's state if it is not reserved tag */ | ||
this.state = state; | ||
/* for printCharWithState */ | ||
this.bytes[j] = input[j-1]; | ||
this.symbols[j] = this.lookupChar(input[j-1]); | ||
this.states[j] = state; | ||
return j; | ||
} else { | ||
this.printChar(input[j]); | ||
} | ||
} | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' close brace of escape expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
}; | ||
// consume the comment expression. | ||
ContextParserHandlebars.prototype._handleCommentExpression = function(input, i, len, type) { | ||
var msg; | ||
for(var j=i;j<len;++j) { | ||
if (type === handlebarsUtil.COMMENT_EXPRESSION_LONG_FORM) { | ||
if (input[j] === '-' && j+3<len && input[j+1] === '-' && input[j+2] === '}' && input[j+3] === '}') { | ||
this.printChar('--}}'); | ||
/* advance the index pointer j to the char after the last brace of expression. */ | ||
j=j+4; | ||
return j; | ||
} | ||
} else if (type === handlebarsUtil.COMMENT_EXPRESSION_SHORT_FORM) { | ||
if (input[j] === '}' && j+1<len && input[j+1] === '}') { | ||
this.printChar('}}'); | ||
/* advance the index pointer j to the char after the last brace of expression. */ | ||
j=j+2; | ||
return j; | ||
} | ||
} | ||
this.printChar(input[j]); | ||
} | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' or '--}}' close brace of comment expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
}; | ||
// consume the expression with }} at the end | ||
ContextParserHandlebars.prototype._handleExpression = function(input, i, len) { | ||
var msg; | ||
for(var j=i;j<len;++j) { | ||
if (input[j] === '}' && j+1<len && input[j+1] === '}') { | ||
this.printChar('}}'); | ||
/* advance the index pointer j to the char after the last brace of expression. */ | ||
j=j+2; | ||
return j; | ||
} | ||
this.printChar(input[j]); | ||
} | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' close brace of partial expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
}; | ||
// consume the branching expression. | ||
ContextParserHandlebars.prototype._handleBranchExpression = function(input, i, state) { | ||
var msg; | ||
try { | ||
var ast = handlebarsUtil.buildBranchAst(input, i); | ||
var result = handlebarsUtil.analyseBranchAst(ast, state); | ||
/* print the output */ | ||
this.printChar(result.output); | ||
/* advance the index pointer i to the char after the last brace of branching expression. */ | ||
i = i+ast.index+1; | ||
this.state = result.lastStates[0]; | ||
debug("_handleBranchTemplate: state:"+this.state+",i:"+i); | ||
return i; | ||
} catch (err) { | ||
msg = err + " ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
}; | ||
/** | ||
@@ -467,252 +593,114 @@ * @function module:ContextParserHandlebars._handleTemplate | ||
var index = i; | ||
/* the length of the input */ | ||
var len = input.length; | ||
/* regular expression validation result */ | ||
var re; | ||
/* error msg */ | ||
var msg; | ||
/* the length of the input */ | ||
var len = input.length; | ||
/* Handlebars expression type */ | ||
var handlebarsExpressionType = handlebarsUtil.NOT_EXPRESSION; | ||
/* Extra information of expression */ | ||
var extraExpressionInfo; | ||
/* Handlebars reserved expression */ | ||
var isHandlebarsReservedExpression = false; | ||
/* Handlebars template context */ | ||
var isHandlebarsContext = false; | ||
/* Handlebars {{#if}} {{else}} {{#with}} {{#each}} {{#unless}} expression */ | ||
var isBranchExpressions = false; | ||
/* regular expression validation result */ | ||
var re; | ||
/* context filters */ | ||
var filters = []; | ||
var noOfFilter = 0; | ||
/* Encounter a known filter, we will not add any customized filters if it is known filter */ | ||
var isPrefixWithKnownFilter = false; | ||
debug("_handleTemplate:len:"+len+",i:"+i); | ||
/* | ||
* ---- LOGIC #1 - is handlebars template? ---- | ||
* Determine the type of Handlebars expression | ||
* Note: character comparison is the faster as compared with any type of string operation. | ||
*/ | ||
if (ch === '{' && i+2 < len && input[i+1] === '{' && input[i+2] === '{') { | ||
isHandlebarsContext = true; | ||
/* handling different type of expression */ | ||
if (ch === '{' && i+3 < len && input[i+1] === '{' && input[i+2] === '{' && input[i+3] === '{') { | ||
msg = "[ERROR] ContextParserHandlebars: Not yet support RAW BLOCK! ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} else if (ch === '{' && i+2 < len && input[i+1] === '{' && input[i+2] === '{') { | ||
handlebarsExpressionType = handlebarsUtil.RAW_EXPRESSION; | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsUtil.RAW_EXPRESSION); | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsExpressionType); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid raw expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
} else if (ch === '{' && i+1 < len && input[i+1] === '{') { | ||
isHandlebarsContext = true; | ||
handlebarsExpressionType = handlebarsUtil.ESCAPE_EXPRESSION; | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsUtil.ESCAPE_EXPRESSION); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
} else { | ||
isHandlebarsContext = false; | ||
handlebarsExpressionType = handlebarsUtil.NOT_EXPRESSION; | ||
/* return immediately for non template start char '{' */ | ||
return index; | ||
} | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
/* | ||
* ---- LOGIC #2 - OPEN BRACE ---- | ||
* Determine the type of Handlebars escape expression | ||
*/ | ||
if (handlebarsExpressionType === handlebarsUtil.ESCAPE_EXPRESSION) { | ||
isBranchExpressions = handlebarsUtil.isBranchExpressions(input, i); | ||
if (i+2<len) { | ||
isHandlebarsReservedExpression = handlebarsUtil.isReservedChar(input[i+2]); | ||
} | ||
if (!isBranchExpressions) { | ||
/* Consume 2 '{' chars */ | ||
this.printChar(input[i]); | ||
i=i+1; /** Point to next '{' */ | ||
this.printChar(input[i]); | ||
} | ||
} else if (handlebarsExpressionType === handlebarsUtil.RAW_EXPRESSION) { | ||
/* consume 3 '{' chars */ | ||
this.printChar(input[i]); | ||
i=i+1; /* point to next '{' */ | ||
this.printChar(input[i]); | ||
i=i+1; /* point to last '{' */ | ||
this.printChar(input[i]); | ||
} | ||
debug("_handleTemplate:LOGIC#2:isBranchExpressions:"+isBranchExpressions+",isHandlebarsReservedExpression:"+isHandlebarsReservedExpression+",i:"+i); | ||
/* for printCharWithState */ | ||
this.bytes[index+1] = ch; | ||
this.symbols[index+1] = this.lookupChar(ch); | ||
this.states[index+1] = state; | ||
/* | ||
* ---- LOGIC #3 - ADD FILTERS ---- | ||
*/ | ||
if (handlebarsExpressionType === handlebarsUtil.ESCAPE_EXPRESSION && !isHandlebarsReservedExpression) { | ||
/* | ||
* Check whether there is a known filter being added, | ||
* if yes, then we will not add any customized filters. | ||
*/ | ||
extraExpressionInfo = this._parseExpression(input, i); | ||
isPrefixWithKnownFilter = extraExpressionInfo.isPrefixWithKnownFilter; | ||
if (!isPrefixWithKnownFilter) { | ||
/* We suppress the escapeExpression of handlebars by changing the {{expression}} into {{{expression}}} */ | ||
this.printChar('{'); | ||
/* Get the customized filter based on the current HTML5 state before the Handlebars template expression. */ | ||
var extraInfo = { | ||
'attributeName': this.getAttributeName(), | ||
'attributeValue': this.getAttributeValue(), | ||
}; | ||
filters = this._addFilters(state, input, i, extraInfo); | ||
for(noOfFilter=filters.length-1;noOfFilter>=0;--noOfFilter) { | ||
if (this._enableSubexpression) { | ||
if (extraExpressionInfo.isSingleIdentifier && noOfFilter === 0) { | ||
this.printChar(filters[noOfFilter] + " "); | ||
} else { | ||
this.printChar(filters[noOfFilter] + " ("); | ||
} | ||
} else { | ||
this.printChar(filters[noOfFilter] + " "); | ||
/* _handleRawExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleRawExpression(input, i, len, state); | ||
} else if (ch === '{' && i+1 < len && input[i+1] === '{') { | ||
// this type may not be 100% correct (the case is BRANCH_EXPRESSION), so it need the isValidExpression call below. | ||
handlebarsExpressionType = handlebarsUtil.getExpressionType(input, i, len); | ||
switch (handlebarsExpressionType) { | ||
case handlebarsUtil.ESCAPE_EXPRESSION: | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsExpressionType); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid escape expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
} | ||
} | ||
} | ||
debug("_handleTemplate:LOGIC#3:extraExpressionInfo:"+extraExpressionInfo+",filters:"+filters); | ||
/* | ||
* ---- LOGIC #A - BRANCHING STATEMENT HANDLING ---- | ||
*/ | ||
if (handlebarsExpressionType === handlebarsUtil.ESCAPE_EXPRESSION && isBranchExpressions && isHandlebarsReservedExpression) { | ||
try { | ||
/* Extract the branching statement, and subpress non-branching expression. */ | ||
var objMaskedStmt = handlebarsUtil.extractBranchStmt(input, i, true); | ||
/* for printCharWithState */ | ||
this.bytes[index+1] = ch; | ||
this.symbols[index+1] = this.lookupChar(ch); | ||
this.states[index+1] = state; | ||
/* Parse the branching statement. */ | ||
var ast = handlebarsUtil.parseBranchStmt(objMaskedStmt.stmt); | ||
/* _handleEscapeExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleEscapeExpression(input, i, len, state); | ||
/* Restore the open/close_brace_nonce with {} for analysis */ | ||
objMaskedStmt.stmt = objMaskedStmt.stmt.replace(new RegExp(objMaskedStmt.openBracePlaceHolder, 'g'), '{'); | ||
objMaskedStmt.stmt = objMaskedStmt.stmt.replace(new RegExp(objMaskedStmt.closeBracePlaceHolder, 'g'), '}'); | ||
var result = handlebarsUtil.parseAstTreeState(ast, state, objMaskedStmt); | ||
/* echo to output */ | ||
this.printChar(result.stmt); | ||
/* Advance the index pointer i to the char after the last brace of branching expression. */ | ||
var objUnmaskedStmt = handlebarsUtil.extractBranchStmt(input, i, false); | ||
i=i+objUnmaskedStmt.stmt.length; | ||
this.state = result.lastStates[0]; | ||
debug("_handleTemplate:LOGIC#A:state:"+this.state+",i:"+i); | ||
return i; | ||
} catch (err) { | ||
msg = err + " ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
} | ||
/* | ||
* ---- LOGIC #4 - CLOSE BRACE ---- | ||
* After the customized filter is added, we simply consume the character till we meet the close braces of Handlebars expression | ||
*/ | ||
for(var j=i+1;j<len;++j) { | ||
i=j; | ||
if (handlebarsExpressionType === handlebarsUtil.ESCAPE_EXPRESSION) { | ||
/* Encounter the end of Handlebars expression close brace */ | ||
if (input[j] === '}' && j+1 < len && input[j+1] === '}') { | ||
/* close the filters subexpression */ | ||
if (this._enableSubexpression) { | ||
for(noOfFilter=filters.length-1;noOfFilter>=0;--noOfFilter) { | ||
if (extraExpressionInfo.isSingleIdentifier && noOfFilter === 0) { | ||
} else { | ||
this.printChar(")"); | ||
} | ||
} | ||
case handlebarsUtil.PARTIAL_EXPRESSION: | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsExpressionType); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid partial expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
/* _handleExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleExpression(input, i, len); | ||
/* Print the first '}' */ | ||
this.printChar(input[j]); | ||
j++; | ||
i=j; | ||
/* Print the second '}' */ | ||
this.printChar(input[j]); | ||
/* we suppress the escapeExpression of handlebars by changing the {{expression}} into {{{expression}}} */ | ||
if (!isHandlebarsReservedExpression && !isPrefixWithKnownFilter) { | ||
this.printChar('}'); | ||
case handlebarsUtil.DATA_VAR_EXPRESSION: | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsExpressionType); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid data var expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
/* _handleExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleExpression(input, i, len); | ||
isHandlebarsContext = false; | ||
handlebarsExpressionType = handlebarsUtil.NOT_EXPRESSION; | ||
i=i+1; /* Point to the char right after the last '}' */ | ||
/* update the Context Parser's state if it is not reserved tag */ | ||
if (!isHandlebarsReservedExpression) { | ||
this.state = state; | ||
/* just for debugging */ | ||
this.bytes[index+1] = ch; | ||
this.symbols[index+1] = this.lookupChar(ch); | ||
this.states[index+1] = state; | ||
this.bytes[i] = input[i-1]; | ||
this.symbols[i] = this.lookupChar(input[i-1]); | ||
this.states[i] = state; | ||
case handlebarsUtil.BRANCH_EXPRESSION: | ||
re = handlebarsUtil.isValidExpression(input, i, handlebarsExpressionType); | ||
if (re.result === false) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Invalid branch expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
/* _handleBranchExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleBranchExpression(input, i, state); | ||
case handlebarsUtil.BRANCH_END_EXPRESSION: | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Unexpected {{/.*}} expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
break; | ||
} else { | ||
this.printChar(input[j]); | ||
} | ||
} else if (handlebarsExpressionType === handlebarsUtil.RAW_EXPRESSION) { | ||
/* Encounter the end of Handlebars expression close brace */ | ||
if (input[j] === '}' && j+2 < len && input[j+1] === '}' && input[j+2] === '}') { | ||
/* Print the first '}' */ | ||
this.printChar(input[j]); | ||
j++; | ||
i=j; | ||
/* Print the second '}' */ | ||
this.printChar(input[j]); | ||
j++; | ||
i=j; | ||
/* Print the third '}' */ | ||
this.printChar(input[j]); | ||
isHandlebarsContext = false; | ||
handlebarsExpressionType = handlebarsUtil.NOT_EXPRESSION; | ||
i=i+1; /* Point to the char right after the last '}' */ | ||
/* update the Context Parser's state if it is not reserved tag */ | ||
this.state = state; | ||
case handlebarsUtil.COMMENT_EXPRESSION_LONG_FORM: | ||
// no need to validate the comment expression as the content inside are skipped. | ||
/* _handleCommentExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleCommentExpression(input, i, len, handlebarsExpressionType); | ||
/* just for debugging */ | ||
this.bytes[index+1] = ch; | ||
this.symbols[index+1] = this.lookupChar(ch); | ||
this.states[index+1] = state; | ||
this.bytes[i] = input[i-1]; | ||
this.symbols[i] = this.lookupChar(input[i-1]); | ||
this.states[i] = state; | ||
case handlebarsUtil.COMMENT_EXPRESSION_SHORT_FORM: | ||
// no need to validate the comment expression as the content inside are skipped. | ||
/* _handleCommentExpression */ | ||
debug("_handleTemplate:LOGIC#1:handlebarsExpressionType:"+handlebarsExpressionType,",i:"+i); | ||
return this._handleCommentExpression(input, i, len, handlebarsExpressionType); | ||
case handlebarsUtil.ELSE_EXPRESSION: | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Unexpected {{else}} or {{^}} expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
break; | ||
} else { | ||
this.printChar(input[j]); | ||
} | ||
default: | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Unknown expression. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
break; | ||
} | ||
} else { | ||
/* return immediately for non template start char '{' */ | ||
return index; | ||
} | ||
debug("_handleTemplate:LOGIC#4:i:"+i); | ||
/* | ||
* ---- LOGIC #5 - BROKEN TEMPLATE ---- | ||
* If we meet the EOF of the input string, while the Context Parser is still in the Handlebars context, | ||
* it indicates that the input Handlebars template file is an incomplete file. | ||
*/ | ||
if (isHandlebarsContext) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' or '}}}' close brace. ["+this._lineNo+":"+this._charNo+"]"; | ||
handlebarsUtil.handleError(msg, true); | ||
} | ||
return i; | ||
}; | ||
@@ -719,0 +707,0 @@ |
@@ -25,42 +25,89 @@ /* | ||
/* type of expression */ | ||
HandlebarsUtils.NOT_EXPRESSION = 0; | ||
HandlebarsUtils.RAW_EXPRESSION = 1; // {{{expression}}} | ||
HandlebarsUtils.ESCAPE_EXPRESSION = 2; // {{expression}} | ||
HandlebarsUtils.PARTIAL_EXPRESSION = 3; // {{>.*}} | ||
HandlebarsUtils.DATA_VAR_EXPRESSION = 4; // {{@.*}} | ||
HandlebarsUtils.BRANCH_EXPRESSION = 5; // {{#.*}}, {{^.*}} | ||
HandlebarsUtils.BRANCH_END_EXPRESSION = 6; // {{/.*}} | ||
HandlebarsUtils.ELSE_EXPRESSION = 7; // {{else}}, {{^}} | ||
HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM = 8; // {{!--.*--}} | ||
HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM = 9; // {{!.*}} | ||
HandlebarsUtils.RAW_BLOCK = 10; // {{{{block}}}} | ||
/* reference: http://handlebarsjs.com/expressions.html */ | ||
/* '{{{{' '~'? 'not {}~'+ '~'? non-greedy '}}}}' and not follow by '}' */ | ||
HandlebarsUtils.rawBlockRegExp = /^\{\{\{\{~?([^\}\{~]+)~??\}\}\}\}(?!})/; | ||
/* '{{{' '~'? 'not {}~'+ '~'? non-greedy '}}}' and not follow by '}' */ | ||
HandlebarsUtils.rawExpressionRegExp = /^\{\{\{~?([^\}\{~]+)~??\}\}\}(?!})/; | ||
/* '{{' '~'? 'space'* ('not {}~'+) '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.escapeExpressionRegExp = /^\{\{~?\s*([^\}\{~]+)~??\}\}(?!})/; | ||
/* '{{' '~'? '>' 'space'* ('not {}~'+) 'space'* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.partialExpressionRegExp = /^\{\{~?>\s*([^\}\{~]+)\s*~??\}\}(?!})/; | ||
/* '{{' '~'? '@' 'space'* ('not {}~'+) 'space'* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.dataVarExpressionRegExp = /^\{\{~?@\s*([^\}\{~]+)\s*~??\}\}(?!})/; | ||
// need to capture the first non-whitespace string and capture the rest | ||
/* '{{' '~'? '# or ^' 'space'* ('not \s{}~'+) 'space'* ('not {}~')* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.branchExpressionRegExp = /^\{\{~?[#|\^]\s*([^\s\}\{~]+)\s*([^\}\{~]*)~??\}\}(?!})/; | ||
/* '{{' '~'? '/' 'space'* ('not \s{}~'+) 'space'* ('not {}~')* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.branchEndExpressionRegExp = /^\{\{~?\/\s*([^\s\}\{~]+)\s*([^\}\{~]*)~??\}\}(?!})/; | ||
/* '{{' '~'? 'space'* 'else' 'space'* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.elseExpressionRegExp = /^\{\{~?\s*else\s*~??\}\}(?!})/; | ||
/* '{{' '~'? 'space'* '^'{1} 'space'* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.elseShortFormExpressionRegExp = /^\{\{~?\s*\^{1}\s*~??\}\}(?!})/; | ||
/** | ||
* @function HandlebarsUtils.generateNonce | ||
* @function HandlebarsUtils.getExpressionType | ||
* | ||
* @static | ||
* | ||
* @returns {string} A random string in the length of 5 (10000 combinations). | ||
* | ||
* @param {string} input - The input string of the HTML5 web page. | ||
* @param {integer} i - The current index of the input string. | ||
* @param {integer} len - The max len of the input. | ||
* @returns {integer} The expression type. | ||
* * | ||
* @description | ||
* <p>This function generates a random string for masking double open/close brace to simplify AST construction.</p> | ||
* <p>this method is to judge the type of expression</p> | ||
* | ||
*/ | ||
HandlebarsUtils.generateNonce = function() { | ||
var nonce = ""; | ||
/* this char set must be non-template reserved char set */ | ||
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | ||
var l = str.length; | ||
for(var i=0;i<5;i++) { | ||
nonce += str.charAt(Math.floor(Math.random()*l)); | ||
HandlebarsUtils.getExpressionType = function(input, i, len) { | ||
// TODO: can optimize | ||
if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '>') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '>') | ||
) { | ||
return HandlebarsUtils.PARTIAL_EXPRESSION; | ||
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '@') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '@') | ||
) { | ||
return HandlebarsUtils.DATA_VAR_EXPRESSION; | ||
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '#') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '#') | ||
) { | ||
return HandlebarsUtils.BRANCH_EXPRESSION; | ||
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '^') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '^') | ||
) { | ||
// this one is not exact, {{~?^}} will pass! | ||
return HandlebarsUtils.BRANCH_EXPRESSION; | ||
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '/') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '/') | ||
) { | ||
return HandlebarsUtils.BRANCH_END_EXPRESSION; | ||
} else if ((input[i] === '{' && i+4<len && input[i+1] === '{' && input[i+2] === '!' && input[i+3] === '-' && input[i+4] === '-') || | ||
(input[i] === '{' && i+4<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '!' && input[i+4] === '-' && input[i+5] === '-') | ||
) { | ||
return HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM; | ||
} else if ((input[i] === '{' && i+2<len && input[i+1] === '{' && input[i+2] === '!') || | ||
(input[i] === '{' && i+3<len && input[i+1] === '{' && input[i+2] === '~' && input[i+3] === '!') | ||
) { | ||
return HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM; | ||
} | ||
return nonce; | ||
return HandlebarsUtils.ESCAPE_EXPRESSION; | ||
}; | ||
/* type of expression */ | ||
HandlebarsUtils.NOT_EXPRESSION = 0; | ||
HandlebarsUtils.ESCAPE_EXPRESSION = 1; | ||
HandlebarsUtils.RAW_EXPRESSION = 2; | ||
/* RegExp to match expression */ | ||
/* '{{' 'non-{,non-}'+ '}}' and not follow by '}' */ | ||
HandlebarsUtils.escapeExpressionRegExp = /^\{\{[^\}\{]+?\}\}(?!})/; | ||
/* '{{{' 'non-{,non-}'+ '}}}' and not follow by '}' */ | ||
HandlebarsUtils.rawExpressionRegExp = /^\{\{\{[^\}\{]+?\}\}\}(?!})/; | ||
/* '{{' '# or ^' 'space'* 'non-space,non-},non-{'+ first-'space or }' */ | ||
HandlebarsUtils.branchExpressionRegExp = /^\{\{[#|\\^]\s*([^\s\}\{]+)?[\s\}]/; | ||
/* '{{' '/' 'space'* 'non-space,non-},non-{'+ first-'space or }' */ | ||
HandlebarsUtils.branchEndExpressionRegExp = /^\{\{\/\s*([^\s\}\{]+)?[\s\}]/; | ||
/* '{{' 'space'* 'else' 'space'* '}}' */ | ||
HandlebarsUtils.elseExpressionRegExp = /^\{\{\s*else\s*?\}\}/; | ||
/** | ||
@@ -78,9 +125,37 @@ * @function HandlebarsUtils.isValidExpression | ||
re.result = false; | ||
var s = input.slice(i); | ||
switch(type) { | ||
case HandlebarsUtils.ESCAPE_EXPRESSION: | ||
re = HandlebarsUtils.escapeExpressionRegExp.exec(input.slice(i)); | ||
case HandlebarsUtils.RAW_BLOCK: | ||
re = HandlebarsUtils.rawBlock.exec(s); | ||
break; | ||
case HandlebarsUtils.RAW_EXPRESSION: | ||
re = HandlebarsUtils.rawExpressionRegExp.exec(input.slice(i)); | ||
re = HandlebarsUtils.rawExpressionRegExp.exec(s); | ||
break; | ||
case HandlebarsUtils.ESCAPE_EXPRESSION: | ||
re = HandlebarsUtils.escapeExpressionRegExp.exec(s); | ||
if (re !== null && re[1] !== undefined) { | ||
if (HandlebarsUtils.isReservedChar(re[1], 0)) { | ||
re.result = false; | ||
return re; | ||
} | ||
} | ||
break; | ||
case HandlebarsUtils.PARTIAL_EXPRESSION: | ||
re = HandlebarsUtils.partialExpressionRegExp.exec(s); | ||
break; | ||
case HandlebarsUtils.DATA_VAR_EXPRESSION: | ||
re = HandlebarsUtils.dataVarExpressionRegExp.exec(s); | ||
break; | ||
case HandlebarsUtils.BRANCH_EXPRESSION: | ||
re = HandlebarsUtils.branchExpressionRegExp.exec(s); | ||
break; | ||
case HandlebarsUtils.BRANCH_END_EXPRESSION: | ||
re = HandlebarsUtils.branchEndExpressionRegExp.exec(s); | ||
break; | ||
case HandlebarsUtils.ELSE_EXPRESSION: | ||
re = HandlebarsUtils.elseExpressionRegExp.exec(s); | ||
if (re === null) { | ||
re = HandlebarsUtils.elseShortFormExpressionRegExp.exec(s); | ||
} | ||
break; | ||
default: | ||
@@ -114,3 +189,8 @@ return re; | ||
*/ | ||
HandlebarsUtils.isReservedChar = function(ch) { | ||
HandlebarsUtils.isReservedChar = function(input, i) { | ||
var ch = input[i]; | ||
if (ch === '~' && input.length > i+1) { | ||
ch = input[i+1]; | ||
} | ||
if (ch === '#' || ch === '/' || ch === '>' || ch === '@' || ch === '^' || ch === '!') { | ||
@@ -177,8 +257,12 @@ return true; | ||
HandlebarsUtils.isElseExpression = function(input, i) { | ||
var re = HandlebarsUtils.elseExpressionRegExp.exec(input.slice(i)); | ||
if (re === null) { | ||
return false; | ||
} else { | ||
var s = input.slice(i); | ||
var re = HandlebarsUtils.elseExpressionRegExp.exec(s); | ||
if (re !== null) { | ||
return true; | ||
} | ||
re = HandlebarsUtils.elseShortFormExpressionRegExp.exec(s); | ||
if (re !== null) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
@@ -230,192 +314,124 @@ | ||
/** | ||
* @function HandlebarsUtils.parseBranchStmt | ||
* | ||
* @static | ||
/* | ||
* @function HandlebarsUtils._analyzeContext | ||
*/ | ||
HandlebarsUtils._analyzeContext = function(state, str) { | ||
var r = { | ||
lastState: '', | ||
output: '' | ||
}; | ||
// TODO: refactor | ||
/* factory class */ | ||
var parser, | ||
ContextParserHandlebars = require('./context-parser-handlebars'); | ||
/* parse the string */ | ||
debugBranch("_analyzeContext:"+str); | ||
parser = new ContextParserHandlebars(false); | ||
parser.setInitState(state); | ||
parser.contextualize(str); | ||
r.lastState = parser.getLastState(); | ||
r.output = parser.getBuffer().join(''); | ||
debugBranch("_analyzeContext:"+r.output); | ||
return r; | ||
}; | ||
/* | ||
* @function HandlebarsUtils.blacklistProtocol | ||
* | ||
* @param {string} s - The string in the format of balanced branching statement like {{#if}}, {{#each}}, {{#list}}, {{#unless}}, {{#with}}, {{#anything}} and {{^anything}}. | ||
* @returns {array} An array of statement in the AST tree. | ||
* | ||
* @description | ||
* <p>This function uses the native Handlebars parser to parse branching statement to generate a AST.</p> | ||
* | ||
* Reference: | ||
* https://github.com/yahoo/xss-filters/blob/master/src/private-xss-filters.js#L266 | ||
*/ | ||
HandlebarsUtils.parseBranchStmt = function(s) { | ||
if (!Handlebars.VERSION.match(/^2\./)) { | ||
var msg = "[ERROR] ContextParserHandlebars: We support Handlebars 2.0 ONLY!"; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
// TODO: we should build our own data structure instead of using Handlebars directly. | ||
var ast = Handlebars.parse(s); | ||
if (ast.statements !== undefined) { | ||
return ast.statements; | ||
HandlebarsUtils._URI_BLACKLIST = null; | ||
HandlebarsUtils._URI_BLACKLIST_REGEXPSTR = "^(?:&#[xX]0*(?:1?[1-9a-fA-F]|10|20);?|�*(?:[1-9]|[1-2][0-9]|30|31|32);?|	|
)*(?:(?:j|J|&#[xX]0*(?:6|4)[aA];?|�*(?:106|74);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:a|A|&#[xX]0*(?:6|4)1;?|�*(?:97|65);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:v|V|&#[xX]0*(?:7|5)6;?|�*(?:118|86);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:a|A|&#[xX]0*(?:6|4)1;?|�*(?:97|65);?)|(?:v|V|&#[xX]0*(?:7|5)6;?|�*(?:118|86);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:b|B|&#[xX]0*(?:6|4)2;?|�*(?:98|66);?))(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:s|S|&#[xX]0*(?:7|5)3;?|�*(?:115|83);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:c|C|&#[xX]0*(?:6|4)3;?|�*(?:99|67);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:r|R|&#[xX]0*(?:7|5)2;?|�*(?:114|82);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:i|I|&#[xX]0*(?:6|4)9;?|�*(?:105|73);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:p|P|&#[xX]0*(?:7|5)0;?|�*(?:112|80);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:t|T|&#[xX]0*(?:7|5)4;?|�*(?:116|84);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?::|&#[xX]0*3[aA];?|�*58;?)"; | ||
HandlebarsUtils.blacklistProtocol = function(s) { | ||
var URI_FASTLANE = ['&', 'j', 'J', 'v', 'V']; | ||
if (URI_FASTLANE.indexOf(s[0]) === -1) { | ||
return false; | ||
} else { | ||
return []; | ||
if (HandlebarsUtils._URI_BLACKLIST === null) { | ||
HandlebarsUtils._URI_BLACKLIST = new RegExp(HandlebarsUtils._URI_BLACKLIST_REGEXPSTR); | ||
} | ||
if (HandlebarsUtils._URI_BLACKLIST.test(s)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
/** | ||
* @function HandlebarsUtils.extractBranchStmt | ||
* | ||
* @static | ||
* | ||
* @param {string} input - The template input string. | ||
* @param {int} k - The pointer to the first char of the first brace expression of Handlebars template. | ||
* @param {boolean} masked - The flag to mask the non branching statement expression. | ||
* @returns {Object} The object with branching statement and place holder. | ||
* | ||
* @description | ||
* <p>This function extracts a branching statement with balanced expression.</p> | ||
* | ||
* @function HandlebarsUtils.analyseBranchAst | ||
*/ | ||
HandlebarsUtils.extractBranchStmt = function(input, k, masked) { | ||
HandlebarsUtils.analyseBranchAst = function(ast, state) { | ||
var obj = {}, | ||
len = ast.program.length; | ||
var stmt = '', | ||
msg = '', | ||
sp = [], | ||
r = {}, | ||
j = 0; | ||
var r = {}, | ||
s = [], | ||
t, msg, | ||
newLastState; | ||
r.lastStates = []; | ||
r.lastStates[0] = state; | ||
r.lastStates[1] = state; | ||
r.output = ''; | ||
/* init */ | ||
var str = input.slice(k); | ||
var l = str.length; | ||
/* | ||
* the reason for extracting the branching statement is to | ||
* be used for building the AST for finding all the combination of strings, | ||
* however the non-branching expression will make the AST more | ||
* complicated, so this function masks out all open/close brace | ||
* with a random nonce. | ||
*/ | ||
r.filterPlaceHolder = []; | ||
r.openBracePlaceHolder = HandlebarsUtils.generateNonce(); | ||
r.closeBracePlaceHolder = HandlebarsUtils.generateNonce(); | ||
for(var i=0;i<l;++i) { | ||
var tag = HandlebarsUtils.isBranchExpression(str, i), | ||
endExpression = HandlebarsUtils.isBranchEndExpression(str, i); | ||
/* push the branching tokens */ | ||
if (tag !== false) { | ||
sp.push(tag); | ||
/* do nothing for 'else' token */ | ||
} else if (HandlebarsUtils.isElseExpression(str, i)) { | ||
/* pop the branching tokens (TODO: not fast enough) */ | ||
} else if (endExpression !== false) { | ||
if (sp.length > 0) { | ||
var lastExpression = sp[sp.length-1]; | ||
/* check for balanced branching statement */ | ||
if (lastExpression === endExpression) { | ||
sp.pop(); | ||
/* consume till the end of '}}' */ | ||
for(j=i;j<l;++j) { | ||
if (str[j] === '}' && j+1<l && str[j+1] === '}') { | ||
stmt += str[j]; | ||
i=j+1; | ||
break; | ||
} else { | ||
stmt += str[j]; | ||
} | ||
} | ||
} else { | ||
/* broken template as the end expression does not match, throw exception before function returns */ | ||
msg = "[ERROR] ContextParserHandlebars: Template expression mismatch (startExpression:"+lastExpression+"/endExpression:"+endExpression+")"; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
} else { | ||
/* broken template, throw exception before function returns */ | ||
msg = "[ERROR] ContextParserHandlebars: Cannot find the corresponding start expression (tag:"+endExpression+")"; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
/* non-branching expression */ | ||
} else { | ||
/* {{{expression}}} case */ | ||
if (str[i] === '{' && i+2<l && str[i+1] === '{' && str[i+2] === '{' && masked) { | ||
/* masked the '{{{' */ | ||
stmt += r.openBracePlaceHolder; | ||
stmt += r.openBracePlaceHolder; | ||
stmt += r.openBracePlaceHolder; | ||
/* loop till the end of '}}}' */ | ||
for(j=i+3;j<l;++j) { | ||
if (str[j] === '}' && i+3<l && str[j+1] === '}' && str[j+2] === '}') { | ||
/* append 3 chars, }}} */ | ||
stmt += r.closeBracePlaceHolder; | ||
stmt += r.closeBracePlaceHolder; | ||
stmt += r.closeBracePlaceHolder; | ||
/* advance the pointer by 2, the for loop will increase by one more for next char */ | ||
i=j+2; | ||
break; | ||
} | ||
stmt += str[j]; | ||
} | ||
continue; | ||
/* {{[!@/>]expression}} */ | ||
} else if (str[i] === '{' && i+2<l && str[i+1] === '{' && masked && HandlebarsUtils.isReservedChar(str[i+2])) { | ||
/* masked the '{{' */ | ||
stmt += r.openBracePlaceHolder; | ||
stmt += r.openBracePlaceHolder; | ||
/* loop till the end of '}}' */ | ||
for(j=i+2;j<l;++j) { | ||
if (str[j] === '}' && i+2<l && str[j+1] === '}') { | ||
/* append 2 chars, }} */ | ||
stmt += r.closeBracePlaceHolder; | ||
stmt += r.closeBracePlaceHolder; | ||
/* advance the pointer by 1, the for loop will increase by one more for next char */ | ||
i=j+1; | ||
break; | ||
} | ||
stmt += str[j]; | ||
} | ||
continue; | ||
/* {{expression}} */ | ||
} else if (str[i] === '{' && i+2<l && str[i+1] === '{' && masked && !HandlebarsUtils.isReservedChar(str[i+2])) { | ||
/* masked the '{{' */ | ||
stmt += r.openBracePlaceHolder; | ||
stmt += r.openBracePlaceHolder; | ||
/* add the filter place holder */ | ||
var filterPlaceHolder = HandlebarsUtils.generateNonce(); | ||
stmt += filterPlaceHolder; | ||
r.filterPlaceHolder.push(filterPlaceHolder); | ||
/* loop till the end of '}}' */ | ||
for(j=i+2;j<l;++j) { | ||
if (str[j] === '}' && i+2<l && str[j+1] === '}') { | ||
/* append 2 chars, }} */ | ||
stmt += r.closeBracePlaceHolder; | ||
stmt += r.closeBracePlaceHolder; | ||
/* advance the pointer by 1, the for loop will increase by one more for next char */ | ||
i=j+1; | ||
break; | ||
} | ||
stmt += str[j]; | ||
} | ||
continue; | ||
} | ||
for(var i=0;i<len;++i) { | ||
obj = ast.program[i]; | ||
if (obj.type === 'content') { | ||
t = HandlebarsUtils._analyzeContext(r.lastStates[0], obj.content); | ||
newLastState = t.lastState; | ||
r.output += t.output; | ||
debugBranch("analyseBranchAst:program:content,["+r.lastStates[0]+"/"+newLastState+"],["+obj.content+"],["+r.output+"]"); | ||
r.lastStates[0] = newLastState; | ||
} else if (obj.type === 'node') { | ||
t = HandlebarsUtils.analyseBranchAst(obj.content, r.lastStates[0]); | ||
newLastState = t.lastStates[0]; // index 0 and 1 MUST be equal | ||
debugBranch("analyseBranchAst:program:node,["+r.lastStates[0]+"/"+newLastState+"]"); | ||
r.lastStates[0] = newLastState; | ||
r.output += t.output; | ||
} else if (obj.type === 'branch' || | ||
obj.type === 'branchelse' || | ||
obj.type === 'branchend') { | ||
r.output += obj.content; | ||
} | ||
stmt += str[i]; | ||
/* The stack is empty, we can return */ | ||
if (sp.length === 0) { | ||
break; | ||
} | ||
len = ast.inverse.length; | ||
for(i=0;i<len;++i) { | ||
obj = ast.inverse[i]; | ||
if (obj.type === 'content') { | ||
t = HandlebarsUtils._analyzeContext(r.lastStates[1], obj.content); | ||
newLastState = t.lastState; | ||
r.output += t.output; | ||
debugBranch("analyseBranchAst:inverse:content,["+r.lastStates[1]+"/"+newLastState+"],["+obj.content+"],["+r.output+"]"); | ||
r.lastStates[1] = newLastState; | ||
} else if (obj.type === 'node') { | ||
t = HandlebarsUtils.analyseBranchAst(obj.content, r.lastStates[1]); | ||
newLastState = t.lastStates[1]; // index 0 and 1 MUST be equal | ||
debugBranch("analyseBranchAst:inverse:node,["+r.lastStates[1]+"/"+newLastState+"]"); | ||
r.lastStates[1] = newLastState; | ||
r.output += t.output; | ||
} else if (obj.type === 'branch' || | ||
obj.type === 'branchelse' || | ||
obj.type === 'branchend') { | ||
r.output += obj.content; | ||
} | ||
} | ||
/* if all chars are consumed while the sp is not empty, the template is broken */ | ||
if (sp.length > 0) { | ||
/* throw error on the template */ | ||
msg = "[ERROR] ContextParserHandlebars: Template does not have balanced branching expression."; | ||
if (ast.program.length > 0 && ast.inverse.length === 0) { | ||
debugBranch("panalyseBranchAst:["+r.lastStates[0]+"/"+r.lastStates[0]+"]"); | ||
r.lastStates[1] = r.lastStates[0]; | ||
} else if (ast.program.length === 0 && ast.inverse.length > 0) { | ||
debugBranch("analyseBranchAst:["+r.lastStates[1]+"/"+r.lastStates[1]+"]"); | ||
r.lastStates[0] = r.lastStates[1]; | ||
} | ||
if (r.lastStates[0] !== r.lastStates[1]) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Inconsitent HTML5 state after conditional branches. Please fix your template!"; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
r.stmt = stmt; | ||
debugBranch("extractBranchStmt:"+stmt); | ||
return r; | ||
@@ -425,290 +441,195 @@ }; | ||
/** | ||
* @function HandlebarsUtils.parseAstTreeState | ||
* | ||
* @static | ||
* | ||
* @description | ||
* <p>This function transverses the AST tree of the brnaching statement of Handlebars, | ||
* and parse and relace filter in the string on the fly.</p> | ||
* | ||
* @param {array} o - The AST of the branching statement. | ||
* @param {int} state - The init state of the string. | ||
* @param {object} obj - The object contains the open/close brace place holder, filter place holder and branching statement. | ||
* @returns {array} The last states of the 1st and 2nd branches. | ||
* | ||
* @function HandlebarsUtils.buildBranchAst | ||
*/ | ||
HandlebarsUtils.parseAstTreeState = function(o, state, obj) { | ||
HandlebarsUtils.buildBranchAst = function(input, i) { | ||
/* | ||
* the expected data structure of branching statement from the AST tree | ||
* | ||
* ________________ branching _____________ | ||
* | | | ||
* 1st branch (if etc.) 2nd branch (else) | ||
* ----------------------------------- ---------------------------------- | ||
* | context | sub-branch | context | | context | sub-branch | context | | ||
* 1st node 2nd node 3rd node 1st node 2nd node 3rd node | ||
* | ||
*/ | ||
/* init the data structure */ | ||
var ast = {}; | ||
ast.program = []; | ||
ast.inverse = []; | ||
/* being used for which node is being handled next */ | ||
var nodeFlag = []; | ||
/* true for first node, false for third node (1st branch) */ | ||
nodeFlag[0] = true; | ||
/* true for first node, false for third node (2nd branch) */ | ||
nodeFlag[1] = true; | ||
var str = input.slice(i), | ||
len = str.length; | ||
/* indicating which branches have been handled before */ | ||
var branchesFlag = []; | ||
/* true for 1st branch */ | ||
branchesFlag[0] = false; | ||
/* true for 2nd branch */ | ||
branchesFlag[1] = false; | ||
var sp = [], | ||
msg, | ||
content = '', | ||
inverse = false, | ||
obj = {}, | ||
k,j,r = 0; | ||
/* last state */ | ||
var newLastState; | ||
for(j=0;j<len;++j) { | ||
var exp = HandlebarsUtils.isBranchExpression(str, j), | ||
endExpression = HandlebarsUtils.isBranchEndExpression(str, j); | ||
if (exp !== false) { | ||
/* encounter the first branch expression */ | ||
if (sp.length === 0) { | ||
/* save the branch expression name */ | ||
sp.push(exp); | ||
/* return object */ | ||
var r = {}; | ||
r.lastStates = []; | ||
r.lastStates[0] = -1; | ||
r.lastStates[1] = -1; | ||
r.stmt = obj.stmt; | ||
content = ''; | ||
inverse = false; | ||
/* transitent variables */ | ||
var t, | ||
j = 0, | ||
s = [], | ||
str = '', | ||
msg = '', | ||
output = ''; | ||
/* consume till the end of expression */ | ||
r = HandlebarsUtils._consumeTillCloseBrace(str, j, len); | ||
j = r.index; | ||
obj = HandlebarsUtils._saveAstObject('branch', r.str); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
for(var i=0;i<o.length;++i) { | ||
} else { | ||
/* encounter another branch expression, save the previous string */ | ||
obj = HandlebarsUtils._saveAstObject('content', content); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
content = ''; | ||
/* if/with/each/list/tag/unless token */ | ||
if (typeof o[i].program !== 'undefined') { | ||
branchesFlag[0] = true; | ||
for(j=0;j<o[i].program.statements.length;++j) { | ||
/* 1st node */ | ||
if (o[i].program.statements[j].type === 'content' && nodeFlag[0]) { | ||
nodeFlag[0] = false; | ||
str = o[i].program.statements[j].string; | ||
/* restore the open/close brace place holder */ | ||
str = str.replace(new RegExp(obj.openBracePlaceHolder, 'g'), '{'); | ||
str = str.replace(new RegExp(obj.closeBracePlaceHolder, 'g'), '}'); | ||
/* parse the string */ | ||
t = HandlebarsUtils._analyzeContext(state, str); | ||
newLastState = t.lastState; | ||
output = t.output; | ||
debugBranch("parseAstTreeState:if:1,["+state+"/"+newLastState+"],["+str+"],["+output+"]"); | ||
r.lastStates[0] = newLastState; | ||
/* replace the filter place holder */ | ||
obj = HandlebarsUtils._replaceFilterPlaceHolder(obj, output); | ||
/* 2nd node */ | ||
} else if (o[i].program.statements[j].type === 'block') { | ||
s = []; | ||
s[0] = o[i].program.statements[j]; | ||
t = HandlebarsUtils.parseAstTreeState(s, r.lastStates[0], obj); | ||
newLastState = t.lastStates[0]; // index 0 and 1 MUST be equal | ||
obj.stmt = t.stmt; | ||
debugBranch("parseAstTreeState:if:2,["+r.lastStates[0]+"/"+newLastState+"]"); | ||
r.lastStates[0] = newLastState; | ||
/* 3rd node */ | ||
} else if (o[i].program.statements[j].type === 'content' && !nodeFlag[0]) { | ||
str = o[i].program.statements[j].string; | ||
/* restore the open/close brace place holder */ | ||
str = str.replace(new RegExp(obj.openBracePlaceHolder, 'g'), '{'); | ||
str = str.replace(new RegExp(obj.closeBracePlaceHolder, 'g'), '}'); | ||
/* parse the string */ | ||
t = HandlebarsUtils._analyzeContext(r.lastStates[0], str); | ||
newLastState = t.lastState; | ||
output = t.output; | ||
debugBranch("parseAstTreeState:if:3,["+r.lastStates[0]+"/"+newLastState+"],["+str+"],["+output+"]"); | ||
r.lastStates[0] = newLastState; | ||
/* replace the filter place holder */ | ||
obj = HandlebarsUtils._replaceFilterPlaceHolder(obj, output); | ||
r = HandlebarsUtils.buildBranchAst(str, j); | ||
obj = HandlebarsUtils._saveAstObject('node', r); | ||
j = j + r.index; | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
} | ||
} | ||
} else if (HandlebarsUtils.isElseExpression(str, j)) { | ||
obj = HandlebarsUtils._saveAstObject('content', content); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
/* else token */ | ||
if (typeof o[i].inverse !== 'undefined') { | ||
branchesFlag[1] = true; | ||
inverse = true; | ||
content = ''; | ||
for(j=0;j<o[i].inverse.statements.length;++j) { | ||
/* consume till the end of expression */ | ||
r = HandlebarsUtils._consumeTillCloseBrace(str, j, len); | ||
j = r.index; | ||
obj = HandlebarsUtils._saveAstObject('branchelse', r.str); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
/* 1st node */ | ||
if (o[i].inverse.statements[j].type === 'content' && nodeFlag[1]) { | ||
nodeFlag[1] = false; | ||
str = o[i].inverse.statements[j].string; | ||
} else if (endExpression !== false) { | ||
var t = sp.pop(); | ||
if (t === endExpression) { | ||
obj = HandlebarsUtils._saveAstObject('content', content); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
/* restore the open/close brace place holder */ | ||
str = str.replace(new RegExp(obj.openBracePlaceHolder, 'g'), '{'); | ||
str = str.replace(new RegExp(obj.closeBracePlaceHolder, 'g'), '}'); | ||
/* consume till the end of expression */ | ||
r = HandlebarsUtils._consumeTillCloseBrace(str, j, len); | ||
j = r.index; | ||
obj = HandlebarsUtils._saveAstObject('branchend', r.str); | ||
if (!inverse) { | ||
ast.program.push(obj); | ||
} else if (inverse) { | ||
ast.inverse.push(obj); | ||
} | ||
/* parse the string */ | ||
t = HandlebarsUtils._analyzeContext(state, str); | ||
newLastState = t.lastState; | ||
output = t.output; | ||
debugBranch("parseAstTreeState:else:1,["+state+"/"+newLastState+"],["+str+"],["+output+"]"); | ||
r.lastStates[1] = newLastState; | ||
/* replace the filter place holder */ | ||
obj = HandlebarsUtils._replaceFilterPlaceHolder(obj, output); | ||
/* 2nd node */ | ||
} else if (o[i].inverse.statements[j].type === 'block') { | ||
s = []; | ||
s[0] = o[i].inverse.statements[j]; | ||
t = HandlebarsUtils.parseAstTreeState(s, r.lastStates[1], obj); | ||
newLastState = t.lastStates[0]; // index 0 and 1 MUST be equal | ||
obj.stmt = t.stmt; | ||
debugBranch("parseAstTreeState:else:2,["+r.lastStates[1]+"/"+newLastState+"]"); | ||
r.lastStates[1] = newLastState; | ||
/* 3rd node */ | ||
} else if (o[i].inverse.statements[j].type === 'content' && !nodeFlag[1]) { | ||
str = o[i].inverse.statements[j].string; | ||
/* restore the open/close brace place holder */ | ||
str = str.replace(new RegExp(obj.openBracePlaceHolder, 'g'), '{'); | ||
str = str.replace(new RegExp(obj.closeBracePlaceHolder, 'g'), '}'); | ||
/* parse the string */ | ||
t = HandlebarsUtils._analyzeContext(r.lastStates[1], str); | ||
newLastState = t.lastState; | ||
output = t.output; | ||
debugBranch("parseAstTreeState:else:3,["+r.lastStates[1]+"/"+newLastState+"],["+str+"],["+output+"]"); | ||
r.lastStates[1] = newLastState; | ||
/* replace the filter place holder */ | ||
obj = HandlebarsUtils._replaceFilterPlaceHolder(obj, output); | ||
} | ||
break; | ||
} else { | ||
/* broken template as the end expression does not match, throw exception before function returns */ | ||
msg = "[ERROR] ContextParserHandlebars: Template expression mismatch (startExpression:"+t+"/endExpression:"+endExpression+")"; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
} else { | ||
var expressionType = HandlebarsUtils.getExpressionType(str, j, len); | ||
if (expressionType === HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM || | ||
expressionType === HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM) { | ||
/* capturing the string till the end of comment */ | ||
r = HandlebarsUtils._consumeTillCommentCloseBrace(str, j, len, expressionType); | ||
j = r.index; | ||
content += r.str; | ||
} else { | ||
/* capturing the string */ | ||
content += str[j]; | ||
} | ||
} | ||
} | ||
if (branchesFlag[0] && !branchesFlag[1]) { | ||
debugBranch("parseAstTreeState:else:0,["+state+"/"+state+"]"); | ||
r.lastStates[1] = state; | ||
} else if (!branchesFlag[0] && branchesFlag[1]) { | ||
debugBranch("parseAstTreeState:if:0,["+state+"/"+state+"]"); | ||
r.lastStates[0] = state; | ||
} | ||
if (r.lastStates[0] !== r.lastStates[1]) { | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Inconsitent HTML5 state after conditional branches. Please fix your template!"; | ||
if (sp.length > 0) { | ||
/* throw error on the template */ | ||
msg = "[ERROR] ContextParserHandlebars: Template does not have balanced branching expression."; | ||
HandlebarsUtils.handleError(msg, true); | ||
} | ||
r.stmt = obj.stmt; | ||
return r; | ||
ast.index = j; | ||
return ast; | ||
}; | ||
/* | ||
* @function HandlebarsUtils._analyzeContext | ||
* | ||
* @static | ||
* @private | ||
* | ||
/** | ||
* @function HandlebarsUtils._saveAstObject | ||
*/ | ||
HandlebarsUtils._analyzeContext = function(state, str) { | ||
var r = { | ||
lastState: '', | ||
output: '' | ||
}; | ||
// TODO: refactor | ||
/* factory class */ | ||
var parser, | ||
ContextParserHandlebars = require('./context-parser-handlebars'); | ||
/* parse the string */ | ||
debugBranch("_analyzeContext:"+str); | ||
parser = new ContextParserHandlebars(false); | ||
parser.setInitState(state); | ||
parser.contextualize(str); | ||
r.lastState = parser.getLastState(); | ||
r.output = parser.getBuffer().join(''); | ||
debugBranch("_analyzeContext:"+r.output); | ||
return r; | ||
HandlebarsUtils._saveAstObject = function(type, content) { | ||
var obj = {}; | ||
obj.type = type; | ||
obj.content = content; | ||
return obj; | ||
}; | ||
/* | ||
* @function HandlebarsUtils._replaceFilterPlaceHolder | ||
* | ||
* @static | ||
* @private | ||
* | ||
/** | ||
* @function HandlebarsUtils._consumeTillCloseBrace | ||
*/ | ||
HandlebarsUtils._replaceFilterPlaceHolder = function(obj, str) { | ||
var filterPlaceHolders = obj.filterPlaceHolder.slice(0); | ||
filterPlaceHolders.forEach(function(filterPlaceHolder) { | ||
/* get the output expression from masked stmt */ | ||
var outputMarkup = new RegExp('\{\{' + filterPlaceHolder + '.*?\}\}', 'g'); | ||
var m1 = outputMarkup.exec(obj.stmt); | ||
/* get the output filter expression from processed stmt */ | ||
var i = str.indexOf(filterPlaceHolder); | ||
if (i !== -1 && m1 !== null && m1[0]) { | ||
var s = str.substr(0,i).lastIndexOf('{'); | ||
var e = str.substr(i).indexOf('}') + i + 1; | ||
var m2 = str.substring(s-2, e+2); | ||
debugBranch("replaceFilterPlaceHolder:i:"+i+",s:"+s+",e:"+e+",m1:"+m1+",m2"+m2); | ||
if (m1 !== null && m1[0] && | ||
m2 !== null && m2) { | ||
/* Replace the output expression with filter expression */ | ||
obj.stmt = obj.stmt.replace(m1[0], m2); | ||
/* Replace the filterPlaceHolder with empty string */ | ||
obj.stmt = obj.stmt.replace(filterPlaceHolder, ""); | ||
/* Remove element from array */ | ||
var j = obj.filterPlaceHolder.indexOf(filterPlaceHolder); | ||
obj.filterPlaceHolder.splice(j, 1); | ||
} | ||
HandlebarsUtils._consumeTillCloseBrace = function(input, i, len) { | ||
var msg, | ||
str = '', | ||
obj = {}; | ||
for(var j=i;j<len;++j) { | ||
if (input[j] === '}' && j+1 < len && input[j+1] === '}') { | ||
str += '}}'; | ||
j++; | ||
obj.index = j; | ||
obj.str = str; | ||
return obj; | ||
} | ||
}); | ||
return obj; | ||
str += input[j]; | ||
} | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' close brace of expression."; | ||
HandlebarsUtils.handleError(msg, true); | ||
}; | ||
/* | ||
* @function HandlebarsUtils.blacklistProtocol | ||
* | ||
* Reference: | ||
* https://github.com/yahoo/xss-filters/blob/master/src/private-xss-filters.js#L266 | ||
/** | ||
* @function HandlebarsUtils._consumeTillCommentCloseBrace | ||
*/ | ||
HandlebarsUtils._URI_BLACKLIST = null; | ||
HandlebarsUtils._URI_BLACKLIST_REGEXPSTR = "^(?:&#[xX]0*(?:1?[1-9a-fA-F]|10|20);?|�*(?:[1-9]|[1-2][0-9]|30|31|32);?|	|
)*(?:(?:j|J|&#[xX]0*(?:6|4)[aA];?|�*(?:106|74);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:a|A|&#[xX]0*(?:6|4)1;?|�*(?:97|65);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:v|V|&#[xX]0*(?:7|5)6;?|�*(?:118|86);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:a|A|&#[xX]0*(?:6|4)1;?|�*(?:97|65);?)|(?:v|V|&#[xX]0*(?:7|5)6;?|�*(?:118|86);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:b|B|&#[xX]0*(?:6|4)2;?|�*(?:98|66);?))(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:s|S|&#[xX]0*(?:7|5)3;?|�*(?:115|83);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:c|C|&#[xX]0*(?:6|4)3;?|�*(?:99|67);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:r|R|&#[xX]0*(?:7|5)2;?|�*(?:114|82);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:i|I|&#[xX]0*(?:6|4)9;?|�*(?:105|73);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:p|P|&#[xX]0*(?:7|5)0;?|�*(?:112|80);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?:t|T|&#[xX]0*(?:7|5)4;?|�*(?:116|84);?)(?:&#[xX]0*[9aAdD];?|�*(?:9|10|13);?|	|
)*(?::|&#[xX]0*3[aA];?|�*58;?)"; | ||
HandlebarsUtils.blacklistProtocol = function(s) { | ||
var URI_FASTLANE = ['&', 'j', 'J', 'v', 'V']; | ||
if (URI_FASTLANE.indexOf(s[0]) === -1) { | ||
return false; | ||
} else { | ||
if (HandlebarsUtils._URI_BLACKLIST === null) { | ||
HandlebarsUtils._URI_BLACKLIST = new RegExp(HandlebarsUtils._URI_BLACKLIST_REGEXPSTR); | ||
HandlebarsUtils._consumeTillCommentCloseBrace = function(input, i, len, type) { | ||
var msg, | ||
str = '', | ||
obj = {}; | ||
for(var j=i;j<len;++j) { | ||
if (type === HandlebarsUtils.COMMENT_EXPRESSION_LONG_FORM) { | ||
if (input[j] === '-' && j+3<len && input[j+1] === '-' && input[j+2] === '}' && input[j+3] === '}') { | ||
str += '--}}'; | ||
j=j+3; | ||
obj.index = j; | ||
obj.str = str; | ||
return obj; | ||
} | ||
} else if (type === HandlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM) { | ||
if (input[j] === '}' && j+1<len && input[j+1] === '}') { | ||
str += '}}'; | ||
j++; | ||
obj.index = j; | ||
obj.str = str; | ||
return obj; | ||
} | ||
} | ||
if (HandlebarsUtils._URI_BLACKLIST.test(s)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
str += input[j]; | ||
} | ||
return true; | ||
msg = "[ERROR] ContextParserHandlebars: Parsing error! Cannot encounter '}}' or '--}}' close brace of comment expression."; | ||
HandlebarsUtils.handleError(msg, true); | ||
}; | ||
@@ -715,0 +636,0 @@ |
@@ -105,3 +105,3 @@ /* | ||
/* this test will not throw exception, but the vanilla handlebars will complain, no need to handle */ | ||
/* this test will throw exception, and the vanilla handlebars will complain */ | ||
it("./bin/handlebarspc broken conditional {{/if}} template test", function(done) { | ||
@@ -111,3 +111,3 @@ var exec = promise.promisify(require("child_process").exec); | ||
.timeout(300) | ||
.then(function(e){ | ||
.catch(function(e){ | ||
done(); | ||
@@ -114,0 +114,0 @@ }); |
@@ -34,3 +34,3 @@ /* | ||
it("handlebars {{expression}} subexpression with \r\n test", function() { | ||
it("handlebars {{expression}} subexpression with \\r\\n test", function() { | ||
[ | ||
@@ -96,2 +96,35 @@ '{{expression\rion}}', | ||
it("handlebars white space control test", function() { | ||
[ | ||
'{{#each nav ~}}\ | ||
xxx\ | ||
{{~/each}}', | ||
'{{#each nav ~}}\ | ||
xxx\ | ||
{{~/ each}}' | ||
].forEach(function(t) { | ||
var ast = handlebars.parse(t); | ||
expect(ast.statements[0].program.statements[0].string).to.equal('xxx'); | ||
}); | ||
[ | ||
// cannot have space between ~ and }} | ||
'{{#each nav ~ }}\ | ||
xxx\ | ||
{{~/each}}', | ||
// cannot have space between ~ and / | ||
'{{#each nav ~}}\ | ||
xxx\ | ||
{{~ / each}}' | ||
].forEach(function(t) { | ||
try { | ||
var ast = handlebars.parse(e); | ||
expect(false).to.equal(true); | ||
} catch (err) { | ||
expect(true).to.equal(true); | ||
} | ||
}); | ||
}); | ||
/* we are not using handlebars to build the AST, so the following test can be skipped | ||
* | ||
it("handlebars {{#if}} {{!-- comment --}} {{/if}} parsing test", function() { | ||
@@ -184,2 +217,28 @@ var t = '{{#if}}xxx{{!-- comment --}}yyy{{/if}}'; | ||
expect(ast.statements[0].inverse.statements[0].string).to.equal('yyy'); | ||
t = '{{~# if}}xxx{{~ else ~}}yyy{{/if}}'; | ||
ast = handlebars.parse(t); | ||
expect(ast.statements[0].mustache.id.string).to.equal('if'); | ||
expect(ast.statements[0].program.statements[0].string).to.equal('xxx'); | ||
expect(ast.statements[0].inverse.statements[0].string).to.equal('yyy'); | ||
t = '{{#if}}xxx{{^}}yyy{{/if}}'; | ||
ast = handlebars.parse(t); | ||
expect(ast.statements[0].mustache.id.string).to.equal('if'); | ||
expect(ast.statements[0].program.statements[0].string).to.equal('xxx'); | ||
expect(ast.statements[0].inverse.statements[0].string).to.equal('yyy'); | ||
t = '{{#if}}xxx{{^ }}yyy{{/if}}'; | ||
ast = handlebars.parse(t); | ||
expect(ast.statements[0].mustache.id.string).to.equal('if'); | ||
expect(ast.statements[0].program.statements[0].string).to.equal('xxx'); | ||
expect(ast.statements[0].inverse.statements[0].string).to.equal('yyy'); | ||
t = '{{#if}}xxx{{ ^ }}yyy{{/if}}'; | ||
try { | ||
ast = handlebars.parse(t); | ||
expect(false).to.equal(true); | ||
} catch (err) { | ||
expect(true).to.equal(true); | ||
} | ||
}); | ||
@@ -245,3 +304,3 @@ | ||
it("handlebars nested {{#if}} / {{#with}} / {{else}} parsing test", function() { | ||
it("handlebars nested {{#if}} / {{#with}} / {{else}} parsing test", function() { | ||
var t = '{{#if}}111{{#with}}222{{else}}333{{/with}}444{{else}}555{{#if}}666{{else}}777{{/if}}888{{/if}}'; | ||
@@ -282,3 +341,3 @@ var ast = handlebars.parse(t); | ||
it("handlebars nested {{#if}} / {{#each}} / {{else}} parsing test", function() { | ||
it("handlebars nested {{#if}} / {{#each}} / {{else}} parsing test", function() { | ||
var t = '{{#if}}111{{#each}}222{{else}}333{{/each}}444{{else}}555{{#if}}666{{else}}777{{/if}}888{{/if}}'; | ||
@@ -319,3 +378,3 @@ var ast = handlebars.parse(t); | ||
it("handlebars nested {{#if}} / {{#list}} / {{else}} parsing test", function() { | ||
it("handlebars nested {{#if}} / {{#list}} / {{else}} parsing test", function() { | ||
var t = '{{#if}}111{{#list people}}people{{else}}no people{{/list}}444{{else}}555{{#if}}666{{else}}777{{/if}}888{{/if}}'; | ||
@@ -356,3 +415,3 @@ var ast = handlebars.parse(t); | ||
it("handlebars nested {{#if}} / {{#tag}} / {{else}} parsing test", function() { | ||
it("handlebars nested {{#if}} / {{#tag}} / {{else}} parsing test", function() { | ||
var t = '{{#if}}111{{#tag people}}people{{else}}no people{{/tag}}444{{else}}555{{#if}}666{{else}}777{{/if}}888{{/if}}'; | ||
@@ -393,3 +452,3 @@ var ast = handlebars.parse(t); | ||
it("handlebars nested {{#if}} / {{^msg}} / {{else}} parsing test", function() { | ||
it("handlebars nested {{#if}} / {{^msg}} / {{else}} parsing test", function() { | ||
var t = '{{#if}}111{{^msg}}222{{else}}333{{/msg}}444{{else}}555{{#if}}666{{else}}777{{/if}}888{{/if}}'; | ||
@@ -518,3 +577,20 @@ var ast = handlebars.parse(t); | ||
it("handlebars parallel {{#if}} parsing test", function() { | ||
var t = '{{#if}} a {{#if}} b {{else}} c {{/if}} d {{#if}} e {{else}} f {{/if}} g {{#if}} h {{else}} i {{/if}} j {{/if}}'; | ||
var ast = handlebars.parse(t); | ||
expect(ast.statements[0].mustache.id.string).to.equal('if'); | ||
expect(ast.statements[0].program.statements[0].string).to.equal(' a '); | ||
expect(ast.statements[0].program.statements[1].mustache.id.string).to.equal('if'); | ||
expect(ast.statements[0].program.statements[1].program.statements[0].string).to.equal(' b '); | ||
expect(ast.statements[0].program.statements[1].inverse.statements[0].string).to.equal(' c '); | ||
expect(ast.statements[0].program.statements[2].string).to.equal(' d '); | ||
expect(ast.statements[0].program.statements[3].program.statements[0].string).to.equal(' e '); | ||
expect(ast.statements[0].program.statements[3].inverse.statements[0].string).to.equal(' f '); | ||
expect(ast.statements[0].program.statements[4].string).to.equal(' g '); | ||
expect(ast.statements[0].program.statements[5].program.statements[0].string).to.equal(' h '); | ||
expect(ast.statements[0].program.statements[5].inverse.statements[0].string).to.equal(' i '); | ||
expect(ast.statements[0].program.statements[6].string).to.equal(' j '); | ||
}); | ||
*/ | ||
}); | ||
}()); |
@@ -93,3 +93,3 @@ /* | ||
/{{!-- comment1 --}}/, | ||
/{{!-- comment2 }}/, | ||
/{{!-- comment2 }} --}}/, | ||
/{{! comment3 }}/ | ||
@@ -96,0 +96,0 @@ ]; |
@@ -18,215 +18,6 @@ /* | ||
describe("handlebars-handlebarsUtilss test suite", function() { | ||
describe("handlebars-utils test suite", function() { | ||
it("handlebars-handlebarsUtilss#generateNonce test", function() { | ||
var n1 = handlebarsUtils.generateNonce(); | ||
var n2 = handlebarsUtils.generateNonce(); | ||
expect(n1).not.to.equal(n2); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression invalid format test", function() { | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression {{else}} test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for {{else}} | ||
{str:'{else}}', isPrefixWithKnownFilter:true, filter:'', isSingleIdentifier:false}, | ||
// test for {{else}} with space after else | ||
{str:'{else }}', isPrefixWithKnownFilter:true, filter:'', isSingleIdentifier:false}, | ||
// test for {{else}} with space before/after else | ||
{str:'{ else }}', isPrefixWithKnownFilter:true, filter:'', isSingleIdentifier:false}, | ||
// test for {{else}} with space before/after else | ||
// {str:'{{else}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression basic test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for single identifier with the same name as known filter {y}} | ||
{str:'{y}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
{str:'{y }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
{str:'{ y }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with the same name as known default filter {h}} | ||
{str:'{h}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with dot notation | ||
{str:'{people.name}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with ../ | ||
{str:'{../name}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with / | ||
{str:'{article/name}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with [] | ||
{str:'{article[0]}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for single identifier with [] | ||
{str:'{article.[0].[#comments]}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
// test for expression with \r and \n as separator | ||
{str:'{y\rparam}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y\nparam}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y\r\nparam}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for expression with the same name as known filter {y}} | ||
{str:'{y output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{ y output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// test for expression with the same name as default filter {h}} | ||
{str:'{h output}}', isPrefixWithKnownFilter:false, filter:'h', isSingleIdentifier:false}, | ||
{str:'{h output}}', isPrefixWithKnownFilter:false, filter:'h', isSingleIdentifier:false}, | ||
{str:'{ h output}}', isPrefixWithKnownFilter:false, filter:'h', isSingleIdentifier:false}, | ||
// test for expression with dot notation filter | ||
{str:'{people.name output}}', isPrefixWithKnownFilter:false, filter:'people.name', isSingleIdentifier:false}, | ||
// test for expression with ../ filter | ||
{str:'{../name output}}', isPrefixWithKnownFilter:false, filter:'../name', isSingleIdentifier:false}, | ||
// test for expression with the same name as known filter {y}} and parameter in dot notation | ||
{str:'{y people.name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y people.name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{ y people.name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// test for expression with the same name as known filter {y}} and parameter with ../ | ||
{str:'{y ../output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y ../output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{ y ../output}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression 2 arguments test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for expression with the same name as known filter {y}} | ||
{str:'{y xxx zzz}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y xxx zzz}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{ y xxx zzz}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// test for expression with the same name as unknown filter | ||
{str:'{unknown xxx zzz}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false}, | ||
{str:'{unknown xxx zzz}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false}, | ||
{str:'{ unknown xxx zzz}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression 2 arguments (reference format) test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for expression with the same name as known filter {y}} with different parameter format | ||
{str:'{y people.name ../name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y article[0] article/name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y article.[0].[#comments] article/name}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// test for expression with the same name as known filter {unknown}} with different parameter format | ||
{str:'{unknown people.name ../name}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false}, | ||
{str:'{unknown article[0] article/name}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false}, | ||
{str:'{unknown article.[0].[#comments] article/name}}', isPrefixWithKnownFilter:false, filter:'unknown', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression reserved tag test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// test for reserved expression {{#.*}} | ||
{str:'{#y}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{# y xxx}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
// test for reserved expression {{/.*}} | ||
{str:'{/y}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{/ y }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
// test for reserved expression {{>.*}} | ||
{str:'{>partial}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{> partial }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
// test for reserved expression {{^.*}} | ||
{str:'{^negation}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{^ negation }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
// test for reserved expression {{!.*}} | ||
{str:'{!comment}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{! comment }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
// test for reserved expression {{@.*}} | ||
{str:'{@var}}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false}, | ||
{str:'{@ var }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression subexpression test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// not a valid handlebars syntax, no need to test | ||
// {str:'{y(output)}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// subexpression with one chain | ||
{str:'{y (output)}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y ( output ) }}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// subexpression with two chain | ||
{str:'{y (helper xxx)}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y ( helper xxx ) }}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y (helper "xxx")}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y ( helper "xxx" ) }}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// subexpression with three chain | ||
{str:'{y helper2 (helper1 xxx)}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y helper2 ( helper1 xxx )}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
{str:'{y helper2 ( helper1 "xxx" )}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// | ||
{str:'{y ( outer-helper (inner-helper "abc") "def")}}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#_parseExpression greedy match test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
var arr = [ | ||
// immediate after an expression | ||
{str:'{else}}{{h zzz }}', isPrefixWithKnownFilter:true, filter:'', isSingleIdentifier:false}, | ||
{str:'{y}}{{h zzz }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
{str:'{y param}}{{h zzz }}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false}, | ||
// not immediate after an expression | ||
{str:'{else}}xxxx{{h zzz }}', isPrefixWithKnownFilter:true, filter:'', isSingleIdentifier:false}, | ||
{str:'{y}}xxxx{{h zzz }}', isPrefixWithKnownFilter:false, filter:'', isSingleIdentifier:true}, | ||
{str:'{y param}}xxxx{{h zzz }}', isPrefixWithKnownFilter:true, filter:'y', isSingleIdentifier:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
var r = parser._parseExpression(obj.str, 0); | ||
utils.testExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#isValidExpression escapeExpressionRegExp test", function() { | ||
var arr = [ | ||
it("handlebars-utils#isValidExpression escapeExpressionRegExp test", function() { | ||
[ | ||
// basic | ||
@@ -240,2 +31,28 @@ {str:'{{anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{anything}}'}, | ||
{str:'{{any\'thing\'}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{any\'thing\'}}'}, | ||
{str:"{{any'thing'}}", type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:"{{any'thing'}}"}, | ||
{str:"{{~any'thing'~}}", type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:"{{~any'thing'~}}"}, | ||
{str:'{{any"thing"}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{any"thing"}}'}, | ||
// with ~ | ||
{str:'{{~anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~anything}}'}, | ||
{str:'{{~anything~}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~anything~}}'}, | ||
{str:'{{~ anything ~}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~ anything ~}}'}, | ||
// invalid reserved expression | ||
{str:'{{#anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~#anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{/anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~/anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{@anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~@anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{^anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~^anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{!anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~!anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{!--anything--}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~!--anything--}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{>anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{~>anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
// invalid expression | ||
@@ -248,5 +65,6 @@ {str:'{ {anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{ }anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
{str:'{{ ~anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
].forEach(function(obj) { | ||
var r = handlebarsUtils.isValidExpression(obj.str, 0, obj.type); | ||
@@ -257,4 +75,4 @@ utils.testIsValidExpression(r, obj); | ||
it("handlebars-handlebarsUtilss#isValidExpression rawExpressionRegExp test", function() { | ||
var arr = [ | ||
it("handlebars-utils#isValidExpression rawExpressionRegExp test", function() { | ||
[ | ||
// basic | ||
@@ -268,13 +86,18 @@ {str:'{{{anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{anything}}}'}, | ||
// with ~ | ||
{str:'{{{~anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~anything}}}'}, | ||
{str:'{{{~anything~}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~anything~}}}'}, | ||
{str:'{{{~ anything ~}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~ anything ~}}}'}, | ||
// invalid expression | ||
{str:'{ {{anything}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{ {anything}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{anything}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{anything}}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{ {anything}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{ }anything}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false}, | ||
{str:'{{{}}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:false} | ||
]; | ||
arr.forEach(function(obj) { | ||
{str:'{ {{anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{ {anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{anything}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{anything}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{anything}}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{ {anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{ }anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{ ~anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false}, | ||
{str:'{{{}}}', type:handlebarsUtils.RAW_EXPRESSION, result:false} | ||
].forEach(function(obj) { | ||
var r = handlebarsUtils.isValidExpression(obj.str, 0, obj.type); | ||
@@ -285,4 +108,4 @@ utils.testIsValidExpression(r, obj); | ||
it("handlebars-handlebarsUtilss#isValidExpression greedy match test", function() { | ||
var arr = [ | ||
it("handlebars-utils#isValidExpression greedy match test", function() { | ||
[ | ||
// basic | ||
@@ -299,2 +122,7 @@ {str:'{{anything}}{{anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{anything}}'}, | ||
// with ~ | ||
{str:'{{~anything}}{{anything}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~anything}}'}, | ||
{str:'{{~anything~}}{{~anything~}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~anything~}}'}, | ||
{str:'{{~ anything ~}}{{~ anything ~}}', type:handlebarsUtils.ESCAPE_EXPRESSION, result:true, rstr:'{{~ anything ~}}'}, | ||
// basic | ||
@@ -310,2 +138,30 @@ {str:'{{{anything}}}{{{anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{anything}}}'}, | ||
{str:'{{{any\r\nthing}}}{{{anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{any\r\nthing}}}'}, | ||
// with ~ | ||
{str:'{{{~anything}}}{{{anything}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~anything}}}'}, | ||
{str:'{{{~anything~}}}{{{~anything~}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~anything~}}}'}, | ||
{str:'{{{~ anything ~}}}{{{~ anything ~}}}', type:handlebarsUtils.RAW_EXPRESSION, result:true, rstr:'{{{~ anything ~}}}'}, | ||
].forEach(function(obj) { | ||
var r = handlebarsUtils.isValidExpression(obj.str, 0, obj.type); | ||
utils.testIsValidExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-utils#isValidExpression partialExpressionRegExp test", function() { | ||
var arr = [ | ||
// basic | ||
{str:'{{>anything}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{>anything}}'}, | ||
{str:'{{> anything }}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{> anything }}'}, | ||
// with \r and \n | ||
{str:'{{>any\rthing}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{>any\rthing}}'}, | ||
{str:'{{>any\nthing}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{>any\nthing}}'}, | ||
{str:'{{>any\r\nthing}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{>any\r\nthing}}'}, | ||
// with ~ | ||
{str:'{{~>anything}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{~>anything}}'}, | ||
{str:'{{~>anything~}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{~>anything~}}'}, | ||
{str:'{{~> anything ~}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:true, rstr:'{{~> anything ~}}'}, | ||
// invalid | ||
{str:'{{@anything}}', type:handlebarsUtils.PARTIAL_EXPRESSION, result:false}, | ||
]; | ||
@@ -318,12 +174,26 @@ arr.forEach(function(obj) { | ||
it("handlebars-handlebarsUtilss#isReservedChar test", function() { | ||
it("handlebars-utils#isValidExpression dataVarExpressionRegExp test", function() { | ||
[ | ||
'#', '/', '>', '@', '^', '!' | ||
].forEach(function(c) { | ||
var r = handlebarsUtils.isReservedChar(c); | ||
expect(r).to.equal(true); | ||
// basic | ||
{str:'{{@anything}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{@anything}}'}, | ||
{str:'{{@ anything }}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{@ anything }}'}, | ||
// with \r and \n | ||
{str:'{{@any\rthing}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{@any\rthing}}'}, | ||
{str:'{{@any\nthing}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{@any\nthing}}'}, | ||
{str:'{{@any\r\nthing}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{@any\r\nthing}}'}, | ||
// with ~ | ||
{str:'{{~@anything}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{~@anything}}'}, | ||
{str:'{{~@anything~}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{~@anything~}}'}, | ||
{str:'{{~@ anything ~}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:true, rstr:'{{~@ anything ~}}'}, | ||
// invalid | ||
{str:'{{>anything}}', type:handlebarsUtils.DATA_VAR_EXPRESSION, result:false}, | ||
].forEach(function(obj) { | ||
var r = handlebarsUtils.isValidExpression(obj.str, 0, obj.type); | ||
utils.testIsValidExpression(r, obj); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss#isBranchExpression test", function() { | ||
it("handlebars-utils#isBranchExpression test", function() { | ||
[ | ||
@@ -336,2 +206,13 @@ {str: '{{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx}}{{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx}}x{{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx}} x {{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~# if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx~}}', rstr: 'if'}, | ||
{str: '{{~#if xxx~}}{{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx~}}x{{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~#if xxx~}} x {{#if xxx}}', rstr: 'if'}, | ||
{str: '{{~# if xxx~}}', rstr: 'if'}, | ||
{str: '{{#with xxx}}', rstr: 'with'}, | ||
@@ -344,2 +225,9 @@ {str: '{{#each xxx}}', rstr: 'each'}, | ||
{str: '{{~^msg xxx}}', rstr: 'msg'}, | ||
{str: '{{^}}', rstr: false}, | ||
{str: '{{~^}}', rstr: false}, | ||
{str: '{{~^~}}', rstr: false}, | ||
{str: '{{~ ^ ~}}', rstr: false}, | ||
// illegal handlebars format | ||
@@ -353,3 +241,3 @@ {str: '{{#t-ag xxx}}', rstr: 't-ag'} | ||
it("handlebars-handlebarsUtilss#isBranchEndExpression test", function() { | ||
it("handlebars-utils#isBranchEndExpression test", function() { | ||
[ | ||
@@ -362,2 +250,13 @@ {str: '{{/if}}', rstr: 'if'}, | ||
{str: '{{~/if}}', rstr: 'if'}, | ||
{str: '{{~/if}}{{/if}}', rstr: 'if'}, | ||
{str: '{{~/if}}x{{/if}}', rstr: 'if'}, | ||
{str: '{{~/if}} x {{/if}}', rstr: 'if'}, | ||
{str: '{{~/ if }}', rstr: 'if'}, | ||
{str: '{{~/if~}}', rstr: 'if'}, | ||
{str: '{{~/if~}}{{/if}}', rstr: 'if'}, | ||
{str: '{{~/if~}}x{{/if}}', rstr: 'if'}, | ||
{str: '{{~/if~}} x {{/if}}', rstr: 'if'}, | ||
{str: '{{~/ if ~}}', rstr: 'if'}, | ||
{str: '{{/with}}', rstr: 'with'}, | ||
@@ -378,3 +277,3 @@ {str: '{{/each}}', rstr: 'each'}, | ||
it("handlebars-handlebarsUtilss#isElseExpression test", function() { | ||
it("handlebars-utils#isElseExpression test", function() { | ||
[ | ||
@@ -385,3 +284,24 @@ {str: '{{else}}', result:true}, | ||
{str: '{{else}}x{{else}}', result:true}, | ||
{str: '{{else}} x {{else}}', result:true} | ||
{str: '{{else}} x {{else}}', result:true}, | ||
{str: '{{~else~}}', result:true}, | ||
{str: '{{~ else ~}}', result:true}, | ||
{str: '{{~else~}}{{~else~}}', result:true}, | ||
{str: '{{~else~}}x{{~else~}}', result:true}, | ||
{str: '{{~else~}} x {{~else~}}', result:true}, | ||
{str: '{{^}}', result:true}, | ||
{str: '{{~^~}}', result:true}, | ||
{str: '{{~ ^ ~}}', result:true}, | ||
{str: '{{^ }}', result:true}, | ||
{str: '{{^ ~}}', result:true}, | ||
{str: '{{^}}{{^}}', result:true}, | ||
{str: '{{^}}x{{^}}', result:true}, | ||
{str: '{{^}} x {{^}}', result:true}, | ||
{str: '{{~^~}}{{~^~}}', result:true}, | ||
{str: '{{^msg}}', result:false}, | ||
{str: '{{^msg ~}}', result:false}, | ||
{str: '{{^ msg}}', result:false}, | ||
{str: '{{^ msg }}', result:false} | ||
].forEach(function(obj) { | ||
@@ -393,3 +313,3 @@ var r = handlebarsUtils.isElseExpression(obj.str); | ||
it("handlebars-handlebarsUtilss#isBranchExpressions test", function() { | ||
it("handlebars-utils#isBranchExpressions test", function() { | ||
[ | ||
@@ -410,3 +330,5 @@ {str: '{{#if xxx}}', result:true}, | ||
{str: '{{else}}', result:false}, | ||
{str: '{{^}}', result:false}, | ||
{str: '{{expression}}', result:false}, | ||
{str: '{{@partial}}', result:false}, | ||
{str: '{{{expression}}}', result:false}, | ||
@@ -419,316 +341,193 @@ ].forEach(function(obj) { | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#if xxx}} statement test", function() { | ||
var s = "{{#if xxx}} a {{/if}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#if xxx}} a {{\/if}}'); | ||
it("handlebars-utils#isReservedChar test", function() { | ||
[ | ||
'#', '/', '>', '@', '^', '!', | ||
'~#', '~/', '~>', '~@', '~^', '~!' | ||
].forEach(function(s) { | ||
var r = handlebarsUtils.isReservedChar(s, 0); | ||
expect(r).to.equal(true); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#if xxx}} statement with {{else}} test", function() { | ||
var s = "{{#if xxx}} a {{else}} b {{/if}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#if xxx}} a {{else}} b {{\/if}}'); | ||
}); | ||
it("context-parser-handlebars#_handleCommentExpression test", function() { | ||
var parser = new ContextParserHandlebars(); | ||
[ | ||
{str: '{{! comment }}', type:handlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM, result:14}, | ||
{str: '{{! comment }} }}', type:handlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM, result:14}, | ||
{str: '{{!-- comment --}}', type:handlebarsUtils.COMMENT_EXPRESSION_LONG_FORM, result:18}, | ||
{str: '{{!-- comment --}} --}}', type:handlebarsUtils.COMMENT_EXPRESSION_LONG_FORM, result:18}, | ||
{str: '{{!-- comment }} --}}', type:handlebarsUtils.COMMENT_EXPRESSION_LONG_FORM, result:22}, | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#if xxx}} statement test", function() { | ||
var s = "{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} h {{/if}} i {{/if}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} h {{/if}} i {{/if}}'); | ||
// these cases are guarded against by isCommentExpression | ||
{str: '{{!-- comment }}', type:handlebarsUtils.COMMENT_EXPRESSION_SHORT_FORM, result:16}, | ||
{str: '{{! comment --}}', type:handlebarsUtils.COMMENT_EXPRESSION_LONG_FORM, result:16} | ||
].forEach(function(obj) { | ||
var r = parser._handleCommentExpression(obj.str, 0, obj.str.length, obj.type); | ||
expect(r).to.equal(obj.result); | ||
}); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#with xxx}} statement test", function() { | ||
var s = "{{#with xxx}} a {{/with}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#with xxx}} a {{\/with}}'); | ||
it("handlebars-utils - build basic branch AST test", function() { | ||
var s = "{{#if xxx}} a b {{/if}}xxxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a b '); | ||
expect(ast.program[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content).to.equal('{{/if}}'); | ||
expect(ast.inverse).to.deep.equal([]); | ||
expect(ast.index).to.equal(22); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a b {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#with xxx}} statement with {{else}} test", function() { | ||
var s = "{{#with xxx}} a {{else}} b {{/with}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#with xxx}} a {{else}} b {{\/with}}'); | ||
it("handlebars-utils - build basic branch with {{expression}} AST test", function() { | ||
var s = "{{#if xxx}} a b {{expression}} {{/if}}xxxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a b {{expression}} '); | ||
expect(ast.program[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content).to.equal('{{/if}}'); | ||
expect(ast.inverse).to.deep.equal([]); | ||
expect(ast.index).to.equal(37); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a b {{{yd expression}}} {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#with xxx}} statement test", function() { | ||
var s = "{{#with xxx}} a {{#with}} b {{else}} c {{/with}} d {{else}} e {{#with}} f {{else}} h {{/with}} i {{/with}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#with xxx}} a {{#with}} b {{else}} c {{/with}} d {{else}} e {{#with}} f {{else}} h {{/with}} i {{/with}}'); | ||
}); | ||
it("handlebars-utils - build basic branch with {{!comment}} AST test", function() { | ||
var s = "{{#if xxx}} a b {{!--comment {{#if xxx}} abc {{/if}} --}} {{/if}}xxxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a b {{!--comment {{#if xxx}} abc {{/if}} --}} '); | ||
expect(ast.program[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content).to.equal('{{/if}}'); | ||
expect(ast.inverse).to.deep.equal([]); | ||
expect(ast.index).to.equal(65); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a b {{!--comment {{#if xxx}} abc {{/if}} --}} {{/if}}'); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#each xxx}} statement test", function() { | ||
var s = "{{#each xxx}} a {{/each}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#each xxx}} a {{\/each}}'); | ||
s = "{{#if xxx}} a b {{!comment {{#if xxx}} abc {{/if}} --}} {{/if}}xxxxxxx"; | ||
ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a b {{!comment {{#if xxx}} abc '); | ||
expect(ast.program[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content).to.equal('{{/if}}'); | ||
expect(ast.inverse).to.deep.equal([]); | ||
expect(ast.index).to.equal(50); | ||
r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a b {{!comment {{#if xxx}} abc {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#each xxx}} statement with {{else}} test", function() { | ||
var s = "{{#each xxx}} a {{else}} b {{/each}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#each xxx}} a {{else}} b {{\/each}}'); | ||
}); | ||
it("handlebars-utils - build basic branch with inverse AST test", function() { | ||
var s = "{{#if xxx}} a {{else}} b {{/if}}xxxxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a '); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#each xxx}} statement test", function() { | ||
var s = "{{#each xxx}} a {{#each}} b {{else}} c {{/each}} d {{else}} e {{#each}} f {{else}} h {{/each}} i {{/each}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#each xxx}} a {{#each}} b {{else}} c {{/each}} d {{else}} e {{#each}} f {{else}} h {{/each}} i {{/each}}'); | ||
expect(ast.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.inverse[1].type).to.equal('content'); | ||
expect(ast.inverse[1].content).to.equal(' b '); | ||
expect(ast.inverse[2].type).to.equal('branchend'); | ||
expect(ast.inverse[2].content).to.equal('{{/if}}'); | ||
expect(ast.index).to.equal(31); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a {{else}} b {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#list xxx}} statement test", function() { | ||
var s = "{{#list xxx}} a {{/list}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#list xxx}} a {{\/list}}'); | ||
}); | ||
it("handlebars-utils - build nested branch AST test", function() { | ||
var s = "{{#if xxx}} a {{#if yyy}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} g {{/if}} h {{/if}}xxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a '); | ||
expect(ast.program[2].type).to.equal('node'); | ||
expect(ast.program[2].content.program[0].type).to.equal('branch'); | ||
expect(ast.program[2].content.program[0].content).to.equal('{{#if yyy}}'); | ||
expect(ast.program[2].content.program[1].type).to.equal('content'); | ||
expect(ast.program[2].content.program[1].content).to.equal(' b '); | ||
expect(ast.program[2].content.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.program[2].content.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.program[2].content.inverse[1].type).to.equal('content'); | ||
expect(ast.program[2].content.inverse[1].content).to.equal(' c '); | ||
expect(ast.program[2].content.inverse[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content.inverse[2].content).to.equal('{{/if}}'); | ||
expect(ast.program[3].type).to.equal('content'); | ||
expect(ast.program[3].content).to.equal(' d '); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#list xxx}} statement with {{else}} test", function() { | ||
var s = "{{#list xxx}} a {{else}} b {{/list}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#list xxx}} a {{else}} b {{\/list}}'); | ||
expect(ast.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.inverse[1].type).to.equal('content'); | ||
expect(ast.inverse[1].content).to.equal(' e '); | ||
expect(ast.inverse[2].type).to.equal('node'); | ||
expect(ast.inverse[2].content.program[0].type).to.equal('branch'); | ||
expect(ast.inverse[2].content.program[0].content).to.equal('{{#if}}'); | ||
expect(ast.inverse[2].content.program[1].type).to.equal('content'); | ||
expect(ast.inverse[2].content.program[1].content).to.equal(' f '); | ||
expect(ast.inverse[2].content.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.inverse[2].content.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.inverse[2].content.inverse[1].type).to.equal('content'); | ||
expect(ast.inverse[2].content.inverse[1].content).to.equal(' g '); | ||
expect(ast.inverse[2].content.inverse[2].type).to.equal('branchend'); | ||
expect(ast.inverse[2].content.inverse[2].content).to.equal('{{/if}}'); | ||
expect(ast.inverse[3].type).to.equal('content'); | ||
expect(ast.inverse[3].content).to.equal(' h '); | ||
expect(ast.inverse[4].type).to.equal('branchend'); | ||
expect(ast.inverse[4].content).to.equal('{{/if}}'); | ||
expect(ast.index).to.equal(97); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a {{#if yyy}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} g {{/if}} h {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#list xxx}} statement test", function() { | ||
var s = "{{#list xxx}} a {{#list yyy}} b {{else}} c {{/list}} d {{else}} e {{#list zzz}} f {{else}} h {{/list}} i {{/list}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#list xxx}} a {{#list yyy}} b {{else}} c {{/list}} d {{else}} e {{#list zzz}} f {{else}} h {{/list}} i {{/list}}'); | ||
it("handlebars-utils - build parallel branch AST test", function() { | ||
var s = "{{#if xxx}} a {{#if yyy}} b {{else}} c {{/if}} d {{#if}} e {{else}} f {{/if}} g {{/if}}xxxxxxx"; | ||
var ast = handlebarsUtils.buildBranchAst(s, 0); | ||
expect(ast.program[0].type).to.equal('branch'); | ||
expect(ast.program[0].content).to.equal('{{#if xxx}}'); | ||
expect(ast.program[1].type).to.equal('content'); | ||
expect(ast.program[1].content).to.equal(' a '); | ||
expect(ast.program[2].type).to.equal('node'); | ||
expect(ast.program[2].content.program[0].type).to.equal('branch'); | ||
expect(ast.program[2].content.program[0].content).to.equal('{{#if yyy}}'); | ||
expect(ast.program[2].content.program[1].type).to.equal('content'); | ||
expect(ast.program[2].content.program[1].content).to.equal(' b '); | ||
expect(ast.program[2].content.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.program[2].content.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.program[2].content.inverse[1].type).to.equal('content'); | ||
expect(ast.program[2].content.inverse[1].content).to.equal(' c '); | ||
expect(ast.program[2].content.inverse[2].type).to.equal('branchend'); | ||
expect(ast.program[2].content.inverse[2].content).to.equal('{{/if}}'); | ||
expect(ast.program[3].type).to.equal('content'); | ||
expect(ast.program[3].content).to.equal(' d '); | ||
expect(ast.program[4].type).to.equal('node'); | ||
expect(ast.program[4].content.program[0].type).to.equal('branch'); | ||
expect(ast.program[4].content.program[0].content).to.equal('{{#if}}'); | ||
expect(ast.program[4].content.program[1].type).to.equal('content'); | ||
expect(ast.program[4].content.program[1].content).to.equal(' e '); | ||
expect(ast.program[4].content.inverse[0].type).to.equal('branchelse'); | ||
expect(ast.program[4].content.inverse[0].content).to.equal('{{else}}'); | ||
expect(ast.program[4].content.inverse[1].type).to.equal('content'); | ||
expect(ast.program[4].content.inverse[1].content).to.equal(' f '); | ||
expect(ast.program[4].content.inverse[2].type).to.equal('branchend'); | ||
expect(ast.program[4].content.inverse[2].content).to.equal('{{/if}}'); | ||
expect(ast.program[5].type).to.equal('content'); | ||
expect(ast.program[5].content).to.equal(' g '); | ||
expect(ast.program[6].type).to.equal('branchend'); | ||
expect(ast.program[6].content).to.equal('{{/if}}'); | ||
expect(ast.index).to.equal(86); | ||
var r = handlebarsUtils.analyseBranchAst(ast, 1); | ||
expect(r.output).to.equal('{{#if xxx}} a {{#if yyy}} b {{else}} c {{/if}} d {{#if}} e {{else}} f {{/if}} g {{/if}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#tag xxx}} statement test", function() { | ||
var s = "{{#tag xxx}} a {{/tag}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#tag xxx}} a {{\/tag}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#tag xxx}} statement with {{else}} test", function() { | ||
var s = "{{#tag xxx}} a {{else}} b {{/tag}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#tag xxx}} a {{else}} b {{\/tag}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#tag xxx}} statement test", function() { | ||
var s = "{{#tag xxx}} a {{#tag yyy}} b {{else}} c {{/tag}} d {{else}} e {{#tag zzz}} f {{else}} h {{/tag}} i {{/tag}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#tag xxx}} a {{#tag yyy}} b {{else}} c {{/tag}} d {{else}} e {{#tag zzz}} f {{else}} h {{/tag}} i {{/tag}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{^msg}} statement test", function() { | ||
var s = "{{^msg}} a {{/msg}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{^msg}} a {{\/msg}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{^msg}} statement with {{else}} test", function() { | ||
var s = "{{^msg}} a {{else}} b {{/msg}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{^msg}} a {{else}} b {{\/msg}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{^msg}} statement test", function() { | ||
var s = "{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{else}} e {{^msg}} f {{else}} h {{/msg}} i {{/msg}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{else}} e {{^msg}} f {{else}} h {{/msg}} i {{/msg}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract basic Handlebars {{#unless xxx}} statement test", function() { | ||
var s = "{{#unless xxx}} a {{/unless}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#unless xxx}} a {{\/unless}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#unless xxx}} statement test", function() { | ||
var s = "{{#unless xxx}} a {{#unless xxx}} b {{/unless}} c {{/unless}} zzzzzzzz"; | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(r['stmt']).to.equal('{{#unless xxx}} a {{#unless xxx}} b {{/unless}} c {{/unless}}'); | ||
}); | ||
it("handlebars-handlebarsUtilss - extract nested Handlebars {{#unless xxx}} statement exception test", function() { | ||
var s = "{{#if} aaaaaaaa"; | ||
try { | ||
var r = handlebarsUtils.extractBranchStmt(s, 0, false); | ||
expect(false).to.equal(true); | ||
} catch (err) { | ||
expect(true).to.equal(true); | ||
} | ||
}); | ||
it("handlebars-handlebarsUtilss - parse basic Handlebars {{#if xxx}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a (1st branch) | ||
// 'empty string' (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse basic Handlebars {{#if xxx}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{else}} b {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{else}} b {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a (1st branch) | ||
// b (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse nested Handlebars {{#if xxx}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{#if}} b {{/if}} c {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{#if}} b {{/if}} c {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b c (1st branch) | ||
// a c (1st branch) | ||
// 'empty string' (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse nested Handlebars {{#if xxx}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} g {{/if}} h {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{else}} e {{#if}} f {{else}} g {{/if}} h {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d (1st branch) | ||
// a c d (1st branch) | ||
// e f h (2nd branch) | ||
// e g h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse parallel Handlebars {{#if xxx}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{#if}} b {{else}} c {{/if}} f {{else}} e {{#if xyz}} f {{else}} g {{/if}} h {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{#if}} b {{else}} c {{/if}} f {{else}} e {{#if xyz}} f {{else}} g {{/if}} h {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d b f (1st branch) | ||
// a c d b f (1st branch) | ||
// a b d c f (1st branch) | ||
// a c d c f (1st branch) | ||
// e f h (2nd branch) | ||
// e g h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse parallel Handlebars {{#if}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{#if}} b {{else}} c {{/if}} f {{else}} e {{#if}} f {{else}} g {{/if}} h {{#if}} 1 {{else}} 2 {{/if}} h {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{#if xxx}} a {{#if}} b {{else}} c {{/if}} d {{#if}} b {{else}} c {{/if}} f {{else}} e {{#if}} f {{else}} g {{/if}} h {{#if}} 1 {{else}} 2 {{/if}} h {{/if}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d b f (1st branch) | ||
// a c d b f (1st branch) | ||
// a b d c f (1st branch) | ||
// a c d c f (1st branch) | ||
// e f h 1 h (2nd branch) | ||
// e g h 1 h (2nd branch) | ||
// e f h 2 h (2nd branch) | ||
// e g h 2 h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse basic Handlebars {{^msg}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a (1st branch) | ||
// b (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse basic Handlebars {{^msg}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{else}} b {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{else}} b {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a (1st branch) | ||
// b (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse nested Handlebars {{^msg}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{^msg}} b {{/msg}} c {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{^msg}} b {{/msg}} c {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b c (1st branch) | ||
// a c (1st branch) | ||
// 'empty string' (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse nested Handlebars {{^msg}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d (1st branch) | ||
// a c d (1st branch) | ||
// e f h (2nd branch) | ||
// e g h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse parallel Handlebars {{^msg}} statement parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{^msg}} b {{else}} c {{/msg}} f {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{^msg}} b {{else}} c {{/msg}} f {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d b f (1st branch) | ||
// a c d b f (1st branch) | ||
// a b d c f (1st branch) | ||
// a c d c f (1st branch) | ||
// e f h (2nd branch) | ||
// e g h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse parallel Handlebars {{^msg}} statement with {{else}} parseAstTreeState test", function() { | ||
var s = "<a href='{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{^msg}} b {{else}} c {{/msg}} f {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{^msg}} 1 {{else}} 2 {{/msg}} h {{/msg}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
expect(obj.stmt).to.equal('{{^msg}} a {{^msg}} b {{else}} c {{/msg}} d {{^msg}} b {{else}} c {{/msg}} f {{else}} e {{^msg}} f {{else}} g {{/msg}} h {{^msg}} 1 {{else}} 2 {{/msg}} h {{/msg}}'); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
// a b d b f (1st branch) | ||
// a c d b f (1st branch) | ||
// a b d c f (1st branch) | ||
// a c d c f (1st branch) | ||
// e f h 1 h (2nd branch) | ||
// e g h 1 h (2nd branch) | ||
// e f h 2 h (2nd branch) | ||
// e g h 2 h (2nd branch) | ||
expect(r.lastStates[0]).to.equal(39); | ||
expect(r.lastStates[1]).to.equal(39); | ||
}); | ||
it("handlebars-handlebarsUtilss - parse basic Handlebars {{#if xxx}} broken statement with {{else}} parseAstTreeState exception test", function() { | ||
var s = "<a href='{{#if xxx}} a {{else}} b'> {{/if}}'>"; | ||
var obj = handlebarsUtils.extractBranchStmt(s, 9, true); | ||
var ast = handlebarsUtils.parseBranchStmt(obj.stmt); | ||
try { | ||
var r = handlebarsUtils.parseAstTreeState(ast, 39, obj); | ||
expect(false).to.equal(true); | ||
} catch (err) { | ||
expect(true).to.equal(true); | ||
} | ||
}); | ||
}); | ||
}()); |
@@ -17,3 +17,3 @@ /* | ||
exports.testExpression = function(result, obj) { | ||
expect(result.isPrefixWithKnowFilter).to.equal(obj.isPrefixWithKnowFilter); | ||
expect(result.isPrefixWithKnownFilter).to.equal(obj.isPrefixWithKnownFilter); | ||
expect(result.filter).to.equal(obj.filter); | ||
@@ -20,0 +20,0 @@ expect(result.isSingleIdentifier).to.equal(obj.isSingleIdentifier); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
235029
67
3503
6