Skip to content

Commit ab8791b

Browse files
authoredNov 16, 2023
Merge pull request #881 from antoineveldhoven/slice-filter-variables
Support variables in slice filter shorthand
2 parents f08598b + 251e52b commit ab8791b

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed
 

‎src/twig.expression.js

+33-5
Original file line numberDiff line numberDiff line change
@@ -576,14 +576,14 @@ module.exports = function (Twig) {
576576
},
577577
{
578578
type: Twig.expression.type.slice,
579-
regex: /^\[(\d*:\d*)\]/,
579+
regex: /^\[(-?\w*:-?\w*)\]/,
580580
next: Twig.expression.set.operationsExtended,
581581
compile(token, stack, output) {
582582
const sliceRange = token.match[1].split(':');
583583

584584
// SliceStart can be undefined when we pass parameters to the slice filter later
585-
const sliceStart = (sliceRange[0]) ? parseInt(sliceRange[0], 10) : undefined;
586-
const sliceEnd = (sliceRange[1]) ? parseInt(sliceRange[1], 10) : undefined;
585+
const sliceStart = sliceRange[0];
586+
const sliceEnd = sliceRange[1];
587587

588588
token.value = 'slice';
589589
token.params = [sliceStart, sliceEnd];
@@ -596,11 +596,39 @@ module.exports = function (Twig) {
596596

597597
output.push(token);
598598
},
599-
parse(token, stack) {
599+
parse(token, stack, context) {
600600
const input = stack.pop();
601-
const {params} = token;
601+
let {params} = token;
602602
const state = this;
603603

604+
if (parseInt(params[0], 10).toString() === params[0]) {
605+
params[0] = parseInt(params[0], 10);
606+
} else {
607+
const value = context[params[0]];
608+
if (state.template.options.strictVariables && value === undefined) {
609+
throw new Twig.Error('Variable "' + params[0] + '" does not exist.');
610+
}
611+
612+
params[0] = value;
613+
}
614+
615+
if (params[1]) {
616+
if (parseInt(params[1], 10).toString() === params[1]) {
617+
params[1] = parseInt(params[1], 10);
618+
} else {
619+
const value = context[params[1]];
620+
if (state.template.options.strictVariables && value === undefined) {
621+
throw new Twig.Error('Variable "' + params[1] + '" does not exist.');
622+
}
623+
624+
if (value === undefined) {
625+
params = [params[0]];
626+
} else {
627+
params[1] = value;
628+
}
629+
}
630+
}
631+
604632
stack.push(Twig.filter.call(state, token.value, input, params));
605633
}
606634
},

‎src/twig.filters.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -644,9 +644,13 @@ module.exports = function (Twig) {
644644
// Default to start of string
645645
const start = params[0] || 0;
646646
// Default to length of string
647-
const length = params.length > 1 ? params[1] : value.length;
647+
let length = params.length > 1 ? params[1] : value.length;
648648
// Handle negative start values
649649
const startIndex = start >= 0 ? start : Math.max(value.length + start, 0);
650+
// Handle negative length values
651+
if (length < 0) {
652+
length = value.length - startIndex + length;
653+
}
650654

651655
if (Twig.lib.is('Array', value)) {
652656
const output = [];

‎test/test.expressions.js

+30
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,36 @@ describe('Twig.js Expressions ->', function () {
467467
output.should.equal('23');
468468
});
469469

470+
it('should support slice shorthand (full form) with negative start', function () {
471+
const testTemplate = twig({data: '{{ "12345"[-2:1] }}'});
472+
const output = testTemplate.render();
473+
output.should.equal('4');
474+
});
475+
476+
it('should support slice shorthand (full form) with negative lenght', function () {
477+
const testTemplate = twig({data: '{{ "12345"[2:-1] }}'});
478+
const output = testTemplate.render();
479+
output.should.equal('34');
480+
});
481+
482+
it('should support slice shorthand (full form) with variables as arguments', function () {
483+
const testTemplate = twig({data: '{{ "12345"[start:length] }}'});
484+
const output = testTemplate.render({start: 2, length: 3});
485+
output.should.equal('345');
486+
});
487+
488+
it('should support slice shorthand (full form) with variable as argument (omit first)', function () {
489+
const testTemplate = twig({data: '{{ "12345"[:length] }}'});
490+
const output = testTemplate.render({length: 3});
491+
output.should.equal('123');
492+
});
493+
494+
it('should support slice shorthand (full form) variable as argument (omit last)', function () {
495+
const testTemplate = twig({data: '{{ "12345"[start:] }}'});
496+
const output = testTemplate.render({start: 2});
497+
output.should.equal('345');
498+
});
499+
470500
it('should support slice shorthand (omit first)', function () {
471501
const testTemplate = twig({data: '{{ "12345"[:2] }}'});
472502
const output = testTemplate.render();

‎test/test.filters.js

+4
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,10 @@ describe('Twig.js Filters ->', function () {
640640
const testTemplate = twig({data: '{{ \'12345\'|slice(1, 2) }}'});
641641
testTemplate.render().should.equal('23');
642642
});
643+
it('should slice a string with variables as arguments', function () {
644+
const testTemplate = twig({data: '{{ \'12345\'|slice(start, length) }}'});
645+
testTemplate.render({start: 2, length: 3}).should.equal('345');
646+
});
643647
it('should slice a string to the end', function () {
644648
const testTemplate = twig({data: '{{ \'12345\'|slice(2) }}'});
645649
testTemplate.render().should.equal('345');

0 commit comments

Comments
 (0)
Please sign in to comment.