mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-16 12:50:38 -07:00
filters
This commit is contained in:
@@ -11,74 +11,79 @@ shall be implemented.
|
||||
|
||||
> Shopify liquid is used by [Jekyll][jekyll] and [Github Pages][gh].
|
||||
|
||||
## Operators
|
||||
|
||||
Documentation: <https://shopify.github.io/liquid/basics/operators/>
|
||||
|
||||
`==`, `!=`, `>`, `<`, `>=`, `<=`, `or`, `and`, `contains`.
|
||||
|
||||
## Tags
|
||||
|
||||
Documentation: <https://shopify.github.io/liquid/basics/introduction/#tags>
|
||||
|
||||
- [x] [assign](https://shopify.github.io/liquid/tags/control-flow/)
|
||||
- [x] [case/when](https://shopify.github.io/liquid/tags/control-flow/)
|
||||
- [ ] [if](https://shopify.github.io/liquid/tags/control-flow/)
|
||||
- [ ] [unless](https://shopify.github.io/liquid/tags/control-flow/)
|
||||
- [ ] [elsif/else](https://shopify.github.io/liquid/tags/control-flow/)
|
||||
- [ ] [for](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [break](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [continue](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [for: limit,offset,range,reversed)](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [cycle](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [cycle: group)](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [tablerow](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [tablerow: cols,limit,offset,range](https://shopify.github.io/liquid/tags/iteration/)
|
||||
- [ ] [assign](https://shopify.github.io/liquid/tags/variable/)
|
||||
- [ ] [capture](https://shopify.github.io/liquid/tags/variable/)
|
||||
- [ ] [increment](https://shopify.github.io/liquid/tags/variable/)
|
||||
- [ ] [decrement](https://shopify.github.io/liquid/tags/variable/)
|
||||
- [x] case/when [Document](https://shopify.github.io/liquid/tags/control-flow/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/case.js) [Test][tt]
|
||||
- [x] if [Document](https://shopify.github.io/liquid/tags/control-flow/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/if.js) [Test][tt]
|
||||
- [x] unless [Document](https://shopify.github.io/liquid/tags/control-flow/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/unless.js) [Test][tt]
|
||||
- [x] elsif [Document/else](https://shopify.github.io/liquid/tags/control-flow/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/if.js) [Test][tt]
|
||||
- [ ] for [Document](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/for.js) [Test][tt]
|
||||
- [ ] break [Document](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] continue [Document](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] for [Document: limit,offset,range,reversed)](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] cycle [Document](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] cycle [Document: group)](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] tablerow [Document](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] tablerow [Document: cols,limit,offset,range](https://shopify.github.io/liquid/tags/iteration/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [x] assign [Document](https://shopify.github.io/liquid/tags/variable/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/assign.js) [Test][tt]
|
||||
- [ ] capture [Document](https://shopify.github.io/liquid/tags/variable/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] increment [Document](https://shopify.github.io/liquid/tags/variable/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
- [ ] decrement [Document](https://shopify.github.io/liquid/tags/variable/) [Source](https://github.com/harttle/shopify-liquid/blob/master/tags/.js) [Test][tt]
|
||||
|
||||
|
||||
## Filters
|
||||
|
||||
Documentation: <https://shopify.github.io/liquid/basics/introduction/#filters>
|
||||
|
||||
- [x] [abs](https://shopify.github.io/liquid/filters/abs/)
|
||||
- [ ] [append](https://shopify.github.io/liquid/filters/append)
|
||||
- [ ] [capitalize](https://shopify.github.io/liquid/filters/capitalize)
|
||||
- [ ] [ceil](https://shopify.github.io/liquid/filters/ceil)
|
||||
- [ ] [date](https://shopify.github.io/liquid/filters/date)
|
||||
- [ ] [default](https://shopify.github.io/liquid/filters/default)
|
||||
- [ ] [divided_by](https://shopify.github.io/liquid/filters/divided_by)
|
||||
- [ ] [downcase](https://shopify.github.io/liquid/filters/downcase)
|
||||
- [ ] [escape](https://shopify.github.io/liquid/filters/escape)
|
||||
- [ ] [escape_once](https://shopify.github.io/liquid/filters/escape_once)
|
||||
- [ ] [first](https://shopify.github.io/liquid/filters/first)
|
||||
- [ ] [floor](https://shopify.github.io/liquid/filters/floor)
|
||||
- [ ] [join](https://shopify.github.io/liquid/filters/join)
|
||||
- [ ] [last](https://shopify.github.io/liquid/filters/last)
|
||||
- [ ] [lstrip](https://shopify.github.io/liquid/filters/lstrip)
|
||||
- [ ] [map](https://shopify.github.io/liquid/filters/map)
|
||||
- [ ] [minus](https://shopify.github.io/liquid/filters/minus)
|
||||
- [ ] [modulo](https://shopify.github.io/liquid/filters/modulo)
|
||||
- [ ] [newline_to_br](https://shopify.github.io/liquid/filters/newline_to_br)
|
||||
- [ ] [plus](https://shopify.github.io/liquid/filters/plus)
|
||||
- [ ] [prepend](https://shopify.github.io/liquid/filters/prepend)
|
||||
- [ ] [remove](https://shopify.github.io/liquid/filters/remove)
|
||||
- [ ] [remove_first](https://shopify.github.io/liquid/filters/remove_first)
|
||||
- [ ] [replace](https://shopify.github.io/liquid/filters/replace)
|
||||
- [ ] [replace_first](https://shopify.github.io/liquid/filters/replace_first)
|
||||
- [ ] [reverse](https://shopify.github.io/liquid/filters/reverse)
|
||||
- [ ] [round](https://shopify.github.io/liquid/filters/round)
|
||||
- [ ] [rstrip](https://shopify.github.io/liquid/filters/rstrip)
|
||||
- [ ] [size](https://shopify.github.io/liquid/filters/size)
|
||||
- [ ] [slice](https://shopify.github.io/liquid/filters/slice)
|
||||
- [ ] [sort](https://shopify.github.io/liquid/filters/sort)
|
||||
- [ ] [split](https://shopify.github.io/liquid/filters/split)
|
||||
- [ ] [strip](https://shopify.github.io/liquid/filters/strip)
|
||||
- [ ] [strip_html](https://shopify.github.io/liquid/filters/strip_html)
|
||||
- [ ] [strip_newlines](https://shopify.github.io/liquid/filters/strip_newlines)
|
||||
- [ ] [times](https://shopify.github.io/liquid/filters/times)
|
||||
- [ ] [truncate](https://shopify.github.io/liquid/filters/truncate)
|
||||
- [ ] [truncatewords](https://shopify.github.io/liquid/filters/truncatewords)
|
||||
- [ ] [uniq](https://shopify.github.io/liquid/filters/uniq)
|
||||
- [ ] [upcase](https://shopify.github.io/liquid/filters/upcase)
|
||||
- [ ] [url_encode](https://shopify.github.io/liquid/filters/url_encode)
|
||||
- [x] abs [Document](https://shopify.github.io/liquid/filters/abs/) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] append [Document](https://shopify.github.io/liquid/filters/append) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] capitalize [Document](https://shopify.github.io/liquid/filters/capitalize) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] ceil [Document](https://shopify.github.io/liquid/filters/ceil) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] date [Document](https://shopify.github.io/liquid/filters/date) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] default [Document](https://shopify.github.io/liquid/filters/default) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] divided_by [Document](https://shopify.github.io/liquid/filters/divided_by) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [x] downcase [Document](https://shopify.github.io/liquid/filters/downcase) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] escape [Document](https://shopify.github.io/liquid/filters/escape) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] escape_once [Document](https://shopify.github.io/liquid/filters/escape_once) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] first [Document](https://shopify.github.io/liquid/filters/first) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] floor [Document](https://shopify.github.io/liquid/filters/floor) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] join [Document](https://shopify.github.io/liquid/filters/join) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] last [Document](https://shopify.github.io/liquid/filters/last) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] lstrip [Document](https://shopify.github.io/liquid/filters/lstrip) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] map [Document](https://shopify.github.io/liquid/filters/map) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] minus [Document](https://shopify.github.io/liquid/filters/minus) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] modulo [Document](https://shopify.github.io/liquid/filters/modulo) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] newline_to_br [Document](https://shopify.github.io/liquid/filters/newline_to_br) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] plus [Document](https://shopify.github.io/liquid/filters/plus) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] prepend [Document](https://shopify.github.io/liquid/filters/prepend) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] remove [Document](https://shopify.github.io/liquid/filters/remove) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] remove_first [Document](https://shopify.github.io/liquid/filters/remove_first) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] replace [Document](https://shopify.github.io/liquid/filters/replace) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] replace_first [Document](https://shopify.github.io/liquid/filters/replace_first) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] reverse [Document](https://shopify.github.io/liquid/filters/reverse) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] round [Document](https://shopify.github.io/liquid/filters/round) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] rstrip [Document](https://shopify.github.io/liquid/filters/rstrip) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] size [Document](https://shopify.github.io/liquid/filters/size) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] slice [Document](https://shopify.github.io/liquid/filters/slice) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] sort [Document](https://shopify.github.io/liquid/filters/sort) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] split [Document](https://shopify.github.io/liquid/filters/split) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] strip [Document](https://shopify.github.io/liquid/filters/strip) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] strip_html [Document](https://shopify.github.io/liquid/filters/strip_html) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] strip_newlines [Document](https://shopify.github.io/liquid/filters/strip_newlines) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] times [Document](https://shopify.github.io/liquid/filters/times) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] truncate [Document](https://shopify.github.io/liquid/filters/truncate) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] truncatewords [Document](https://shopify.github.io/liquid/filters/truncatewords) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] uniq [Document](https://shopify.github.io/liquid/filters/uniq) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] upcase [Document](https://shopify.github.io/liquid/filters/upcase) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
- [ ] url_encode [Document](https://shopify.github.io/liquid/filters/url_encode) [Source](https://github.com/harttle/shopify-liquid/blob/master/filters.js) [Test][ft]
|
||||
|
||||
## Async Support
|
||||
|
||||
@@ -97,3 +102,5 @@ For template-driven projects, checkout these Liquid-like engines:
|
||||
[shopify-liquid]: https://shopify.github.io/liquid/
|
||||
[jekyll]: http://jekyllrb.com/
|
||||
[gh]: https://pages.github.com/
|
||||
[tt]: https://github.com/harttle/shopify-liquid/blob/master/test/tags.js
|
||||
[ft]: https://github.com/harttle/shopify-liquid/blob/master/test/filters.js
|
||||
|
||||
@@ -2,8 +2,8 @@ const lexical = require('./lexical.js');
|
||||
const _ = require('lodash');
|
||||
|
||||
var _filterInstance = {
|
||||
render: function(output, ctx) {
|
||||
var args = this.args.map(arg => ctx.get(arg));
|
||||
render: function(output, scope) {
|
||||
var args = this.args.map(arg => scope.get(arg));
|
||||
args.unshift(output);
|
||||
return this.filter.apply(null, args);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ module.exports = function() {
|
||||
var filters = {};
|
||||
|
||||
function construct(str) {
|
||||
var match = lexical.patterns.filterLine.exec(str.trim());
|
||||
var match = lexical.filterLine.exec(str.trim());
|
||||
if (!match) {
|
||||
throw new Error('illegal filter: ' + str);
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
const _ = require('lodash');
|
||||
const strftime = require('strftime').timezone(-(new Date()).getTimezoneOffset());
|
||||
|
||||
module.exports = function(liquid) {
|
||||
liquid.registerFilter('abs', v => Math.abs(v));
|
||||
liquid.registerFilter('append', (v, arg) => v + arg);
|
||||
liquid.registerFilter('capitalize', v => _.capitalize(v));
|
||||
liquid.registerFilter('ceil', v => Math.ceil(v));
|
||||
liquid.registerFilter('date', (v, arg) => strftime(arg, v));
|
||||
liquid.registerFilter('default', (v, arg) => arg || v);
|
||||
liquid.registerFilter('divided_by', (v, arg) => Math.floor(v/arg));
|
||||
liquid.registerFilter('downcase', v => v.toLowerCase());
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = function(liquid) {
|
||||
liquid.registerFilter('abs', v => Math.abs(v));
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
const context = require('./context');
|
||||
const scope = require('./scope');
|
||||
const tokenizer = require('./tokenizer.js');
|
||||
const Render = require('./render.js');
|
||||
const lexical = require('./lexical.js');
|
||||
@@ -25,10 +25,14 @@ function factory(){
|
||||
engine.filter = Filter();
|
||||
|
||||
var renderer = Render(engine.filter, engine.tag);
|
||||
engine.evaluate = renderer.evaluate;
|
||||
|
||||
engine.evaluate = renderer.evalExp;
|
||||
engine.evalExp = renderer.evalExp;
|
||||
engine.evalFilter = renderer.evalFilter;
|
||||
|
||||
engine.renderTokens = renderer.render;
|
||||
engine.render = function(html, ctx) {
|
||||
return engine.renderTokens(tokenizer.parse(html), context.factory(ctx));
|
||||
return engine.renderTokens(tokenizer.parse(html), scope.factory(ctx));
|
||||
},
|
||||
|
||||
fs.readdirSync(tagsPath).map(function(f){
|
||||
@@ -36,12 +40,7 @@ function factory(){
|
||||
if(!match) return;
|
||||
require("./tags/" + f)(engine);
|
||||
});
|
||||
|
||||
fs.readdirSync(filtersPath).map(function(f){
|
||||
var match = /^(\w+)\.js$/.exec(f);
|
||||
if(!match) return;
|
||||
require("./filters/" + f)(engine);
|
||||
});
|
||||
require("./filters.js")(engine);
|
||||
return engine;
|
||||
}
|
||||
|
||||
|
||||
+21
-9
@@ -15,7 +15,9 @@ var variable = new RegExp(`${identifier.source}(?:\\.${identifier.source}|${subs
|
||||
var value = new RegExp(`${literal.source}|${variable.source}`, 'i');
|
||||
var hash = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g');
|
||||
var filter = new RegExp(`(${identifier.source})(?:\\s*:\\s*(${value.source}))?`);
|
||||
var quoteBalanced = new RegExp(`(?:${singleQuoted.source}|${doubleQuoted.source}|[^'"])*`);
|
||||
|
||||
var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*(.*)\\s*$`);
|
||||
var literalLine = new RegExp(`^(?:${literal.source})$`, 'i');
|
||||
var variableLine = new RegExp(`^(?:${variable.source})$`);
|
||||
var numberLine = new RegExp(`^(?:${number.source})$`);
|
||||
@@ -24,20 +26,22 @@ var quotedLine = new RegExp(`^(?:${quoted.source})$`);
|
||||
var rangeLine = new RegExp(`^(?:${range.source})$`);
|
||||
var filterLine = new RegExp(`^(?:${filter.source})$`);
|
||||
|
||||
exports.patterns = {
|
||||
quoted, number, bool, range, literal, hash, filter, identifier, value,
|
||||
quotedLine, numberLine, boolLine, rangeLine, literalLine, filterLine
|
||||
};
|
||||
var operators = [
|
||||
/\s+or\s+/,
|
||||
/\s+and\s+/,
|
||||
/==|!=|<=|>=|<|>|\s+contains\s+/
|
||||
];
|
||||
|
||||
exports.isLiteral = function(str) {
|
||||
|
||||
function isLiteral (str) {
|
||||
return literalLine.test(str);
|
||||
};
|
||||
}
|
||||
|
||||
exports.isVariable = function(str) {
|
||||
function isVariable (str) {
|
||||
return variableLine.test(str);
|
||||
};
|
||||
}
|
||||
|
||||
exports.parseLiteral = function(str) {
|
||||
function parseLiteral (str) {
|
||||
var res;
|
||||
if (res = str.match(numberLine)) {
|
||||
return Number(str);
|
||||
@@ -51,4 +55,12 @@ exports.parseLiteral = function(str) {
|
||||
if (res = str.match(rangeLine)) {
|
||||
return _.range(res[1], res[2]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
quoted, number, bool, range, literal, hash, filter,
|
||||
identifier, value, quoteBalanced, operators,
|
||||
quotedLine, numberLine, boolLine, rangeLine, literalLine, filterLine, tagLine,
|
||||
isLiteral, isVariable, parseLiteral
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "shopify-liquid",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "A Shopify Liquid Implementation in Node.js",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const syntax = require('./syntax.js');
|
||||
|
||||
module.exports = function(Filter, Tag) {
|
||||
function render(tokens, ctx) {
|
||||
function render(tokens, scope) {
|
||||
var html = '';
|
||||
while (tokens.length) {
|
||||
var token = tokens.shift();
|
||||
@@ -8,10 +11,10 @@ module.exports = function(Filter, Tag) {
|
||||
html += token.value;
|
||||
break;
|
||||
case 'output':
|
||||
html += evaluate(token.value, ctx);
|
||||
html += evalFilter(token.value, scope);
|
||||
break;
|
||||
case 'tag':
|
||||
html += renderTag(token, tokens, ctx);
|
||||
html += renderTag(token, tokens, scope);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected type: ${token.type}`);
|
||||
@@ -20,20 +23,37 @@ module.exports = function(Filter, Tag) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function evaluate(str, ctx) {
|
||||
if(!ctx) throw new Error('ctx is needed to evaluate');
|
||||
var filters = str.split('|');
|
||||
var val = ctx.get(filters.shift());
|
||||
return filters
|
||||
.map(str => Filter.construct(str))
|
||||
.reduce((v, filter) => filter.render(v, ctx), val);
|
||||
function evalExp(exp, scope) {
|
||||
if(!scope) throw new 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 renderTag(token, tokens, ctx) {
|
||||
function evalFilter(str, scope){
|
||||
if(!scope) throw new 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.name;
|
||||
var curToken, endToken = 'end' + tag.token.name;
|
||||
while ((curToken = tokens.shift()) && curToken.value !== endToken) {
|
||||
subTokens.push(curToken);
|
||||
}
|
||||
@@ -41,10 +61,10 @@ module.exports = function(Filter, Tag) {
|
||||
throw new Error(`${token.value} not closed`);
|
||||
}
|
||||
}
|
||||
return tag.render(subTokens, ctx);
|
||||
return tag.render(subTokens, scope);
|
||||
}
|
||||
|
||||
return {
|
||||
render, evaluate, renderTag
|
||||
render, renderTag, evalFilter, evalExp
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const _ = require('lodash');
|
||||
const lexical = require('./lexical.js');
|
||||
|
||||
var context = {
|
||||
var scope = {
|
||||
get: function(str) {
|
||||
str = str && str.trim();
|
||||
if(!str) return '';
|
||||
@@ -11,27 +11,27 @@ var context = {
|
||||
return lexical.parseLiteral(str);
|
||||
}
|
||||
if (lexical.isVariable(str)) {
|
||||
for (var i = this.context.length - 1; i >= 0; i--) {
|
||||
var v = _.get(this.context[i], str);
|
||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
||||
var v = _.get(this.scopes[i], str);
|
||||
if (v !== undefined) return v;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
set: function(k, v){
|
||||
this.context[this.context.length-1][k] = v;
|
||||
this.scopes[this.scopes.length-1][k] = v;
|
||||
return this;
|
||||
},
|
||||
push: function(ctx) {
|
||||
return this.context.push(ctx);
|
||||
return this.scopes.push(ctx);
|
||||
},
|
||||
pop: function() {
|
||||
return this.context.pop();
|
||||
return this.scopes.pop();
|
||||
}
|
||||
};
|
||||
|
||||
exports.factory = function(_ctx) {
|
||||
var ctx = Object.create(context);
|
||||
ctx.context = [_ctx];
|
||||
var ctx = Object.create(scope);
|
||||
ctx.scopes = [_ctx];
|
||||
return ctx;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
var operators = {
|
||||
'==': (l, r) => l == r,
|
||||
'!=': (l, r) => l != r,
|
||||
'>': (l, r) => l > r,
|
||||
'<': (l, r) => l < r,
|
||||
'>=': (l, r) => l >= r,
|
||||
'<=': (l, r) => l <= r,
|
||||
'contains': (l, r) => l.indexOf(r) > -1,
|
||||
'and': (l, r) => l && r,
|
||||
'or': (l, r) => l || r
|
||||
};
|
||||
|
||||
exports.operators = operators;
|
||||
@@ -1,21 +1,21 @@
|
||||
const lexical = require('./lexical.js');
|
||||
|
||||
var _tagInstance = {
|
||||
render: function(tokens, ctx) {
|
||||
var obj = hash(this.markup, ctx);
|
||||
var res = this.tag.render(tokens, ctx, this.markup, obj);
|
||||
render: function(tokens, scope) {
|
||||
var obj = hash(this.token.args, scope);
|
||||
var res = this.tag.render(tokens, scope, this.token, obj);
|
||||
return res === undefined ? '' : res;
|
||||
}
|
||||
};
|
||||
|
||||
function hash(markup, ctx) {
|
||||
function hash(markup, scope) {
|
||||
var obj = {};
|
||||
lexical.patterns.hash.lastIndex = 0;
|
||||
while (match = lexical.patterns.hash.exec(markup)) {
|
||||
lexical.hash.lastIndex = 0;
|
||||
while (match = lexical.hash.exec(markup)) {
|
||||
var k = match[1],
|
||||
v = match[2];
|
||||
if (!k) continue;
|
||||
obj[k] = ctx.get(v);
|
||||
obj[k] = scope.get(v);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@@ -35,8 +35,7 @@ module.exports = function() {
|
||||
if (!tag) throw new Error(`tag ${token.name} not found`);
|
||||
|
||||
var instance = Object.create(_tagInstance);
|
||||
instance.name = token.name;
|
||||
instance.markup = token.value;
|
||||
instance.token = token;
|
||||
instance.tag = tag;
|
||||
instance.needClose = tag.needClose;
|
||||
return instance;
|
||||
|
||||
+5
-5
@@ -1,14 +1,14 @@
|
||||
var Liquid = require('..');
|
||||
var patterns = Liquid.lexical.patterns;
|
||||
var re = new RegExp(`(${patterns.identifier.source})\\s*=(.*)`);
|
||||
var lexical = Liquid.lexical;
|
||||
var re = new RegExp(`(${lexical.identifier.source})\\s*=(.*)`);
|
||||
|
||||
module.exports = function(liquid) {
|
||||
|
||||
liquid.registerTag('assign', {
|
||||
render: function(tokens, ctx, markup, hash) {
|
||||
var match = markup.match(re);
|
||||
render: function(tokens, scope, token, hash) {
|
||||
var match = token.value.match(re);
|
||||
var k = match[1], v = match[2];
|
||||
ctx.set(k, liquid.evaluate(v, ctx));
|
||||
scope.set(k, liquid.evaluate(v, scope));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+13
-13
@@ -1,34 +1,34 @@
|
||||
var Liquid = require('..');
|
||||
var patterns = Liquid.lexical.patterns;
|
||||
var caseRE = new RegExp(`^\\s*case\\s+(${patterns.value.source})`);
|
||||
var whenRE = new RegExp(`^\\s*when\\s+(${patterns.value.source})`);
|
||||
var lexical = Liquid.lexical;
|
||||
var caseRE = new RegExp(`^\\s*case\\s+(${lexical.value.source})`);
|
||||
var whenRE = new RegExp(`^\\s*when\\s+(${lexical.value.source})`);
|
||||
|
||||
module.exports = function(liquid) {
|
||||
|
||||
liquid.registerTag('case', {
|
||||
needClose: true,
|
||||
render: function(tokens, ctx, markup, hash) {
|
||||
var match = markup.match(caseRE);
|
||||
var cond = liquid.evaluate(match[1], ctx);
|
||||
render: function(tokens, scope, token, hash) {
|
||||
var match = token.value.match(caseRE);
|
||||
var cond = liquid.evaluate(match[1], scope);
|
||||
|
||||
var partialTokens = [],
|
||||
matching = false;
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
if (token.type === 'tag' && token.name === 'when') {
|
||||
var tk = tokens[i];
|
||||
if (tk.type === 'tag' && tk.name === 'when') {
|
||||
if (matching) break;
|
||||
match = token.value.match(whenRE);
|
||||
match = tk.value.match(whenRE);
|
||||
if(!match) continue;
|
||||
|
||||
var val = liquid.evaluate(match[1], ctx);
|
||||
var val = liquid.evaluate(match[1], scope);
|
||||
if (val === cond) matching = true;
|
||||
} else if (token.type === 'tag' && token.name === 'else') {
|
||||
} else if (tk.type === 'tag' && tk.name === 'else') {
|
||||
if (matching) break;
|
||||
else matching = true;
|
||||
} else if (matching) partialTokens.push(token);
|
||||
} else if (matching) partialTokens.push(tk);
|
||||
}
|
||||
|
||||
return liquid.renderTokens(partialTokens, ctx);
|
||||
return liquid.renderTokens(partialTokens, scope);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
var Liquid = require('..');
|
||||
var lexical = Liquid.lexical;
|
||||
|
||||
module.exports = function(liquid) {
|
||||
liquid.registerTag('if', {
|
||||
needClose: true,
|
||||
render: function(tokens, scope, token, hash) {
|
||||
var partialTokens = [],
|
||||
matching = liquid.evaluate(token.args, scope);
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var tk = tokens[i];
|
||||
if (tk.type === 'tag' && tk.name === 'elsif') {
|
||||
if (matching) break;
|
||||
matching = liquid.evaluate(tk.args, scope);
|
||||
} else if (tk.type === 'tag' && tk.name === 'else') {
|
||||
if (matching) break;
|
||||
else matching = true;
|
||||
} else if (matching) partialTokens.push(tk);
|
||||
}
|
||||
return liquid.renderTokens(partialTokens, scope);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
var Liquid = require('..');
|
||||
var lexical = Liquid.lexical;
|
||||
|
||||
module.exports = function(liquid) {
|
||||
liquid.registerTag('unless', {
|
||||
needClose: true,
|
||||
render: function(tokens, scope, token, hash) {
|
||||
var partialTokens = [],
|
||||
matching = !liquid.evaluate(token.args, scope);
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var tk = tokens[i];
|
||||
if (tk.type === 'tag' && tk.name === 'else') {
|
||||
if (matching) break;
|
||||
else matching = true;
|
||||
} else if (matching) partialTokens.push(tk);
|
||||
}
|
||||
return liquid.renderTokens(partialTokens, scope);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
var chai = require("chai");
|
||||
var should = chai.should();
|
||||
var expect = chai.expect;
|
||||
|
||||
var context = require('../context.js');
|
||||
|
||||
describe('context', function() {
|
||||
var ctx;
|
||||
beforeEach(function(){
|
||||
ctx = context.factory({
|
||||
foo: 'bar',
|
||||
bar: ['a', {b: [1, 2]}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse literal', function() {
|
||||
ctx.get('2.3').should.equal(2.3);
|
||||
ctx.get('(2..4)').should.deep.equal([2,3]);
|
||||
ctx.get('"foo"').should.equal("foo");
|
||||
});
|
||||
|
||||
it('should get property', function() {
|
||||
ctx.get('foo').should.equal('bar');
|
||||
});
|
||||
|
||||
it('should set property', function() {
|
||||
ctx.set('foo', 'FOO');
|
||||
ctx.get('foo').should.equal('FOO');
|
||||
});
|
||||
|
||||
it('should get desendent property', function() {
|
||||
ctx.get('bar[0]').should.equal('a');
|
||||
ctx.get('bar[1].b').should.deep.equal([1, 2]);
|
||||
ctx.get('bar[1].b[1]').should.equal(2);
|
||||
});
|
||||
|
||||
it('should push context', function() {
|
||||
ctx.push({foo: 'foo', foo1: 'foo1'});
|
||||
ctx.get('foo').should.equal('foo');
|
||||
ctx.get('foo1').should.equal('foo1');
|
||||
ctx.get('bar[1].b[1]').should.equal(2);
|
||||
});
|
||||
|
||||
it('should pop context', function() {
|
||||
ctx.push({foo: 'foo', foo1: 'foo1'});
|
||||
ctx.pop();
|
||||
expect(ctx.get('foo')).to.equal('bar');
|
||||
expect(ctx.get('foo1')).to.equal('');
|
||||
expect(ctx.get('bar[1].b[1]')).to.equal(2);
|
||||
});
|
||||
});
|
||||
+5
-5
@@ -6,13 +6,13 @@ const expect = chai.expect;
|
||||
chai.use(sinonChai);
|
||||
|
||||
var filter = require('../filter.js')();
|
||||
var context = require('../context.js');
|
||||
var Scope = require('../scope.js');
|
||||
|
||||
describe('filter', function() {
|
||||
var ctx;
|
||||
var scope;
|
||||
beforeEach(function(){
|
||||
filter.clear();
|
||||
ctx = context.factory();
|
||||
scope = Scope.factory();
|
||||
});
|
||||
it('should throw when not registered', function() {
|
||||
expect(function() {
|
||||
@@ -22,13 +22,13 @@ describe('filter', function() {
|
||||
|
||||
it('should register a simple filter', function(){
|
||||
filter.register('foo', x => x.toUpperCase());
|
||||
expect(filter.construct('foo').render('foo', ctx)).to.equal('FOO');
|
||||
expect(filter.construct('foo').render('foo', scope)).to.equal('FOO');
|
||||
});
|
||||
|
||||
it('should call filter with corrct arguments', function(){
|
||||
var spy = sinon.spy();
|
||||
filter.register('foo', spy);
|
||||
filter.construct('foo: 33').render('foo', ctx);
|
||||
filter.construct('foo: 33').render('foo', scope);
|
||||
expect(spy).to.have.been.calledWith('foo', 33);
|
||||
});
|
||||
});
|
||||
|
||||
+38
-1
@@ -5,12 +5,49 @@ var liquid = require('..')();
|
||||
|
||||
describe('filters', function() {
|
||||
var ctx = {
|
||||
date: new Date('1995-12-17T03:24:00'),
|
||||
foo: 'bar',
|
||||
arr: [-2, 'a']
|
||||
};
|
||||
|
||||
it('should support abs', function() {
|
||||
expect(liquid.render('{{ -3 | abs }}', ctx)).to.equal('3');
|
||||
expect(liquid.render('{{ -3 | abs }}')).to.equal('3');
|
||||
expect(liquid.render('{{ arr[0] | abs }}', ctx)).to.equal('2');
|
||||
});
|
||||
|
||||
it('should support append', function() {
|
||||
expect(liquid.render('{{ -3 | append: "abc" }}')).to.equal('-3abc');
|
||||
expect(liquid.render('{{ "a" | append: foo }}', ctx)).to.equal('abar');
|
||||
});
|
||||
|
||||
it('should support capitalize', function() {
|
||||
expect(liquid.render('{{ "i am good" | capitalize }}')).to.equal('I am good');
|
||||
});
|
||||
|
||||
it('should support ceil', function() {
|
||||
expect(liquid.render('{{ 1.2 | ceil }}')).to.equal('2');
|
||||
expect(liquid.render('{{ 2.0 | ceil }}')).to.equal('2');
|
||||
expect(liquid.render('{{ "3.5" | ceil }}')).to.equal('4');
|
||||
expect(liquid.render('{{ 183.357 | ceil }}')).to.equal('184');
|
||||
});
|
||||
|
||||
it('should support date', function() {
|
||||
expect(liquid.render('{{ date | date:"%Y-%m-%d %H:%M:%S"}}', ctx)).to.equal('1995-12-17 11:24:00');
|
||||
expect(liquid.render('{{ date | date:"%a, %b %d, %y"}}', ctx)).to.equal('Sun, Dec 17, 95');
|
||||
});
|
||||
|
||||
it('should support default', function() {
|
||||
expect(liquid.render('{{false |default: "a"}}')).to.equal('a');
|
||||
});
|
||||
|
||||
it('should support divided_by', function() {
|
||||
expect(liquid.render('{{4 | divided_by: 2}}')).to.equal('2');
|
||||
expect(liquid.render('{{16 | divided_by: 4}}')).to.equal('4');
|
||||
expect(liquid.render('{{5 | divided_by: 3}}')).to.equal('1');
|
||||
});
|
||||
|
||||
it('should support downcase', function() {
|
||||
expect(liquid.render('{{ "Parker Moore" | downcase }}')).to.equal('parker moore');
|
||||
expect(liquid.render('{{ "apple" | downcase }}')).to.equal('apple');
|
||||
});
|
||||
});
|
||||
|
||||
+32
-11
@@ -6,15 +6,20 @@ const expect = chai.expect;
|
||||
chai.use(sinonChai);
|
||||
|
||||
var tag = require('../tag.js')();
|
||||
var context = require('../context.js');
|
||||
var Scope = require('../scope.js');
|
||||
var filter = require('../filter')();
|
||||
var render = require('../render.js')(filter, tag).render;
|
||||
var Render = require('../render.js')(filter, tag);
|
||||
var render = Render.render;
|
||||
var evalExp = Render.evalExp;
|
||||
var evalFilter = Render.evalFilter;
|
||||
|
||||
describe('render', function() {
|
||||
var ctx, htmlToken, tagToken, filterToken;
|
||||
var scope, htmlToken, tagToken, filterToken;
|
||||
|
||||
before(function() {
|
||||
ctx = context.factory({
|
||||
scope = Scope.factory({
|
||||
one: 1,
|
||||
two: 2,
|
||||
x: 'XXX',
|
||||
foo: {
|
||||
bar: ['a', 2]
|
||||
@@ -23,7 +28,8 @@ describe('render', function() {
|
||||
tagToken = {
|
||||
type: 'tag',
|
||||
value: 'foo bar:x foo:"FOO" num:2.3',
|
||||
name: 'foo'
|
||||
name: 'foo',
|
||||
args: 'bar:x foo:"FOO" num:2.3'
|
||||
};
|
||||
htmlToken = {
|
||||
type: 'html',
|
||||
@@ -41,21 +47,21 @@ describe('render', function() {
|
||||
});
|
||||
|
||||
it('should render html', function() {
|
||||
expect(render([htmlToken], ctx)).to.equal('<p>');
|
||||
expect(render([htmlToken], scope)).to.equal('<p>');
|
||||
});
|
||||
|
||||
it('should render with tag function', function() {
|
||||
tag.register('foo', {
|
||||
render: x => 'X'
|
||||
});
|
||||
expect(render([tagToken], ctx)).to.equal('X');
|
||||
expect(render([tagToken], scope)).to.equal('X');
|
||||
});
|
||||
|
||||
it('should call tag with correct arguments', function() {
|
||||
var spy = sinon.spy();
|
||||
tag.register('foo', { render: spy });
|
||||
render([tagToken], ctx);
|
||||
expect(spy).to.have.been.calledWithMatch([], ctx, tagToken.value, {
|
||||
render([tagToken], scope);
|
||||
expect(spy).to.have.been.calledWithMatch([], scope, tagToken, {
|
||||
bar: 'XXX',
|
||||
foo: 'FOO',
|
||||
num: 2.3
|
||||
@@ -65,7 +71,7 @@ describe('render', function() {
|
||||
it('should render with filter function', function() {
|
||||
filter.register('date', (l, r) => l + r);
|
||||
filter.register('time', (l, r) => l + 3*r);
|
||||
expect(render([filterToken], ctx)).to.equal('ab6');
|
||||
expect(render([filterToken], scope)).to.equal('ab6');
|
||||
});
|
||||
|
||||
it('should call filter with correct arguments', function() {
|
||||
@@ -73,8 +79,23 @@ describe('render', function() {
|
||||
var time = sinon.spy();
|
||||
filter.register('date', date);
|
||||
filter.register('time', time);
|
||||
render([filterToken], ctx);
|
||||
render([filterToken], scope);
|
||||
expect(date).to.have.been.calledWith('a', 'b');
|
||||
expect(time).to.have.been.calledWith('y', 2);
|
||||
});
|
||||
|
||||
it('should eval expression', function(){
|
||||
expect(evalExp('1<2', scope)).to.equal(true);
|
||||
expect(evalExp('2<=2', scope)).to.equal(true);
|
||||
expect(evalExp('one<=two', scope)).to.equal(true);
|
||||
expect(function(){
|
||||
evalExp('1 contains "x"', scope);
|
||||
}).to.throw();
|
||||
expect(evalExp('x contains "x"', scope)).to.equal(false);
|
||||
expect(evalExp('x contains "X"', scope)).to.equal(true);
|
||||
expect(evalExp('x contains z', scope)).to.equal(true);
|
||||
expect(evalExp('1<2 and x contains "x"', scope)).to.equal(false);
|
||||
expect(evalExp('1<2 or x contains "x"', scope)).to.equal(true);
|
||||
expect(evalExp('"<=" == "<="', scope)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
var chai = require("chai");
|
||||
var should = chai.should();
|
||||
var expect = chai.expect;
|
||||
|
||||
var Scope = require('../scope.js');
|
||||
|
||||
describe('scope', function() {
|
||||
var scope;
|
||||
beforeEach(function(){
|
||||
scope = Scope.factory({
|
||||
foo: 'bar',
|
||||
bar: ['a', {b: [1, 2]}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse literal', function() {
|
||||
scope.get('2.3').should.equal(2.3);
|
||||
scope.get('(2..4)').should.deep.equal([2,3]);
|
||||
scope.get('"foo"').should.equal("foo");
|
||||
});
|
||||
|
||||
it('should get property', function() {
|
||||
scope.get('foo').should.equal('bar');
|
||||
});
|
||||
|
||||
it('should set property', function() {
|
||||
scope.set('foo', 'FOO');
|
||||
scope.get('foo').should.equal('FOO');
|
||||
});
|
||||
|
||||
it('should get desendent property', function() {
|
||||
scope.get('bar[0]').should.equal('a');
|
||||
scope.get('bar[1].b').should.deep.equal([1, 2]);
|
||||
scope.get('bar[1].b[1]').should.equal(2);
|
||||
});
|
||||
|
||||
it('should push scope', function() {
|
||||
scope.push({foo: 'foo', foo1: 'foo1'});
|
||||
scope.get('foo').should.equal('foo');
|
||||
scope.get('foo1').should.equal('foo1');
|
||||
scope.get('bar[1].b[1]').should.equal(2);
|
||||
});
|
||||
|
||||
it('should pop scope', function() {
|
||||
scope.push({foo: 'foo', foo1: 'foo1'});
|
||||
scope.pop();
|
||||
expect(scope.get('foo')).to.equal('bar');
|
||||
expect(scope.get('foo1')).to.equal('');
|
||||
expect(scope.get('bar[1].b[1]')).to.equal(2);
|
||||
});
|
||||
});
|
||||
+10
-9
@@ -5,12 +5,12 @@ var expect = chai.expect;
|
||||
chai.use(sinonChai);
|
||||
|
||||
var tag = require('../tag.js')();
|
||||
var context = require('../context.js');
|
||||
var Scope = require('../scope.js');
|
||||
|
||||
describe('tag', function() {
|
||||
var ctx;
|
||||
var scope;
|
||||
before(function() {
|
||||
ctx = context.factory({
|
||||
scope = Scope.factory({
|
||||
foo: 'bar',
|
||||
arr: [2, 1]
|
||||
});
|
||||
@@ -52,7 +52,7 @@ describe('tag', function() {
|
||||
type: 'tag',
|
||||
value: 'foo',
|
||||
name: 'foo'
|
||||
}).render(tokens, ctx);
|
||||
}).render(tokens, scope);
|
||||
expect(spy).to.have.been.called;
|
||||
});
|
||||
|
||||
@@ -62,13 +62,14 @@ describe('tag', function() {
|
||||
tag.register('foo', {
|
||||
render: spy
|
||||
});
|
||||
var t = tag.construct({
|
||||
var token = {
|
||||
type: 'tag',
|
||||
value: 'foo aa:foo bb: arr[0] cc: 2.3',
|
||||
name: 'foo'
|
||||
});
|
||||
t.render(tokens, ctx);
|
||||
expect(spy).to.have.been.calledWithMatch(tokens, ctx, 'foo', {
|
||||
name: 'foo',
|
||||
args: 'aa:foo bb: arr[0] cc: 2.3'
|
||||
};
|
||||
tag.construct(token).render(tokens, scope);
|
||||
expect(spy).to.have.been.calledWithMatch(tokens, scope, token, {
|
||||
aa: 'bar',
|
||||
bb: 2,
|
||||
cc: 2.3
|
||||
|
||||
@@ -4,6 +4,9 @@ const expect = chai.expect;
|
||||
var liquid = require('..')();
|
||||
|
||||
var ctx = {
|
||||
one: 1,
|
||||
two: 2,
|
||||
leq: '<=',
|
||||
empty: '',
|
||||
foo: 'bar',
|
||||
arr: [-2, 'a']
|
||||
@@ -30,5 +33,16 @@ describe('tags', function() {
|
||||
'{% when "b" %}b{% when "c"%}c{%else %}d' +
|
||||
'{%endcase%}')).to.equal('d');
|
||||
});
|
||||
|
||||
it('should support if', function(){
|
||||
expect(liquid.render('{% if 2==3 %}yes{%else%}no{%endif%}', ctx)).to.equal('no');
|
||||
expect(liquid.render('{% if 1==2 and one<two %}a{%endif%}', ctx)).to.equal('');
|
||||
expect(liquid.render('{% if false %}yes{%else%}no{%endif%}', ctx)).to.equal('no');
|
||||
});
|
||||
|
||||
it('should support unless', function(){
|
||||
expect(liquid.render('{% unless 1 %}yes{%else%}no{%endunless%}', ctx)).to.equal('no');
|
||||
expect(liquid.render('{% unless 1>2 %}yes{%endunless%}', ctx)).to.equal('yes');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+15
-6
@@ -16,19 +16,28 @@ function parse(html){
|
||||
value: htmlFragment
|
||||
});
|
||||
}
|
||||
if(result[1]){
|
||||
var match = result[1].trim().match(lexical.patterns.identifier);
|
||||
if (!match) throw new Error('illegal tag: ' + result[1]);
|
||||
var rawTag = result[1],
|
||||
cleanTag = result[2],
|
||||
rawOut = result[3],
|
||||
cleanOut = result[4];
|
||||
|
||||
if(rawTag){
|
||||
var match = cleanTag.trim().match(lexical.tagLine);
|
||||
if (!match) throw new Error('illegal tag: ' + rawTag);
|
||||
var name = match[1], args = match[2];
|
||||
|
||||
tokens.push({
|
||||
type: 'tag',
|
||||
name: match[0],
|
||||
value: result[2].trim()
|
||||
value: cleanTag.trim(),
|
||||
raw: rawTag,
|
||||
args, name
|
||||
});
|
||||
}
|
||||
else{
|
||||
tokens.push({
|
||||
type: 'output',
|
||||
value: result[4].trim()
|
||||
raw: rawOut,
|
||||
value: cleanOut.trim()
|
||||
});
|
||||
}
|
||||
idx = syntax.lastIndex;
|
||||
|
||||
Reference in New Issue
Block a user