first iteration of query and resolver

This commit is contained in:
Emmaline Autumn 2024-08-05 04:00:00 -06:00
parent 7839dbbc1c
commit 3656fc42ac
3 changed files with 134 additions and 32 deletions

View File

@ -1,6 +1,4 @@
type QueryableObject = Record<string, any>; export class TTCQueryParser {
class TtcQueryParser {
private data: QueryableObject; private data: QueryableObject;
private relativeMap: Map<QueryableObject, QueryableObject>; private relativeMap: Map<QueryableObject, QueryableObject>;
@ -26,24 +24,12 @@ class TtcQueryParser {
} else if (query.startsWith("$")) { } else if (query.startsWith("$")) {
result = this.queryRelativeObject(query, currentObject); result = this.queryRelativeObject(query, currentObject);
} else { } else {
result = this.queryPublication(query); result = this.searchInObject(this.data, query);
} }
return result; 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( private queryCurrentObject(
query: string, query: string,
currentObject: QueryableObject currentObject: QueryableObject
@ -109,7 +95,9 @@ class TtcQueryParser {
return []; return [];
} }
} else { } else {
current = current.map((e: any) => e[key]); current = Array.isArray(current)
? current.map((e: any) => e[key])
: current[key];
} }
} else { } else {
return []; return [];
@ -161,17 +149,11 @@ class TtcQueryParser {
} }
// Example usage: // Example usage:
const data = { // const
relative: true,
weapon_abilities: [
{ name: "Rapid Fire", body: "Shoot again" },
{ name: "Sustained Hits", body: "More damage", relative: true },
],
};
const parser = new TtcQueryParser(data); // const parser = new TTCQueryParser(data);
// Example queries // // Example queries
console.log(parser.search("weapon_abilities[name=Rapid Fire].body")); // Example output // 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]", data)); // Example output
console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output // console.log(parser.search("$weapon_abilities[name=Rapid Fire].body", data)); // Example output

View 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
View File

@ -31,7 +31,7 @@ type FrontMatter = Record<string, string>;
type SearchFunction = ( type SearchFunction = (
s: string, s: string,
start: number, start: number,
end: number, end: number
) => { ) => {
start: number; start: number;
end: number; end: number;
@ -53,7 +53,7 @@ type IdentifierRegistration = <N = Record<string, string>>(
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>, parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
renderFunction: TokenRenderer<N>, renderFunction: TokenRenderer<N>,
openTagRx?: RegExp, openTagRx?: RegExp,
closeTagRx?: RegExp, closeTagRx?: RegExp
) => void; ) => void;
// Schema // Schema
@ -88,6 +88,9 @@ type InputBinder = {
name: string; name: string;
value: string | number; value: string | number;
onChange: ( onChange: (
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>, e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
) => void; ) => void;
}; };
// Query
type QueryableObject = Record<string, any>;