Add support for pipes in templates #53
The goal is to be able to modify values of variables used in templates. It enables future functionality such as escaping, inlining etc. It adds support applying predefined pipes to variables. Pipes can be applied to variable substitution in with and parameter substitution expressions. They work in similar way to piping in Unix where each pipe applied to the compiled result of pipe before. It adds support for using pipes in `with` and parameter substitution expressions. It also refactors how their regex is build to reuse more of the logic by abstracting regex building into a new class. Finally, it separates and extends documentation for templating.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { ExpressionRegexBuilder } from '@/application/Parser/Script/Compiler/Expressions/Parser/Regex/ExpressionRegexBuilder';
|
||||
|
||||
describe('ExpressionRegexBuilder', () => {
|
||||
describe('expectCharacters', () => {
|
||||
describe('escape single as expected', () => {
|
||||
const charactersToEscape = [ '.', '$' ];
|
||||
for (const character of charactersToEscape) {
|
||||
it(character, () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectCharacters(character),
|
||||
// assert
|
||||
`\\${character}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
it('escapes multiple as expected', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectCharacters('.I have no $$.'),
|
||||
// assert
|
||||
'\\.I have no \\$\\\$\\.');
|
||||
});
|
||||
it('adds as expected', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectCharacters('return as it is'),
|
||||
// assert
|
||||
'return as it is');
|
||||
});
|
||||
});
|
||||
it('expectOneOrMoreWhitespaces', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectOneOrMoreWhitespaces(),
|
||||
// assert
|
||||
'\\s+');
|
||||
});
|
||||
it('matchPipeline', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.matchPipeline(),
|
||||
// assert
|
||||
'\\s*(\\|\\s*.+?)?');
|
||||
});
|
||||
it('matchUntilFirstWhitespace', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.matchUntilFirstWhitespace(),
|
||||
// assert
|
||||
'([^|\\s]+)');
|
||||
});
|
||||
it('matchAnythingExceptSurroundingWhitespaces', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.matchAnythingExceptSurroundingWhitespaces(),
|
||||
// assert
|
||||
'\\s*(.+?)\\s*');
|
||||
});
|
||||
it('expectExpressionStart', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectExpressionStart(),
|
||||
// assert
|
||||
'{{\\s*');
|
||||
});
|
||||
it('expectExpressionEnd', () => {
|
||||
runRegExTest(
|
||||
// act
|
||||
(act) => act.expectExpressionEnd(),
|
||||
// assert
|
||||
'\\s*}}');
|
||||
});
|
||||
describe('buildRegExp', () => {
|
||||
it('sets global flag', () => {
|
||||
// arrange
|
||||
const expected = 'g';
|
||||
const sut = new ExpressionRegexBuilder()
|
||||
.expectOneOrMoreWhitespaces();
|
||||
// act
|
||||
const actual = sut.buildRegExp().flags;
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
describe('can combine multiple parts', () => {
|
||||
it('with', () => {
|
||||
runRegExTest((sut) => sut
|
||||
// act
|
||||
.expectExpressionStart().expectCharacters('with').expectOneOrMoreWhitespaces().expectCharacters('$')
|
||||
.matchUntilFirstWhitespace()
|
||||
.expectExpressionEnd()
|
||||
.matchAnythingExceptSurroundingWhitespaces()
|
||||
.expectExpressionStart().expectCharacters('end').expectExpressionEnd(),
|
||||
// assert
|
||||
'{{\\s*with\\s+\\$([^|\\s]+)\\s*}}\\s*(.+?)\\s*{{\\s*end\\s*}}',
|
||||
);
|
||||
});
|
||||
it('scoped substitution', () => {
|
||||
runRegExTest((sut) => sut
|
||||
// act
|
||||
.expectExpressionStart().expectCharacters('.')
|
||||
.matchPipeline()
|
||||
.expectExpressionEnd(),
|
||||
// assert
|
||||
'{{\\s*\\.\\s*(\\|\\s*.+?)?\\s*}}',
|
||||
);
|
||||
});
|
||||
it('parameter substitution', () => {
|
||||
runRegExTest((sut) => sut
|
||||
// act
|
||||
.expectExpressionStart().expectCharacters('$')
|
||||
.matchUntilFirstWhitespace()
|
||||
.matchPipeline()
|
||||
.expectExpressionEnd(),
|
||||
// assert
|
||||
'{{\\s*\\$([^|\\s]+)\\s*(\\|\\s*.+?)?\\s*}}',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function runRegExTest(
|
||||
act: (sut: ExpressionRegexBuilder) => ExpressionRegexBuilder,
|
||||
expected: string,
|
||||
) {
|
||||
// arrange
|
||||
const sut = new ExpressionRegexBuilder();
|
||||
// act
|
||||
const actual = act(sut).buildRegExp().source;
|
||||
// assert
|
||||
expect(actual).to.equal(expected);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { ExpressionEvaluator } from '@/application/Parser/Script/Compiler/Expressions/Expression/Expression';
|
||||
import { IPrimitiveExpression, RegexParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/RegexParser';
|
||||
import { IPrimitiveExpression, RegexParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/Regex/RegexParser';
|
||||
import { ExpressionPosition } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPosition';
|
||||
import { FunctionParameterStub } from '@tests/unit/stubs/FunctionParameterStub';
|
||||
|
||||
Reference in New Issue
Block a user