binja 0.4.6 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -2
- package/dist/cli.js +254 -2
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.d.ts.map +1 -1
- package/dist/index.js +726 -27
- package/dist/parser/index.d.ts +10 -0
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/nodes.d.ts +49 -2
- package/dist/parser/nodes.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +11 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -660,6 +660,28 @@ class Parser {
|
|
|
660
660
|
case "autoescape":
|
|
661
661
|
case "verbatim":
|
|
662
662
|
return this.parseSimpleBlock(start, tagName.value);
|
|
663
|
+
case "cycle":
|
|
664
|
+
return this.parseCycle(start);
|
|
665
|
+
case "firstof":
|
|
666
|
+
return this.parseFirstof(start);
|
|
667
|
+
case "ifchanged":
|
|
668
|
+
return this.parseIfchanged(start);
|
|
669
|
+
case "regroup":
|
|
670
|
+
return this.parseRegroup(start);
|
|
671
|
+
case "widthratio":
|
|
672
|
+
return this.parseWidthratio(start);
|
|
673
|
+
case "lorem":
|
|
674
|
+
return this.parseLorem(start);
|
|
675
|
+
case "csrf_token":
|
|
676
|
+
return this.parseCsrfToken(start);
|
|
677
|
+
case "debug":
|
|
678
|
+
return this.parseDebug(start);
|
|
679
|
+
case "templatetag":
|
|
680
|
+
return this.parseTemplatetag(start);
|
|
681
|
+
case "ifequal":
|
|
682
|
+
return this.parseIfequal(start, false);
|
|
683
|
+
case "ifnotequal":
|
|
684
|
+
return this.parseIfequal(start, true);
|
|
663
685
|
default:
|
|
664
686
|
this.skipToBlockEnd();
|
|
665
687
|
return null;
|
|
@@ -963,7 +985,7 @@ class Parser {
|
|
|
963
985
|
column: start.column
|
|
964
986
|
};
|
|
965
987
|
}
|
|
966
|
-
parseComment(
|
|
988
|
+
parseComment(_start) {
|
|
967
989
|
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
968
990
|
while (!this.isAtEnd()) {
|
|
969
991
|
if (this.checkBlockTag("endcomment"))
|
|
@@ -973,7 +995,7 @@ class Parser {
|
|
|
973
995
|
this.expectBlockTag("endcomment");
|
|
974
996
|
return null;
|
|
975
997
|
}
|
|
976
|
-
parseSimpleBlock(
|
|
998
|
+
parseSimpleBlock(_start, tagName) {
|
|
977
999
|
this.skipToBlockEnd();
|
|
978
1000
|
const endTag = `end${tagName}`;
|
|
979
1001
|
while (!this.isAtEnd()) {
|
|
@@ -988,6 +1010,236 @@ class Parser {
|
|
|
988
1010
|
}
|
|
989
1011
|
return null;
|
|
990
1012
|
}
|
|
1013
|
+
parseCycle(start) {
|
|
1014
|
+
const values = [];
|
|
1015
|
+
let asVar = null;
|
|
1016
|
+
let silent = false;
|
|
1017
|
+
while (!this.check("BLOCK_END" /* BLOCK_END */)) {
|
|
1018
|
+
if (this.check("NAME" /* NAME */) && this.peek().value === "as") {
|
|
1019
|
+
this.advance();
|
|
1020
|
+
asVar = this.expect("NAME" /* NAME */).value;
|
|
1021
|
+
if (this.check("NAME" /* NAME */) && this.peek().value === "silent") {
|
|
1022
|
+
this.advance();
|
|
1023
|
+
silent = true;
|
|
1024
|
+
}
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
values.push(this.parseExpression());
|
|
1028
|
+
}
|
|
1029
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1030
|
+
return {
|
|
1031
|
+
type: "Cycle",
|
|
1032
|
+
values,
|
|
1033
|
+
asVar,
|
|
1034
|
+
silent,
|
|
1035
|
+
line: start.line,
|
|
1036
|
+
column: start.column
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
parseFirstof(start) {
|
|
1040
|
+
const values = [];
|
|
1041
|
+
let fallback = null;
|
|
1042
|
+
let asVar = null;
|
|
1043
|
+
while (!this.check("BLOCK_END" /* BLOCK_END */)) {
|
|
1044
|
+
if (this.check("NAME" /* NAME */) && this.peek().value === "as") {
|
|
1045
|
+
this.advance();
|
|
1046
|
+
asVar = this.expect("NAME" /* NAME */).value;
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
values.push(this.parseExpression());
|
|
1050
|
+
}
|
|
1051
|
+
if (values.length > 0) {
|
|
1052
|
+
const last = values[values.length - 1];
|
|
1053
|
+
if (last.type === "Literal" && typeof last.value === "string") {
|
|
1054
|
+
fallback = values.pop();
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1058
|
+
return {
|
|
1059
|
+
type: "Firstof",
|
|
1060
|
+
values,
|
|
1061
|
+
fallback,
|
|
1062
|
+
asVar,
|
|
1063
|
+
line: start.line,
|
|
1064
|
+
column: start.column
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
parseIfchanged(start) {
|
|
1068
|
+
const values = [];
|
|
1069
|
+
while (!this.check("BLOCK_END" /* BLOCK_END */)) {
|
|
1070
|
+
values.push(this.parseExpression());
|
|
1071
|
+
}
|
|
1072
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1073
|
+
const body = [];
|
|
1074
|
+
let else_ = [];
|
|
1075
|
+
while (!this.isAtEnd()) {
|
|
1076
|
+
if (this.checkBlockTag("else") || this.checkBlockTag("endifchanged"))
|
|
1077
|
+
break;
|
|
1078
|
+
const node = this.parseStatement();
|
|
1079
|
+
if (node)
|
|
1080
|
+
body.push(node);
|
|
1081
|
+
}
|
|
1082
|
+
if (this.checkBlockTag("else")) {
|
|
1083
|
+
this.advance();
|
|
1084
|
+
this.advance();
|
|
1085
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1086
|
+
while (!this.isAtEnd()) {
|
|
1087
|
+
if (this.checkBlockTag("endifchanged"))
|
|
1088
|
+
break;
|
|
1089
|
+
const node = this.parseStatement();
|
|
1090
|
+
if (node)
|
|
1091
|
+
else_.push(node);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
this.expectBlockTag("endifchanged");
|
|
1095
|
+
return {
|
|
1096
|
+
type: "Ifchanged",
|
|
1097
|
+
values,
|
|
1098
|
+
body,
|
|
1099
|
+
else_,
|
|
1100
|
+
line: start.line,
|
|
1101
|
+
column: start.column
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
parseRegroup(start) {
|
|
1105
|
+
const target = this.parseExpression();
|
|
1106
|
+
this.expectName("by");
|
|
1107
|
+
const key = this.expect("NAME" /* NAME */).value;
|
|
1108
|
+
this.expectName("as");
|
|
1109
|
+
const asVar = this.expect("NAME" /* NAME */).value;
|
|
1110
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1111
|
+
return {
|
|
1112
|
+
type: "Regroup",
|
|
1113
|
+
target,
|
|
1114
|
+
key,
|
|
1115
|
+
asVar,
|
|
1116
|
+
line: start.line,
|
|
1117
|
+
column: start.column
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
parseWidthratio(start) {
|
|
1121
|
+
const value = this.parseExpression();
|
|
1122
|
+
const maxValue = this.parseExpression();
|
|
1123
|
+
const maxWidth = this.parseExpression();
|
|
1124
|
+
let asVar = null;
|
|
1125
|
+
if (this.check("NAME" /* NAME */) && this.peek().value === "as") {
|
|
1126
|
+
this.advance();
|
|
1127
|
+
asVar = this.expect("NAME" /* NAME */).value;
|
|
1128
|
+
}
|
|
1129
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1130
|
+
return {
|
|
1131
|
+
type: "Widthratio",
|
|
1132
|
+
value,
|
|
1133
|
+
maxValue,
|
|
1134
|
+
maxWidth,
|
|
1135
|
+
asVar,
|
|
1136
|
+
line: start.line,
|
|
1137
|
+
column: start.column
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
parseLorem(start) {
|
|
1141
|
+
let count = null;
|
|
1142
|
+
let method = "p";
|
|
1143
|
+
let random = false;
|
|
1144
|
+
if (this.check("NUMBER" /* NUMBER */)) {
|
|
1145
|
+
count = {
|
|
1146
|
+
type: "Literal",
|
|
1147
|
+
value: parseInt(this.advance().value, 10),
|
|
1148
|
+
line: start.line,
|
|
1149
|
+
column: start.column
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
if (this.check("NAME" /* NAME */)) {
|
|
1153
|
+
const m = this.peek().value.toLowerCase();
|
|
1154
|
+
if (m === "w" || m === "p" || m === "b") {
|
|
1155
|
+
method = m;
|
|
1156
|
+
this.advance();
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
if (this.check("NAME" /* NAME */) && this.peek().value === "random") {
|
|
1160
|
+
random = true;
|
|
1161
|
+
this.advance();
|
|
1162
|
+
}
|
|
1163
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1164
|
+
return {
|
|
1165
|
+
type: "Lorem",
|
|
1166
|
+
count,
|
|
1167
|
+
method,
|
|
1168
|
+
random,
|
|
1169
|
+
line: start.line,
|
|
1170
|
+
column: start.column
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
parseCsrfToken(start) {
|
|
1174
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1175
|
+
return {
|
|
1176
|
+
type: "CsrfToken",
|
|
1177
|
+
line: start.line,
|
|
1178
|
+
column: start.column
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
parseDebug(start) {
|
|
1182
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1183
|
+
return {
|
|
1184
|
+
type: "Debug",
|
|
1185
|
+
line: start.line,
|
|
1186
|
+
column: start.column
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
parseTemplatetag(start) {
|
|
1190
|
+
const tagType = this.expect("NAME" /* NAME */).value;
|
|
1191
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1192
|
+
return {
|
|
1193
|
+
type: "Templatetag",
|
|
1194
|
+
tagType,
|
|
1195
|
+
line: start.line,
|
|
1196
|
+
column: start.column
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
parseIfequal(start, negated) {
|
|
1200
|
+
const left = this.parseExpression();
|
|
1201
|
+
const right = this.parseExpression();
|
|
1202
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1203
|
+
const test = {
|
|
1204
|
+
type: "Compare",
|
|
1205
|
+
left,
|
|
1206
|
+
ops: [{ operator: negated ? "!=" : "==", right }],
|
|
1207
|
+
line: start.line,
|
|
1208
|
+
column: start.column
|
|
1209
|
+
};
|
|
1210
|
+
const body = [];
|
|
1211
|
+
let else_ = [];
|
|
1212
|
+
const endTag = negated ? "endifnotequal" : "endifequal";
|
|
1213
|
+
while (!this.isAtEnd()) {
|
|
1214
|
+
if (this.checkBlockTag("else") || this.checkBlockTag(endTag))
|
|
1215
|
+
break;
|
|
1216
|
+
const node = this.parseStatement();
|
|
1217
|
+
if (node)
|
|
1218
|
+
body.push(node);
|
|
1219
|
+
}
|
|
1220
|
+
if (this.checkBlockTag("else")) {
|
|
1221
|
+
this.advance();
|
|
1222
|
+
this.advance();
|
|
1223
|
+
this.expect("BLOCK_END" /* BLOCK_END */);
|
|
1224
|
+
while (!this.isAtEnd()) {
|
|
1225
|
+
if (this.checkBlockTag(endTag))
|
|
1226
|
+
break;
|
|
1227
|
+
const node = this.parseStatement();
|
|
1228
|
+
if (node)
|
|
1229
|
+
else_.push(node);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
this.expectBlockTag(endTag);
|
|
1233
|
+
return {
|
|
1234
|
+
type: "If",
|
|
1235
|
+
test,
|
|
1236
|
+
body,
|
|
1237
|
+
elifs: [],
|
|
1238
|
+
else_,
|
|
1239
|
+
line: start.line,
|
|
1240
|
+
column: start.column
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
991
1243
|
parseExpression() {
|
|
992
1244
|
return this.parseConditional();
|
|
993
1245
|
}
|
|
@@ -2231,6 +2483,195 @@ ${indent2}`;
|
|
|
2231
2483
|
safeString.__safe__ = true;
|
|
2232
2484
|
return safeString;
|
|
2233
2485
|
};
|
|
2486
|
+
var addslashes = (value) => {
|
|
2487
|
+
const result = String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, "\\\"");
|
|
2488
|
+
const safeString = new String(result);
|
|
2489
|
+
safeString.__safe__ = true;
|
|
2490
|
+
return safeString;
|
|
2491
|
+
};
|
|
2492
|
+
var get_digit = (value, digit) => {
|
|
2493
|
+
const num = parseInt(String(value), 10);
|
|
2494
|
+
if (isNaN(num))
|
|
2495
|
+
return value;
|
|
2496
|
+
const str = String(Math.abs(num));
|
|
2497
|
+
const pos = Number(digit) || 1;
|
|
2498
|
+
if (pos < 1 || pos > str.length)
|
|
2499
|
+
return value;
|
|
2500
|
+
return parseInt(str[str.length - pos], 10);
|
|
2501
|
+
};
|
|
2502
|
+
var iriencode = (value) => {
|
|
2503
|
+
return String(value).replace(/ /g, "%20").replace(/"/g, "%22").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\\/g, "%5C").replace(/\^/g, "%5E").replace(/`/g, "%60").replace(/\{/g, "%7B").replace(/\|/g, "%7C").replace(/\}/g, "%7D");
|
|
2504
|
+
};
|
|
2505
|
+
var json_script = (value, elementId) => {
|
|
2506
|
+
const jsonStr = JSON.stringify(value).replace(/</g, "\\u003C").replace(/>/g, "\\u003E").replace(/&/g, "\\u0026");
|
|
2507
|
+
const id = elementId ? ` id="${String(elementId)}"` : "";
|
|
2508
|
+
const html = `<script${id} type="application/json">${jsonStr}</script>`;
|
|
2509
|
+
const safeString = new String(html);
|
|
2510
|
+
safeString.__safe__ = true;
|
|
2511
|
+
return safeString;
|
|
2512
|
+
};
|
|
2513
|
+
var safeseq = (value) => {
|
|
2514
|
+
if (!Array.isArray(value))
|
|
2515
|
+
return value;
|
|
2516
|
+
return value.map((item) => {
|
|
2517
|
+
const safeString = new String(item);
|
|
2518
|
+
safeString.__safe__ = true;
|
|
2519
|
+
return safeString;
|
|
2520
|
+
});
|
|
2521
|
+
};
|
|
2522
|
+
var stringformat = (value, formatStr) => {
|
|
2523
|
+
const fmt = String(formatStr);
|
|
2524
|
+
const val = value;
|
|
2525
|
+
if (fmt === "s")
|
|
2526
|
+
return String(val);
|
|
2527
|
+
if (fmt === "d" || fmt === "i")
|
|
2528
|
+
return String(parseInt(String(val), 10) || 0);
|
|
2529
|
+
if (fmt === "f")
|
|
2530
|
+
return String(parseFloat(String(val)) || 0);
|
|
2531
|
+
if (fmt === "x")
|
|
2532
|
+
return (parseInt(String(val), 10) || 0).toString(16);
|
|
2533
|
+
if (fmt === "X")
|
|
2534
|
+
return (parseInt(String(val), 10) || 0).toString(16).toUpperCase();
|
|
2535
|
+
if (fmt === "o")
|
|
2536
|
+
return (parseInt(String(val), 10) || 0).toString(8);
|
|
2537
|
+
if (fmt === "b")
|
|
2538
|
+
return (parseInt(String(val), 10) || 0).toString(2);
|
|
2539
|
+
if (fmt === "e")
|
|
2540
|
+
return (parseFloat(String(val)) || 0).toExponential();
|
|
2541
|
+
const precisionMatch = fmt.match(/^\.?(\d+)f$/);
|
|
2542
|
+
if (precisionMatch) {
|
|
2543
|
+
const precision = parseInt(precisionMatch[1], 10);
|
|
2544
|
+
return (parseFloat(String(val)) || 0).toFixed(precision);
|
|
2545
|
+
}
|
|
2546
|
+
const widthMatch = fmt.match(/^(\d+)([sd])$/);
|
|
2547
|
+
if (widthMatch) {
|
|
2548
|
+
const width = parseInt(widthMatch[1], 10);
|
|
2549
|
+
const type = widthMatch[2];
|
|
2550
|
+
const strVal = type === "d" ? String(parseInt(String(val), 10) || 0) : String(val);
|
|
2551
|
+
return strVal.padStart(width, type === "d" ? "0" : " ");
|
|
2552
|
+
}
|
|
2553
|
+
return String(val);
|
|
2554
|
+
};
|
|
2555
|
+
var truncatechars_html = (value, length2 = 30) => {
|
|
2556
|
+
const str = String(value);
|
|
2557
|
+
const maxLen = Number(length2);
|
|
2558
|
+
let result = "";
|
|
2559
|
+
let textLen = 0;
|
|
2560
|
+
let inTag = false;
|
|
2561
|
+
const openTags = [];
|
|
2562
|
+
for (let i = 0;i < str.length && textLen < maxLen; i++) {
|
|
2563
|
+
const char = str[i];
|
|
2564
|
+
if (char === "<") {
|
|
2565
|
+
inTag = true;
|
|
2566
|
+
const closeMatch = str.slice(i).match(/^<\/(\w+)/);
|
|
2567
|
+
const openMatch = str.slice(i).match(/^<(\w+)/);
|
|
2568
|
+
if (closeMatch) {
|
|
2569
|
+
const tagName = closeMatch[1].toLowerCase();
|
|
2570
|
+
const lastOpen = openTags.lastIndexOf(tagName);
|
|
2571
|
+
if (lastOpen !== -1)
|
|
2572
|
+
openTags.splice(lastOpen, 1);
|
|
2573
|
+
} else if (openMatch && !str.slice(i).match(/^<\w+[^>]*\/>/)) {
|
|
2574
|
+
openTags.push(openMatch[1].toLowerCase());
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
result += char;
|
|
2578
|
+
if (char === ">") {
|
|
2579
|
+
inTag = false;
|
|
2580
|
+
} else if (!inTag) {
|
|
2581
|
+
textLen++;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
if (textLen >= maxLen && str.length > result.length) {
|
|
2585
|
+
result += "...";
|
|
2586
|
+
}
|
|
2587
|
+
for (let i = openTags.length - 1;i >= 0; i--) {
|
|
2588
|
+
result += `</${openTags[i]}>`;
|
|
2589
|
+
}
|
|
2590
|
+
const safeString = new String(result);
|
|
2591
|
+
safeString.__safe__ = true;
|
|
2592
|
+
return safeString;
|
|
2593
|
+
};
|
|
2594
|
+
var truncatewords_html = (value, count = 15) => {
|
|
2595
|
+
const str = String(value);
|
|
2596
|
+
const maxWords = Number(count);
|
|
2597
|
+
let result = "";
|
|
2598
|
+
let wordCount = 0;
|
|
2599
|
+
let inTag = false;
|
|
2600
|
+
let inWord = false;
|
|
2601
|
+
const openTags = [];
|
|
2602
|
+
for (let i = 0;i < str.length && wordCount < maxWords; i++) {
|
|
2603
|
+
const char = str[i];
|
|
2604
|
+
if (char === "<") {
|
|
2605
|
+
inTag = true;
|
|
2606
|
+
const closeMatch = str.slice(i).match(/^<\/(\w+)/);
|
|
2607
|
+
const openMatch = str.slice(i).match(/^<(\w+)/);
|
|
2608
|
+
if (closeMatch) {
|
|
2609
|
+
const tagName = closeMatch[1].toLowerCase();
|
|
2610
|
+
const lastOpen = openTags.lastIndexOf(tagName);
|
|
2611
|
+
if (lastOpen !== -1)
|
|
2612
|
+
openTags.splice(lastOpen, 1);
|
|
2613
|
+
} else if (openMatch && !str.slice(i).match(/^<\w+[^>]*\/>/)) {
|
|
2614
|
+
openTags.push(openMatch[1].toLowerCase());
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
result += char;
|
|
2618
|
+
if (char === ">") {
|
|
2619
|
+
inTag = false;
|
|
2620
|
+
} else if (!inTag) {
|
|
2621
|
+
const isSpace = /\s/.test(char);
|
|
2622
|
+
if (!isSpace && !inWord) {
|
|
2623
|
+
inWord = true;
|
|
2624
|
+
} else if (isSpace && inWord) {
|
|
2625
|
+
inWord = false;
|
|
2626
|
+
wordCount++;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
if (inWord)
|
|
2631
|
+
wordCount++;
|
|
2632
|
+
if (wordCount >= maxWords) {
|
|
2633
|
+
result = result.trimEnd() + "...";
|
|
2634
|
+
}
|
|
2635
|
+
for (let i = openTags.length - 1;i >= 0; i--) {
|
|
2636
|
+
result += `</${openTags[i]}>`;
|
|
2637
|
+
}
|
|
2638
|
+
const safeString = new String(result);
|
|
2639
|
+
safeString.__safe__ = true;
|
|
2640
|
+
return safeString;
|
|
2641
|
+
};
|
|
2642
|
+
var urlizetrunc = (value, limit = 15) => {
|
|
2643
|
+
const maxLen = Number(limit);
|
|
2644
|
+
const html = String(value).replace(URLIZE_REGEX, (url) => {
|
|
2645
|
+
const displayUrl = url.length > maxLen ? url.slice(0, maxLen) + "..." : url;
|
|
2646
|
+
return `<a href="${url}">${displayUrl}</a>`;
|
|
2647
|
+
});
|
|
2648
|
+
const safeString = new String(html);
|
|
2649
|
+
safeString.__safe__ = true;
|
|
2650
|
+
return safeString;
|
|
2651
|
+
};
|
|
2652
|
+
var items = (value) => {
|
|
2653
|
+
if (value == null || typeof value !== "object")
|
|
2654
|
+
return [];
|
|
2655
|
+
return Object.entries(value);
|
|
2656
|
+
};
|
|
2657
|
+
var xmlattr = (value, autospace = true) => {
|
|
2658
|
+
if (value == null || typeof value !== "object")
|
|
2659
|
+
return "";
|
|
2660
|
+
const attrs = [];
|
|
2661
|
+
for (const [key, val] of Object.entries(value)) {
|
|
2662
|
+
if (val === true) {
|
|
2663
|
+
attrs.push(key);
|
|
2664
|
+
} else if (val !== false && val != null) {
|
|
2665
|
+
const escaped = String(val).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2666
|
+
attrs.push(`${key}="${escaped}"`);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
const result = attrs.join(" ");
|
|
2670
|
+
const output = autospace && result ? " " + result : result;
|
|
2671
|
+
const safeString = new String(output);
|
|
2672
|
+
safeString.__safe__ = true;
|
|
2673
|
+
return safeString;
|
|
2674
|
+
};
|
|
2234
2675
|
var builtinFilters = {
|
|
2235
2676
|
upper,
|
|
2236
2677
|
lower,
|
|
@@ -2309,7 +2750,18 @@ var builtinFilters = {
|
|
|
2309
2750
|
forceescape,
|
|
2310
2751
|
phone2numeric,
|
|
2311
2752
|
linenumbers,
|
|
2312
|
-
unordered_list
|
|
2753
|
+
unordered_list,
|
|
2754
|
+
addslashes,
|
|
2755
|
+
get_digit,
|
|
2756
|
+
iriencode,
|
|
2757
|
+
json_script,
|
|
2758
|
+
safeseq,
|
|
2759
|
+
stringformat,
|
|
2760
|
+
truncatechars_html,
|
|
2761
|
+
truncatewords_html,
|
|
2762
|
+
urlizetrunc,
|
|
2763
|
+
items,
|
|
2764
|
+
xmlattr
|
|
2313
2765
|
};
|
|
2314
2766
|
|
|
2315
2767
|
// src/tests/index.ts
|
|
@@ -2625,6 +3077,24 @@ class Runtime {
|
|
|
2625
3077
|
case "Load":
|
|
2626
3078
|
case "Extends":
|
|
2627
3079
|
return null;
|
|
3080
|
+
case "Cycle":
|
|
3081
|
+
return this.renderCycleSync(node, ctx);
|
|
3082
|
+
case "Firstof":
|
|
3083
|
+
return this.renderFirstofSync(node, ctx);
|
|
3084
|
+
case "Ifchanged":
|
|
3085
|
+
return this.renderIfchangedSync(node, ctx);
|
|
3086
|
+
case "Regroup":
|
|
3087
|
+
return this.renderRegroupSync(node, ctx);
|
|
3088
|
+
case "Widthratio":
|
|
3089
|
+
return this.renderWidthratioSync(node, ctx);
|
|
3090
|
+
case "Lorem":
|
|
3091
|
+
return this.renderLoremSync(node, ctx);
|
|
3092
|
+
case "CsrfToken":
|
|
3093
|
+
return this.renderCsrfTokenSync();
|
|
3094
|
+
case "Debug":
|
|
3095
|
+
return this.renderDebugSync(ctx);
|
|
3096
|
+
case "Templatetag":
|
|
3097
|
+
return this.renderTemplatetagSync(node);
|
|
2628
3098
|
default:
|
|
2629
3099
|
return null;
|
|
2630
3100
|
}
|
|
@@ -2642,13 +3112,13 @@ class Runtime {
|
|
|
2642
3112
|
}
|
|
2643
3113
|
renderForSync(node, ctx) {
|
|
2644
3114
|
const iterable2 = this.eval(node.iter, ctx);
|
|
2645
|
-
const
|
|
2646
|
-
const len =
|
|
3115
|
+
const items2 = this.toIterable(iterable2);
|
|
3116
|
+
const len = items2.length;
|
|
2647
3117
|
if (len === 0) {
|
|
2648
3118
|
return this.renderNodesSync(node.else_, ctx);
|
|
2649
3119
|
}
|
|
2650
3120
|
ctx.push();
|
|
2651
|
-
ctx.pushForLoop(
|
|
3121
|
+
ctx.pushForLoop(items2, 0);
|
|
2652
3122
|
let result;
|
|
2653
3123
|
if (Array.isArray(node.target)) {
|
|
2654
3124
|
const targets = node.target;
|
|
@@ -2656,9 +3126,9 @@ class Runtime {
|
|
|
2656
3126
|
if (len < 50) {
|
|
2657
3127
|
result = "";
|
|
2658
3128
|
for (let i = 0;i < len; i++) {
|
|
2659
|
-
const item =
|
|
3129
|
+
const item = items2[i];
|
|
2660
3130
|
if (i > 0)
|
|
2661
|
-
ctx.updateForLoop(i,
|
|
3131
|
+
ctx.updateForLoop(i, items2);
|
|
2662
3132
|
let values;
|
|
2663
3133
|
if (Array.isArray(item)) {
|
|
2664
3134
|
values = item;
|
|
@@ -2675,9 +3145,9 @@ class Runtime {
|
|
|
2675
3145
|
} else {
|
|
2676
3146
|
const parts = new Array(len);
|
|
2677
3147
|
for (let i = 0;i < len; i++) {
|
|
2678
|
-
const item =
|
|
3148
|
+
const item = items2[i];
|
|
2679
3149
|
if (i > 0)
|
|
2680
|
-
ctx.updateForLoop(i,
|
|
3150
|
+
ctx.updateForLoop(i, items2);
|
|
2681
3151
|
let values;
|
|
2682
3152
|
if (Array.isArray(item)) {
|
|
2683
3153
|
values = item;
|
|
@@ -2699,16 +3169,16 @@ class Runtime {
|
|
|
2699
3169
|
result = "";
|
|
2700
3170
|
for (let i = 0;i < len; i++) {
|
|
2701
3171
|
if (i > 0)
|
|
2702
|
-
ctx.updateForLoop(i,
|
|
2703
|
-
ctx.set(target,
|
|
3172
|
+
ctx.updateForLoop(i, items2);
|
|
3173
|
+
ctx.set(target, items2[i]);
|
|
2704
3174
|
result += this.renderNodesSync(node.body, ctx);
|
|
2705
3175
|
}
|
|
2706
3176
|
} else {
|
|
2707
3177
|
const parts = new Array(len);
|
|
2708
3178
|
for (let i = 0;i < len; i++) {
|
|
2709
3179
|
if (i > 0)
|
|
2710
|
-
ctx.updateForLoop(i,
|
|
2711
|
-
ctx.set(target,
|
|
3180
|
+
ctx.updateForLoop(i, items2);
|
|
3181
|
+
ctx.set(target, items2[i]);
|
|
2712
3182
|
parts[i] = this.renderNodesSync(node.body, ctx);
|
|
2713
3183
|
}
|
|
2714
3184
|
result = parts.join("");
|
|
@@ -2770,6 +3240,217 @@ class Runtime {
|
|
|
2770
3240
|
}
|
|
2771
3241
|
return result;
|
|
2772
3242
|
}
|
|
3243
|
+
cycleState = new Map;
|
|
3244
|
+
renderCycleSync(node, ctx) {
|
|
3245
|
+
const key = node.values.map((v) => JSON.stringify(v)).join(",");
|
|
3246
|
+
const currentIndex = this.cycleState.get(key) ?? 0;
|
|
3247
|
+
const values = node.values.map((v) => this.eval(v, ctx));
|
|
3248
|
+
const value = values[currentIndex % values.length];
|
|
3249
|
+
this.cycleState.set(key, currentIndex + 1);
|
|
3250
|
+
if (node.asVar) {
|
|
3251
|
+
ctx.set(node.asVar, value);
|
|
3252
|
+
return node.silent ? "" : this.stringify(value);
|
|
3253
|
+
}
|
|
3254
|
+
return this.stringify(value);
|
|
3255
|
+
}
|
|
3256
|
+
renderFirstofSync(node, ctx) {
|
|
3257
|
+
for (const expr of node.values) {
|
|
3258
|
+
const value = this.eval(expr, ctx);
|
|
3259
|
+
if (this.isTruthy(value)) {
|
|
3260
|
+
if (node.asVar) {
|
|
3261
|
+
ctx.set(node.asVar, value);
|
|
3262
|
+
return "";
|
|
3263
|
+
}
|
|
3264
|
+
return this.stringify(value);
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
const fallback = node.fallback ? this.eval(node.fallback, ctx) : "";
|
|
3268
|
+
if (node.asVar) {
|
|
3269
|
+
ctx.set(node.asVar, fallback);
|
|
3270
|
+
return "";
|
|
3271
|
+
}
|
|
3272
|
+
return this.stringify(fallback);
|
|
3273
|
+
}
|
|
3274
|
+
ifchangedState = new Map;
|
|
3275
|
+
renderIfchangedSync(node, ctx) {
|
|
3276
|
+
const key = `ifchanged_${node.line}_${node.column}`;
|
|
3277
|
+
let currentValue;
|
|
3278
|
+
if (node.values.length > 0) {
|
|
3279
|
+
currentValue = node.values.map((v) => this.eval(v, ctx));
|
|
3280
|
+
} else {
|
|
3281
|
+
currentValue = this.renderNodesSync(node.body, ctx);
|
|
3282
|
+
}
|
|
3283
|
+
const lastValue = this.ifchangedState.get(key);
|
|
3284
|
+
const changed = JSON.stringify(currentValue) !== JSON.stringify(lastValue);
|
|
3285
|
+
this.ifchangedState.set(key, currentValue);
|
|
3286
|
+
if (changed) {
|
|
3287
|
+
if (node.values.length > 0) {
|
|
3288
|
+
return this.renderNodesSync(node.body, ctx);
|
|
3289
|
+
}
|
|
3290
|
+
return currentValue;
|
|
3291
|
+
} else {
|
|
3292
|
+
return this.renderNodesSync(node.else_, ctx);
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
renderRegroupSync(node, ctx) {
|
|
3296
|
+
const list2 = this.toIterable(this.eval(node.target, ctx));
|
|
3297
|
+
const groups = [];
|
|
3298
|
+
let currentGrouper = Symbol("initial");
|
|
3299
|
+
let currentList = [];
|
|
3300
|
+
for (const item of list2) {
|
|
3301
|
+
const grouper = item && typeof item === "object" ? item[node.key] : undefined;
|
|
3302
|
+
if (grouper !== currentGrouper) {
|
|
3303
|
+
if (currentList.length > 0) {
|
|
3304
|
+
groups.push({ grouper: currentGrouper, list: currentList });
|
|
3305
|
+
}
|
|
3306
|
+
currentGrouper = grouper;
|
|
3307
|
+
currentList = [item];
|
|
3308
|
+
} else {
|
|
3309
|
+
currentList.push(item);
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
if (currentList.length > 0) {
|
|
3313
|
+
groups.push({ grouper: currentGrouper, list: currentList });
|
|
3314
|
+
}
|
|
3315
|
+
ctx.set(node.asVar, groups);
|
|
3316
|
+
return "";
|
|
3317
|
+
}
|
|
3318
|
+
renderWidthratioSync(node, ctx) {
|
|
3319
|
+
const value = Number(this.eval(node.value, ctx));
|
|
3320
|
+
const maxValue = Number(this.eval(node.maxValue, ctx));
|
|
3321
|
+
const maxWidth = Number(this.eval(node.maxWidth, ctx));
|
|
3322
|
+
const ratio = maxValue === 0 ? 0 : Math.round(value / maxValue * maxWidth);
|
|
3323
|
+
if (node.asVar) {
|
|
3324
|
+
ctx.set(node.asVar, ratio);
|
|
3325
|
+
return "";
|
|
3326
|
+
}
|
|
3327
|
+
return String(ratio);
|
|
3328
|
+
}
|
|
3329
|
+
renderLoremSync(node, ctx) {
|
|
3330
|
+
const count = node.count ? Number(this.eval(node.count, ctx)) : 1;
|
|
3331
|
+
const method = node.method;
|
|
3332
|
+
const words = [
|
|
3333
|
+
"lorem",
|
|
3334
|
+
"ipsum",
|
|
3335
|
+
"dolor",
|
|
3336
|
+
"sit",
|
|
3337
|
+
"amet",
|
|
3338
|
+
"consectetur",
|
|
3339
|
+
"adipiscing",
|
|
3340
|
+
"elit",
|
|
3341
|
+
"sed",
|
|
3342
|
+
"do",
|
|
3343
|
+
"eiusmod",
|
|
3344
|
+
"tempor",
|
|
3345
|
+
"incididunt",
|
|
3346
|
+
"ut",
|
|
3347
|
+
"labore",
|
|
3348
|
+
"et",
|
|
3349
|
+
"dolore",
|
|
3350
|
+
"magna",
|
|
3351
|
+
"aliqua",
|
|
3352
|
+
"enim",
|
|
3353
|
+
"ad",
|
|
3354
|
+
"minim",
|
|
3355
|
+
"veniam",
|
|
3356
|
+
"quis",
|
|
3357
|
+
"nostrud",
|
|
3358
|
+
"exercitation",
|
|
3359
|
+
"ullamco",
|
|
3360
|
+
"laboris",
|
|
3361
|
+
"nisi",
|
|
3362
|
+
"aliquip",
|
|
3363
|
+
"ex",
|
|
3364
|
+
"ea",
|
|
3365
|
+
"commodo",
|
|
3366
|
+
"consequat",
|
|
3367
|
+
"duis",
|
|
3368
|
+
"aute",
|
|
3369
|
+
"irure",
|
|
3370
|
+
"in",
|
|
3371
|
+
"reprehenderit",
|
|
3372
|
+
"voluptate",
|
|
3373
|
+
"velit",
|
|
3374
|
+
"esse",
|
|
3375
|
+
"cillum",
|
|
3376
|
+
"fugiat",
|
|
3377
|
+
"nulla",
|
|
3378
|
+
"pariatur",
|
|
3379
|
+
"excepteur",
|
|
3380
|
+
"sint",
|
|
3381
|
+
"occaecat",
|
|
3382
|
+
"cupidatat",
|
|
3383
|
+
"non",
|
|
3384
|
+
"proident",
|
|
3385
|
+
"sunt",
|
|
3386
|
+
"culpa",
|
|
3387
|
+
"qui",
|
|
3388
|
+
"officia",
|
|
3389
|
+
"deserunt",
|
|
3390
|
+
"mollit",
|
|
3391
|
+
"anim",
|
|
3392
|
+
"id",
|
|
3393
|
+
"est",
|
|
3394
|
+
"laborum"
|
|
3395
|
+
];
|
|
3396
|
+
const getWord = (index) => {
|
|
3397
|
+
if (node.random) {
|
|
3398
|
+
return words[Math.floor(Math.random() * words.length)];
|
|
3399
|
+
}
|
|
3400
|
+
return words[index % words.length];
|
|
3401
|
+
};
|
|
3402
|
+
if (method === "w") {
|
|
3403
|
+
const result = [];
|
|
3404
|
+
for (let i = 0;i < count; i++) {
|
|
3405
|
+
result.push(getWord(i));
|
|
3406
|
+
}
|
|
3407
|
+
return result.join(" ");
|
|
3408
|
+
} else if (method === "p" || method === "b") {
|
|
3409
|
+
const paragraphs = [];
|
|
3410
|
+
for (let p = 0;p < count; p++) {
|
|
3411
|
+
const sentenceCount = 3 + p % 3;
|
|
3412
|
+
const sentences = [];
|
|
3413
|
+
for (let s = 0;s < sentenceCount; s++) {
|
|
3414
|
+
const wordCount = 8 + s % 7;
|
|
3415
|
+
const sentenceWords = [];
|
|
3416
|
+
for (let w = 0;w < wordCount; w++) {
|
|
3417
|
+
sentenceWords.push(getWord(p * 100 + s * 20 + w));
|
|
3418
|
+
}
|
|
3419
|
+
sentenceWords[0] = sentenceWords[0].charAt(0).toUpperCase() + sentenceWords[0].slice(1);
|
|
3420
|
+
sentences.push(sentenceWords.join(" ") + ".");
|
|
3421
|
+
}
|
|
3422
|
+
paragraphs.push(sentences.join(" "));
|
|
3423
|
+
}
|
|
3424
|
+
if (method === "b") {
|
|
3425
|
+
return paragraphs.join(`
|
|
3426
|
+
|
|
3427
|
+
`);
|
|
3428
|
+
}
|
|
3429
|
+
return paragraphs.map((p) => `<p>${p}</p>`).join(`
|
|
3430
|
+
`);
|
|
3431
|
+
}
|
|
3432
|
+
return "";
|
|
3433
|
+
}
|
|
3434
|
+
renderCsrfTokenSync() {
|
|
3435
|
+
return '<input type="hidden" name="csrfmiddlewaretoken" value="CSRF_TOKEN_PLACEHOLDER">';
|
|
3436
|
+
}
|
|
3437
|
+
renderDebugSync(ctx) {
|
|
3438
|
+
const data = ctx.toObject?.() || {};
|
|
3439
|
+
return `<pre>${JSON.stringify(data, null, 2)}</pre>`;
|
|
3440
|
+
}
|
|
3441
|
+
renderTemplatetagSync(node) {
|
|
3442
|
+
const tagMap = {
|
|
3443
|
+
openblock: "{%",
|
|
3444
|
+
closeblock: "%}",
|
|
3445
|
+
openvariable: "{{",
|
|
3446
|
+
closevariable: "}}",
|
|
3447
|
+
openbrace: "{",
|
|
3448
|
+
closebrace: "}",
|
|
3449
|
+
opencomment: "{#",
|
|
3450
|
+
closecomment: "#}"
|
|
3451
|
+
};
|
|
3452
|
+
return tagMap[node.tagType] || "";
|
|
3453
|
+
}
|
|
2773
3454
|
getDateInTimezone(d, tz) {
|
|
2774
3455
|
if (!tz) {
|
|
2775
3456
|
return {
|
|
@@ -3192,6 +3873,24 @@ class Runtime {
|
|
|
3192
3873
|
return this.renderStaticSync(node, ctx);
|
|
3193
3874
|
case "Now":
|
|
3194
3875
|
return this.renderNowSync(node, ctx);
|
|
3876
|
+
case "Cycle":
|
|
3877
|
+
return this.renderCycleSync(node, ctx);
|
|
3878
|
+
case "Firstof":
|
|
3879
|
+
return this.renderFirstofSync(node, ctx);
|
|
3880
|
+
case "Ifchanged":
|
|
3881
|
+
return this.renderIfchangedSync(node, ctx);
|
|
3882
|
+
case "Regroup":
|
|
3883
|
+
return this.renderRegroupSync(node, ctx);
|
|
3884
|
+
case "Widthratio":
|
|
3885
|
+
return this.renderWidthratioSync(node, ctx);
|
|
3886
|
+
case "Lorem":
|
|
3887
|
+
return this.renderLoremSync(node, ctx);
|
|
3888
|
+
case "CsrfToken":
|
|
3889
|
+
return this.renderCsrfTokenSync();
|
|
3890
|
+
case "Debug":
|
|
3891
|
+
return this.renderDebugSync(ctx);
|
|
3892
|
+
case "Templatetag":
|
|
3893
|
+
return this.renderTemplatetagSync(node);
|
|
3195
3894
|
default:
|
|
3196
3895
|
return null;
|
|
3197
3896
|
}
|
|
@@ -3209,19 +3908,19 @@ class Runtime {
|
|
|
3209
3908
|
}
|
|
3210
3909
|
async renderForAsync(node, ctx) {
|
|
3211
3910
|
const iterable2 = this.eval(node.iter, ctx);
|
|
3212
|
-
const
|
|
3213
|
-
const len =
|
|
3911
|
+
const items2 = this.toIterable(iterable2);
|
|
3912
|
+
const len = items2.length;
|
|
3214
3913
|
if (len === 0) {
|
|
3215
3914
|
return this.renderNodesAsync(node.else_, ctx);
|
|
3216
3915
|
}
|
|
3217
3916
|
const parts = new Array(len);
|
|
3218
3917
|
const isUnpacking = Array.isArray(node.target);
|
|
3219
3918
|
ctx.push();
|
|
3220
|
-
ctx.pushForLoop(
|
|
3919
|
+
ctx.pushForLoop(items2, 0);
|
|
3221
3920
|
for (let i = 0;i < len; i++) {
|
|
3222
|
-
const item =
|
|
3921
|
+
const item = items2[i];
|
|
3223
3922
|
if (i > 0)
|
|
3224
|
-
ctx.updateForLoop(i,
|
|
3923
|
+
ctx.updateForLoop(i, items2);
|
|
3225
3924
|
if (isUnpacking) {
|
|
3226
3925
|
let values;
|
|
3227
3926
|
if (Array.isArray(item)) {
|
|
@@ -4233,8 +4932,8 @@ class DebugCollector {
|
|
|
4233
4932
|
if (value.length === 0)
|
|
4234
4933
|
return "[]";
|
|
4235
4934
|
if (value.length <= 3) {
|
|
4236
|
-
const
|
|
4237
|
-
return `[${
|
|
4935
|
+
const items2 = value.map((v) => this.getPreview(v, 15)).join(", ");
|
|
4936
|
+
return `[${items2}]`;
|
|
4238
4937
|
}
|
|
4239
4938
|
return `[${this.getPreview(value[0], 15)}, ... +${value.length - 1}]`;
|
|
4240
4939
|
}
|
|
@@ -4546,7 +5245,7 @@ function generateContextSection(data) {
|
|
|
4546
5245
|
const keys = Object.keys(data.contextSnapshot);
|
|
4547
5246
|
if (keys.length === 0)
|
|
4548
5247
|
return "";
|
|
4549
|
-
const
|
|
5248
|
+
const items2 = keys.map((key) => renderContextValue(key, data.contextSnapshot[key])).join("");
|
|
4550
5249
|
return `
|
|
4551
5250
|
<div class="dbg-section">
|
|
4552
5251
|
<div class="dbg-section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
@@ -4555,7 +5254,7 @@ function generateContextSection(data) {
|
|
|
4555
5254
|
<span class="dbg-chevron">${icons.chevron}</span>
|
|
4556
5255
|
</div>
|
|
4557
5256
|
<div class="dbg-section-content">
|
|
4558
|
-
<div class="dbg-ctx-grid">${
|
|
5257
|
+
<div class="dbg-ctx-grid">${items2}</div>
|
|
4559
5258
|
</div>
|
|
4560
5259
|
</div>`;
|
|
4561
5260
|
}
|
|
@@ -4585,7 +5284,7 @@ function generateFiltersSection(data) {
|
|
|
4585
5284
|
const filters = Array.from(data.filtersUsed.entries());
|
|
4586
5285
|
if (filters.length === 0)
|
|
4587
5286
|
return "";
|
|
4588
|
-
const
|
|
5287
|
+
const items2 = filters.map(([name, count]) => `<span class="dbg-filter">${name}<span class="dbg-filter-count">\xD7${count}</span></span>`).join("");
|
|
4589
5288
|
return `
|
|
4590
5289
|
<div class="dbg-section">
|
|
4591
5290
|
<div class="dbg-section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
@@ -4594,7 +5293,7 @@ function generateFiltersSection(data) {
|
|
|
4594
5293
|
<span class="dbg-chevron">${icons.chevron}</span>
|
|
4595
5294
|
</div>
|
|
4596
5295
|
<div class="dbg-section-content">
|
|
4597
|
-
<div class="dbg-filters">${
|
|
5296
|
+
<div class="dbg-filters">${items2}</div>
|
|
4598
5297
|
</div>
|
|
4599
5298
|
</div>`;
|
|
4600
5299
|
}
|
|
@@ -4626,7 +5325,7 @@ function generateCacheSection(data) {
|
|
|
4626
5325
|
function generateWarningsSection(data) {
|
|
4627
5326
|
if (data.warnings.length === 0)
|
|
4628
5327
|
return "";
|
|
4629
|
-
const
|
|
5328
|
+
const items2 = data.warnings.map((w) => `
|
|
4630
5329
|
<div class="dbg-warning">
|
|
4631
5330
|
${icons.warning}
|
|
4632
5331
|
<span class="dbg-warning-text">${escapeHtml(w)}</span>
|
|
@@ -4640,7 +5339,7 @@ function generateWarningsSection(data) {
|
|
|
4640
5339
|
<span class="dbg-chevron">${icons.chevron}</span>
|
|
4641
5340
|
</div>
|
|
4642
5341
|
<div class="dbg-section-content">
|
|
4643
|
-
<div class="dbg-warnings">${
|
|
5342
|
+
<div class="dbg-warnings">${items2}</div>
|
|
4644
5343
|
</div>
|
|
4645
5344
|
</div>`;
|
|
4646
5345
|
}
|