tina4-nodejs 3.10.30 → 3.10.32
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.
|
@@ -419,6 +419,40 @@ function evalExpr(expr: string, context: Record<string, unknown>): unknown {
|
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
// Arithmetic operators: +, -, *, //, /, %, ** (lowest to highest precedence)
|
|
423
|
+
for (const op of [" + ", " - ", " * ", " // ", " / ", " % ", " ** "]) {
|
|
424
|
+
const pos = findOutsideQuotes(expr, op);
|
|
425
|
+
if (pos >= 0) {
|
|
426
|
+
const left = expr.slice(0, pos).trim();
|
|
427
|
+
const right = expr.slice(pos + op.length).trim();
|
|
428
|
+
const lVal = evalExpr(left, context);
|
|
429
|
+
const rVal = evalExpr(right, context);
|
|
430
|
+
try {
|
|
431
|
+
let lNum = lVal != null ? Number(lVal) : 0;
|
|
432
|
+
let rNum = rVal != null ? Number(rVal) : 0;
|
|
433
|
+
if (isNaN(lNum)) lNum = 0;
|
|
434
|
+
if (isNaN(rNum)) rNum = 0;
|
|
435
|
+
const opS = op.trim();
|
|
436
|
+
// Preserve int type when both operands are int-like (except for / which returns float)
|
|
437
|
+
const bothInt = Number.isInteger(lNum) && Number.isInteger(rNum) && opS !== "/";
|
|
438
|
+
let result: number;
|
|
439
|
+
switch (opS) {
|
|
440
|
+
case "+": result = lNum + rNum; break;
|
|
441
|
+
case "-": result = lNum - rNum; break;
|
|
442
|
+
case "*": result = lNum * rNum; break;
|
|
443
|
+
case "//": result = rNum !== 0 ? Math.floor(lNum / rNum) : 0; break;
|
|
444
|
+
case "/": result = rNum !== 0 ? lNum / rNum : 0; break;
|
|
445
|
+
case "%": result = rNum !== 0 ? lNum % rNum : 0; break;
|
|
446
|
+
case "**": result = lNum ** rNum; break;
|
|
447
|
+
default: result = 0;
|
|
448
|
+
}
|
|
449
|
+
return bothInt && Number.isInteger(result) ? result : result;
|
|
450
|
+
} catch {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
422
456
|
// Function call: name("arg1", "arg2") — supports dotted names like user.t("key")
|
|
423
457
|
const fnMatch = expr.match(FN_CALL_RE);
|
|
424
458
|
if (fnMatch) {
|
|
@@ -1782,7 +1816,7 @@ export class Frond {
|
|
|
1782
1816
|
if (m) {
|
|
1783
1817
|
const name = m[1];
|
|
1784
1818
|
const expr = m[2].trim();
|
|
1785
|
-
context[name] =
|
|
1819
|
+
context[name] = this.evalVarRaw(expr, context);
|
|
1786
1820
|
}
|
|
1787
1821
|
}
|
|
1788
1822
|
|