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