resolver rework
This commit is contained in:
parent
3417fdd3d7
commit
9c9edd9e90
@ -8,7 +8,15 @@ export function Resolver({ resolver }: { resolver: string }) {
|
||||
const [res] = useState(new TTCQueryResolver(parser));
|
||||
const [content, setContent] = useState<ReactNode>("");
|
||||
useEffect(() => {
|
||||
setContent(res.resolve(resolver));
|
||||
let resolved = res.resolve(resolver);
|
||||
|
||||
setContent(
|
||||
typeof resolved?.display === "function" ? (
|
||||
<resolved.display />
|
||||
) : (
|
||||
resolved?.display
|
||||
)
|
||||
);
|
||||
}, [resolver, res]);
|
||||
return <span>{content}</span>;
|
||||
}
|
||||
@ -31,8 +39,9 @@ export function OnDemandResolver({
|
||||
for (const idx of stackIdxs) {
|
||||
let thing = res.current.getFromStack(idx);
|
||||
if (Array.isArray(thing)) thing = thing.at(0);
|
||||
if (typeof thing === "function") thing = thing();
|
||||
content = content.replaceAll(idx, thing as string);
|
||||
if (typeof thing.display === "function")
|
||||
content = content.replaceAll(idx, thing.display() as string);
|
||||
else content = content.replaceAll(idx, thing.display as string);
|
||||
}
|
||||
setContent(content);
|
||||
}, [res, template]);
|
||||
|
@ -1,14 +1,20 @@
|
||||
/* eslint-disable react/display-name */
|
||||
import { ReactNode } from "react";
|
||||
import { Dice } from "../dice";
|
||||
import { sum } from "../utils/sum";
|
||||
import { DiceChart } from "./DiceChart";
|
||||
import { TTCQueryParser } from "./TTCQueryParser";
|
||||
|
||||
interface StackItem {
|
||||
value: any;
|
||||
display: ReactNode | (() => ReactNode);
|
||||
}
|
||||
|
||||
export class TTCQueryResolver {
|
||||
private parser: TTCQueryParser | null;
|
||||
private context: QueryableObject | null = null;
|
||||
|
||||
private stack: any[] = [];
|
||||
private stack: StackItem[] = [];
|
||||
|
||||
constructor(parser?: TTCQueryParser) {
|
||||
this.parser = parser || null;
|
||||
@ -22,25 +28,35 @@ export class TTCQueryResolver {
|
||||
this.context = obj;
|
||||
}
|
||||
|
||||
public resolve(resolver: string, onDemand?: boolean) {
|
||||
public resolve(resolver: string, onDemand?: boolean): StackItem | undefined {
|
||||
try {
|
||||
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();
|
||||
if (typeof last?.display === "function" && !onDemand) {
|
||||
last.display = last.display();
|
||||
}
|
||||
|
||||
return last;
|
||||
} catch (e) {
|
||||
return e?.toString();
|
||||
return { value: e?.toString(), display: e?.toString() };
|
||||
}
|
||||
}
|
||||
|
||||
private parseResolver(resolver: string) {
|
||||
private parseResolver(resolver: string): StackItem {
|
||||
if (this.isArithmetic(resolver)) return this.solveArithmetic(resolver);
|
||||
if (this.isQuery(resolver)) return this.runQuery(resolver);
|
||||
return resolver;
|
||||
if (Dice.isDice(resolver)) {
|
||||
const value = new Dice(resolver);
|
||||
const dice: StackItem = {
|
||||
value,
|
||||
display: () => value.toString(),
|
||||
};
|
||||
return dice;
|
||||
}
|
||||
return { value: resolver, display: resolver };
|
||||
}
|
||||
private isQuery(resolver: string) {
|
||||
return (
|
||||
@ -49,100 +65,140 @@ export class TTCQueryResolver {
|
||||
/^\$\d\./.test(resolver)
|
||||
);
|
||||
}
|
||||
private runQuery(query: string) {
|
||||
private runQuery(query: string): StackItem {
|
||||
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.replace(/\$\d+/g, (e) =>
|
||||
this.getFromStack<number>(e).toString()
|
||||
)
|
||||
)
|
||||
) {
|
||||
return this.handleDice(
|
||||
stackItem.replace(/\$\d+/g, (e) =>
|
||||
this.getFromStack<number>(e).toString()
|
||||
),
|
||||
q
|
||||
);
|
||||
|
||||
if (stackItem.value instanceof Dice) {
|
||||
return {
|
||||
value: query,
|
||||
display: this.handleDice(stackItem.value, q),
|
||||
};
|
||||
}
|
||||
|
||||
return this.parser.search(q, stackItem as QueryableObject);
|
||||
const [res] = this.parser.search(q, stackItem.value as QueryableObject);
|
||||
debugger;
|
||||
if (Dice.isDice(res)) {
|
||||
const value = new Dice(res);
|
||||
return {
|
||||
value,
|
||||
display: () => value.toString(),
|
||||
};
|
||||
}
|
||||
return {
|
||||
value: res,
|
||||
display() {
|
||||
return (
|
||||
this.value.render ?? this.value ?? "Error resolving query: " + query
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 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().total;
|
||||
case "rollAvg":
|
||||
return () => d.rollAvg();
|
||||
case "rollTimes":
|
||||
return () => d.rollTimes(num);
|
||||
case "rollTimesAvg":
|
||||
return () => d.rollTimesAvg(num);
|
||||
case "rollLowest":
|
||||
return () => d.rollMin();
|
||||
case "rollHighest":
|
||||
return () => d.rollMax();
|
||||
case "rollDropHighest":
|
||||
return () => sum(...d.roll().results.toSorted().toSpliced(-1, 1));
|
||||
case "rollDropLowest":
|
||||
return () => sum(...d.roll().results.toSorted().toSpliced(0, 1));
|
||||
case "distribution":
|
||||
return () => DiceChart({ dice: d.getRollDistribution() });
|
||||
case "distribution.normalized":
|
||||
return () => DiceChart({ dice: d.getNormalizedRollDistribution() });
|
||||
default:
|
||||
return "No valid method provided for dice";
|
||||
const res =
|
||||
query.startsWith("_") && this.context
|
||||
? this.parser.search(query.replace("_", "^"), this.context).at(0)
|
||||
: this.parser.search(query.replace(/^[?_].?/, "")).at(0);
|
||||
if (Dice.isDice(res)) {
|
||||
const value = new Dice(res);
|
||||
return {
|
||||
value,
|
||||
display: () => value.toString(),
|
||||
};
|
||||
}
|
||||
return {
|
||||
value: res,
|
||||
display() {
|
||||
return (
|
||||
this.value.render ?? this.value ?? "Error resolving query: " + query
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private isArithmetic(resolver: string) {
|
||||
return resolver.split(/\+|\/|-|\*|\^/).filter((e) => !!e).length > 1;
|
||||
}
|
||||
private solveArithmetic(resolver: string) {
|
||||
private solveArithmetic(resolver: string): StackItem {
|
||||
const [n1, op, n2] = resolver
|
||||
.match(/(\$?\d+)([+\-*\/^])(\$?\d+)/)
|
||||
?.slice(1) || ["", "+", ""];
|
||||
let num1 = Number(n1),
|
||||
num2 = Number(n2);
|
||||
let num1: number = Number(n1),
|
||||
num2: number = 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";
|
||||
if (n1.startsWith("$")) {
|
||||
const result = this.getFromStack(n1).value;
|
||||
num1 = result instanceof Dice ? result.roll().total : Number(result);
|
||||
}
|
||||
if (n2.startsWith("$")) {
|
||||
const result = this.getFromStack(n1).value;
|
||||
num2 = result instanceof Dice ? result.roll().total : Number(result);
|
||||
}
|
||||
|
||||
const thing: StackItem = {
|
||||
value: () => {
|
||||
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";
|
||||
}
|
||||
},
|
||||
display() {
|
||||
return typeof this.value === "function" ? this.value() : this.value;
|
||||
},
|
||||
};
|
||||
|
||||
return thing;
|
||||
}
|
||||
|
||||
public getFromStack<T>(stackIndex: string): T {
|
||||
public getFromStack(stackIndex: string): StackItem {
|
||||
const i = Number(stackIndex.replace("$", ""));
|
||||
const val = this.stack[i] as T;
|
||||
const val = this.stack[i];
|
||||
return val;
|
||||
}
|
||||
private handleDice(dice: Dice, query: string) {
|
||||
const [method, n] = query.split(":");
|
||||
let num = Number(n);
|
||||
// if (n && n.startsWith("$")) num = this.getFromStack(n);
|
||||
switch (method) {
|
||||
case "roll":
|
||||
return () => dice.roll.apply(dice).total;
|
||||
case "rollAvg":
|
||||
return () => dice.rollAvg.apply(dice);
|
||||
case "rollTimes":
|
||||
return () => dice.rollTimes.apply(dice, [num]);
|
||||
case "rollTimesAvg":
|
||||
return () => dice.rollTimesAvg.apply(dice, [num]);
|
||||
case "rollLowest":
|
||||
return () => dice.rollMin.apply(dice);
|
||||
case "rollHighest":
|
||||
return () => dice.rollMax.apply(dice);
|
||||
case "rollDropHighest":
|
||||
return () =>
|
||||
sum(...dice.roll.apply(dice).results.toSorted().toSpliced(-1, 1));
|
||||
case "rollDropLowest":
|
||||
return () =>
|
||||
sum(...dice.roll.apply(dice).results.toSorted().toSpliced(0, 1));
|
||||
case "distribution":
|
||||
return () => DiceChart({ dice: dice.getRollDistribution.apply(dice) });
|
||||
case "distribution.normalized":
|
||||
return () =>
|
||||
DiceChart({ dice: dice.getNormalizedRollDistribution.apply(dice) });
|
||||
default:
|
||||
return () => "No valid method provided for dice";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user