mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 12:20:40 -07:00
liquid instance
This commit is contained in:
@@ -1,46 +1,48 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const _ = require('lodash');
|
||||
|
||||
var filters = {};
|
||||
|
||||
var _filterInstance = {
|
||||
render: function(output, ctx) {
|
||||
var args = this.args.map(arg => ctx.get(arg));
|
||||
args.unshift(output);
|
||||
return this.filter.apply(null, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function parse(str) {
|
||||
var match = lexical.patterns.filterLine.exec(str.trim());
|
||||
if (!match) {
|
||||
throw new Error('illegal filter: ' + str);
|
||||
module.exports = function() {
|
||||
var filters = {};
|
||||
|
||||
function parse(str) {
|
||||
var match = lexical.patterns.filterLine.exec(str.trim());
|
||||
if (!match) {
|
||||
throw new Error('illegal filter: ' + str);
|
||||
}
|
||||
var k = match[1],
|
||||
v = match[2];
|
||||
|
||||
return factory(k, [v]);
|
||||
}
|
||||
var k = match[1],
|
||||
v = match[2];
|
||||
|
||||
return factory(k, [v]);
|
||||
}
|
||||
function factory(name, args) {
|
||||
var filter = filters[name];
|
||||
if (typeof filter !== 'function')
|
||||
throw new Error(`filter ${name} not found`);
|
||||
|
||||
function factory(name, args) {
|
||||
var filter = filters[name];
|
||||
if (typeof filter !== 'function')
|
||||
throw new Error(`filter ${name} not found`);
|
||||
var instance = Object.create(_filterInstance);
|
||||
instance.args = args;
|
||||
instance.filter = filter;
|
||||
return instance;
|
||||
}
|
||||
|
||||
var instance = Object.create(_filterInstance);
|
||||
instance.args = args;
|
||||
instance.filter = filter;
|
||||
return instance;
|
||||
}
|
||||
function register(name, filter) {
|
||||
filters[name] = filter;
|
||||
}
|
||||
|
||||
function register(name, filter) {
|
||||
filters[name] = filter;
|
||||
}
|
||||
function clear() {
|
||||
filters = {};
|
||||
}
|
||||
|
||||
function clear() {
|
||||
filters = {};
|
||||
}
|
||||
|
||||
exports.parse = parse;
|
||||
exports.register = register;
|
||||
exports.clear = clear;
|
||||
return {
|
||||
parse, register, clear
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = v => Math.abs(v);
|
||||
@@ -2,9 +2,45 @@ const context = require('./context');
|
||||
const tokenizer = require('./tokenizer.js');
|
||||
const render = require('./render.js');
|
||||
const lexical = require('./lexical.js');
|
||||
const path = require("path");
|
||||
const fs = require('fs');
|
||||
const Tag = require('./tag.js');
|
||||
const Filter = require('./filter.js');
|
||||
|
||||
exports.render = function(html, ctx){
|
||||
return render(tokenizer(html), context.factory(ctx));
|
||||
const tagsPath = path.join(__dirname, "tags");
|
||||
const filtersPath = path.join(__dirname, "filters");
|
||||
|
||||
var _engine = {
|
||||
render: function(html, ctx) {
|
||||
return this.doRender(tokenizer.parse(html), context.factory(ctx));
|
||||
},
|
||||
lexical,
|
||||
registerFilter : function(name, filter){
|
||||
return this.filter.register(name, filter);
|
||||
},
|
||||
registerTag : function(name, tag){
|
||||
return this.filter.register(name, tag);
|
||||
}
|
||||
};
|
||||
|
||||
exports.lexical = lexical;
|
||||
function factory(){
|
||||
var engine = Object.create(_engine);
|
||||
engine.tag = Tag();
|
||||
engine.filter = Filter();
|
||||
engine.doRender = render(engine.filter, engine.tag);
|
||||
|
||||
fs.readdirSync(tagsPath).map(function(f){
|
||||
var match = /^(\w+)\.js$/.exec(f);
|
||||
if(!match) return;
|
||||
engine.tag.register(match[1], require("./tags/" + f));
|
||||
});
|
||||
|
||||
fs.readdirSync(filtersPath).map(function(f){
|
||||
var match = /^(\w+)\.js$/.exec(f);
|
||||
if(!match) return;
|
||||
engine.filter.register(match[1], require("./filters/" + f));
|
||||
});
|
||||
return engine;
|
||||
}
|
||||
|
||||
module.exports = factory;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ const _ = require('lodash');
|
||||
var singleQuoted = /'[^']*'/;
|
||||
var doubleQuoted = /"[^"]*"/;
|
||||
|
||||
var number = /\d+\.?\d*|\.?\d+/;
|
||||
var number = /-?\d+\.?\d*|\.?\d+/;
|
||||
var bool = /true|false/i;
|
||||
var range = /\((\d+)\.\.(\d+)\)/;
|
||||
var identifier = /[a-zA-Z_$][a-zA-Z_$0-9]*/;
|
||||
|
||||
@@ -1,46 +1,44 @@
|
||||
const Filter = require('./filter');
|
||||
const Tag = require('./tag');
|
||||
|
||||
module.exports = function render(tokens, ctx) {
|
||||
var html = '';
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens.shift();
|
||||
switch (token.type) {
|
||||
case 'html':
|
||||
html += token.value;
|
||||
break;
|
||||
case 'output':
|
||||
html += renderOutput(token);
|
||||
break;
|
||||
case 'tag':
|
||||
html += renderTag(token);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected type: ${token.type}`);
|
||||
}
|
||||
}
|
||||
return html;
|
||||
|
||||
function renderOutput(token) {
|
||||
var filters = token.value.split('|');
|
||||
var val = ctx.get(filters.shift());
|
||||
return filters
|
||||
.map(str => Filter.parse(str))
|
||||
.reduce((v, filter) => filter.render(v, ctx), val);
|
||||
}
|
||||
|
||||
function renderTag(token) {
|
||||
var tag = Tag.parse(token.value), subTokens = [];
|
||||
if(tag.needClose){
|
||||
var curToken, endToken = 'end' + tag.name;
|
||||
while((curToken = tokens.shift()).value !== endToken){
|
||||
subTokens.push(curToken);
|
||||
}
|
||||
if(curToken.value !== endToken){
|
||||
throw new Error(`${token.value} not closed`);
|
||||
module.exports = (Filter, Tag) =>
|
||||
function render(tokens, ctx) {
|
||||
var html = '';
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens.shift();
|
||||
switch (token.type) {
|
||||
case 'html':
|
||||
html += token.value;
|
||||
break;
|
||||
case 'output':
|
||||
html += renderOutput(token);
|
||||
break;
|
||||
case 'tag':
|
||||
html += renderTag(token);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected type: ${token.type}`);
|
||||
}
|
||||
}
|
||||
return tag.render(subTokens, ctx);
|
||||
}
|
||||
};
|
||||
return html;
|
||||
|
||||
function renderOutput(token) {
|
||||
var filters = token.value.split('|');
|
||||
var val = ctx.get(filters.shift());
|
||||
return filters
|
||||
.map(str => Filter.parse(str))
|
||||
.reduce((v, filter) => filter.render(v, ctx), val);
|
||||
}
|
||||
|
||||
function renderTag(token) {
|
||||
var tag = Tag.parse(token.value),
|
||||
subTokens = [];
|
||||
if (tag.needClose) {
|
||||
var curToken, endToken = 'end' + tag.name;
|
||||
while ((curToken = tokens.shift()).value !== endToken) {
|
||||
subTokens.push(curToken);
|
||||
}
|
||||
if (curToken.value !== endToken) {
|
||||
throw new Error(`${token.value} not closed`);
|
||||
}
|
||||
}
|
||||
return tag.render(subTokens, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,57 +1,58 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const context = require('./context.js');
|
||||
|
||||
var tags = {};
|
||||
|
||||
var _tagInstance = {
|
||||
render: function(tokens, ctx){
|
||||
render: function(tokens, ctx) {
|
||||
var obj = hash(this.markup, ctx);
|
||||
return this.tag.render(tokens, ctx, this.markup, obj);
|
||||
}
|
||||
};
|
||||
|
||||
function register(name, tag){
|
||||
if(typeof tag.render !== 'function'){
|
||||
throw new Error(`expect ${name}.render to be a function`);
|
||||
}
|
||||
tags[name] = tag;
|
||||
}
|
||||
|
||||
function parse(str){
|
||||
var match = lexical.patterns.identifier.exec(str.trim());
|
||||
if(!match) throw new Error('illegal tag: '+ str);
|
||||
|
||||
var tagInstance = factory(match[0], str);
|
||||
return tagInstance;
|
||||
}
|
||||
|
||||
function hash(markup, ctx){
|
||||
function hash(markup, ctx) {
|
||||
var obj = {};
|
||||
lexical.patterns.hash.lastIndex = 0;
|
||||
while(match = lexical.patterns.hash.exec(markup)){
|
||||
var k = match[1], v = match[2];
|
||||
if(!k) continue;
|
||||
while (match = lexical.patterns.hash.exec(markup)) {
|
||||
var k = match[1],
|
||||
v = match[2];
|
||||
if (!k) continue;
|
||||
obj[k] = ctx.get(v);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function factory(name, markup){
|
||||
var tag = tags[name];
|
||||
if(!tag) throw new Error(`tag ${name} not found`);
|
||||
|
||||
var instance = Object.create(_tagInstance);
|
||||
instance.name = name;
|
||||
instance.markup = markup;
|
||||
instance.tag = tag;
|
||||
return instance;
|
||||
}
|
||||
module.exports = function() {
|
||||
var tags = {};
|
||||
|
||||
function clear(){
|
||||
tags = {};
|
||||
}
|
||||
function register(name, tag) {
|
||||
if (typeof tag.render !== 'function') {
|
||||
throw new Error(`expect ${name}.render to be a function`);
|
||||
}
|
||||
tags[name] = tag;
|
||||
}
|
||||
|
||||
exports.parse = parse;
|
||||
exports.register = register;
|
||||
exports.hash = hash;
|
||||
exports.clear = clear;
|
||||
function parse(str) {
|
||||
var match = lexical.patterns.identifier.exec(str.trim());
|
||||
if (!match) throw new Error('illegal tag: ' + str);
|
||||
|
||||
var tagInstance = factory(match[0], str);
|
||||
return tagInstance;
|
||||
}
|
||||
|
||||
function factory(name, markup) {
|
||||
var tag = tags[name];
|
||||
if (!tag) throw new Error(`tag ${name} not found`);
|
||||
|
||||
var instance = Object.create(_tagInstance);
|
||||
instance.name = name;
|
||||
instance.markup = markup;
|
||||
instance.tag = tag;
|
||||
return instance;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
tags = {};
|
||||
}
|
||||
|
||||
return {
|
||||
parse, register, hash, clear
|
||||
};
|
||||
};
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ const expect = chai.expect;
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
var filter = require('../filter.js');
|
||||
var filter = require('../filter.js')();
|
||||
var context = require('../context.js');
|
||||
|
||||
describe('filter', function() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const chai = require("chai");
|
||||
const expect = chai.expect;
|
||||
|
||||
var liquid = require('..')();
|
||||
|
||||
describe('filters', function() {
|
||||
var ctx = {
|
||||
foo: 'bar',
|
||||
arr: [-2, 'a']
|
||||
};
|
||||
|
||||
it('should support abs', function() {
|
||||
expect(liquid.render('{{ -3 | abs }}', ctx)).to.equal('3');
|
||||
expect(liquid.render('{{ arr[0] | abs }}', ctx)).to.equal('2');
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -14,7 +14,7 @@ describe('identifier', function() {
|
||||
it('should test number literal', function() {
|
||||
identifier.isLiteral('2.3').should.equal(true);
|
||||
identifier.isLiteral('.3').should.equal(true);
|
||||
identifier.isLiteral('3.').should.equal(true);
|
||||
identifier.isLiteral('-3.').should.equal(true);
|
||||
identifier.isLiteral('23').should.equal(true);
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('identifier', function() {
|
||||
it('should parse number literal', function() {
|
||||
identifier.parseLiteral('2.3').should.equal(2.3);
|
||||
identifier.parseLiteral('.32').should.equal(0.32);
|
||||
identifier.parseLiteral('23.').should.equal(23);
|
||||
identifier.parseLiteral('-23.').should.equal(-23);
|
||||
identifier.parseLiteral('23').should.equal(23);
|
||||
});
|
||||
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@ const expect = chai.expect;
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
var tag = require('../tag.js');
|
||||
var tag = require('../tag.js')();
|
||||
var context = require('../context.js');
|
||||
var filter = require('../filter');
|
||||
var render = require('../render.js');
|
||||
var filter = require('../filter')();
|
||||
var render = require('../render.js')(filter, tag);
|
||||
|
||||
describe('render', function() {
|
||||
var ctx, htmlToken, tagToken, filterToken;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ var sinon = require("sinon");
|
||||
var expect = chai.expect;
|
||||
chai.use(sinonChai);
|
||||
|
||||
var tag = require('../tag.js');
|
||||
var tag = require('../tag.js')();
|
||||
var context = require('../context.js');
|
||||
|
||||
describe('tag', function() {
|
||||
|
||||
Reference in New Issue
Block a user