From 5a4a271f980b8c5d70a2dc5ef36b8293e1c52b5d Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Tue, 26 Sep 2023 21:45:17 +0200 Subject: [PATCH 01/16] Add expression type filterCallbackFunction. --- src/twig.expression.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/twig.expression.js b/src/twig.expression.js index 80a8b4dc..ce114393 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -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, Twig.expression.type.operator.unary, Twig.expression.type.operator.binary, Twig.expression.type.array.end, @@ -479,6 +481,29 @@ 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). + * ((params) => body) + */ + type: Twig.expression.type.filterCallbackFunction, + regex: /^\(\(([\w\s]+(?:,\s?[\w\s]+)*)\)\s*=>\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.'); + } + + filter.params = token; + token.params = token.match[1]; + token.body = '{{ ' + token.match[2] + ' }}'; + output.push(filter); + }, + parse(token, stack) { + stack.push(token); + } + }, { /** * Match a parameter set start. @@ -756,6 +781,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, Twig.expression.type.parameter.start ]), compile(token, stack, output) { From d108a8185c649d7aec0da7fec2ef2f685ec379c0 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Tue, 26 Sep 2023 23:47:17 +0200 Subject: [PATCH 02/16] Support for spaceship operator. --- docs/wiki | 2 +- src/twig.expression.js | 4 ++-- src/twig.expression.operator.js | 9 +++++++++ test/test.expressions.js | 7 +++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/wiki b/docs/wiki index 169dc5a2..cd1010ec 160000 --- a/docs/wiki +++ b/docs/wiki @@ -1 +1 @@ -Subproject commit 169dc5a2a542849afd8c057405a13bfdd4b191c3 +Subproject commit cd1010ec51d0f8dd3ad5a473a168e94852bfae96 diff --git a/src/twig.expression.js b/src/twig.expression.js index ce114393..e9fd1634 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -214,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 // 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)|^\.\.)/, next: Twig.expression.set.expressions, transform(match, tokens) { switch (match[0]) { diff --git a/src/twig.expression.operator.js b/src/twig.expression.operator.js index 452add4e..027382e1 100644 --- a/src/twig.expression.operator.js +++ b/src/twig.expression.operator.js @@ -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; + 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; + case '<': stack.push(a < b); break; diff --git a/test/test.expressions.js b/test/test.expressions.js index fb414283..6620479a 100644 --- a/test/test.expressions.js +++ b/test/test.expressions.js @@ -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()); + }); + }); it('should support less then', function () { const testTemplate = twig({data: '{{ a < b }}'}); numericTestData.forEach(pair => { From a23266a4dbbfa2dbb7a40d1ef677ac67339724b6 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 00:00:53 +0200 Subject: [PATCH 03/16] Add support for arrow functions to sort filter. --- src/twig.filters.js | 19 +++++++++++++++++-- test/test.filters.js | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/twig.filters.js b/src/twig.filters.js index 18b3fd89..591a5ca6 100644 --- a/src/twig.filters.js +++ b/src/twig.filters.js @@ -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)) { diff --git a/test/test.filters.js b/test/test.filters.js index a0323ab0..3f33b2e5 100644 --- a/test/test.filters.js +++ b/test/test.filters.js @@ -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%}'}); From f7c4666afabe73c92c6c0f721a4d9442a7fcc02a Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 00:55:59 +0200 Subject: [PATCH 04/16] Make parenthesis for parameters optional. --- src/twig.expression.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index e9fd1634..cc274a7f 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -487,7 +487,7 @@ module.exports = function (Twig) { * ((params) => body) */ type: Twig.expression.type.filterCallbackFunction, - regex: /^\(\(([\w\s]+(?:,\s?[\w\s]+)*)\)\s*=>\s*[{}]*(.*)[}]*\)/, + regex: /^\(\(*([\w\s]+(?:,\s?[\w\s]+)*)\)*\s*=>\s*[{}]*(.*)[}]*\)/, next: Twig.expression.set.expressions.concat([Twig.expression.type.subexpression.end]), compile(token, stack, output) { const filter = output.pop(); @@ -496,7 +496,7 @@ module.exports = function (Twig) { } filter.params = token; - token.params = token.match[1]; + token.params = token.match[1].trim(); token.body = '{{ ' + token.match[2] + ' }}'; output.push(filter); }, From 5915fe9ad5fea3c65c487073396ecabe5b1fdbc4 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 00:56:55 +0200 Subject: [PATCH 05/16] Add support for arrow functions to filter filter. --- src/twig.filters.js | 11 +++++++++++ test/test.filters.js | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/twig.filters.js b/src/twig.filters.js index 591a5ca6..b6f18f0a 100644 --- a/src/twig.filters.js +++ b/src/twig.filters.js @@ -835,6 +835,17 @@ module.exports = function (Twig) { }, spaceless(value) { return value.replace(/>\s+<').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'; + }); + } } }; diff --git a/test/test.filters.js b/test/test.filters.js index 3f33b2e5..1583982c 100644 --- a/test/test.filters.js +++ b/test/test.filters.js @@ -859,6 +859,18 @@ 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'); + }); + }); + it('should chain', function () { const testTemplate = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}'}); testTemplate.render().should.equal('2,1,0'); From 93a1b6be728e4b5c1d2ec46188f4006e9213a21b Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 09:53:25 +0200 Subject: [PATCH 06/16] Add support for arrow functions to map filter. --- src/twig.filters.js | 19 +++++++++++++++++++ test/test.filters.js | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/src/twig.filters.js b/src/twig.filters.js index b6f18f0a..f2a2a258 100644 --- a/src/twig.filters.js +++ b/src/twig.filters.js @@ -846,6 +846,25 @@ module.exports = function (Twig) { 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]] = _b; + if (callBackParams[1]) { + data[callBackParams[1]] = _a; + } + + const template = Twig.exports.twig({data: params.body}); + newValue[_a] = template.render(data); + }); + return newValue; + } } }; diff --git a/test/test.filters.js b/test/test.filters.js index 1583982c..680fda42 100644 --- a/test/test.filters.js +++ b/test/test.filters.js @@ -871,6 +871,13 @@ describe('Twig.js Filters ->', function () { }); }); + describe('map ->', function () { + it('should map an array (with keys)', function () { + let testTemplate = twig({data: '{{ [1,5,2,7,8]|map((v) => v*v) }}'}); + testTemplate.render().should.equal('1,25,4,49,64'); + }); + }); + it('should chain', function () { const testTemplate = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}'}); testTemplate.render().should.equal('2,1,0'); From bdcd4cee60a18943aba605b1028d42a664aa5dc6 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 12:41:55 +0200 Subject: [PATCH 07/16] Trim object member names. --- src/twig.filters.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/twig.filters.js b/src/twig.filters.js index f2a2a258..4fee1026 100644 --- a/src/twig.filters.js +++ b/src/twig.filters.js @@ -855,9 +855,9 @@ module.exports = function (Twig) { const newValue = []; value.forEach((_b, _a) => { const data = {}; - data[callBackParams[0]] = _b; + data[callBackParams[0].trim()] = _b; if (callBackParams[1]) { - data[callBackParams[1]] = _a; + data[callBackParams[1].trim()] = _a; } const template = Twig.exports.twig({data: params.body}); From 5a7d299126fa1dc17dde9f21232ead9b503ae795 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 12:43:08 +0200 Subject: [PATCH 08/16] Also supply a test with keys for map filter. --- test/test.filters.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test.filters.js b/test/test.filters.js index 680fda42..a4c8c0bb 100644 --- a/test/test.filters.js +++ b/test/test.filters.js @@ -873,6 +873,11 @@ describe('Twig.js Filters ->', function () { 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'); }); From 1f81225cb6b922dc8a121a89e5b96125c30742da Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 12:43:47 +0200 Subject: [PATCH 09/16] Extend filterCallbackFunction expression with extra (optional) arguments. --- src/twig.expression.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index cc274a7f..551ad483 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -487,7 +487,7 @@ module.exports = function (Twig) { * ((params) => body) */ type: Twig.expression.type.filterCallbackFunction, - regex: /^\(\(*([\w\s]+(?:,\s?[\w\s]+)*)\)*\s*=>\s*[{}]*(.*)[}]*\)/, + 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(); @@ -495,9 +495,11 @@ module.exports = function (Twig) { throw new Twig.Error('Expected filter before filterCallbackFunction.'); } - filter.params = token; 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) { From ee22d770367dfd76bf4813df99d6cff32b8284f4 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 27 Sep 2023 12:44:03 +0200 Subject: [PATCH 10/16] Add support for arrow functions to reduce filter. --- src/twig.filters.js | 14 ++++++++++++++ test/test.filters.js | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/twig.filters.js b/src/twig.filters.js index 4fee1026..f1b744ee 100644 --- a/src/twig.filters.js +++ b/src/twig.filters.js @@ -865,6 +865,20 @@ module.exports = function (Twig) { }); 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); + } } }; diff --git a/test/test.filters.js b/test/test.filters.js index a4c8c0bb..35960215 100644 --- a/test/test.filters.js +++ b/test/test.filters.js @@ -883,6 +883,18 @@ describe('Twig.js Filters ->', function () { }); }); + 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'); + }); + }); + it('should chain', function () { const testTemplate = twig({data: '{{ ["a", "b", "c"]|keys|reverse }}'}); testTemplate.render().should.equal('2,1,0'); From 88e21a6e8a9cf0725986f7c1034ebf6501d4df0c Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:39:38 +0200 Subject: [PATCH 11/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index 551ad483..4b00951b 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -35,7 +35,7 @@ module.exports = function (Twig) { unary: 'Twig.expression.type.operator.unary', binary: 'Twig.expression.type.operator.binary' }, - filterCallbackFunction: 'Twig.expression.type.filterCallbackFunction', + arrowFunction: 'Twig.expression.type.arrowFunction', string: 'Twig.expression.type.string', bool: 'Twig.expression.type.bool', slice: 'Twig.expression.type.slice', From ae3e172e7c6f9636cc8649cfe2dbdbf540abfc0a Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:39:46 +0200 Subject: [PATCH 12/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index 4b00951b..18838d37 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -72,7 +72,7 @@ module.exports = function (Twig) { // What can follow an expression (in general) operations: [ Twig.expression.type.filter, - Twig.expression.type.filterCallbackFunction, + Twig.expression.type.arrowFunction, Twig.expression.type.operator.unary, Twig.expression.type.operator.binary, Twig.expression.type.array.end, From 1a6b3c1823d184277010a6e7ce87f64816a2ca4c Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:40:00 +0200 Subject: [PATCH 13/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index 18838d37..f2893749 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -486,7 +486,7 @@ module.exports = function (Twig) { * Match a filter callback function (after a filter). * ((params) => body) */ - type: Twig.expression.type.filterCallbackFunction, + type: Twig.expression.type.arrowFunction, 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) { From d91d7c80622304af21dfc2a322139a04c2bde804 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:40:07 +0200 Subject: [PATCH 14/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index f2893749..b93d5ed2 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -483,7 +483,7 @@ module.exports = function (Twig) { }, { /** - * Match a filter callback function (after a filter). + * Match an arrow function after a filter. * ((params) => body) */ type: Twig.expression.type.arrowFunction, From ff4455854335c30741b7a05c47c1124bdb347ad5 Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:40:14 +0200 Subject: [PATCH 15/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index b93d5ed2..f21ca882 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -492,7 +492,7 @@ module.exports = function (Twig) { compile(token, stack, output) { const filter = output.pop(); if (filter.type !== Twig.expression.type.filter) { - throw new Twig.Error('Expected filter before filterCallbackFunction.'); + throw new Twig.Error('Expected filter before arrow function.'); } token.params = token.match[1].trim(); From 5c905a45c49226d7e10f57dfcb9b9d4369a3a5ca Mon Sep 17 00:00:00 2001 From: Antoine Veldhoven Date: Wed, 11 Oct 2023 21:40:21 +0200 Subject: [PATCH 16/16] Update twig.expression.js Co-authored-by: Will Rowe --- src/twig.expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/twig.expression.js b/src/twig.expression.js index f21ca882..9dee5784 100644 --- a/src/twig.expression.js +++ b/src/twig.expression.js @@ -783,7 +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, + Twig.expression.type.arrowFunction, Twig.expression.type.parameter.start ]), compile(token, stack, output) {