diff --git a/src/lexical.js b/src/lexical.js index a80b51a3c..8ef832f5f 100644 --- a/src/lexical.js +++ b/src/lexical.js @@ -4,13 +4,14 @@ var doubleQuoted = /"[^"]*"/; var quoted = new RegExp(`${singleQuoted.source}|${doubleQuoted.source}`); var quoteBalanced = new RegExp(`(?:${quoted.source}|[^'"])*`); -// values +// basic types var integer = /-?\d+/; var number = /-?\d+\.?\d*|\.?\d+/; var bool = /true|false/; + +// peoperty access var identifier = /[\w-]+/; var subscript = new RegExp(`\\[(?:${quoted.source}|[\\w-\\.]+)\\]`); - var literal = new RegExp(`(?:${quoted.source}|${bool.source}|${number.source})`); var variable = new RegExp(`${identifier.source}(?:\\.${identifier.source}|${subscript.source})*`); @@ -19,12 +20,13 @@ var rangeLimit = new RegExp(`(?:${variable.source}|${number.source})`); var range = new RegExp(`\\(${rangeLimit.source}\\.\\.${rangeLimit.source}\\)`); var rangeCapture = new RegExp(`\\((${rangeLimit.source})\\.\\.(${rangeLimit.source})\\)`); -var value = new RegExp(`(?:${literal.source}|${variable.source}|${range.source})`); +var value = new RegExp(`(?:${variable.source}|${literal.source}|${range.source})`); // hash related var hash = new RegExp(`(?:${identifier.source})\\s*:\\s*(?:${value.source})`); var hashCapture = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g'); +// full match var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*(.*)\\s*$`); var literalLine = new RegExp(`^${literal.source}$`, 'i'); var variableLine = new RegExp(`^${variable.source}$`); @@ -57,6 +59,10 @@ function isVariable(str) { return variableLine.test(str); } +function matchValue(str) { + return value.exec(str); +} + function parseLiteral(str) { var res; if (res = str.match(numberLine)) { @@ -76,5 +82,5 @@ module.exports = { range, rangeCapture, identifier, value, quoteBalanced, operators, quotedLine, numberLine, boolLine, rangeLine, literalLine, filterLine, tagLine, - isLiteral, isVariable, parseLiteral, isRange + isLiteral, isVariable, parseLiteral, isRange, matchValue }; diff --git a/src/parser.js b/src/parser.js index 938812c46..0b991477f 100644 --- a/src/parser.js +++ b/src/parser.js @@ -70,7 +70,7 @@ module.exports = function(Tag, Filter) { } function parseOutput(str) { - var match = lexical.value.exec(str); + var match = lexical.matchValue(str); if(!match) throw new Error(`illegal output string: ${str}`); var initial = match[0]; diff --git a/src/render.js b/src/render.js index 72af250ee..e0ec1cce4 100644 --- a/src/render.js +++ b/src/render.js @@ -14,7 +14,7 @@ var render = { // It's fundamentally equivalent to the following... // emptyPromise.then(renderTag(template0).then(renderTag(template1).then(renderTag(template2)... var lastPromise = templates.reduce((promise, template) => { - return promise.then((partial) => { + return promise.then(() => { if (scope.safeGet('forloop.skip')) { return Promise.resolve(''); } diff --git a/tags/assign.js b/tags/assign.js index a3ca7fd28..d0d67ebb6 100644 --- a/tags/assign.js +++ b/tags/assign.js @@ -12,7 +12,7 @@ module.exports = function(liquid) { this.key = match[1]; this.value = match[2]; }, - render: function(scope, hash) { + render: function(scope) { scope.set(this.key, liquid.evalOutput(this.value, scope)); return Promise.resolve(''); } diff --git a/test/lexical.js b/test/lexical.js index d7352b755..8dc40dda9 100644 --- a/test/lexical.js +++ b/test/lexical.js @@ -1,11 +1,10 @@ -var chai = require("chai"); -var should = chai.should(); -var expect = chai.expect; +const chai = require("chai"); +const expect = chai.expect; var lexical = require('../src/lexical.js'); describe('lexical', function() { - it('should test filter syntax', function(){ + it('should test filter syntax', function() { lexical.filterLine.test('abs').should.equal(true); lexical.filterLine.test('plus:1').should.equal(true); lexical.filterLine.test('replace: "a", b').should.equal(true); @@ -40,24 +39,36 @@ describe('lexical', function() { }); describe('.isVariable()', function() { - it('should return true for foo', function(){ + it('should return true for foo', function() { lexical.isVariable("foo").should.equal(true); }); - it('should return true for.bar.foo', function(){ + it('should return true for.bar.foo', function() { lexical.isVariable("foo.bar.foo").should.equal(true); }); - it('should return true for foo[0].b', function(){ + it('should return true for foo[0].b', function() { lexical.isVariable("foo[0].b").should.equal(true); }); - it('should return true for 0a', function(){ + it('should return true for 0a', function() { lexical.isVariable("0a").should.equal(true); }); - it('should return true for foo[a.b]', function(){ + it('should return true for foo[a.b]', function() { lexical.isVariable("foo[a.b]").should.equal(true); }); - it('should return true for foo[a.b]', function(){ + it('should return true for foo[a.b]', function() { lexical.isVariable("foo['a[0]']").should.equal(true); }); + it('should return true for "var-1"', function() { + lexical.isVariable("var-1").should.equal(true); + }); + it('should return true for "-var"', function() { + lexical.isVariable("-var").should.equal(true); + }); + it('should return true for "var-"', function() { + lexical.isVariable("var-").should.equal(true); + }); + it('should return true for "3-4"', function() { + lexical.isVariable("3-4").should.equal(true); + }); }); it('should test none literal', function() { @@ -90,4 +101,22 @@ describe('lexical', function() { lexical.parseLiteral('"ab\'c"').should.equal("ab\'c"); }); + describe('.matchValue()', function(){ + it('should match -5-5', function() { + var match = lexical.matchValue('-5-5'); + expect(match && match[0]).to.equal('-5-5'); + }); + it('should match 4-3', function() { + var match = lexical.matchValue('4-3'); + expect(match && match[0]).to.equal('4-3'); + }); + it('should match 4-3', function() { + var match = lexical.matchValue('4-3'); + expect(match && match[0]).to.equal('4-3'); + }); + it('should match var-1', function() { + var match = lexical.matchValue('var-1'); + expect(match && match[0]).to.equal('var-1'); + }); + }); }); diff --git a/test/tags/assign.js b/test/tags/assign.js index d38b1a3e0..9b9f3431d 100644 --- a/test/tags/assign.js +++ b/test/tags/assign.js @@ -5,19 +5,43 @@ chai.use(require("chai-as-promised")); describe('tags/assign', function() { var liquid = Liquid(); - it('should support assign 1', function() { + it('should assign as string', function() { var src = '{% assign foo="bar" %}{{foo}}'; return expect(liquid.parseAndRender(src)) .to.eventually.equal('bar'); }); - it('should support assign 2', function() { + it('should assign as array', function() { var src = '{% assign foo=(1..3) %}{{foo}}'; return expect(liquid.parseAndRender(src)) .to.eventually.equal('[1,2,3]'); }); - it('should support assign 3', function() { + it('should assign as filter result', function() { var src = '{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}'; return expect(liquid.parseAndRender(src)) .to.eventually.equal('A'); }); + it('should assign var-1', function() { + var src = '{% assign var-1 = 5 %}{{ var-1 }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('5'); + }); + it('should assign var-', function() { + var src = '{% assign var- = 5 %}{{ var- }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('5'); + }); + it('should assign -var', function() { + var src = '{% assign -var = 5 %}{{ -var }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('5'); + }); + it('should assign -5-5', function() { + var src = '{% assign -5-5 = 5 %}{{ -5-5 }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('5'); + }); + it('should assign 4-3', function() { + var src = '{% assign 4-3 = 5 %}{{ 4-3 }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('5'); + }); + it('should not assign -6', function() { + var src = '{% assign -6 = 5 %}{{ -6 }}'; + return expect(liquid.parseAndRender(src)).to.eventually.equal('-6'); + }); });