-
-
Save atian25/6388f6853ef70ac01d58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var swig = require('swig'); | |
var expect = require('expect.js'); | |
describe('test', function() { | |
var compileFn = function(compiler, args, content, parents, options, blockName) { | |
return ';_output += "<div"' + JSON.stringify(args) + '+">";' + compiler(content, parents, options, blockName) + ';' + '_output += "</div>";'; | |
}; | |
var parseFn = function(str, line, parser, types, options) { | |
function parseToken(token){ | |
var _t = types; | |
var self = this, | |
fn = self._parsers[token.type] || self._parsers['*'], | |
match = token.match, | |
prevToken = self.prevToken, | |
prevTokenType = prevToken ? prevToken.type : null, | |
lastState = (self.state.length) ? self.state[self.state.length - 1] : null, | |
temp; | |
if (lastState && prevToken && | |
lastState === _t.FILTER && | |
prevTokenType === _t.FILTER && | |
token.type !== _t.PARENCLOSE && | |
token.type !== _t.COMMA && | |
token.type !== _t.OPERATOR && | |
token.type !== _t.FILTER && | |
token.type !== _t.FILTEREMPTY) { | |
self.out.push(', '); | |
} | |
if (lastState && lastState === _t.METHODOPEN) { | |
self.state.pop(); | |
if (token.type !== _t.PARENCLOSE) { | |
self.out.push(', '); | |
} | |
} | |
switch (token.type) { | |
case _t.WHITESPACE: | |
break; | |
case _t.STRING: | |
self.filterApplyIdx.push(self.out.length); | |
self.out.push(match.replace(/\\/g, '\\\\')); | |
break; | |
case _t.NUMBER: | |
case _t.BOOL: | |
self.filterApplyIdx.push(self.out.length); | |
self.out.push(match); | |
break; | |
case _t.FILTER: | |
if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") { | |
utils.throwError('Invalid filter "' + match + '"', self.line, self.filename); | |
} | |
self.escape = self.filters[match].safe ? false : self.escape; | |
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"]('); | |
self.state.push(token.type); | |
break; | |
case _t.FILTEREMPTY: | |
if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") { | |
utils.throwError('Invalid filter "' + match + '"', self.line, self.filename); | |
} | |
self.escape = self.filters[match].safe ? false : self.escape; | |
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"]('); | |
self.out.push(')'); | |
break; | |
case _t.FUNCTION: | |
case _t.FUNCTIONEMPTY: | |
self.out.push('((typeof _ctx.' + match + ' !== "undefined") ? _ctx.' + match + | |
' : ((typeof ' + match + ' !== "undefined") ? ' + match + | |
' : _fn))('); | |
self.escape = false; | |
if (token.type === _t.FUNCTIONEMPTY) { | |
self.out[self.out.length - 1] = self.out[self.out.length - 1] + ')'; | |
} else { | |
self.state.push(token.type); | |
} | |
self.filterApplyIdx.push(self.out.length - 1); | |
break; | |
case _t.PARENOPEN: | |
self.state.push(token.type); | |
if (self.filterApplyIdx.length) { | |
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '('); | |
if (prevToken && prevTokenType === _t.VAR) { | |
temp = prevToken.match.split('.').slice(0, -1); | |
self.out.push(' || _fn).call(' + self.checkMatch(temp)); | |
self.state.push(_t.METHODOPEN); | |
self.escape = false; | |
} else { | |
self.out.push(' || _fn)('); | |
} | |
self.filterApplyIdx.push(self.out.length - 3); | |
} else { | |
self.out.push('('); | |
self.filterApplyIdx.push(self.out.length - 1); | |
} | |
break; | |
case _t.PARENCLOSE: | |
temp = self.state.pop(); | |
if (temp !== _t.PARENOPEN && temp !== _t.FUNCTION && temp !== _t.FILTER) { | |
utils.throwError('Mismatched nesting state', self.line, self.filename); | |
} | |
self.out.push(')'); | |
// Once off the previous entry | |
self.filterApplyIdx.pop(); | |
if (temp !== _t.FILTER) { | |
// Once for the open paren | |
self.filterApplyIdx.pop(); | |
} | |
break; | |
case _t.COMMA: | |
if (lastState !== _t.FUNCTION && | |
lastState !== _t.FILTER && | |
lastState !== _t.ARRAYOPEN && | |
lastState !== _t.CURLYOPEN && | |
lastState !== _t.PARENOPEN && | |
lastState !== _t.COLON) { | |
utils.throwError('Unexpected comma', self.line, self.filename); | |
} | |
if (lastState === _t.COLON) { | |
self.state.pop(); | |
} | |
self.out.push(', '); | |
self.filterApplyIdx.pop(); | |
break; | |
case _t.LOGIC: | |
case _t.COMPARATOR: | |
if (!prevToken || | |
prevTokenType === _t.COMMA || | |
prevTokenType === token.type || | |
prevTokenType === _t.BRACKETOPEN || | |
prevTokenType === _t.CURLYOPEN || | |
prevTokenType === _t.PARENOPEN || | |
prevTokenType === _t.FUNCTION) { | |
utils.throwError('Unexpected logic', self.line, self.filename); | |
} | |
self.out.push(token.match); | |
break; | |
case _t.NOT: | |
self.out.push(token.match); | |
break; | |
case _t.VAR: | |
self.parseVar(token, match, lastState); | |
break; | |
case _t.BRACKETOPEN: | |
if (!prevToken || | |
(prevTokenType !== _t.VAR && | |
prevTokenType !== _t.BRACKETCLOSE && | |
prevTokenType !== _t.PARENCLOSE)) { | |
self.state.push(_t.ARRAYOPEN); | |
self.filterApplyIdx.push(self.out.length); | |
} else { | |
self.state.push(token.type); | |
} | |
self.out.push('['); | |
break; | |
case _t.BRACKETCLOSE: | |
temp = self.state.pop(); | |
if (temp !== _t.BRACKETOPEN && temp !== _t.ARRAYOPEN) { | |
utils.throwError('Unexpected closing square bracket', self.line, self.filename); | |
} | |
self.out.push(']'); | |
self.filterApplyIdx.pop(); | |
break; | |
case _t.CURLYOPEN: | |
self.state.push(token.type); | |
self.out.push('{'); | |
self.filterApplyIdx.push(self.out.length - 1); | |
break; | |
case _t.COLON: | |
if (lastState !== _t.CURLYOPEN) { | |
utils.throwError('Unexpected colon', self.line, self.filename); | |
} | |
self.state.push(token.type); | |
self.out.push(':'); | |
self.filterApplyIdx.pop(); | |
break; | |
case _t.CURLYCLOSE: | |
if (lastState === _t.COLON) { | |
self.state.pop(); | |
} | |
if (self.state.pop() !== _t.CURLYOPEN) { | |
utils.throwError('Unexpected closing curly brace', self.line, self.filename); | |
} | |
self.out.push('}'); | |
self.filterApplyIdx.pop(); | |
break; | |
case _t.DOTKEY: | |
if (!prevToken || ( | |
prevTokenType !== _t.VAR && | |
prevTokenType !== _t.BRACKETCLOSE && | |
prevTokenType !== _t.DOTKEY && | |
prevTokenType !== _t.PARENCLOSE && | |
prevTokenType !== _t.FUNCTIONEMPTY && | |
prevTokenType !== _t.FILTEREMPTY && | |
prevTokenType !== _t.CURLYCLOSE | |
)) { | |
utils.throwError('Unexpected key "' + match + '"', self.line, self.filename); | |
} | |
self.out.push('.' + match); | |
break; | |
case _t.OPERATOR: | |
self.out.push(' ' + match + ' '); | |
self.filterApplyIdx.pop(); | |
break; | |
} | |
} | |
parser.on('start', function() { | |
this | |
// called when a parse starts | |
}); | |
parser.on('*', function(token) { | |
var str = token.match; | |
// 自定义时貌似只能拷贝parseToken实现出来, 去掉fn.call的判断 | |
// this.out.push(parseToken.call(this, token)); | |
return true; | |
// called on the match of any token at all ("*") | |
}); | |
parser.on('end', function() { | |
this.out | |
// called when a parse ends | |
}); | |
return true; // parser is good to go | |
}; | |
swig.setTag('test', parseFn, compileFn, true, false); | |
var context = { | |
locals: { | |
clz: 'test', | |
foo: { | |
bar: 'bar' | |
}, | |
bool: false, | |
html: '<img src=>', | |
jsonStr: JSON.stringify({ a: 'b' }) | |
} | |
}; | |
it('should parse: ', function() { | |
var c = '{% test a=!bool.test["a"]|first|last %}content{% endtest %}'; | |
expect(swig.render(c, context)).to.be.equal('<div>content</div>'); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment