jinja : add support for dict builtin (#29477)

* add support for dict builtin

* add tests
This commit is contained in:
Sigbjørn Skjæret
2026-09-27 13:41:50 +02:00
committed by GitHub
parent c9064dded7
commit 33c923db1b
2 changed files with 63 additions and 12 deletions
+39 -12
View File
@@ -348,6 +348,43 @@ static value default_value(const func_args & args) {
return no_value ? args.get_pos(1) : args.get_pos(0);
}
static value toobject(const func_args & args) {
auto out = mk_val<value_object>();
value iter = args.get_pos(0, mk_val<value_undefined>());
bool iter_first = false;
if (is_val<value_array>(iter)) {
iter_first = true;
for (const auto & it : iter->as_array()) {
if (is_val<value_array>(it) && it->as_array().size() == 2) {
auto tuple = it->as_array();
auto key = tuple[0];
auto val = tuple[1];
JJ_DEBUG("namespace/dict: adding key '%s'", key->as_string().str().c_str());
out->insert(key, val);
} else {
throw raised_exception("namespace/dict() iterable argument must consist of tuples, not " + it->type());
}
}
} else if (is_val<value_object>(iter)) {
iter_first = true;
for (const auto & pair : iter->as_ordered_object()) {
JJ_DEBUG("namespace/dict: adding key '%s'", pair.first->as_string().str().c_str());
out->insert(pair.first, pair.second);
}
}
for (const auto & arg : args.get_args()) {
if (is_val<value_kwarg>(arg)) {
auto kwarg = cast_val<value_kwarg>(arg);
JJ_DEBUG("namespace/dict: adding key '%s'", kwarg->key.c_str());
out->insert(kwarg->key, kwarg->val);
} else if (!iter_first) {
throw raised_exception("namespace/dict() arguments must be kwargs, dict and/or iterable of tuples, not " + arg->type());
}
iter_first = false;
}
return out;
}
const func_builtins & global_builtins() {
static const func_builtins builtins = {
{"raise_exception", [](const func_args & args) -> value {
@@ -355,18 +392,8 @@ const func_builtins & global_builtins() {
std::string msg = args.get_pos(0)->as_string().str();
throw raised_exception("Jinja Exception: " + msg);
}},
{"namespace", [](const func_args & args) -> value {
auto out = mk_val<value_object>();
for (const auto & arg : args.get_args()) {
if (!is_val<value_kwarg>(arg)) {
throw raised_exception("namespace() arguments must be kwargs");
}
auto kwarg = cast_val<value_kwarg>(arg);
JJ_DEBUG("namespace: adding key '%s'", kwarg->key.c_str());
out->insert(kwarg->key, kwarg->val);
}
return out;
}},
{"dict", toobject},
{"namespace", toobject},
{"strftime_now", [](const func_args & args) -> value {
args.ensure_vals<value_string>();
std::string format = args.get_pos(0)->as_string().str();
+24
View File
@@ -1976,6 +1976,30 @@ static void test_object_methods(testing & t) {
json::object(),
""
);
test_template(t, "dict from dict",
"{% set o = dict({'a': 3, 'b': 1, 'c': 2}) %}{{ o|tojson }}",
json::object(),
"{\"a\": 3, \"b\": 1, \"c\": 2}"
);
test_template(t, "dict from kwargs",
"{% set o = dict(a=3, b=1, c=2) %}{{ o|tojson }}",
json::object(),
"{\"a\": 3, \"b\": 1, \"c\": 2}"
);
test_template(t, "dict from tuples",
"{% set o = dict((obj | items | list)) %}{{ o|tojson }}",
{{"obj", {{"a", 3}, {"b", 1}, {"c", 2}}}},
"{\"a\": 3, \"b\": 1, \"c\": 2}"
);
test_template(t, "dict from tuples and kwargs",
"{% set o = dict((obj | items | list), c=2) %}{{ o|tojson }}",
{{"obj", {{"a", 3}, {"b", 1}}}},
"{\"a\": 3, \"b\": 1, \"c\": 2}"
);
}
static void test_hasher(testing & t) {