init
This commit is contained in:
commit
8c18398ae4
6 changed files with 111 additions and 0 deletions
21
lib/extractor.ts
Normal file
21
lib/extractor.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
export class Extractor<O> {
|
||||||
|
private extract: (text: string) => O | null;
|
||||||
|
|
||||||
|
public constructor(extract: (text: string) => O | null) {
|
||||||
|
this.extract = extract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(text: string) {
|
||||||
|
return this.extract(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public or<T>(other: Extractor<T>) {
|
||||||
|
const this_extract = this.extract;
|
||||||
|
return new Extractor(text => {
|
||||||
|
const r1 = this_extract(text);
|
||||||
|
if (r1 !== null) return r1;
|
||||||
|
else return other.extract(text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
28
lib/lib.ts
Normal file
28
lib/lib.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Rule } from "./rule.ts";
|
||||||
|
import { PairElts, StructOfArr } from "./types.ts";
|
||||||
|
import { Extractor } from "./extractor.ts"
|
||||||
|
|
||||||
|
export function extr<A extends string[]>(...args: A): Extractor<StructOfArr<PairElts<A>, string>> {
|
||||||
|
const seps = [] as string[];
|
||||||
|
const vars = [] as string[];
|
||||||
|
|
||||||
|
let pair = true;
|
||||||
|
for (const arg of args) {
|
||||||
|
if (pair) seps.push(arg);
|
||||||
|
else vars.push(arg);
|
||||||
|
pair = !pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vars_ = vars as PairElts<A>;
|
||||||
|
const rule = new Rule(seps, vars_);
|
||||||
|
return new Extractor(text => rule.get(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
Deno.test("types", async () => {
|
||||||
|
const { assertEquals } = await import("https://deno.land/std@0.224.0/assert/assert_equals.ts");
|
||||||
|
const vars = extr()
|
||||||
|
.or(extr("bonjour, ", 'animal', ", poilu"))
|
||||||
|
.or(extr("bonjour, ", 'arbre', ", feuillu"))
|
||||||
|
.get("bonjour, le chêne, feuillu");
|
||||||
|
assertEquals({ vars }, { vars: { "arbre": "le chêne" } })
|
||||||
|
})
|
34
lib/rule.ts
Normal file
34
lib/rule.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
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>;
|
||||||
|
}
|
||||||
|
if (!text.includes(first_sep.word)) return null;
|
||||||
|
let [val, rest] = text.split(first_sep.word, 2);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (!rest.includes(sep.word)) return null;
|
||||||
|
[val, rest] = rest.split(sep.word, 2);
|
||||||
|
result[key] = val;
|
||||||
|
}
|
||||||
|
return result as StructOfArr<V, string>;
|
||||||
|
}
|
||||||
|
}
|
13
lib/types.ts
Normal file
13
lib/types.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
// deno-lint-ignore no-explicit-any
|
||||||
|
export type PairElts<A extends any[]> =
|
||||||
|
A extends [] ? [] :
|
||||||
|
A extends [infer _F] ? [] :
|
||||||
|
A extends [infer _F, infer S, ...infer R] ? [S, ...PairElts<R>] :
|
||||||
|
never;
|
||||||
|
|
||||||
|
export type StructOfArr<A extends string[], V> =
|
||||||
|
// deno-lint-ignore ban-types
|
||||||
|
A extends [] ? {} :
|
||||||
|
A extends [infer K extends string, ...infer R extends string[]] ? { [key in K]: V } & StructOfArr<R, V> :
|
||||||
|
never;
|
14
lib/utils.ts
Normal file
14
lib/utils.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export function* zip<A, B>(a: Iterable<A>, b: Iterable<B>): Generator<[A, B], void, void> {
|
||||||
|
const iter_a = a[Symbol.iterator](), iter_b = b[Symbol.iterator]();
|
||||||
|
while (true) {
|
||||||
|
const next_a = next(iter_a), next_b = next(iter_b);
|
||||||
|
if (next_a === null || next_b === null) return;
|
||||||
|
yield [next_a, next_b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function next<T>(iterator: Iterator<T>) {
|
||||||
|
const result = iterator.next().value;
|
||||||
|
if (result === undefined) return null;
|
||||||
|
else return result as T;
|
||||||
|
}
|
1
mod.ts
Normal file
1
mod.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import { extr } from "./lib/lib.ts"
|
Loading…
Add table
Add a link
Reference in a new issue