diff --git a/common/jinja/runtime.cpp b/common/jinja/runtime.cpp index 2232790c31..5b51427aa0 100644 --- a/common/jinja/runtime.cpp +++ b/common/jinja/runtime.cpp @@ -306,6 +306,19 @@ value filter_expression::execute_impl(context & ctx) { filter_id = "strip"; // alias } JJ_DEBUG("Applying filter '%s' to %s", filter_id.c_str(), input->type().c_str()); + // TODO: Refactor filters so this coercion can be done automatically + if (!input->is_undefined() && !is_val(input) && ( + filter_id == "capitalize" || + filter_id == "lower" || + filter_id == "replace" || + filter_id == "strip" || + filter_id == "title" || + filter_id == "upper" || + filter_id == "wordcount" + )) { + JJ_DEBUG("Coercing %s to String for '%s' filter", input->type().c_str(), filter_id.c_str()); + input = mk_val(input->as_string()); + } return try_builtin_func(ctx, filter_id, input)->invoke(func_args(ctx)); } else if (is_stmt(filter)) { diff --git a/common/jinja/value.cpp b/common/jinja/value.cpp index 749113124b..7dc1d65407 100644 --- a/common/jinja/value.cpp +++ b/common/jinja/value.cpp @@ -465,8 +465,9 @@ const func_builtins & value_int_t::get_builtins() const { double val = static_cast(args.get_pos(0)->as_int()); return mk_val(val); }}, - {"tojson", tojson}, + {"safe", tojson}, {"string", tojson}, + {"tojson", tojson}, }; return builtins; } @@ -485,8 +486,9 @@ const func_builtins & value_float_t::get_builtins() const { int64_t val = static_cast(args.get_pos(0)->as_float()); return mk_val(val); }}, - {"tojson", tojson}, + {"safe", tojson}, {"string", tojson}, + {"tojson", tojson}, }; return builtins; } @@ -771,6 +773,11 @@ const func_builtins & value_string_t::get_builtins() const { const func_builtins & value_bool_t::get_builtins() const { + static const func_handler tostring = [](const func_args & args) -> value { + args.ensure_vals(); + bool val = args.get_pos(0)->as_bool(); + return mk_val(val ? "True" : "False"); + }; static const func_builtins builtins = { {"default", default_value}, {"int", [](const func_args & args) -> value { @@ -783,11 +790,8 @@ const func_builtins & value_bool_t::get_builtins() const { bool val = args.get_pos(0)->as_bool(); return mk_val(val ? 1.0 : 0.0); }}, - {"string", [](const func_args & args) -> value { - args.ensure_vals(); - bool val = args.get_pos(0)->as_bool(); - return mk_val(val ? "True" : "False"); - }}, + {"safe", tostring}, + {"string", tostring}, {"tojson", tojson}, }; return builtins; @@ -1100,18 +1104,14 @@ const func_builtins & value_object_t::get_builtins() const { } const func_builtins & value_none_t::get_builtins() const { + static const func_handler tostring = [](const func_args &) -> value { + return mk_val("None"); + }; static const func_builtins builtins = { {"default", default_value}, {"tojson", tojson}, - {"string", [](const func_args &) -> value { - return mk_val("None"); - }}, - {"safe", [](const func_args &) -> value { - return mk_val("None"); - }}, - {"strip", [](const func_args &) -> value { - return mk_val("None"); - }}, + {"string", tostring}, + {"safe", tostring}, {"items", empty_value_fn}, {"map", empty_value_fn}, {"reject", empty_value_fn}, diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 5d4b2806ac..ce3008f4c7 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -523,6 +523,18 @@ static void test_filters(testing & t) { "hello" ); + test_template(t, "upper array", + "{{ items|upper }}", + {{"items", json::array({"hello", "world"})}}, + "['HELLO', 'WORLD']" + ); + + test_template(t, "upper dict", + "{{ items|upper }}", + {{"items", {{"hello", "world"}}}}, + "{'HELLO': 'WORLD'}" + ); + test_template(t, "capitalize", "{{ 'heLlo World'|capitalize }}", json::object(),