tools/core/readers/agenda.reader.ts
tools/core/readers/agenda.reader.ts is a file in Coordination Surface. 101 lines of code and 31 definitions.
const AGENDA_MARK = "`";
const ROW_LEAD = "|";
const PLANNED_STATE = "planned";
const LETTER_SCALE = 100;
interface AgendaRow {
readonly invariant: string;
readonly ordinal: string;
readonly planned: boolean;
}
interface DisorderedRow {
readonly invariant: string;
readonly ordinal: string;
readonly after: string;
}
const stateCellOf = function stateCellOf(row: string): string {
const cells = row.split(ROW_LEAD);
if (cells.length < 3) {
return "";
}
const cell = (cells.at(-2) ?? "").trim();
if (!cell.startsWith(AGENDA_MARK)) {
return cell;
}
const closes = cell.indexOf(AGENDA_MARK, 1);
return closes === -1 ? cell.slice(1) : cell.slice(1, closes);
};
const agendaRowOf = function agendaRowOf(line: string): AgendaRow | null {
const trimmed = line.trim();
const opens = trimmed.startsWith(ROW_LEAD) ? trimmed.indexOf(AGENDA_MARK) : -1;
const closes = opens === -1 ? -1 : trimmed.indexOf(AGENDA_MARK, opens + 1);
const invariant = closes === -1 ? "" : trimmed.slice(opens + 1, closes).trim();
if (invariant.length === 0) {
return null;
}
const cell = trimmed.indexOf(ROW_LEAD, 1);
const ordinal = cell === -1 ? "" : trimmed.slice(1, cell).trim();
return { invariant, ordinal, planned: stateCellOf(trimmed).startsWith(PLANNED_STATE) };
};
export const agendaRows = function agendaRows(agenda: string): AgendaRow[] {
return agenda
.split("\n")
.flatMap((line) => {
const row = agendaRowOf(line);
return row === null ? [] : [row];
})
.filter((row, index, rows) => rows.findIndex((held) => held.invariant === row.invariant) === index);
};
export const ordinalValue = function ordinalValue(ordinal: string): number | null {
let digits = "";
let cursor = 0;
while (cursor < ordinal.length && ordinal.charAt(cursor) >= "0" && ordinal.charAt(cursor) <= "9") {
digits += ordinal.charAt(cursor);
cursor += 1;
}
if (digits.length === 0) {
return null;
}
let suffix = 0;
for (; cursor < ordinal.length; cursor += 1) {
const char = ordinal.charAt(cursor);
if (char < "a" || char > "z") {
return null;
}
suffix = suffix * LETTER_SCALE + ((char.codePointAt(0) ?? 0) - ("a".codePointAt(0) ?? 0) + 1);
}
return Number(digits) + suffix / (LETTER_SCALE * LETTER_SCALE);
};
export const disorderedRows = function disorderedRows(agenda: string): DisorderedRow[] {
const out: DisorderedRow[] = [];
let held: { value: number; invariant: string } | null = null;
for (const row of agendaRows(agenda)) {
const value = ordinalValue(row.ordinal);
if (value !== null) {
if (held !== null && value < held.value) {
out.push({ after: held.invariant, invariant: row.invariant, ordinal: row.ordinal });
} else {
held = { invariant: row.invariant, value };
}
}
}
return out;
};
export const agendaOrdinalOf = function agendaOrdinalOf(agenda: string, invariant: string): string {
return agendaRows(agenda).find((row) => row.invariant === invariant)?.ordinal ?? "";
};
export const agendaInvariants = function agendaInvariants(agenda: string): string[] {
return agendaRows(agenda).map((row) => row.invariant);
};
export const plannedInvariants = function plannedInvariants(agenda: string): string[] {
return agendaRows(agenda)
.filter((row) => row.planned)
.map((row) => row.invariant);
};
export const admissibleInvariants = function admissibleInvariants(agenda: string, venues: readonly string[]): string[] {
return agendaRows(agenda)
.filter((row) => row.planned && !venues.some((venue) => venue.includes(row.invariant)))
.map((row) => row.invariant);
};
export const nextUnraised = function nextUnraised(agenda: string, venues: readonly string[]): string | null {
return admissibleInvariants(agenda, venues)[0] ?? null;
};