diff --git a/index.js b/index.js index ee9c06f48..b9094eddf 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const Render = require('./src/render.js'); const lexical = require('./src/lexical.js'); const Tag = require('./src/tag.js'); const Filter = require('./src/filter.js'); -const Template = require('./src/parser'); +const Parser = require('./src/parser'); const Syntax = require('./src/syntax.js'); const tags = require('./tags'); const filters = require('./filters'); @@ -25,7 +25,7 @@ var _engine = { this.options = options; this.tag = tag; this.filter = filter; - this.parser = Template(tag, filter); + this.parser = Parser(tag, filter); this.renderer = Render(); tags(this); @@ -127,7 +127,7 @@ function factory(options) { var engine = Object.create(_engine); - engine.init(Tag(), Filter(), options); + engine.init(Tag(), Filter(options), options); return engine; } diff --git a/package.json b/package.json index aae1dc8ee..df6a9077c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shopify-liquid", - "version": "1.3.3", + "version": "1.4.0", "description": "Liquid template engine for JavaScript, Node.js and Browser", "main": "index.js", "scripts": { diff --git a/src/filter.js b/src/filter.js index 0c03e5660..c86f930c8 100644 --- a/src/filter.js +++ b/src/filter.js @@ -1,10 +1,12 @@ const lexical = require('./lexical.js'); const Syntax = require('./syntax.js'); const assert = require('./util/assert.js'); +const _ = require('./util/underscore.js'); var valueRE = new RegExp(`${lexical.value.source}`, 'g'); -module.exports = function() { +module.exports = function(options) { + options = _.assign({}, options); var filters = {}; var _filterInstance = { @@ -19,10 +21,17 @@ module.exports = function() { var name = match[1], argList = match[2] || '', filter = filters[name]; if (typeof filter !== 'function'){ - return { - name: name, - error: new TypeError(`undefined filter: ${name}`) - }; + if(options.strict_filters){ + throw new TypeError(`undefined filter: ${name}`); + } + this.name= name; + this.filter= x => x; + this.args= []; + return this; + //return { + //name: name, + //error: new TypeError(`undefined filter: ${name}`) + //}; } var args = []; diff --git a/src/render.js b/src/render.js index 27cedd889..9c3e1e65b 100644 --- a/src/render.js +++ b/src/render.js @@ -15,15 +15,15 @@ var render = { return renderTemplate.call(this, tpl) .then(partial => html += partial) .catch(e => { - if(e instanceof RenderBreakError){ - e.resolvedHTML = html; + if (e instanceof RenderBreakError) { + e.resolvedHTML = html; throw e; } throw new RenderError(e, tpl); }); }).then(() => html); - function renderTemplate(template){ + function renderTemplate(template) { if (template.type === 'tag') { return this.renderTag(template, scope) .then(partial => partial === undefined ? '' : partial); @@ -49,19 +49,9 @@ var render = { evalOutput: function(template, scope) { assert(scope, 'unable to evalOutput: scope undefined'); - var val = Syntax.evalExp(template.initial, scope); - template.filters.some(filter => { - if (filter.error) { - if (scope.get('liquid.strict_filters')) { - throw filter.error; - } else { - val = ''; - return true; - } - } - val = filter.render(val, scope); - }); - return val; + return template.filters.reduce( + (prev, filter) => filter.render(prev, scope), + Syntax.evalExp(template.initial, scope)); } }; diff --git a/test/filter.js b/test/filter.js index 130b071b1..cf490a1d5 100644 --- a/test/filter.js +++ b/test/filter.js @@ -14,10 +14,9 @@ describe('filter', function() { filter.clear(); scope = Scope.factory(); }); - it('should return undefined when not registered', function() { + it('should return default filter when not registered', function() { var result = filter.construct('foo'); expect(result.name).to.equal('foo'); - expect(result.error).to.be.an('Error'); }); it('should throw when filter name illegal', function() { diff --git a/test/liquid.js b/test/liquid.js index eec3f9bbf..b46573f36 100644 --- a/test/liquid.js +++ b/test/liquid.js @@ -5,7 +5,7 @@ const mock = require('mock-fs'); chai.use(require("chai-as-promised")); describe('liquid', function() { - var engine, ctx; + var engine, strictEngine, ctx; beforeEach(function() { ctx = { name: 'harttle', @@ -18,6 +18,11 @@ describe('liquid', function() { root: '/root/', extname: '.html' }); + strictEngine = Liquid({ + root: '/root', + extname: '.html', + strict_filters: true + }); mock({ '/root/files/foo.html': 'foo', '/root/files/name.html': 'My name is {{name}}.', @@ -40,13 +45,10 @@ describe('liquid', function() { return engine.parseAndRender('foo{{zzz}}bar', ctx).should.eventually.equal('foobar'); }); it('should render as null when filter undefined', function() { - return engine.parseAndRender('{{arr | filter1}}', ctx).should.eventually.equal(''); + return engine.parseAndRender('{{"foo" | filter1}}', ctx).should.eventually.equal('foo'); }); it('should throw upon undefined filter when strict_filters set', function() { - var opts = { - strict_filters: true - }; - return expect(engine.parseAndRender('{{arr | filter1}}', ctx, opts)).to + return expect(strictEngine.parseAndRender('{{arr | filter1}}', ctx)).to .be.rejectedWith(/undefined filter: filter1/); }); }); diff --git a/test/util/error.js b/test/util/error.js index 2ba04d28a..31b368374 100644 --- a/test/util/error.js +++ b/test/util/error.js @@ -130,14 +130,6 @@ describe('error', function() { expect(e.message).to.contain('undefined variable: a'); }); }); - it('should throw RenderError when filter not defined', function() { - return expect(strictEngine.parseAndRender('{{1 | a}}')).to.eventually - .be.rejected - .then(function(e) { - expect(e).to.have.property('name', 'RenderError'); - expect(e.message).to.contain('undefined filter: a'); - }); - }); it('should contain template content in err.message', function() { var html = ['1st', '2nd', '3rd', 'X{%throwingTag%} Y', '5th', '6th', '7th']; var message = [ @@ -207,6 +199,14 @@ describe('error', function() { } }); }); + it('should throw RenderError when filter not defined', function() { + return expect(strictEngine.parseAndRender('{{1 | a}}')).to.eventually + .be.rejected + .then(function(e) { + expect(e).to.have.property('name', 'ParseError'); + expect(e.message).to.contain('undefined filter: a'); + }); + }); it('should throw ParseError when tag not closed', function() { return expect(engine.parseAndRender('{% if %}')).to.eventually .be.rejected