diff options
Diffstat (limited to 'node_modules/@bcoe/v8-coverage/dist/lib/_src/ascii.ts')
-rw-r--r-- | node_modules/@bcoe/v8-coverage/dist/lib/_src/ascii.ts | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/node_modules/@bcoe/v8-coverage/dist/lib/_src/ascii.ts b/node_modules/@bcoe/v8-coverage/dist/lib/_src/ascii.ts new file mode 100644 index 0000000..5a52b91 --- /dev/null +++ b/node_modules/@bcoe/v8-coverage/dist/lib/_src/ascii.ts @@ -0,0 +1,146 @@ +import { compareRangeCovs } from "./compare"; +import { RangeCov } from "./types"; + +interface ReadonlyRangeTree { + readonly start: number; + readonly end: number; + readonly count: number; + readonly children: ReadonlyRangeTree[]; +} + +export function emitForest(trees: ReadonlyArray<ReadonlyRangeTree>): string { + return emitForestLines(trees).join("\n"); +} + +export function emitForestLines(trees: ReadonlyArray<ReadonlyRangeTree>): string[] { + const colMap: Map<number, number> = getColMap(trees); + const header: string = emitOffsets(colMap); + return [header, ...trees.map(tree => emitTree(tree, colMap).join("\n"))]; +} + +function getColMap(trees: Iterable<ReadonlyRangeTree>): Map<number, number> { + const eventSet: Set<number> = new Set(); + for (const tree of trees) { + const stack: ReadonlyRangeTree[] = [tree]; + while (stack.length > 0) { + const cur: ReadonlyRangeTree = stack.pop()!; + eventSet.add(cur.start); + eventSet.add(cur.end); + for (const child of cur.children) { + stack.push(child); + } + } + } + const events: number[] = [...eventSet]; + events.sort((a, b) => a - b); + let maxDigits: number = 1; + for (const event of events) { + maxDigits = Math.max(maxDigits, event.toString(10).length); + } + const colWidth: number = maxDigits + 3; + const colMap: Map<number, number> = new Map(); + for (const [i, event] of events.entries()) { + colMap.set(event, i * colWidth); + } + return colMap; +} + +function emitTree(tree: ReadonlyRangeTree, colMap: Map<number, number>): string[] { + const layers: ReadonlyRangeTree[][] = []; + let nextLayer: ReadonlyRangeTree[] = [tree]; + while (nextLayer.length > 0) { + const layer: ReadonlyRangeTree[] = nextLayer; + layers.push(layer); + nextLayer = []; + for (const node of layer) { + for (const child of node.children) { + nextLayer.push(child); + } + } + } + return layers.map(layer => emitTreeLayer(layer, colMap)); +} + +export function parseFunctionRanges(text: string, offsetMap: Map<number, number>): RangeCov[] { + const result: RangeCov[] = []; + for (const line of text.split("\n")) { + for (const range of parseTreeLayer(line, offsetMap)) { + result.push(range); + } + } + result.sort(compareRangeCovs); + return result; +} + +/** + * + * @param layer Sorted list of disjoint trees. + * @param colMap + */ +function emitTreeLayer(layer: ReadonlyRangeTree[], colMap: Map<number, number>): string { + const line: string[] = []; + let curIdx: number = 0; + for (const {start, end, count} of layer) { + const startIdx: number = colMap.get(start)!; + const endIdx: number = colMap.get(end)!; + if (startIdx > curIdx) { + line.push(" ".repeat(startIdx - curIdx)); + } + line.push(emitRange(count, endIdx - startIdx)); + curIdx = endIdx; + } + return line.join(""); +} + +function parseTreeLayer(text: string, offsetMap: Map<number, number>): RangeCov[] { + const result: RangeCov[] = []; + const regex: RegExp = /\[(\d+)-*\)/gs; + while (true) { + const match: RegExpMatchArray | null = regex.exec(text); + if (match === null) { + break; + } + const startIdx: number = match.index!; + const endIdx: number = startIdx + match[0].length; + const count: number = parseInt(match[1], 10); + const startOffset: number | undefined = offsetMap.get(startIdx); + const endOffset: number | undefined = offsetMap.get(endIdx); + if (startOffset === undefined || endOffset === undefined) { + throw new Error(`Invalid offsets for: ${JSON.stringify(text)}`); + } + result.push({startOffset, endOffset, count}); + } + return result; +} + +function emitRange(count: number, len: number): string { + const rangeStart: string = `[${count.toString(10)}`; + const rangeEnd: string = ")"; + const hyphensLen: number = len - (rangeStart.length + rangeEnd.length); + const hyphens: string = "-".repeat(Math.max(0, hyphensLen)); + return `${rangeStart}${hyphens}${rangeEnd}`; +} + +function emitOffsets(colMap: Map<number, number>): string { + let line: string = ""; + for (const [event, col] of colMap) { + if (line.length < col) { + line += " ".repeat(col - line.length); + } + line += event.toString(10); + } + return line; +} + +export function parseOffsets(text: string): Map<number, number> { + const result: Map<number, number> = new Map(); + const regex: RegExp = /\d+/gs; + while (true) { + const match: RegExpExecArray | null = regex.exec(text); + if (match === null) { + break; + } + result.set(match.index, parseInt(match[0], 10)); + } + return result; +} |