diff --git a/example.ts b/example.ts index 7c42052..d56e755 100755 --- a/example.ts +++ b/example.ts @@ -1,10 +1,11 @@ #!/bin/env -S deno run -import { extr } from "./mod.ts" +import { def } from "./mod.ts" -const date = ["month", " ", "day", " ", "h", ":", "m", ":", "s"] as const; -const service = extr("", ...date, " ", "device", " ", "service", "[", "pid", "]: ", "line"); -const kernel_ = extr("", ...date, " ", "device", " kernel: ", "line"); + +const date = "{{month}} {{day}} {{h}}:{{m}}:{{s}}" as const; +const service = def(`${date} {{device}} {{service}}[{{pid}}]: {{line}}`); +const kernel_ = def(`${date} {{device}} kernel: {{line}}`); const lines = [ "août 06 09:25:18 navis systemd[1]: Finished Load Kernel Module configfs.", diff --git a/lib/lib.ts b/lib/lib.ts index 0a75dbe..a3337b5 100644 --- a/lib/lib.ts +++ b/lib/lib.ts @@ -1,6 +1,7 @@ import { Rule } from "./rule.ts"; import { PairElts, StructOfArr } from "./types.ts"; import { Extractor } from "./extractor.ts" +import { split_once } from "./utils.ts"; export function extr(...args: A): Extractor, string>> { const seps = [] as string[]; @@ -18,7 +19,7 @@ export function extr(...args: A): Extractor rule.get(text)) } -Deno.test("types", async () => { +Deno.test("extr_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")) @@ -26,3 +27,34 @@ Deno.test("types", async () => { .get("bonjour, le chêne, feuillu"); assertEquals({ vars }, { vars: { "arbre": "le chêne" } }) }) + +type ArrForDef = + D extends "" ? [] : + D extends `${infer W extends string}{{${infer V extends string}}}${infer R extends string}` ? [W, V, ...ArrForDef] : + D extends `${infer W extends string}` ? [W] : + never; + +export function def(def: D): Extractor>, string>> { + const result = [] as string[]; + let rest = def as string; + while (true) { + const [word, var_rest] = split_once(rest, "{{"); + if (var_rest === null) break; + const [var_, rest_] = split_once(var_rest, "}}"); + if (rest_ === null) throw new Error(`Invalid rule near '${rest}'`); + result.push(word, var_); + rest = rest_; + } + if (rest.length > 0) result.push(rest); + const args = result as ArrForDef; + return extr(...args); +} + +Deno.test("def_types", async () => { + const { assertEquals } = await import("https://deno.land/std@0.224.0/assert/assert_equals.ts"); + const vars = extr() + .or(def("bonjour, {{animal}}, poilu")) + .or(def("bonjour, {{arbre}}, feuillu")) + .get("bonjour, le chêne, feuillu"); + assertEquals({ vars }, { vars: { "arbre": "le chêne" } }) +}) diff --git a/lib/rule.ts b/lib/rule.ts index 3f950a7..c663126 100644 --- a/lib/rule.ts +++ b/lib/rule.ts @@ -1,5 +1,5 @@ import { StructOfArr } from "./types.ts"; -import { zip } from "./utils.ts"; +import { split_once, zip } from "./utils.ts"; export class Rule { private separators: ({ kind: "word", word: string } | { kind: "end" })[]; @@ -32,11 +32,3 @@ export class Rule { return result as StructOfArr; } } - -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; -} diff --git a/lib/utils.ts b/lib/utils.ts index b59e86a..41c59d5 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -12,3 +12,11 @@ export function next(iterator: Iterator) { if (result === undefined) return null; else return result as T; } + +export 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; +} diff --git a/mod.ts b/mod.ts index b7107de..541ae2d 100644 --- a/mod.ts +++ b/mod.ts @@ -1 +1 @@ -export { extr } from "./lib/lib.ts" +export { extr, def } from "./lib/lib.ts"