first iteration of query and resolver
This commit is contained in:
parent
7839dbbc1c
commit
3656fc42ac
@ -1,6 +1,4 @@
|
||||
type QueryableObject = Record<string, any>;
|
||||
|
||||
class TtcQueryParser {
|
||||
export class TTCQueryParser {
|
||||
private data: QueryableObject;
|
||||
private relativeMap: Map<QueryableObject, QueryableObject>;
|
||||
|
||||
@ -26,24 +24,12 @@ class TtcQueryParser {
|
||||
} else if (query.startsWith("$")) {
|
||||
result = this.queryRelativeObject(query, currentObject);
|
||||
} else {
|
||||
result = this.queryPublication(query);
|
||||
result = this.searchInObject(this.data, query);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private queryPublication(query: string): any[] {
|
||||
// Example implementation for searching publication
|
||||
const publicationMatch = query.match(/^(\w+)(\[(\w+)\])?(\..+)?/);
|
||||
if (publicationMatch) {
|
||||
const subQuery = publicationMatch[4];
|
||||
|
||||
// Search within the publication data
|
||||
return this.searchInObject(this.data, subQuery);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private queryCurrentObject(
|
||||
query: string,
|
||||
currentObject: QueryableObject
|
||||
@ -109,7 +95,9 @@ class TtcQueryParser {
|
||||
return [];
|
||||
}
|
||||
} else {
|
||||
current = current.map((e: any) => e[key]);
|
||||
current = Array.isArray(current)
|
||||
? current.map((e: any) => e[key])
|
||||
: current[key];
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
@ -161,17 +149,11 @@ class TtcQueryParser {
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
const data = {
|
||||
relative: true,
|
||||
weapon_abilities: [
|
||||
{ name: "Rapid Fire", body: "Shoot again" },
|
||||
{ name: "Sustained Hits", body: "More damage", relative: true },
|
||||
],
|
||||
};
|
||||
// const
|
||||
|
||||
const parser = new TtcQueryParser(data);
|
||||
// const parser = new TTCQueryParser(data);
|
||||
|
||||
// Example queries
|
||||
console.log(parser.search("weapon_abilities[name=Rapid Fire].body")); // Example output
|
||||
// console.log(parser.search("^weapon_abilities[name=Rapid Fire]", data)); // Example output
|
||||
console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output
|
||||
// // Example queries
|
||||
// console.log(parser.search("$weapon_abilities[name=Rapid Fire].body")); // Example output
|
||||
// // console.log(parser.search("^weapon_abilities[name=Rapid Fire]", data)); // Example output
|
||||
// console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output
|
||||
|
117
lib/ttcQuery/TTCResolvers.ts
Normal file
117
lib/ttcQuery/TTCResolvers.ts
Normal file
@ -0,0 +1,117 @@
|
||||
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)) this.runQuery(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);
|
||||
}
|
||||
|
||||
// if (query.startsWith("?") || query.startsWith("_"))
|
||||
return query.startsWith("_") && this.context
|
||||
? this.parser.search(query.replace("_", ""), this.context)
|
||||
: this.parser.search(query.replace(/^[?_].?/, ""));
|
||||
}
|
||||
|
||||
private handleDice(dice: string, query: string) {
|
||||
const d = new Dice(dice);
|
||||
const [method, n] = query.split(":");
|
||||
let num = Number(n);
|
||||
if (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);
|
||||
console.log(num1, num2);
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
private getFromStack<T>(stackIndex: string): T {
|
||||
const i = Number(stackIndex.replace("$", ""));
|
||||
const val = this.stack[i] as T;
|
||||
return val;
|
||||
}
|
||||
}
|
9
types.d.ts
vendored
9
types.d.ts
vendored
@ -31,7 +31,7 @@ type FrontMatter = Record<string, string>;
|
||||
type SearchFunction = (
|
||||
s: string,
|
||||
start: number,
|
||||
end: number,
|
||||
end: number
|
||||
) => {
|
||||
start: number;
|
||||
end: number;
|
||||
@ -53,7 +53,7 @@ type IdentifierRegistration = <N = Record<string, string>>(
|
||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
|
||||
renderFunction: TokenRenderer<N>,
|
||||
openTagRx?: RegExp,
|
||||
closeTagRx?: RegExp,
|
||||
closeTagRx?: RegExp
|
||||
) => void;
|
||||
|
||||
// Schema
|
||||
@ -88,6 +88,9 @@ type InputBinder = {
|
||||
name: string;
|
||||
value: string | number;
|
||||
onChange: (
|
||||
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,
|
||||
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||||
) => void;
|
||||
};
|
||||
|
||||
// Query
|
||||
type QueryableObject = Record<string, any>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user