import { Stream } from "../../src/Stream"; import { Vector } from "../../src/Vector"; import { readFileSync } from "fs"; export function requireNotNull(x:T|null): T { if (x === null) { throw "requireNotNull got null!"; } return x; } export function indent(count: number): string { return "\n" + Stream.continually(()=>"\t") .take(count).mkString(""); } export type LineByIndent = {contents:string,indent:number}; export type LinesByIndent = Vector; export function fileGetLinesByIndent(fname: string): LinesByIndent { const contents = readFileSync(fname).toString(); return Vector.ofIterable(contents.split("\n")) .map(l => ({indent: l.length-l.trim().length, contents: l})); } /** * extract a tag from the linesbyindent. You tell me the tag name, * how to match the start tag, I return to you the rows before, the rows within that * tag (depth>=tagDepth) and the rows after. * returns [before, atTag, after] */ export function linesByIndentGetTagContents( lines: LinesByIndent, tagName: string, startPredicate: (line:string)=>boolean): [LinesByIndent, LinesByIndent, LinesByIndent] { // split the parts before & after using string the predicate & indentation. const [before, atTag] = lines.span(l => !startPredicate(l.contents)); const indentAtTag = atTag.head().getOrThrow().indent; const [tagContents,after] = atTag.span(l => (l.indent > indentAtTag) || (l.indent <= indentAtTag && l.contents.indexOf(" l.contents).mkString("\n"); }