Stub out Idv parser

This commit is contained in:
Tangent Wantwight 2024-07-07 21:00:20 -04:00
parent a2df9a4142
commit e90727a06c
4 changed files with 118 additions and 1 deletions

View file

@ -6,6 +6,7 @@
<script src="js/debug.js"></script>
<script>
document.body.append(...TickDebug());
document.body.append(...IdvDebug());
</script>
</body>
</html>

View file

@ -1,3 +1,4 @@
import { TickDebug } from "./debug/tick";
import { IdvDebug } from "./debug/idv";
Object.assign(globalThis, { TickDebug });
Object.assign(globalThis, { TickDebug, IdvDebug });

43
debug/idv.ts Normal file
View file

@ -0,0 +1,43 @@
import { h } from "../lib/html";
import { Idv, StringFromDocument } from "../lib/idv";
export function IdvDebug() {
const textarea = h(
"textarea",
{
cols: 80,
rows: 40,
oninput(ev) {
parse();
},
},
`# Idv Testing Ground
Uid: 0
Shell: tclsh
Group: users
Group: sudo
`
);
const pre = h("pre");
function parse() {
try {
const idv = Idv.parse(textarea.value);
pre.textContent = JSON.stringify(
{
shell: idv.getProperty("Shell", String, StringFromDocument),
groups: idv.getList("Group", String, StringFromDocument),
},
null,
2
);
} catch (e) {
pre.textContent = String(e);
}
}
parse();
return [textarea, pre];
}

72
lib/idv.ts Normal file
View file

@ -0,0 +1,72 @@
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");