Skip to content

Commit 65b4dad

Browse files
authored
[jinja] Add more built-in functions (#484)
This PR adds support for several built-in jinja filters (from [this list](https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-builtin-filters)). Related discussion: https://huggingface.co/codellama/CodeLlama-70b-Instruct-hf/discussions/21
1 parent d57fc81 commit 65b4dad

File tree

2 files changed

+97
-3
lines changed

2 files changed

+97
-3
lines changed

packages/jinja/src/runtime.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ export class Interpreter {
341341
// }
342342
// return filter.value([operand], environment);
343343

344+
// https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-builtin-filters
344345
if (operand instanceof ArrayValue) {
345346
switch (node.filter.value) {
346347
case "first":
@@ -368,12 +369,35 @@ export class Interpreter {
368369
})
369370
);
370371
default:
371-
throw new Error(`Unknown filter: ${node.filter.value}`);
372+
throw new Error(`Unknown ArrayValue filter: ${node.filter.value}`);
373+
}
374+
} else if (operand instanceof StringValue) {
375+
switch (node.filter.value) {
376+
case "length":
377+
return new NumericValue(operand.value.length);
378+
case "upper":
379+
return new StringValue(operand.value.toUpperCase());
380+
case "lower":
381+
return new StringValue(operand.value.toLowerCase());
382+
case "title":
383+
return new StringValue(operand.value.replace(/\b\w/g, (c) => c.toUpperCase()));
384+
case "capitalize":
385+
return new StringValue(operand.value.charAt(0).toUpperCase() + operand.value.slice(1));
386+
case "trim":
387+
return new StringValue(operand.value.trim());
388+
default:
389+
throw new Error(`Unknown StringValue filter: ${node.filter.value}`);
390+
}
391+
} else if (operand instanceof NumericValue) {
392+
switch (node.filter.value) {
393+
case "abs":
394+
return new NumericValue(Math.abs(operand.value));
395+
default:
396+
throw new Error(`Unknown NumericValue filter: ${node.filter.value}`);
372397
}
373398
}
374399

375-
// TODO add support for StringValue operand
376-
throw new Error(`Cannot apply filter to type: ${operand.type}`);
400+
throw new Error(`Cannot apply filter "${node.filter.value}" to type: ${operand.type}`);
377401
}
378402

379403
/**

packages/jinja/test/templates.test.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ const TEST_STRINGS = {
6969

7070
// Filter operator
7171
FILTER_OPERATOR: `{{ arr | length }}{{ 1 + arr | length }}{{ 2 + arr | sort | length }}{{ (arr | sort)[0] }}`,
72+
FILTER_OPERATOR_2: `|{{ 'abc' | length }}|{{ 'aBcD' | upper }}|{{ 'aBcD' | lower }}|{{ 'test test' | capitalize}}|{{ 'test test' | title }}|{{ ' a b ' | trim }}|{{ ' A B ' | trim | lower | length }}|`,
73+
FILTER_OPERATOR_3: `|{{ -1 | abs }}|{{ 1 | abs }}|`,
7274

7375
// Logical operators between non-Booleans
7476
BOOLEAN_NUMERICAL: `|{{ 1 and 2 }}|{{ 1 and 0 }}|{{ 0 and 1 }}|{{ 0 and 0 }}|{{ 1 or 2 }}|{{ 1 or 0 }}|{{ 0 or 1 }}|{{ 0 or 0 }}|{{ not 1 }}|{{ not 0 }}|`,
@@ -1139,6 +1141,70 @@ const TEST_PARSED = {
11391141
{ value: "]", type: "CloseSquareBracket" },
11401142
{ value: "}}", type: "CloseExpression" },
11411143
],
1144+
FILTER_OPERATOR_2: [
1145+
{ value: "|", type: "Text" },
1146+
{ value: "{{", type: "OpenExpression" },
1147+
{ value: "abc", type: "StringLiteral" },
1148+
{ value: "|", type: "Pipe" },
1149+
{ value: "length", type: "Identifier" },
1150+
{ value: "}}", type: "CloseExpression" },
1151+
{ value: "|", type: "Text" },
1152+
{ value: "{{", type: "OpenExpression" },
1153+
{ value: "aBcD", type: "StringLiteral" },
1154+
{ value: "|", type: "Pipe" },
1155+
{ value: "upper", type: "Identifier" },
1156+
{ value: "}}", type: "CloseExpression" },
1157+
{ value: "|", type: "Text" },
1158+
{ value: "{{", type: "OpenExpression" },
1159+
{ value: "aBcD", type: "StringLiteral" },
1160+
{ value: "|", type: "Pipe" },
1161+
{ value: "lower", type: "Identifier" },
1162+
{ value: "}}", type: "CloseExpression" },
1163+
{ value: "|", type: "Text" },
1164+
{ value: "{{", type: "OpenExpression" },
1165+
{ value: "test test", type: "StringLiteral" },
1166+
{ value: "|", type: "Pipe" },
1167+
{ value: "capitalize", type: "Identifier" },
1168+
{ value: "}}", type: "CloseExpression" },
1169+
{ value: "|", type: "Text" },
1170+
{ value: "{{", type: "OpenExpression" },
1171+
{ value: "test test", type: "StringLiteral" },
1172+
{ value: "|", type: "Pipe" },
1173+
{ value: "title", type: "Identifier" },
1174+
{ value: "}}", type: "CloseExpression" },
1175+
{ value: "|", type: "Text" },
1176+
{ value: "{{", type: "OpenExpression" },
1177+
{ value: " a b ", type: "StringLiteral" },
1178+
{ value: "|", type: "Pipe" },
1179+
{ value: "trim", type: "Identifier" },
1180+
{ value: "}}", type: "CloseExpression" },
1181+
{ value: "|", type: "Text" },
1182+
{ value: "{{", type: "OpenExpression" },
1183+
{ value: " A B ", type: "StringLiteral" },
1184+
{ value: "|", type: "Pipe" },
1185+
{ value: "trim", type: "Identifier" },
1186+
{ value: "|", type: "Pipe" },
1187+
{ value: "lower", type: "Identifier" },
1188+
{ value: "|", type: "Pipe" },
1189+
{ value: "length", type: "Identifier" },
1190+
{ value: "}}", type: "CloseExpression" },
1191+
{ value: "|", type: "Text" },
1192+
],
1193+
FILTER_OPERATOR_3: [
1194+
{ value: "|", type: "Text" },
1195+
{ value: "{{", type: "OpenExpression" },
1196+
{ value: "-1", type: "NumericLiteral" },
1197+
{ value: "|", type: "Pipe" },
1198+
{ value: "abs", type: "Identifier" },
1199+
{ value: "}}", type: "CloseExpression" },
1200+
{ value: "|", type: "Text" },
1201+
{ value: "{{", type: "OpenExpression" },
1202+
{ value: "1", type: "NumericLiteral" },
1203+
{ value: "|", type: "Pipe" },
1204+
{ value: "abs", type: "Identifier" },
1205+
{ value: "}}", type: "CloseExpression" },
1206+
{ value: "|", type: "Text" },
1207+
],
11421208

11431209
// Logical operators between non-Booleans
11441210
BOOLEAN_NUMERICAL: [
@@ -1518,6 +1584,8 @@ const TEST_CONTEXT = {
15181584
FILTER_OPERATOR: {
15191585
arr: [3, 2, 1],
15201586
},
1587+
FILTER_OPERATOR_2: {},
1588+
FILTER_OPERATOR_3: {},
15211589

15221590
// Logical operators between non-Booleans
15231591
BOOLEAN_NUMERICAL: {},
@@ -1594,6 +1662,8 @@ const EXPECTED_OUTPUTS = {
15941662

15951663
// Filter operator
15961664
FILTER_OPERATOR: `3451`,
1665+
FILTER_OPERATOR_2: `|3|ABCD|abcd|Test test|Test Test|a b|4|`,
1666+
FILTER_OPERATOR_3: `|1|1|`,
15971667

15981668
// Logical operators between non-Booleans
15991669
BOOLEAN_NUMERICAL: `|2|0|0|0|1|1|1|0|false|true|`,

0 commit comments

Comments
 (0)