UNPKG

klog.js

Version:

A JavaScript implementation of the Klog time tracking file format

65 lines (64 loc) 2.78 kB
// TODO: check how Klog handles summaries (are new-lines kept as-is, or are // they stripped and then auto-added in serialisation?) // Regex for extracting parts of a tag into named groups. const tagRe = /#(?<name>[\p{L}\d_-]+)(?:=(?<value>(?:"[^"]*")|(?:'[^']*')|(?:[\p{L}\d_-]*)))?/gu; // Regex for splitting a string into parts that have tags and regular text separate. const splitRe = /(#(?:[\p{L}\d_-]+)(?:=(?:(?:"[^"]*")|(?:'[^']*')|(?:[\p{L}\d_-]*)))?)/gu; // TODO: throw if any lines with blank characters export class Summary { lines; // TODO: maybe take a rest parameter instead constructor(text) { this.lines = typeof text === "string" ? text.split("\n") : text; } setText(text) { this.lines = text.split("\n"); } get tags() { const tags = []; for (const line of this.lines) { const matches = line.matchAll(tagRe); if (!matches) continue; for (const tag of matches) { const toPush = { name: tag.groups.name }; if (tag.groups.value) toPush.value = tag.groups.value; tags.push(toPush); } } return tags; } /** Split the summary into a list of text nodes and tag nodes, useful for rich * text formatting. */ splitOnTags() { const nodes = []; const textSplitOnTags = this.lines.map((x) => x.split(splitRe)); for (const [lineIndex, line] of textSplitOnTags.entries()) { for (const [index, value] of line.entries()) { // We don't care for empty text nodes at the start or end of each line. const isEmptyTextAtFirstIndex = index === 0 && value === ""; const isEmptyTextAtLastIndex = index === line.length - 1 && value === ""; if (isEmptyTextAtFirstIndex || isEmptyTextAtLastIndex) continue; const match = tagRe.exec(value); if (!match) { nodes.push({ type: "text", value }); continue; } const toPush = { type: "tag", name: match.groups.name }; if (match.groups.value) toPush.value = match.groups.value; nodes.push(toPush); } if (lineIndex !== textSplitOnTags.length - 1) nodes.push({ type: "end-of-line" }); } return nodes; } toString(indentation = null, startOnNextLine = false) { const indent = (l, i) => i !== 0 || startOnNextLine ? `${(indentation || "").repeat(2)}${l}` : l; return ((startOnNextLine ? "\n" : "") + this.lines.map((l, i) => indent(l, i)).join("\n")); } }