@bitbybit-dev/base 1.0.0-rc.1 → 1.0.0
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.
|
@@ -462,4 +462,12 @@ export declare namespace Math {
|
|
|
462
462
|
*/
|
|
463
463
|
maxDelta: number;
|
|
464
464
|
}
|
|
465
|
+
class EvalArithmeticDto {
|
|
466
|
+
constructor(expression?: string);
|
|
467
|
+
/**
|
|
468
|
+
* Arithmetic expression containing numbers, +, -, *, /, and parentheses
|
|
469
|
+
* @default 1+1
|
|
470
|
+
*/
|
|
471
|
+
expression: string;
|
|
472
|
+
}
|
|
465
473
|
}
|
|
@@ -605,4 +605,17 @@ export var Math;
|
|
|
605
605
|
}
|
|
606
606
|
}
|
|
607
607
|
Math.MoveTowardsDto = MoveTowardsDto;
|
|
608
|
+
class EvalArithmeticDto {
|
|
609
|
+
constructor(expression) {
|
|
610
|
+
/**
|
|
611
|
+
* Arithmetic expression containing numbers, +, -, *, /, and parentheses
|
|
612
|
+
* @default 1+1
|
|
613
|
+
*/
|
|
614
|
+
this.expression = "1+1";
|
|
615
|
+
if (expression !== undefined) {
|
|
616
|
+
this.expression = expression;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
Math.EvalArithmeticDto = EvalArithmeticDto;
|
|
608
621
|
})(Math || (Math = {}));
|
|
@@ -461,6 +461,18 @@ export declare class MathBitByBit {
|
|
|
461
461
|
* @drawable false
|
|
462
462
|
*/
|
|
463
463
|
moveTowards(inputs: Inputs.Math.MoveTowardsDto): number;
|
|
464
|
+
/**
|
|
465
|
+
* Safely evaluates a simple arithmetic expression containing only
|
|
466
|
+
* numbers, +, -, *, /, parentheses, and whitespace.
|
|
467
|
+
* Uses the shunting-yard algorithm — no eval/Function.
|
|
468
|
+
* Example: '(3+2)*4' → 20, '10/3' → 3.3333...
|
|
469
|
+
* @param inputs arithmetic expression string
|
|
470
|
+
* @returns evaluated result
|
|
471
|
+
* @group operations
|
|
472
|
+
* @shortname eval arithmetic
|
|
473
|
+
* @drawable false
|
|
474
|
+
*/
|
|
475
|
+
evalArithmetic(inputs: Inputs.Math.EvalArithmeticDto): number;
|
|
464
476
|
private easeInSine;
|
|
465
477
|
private easeOutSine;
|
|
466
478
|
private easeInOutSine;
|
package/lib/api/services/math.js
CHANGED
|
@@ -660,6 +660,128 @@ export class MathBitByBit {
|
|
|
660
660
|
}
|
|
661
661
|
return inputs.current + Math.sign(delta) * inputs.maxDelta;
|
|
662
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Safely evaluates a simple arithmetic expression containing only
|
|
665
|
+
* numbers, +, -, *, /, parentheses, and whitespace.
|
|
666
|
+
* Uses the shunting-yard algorithm — no eval/Function.
|
|
667
|
+
* Example: '(3+2)*4' → 20, '10/3' → 3.3333...
|
|
668
|
+
* @param inputs arithmetic expression string
|
|
669
|
+
* @returns evaluated result
|
|
670
|
+
* @group operations
|
|
671
|
+
* @shortname eval arithmetic
|
|
672
|
+
* @drawable false
|
|
673
|
+
*/
|
|
674
|
+
evalArithmetic(inputs) {
|
|
675
|
+
var _a;
|
|
676
|
+
const expr = inputs.expression;
|
|
677
|
+
const tokens = [];
|
|
678
|
+
let i = 0;
|
|
679
|
+
while (i < expr.length) {
|
|
680
|
+
const ch = expr[i];
|
|
681
|
+
if (ch === " ") {
|
|
682
|
+
i++;
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (ch === "(" || ch === ")") {
|
|
686
|
+
tokens.push(ch);
|
|
687
|
+
i++;
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (ch === "+" || ch === "*" || ch === "/") {
|
|
691
|
+
tokens.push(ch);
|
|
692
|
+
i++;
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if (ch === "-") {
|
|
696
|
+
const prev = tokens.length > 0 ? tokens[tokens.length - 1] : undefined;
|
|
697
|
+
if (prev === undefined || prev === "(" || prev === "+" || prev === "-" || prev === "*" || prev === "/") {
|
|
698
|
+
let num = "-";
|
|
699
|
+
i++;
|
|
700
|
+
while (i < expr.length && (expr[i] >= "0" && expr[i] <= "9" || expr[i] === ".")) {
|
|
701
|
+
num += expr[i];
|
|
702
|
+
i++;
|
|
703
|
+
}
|
|
704
|
+
if (num === "-") {
|
|
705
|
+
throw new Error("Invalid expression");
|
|
706
|
+
}
|
|
707
|
+
tokens.push(num);
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
tokens.push(ch);
|
|
711
|
+
i++;
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if ((ch >= "0" && ch <= "9") || ch === ".") {
|
|
715
|
+
let num = "";
|
|
716
|
+
while (i < expr.length && (expr[i] >= "0" && expr[i] <= "9" || expr[i] === ".")) {
|
|
717
|
+
num += expr[i];
|
|
718
|
+
i++;
|
|
719
|
+
}
|
|
720
|
+
tokens.push(num);
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
throw new Error("Invalid character in expression");
|
|
724
|
+
}
|
|
725
|
+
const output = [];
|
|
726
|
+
const ops = [];
|
|
727
|
+
const prec = { "+": 1, "-": 1, "*": 2, "/": 2 };
|
|
728
|
+
const applyOp = () => {
|
|
729
|
+
const op = ops.pop();
|
|
730
|
+
const b = output.pop();
|
|
731
|
+
const a = output.pop();
|
|
732
|
+
switch (op) {
|
|
733
|
+
case "+":
|
|
734
|
+
output.push(a + b);
|
|
735
|
+
break;
|
|
736
|
+
case "-":
|
|
737
|
+
output.push(a - b);
|
|
738
|
+
break;
|
|
739
|
+
case "*":
|
|
740
|
+
output.push(a * b);
|
|
741
|
+
break;
|
|
742
|
+
case "/":
|
|
743
|
+
output.push(a / b);
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
for (const tok of tokens) {
|
|
748
|
+
if (tok === "(") {
|
|
749
|
+
ops.push(tok);
|
|
750
|
+
}
|
|
751
|
+
else if (tok === ")") {
|
|
752
|
+
while (ops.length > 0 && ops[ops.length - 1] !== "(") {
|
|
753
|
+
applyOp();
|
|
754
|
+
}
|
|
755
|
+
if (ops.length === 0) {
|
|
756
|
+
throw new Error("Mismatched parentheses");
|
|
757
|
+
}
|
|
758
|
+
ops.pop();
|
|
759
|
+
}
|
|
760
|
+
else if (tok in prec) {
|
|
761
|
+
while (ops.length > 0 && ops[ops.length - 1] !== "(" && ((_a = prec[ops[ops.length - 1]]) !== null && _a !== void 0 ? _a : 0) >= prec[tok]) {
|
|
762
|
+
applyOp();
|
|
763
|
+
}
|
|
764
|
+
ops.push(tok);
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
const n = parseFloat(tok);
|
|
768
|
+
if (isNaN(n)) {
|
|
769
|
+
throw new Error("Invalid number");
|
|
770
|
+
}
|
|
771
|
+
output.push(n);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
while (ops.length > 0) {
|
|
775
|
+
if (ops[ops.length - 1] === "(") {
|
|
776
|
+
throw new Error("Mismatched parentheses");
|
|
777
|
+
}
|
|
778
|
+
applyOp();
|
|
779
|
+
}
|
|
780
|
+
if (output.length !== 1) {
|
|
781
|
+
throw new Error("Invalid expression");
|
|
782
|
+
}
|
|
783
|
+
return output[0];
|
|
784
|
+
}
|
|
663
785
|
easeInSine(x) {
|
|
664
786
|
return 1 - Math.cos((x * Math.PI) / 2);
|
|
665
787
|
}
|