feat: add native Tomie adapter and strict import compatibility checks

This commit is contained in:
mrleo1nid committed 2026-10-25 11:02:52 +03:00
1 parent c8d83b3fe7
commit 57a4edcbfd
45 files changed
+2985 -71

No files matched your search

+21 -8
View File
@@ -12,7 +12,18 @@ function number(value: any): number {
return n;
}
export function evaluateNani(ast: NaniAst, lookup: (name: string) => any, random = Math.random): any {
function equal(a: any, b: any): boolean {
if (a === null || b === null) return a === null && b === null;
if ((typeof a === "string") !== (typeof b === "string")) {
const text = typeof a === "string" ? a : b;
return text.trim() !== "" && Number.isFinite(Number(text)) && Number(a) === Number(b);
}
if (["number", "boolean"].includes(typeof a) && ["number", "boolean"].includes(typeof b)) return Number(a) === Number(b);
return typeof a === typeof b && a === b;
}
export function evaluateNani(ast: NaniAst, lookup: (name: string) => any, random = Math.random,
functions: Record<string, (...args: any[]) => any> = {}): any {
const evaluate = (node: NaniAst): any => {
switch (node[0]) {
case "const": return node[1];
@@ -37,12 +48,12 @@ export function evaluateNani(ast: NaniAst, lookup: (name: string) => any, random
case "*": return number(a) * number(b);
case "/": if (number(b) === 0) throw new Error("Naninovel: деление на ноль"); return number(a) / number(b);
case "%": if (number(b) === 0) throw new Error("Naninovel: деление на ноль"); return number(a) % number(b);
case "=": case "==": return String(a) === String(b);
case "!=": case "<>": return String(a) !== String(b);
case "<": return number(a) < number(b);
case ">": return number(a) > number(b);
case "<=": return number(a) <= number(b);
case ">=": return number(a) >= number(b);
case "=": case "==": return equal(a, b);
case "!=": case "<>": return !equal(a, b);
case "<": return typeof a === "string" && typeof b === "string" ? a < b : number(a) < number(b);
case ">": return typeof a === "string" && typeof b === "string" ? a > b : number(a) > number(b);
case "<=": return typeof a === "string" && typeof b === "string" ? a <= b : number(a) <= number(b);
case ">=": return typeof a === "string" && typeof b === "string" ? a >= b : number(a) >= number(b);
case "&": return number(a) & number(b);
case "|": return number(a) | number(b);
case "^": return number(a) ^ number(b);
@@ -52,7 +63,9 @@ export function evaluateNani(ast: NaniAst, lookup: (name: string) => any, random
}
}
case "call": {
const args = node[2].map((value: NaniAst) => number(evaluate(value)));
const values = node[2].map((value: NaniAst) => evaluate(value));
if (Object.hasOwn(functions, node[1])) return functions[node[1]](...values);
const args = values.map(number);
switch (node[1]) {
case "Random": case "random": case "Rand": {
const min = args.length > 1 ? args[0] : 0, max = args.length > 1 ? args[1] : args[0];