118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import { Dice } from "../dice";
|
|
import { TTCQueryParser } from "./TTCQueryParser";
|
|
|
|
export class TTCQueryResolver {
|
|
private parser: TTCQueryParser | null;
|
|
private context: QueryableObject | null = null;
|
|
|
|
private stack: any[] = [];
|
|
|
|
constructor(parser?: TTCQueryParser) {
|
|
this.parser = parser || null;
|
|
}
|
|
|
|
public setParser(parser: TTCQueryParser) {
|
|
this.parser = parser;
|
|
}
|
|
|
|
public setContext(obj: QueryableObject) {
|
|
this.context = obj;
|
|
}
|
|
|
|
public resolve(resolver: string, onDemand?: boolean) {
|
|
const resList = resolver.split(",");
|
|
for (const res of resList) {
|
|
this.stack.push(this.parseResolver(res));
|
|
}
|
|
const last = this.stack.at(-1);
|
|
if (typeof last === "function" && !onDemand) return last();
|
|
|
|
return last;
|
|
}
|
|
|
|
private parseResolver(resolver: string) {
|
|
if (this.isArithmetic(resolver)) return this.solveArithmetic(resolver);
|
|
if (this.isQuery(resolver)) return this.runQuery(resolver);
|
|
return resolver;
|
|
}
|
|
private isQuery(resolver: string) {
|
|
return (
|
|
resolver.startsWith("?") ||
|
|
resolver.startsWith("_") ||
|
|
/^\$\d\./.test(resolver)
|
|
);
|
|
}
|
|
private runQuery(query: string) {
|
|
if (!this.parser) throw "Parser not defined in query resolver";
|
|
if (query.startsWith("$")) {
|
|
const [_, idx, q] = query.match(/^(\$\d+)\.(.*)/) || [];
|
|
if (!_) throw "Detected stack query but did not match the regex";
|
|
const stackItem = this.getFromStack(idx);
|
|
if (typeof stackItem === "string" && Dice.isDice(stackItem)) {
|
|
return this.handleDice(stackItem, q);
|
|
}
|
|
|
|
return this.parser.search(q, stackItem as QueryableObject);
|
|
}
|
|
|
|
// if (query.startsWith("?") || query.startsWith("_"))
|
|
return query.startsWith("_") && this.context
|
|
? this.parser.search(query.replace("_", "^"), this.context).at(0)
|
|
: this.parser.search(query.replace(/^[?_].?/, "")).at(0);
|
|
}
|
|
|
|
private handleDice(dice: string, query: string) {
|
|
const d = new Dice(dice);
|
|
const [method, n] = query.split(":");
|
|
let num = Number(n);
|
|
if (n && n.startsWith("$")) num = this.getFromStack(n);
|
|
switch (method) {
|
|
case "roll":
|
|
return () => d.roll();
|
|
case "rollAvg":
|
|
return () => d.rollAvg();
|
|
case "rollTimes":
|
|
return () => d.rollTimes(num);
|
|
case "rollTimesAvg":
|
|
return () => d.rollTimesAvg(num);
|
|
default:
|
|
return "No valid method provided for dice";
|
|
}
|
|
}
|
|
|
|
private isArithmetic(resolver: string) {
|
|
return resolver.split(/\+|\/|-|\*|\^/).filter((e) => !!e).length > 1;
|
|
}
|
|
private solveArithmetic(resolver: string) {
|
|
const [n1, op, n2] = resolver
|
|
.match(/(\$?\d+)([+\-*\/^])(\$?\d+)/)
|
|
?.slice(1) || ["", "+", ""];
|
|
let num1 = Number(n1),
|
|
num2 = Number(n2);
|
|
|
|
if (n1.startsWith("$")) num1 = this.getFromStack<number>(n1);
|
|
if (n2.startsWith("$")) num2 = this.getFromStack<number>(n2);
|
|
|
|
switch (op) {
|
|
case "+":
|
|
return num1 + num2;
|
|
case "-":
|
|
return num1 - num2;
|
|
case "*":
|
|
return num1 * num2;
|
|
case "/":
|
|
return num1 / num2;
|
|
case "^":
|
|
return num1 ^ num2;
|
|
default:
|
|
throw "Arithmetic detected but no proper operator assigned";
|
|
}
|
|
}
|
|
|
|
public getFromStack<T>(stackIndex: string): T {
|
|
const i = Number(stackIndex.replace("$", ""));
|
|
const val = this.stack[i] as T;
|
|
return val;
|
|
}
|
|
}
|