The previous implementation of `WithParser` used regex, which struggles
with parsing nested structures correctly. This commit improves
`WithParser` to track and parse all nested `with` expressions.
Other improvements:
- Throw meaningful errors when syntax is wrong. Replacing the prior
behavior of silently ignoring such issues.
- Remove `I` prefix from related interfaces to align with newer code
conventions.
- Add more unit tests for `with` expression.
- Improve documentation for templating.
- `ExpressionRegexBuilder`:
- Use words `capture` and `match` correctly.
- Fix minor issues revealed by new and improved tests:
- Change regex for matching anything except surrounding
whitespaces. The new regex ensures that it works even without
having any preceeding text.
- Change regex for capturing pipelines. The old regex was only
matching (non-greedy) first character of the pipeline in tests,
new regex matches the full pipeline.
- `ExpressionRegexBuilder.spec.ts`:
- Ensure consistent way to define `describe` and `it` blocks.
- Replace `expectRegex` tests, regex expectations test internal
behavior of the class, not the external.
- Simplified tests by eliminating the need for UUID suffixes/prefixes.
30 lines
1.1 KiB
TypeScript
30 lines
1.1 KiB
TypeScript
import { FunctionParameter } from '@/application/Parser/Script/Compiler/Function/Parameter/FunctionParameter';
|
|
import { RegexParser, IPrimitiveExpression } from '../Parser/Regex/RegexParser';
|
|
import { ExpressionRegexBuilder } from '../Parser/Regex/ExpressionRegexBuilder';
|
|
|
|
export class ParameterSubstitutionParser extends RegexParser {
|
|
protected readonly regex = new ExpressionRegexBuilder()
|
|
.expectExpressionStart()
|
|
.expectCharacters('$')
|
|
.captureUntilWhitespaceOrPipe() // First capture: Parameter name
|
|
.expectOptionalWhitespaces()
|
|
.captureOptionalPipeline() // Second capture: Pipeline
|
|
.expectExpressionEnd()
|
|
.buildRegExp();
|
|
|
|
protected buildExpression(match: RegExpMatchArray): IPrimitiveExpression {
|
|
const parameterName = match[1];
|
|
const pipeline = match[2];
|
|
return {
|
|
parameters: [new FunctionParameter(parameterName, false)],
|
|
evaluator: (context) => {
|
|
const { argumentValue } = context.args.getArgument(parameterName);
|
|
if (!pipeline) {
|
|
return argumentValue;
|
|
}
|
|
return context.pipelineCompiler.compile(argumentValue, pipeline);
|
|
},
|
|
};
|
|
}
|
|
}
|