Files
liquidjs/render.js
T
2016-06-16 01:02:00 +08:00

70 lines
2.3 KiB
JavaScript

const lexical = require('./lexical.js');
const syntax = require('./syntax.js');
const error = require('./error.js');
module.exports = function(Filter, Tag) {
function render(tokens, scope) {
var html = '';
while (tokens.length) {
var token = tokens.shift();
switch (token.type) {
case 'html':
html += token.value;
break;
case 'output':
html += evalFilter(token.value, scope);
break;
case 'tag':
html += renderTag(token, tokens, scope);
break;
default:
error(`unexpected type: ${token.type}`, token);
}
}
return html;
}
function evalExp(exp, scope) {
if(!scope) error('unable to evalExp: scope undefined');
var operatorREs = lexical.operators;
for (var i = 0; i < operatorREs.length; i++) {
var operatorRE = operatorREs[i];
var expRE = new RegExp(`^(${lexical.quoteBalanced.source})(${operatorRE.source})(${lexical.quoteBalanced.source})$`);
var match = exp.match(expRE);
if (match) {
var l = evalExp(match[1], scope);
var op = syntax.operators[match[2].trim()];
var r = evalExp(match[3], scope);
return op(l, r);
}
}
return evalFilter(exp, scope);
}
function evalFilter(str, scope){
if(!scope) error('unable to evalFilter: scope undefined');
var filters = str.split('|');
var val = scope.get(filters.shift());
return filters
.map(str => Filter.construct(str))
.reduce((v, filter) => filter.render(v, scope), val);
}
function renderTag(token, tokens, scope) {
var tag = Tag.construct(token),
subTokens = [];
if (tag.needClose) {
var curToken, endToken = 'end' + tag.token.name;
while ((curToken = tokens.shift()) && curToken.value !== endToken) {
subTokens.push(curToken);
}
if (!curToken) error(`${token.value} not closed`);
}
return tag.render(subTokens, scope);
}
return {
render, renderTag, evalFilter, evalExp
};
};