@ascribed/review 0.1.2-next.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/github/marker.d.ts
CHANGED
|
@@ -14,8 +14,6 @@ export interface MarkedSection {
|
|
|
14
14
|
* this, which reading and submitting remove.
|
|
15
15
|
*/
|
|
16
16
|
export declare const PLACEHOLDER = "<!-- ascribe:review -->";
|
|
17
|
-
/** Ends a review's summary when anchored comments follow it. */
|
|
18
|
-
export declare const SUMMARY_END = "<!-- ascribe:summary -->";
|
|
19
17
|
/** `body` without the placeholder summary. */
|
|
20
18
|
export declare function withoutPlaceholder(body: string): string;
|
|
21
19
|
/**
|
package/dist/github/marker.js
CHANGED
|
@@ -21,7 +21,7 @@ const MARKER = /<!-- ascribe:anchor (\S+)(?: build=(\S+))?( quote=text)? -->/g;
|
|
|
21
21
|
*/
|
|
22
22
|
export const PLACEHOLDER = "<!-- ascribe:review -->";
|
|
23
23
|
/** Ends a review's summary when anchored comments follow it. */
|
|
24
|
-
|
|
24
|
+
const SUMMARY_END = "<!-- ascribe:summary -->";
|
|
25
25
|
/** `body` without the placeholder summary. */
|
|
26
26
|
export function withoutPlaceholder(body) {
|
|
27
27
|
return body.split(PLACEHOLDER).join("").trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../src/github/marker.ts"],"names":[],"mappings":"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","sourcesContent":["// Comments GitHub can't anchor to a line go on the pull request's\n// conversation, each ending with a hidden marker naming its block:\n//\n// <!-- ascribe:anchor guides/install.md:12-14 build=site -->\n//\n// Several can share one body (a review's), one after another. A review's\n// summary goes before them, ended by another marker:\n//\n// Looks good, a few notes below.\n//\n// <!-- ascribe:summary -->\n//\n// A comment quotes its block's source, or its text as the page shows it,\n// escaped so GitHub shows it as written; the marker of one that quotes the\n// shown text ends ` quote=text`.\n\n/** One anchored comment, as written in a body. */\nexport interface MarkedSection {\n /** The block's source. */\n source: string;\n build: string | undefined;\n /** The comment, without the quote, the link line, or the marker. */\n body: string;\n /** The block's text the comment quoted, if it did. */\n quote: string | undefined;\n}\n\nconst MARKER = /<!-- ascribe:anchor (\\S+)(?: build=(\\S+))?( quote=text)? -->/g;\n\n/**\n * The summary a pending review starts with. GitHub can't edit the summary of\n * a pending review created without one, so the session's reviews start with\n * this, which reading and submitting remove.\n */\nexport const PLACEHOLDER = \"<!-- ascribe:review -->\";\n\n/** Ends a review's summary when anchored comments follow it. */\nexport const SUMMARY_END = \"<!-- ascribe:summary -->\";\n\n/** `body` without the placeholder summary. */\nexport function withoutPlaceholder(body: string): string {\n return body.split(PLACEHOLDER).join(\"\").trim();\n}\n\n/**\n * The marker for a block. Without a build (or with `\"\"`), the comment is on\n * every build's page. `shown` marks a quote of the shown text.\n */\nexport function marker(source: string, build: string | undefined, shown = false): string {\n return `<!-- ascribe:anchor ${source}${build === undefined || build === \"\" ? \"\" : ` build=${build}`}${shown ? \" quote=text\" : \"\"} -->`;\n}\n\n/** Joins a mention or reference sign to what follows, so GitHub doesn't link it. */\nconst JOINER = \"\\u2060\";\n\n/**\n * Plain text as Markdown that GitHub shows as the text: punctuation\n * escaped, `@name` and `#123` not linked, line breaks and leading spaces\n * kept.\n */\nexport function escapeText(text: string): string {\n const lines = text.split(/\\r?\\n/).map((line) => {\n const indent = /^ */.exec(line)?.[0].length ?? 0;\n const rest = line\n .slice(indent)\n .replace(/[!-/:-@[-`{-~]/g, (c) => (c === \"<\" ? \"<\" : `\\\\${c}`))\n .replace(/[@#]/g, `$&${JOINER}`);\n return \"\\u00a0\".repeat(indent) + rest;\n });\n // A backslash at the end of a line breaks it, but not before a blank line.\n return lines\n .map((line, i) => (line !== \"\" && (lines[i + 1] ?? \"\") !== \"\" ? `${line}\\\\` : line))\n .join(\"\\n\");\n}\n\n/** Text that `escapeText` wrote, as it was. */\nexport function unescapeText(text: string): string {\n return text\n .split(/\\r?\\n/)\n .map((line) => {\n const trailing = /\\\\*$/.exec(line)?.[0].length ?? 0;\n const unbroken = trailing % 2 === 1 ? line.slice(0, -1) : line;\n const indent = /^\\u00a0*/.exec(unbroken)?.[0].length ?? 0;\n return (\n \" \".repeat(indent) +\n unbroken\n .slice(indent)\n .replace(new RegExp(`([@#])${JOINER}`, \"g\"), \"$1\")\n .replace(/\\\\([!-/:-@[-`{-~])|</g, (_, c: string | undefined) => c ?? \"<\")\n );\n })\n .join(\"\\n\");\n}\n\n/**\n * Writes a section: the block's text quoted, the comment, a line linking the\n * block's lines, and the marker.\n */\nexport function formatSection(options: {\n source: string;\n build: string | undefined;\n body: string;\n quote: string | undefined;\n /** Whether `quote` is the block's text as the page shows it, rather than its source. */\n shown?: boolean;\n link: { label: string; url: string } | undefined;\n}): string {\n const parts: string[] = [];\n const shown = options.shown === true;\n if (options.quote !== undefined && options.quote.trim() !== \"\") {\n parts.push(\n (shown ? escapeText(options.quote) : options.quote)\n .split(/\\r?\\n/)\n .map((line) => (line === \"\" ? \">\" : `> ${line}`))\n .join(\"\\n\"),\n );\n }\n parts.push(options.body.trim());\n const end = marker(options.source, options.build, shown);\n parts.push(\n options.link === undefined\n ? end\n : `<sub>On [${options.link.label.replace(/[[\\]]/g, \"\\\\$&\")}](${options.link.url})</sub>\\n${end}`,\n );\n return parts.join(\"\\n\\n\");\n}\n\n/**\n * Splits a body into its summary, its marked sections, and the text after\n * the last marker (`rest`), which isn't anchored either.\n */\nexport function parseSections(text: string): {\n summary: string;\n sections: MarkedSection[];\n rest: string;\n} {\n let body = withoutPlaceholder(text);\n let summary = \"\";\n // The summary ends before the first comment, if it's there at all.\n const end = body.indexOf(SUMMARY_END);\n const first = body.search(new RegExp(MARKER.source));\n if (end >= 0 && (first < 0 || end < first)) {\n summary = body.slice(0, end).trim();\n body = body.slice(end + SUMMARY_END.length).trim();\n }\n const sections: MarkedSection[] = [];\n let start = 0;\n for (const match of body.matchAll(MARKER)) {\n const source = match[1] ?? \"\";\n const text = body.slice(start, match.index);\n start = match.index + match[0].length;\n const { body: comment, quote } = unwrap(text);\n sections.push({\n source,\n build: match[2],\n body: comment,\n quote: quote !== undefined && match[3] !== undefined ? unescapeText(quote) : quote,\n });\n }\n return { summary, sections, rest: body.slice(start).trim() };\n}\n\nfunction unwrap(text: string): { body: string; quote: string | undefined } {\n let rest = text.replace(/\\s*<sub>On \\[[^\\n]*\\]\\([^\\n)]*\\)<\\/sub>\\s*$/, \"\").trim();\n let quote: string | undefined;\n const lines = rest.split(/\\r?\\n/);\n let quoted = 0;\n while (quoted < lines.length && /^>( |$)/.test(lines[quoted] ?? \"\")) quoted++;\n if (quoted > 0 && quoted < lines.length && (lines[quoted] ?? \"\").trim() === \"\") {\n quote = lines\n .slice(0, quoted)\n .map((line) => line.replace(/^> ?/, \"\"))\n .join(\"\\n\");\n rest = lines\n .slice(quoted + 1)\n .join(\"\\n\")\n .trim();\n }\n return { body: rest, quote };\n}\n\n/**\n * Joins a summary and sections into one body: the summary first, so it\n * doesn't read as a remark on the last section.\n */\nexport function joinSections(sections: readonly string[], summary: string | undefined): string {\n const held = sections.filter((part) => part.trim() !== \"\");\n // A marker in the summary would be read as one of Ascribe's.\n const lead = (summary ?? \"\").trim().replace(/(<!--\\s*ascribe):/g, `$1${JOINER}:`);\n if (lead === \"\") return held.join(\"\\n\\n\");\n if (held.length === 0) return lead;\n return [lead, SUMMARY_END, ...held].join(\"\\n\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../src/github/marker.ts"],"names":[],"mappings":"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","sourcesContent":["// Comments GitHub can't anchor to a line go on the pull request's\n// conversation, each ending with a hidden marker naming its block:\n//\n// <!-- ascribe:anchor guides/install.md:12-14 build=site -->\n//\n// Several can share one body (a review's), one after another. A review's\n// summary goes before them, ended by another marker:\n//\n// Looks good, a few notes below.\n//\n// <!-- ascribe:summary -->\n//\n// A comment quotes its block's source, or its text as the page shows it,\n// escaped so GitHub shows it as written; the marker of one that quotes the\n// shown text ends ` quote=text`.\n\n/** One anchored comment, as written in a body. */\nexport interface MarkedSection {\n /** The block's source. */\n source: string;\n build: string | undefined;\n /** The comment, without the quote, the link line, or the marker. */\n body: string;\n /** The block's text the comment quoted, if it did. */\n quote: string | undefined;\n}\n\nconst MARKER = /<!-- ascribe:anchor (\\S+)(?: build=(\\S+))?( quote=text)? -->/g;\n\n/**\n * The summary a pending review starts with. GitHub can't edit the summary of\n * a pending review created without one, so the session's reviews start with\n * this, which reading and submitting remove.\n */\nexport const PLACEHOLDER = \"<!-- ascribe:review -->\";\n\n/** Ends a review's summary when anchored comments follow it. */\nconst SUMMARY_END = \"<!-- ascribe:summary -->\";\n\n/** `body` without the placeholder summary. */\nexport function withoutPlaceholder(body: string): string {\n return body.split(PLACEHOLDER).join(\"\").trim();\n}\n\n/**\n * The marker for a block. Without a build (or with `\"\"`), the comment is on\n * every build's page. `shown` marks a quote of the shown text.\n */\nexport function marker(source: string, build: string | undefined, shown = false): string {\n return `<!-- ascribe:anchor ${source}${build === undefined || build === \"\" ? \"\" : ` build=${build}`}${shown ? \" quote=text\" : \"\"} -->`;\n}\n\n/** Joins a mention or reference sign to what follows, so GitHub doesn't link it. */\nconst JOINER = \"\\u2060\";\n\n/**\n * Plain text as Markdown that GitHub shows as the text: punctuation\n * escaped, `@name` and `#123` not linked, line breaks and leading spaces\n * kept.\n */\nexport function escapeText(text: string): string {\n const lines = text.split(/\\r?\\n/).map((line) => {\n const indent = /^ */.exec(line)?.[0].length ?? 0;\n const rest = line\n .slice(indent)\n .replace(/[!-/:-@[-`{-~]/g, (c) => (c === \"<\" ? \"<\" : `\\\\${c}`))\n .replace(/[@#]/g, `$&${JOINER}`);\n return \"\\u00a0\".repeat(indent) + rest;\n });\n // A backslash at the end of a line breaks it, but not before a blank line.\n return lines\n .map((line, i) => (line !== \"\" && (lines[i + 1] ?? \"\") !== \"\" ? `${line}\\\\` : line))\n .join(\"\\n\");\n}\n\n/** Text that `escapeText` wrote, as it was. */\nexport function unescapeText(text: string): string {\n return text\n .split(/\\r?\\n/)\n .map((line) => {\n const trailing = /\\\\*$/.exec(line)?.[0].length ?? 0;\n const unbroken = trailing % 2 === 1 ? line.slice(0, -1) : line;\n const indent = /^\\u00a0*/.exec(unbroken)?.[0].length ?? 0;\n return (\n \" \".repeat(indent) +\n unbroken\n .slice(indent)\n .replace(new RegExp(`([@#])${JOINER}`, \"g\"), \"$1\")\n .replace(/\\\\([!-/:-@[-`{-~])|</g, (_, c: string | undefined) => c ?? \"<\")\n );\n })\n .join(\"\\n\");\n}\n\n/**\n * Writes a section: the block's text quoted, the comment, a line linking the\n * block's lines, and the marker.\n */\nexport function formatSection(options: {\n source: string;\n build: string | undefined;\n body: string;\n quote: string | undefined;\n /** Whether `quote` is the block's text as the page shows it, rather than its source. */\n shown?: boolean;\n link: { label: string; url: string } | undefined;\n}): string {\n const parts: string[] = [];\n const shown = options.shown === true;\n if (options.quote !== undefined && options.quote.trim() !== \"\") {\n parts.push(\n (shown ? escapeText(options.quote) : options.quote)\n .split(/\\r?\\n/)\n .map((line) => (line === \"\" ? \">\" : `> ${line}`))\n .join(\"\\n\"),\n );\n }\n parts.push(options.body.trim());\n const end = marker(options.source, options.build, shown);\n parts.push(\n options.link === undefined\n ? end\n : `<sub>On [${options.link.label.replace(/[[\\]]/g, \"\\\\$&\")}](${options.link.url})</sub>\\n${end}`,\n );\n return parts.join(\"\\n\\n\");\n}\n\n/**\n * Splits a body into its summary, its marked sections, and the text after\n * the last marker (`rest`), which isn't anchored either.\n */\nexport function parseSections(text: string): {\n summary: string;\n sections: MarkedSection[];\n rest: string;\n} {\n let body = withoutPlaceholder(text);\n let summary = \"\";\n // The summary ends before the first comment, if it's there at all.\n const end = body.indexOf(SUMMARY_END);\n const first = body.search(new RegExp(MARKER.source));\n if (end >= 0 && (first < 0 || end < first)) {\n summary = body.slice(0, end).trim();\n body = body.slice(end + SUMMARY_END.length).trim();\n }\n const sections: MarkedSection[] = [];\n let start = 0;\n for (const match of body.matchAll(MARKER)) {\n const source = match[1] ?? \"\";\n const text = body.slice(start, match.index);\n start = match.index + match[0].length;\n const { body: comment, quote } = unwrap(text);\n sections.push({\n source,\n build: match[2],\n body: comment,\n quote: quote !== undefined && match[3] !== undefined ? unescapeText(quote) : quote,\n });\n }\n return { summary, sections, rest: body.slice(start).trim() };\n}\n\nfunction unwrap(text: string): { body: string; quote: string | undefined } {\n let rest = text.replace(/\\s*<sub>On \\[[^\\n]*\\]\\([^\\n)]*\\)<\\/sub>\\s*$/, \"\").trim();\n let quote: string | undefined;\n const lines = rest.split(/\\r?\\n/);\n let quoted = 0;\n while (quoted < lines.length && /^>( |$)/.test(lines[quoted] ?? \"\")) quoted++;\n if (quoted > 0 && quoted < lines.length && (lines[quoted] ?? \"\").trim() === \"\") {\n quote = lines\n .slice(0, quoted)\n .map((line) => line.replace(/^> ?/, \"\"))\n .join(\"\\n\");\n rest = lines\n .slice(quoted + 1)\n .join(\"\\n\")\n .trim();\n }\n return { body: rest, quote };\n}\n\n/**\n * Joins a summary and sections into one body: the summary first, so it\n * doesn't read as a remark on the last section.\n */\nexport function joinSections(sections: readonly string[], summary: string | undefined): string {\n const held = sections.filter((part) => part.trim() !== \"\");\n // A marker in the summary would be read as one of Ascribe's.\n const lead = (summary ?? \"\").trim().replace(/(<!--\\s*ascribe):/g, `$1${JOINER}:`);\n if (lead === \"\") return held.join(\"\\n\\n\");\n if (held.length === 0) return lead;\n return [lead, SUMMARY_END, ...held].join(\"\\n\\n\");\n}\n"]}
|
package/dist/overlay/text.d.ts
CHANGED
|
@@ -2,8 +2,6 @@ import type { LocatedThread } from "../place/place.js";
|
|
|
2
2
|
import type { Author } from "../shared/types.js";
|
|
3
3
|
/** `"1 comment"`, `"2 comments"`. */
|
|
4
4
|
export declare function plural(count: number, one: string, many?: string): string;
|
|
5
|
-
/** The last segment of a content path. */
|
|
6
|
-
export declare function fileName(path: string): string;
|
|
7
5
|
/** `rollouts.md:28`, or `rollouts.md:28-30`. */
|
|
8
6
|
export declare function linesLabel(path: string, lines: {
|
|
9
7
|
first: number;
|
package/dist/overlay/text.js
CHANGED
|
@@ -3,7 +3,7 @@ export function plural(count, one, many = `${one}s`) {
|
|
|
3
3
|
return `${count} ${count === 1 ? one : many}`;
|
|
4
4
|
}
|
|
5
5
|
/** The last segment of a content path. */
|
|
6
|
-
|
|
6
|
+
function fileName(path) {
|
|
7
7
|
return path.slice(path.lastIndexOf("/") + 1);
|
|
8
8
|
}
|
|
9
9
|
/** `rollouts.md:28`, or `rollouts.md:28-30`. */
|
package/dist/overlay/text.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/overlay/text.ts"],"names":[],"mappings":"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","sourcesContent":["// What the overlay says about threads: where each one is, when a comment was\n// made, and counts in words.\nimport type { LocatedThread } from \"../place/place.js\";\nimport type { Author } from \"../shared/types.js\";\n\n/** `\"1 comment\"`, `\"2 comments\"`. */\nexport function plural(count: number, one: string, many = `${one}s`): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** The last segment of a content path. */\nexport function fileName(path: string): string {\n return path.slice(path.lastIndexOf(\"/\") + 1);\n}\n\n/** `rollouts.md:28`, or `rollouts.md:28-30`. */\nexport function linesLabel(path: string, lines: { first: number; last: number }): string {\n const range = lines.first === lines.last ? `${lines.first}` : `${lines.first}-${lines.last}`;\n return `${fileName(path)}:${range}`;\n}\n\n/** Where a thread is, for its card's header. */\nexport function whereLabel(thread: LocatedThread): string {\n const file = fileName(thread.path);\n if (thread.detached === \"file\") return `On ${file} as a whole`;\n if (thread.detached === \"line-gone\") {\n const line = thread.originalLine ?? thread.line;\n const commit = thread.originalCommit?.slice(0, 7);\n if (line === null) return `Was on ${file}, since removed`;\n return `Was on ${file}, line ${line}${commit ? ` at ${commit}` : \"\"}, since removed`;\n }\n if (thread.lines === undefined) return file;\n if (thread.detached === \"no-block\")\n return `${linesLabel(thread.path, thread.lines)}, not on this page`;\n if (thread.kind === \"review\" && thread.side === \"LEFT\") return file;\n return linesLabel(thread.path, thread.lines);\n}\n\n/** Where a thread is, for a list of them: shorter, and naming removed text. */\nexport function listLabel(thread: LocatedThread): string {\n const file = fileName(thread.path);\n if (thread.detached !== undefined) return `no block, was ${file}`;\n if (thread.kind === \"review\" && thread.side === \"LEFT\") return `removed text in ${file}`;\n return thread.lines === undefined ? file : linesLabel(thread.path, thread.lines);\n}\n\n/** Whether the thread is on removed text. */\nexport function onRemovedText(thread: LocatedThread): boolean {\n return thread.kind === \"review\" && thread.side === \"LEFT\";\n}\n\n/** Whether any comment of the thread is unsent. */\nexport function hasUnsent(thread: LocatedThread): boolean {\n return thread.comments.some((comment) => comment.pending);\n}\n\n/** A comment's author's name, `\"you\"` for the viewer. */\nexport function authorName(author: Author | null, viewer: string): string {\n if (author === null) return \"ghost\";\n return author.login === viewer ? \"you\" : author.login;\n}\n\n/** Two letters standing for an author, for the avatar's place. */\nexport function initials(author: Author | null): string {\n return (\n (author?.login ?? \"?\")\n .replace(/[^A-Za-z0-9]/g, \"\")\n .slice(0, 2)\n .toUpperCase() || \"?\"\n );\n}\n\n/** `\"just now\"`, `\"5 minutes ago\"`, `\"yesterday\"`, or a date. */\nexport function relativeTime(iso: string, now: number): string {\n const then = Date.parse(iso);\n if (Number.isNaN(then)) return \"\";\n const seconds = Math.max(0, Math.round((now - then) / 1000));\n if (seconds < 60) return \"just now\";\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${plural(minutes, \"minute\")} ago`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${plural(hours, \"hour\")} ago`;\n const days = Math.round(hours / 24);\n if (days === 1) return \"yesterday\";\n if (days < 30) return `${days} days ago`;\n return new Date(then).toISOString().slice(0, 10);\n}\n\n/** Elements whose text starts on a line of its own. */\nconst BLOCK_TAGS = new Set([\n \"ADDRESS\",\n \"ARTICLE\",\n \"ASIDE\",\n \"BLOCKQUOTE\",\n \"DD\",\n \"DETAILS\",\n \"DIV\",\n \"DL\",\n \"DT\",\n \"FIGCAPTION\",\n \"FIGURE\",\n \"FOOTER\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n \"HEADER\",\n \"HR\",\n \"LI\",\n \"OL\",\n \"P\",\n \"PRE\",\n \"SECTION\",\n \"SUMMARY\",\n \"TABLE\",\n \"TR\",\n \"UL\",\n]);\n\n/** Classes that hide text from sight but not from screen readers. */\nconst SCREEN_READER_ONLY = [\"sr-only\", \"visually-hidden\", \"sl-sr-only\"];\n\n/** Whether a reader can't see `el`. */\nfunction unseen(el: Element): boolean {\n if (\n el.hasAttribute(\"hidden\") ||\n el.getAttribute(\"aria-hidden\") === \"true\" ||\n SCREEN_READER_ONLY.some((name) => el.classList.contains(name))\n ) {\n return true;\n }\n const style = el.ownerDocument.defaultView?.getComputedStyle(el);\n return style?.display === \"none\" || style?.visibility === \"hidden\";\n}\n\n/**\n * A block's text as a reader sees it, for quoting: links as their text, a\n * line for each paragraph, list item, or row, numbered items with their\n * numbers, images as their alt text, and code as written. What the marks and\n * the overlay add is left out, but for the words a change inserted, and so\n * is anything a reader can't see.\n */\nexport function blockText(block: Element): string {\n // Each line, and whether it's code, which keeps its spaces.\n const lines: { text: string; pre: boolean }[] = [];\n let line = \"\";\n let linePre = false;\n const breakLine = (): void => {\n if (line.trim() !== \"\") lines.push({ text: line, pre: linePre });\n line = \"\";\n linePre = false;\n };\n const walk = (node: Node, pre: boolean): void => {\n if (node.nodeType === 3) {\n const text = node.nodeValue ?? \"\";\n if (!pre) {\n line += text.replace(/\\s+/g, \" \");\n return;\n }\n const [first = \"\", ...rest] = text.split(\"\\n\");\n line += first;\n linePre = true;\n for (const next of rest) {\n lines.push({ text: line, pre: true });\n line = next;\n }\n return;\n }\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toUpperCase();\n if (\n node.hasAttribute(\"data-ascribe-overlay\") ||\n (node.hasAttribute(\"data-ascribe-ui\") && tag !== \"INS\") ||\n [\"SCRIPT\", \"STYLE\", \"TEMPLATE\", \"NOSCRIPT\"].includes(tag) ||\n unseen(node)\n ) {\n return;\n }\n if (tag === \"BR\") {\n breakLine();\n return;\n }\n if (tag === \"IMG\") {\n line += node.getAttribute(\"alt\") ?? \"\";\n return;\n }\n const block = BLOCK_TAGS.has(tag);\n if (block) breakLine();\n if ((tag === \"TD\" || tag === \"TH\") && node.previousElementSibling !== null) line += \" | \";\n if (tag === \"LI\" && node.parentElement?.tagName.toUpperCase() === \"OL\") {\n const list = node.parentElement;\n const start = Number(list.getAttribute(\"start\") ?? \"1\");\n const items = Array.from(list.children).filter((c) => c.tagName.toUpperCase() === \"LI\");\n line += `${(Number.isFinite(start) ? start : 1) + items.indexOf(node)}. `;\n }\n for (const child of Array.from(node.childNodes)) walk(child, pre || tag === \"PRE\");\n if (block) breakLine();\n };\n walk(block, false);\n breakLine();\n return lines.map(({ text, pre }) => (pre ? text.trimEnd() : text.trim())).join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/overlay/text.ts"],"names":[],"mappings":"AAKA,qCAAqC;AACrC,MAAM,UAAU,MAAM,CAAC,KAAa,EAAE,GAAW,EAAE,IAAI,GAAG,GAAG,GAAG,GAAG;IACjE,OAAO,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAChD,CAAC;AAED,0CAA0C;AAC1C,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAsC;IAC7E,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7F,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;AACtC,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,MAAqB;IAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,MAAM,IAAI,aAAa,CAAC;IAC/D,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClD,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,UAAU,IAAI,iBAAiB,CAAC;QAC1D,OAAO,UAAU,IAAI,UAAU,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC;IACvF,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,MAAM,CAAC,QAAQ,KAAK,UAAU;QAChC,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC;IACtE,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpE,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,iBAAiB,IAAI,EAAE,CAAC;IAClE,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,mBAAmB,IAAI,EAAE,CAAC;IACzF,OAAO,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACnF,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC;AAC5D,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,MAAqB,EAAE,MAAc;IAC9D,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACpC,OAAO,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACxD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,QAAQ,CAAC,MAAqB;IAC5C,OAAO,CACL,CAAC,MAAM,EAAE,KAAK,IAAI,GAAG,CAAC;SACnB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,WAAW,EAAE,IAAI,GAAG,CACxB,CAAC;AACJ,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,GAAW;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7D,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,UAAU,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACzC,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACnC,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,GAAG,IAAI,WAAW,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,SAAS;IACT,SAAS;IACT,OAAO;IACP,YAAY;IACZ,IAAI;IACJ,SAAS;IACT,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,GAAG;IACH,KAAK;IACL,SAAS;IACT,SAAS;IACT,OAAO;IACP,IAAI;IACJ,IAAI;CACL,CAAC,CAAC;AAEH,qEAAqE;AACrE,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAExE,uCAAuC;AACvC,SAAS,MAAM,CAAC,EAAW;IACzB,IACE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC;QACzB,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,MAAM;QACzC,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAC9D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACjE,OAAO,KAAK,EAAE,OAAO,KAAK,MAAM,IAAI,KAAK,EAAE,UAAU,KAAK,QAAQ,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,4DAA4D;IAC5D,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,IAAI,GAAG,EAAE,CAAC;QACV,OAAO,GAAG,KAAK,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,IAAU,EAAE,GAAY,EAAQ,EAAE;QAC9C,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAClC,OAAO;YACT,CAAC;YACD,MAAM,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,IAAI,KAAK,CAAC;YACd,OAAO,GAAG,IAAI,CAAC;YACf,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtC,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,YAAY,OAAO,CAAC;YAAE,OAAO;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACvC,IACE,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC;YACzC,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,GAAG,KAAK,KAAK,CAAC;YACvD,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,EACZ,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,SAAS,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QACD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAClB,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK;YAAE,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,sBAAsB,KAAK,IAAI;YAAE,IAAI,IAAI,KAAK,CAAC;QAC1F,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC;YACvE,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC;YAChC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC;YACxF,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5E,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC;QACnF,IAAI,KAAK;YAAE,SAAS,EAAE,CAAC;IACzB,CAAC,CAAC;IACF,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnB,SAAS,EAAE,CAAC;IACZ,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvF,CAAC","sourcesContent":["// What the overlay says about threads: where each one is, when a comment was\n// made, and counts in words.\nimport type { LocatedThread } from \"../place/place.js\";\nimport type { Author } from \"../shared/types.js\";\n\n/** `\"1 comment\"`, `\"2 comments\"`. */\nexport function plural(count: number, one: string, many = `${one}s`): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** The last segment of a content path. */\nfunction fileName(path: string): string {\n return path.slice(path.lastIndexOf(\"/\") + 1);\n}\n\n/** `rollouts.md:28`, or `rollouts.md:28-30`. */\nexport function linesLabel(path: string, lines: { first: number; last: number }): string {\n const range = lines.first === lines.last ? `${lines.first}` : `${lines.first}-${lines.last}`;\n return `${fileName(path)}:${range}`;\n}\n\n/** Where a thread is, for its card's header. */\nexport function whereLabel(thread: LocatedThread): string {\n const file = fileName(thread.path);\n if (thread.detached === \"file\") return `On ${file} as a whole`;\n if (thread.detached === \"line-gone\") {\n const line = thread.originalLine ?? thread.line;\n const commit = thread.originalCommit?.slice(0, 7);\n if (line === null) return `Was on ${file}, since removed`;\n return `Was on ${file}, line ${line}${commit ? ` at ${commit}` : \"\"}, since removed`;\n }\n if (thread.lines === undefined) return file;\n if (thread.detached === \"no-block\")\n return `${linesLabel(thread.path, thread.lines)}, not on this page`;\n if (thread.kind === \"review\" && thread.side === \"LEFT\") return file;\n return linesLabel(thread.path, thread.lines);\n}\n\n/** Where a thread is, for a list of them: shorter, and naming removed text. */\nexport function listLabel(thread: LocatedThread): string {\n const file = fileName(thread.path);\n if (thread.detached !== undefined) return `no block, was ${file}`;\n if (thread.kind === \"review\" && thread.side === \"LEFT\") return `removed text in ${file}`;\n return thread.lines === undefined ? file : linesLabel(thread.path, thread.lines);\n}\n\n/** Whether the thread is on removed text. */\nexport function onRemovedText(thread: LocatedThread): boolean {\n return thread.kind === \"review\" && thread.side === \"LEFT\";\n}\n\n/** Whether any comment of the thread is unsent. */\nexport function hasUnsent(thread: LocatedThread): boolean {\n return thread.comments.some((comment) => comment.pending);\n}\n\n/** A comment's author's name, `\"you\"` for the viewer. */\nexport function authorName(author: Author | null, viewer: string): string {\n if (author === null) return \"ghost\";\n return author.login === viewer ? \"you\" : author.login;\n}\n\n/** Two letters standing for an author, for the avatar's place. */\nexport function initials(author: Author | null): string {\n return (\n (author?.login ?? \"?\")\n .replace(/[^A-Za-z0-9]/g, \"\")\n .slice(0, 2)\n .toUpperCase() || \"?\"\n );\n}\n\n/** `\"just now\"`, `\"5 minutes ago\"`, `\"yesterday\"`, or a date. */\nexport function relativeTime(iso: string, now: number): string {\n const then = Date.parse(iso);\n if (Number.isNaN(then)) return \"\";\n const seconds = Math.max(0, Math.round((now - then) / 1000));\n if (seconds < 60) return \"just now\";\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${plural(minutes, \"minute\")} ago`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${plural(hours, \"hour\")} ago`;\n const days = Math.round(hours / 24);\n if (days === 1) return \"yesterday\";\n if (days < 30) return `${days} days ago`;\n return new Date(then).toISOString().slice(0, 10);\n}\n\n/** Elements whose text starts on a line of its own. */\nconst BLOCK_TAGS = new Set([\n \"ADDRESS\",\n \"ARTICLE\",\n \"ASIDE\",\n \"BLOCKQUOTE\",\n \"DD\",\n \"DETAILS\",\n \"DIV\",\n \"DL\",\n \"DT\",\n \"FIGCAPTION\",\n \"FIGURE\",\n \"FOOTER\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n \"HEADER\",\n \"HR\",\n \"LI\",\n \"OL\",\n \"P\",\n \"PRE\",\n \"SECTION\",\n \"SUMMARY\",\n \"TABLE\",\n \"TR\",\n \"UL\",\n]);\n\n/** Classes that hide text from sight but not from screen readers. */\nconst SCREEN_READER_ONLY = [\"sr-only\", \"visually-hidden\", \"sl-sr-only\"];\n\n/** Whether a reader can't see `el`. */\nfunction unseen(el: Element): boolean {\n if (\n el.hasAttribute(\"hidden\") ||\n el.getAttribute(\"aria-hidden\") === \"true\" ||\n SCREEN_READER_ONLY.some((name) => el.classList.contains(name))\n ) {\n return true;\n }\n const style = el.ownerDocument.defaultView?.getComputedStyle(el);\n return style?.display === \"none\" || style?.visibility === \"hidden\";\n}\n\n/**\n * A block's text as a reader sees it, for quoting: links as their text, a\n * line for each paragraph, list item, or row, numbered items with their\n * numbers, images as their alt text, and code as written. What the marks and\n * the overlay add is left out, but for the words a change inserted, and so\n * is anything a reader can't see.\n */\nexport function blockText(block: Element): string {\n // Each line, and whether it's code, which keeps its spaces.\n const lines: { text: string; pre: boolean }[] = [];\n let line = \"\";\n let linePre = false;\n const breakLine = (): void => {\n if (line.trim() !== \"\") lines.push({ text: line, pre: linePre });\n line = \"\";\n linePre = false;\n };\n const walk = (node: Node, pre: boolean): void => {\n if (node.nodeType === 3) {\n const text = node.nodeValue ?? \"\";\n if (!pre) {\n line += text.replace(/\\s+/g, \" \");\n return;\n }\n const [first = \"\", ...rest] = text.split(\"\\n\");\n line += first;\n linePre = true;\n for (const next of rest) {\n lines.push({ text: line, pre: true });\n line = next;\n }\n return;\n }\n if (!(node instanceof Element)) return;\n const tag = node.tagName.toUpperCase();\n if (\n node.hasAttribute(\"data-ascribe-overlay\") ||\n (node.hasAttribute(\"data-ascribe-ui\") && tag !== \"INS\") ||\n [\"SCRIPT\", \"STYLE\", \"TEMPLATE\", \"NOSCRIPT\"].includes(tag) ||\n unseen(node)\n ) {\n return;\n }\n if (tag === \"BR\") {\n breakLine();\n return;\n }\n if (tag === \"IMG\") {\n line += node.getAttribute(\"alt\") ?? \"\";\n return;\n }\n const block = BLOCK_TAGS.has(tag);\n if (block) breakLine();\n if ((tag === \"TD\" || tag === \"TH\") && node.previousElementSibling !== null) line += \" | \";\n if (tag === \"LI\" && node.parentElement?.tagName.toUpperCase() === \"OL\") {\n const list = node.parentElement;\n const start = Number(list.getAttribute(\"start\") ?? \"1\");\n const items = Array.from(list.children).filter((c) => c.tagName.toUpperCase() === \"LI\");\n line += `${(Number.isFinite(start) ? start : 1) + items.indexOf(node)}. `;\n }\n for (const child of Array.from(node.childNodes)) walk(child, pre || tag === \"PRE\");\n if (block) breakLine();\n };\n walk(block, false);\n breakLine();\n return lines.map(({ text, pre }) => (pre ? text.trimEnd() : text.trim())).join(\"\\n\");\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ascribed/review",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Reviewing Ascribe pages as readers see them: changed blocks marked on the rendered page, and a pull request's review threads beside them.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=24"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@ascribed/elements": "0.
|
|
43
|
+
"@ascribed/elements": "0.2.0",
|
|
44
44
|
"@types/node": "^24.0.0",
|
|
45
45
|
"esbuild": "^0.28.2",
|
|
46
46
|
"jsdom": "^30.1.1"
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"smol-toml": "^1.9.0"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "99076558e4ae83f57ebfdfcf521b7d350655a385",
|
|
55
54
|
"scripts": {
|
|
56
55
|
"build": "tsc -p tsconfig.build.json",
|
|
57
56
|
"typecheck": "tsc --noEmit",
|