42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
import { StructOfArr } from "./types.ts";
|
|
import { zip } from "./utils.ts";
|
|
|
|
export class Rule<V extends string[]> {
|
|
private separators: ({ kind: "word", word: string } | { kind: "end" })[];
|
|
private vars: V;
|
|
|
|
public constructor(separators: string[], vars: V) {
|
|
this.separators = separators.map(word => ({ kind: "word", word }));
|
|
this.vars = vars;
|
|
this.separators.push({ kind: "end" });
|
|
}
|
|
|
|
public get(text: string): StructOfArr<V, string> | null {
|
|
const first_sep = this.separators[0] ?? "";
|
|
if (first_sep.kind === "end") {
|
|
if (text.length > 0) return null;
|
|
else return {} as StructOfArr<V, string>;
|
|
}
|
|
let [val, rest] = split_once(text, first_sep.word);
|
|
if (rest === null) return null;
|
|
const result = {} as Record<string, string>;
|
|
for (const [key, sep] of zip(this.vars, this.separators.slice(1))) {
|
|
if (sep.kind === "end") {
|
|
result[key] = rest;
|
|
break;
|
|
}
|
|
[val, rest] = split_once(rest, sep.word);
|
|
if (rest === null) return null;
|
|
result[key] = val;
|
|
}
|
|
return result as StructOfArr<V, string>;
|
|
}
|
|
}
|
|
|
|
function split_once(text: string, separator: string) {
|
|
const cursor = text.indexOf(separator);
|
|
if (cursor === -1) return [text, null] as const;
|
|
const left = text.slice(0, cursor);
|
|
const right = text.slice(cursor + separator.length);
|
|
return [left, right] as const;
|
|
}
|