2024.js/lib/idv.ts

72 lines
2 KiB
TypeScript

export type DistinguisherParser<T> = (distinguisher: string) => T;
export type DocumentParser<T> = (document: string[]) => T;
const LEADING_WHITESPACE = /^([ \t]+)/;
const ENTRY = /^(.+?):\s*(.*)/;
export class Idv {
collections: Record<string, undefined | [string, string[]][]> = {};
public static parse(input: string): Idv {
const lines = input.split("\n").map((line) => line.trimEnd());
return Idv.parseLines(lines);
}
static parseLines(input: string[]): Idv {
const idv = new Idv();
let currentDocument: string[] = [];
input.forEach((line) => {
const indent = LEADING_WHITESPACE.exec(line)?.[1];
if (indent) {
// TODO
} else if (line == "") {
// TODO
} else if (line[0] == "#") {
// skip
} else {
const matches = ENTRY.exec(line);
if (matches) {
const [, collection, distinguisher] = matches;
if (idv.collections[collection] == undefined) {
idv.collections[collection] = [];
}
currentDocument = [];
idv.collections[collection].push([distinguisher, currentDocument]);
} else {
throw new Error("Failed to parse a property");
}
}
});
return idv;
}
public getProperty<T>(
name: string,
parseDistinguisher: DistinguisherParser<T>,
parseDocument: DocumentParser<T>
): T | null {
const firstEntry = this.collections[name]?.[0];
return firstEntry && firstEntry[1].length > 0
? parseDocument(firstEntry[1])
: firstEntry?.[0]
? parseDistinguisher(firstEntry[0])
: null;
}
public getList<T>(
name: string,
parseDistinguisher: DistinguisherParser<T>,
parseDocument: DocumentParser<T>
): T[] {
return (this.collections[name] ?? []).map(([distinguisher, document]) =>
document.length > 0
? parseDocument(document)
: parseDistinguisher(distinguisher)
);
}
}
export const StringFromDocument = (lines: string[]) => lines.join("\n");