-
Notifications
You must be signed in to change notification settings - Fork 275
Add support for arrow functions #871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
5a4a271
d108a81
a23266a
f7c4666
5915fe9
93a1b6b
bdcd4ce
5a7d299
1f81225
ee22d77
88e21a6
ae3e172
1a6b3c1
d91d7c8
ff44558
5c905a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ module.exports = function (Twig) { | |
| unary: 'Twig.expression.type.operator.unary', | ||
| binary: 'Twig.expression.type.operator.binary' | ||
| }, | ||
| filterCallbackFunction: 'Twig.expression.type.filterCallbackFunction', | ||
| string: 'Twig.expression.type.string', | ||
| bool: 'Twig.expression.type.bool', | ||
| slice: 'Twig.expression.type.slice', | ||
|
|
@@ -71,6 +72,7 @@ module.exports = function (Twig) { | |
| // What can follow an expression (in general) | ||
| operations: [ | ||
| Twig.expression.type.filter, | ||
| Twig.expression.type.filterCallbackFunction, | ||
antoineveldhoven marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Twig.expression.type.operator.unary, | ||
| Twig.expression.type.operator.binary, | ||
| Twig.expression.type.array.end, | ||
|
|
@@ -212,9 +214,9 @@ module.exports = function (Twig) { | |
| }, | ||
| { | ||
| type: Twig.expression.type.operator.binary, | ||
| // Match any of ??, ?:, +, *, /, -, %, ~, <, <=, >, >=, !=, ==, **, ?, :, and, b-and, or, b-or, b-xor, in, not in | ||
| // Match any of ??, ?:, +, *, /, -, %, ~, <=>, <, <=, >, >=, !=, ==, **, ?, :, and, b-and, or, b-or, b-xor, in, not in | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this change and submit as separate PR. |
||
| // and, or, in, not in, matches, starts with, ends with can be followed by a space or parenthesis | ||
| regex: /(^\?\?|^\?:|^(b-and)|^(b-or)|^(b-xor)|^[+\-~%?]|^[:](?!\d\])|^[!=]==?|^[!<>]=?|^\*\*?|^\/\/?|^(and)[(|\s+]|^(or)[(|\s+]|^(in)[(|\s+]|^(not in)[(|\s+]|^(matches)|^(starts with)|^(ends with)|^\.\.)/, | ||
| regex: /(^\?\?|^\?:|^(b-and)|^(b-or)|^(b-xor)|^[+\-~%?]|^(<=>)|^[:](?!\d\])|^[!=]==?|^[!<>]=?|^\*\*?|^\/\/?|^(and)[(|\s+]|^(or)[(|\s+]|^(in)[(|\s+]|^(not in)[(|\s+]|^(matches)|^(starts with)|^(ends with)|^\.\.)/, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this change and submit as separate PR. |
||
| next: Twig.expression.set.expressions, | ||
| transform(match, tokens) { | ||
| switch (match[0]) { | ||
|
|
@@ -479,6 +481,31 @@ module.exports = function (Twig) { | |
| throw new Twig.Error('Unexpected subexpression end when token is not marked as an expression'); | ||
| } | ||
| }, | ||
| { | ||
| /** | ||
| * Match a filter callback function (after a filter). | ||
antoineveldhoven marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * ((params) => body) | ||
| */ | ||
| type: Twig.expression.type.filterCallbackFunction, | ||
antoineveldhoven marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| regex: /^\(\(*\s*([a-zA-Z_]\w*\s*(?:\s?,\s?[a-zA-Z_]\w*\s*)*)\)*\s*=>\s*([^,]*),*\s*(\w*(?:,\s?\w*)*)\s*\)/, | ||
| next: Twig.expression.set.expressions.concat([Twig.expression.type.subexpression.end]), | ||
| compile(token, stack, output) { | ||
| const filter = output.pop(); | ||
| if (filter.type !== Twig.expression.type.filter) { | ||
| throw new Twig.Error('Expected filter before filterCallbackFunction.'); | ||
antoineveldhoven marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| token.params = token.match[1].trim(); | ||
| token.body = '{{ ' + token.match[2] + ' }}'; | ||
| token.args = token.match[3].trim(); | ||
| filter.params = token; | ||
|
|
||
| output.push(filter); | ||
| }, | ||
| parse(token, stack) { | ||
| stack.push(token); | ||
| } | ||
| }, | ||
| { | ||
| /** | ||
| * Match a parameter set start. | ||
|
|
@@ -756,6 +783,7 @@ module.exports = function (Twig) { | |
| // Match a | then a letter or _, then any number of letters, numbers, _ or - | ||
| regex: /^\|\s?([a-zA-Z_][a-zA-Z0-9_-]*)/, | ||
| next: Twig.expression.set.operationsExtended.concat([ | ||
| Twig.expression.type.filterCallbackFunction, | ||
antoineveldhoven marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Twig.expression.type.parameter.start | ||
| ]), | ||
| compile(token, stack, output) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,6 +93,11 @@ module.exports = function (Twig) { | |
| token.associativity = Twig.expression.operator.leftToRight; | ||
| break; | ||
|
|
||
| case '<=>': | ||
| token.precidence = 9; | ||
| token.associativity = Twig.expression.operator.leftToRight; | ||
| break; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this change and submit as separate PR. |
||
| case '<': | ||
| case '<=': | ||
| case '>': | ||
|
|
@@ -275,6 +280,10 @@ module.exports = function (Twig) { | |
| stack.push(!Twig.lib.boolval(b)); | ||
| break; | ||
|
|
||
| case '<=>': | ||
| stack.push(a === b ? 0 : (a < b ? -1 : 1)); | ||
| break; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this change and submit as separate PR. |
||
| case '<': | ||
| stack.push(a < b); | ||
| break; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,9 +72,24 @@ module.exports = function (Twig) { | |
| return value; | ||
| } | ||
| }, | ||
| sort(value) { | ||
| sort(value, params) { | ||
| if (is('Array', value)) { | ||
| return value.sort(); | ||
| let ret; | ||
| if (params) { | ||
| const callBackParams = params.params.split(','); | ||
| ret = value.sort((_a, _b) => { | ||
| const data = {}; | ||
| data[callBackParams[0]] = _a; | ||
| data[callBackParams[1]] = _b; | ||
|
|
||
| const template = Twig.exports.twig({data: params.body}); | ||
| return template.render(data); | ||
| }); | ||
| } else { | ||
| ret = value.sort(); | ||
| } | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| if (is('Object', value)) { | ||
|
|
@@ -820,6 +835,50 @@ module.exports = function (Twig) { | |
| }, | ||
| spaceless(value) { | ||
| return value.replace(/>\s+</g, '><').trim(); | ||
| }, | ||
| filter(value, params) { | ||
| if (is('Array', value)) { | ||
| return value.filter(_a => { | ||
| const data = {}; | ||
| data[params.params] = _a; | ||
|
|
||
| const template = Twig.exports.twig({data: params.body}); | ||
| return template.render(data) === 'true'; | ||
| }); | ||
| } | ||
| }, | ||
| map(value, params) { | ||
| if (is('Array', value)) { | ||
| const callBackParams = params.params.split(','); | ||
| // Since Javascript does not support a callBack function to map() with both keys and values; we use forEach here | ||
| // Note: Twig and PHP use ((value[, key])) for map(); whereas Javascript uses (([key, ]value)) for forEach() | ||
| const newValue = []; | ||
| value.forEach((_b, _a) => { | ||
| const data = {}; | ||
| data[callBackParams[0].trim()] = _b; | ||
| if (callBackParams[1]) { | ||
| data[callBackParams[1].trim()] = _a; | ||
| } | ||
|
|
||
| const template = Twig.exports.twig({data: params.body}); | ||
| newValue[_a] = template.render(data); | ||
| }); | ||
| return newValue; | ||
| } | ||
| }, | ||
| reduce(value, params) { | ||
| if (is('Array', value)) { | ||
| const callBackParams = params.params.split(','); | ||
| return value.reduce((_carry, _v, _k) => { | ||
| const data = {}; | ||
| data[callBackParams[0]] = _carry; | ||
| data[callBackParams[1].trim()] = _v; | ||
| data[callBackParams[2].trim()] = _k; | ||
|
|
||
| const template = Twig.exports.twig({data: params.body}); | ||
| return template.render(data); | ||
| }, params.args || 0); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove these changes and submit as a separate PR after this is one merged. |
||
| } | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,6 +173,13 @@ describe('Twig.js Expressions ->', function () { | |
| {a: false, b: true}, | ||
| {a: false, b: false} | ||
| ]; | ||
| it('should support spaceship operator', function () { | ||
| const testTemplate = twig({data: '{{ a <=> b }}'}); | ||
| numericTestData.forEach(pair => { | ||
| const output = testTemplate.render(pair); | ||
| output.should.equal((pair.a === pair.b ? 0 : (pair.a < pair.b ? -1 : 1)).toString()); | ||
| }); | ||
| }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this change and submit as separate PR. |
||
| it('should support less then', function () { | ||
| const testTemplate = twig({data: '{{ a < b }}'}); | ||
| numericTestData.forEach(pair => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -151,6 +151,10 @@ describe('Twig.js Filters ->', function () { | |
| testTemplate = twig({data: '{% set obj = {\'z\':\'abc\',\'a\':2,\'y\':7,\'m\':\'test\'} %}{% for key,value in obj|sort %}{{key}}:{{value}} {%endfor %}'}); | ||
| testTemplate.render().should.equal('a:2 y:7 z:abc m:test '); | ||
| }); | ||
| it('should sort an array of objects with a callback function', function () { | ||
| let testTemplate = twig({data: '{% for item in items|sort((left,right) => left.num - right.num) %}{{ item|json_encode }}{% endfor %}'}); | ||
| testTemplate.render({items:[{id: 1,num: 6},{id: 2, num: 3},{id: 3, num: 4}]}).should.equal('{"id":2,"num":3}{"id":3,"num":4}{"id":1,"num":6}'); | ||
| }); | ||
|
|
||
| it('should handle undefined', function () { | ||
| const testTemplate = twig({data: '{% set obj = undef|sort %}{% for key, value in obj|sort %}{{key}}:{{value}}{%endfor%}'}); | ||
|
|
@@ -855,6 +859,42 @@ describe('Twig.js Filters ->', function () { | |
| }); | ||
| }); | ||
|
|
||
| describe('filter ->', function () { | ||
| it('should filter an array (with perenthesis)', function () { | ||
| let testTemplate = twig({data: '{{ [1,5,2,7,8]|filter((f) => f % 2 == 0) }}'}); | ||
| testTemplate.render().should.equal('2,8'); | ||
| }); | ||
|
|
||
| it('should filter an array (without perenthesis)', function () { | ||
| let testTemplate = twig({data: '{{ [1,5,2,7,8]|filter(f => f % 2 == 0) }}'}); | ||
| testTemplate.render().should.equal('2,8'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('map ->', function () { | ||
| it('should map an array (with keys)', function () { | ||
| let testTemplate = twig({data: '{{ [1,5,2,7,8]|map((v, k) => v*v+k) }}'}); | ||
| testTemplate.render().should.equal('1,26,6,52,68'); | ||
| }); | ||
|
|
||
| it('should map an array', function () { | ||
| let testTemplate = twig({data: '{{ [1,5,2,7,8]|map((v) => v*v) }}'}); | ||
| testTemplate.render().should.equal('1,25,4,49,64'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('reduce ->', function () { | ||
| it('should reduce an array (with inital value)', function () { | ||
| let testTemplate = twig({data: '{{ [1,2,3]|reduce((carry, v, k) => carry + v * k) }}'}); | ||
| testTemplate.render().should.equal('8'); | ||
| }); | ||
|
|
||
| it('should reduce an array)', function () { | ||
| let testTemplate = twig({data: '{{ [1,2,3]|reduce((carry, v, k) => carry + v * k, 10) }}'}); | ||
| testTemplate.render().should.equal('18'); | ||
| }); | ||
| }); | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove these changes and submit as a separate PR after this is one merged. |
||
| it('should chain', function () { | ||
| const testTemplate = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}'}); | ||
| testTemplate.render().should.equal('2,1,0'); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.