Added replace built-in function to mapper DSL

This commit is contained in:
euzu
2025-07-21 22:39:23 +02:00
parent 504b4df277
commit 7ef30e1aae
4 changed files with 43 additions and 11 deletions
+5
View File
@@ -1,4 +1,9 @@
# Changelog
- Hot reload for config
- Fixed shared stream provider connection count
- Added hanging client connection release
- Added `replace` built-in function for mapper scripts
# 3.1.4 (2025-06-17)
- share live stream refactored
- fixed active user count
+5
View File
@@ -1115,6 +1115,7 @@ It is whitespace-tolerant and uses familiar programming concepts with a custom s
- print(a, b, c)
- first(a)
- template(a)
- replace(text, match, replacement)
Field names are: `name`, `title"`, `caption"`, `group"`, `id"`, `chno"`, `logo"`, `logo_small"`, `parent_code"`, `time_shift" | "url"`, `epg_channel_id"`, `epg_id`.
When you use Regular expressions it could be that your match contains multiple results. The builtin function `first` returns the first match.
Example `print(uppercase("hello"))`. output is only visible in `trace` log level you can enable it like `log_level: debug,tuliprox::foundation::mapper=trace` in config
@@ -1182,6 +1183,10 @@ Example `if then else` block
}
```
Example of removing prefix
```
`@Caption = replace(@Caption, "UK:", "EN:"`
```
Example `mapping.yml`
+1 -1
View File
@@ -18,7 +18,7 @@ block_expr = { "{" ~ statements ~ "}" }
condition = { function_call | var_access | field_access }
assignment = { (field_access | identifier) ~ "=" ~ expression }
expression = { assignment | map_block | match_block | function_call | regex_expr | string_literal | number | var_access | field_access | null | block_expr }
function_name = { "concat" | "uppercase" | "lowercase" | "capitalize" | "trim" | "print" | "number" | "first" | "template" }
function_name = { "concat" | "uppercase" | "lowercase" | "capitalize" | "trim" | "print" | "number" | "first" | "template" | "replace" }
function_call = { function_name ~ "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
any_match = { "_" }
match_case_key = { any_match | identifier }
+32 -10
View File
@@ -37,7 +37,7 @@ block_expr = { "{" ~ statements ~ "}" }
condition = { function_call | var_access | field_access }
assignment = { (field_access | identifier) ~ "=" ~ expression }
expression = { assignment | map_block | match_block | function_call | regex_expr | string_literal | number | var_access | field_access | null | block_expr }
function_name = { "concat" | "uppercase" | "lowercase" | "capitalize" | "trim" | "print" | "number" | "first" | "template" }
function_name = { "concat" | "uppercase" | "lowercase" | "capitalize" | "trim" | "print" | "number" | "first" | "template" | "replace" }
function_call = { function_name ~ "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
any_match = { "_" }
match_case_key = { any_match | identifier }
@@ -107,6 +107,7 @@ enum BuiltInFunction {
ToNumber,
First,
Template,
Replace,
}
impl FromStr for BuiltInFunction {
@@ -123,6 +124,7 @@ impl FromStr for BuiltInFunction {
"number" => Ok(Self::ToNumber),
"first" => Ok(Self::First),
"template" => Ok(Self::Template),
"replace" => Ok(Self::Replace),
_ => create_tuliprox_error_result!(TuliproxErrorKind::Info, "Unknown function {}", s),
}
}
@@ -659,8 +661,13 @@ impl<'a> MapperContext<'a> {
if args.len() > 1 {
return create_tuliprox_error_result!(TuliproxErrorKind::Info, "Function accepts only one argument {:?}, {} given", name, args.len());
}
},
BuiltInFunction::Replace => {
if args.len() != 3 {
return create_tuliprox_error_result!(TuliproxErrorKind::Info, "Function accepts three arguments {:?}, {} given", name, args.len());
}
}
_ => {}
_ => {}
}
for expr_id in args {
self.validate_expr(*expr_id, identifiers)?;
@@ -887,6 +894,17 @@ fn concat_args(args: &Vec<EvalResult>) -> Vec<Cow<str>> {
result
}
macro_rules! extract_evaluated_arg_value {
($evaluated_args:expr, $index:expr) => {{
let evaluated_arg = &$evaluated_args[$index];
match evaluated_arg {
Value(value) => Some(value),
Named(values) => values.first().map(|(_key, val)| val),
_ => None,
}
}};
}
impl Expression {
#[allow(clippy::too_many_lines)]
pub fn eval(&self, ctx: &mut MapperContext, accessor: &mut ValueAccessor) -> EvalResult {
@@ -1048,14 +1066,7 @@ impl Expression {
}
}
BuiltInFunction::Template => {
let evaluated_arg = &evaluated_args[0];
let value = match evaluated_arg {
Value(value) => {
Some(value)
}
Named(values) => values.first().map(|(_key, val)| val),
_ => None
};
let value = extract_evaluated_arg_value!(evaluated_args, 0);
if let Some(val) = value {
match ctx.get_template(val) {
Some(v) => Value(v.to_string()),
@@ -1065,6 +1076,17 @@ impl Expression {
Undefined
}
}
BuiltInFunction::Replace => {
let value = extract_evaluated_arg_value!(evaluated_args, 0);
let pattern = extract_evaluated_arg_value!(evaluated_args, 1);
let substring = extract_evaluated_arg_value!(evaluated_args, 2);
if let (Some(text), Some(pat), Some(subst)) = (value, pattern, substring) {
Value(text.replace(pat, subst))
} else {
evaluated_args[0].clone()
}
}
}
}
}