@mrsf/marp-mrsf 0.4.8 → 0.4.9
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/browser.js +14 -4
- package/dist/browser.js.map +2 -2
- package/dist/index.js +14 -4
- package/dist/index.js.map +2 -2
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
// ../shared/dist/comments.js
|
|
2
|
+
function getExtensionFields(comment) {
|
|
3
|
+
const extensions = {};
|
|
4
|
+
for (const [key, value] of Object.entries(comment)) {
|
|
5
|
+
if (key.startsWith("x_")) {
|
|
6
|
+
extensions[key] = value;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return extensions;
|
|
10
|
+
}
|
|
2
11
|
function toSlimComments(doc) {
|
|
3
12
|
return doc.comments.map((c) => ({
|
|
4
13
|
id: c.id,
|
|
5
14
|
author: c.author || "Unknown",
|
|
6
15
|
text: c.text || "",
|
|
7
16
|
line: c.line ?? null,
|
|
8
|
-
x_page: typeof c.x_page === "number" ? c.x_page : null,
|
|
9
17
|
end_line: c.end_line ?? null,
|
|
10
18
|
start_column: c.start_column ?? null,
|
|
11
19
|
end_column: c.end_column ?? null,
|
|
@@ -14,7 +22,8 @@ function toSlimComments(doc) {
|
|
|
14
22
|
reply_to: c.reply_to || null,
|
|
15
23
|
severity: c.severity || null,
|
|
16
24
|
type: c.type || null,
|
|
17
|
-
timestamp: c.timestamp || null
|
|
25
|
+
timestamp: c.timestamp || null,
|
|
26
|
+
...getExtensionFields(c)
|
|
18
27
|
}));
|
|
19
28
|
}
|
|
20
29
|
function groupByLine(comments) {
|
|
@@ -87,10 +96,11 @@ function mergePageScopedThreads(lineMap, comments, pageLineMap) {
|
|
|
87
96
|
replyMap.set(comment.reply_to, replies);
|
|
88
97
|
}
|
|
89
98
|
for (const comment of comments) {
|
|
90
|
-
|
|
99
|
+
const pageNumber = typeof comment.x_page === "number" ? comment.x_page : null;
|
|
100
|
+
if (comment.reply_to || comment.line != null || pageNumber == null) {
|
|
91
101
|
continue;
|
|
92
102
|
}
|
|
93
|
-
const displayLine = pageLineMap.get(
|
|
103
|
+
const displayLine = pageLineMap.get(pageNumber);
|
|
94
104
|
if (displayLine == null) {
|
|
95
105
|
continue;
|
|
96
106
|
}
|
package/dist/browser.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../shared/src/comments.ts", "../src/rules/core.ts", "../src/rules/renderer.ts", "../src/shared.ts", "../src/browser.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Shared comment loading and grouping logic for MRSF rendering plugins.\n */\n\nimport type { MrsfDocument } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\n\nexport type { CommentLoader };\n\n/**\n * Convert an MrsfDocument into a slim comment array.\n */\nexport function toSlimComments(doc: MrsfDocument): SlimComment[] {\n return doc.comments.map((c) => ({\n id: c.id,\n author: c.author || \"Unknown\",\n text: c.text || \"\",\n line: c.line ?? null,\n x_page: typeof c.x_page === \"number\" ? c.x_page : null,\n end_line: c.end_line ?? null,\n start_column: c.start_column ?? null,\n end_column: c.end_column ?? null,\n selected_text: c.selected_text || null,\n resolved: !!c.resolved,\n reply_to: c.reply_to || null,\n severity: c.severity || null,\n type: c.type || null,\n timestamp: c.timestamp || null,\n }));\n}\n\n/**\n * Group comments by line number, threading replies under parents.\n */\nexport function groupByLine(comments: SlimComment[]): LineMap {\n const rootComments = comments.filter((c) => !c.reply_to && c.line != null);\n const replies = comments.filter((c) => c.reply_to);\n\n const replyMap = new Map<string, SlimComment[]>();\n for (const r of replies) {\n const list = replyMap.get(r.reply_to!) || [];\n list.push(r);\n replyMap.set(r.reply_to!, list);\n }\n\n const lineMap: LineMap = new Map();\n for (const c of rootComments) {\n const line = c.line!;\n const threads = lineMap.get(line) || [];\n threads.push({\n comment: c,\n replies: replyMap.get(c.id) || [],\n });\n lineMap.set(line, threads);\n }\n\n return lineMap;\n}\n\n/**\n * Resolve options into a filtered LineMap ready for rendering.\n * Returns null if there are no comments to render.\n */\nexport function resolveComments(\n loader: CommentLoader,\n options: MrsfPluginOptions,\n env?: unknown,\n): { lineMap: LineMap; comments: SlimComment[] } | null {\n const showResolved = options.showResolved ?? true;\n\n const doc = loader(options, env);\n if (!doc || !doc.comments || doc.comments.length === 0) {\n return null;\n }\n\n let comments = toSlimComments(doc);\n if (!showResolved) {\n comments = comments.filter((c) => !c.resolved);\n }\n\n if (comments.length === 0) return null;\n\n const lineMap = groupByLine(comments);\n return { lineMap, comments };\n}\n", "import type Token from \"markdown-it/lib/token.mjs\";\nimport type StateCore from \"markdown-it/lib/rules_core/state_core.mjs\";\nimport type { LineMap, CommentThread, SlimComment } from \"../types.js\";\n\nexport interface CoreRuleOptions {\n lineHighlight?: boolean;\n}\n\nexport interface ResolvedCommentData {\n lineMap: LineMap;\n comments: SlimComment[];\n}\n\nfunction buildPageLineMap(tokens: Token[]): Map<number, number> {\n const pageLineMap = new Map<number, number>();\n let pageNumber = 0;\n\n for (const token of tokens) {\n if (token.type !== \"marpit_slide_open\" || !token.map) {\n continue;\n }\n\n pageNumber += 1;\n pageLineMap.set(pageNumber, token.map[0] + 1);\n }\n\n return pageLineMap;\n}\n\nfunction mergePageScopedThreads(\n lineMap: LineMap,\n comments: SlimComment[],\n pageLineMap: Map<number, number>,\n): LineMap {\n const merged: LineMap = new Map(\n Array.from(lineMap.entries(), ([line, threads]) => [\n line,\n threads.map((thread) => ({\n comment: thread.comment,\n replies: [...thread.replies],\n })),\n ]),\n );\n const replyMap = new Map<string, SlimComment[]>();\n\n for (const comment of comments) {\n if (!comment.reply_to) {\n continue;\n }\n\n const replies = replyMap.get(comment.reply_to) || [];\n replies.push(comment);\n replyMap.set(comment.reply_to, replies);\n }\n\n for (const comment of comments) {\n if (comment.reply_to || comment.line != null || comment.x_page == null) {\n continue;\n }\n\n const displayLine = pageLineMap.get(comment.x_page);\n if (displayLine == null) {\n continue;\n }\n\n const threadComment: SlimComment = {\n ...comment,\n line: displayLine,\n };\n const threadReplies = (replyMap.get(comment.id) || []).map((reply) => ({\n ...reply,\n line: reply.line ?? displayLine,\n }));\n const threads = merged.get(displayLine) || [];\n\n threads.push({\n comment: threadComment,\n replies: threadReplies,\n });\n merged.set(displayLine, threads);\n }\n\n return merged;\n}\n\nexport function installCoreRule(\n md: { core: { ruler: { push: (name: string, fn: (state: StateCore) => void) => void } } },\n resolveComments: (state: StateCore) => ResolvedCommentData | null,\n options: CoreRuleOptions = {},\n): void {\n md.core.ruler.push(\"mrsf_inject\", (state: StateCore) => {\n const result = resolveComments(state);\n if (!result) return;\n\n const pageLineMap = buildPageLineMap(state.tokens);\n const lineMap = mergePageScopedThreads(result.lineMap, result.comments, pageLineMap);\n const tokens = state.tokens;\n const TokenCtor = state.Token;\n const processed = new Set<number>();\n\n for (let i = tokens.length - 1; i >= 0; i--) {\n const token = tokens[i];\n const map = token.map;\n if (!map) continue;\n\n if (token.type === \"inline\") continue;\n\n const startLine1 = map[0] + 1;\n const endLine1 = map[1];\n token.attrSet(\"data-mrsf-line\", String(startLine1));\n token.attrSet(\"data-mrsf-start-line\", String(startLine1));\n token.attrSet(\"data-mrsf-end-line\", String(endLine1));\n\n for (let line0 = map[0]; line0 < map[1]; line0++) {\n const line = line0 + 1;\n if (processed.has(line)) continue;\n processed.add(line);\n\n const threads = lineMap.get(line);\n if (threads && threads.length > 0) {\n if (options.lineHighlight) {\n const existingClass = token.attrGet(\"class\") || \"\";\n if (!existingClass.includes(\"mrsf-line-highlight\")) {\n token.attrSet(\n \"class\",\n existingClass ? `${existingClass} mrsf-line-highlight` : \"mrsf-line-highlight\",\n );\n }\n }\n token.attrSet(\"data-mrsf-line\", String(line));\n }\n }\n }\n\n const allThreads: CommentThread[] = [];\n for (const threads of lineMap.values()) {\n allThreads.push(...threads);\n }\n if (allThreads.length > 0) {\n const scriptToken = new TokenCtor(\"mrsf_data_script\", \"\", 0);\n scriptToken.meta = { threads: allThreads };\n tokens.push(scriptToken);\n }\n });\n}", "import type { CommentThread } from \"../types.js\";\n\nexport interface RendererRuleOptions {\n dataContainer?: \"script\" | \"element\";\n dataElementId?: string;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nexport function installRendererRules(\n md: { renderer: { rules: Record<string, ((...args: any[]) => string) | undefined> } },\n options: RendererRuleOptions = {},\n): void {\n md.renderer.rules[\"mrsf_data_script\"] = (\n tokens: { meta: { threads: CommentThread[] } }[],\n idx: number,\n ): string => {\n const { threads } = tokens[idx].meta;\n const payload = JSON.stringify({ threads });\n if (options.dataContainer === \"element\") {\n const elementId = options.dataElementId || \"mrsf-comment-data\";\n return `<div id=\"${escapeAttribute(elementId)}\" data-mrsf-json=\"${escapeAttribute(payload)}\" aria-hidden=\"true\"></div>`;\n }\n\n const data = payload.replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/mrsf+json\">${data}</script>`;\n };\n}", "import type MarkdownIt from \"markdown-it\";\nimport { resolveComments } from \"@mrsf/plugin-shared\";\nimport type { CommentLoader, MrsfPluginOptions } from \"./types.js\";\nimport { installCoreRule } from \"./rules/core.js\";\nimport { installRendererRules } from \"./rules/renderer.js\";\n\nexport interface MarpitRenderResult {\n html: string | string[];\n css: string;\n comments?: string[][];\n}\n\nexport interface MarpitLike {\n render(markdown: string, env?: Record<string, unknown>): MarpitRenderResult;\n use(plugin: (context: unknown, ...params: unknown[]) => unknown, ...params: unknown[]): unknown;\n markdown?: MarkdownIt;\n}\n\nexport interface MarpitPluginContext {\n marpit?: MarpitLike;\n markdown?: MarkdownIt;\n}\n\nexport type MrsfMarpPlugin = (\n context: MarpitPluginContext,\n options?: MrsfPluginOptions,\n) => void;\n\nconst patchedRenderers = new WeakSet<MarpitLike>();\n\nexport function installMarkdownMrsfPlugin(\n md: MarkdownIt,\n options: MrsfPluginOptions,\n loader: CommentLoader,\n): void {\n installCoreRule(\n md,\n (state) => resolveComments(loader, options, state.env),\n { lineHighlight: options.lineHighlight ?? false },\n );\n installRendererRules(md, {\n dataContainer: options.dataContainer,\n dataElementId: options.dataElementId,\n });\n}\n\nexport function createMarpPlugin(loader: CommentLoader): MrsfMarpPlugin {\n return function mrsfPlugin(\n context: MarpitPluginContext,\n options: MrsfPluginOptions = {},\n ): void {\n const markdown = context.markdown ?? context.marpit?.markdown;\n if (markdown) {\n installMarkdownMrsfPlugin(markdown, options, loader);\n }\n\n if (!context.marpit) {\n return;\n }\n\n patchRender(context.marpit, options);\n };\n}\n\nfunction patchRender(marpit: MarpitLike, options: MrsfPluginOptions): void {\n if (patchedRenderers.has(marpit)) {\n return;\n }\n\n const originalRender = marpit.render.bind(marpit);\n marpit.render = (markdown: string, env?: Record<string, unknown>): MarpitRenderResult => {\n const result = originalRender(markdown, env);\n const fallbackHtml = Array.isArray(result.html)\n ? originalRender(markdown, { ...(env ?? {}), htmlAsArray: false }).html\n : null;\n\n return {\n ...result,\n html: normalizeRenderedHtml(result.html, options, typeof fallbackHtml === \"string\" ? fallbackHtml : null),\n };\n };\n\n patchedRenderers.add(marpit);\n}\n\nconst SCRIPT_RE = /<script type=\"application\\/mrsf\\+json\">[\\s\\S]*?<\\/script>/g;\n\nfunction normalizeRenderedHtml(\n html: string | string[],\n options: MrsfPluginOptions,\n fallbackHtml: string | null = null,\n): string | string[] {\n if (Array.isArray(html)) {\n let payload: string | null = null;\n\n const pages = html.map((pageHtml, index) => {\n const extracted = extractPayloads(pageHtml);\n if (extracted.payloads.length > 0) {\n payload = extracted.payloads[extracted.payloads.length - 1];\n }\n\n return annotatePageFragment(extracted.html, index + 1, options);\n });\n\n if (!payload && fallbackHtml) {\n const fallback = extractPayloads(fallbackHtml);\n payload = fallback.payloads[fallback.payloads.length - 1] ?? null;\n }\n\n if (payload && pages.length > 0) {\n pages[pages.length - 1] += payload;\n }\n\n return pages;\n }\n\n const extracted = extractPayloads(html);\n const annotated = annotateSectionTags(extracted.html, options);\n\n if (extracted.payloads.length === 0) {\n return annotated;\n }\n\n const payload = extracted.payloads[extracted.payloads.length - 1];\n return insertPayloadIntoContainer(annotated, payload);\n}\n\nfunction extractPayloads(html: string): { html: string; payloads: string[] } {\n const payloads = html.match(SCRIPT_RE) ?? [];\n return {\n html: html.replace(SCRIPT_RE, \"\"),\n payloads,\n };\n}\n\nfunction annotatePageFragment(\n html: string,\n pageNumber: number,\n options: MrsfPluginOptions,\n): string {\n const attrName = resolvePageAttributeName(options);\n return html.replace(/<([a-zA-Z][\\w:-]*)(\\s|>)/, `<$1 ${attrName}=\"${pageNumber}\"$2`);\n}\n\nfunction annotateSectionTags(html: string, options: MrsfPluginOptions): string {\n if (html.includes(\"<svg\") && html.includes(\"data-marpit-svg\")) {\n return annotateSvgPageTags(html, options);\n }\n\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<section(\\s|>)/g, (_match, suffix: string) => {\n pageNumber += 1;\n return `<section ${attrName}=\"${pageNumber}\"${suffix}`;\n });\n}\n\nfunction annotateSvgPageTags(html: string, options: MrsfPluginOptions): string {\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<svg\\b([^>]*)>/g, (_match, attrs: string) => {\n if (!attrs.includes(\"data-marpit-svg\")) {\n return `<svg${attrs}>`;\n }\n\n pageNumber += 1;\n return `<svg${attrs} ${attrName}=\"${pageNumber}\">`;\n });\n}\n\nfunction resolvePageAttributeName(_options: MrsfPluginOptions): string {\n return \"data-mrsf-page\";\n}\n\nfunction insertPayloadIntoContainer(html: string, payload: string): string {\n const closingTagIndex = html.lastIndexOf(\"</\");\n if (closingTagIndex === -1) {\n return html + payload;\n }\n\n return html.slice(0, closingTagIndex) + payload + html.slice(closingTagIndex);\n}", "import type { MrsfPluginOptions } from \"./types.js\";\nimport { createMarpPlugin } from \"./shared.js\";\nimport type { MrsfMarpPlugin } from \"./shared.js\";\n\nexport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\nexport type { MrsfMarpPlugin, MarpitLike, MarpitPluginContext } from \"./shared.js\";\n\nexport const mrsfPlugin: MrsfMarpPlugin = createMarpPlugin((options: MrsfPluginOptions, env?: unknown) => {\n if (options.comments) {\n return options.comments;\n }\n\n if (options.loader) {\n try {\n return options.loader(options, env);\n } catch {\n return null;\n }\n }\n\n if (options.sidecarPath || options.documentPath) {\n console.warn(\n \"[@mrsf/marp-mrsf] sidecarPath and documentPath require Node.js. \" +\n \"Use `comments` or `loader` options in browser environments.\",\n );\n }\n\n return null;\n});\n\nexport default mrsfPlugin;"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * Shared comment loading and grouping logic for MRSF rendering plugins.\n */\n\nimport type { MrsfDocument } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\n\nexport type { CommentLoader };\n\nfunction getExtensionFields(comment: Record<string, unknown>): Record<`x_${string}`, unknown> {\n const extensions: Record<`x_${string}`, unknown> = {};\n\n for (const [key, value] of Object.entries(comment)) {\n if (key.startsWith(\"x_\")) {\n extensions[key as `x_${string}`] = value;\n }\n }\n\n return extensions;\n}\n\n/**\n * Convert an MrsfDocument into a slim comment array.\n */\nexport function toSlimComments(doc: MrsfDocument): SlimComment[] {\n return doc.comments.map((c) => ({\n id: c.id,\n author: c.author || \"Unknown\",\n text: c.text || \"\",\n line: c.line ?? null,\n end_line: c.end_line ?? null,\n start_column: c.start_column ?? null,\n end_column: c.end_column ?? null,\n selected_text: c.selected_text || null,\n resolved: !!c.resolved,\n reply_to: c.reply_to || null,\n severity: c.severity || null,\n type: c.type || null,\n timestamp: c.timestamp || null,\n ...getExtensionFields(c as Record<string, unknown>),\n }));\n}\n\n/**\n * Group comments by line number, threading replies under parents.\n */\nexport function groupByLine(comments: SlimComment[]): LineMap {\n const rootComments = comments.filter((c) => !c.reply_to && c.line != null);\n const replies = comments.filter((c) => c.reply_to);\n\n const replyMap = new Map<string, SlimComment[]>();\n for (const r of replies) {\n const list = replyMap.get(r.reply_to!) || [];\n list.push(r);\n replyMap.set(r.reply_to!, list);\n }\n\n const lineMap: LineMap = new Map();\n for (const c of rootComments) {\n const line = c.line!;\n const threads = lineMap.get(line) || [];\n threads.push({\n comment: c,\n replies: replyMap.get(c.id) || [],\n });\n lineMap.set(line, threads);\n }\n\n return lineMap;\n}\n\n/**\n * Resolve options into a filtered LineMap ready for rendering.\n * Returns null if there are no comments to render.\n */\nexport function resolveComments(\n loader: CommentLoader,\n options: MrsfPluginOptions,\n env?: unknown,\n): { lineMap: LineMap; comments: SlimComment[] } | null {\n const showResolved = options.showResolved ?? true;\n\n const doc = loader(options, env);\n if (!doc || !doc.comments || doc.comments.length === 0) {\n return null;\n }\n\n let comments = toSlimComments(doc);\n if (!showResolved) {\n comments = comments.filter((c) => !c.resolved);\n }\n\n if (comments.length === 0) return null;\n\n const lineMap = groupByLine(comments);\n return { lineMap, comments };\n}\n", "import type Token from \"markdown-it/lib/token.mjs\";\nimport type StateCore from \"markdown-it/lib/rules_core/state_core.mjs\";\nimport type { LineMap, CommentThread, SlimComment } from \"../types.js\";\n\nexport interface CoreRuleOptions {\n lineHighlight?: boolean;\n}\n\nexport interface ResolvedCommentData {\n lineMap: LineMap;\n comments: SlimComment[];\n}\n\nfunction buildPageLineMap(tokens: Token[]): Map<number, number> {\n const pageLineMap = new Map<number, number>();\n let pageNumber = 0;\n\n for (const token of tokens) {\n if (token.type !== \"marpit_slide_open\" || !token.map) {\n continue;\n }\n\n pageNumber += 1;\n pageLineMap.set(pageNumber, token.map[0] + 1);\n }\n\n return pageLineMap;\n}\n\nfunction mergePageScopedThreads(\n lineMap: LineMap,\n comments: SlimComment[],\n pageLineMap: Map<number, number>,\n): LineMap {\n const merged: LineMap = new Map(\n Array.from(lineMap.entries(), ([line, threads]) => [\n line,\n threads.map((thread) => ({\n comment: thread.comment,\n replies: [...thread.replies],\n })),\n ]),\n );\n const replyMap = new Map<string, SlimComment[]>();\n\n for (const comment of comments) {\n if (!comment.reply_to) {\n continue;\n }\n\n const replies = replyMap.get(comment.reply_to) || [];\n replies.push(comment);\n replyMap.set(comment.reply_to, replies);\n }\n\n for (const comment of comments) {\n const pageNumber = typeof comment.x_page === \"number\" ? comment.x_page : null;\n\n if (comment.reply_to || comment.line != null || pageNumber == null) {\n continue;\n }\n\n const displayLine = pageLineMap.get(pageNumber);\n if (displayLine == null) {\n continue;\n }\n\n const threadComment: SlimComment = {\n ...comment,\n line: displayLine,\n };\n const threadReplies = (replyMap.get(comment.id) || []).map((reply) => ({\n ...reply,\n line: reply.line ?? displayLine,\n }));\n const threads = merged.get(displayLine) || [];\n\n threads.push({\n comment: threadComment,\n replies: threadReplies,\n });\n merged.set(displayLine, threads);\n }\n\n return merged;\n}\n\nexport function installCoreRule(\n md: { core: { ruler: { push: (name: string, fn: (state: StateCore) => void) => void } } },\n resolveComments: (state: StateCore) => ResolvedCommentData | null,\n options: CoreRuleOptions = {},\n): void {\n md.core.ruler.push(\"mrsf_inject\", (state: StateCore) => {\n const result = resolveComments(state);\n if (!result) return;\n\n const pageLineMap = buildPageLineMap(state.tokens);\n const lineMap = mergePageScopedThreads(result.lineMap, result.comments, pageLineMap);\n const tokens = state.tokens;\n const TokenCtor = state.Token;\n const processed = new Set<number>();\n\n for (let i = tokens.length - 1; i >= 0; i--) {\n const token = tokens[i];\n const map = token.map;\n if (!map) continue;\n\n if (token.type === \"inline\") continue;\n\n const startLine1 = map[0] + 1;\n const endLine1 = map[1];\n token.attrSet(\"data-mrsf-line\", String(startLine1));\n token.attrSet(\"data-mrsf-start-line\", String(startLine1));\n token.attrSet(\"data-mrsf-end-line\", String(endLine1));\n\n for (let line0 = map[0]; line0 < map[1]; line0++) {\n const line = line0 + 1;\n if (processed.has(line)) continue;\n processed.add(line);\n\n const threads = lineMap.get(line);\n if (threads && threads.length > 0) {\n if (options.lineHighlight) {\n const existingClass = token.attrGet(\"class\") || \"\";\n if (!existingClass.includes(\"mrsf-line-highlight\")) {\n token.attrSet(\n \"class\",\n existingClass ? `${existingClass} mrsf-line-highlight` : \"mrsf-line-highlight\",\n );\n }\n }\n token.attrSet(\"data-mrsf-line\", String(line));\n }\n }\n }\n\n const allThreads: CommentThread[] = [];\n for (const threads of lineMap.values()) {\n allThreads.push(...threads);\n }\n if (allThreads.length > 0) {\n const scriptToken = new TokenCtor(\"mrsf_data_script\", \"\", 0);\n scriptToken.meta = { threads: allThreads };\n tokens.push(scriptToken);\n }\n });\n}", "import type { CommentThread } from \"../types.js\";\n\nexport interface RendererRuleOptions {\n dataContainer?: \"script\" | \"element\";\n dataElementId?: string;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nexport function installRendererRules(\n md: { renderer: { rules: Record<string, ((...args: any[]) => string) | undefined> } },\n options: RendererRuleOptions = {},\n): void {\n md.renderer.rules[\"mrsf_data_script\"] = (\n tokens: { meta: { threads: CommentThread[] } }[],\n idx: number,\n ): string => {\n const { threads } = tokens[idx].meta;\n const payload = JSON.stringify({ threads });\n if (options.dataContainer === \"element\") {\n const elementId = options.dataElementId || \"mrsf-comment-data\";\n return `<div id=\"${escapeAttribute(elementId)}\" data-mrsf-json=\"${escapeAttribute(payload)}\" aria-hidden=\"true\"></div>`;\n }\n\n const data = payload.replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/mrsf+json\">${data}</script>`;\n };\n}", "import type MarkdownIt from \"markdown-it\";\nimport { resolveComments } from \"@mrsf/plugin-shared\";\nimport type { CommentLoader, MrsfPluginOptions } from \"./types.js\";\nimport { installCoreRule } from \"./rules/core.js\";\nimport { installRendererRules } from \"./rules/renderer.js\";\n\nexport interface MarpitRenderResult {\n html: string | string[];\n css: string;\n comments?: string[][];\n}\n\nexport interface MarpitLike {\n render(markdown: string, env?: Record<string, unknown>): MarpitRenderResult;\n use(plugin: (context: unknown, ...params: unknown[]) => unknown, ...params: unknown[]): unknown;\n markdown?: MarkdownIt;\n}\n\nexport interface MarpitPluginContext {\n marpit?: MarpitLike;\n markdown?: MarkdownIt;\n}\n\nexport type MrsfMarpPlugin = (\n context: MarpitPluginContext,\n options?: MrsfPluginOptions,\n) => void;\n\nconst patchedRenderers = new WeakSet<MarpitLike>();\n\nexport function installMarkdownMrsfPlugin(\n md: MarkdownIt,\n options: MrsfPluginOptions,\n loader: CommentLoader,\n): void {\n installCoreRule(\n md,\n (state) => resolveComments(loader, options, state.env),\n { lineHighlight: options.lineHighlight ?? false },\n );\n installRendererRules(md, {\n dataContainer: options.dataContainer,\n dataElementId: options.dataElementId,\n });\n}\n\nexport function createMarpPlugin(loader: CommentLoader): MrsfMarpPlugin {\n return function mrsfPlugin(\n context: MarpitPluginContext,\n options: MrsfPluginOptions = {},\n ): void {\n const markdown = context.markdown ?? context.marpit?.markdown;\n if (markdown) {\n installMarkdownMrsfPlugin(markdown, options, loader);\n }\n\n if (!context.marpit) {\n return;\n }\n\n patchRender(context.marpit, options);\n };\n}\n\nfunction patchRender(marpit: MarpitLike, options: MrsfPluginOptions): void {\n if (patchedRenderers.has(marpit)) {\n return;\n }\n\n const originalRender = marpit.render.bind(marpit);\n marpit.render = (markdown: string, env?: Record<string, unknown>): MarpitRenderResult => {\n const result = originalRender(markdown, env);\n const fallbackHtml = Array.isArray(result.html)\n ? originalRender(markdown, { ...(env ?? {}), htmlAsArray: false }).html\n : null;\n\n return {\n ...result,\n html: normalizeRenderedHtml(result.html, options, typeof fallbackHtml === \"string\" ? fallbackHtml : null),\n };\n };\n\n patchedRenderers.add(marpit);\n}\n\nconst SCRIPT_RE = /<script type=\"application\\/mrsf\\+json\">[\\s\\S]*?<\\/script>/g;\n\nfunction normalizeRenderedHtml(\n html: string | string[],\n options: MrsfPluginOptions,\n fallbackHtml: string | null = null,\n): string | string[] {\n if (Array.isArray(html)) {\n let payload: string | null = null;\n\n const pages = html.map((pageHtml, index) => {\n const extracted = extractPayloads(pageHtml);\n if (extracted.payloads.length > 0) {\n payload = extracted.payloads[extracted.payloads.length - 1];\n }\n\n return annotatePageFragment(extracted.html, index + 1, options);\n });\n\n if (!payload && fallbackHtml) {\n const fallback = extractPayloads(fallbackHtml);\n payload = fallback.payloads[fallback.payloads.length - 1] ?? null;\n }\n\n if (payload && pages.length > 0) {\n pages[pages.length - 1] += payload;\n }\n\n return pages;\n }\n\n const extracted = extractPayloads(html);\n const annotated = annotateSectionTags(extracted.html, options);\n\n if (extracted.payloads.length === 0) {\n return annotated;\n }\n\n const payload = extracted.payloads[extracted.payloads.length - 1];\n return insertPayloadIntoContainer(annotated, payload);\n}\n\nfunction extractPayloads(html: string): { html: string; payloads: string[] } {\n const payloads = html.match(SCRIPT_RE) ?? [];\n return {\n html: html.replace(SCRIPT_RE, \"\"),\n payloads,\n };\n}\n\nfunction annotatePageFragment(\n html: string,\n pageNumber: number,\n options: MrsfPluginOptions,\n): string {\n const attrName = resolvePageAttributeName(options);\n return html.replace(/<([a-zA-Z][\\w:-]*)(\\s|>)/, `<$1 ${attrName}=\"${pageNumber}\"$2`);\n}\n\nfunction annotateSectionTags(html: string, options: MrsfPluginOptions): string {\n if (html.includes(\"<svg\") && html.includes(\"data-marpit-svg\")) {\n return annotateSvgPageTags(html, options);\n }\n\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<section(\\s|>)/g, (_match, suffix: string) => {\n pageNumber += 1;\n return `<section ${attrName}=\"${pageNumber}\"${suffix}`;\n });\n}\n\nfunction annotateSvgPageTags(html: string, options: MrsfPluginOptions): string {\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<svg\\b([^>]*)>/g, (_match, attrs: string) => {\n if (!attrs.includes(\"data-marpit-svg\")) {\n return `<svg${attrs}>`;\n }\n\n pageNumber += 1;\n return `<svg${attrs} ${attrName}=\"${pageNumber}\">`;\n });\n}\n\nfunction resolvePageAttributeName(_options: MrsfPluginOptions): string {\n return \"data-mrsf-page\";\n}\n\nfunction insertPayloadIntoContainer(html: string, payload: string): string {\n const closingTagIndex = html.lastIndexOf(\"</\");\n if (closingTagIndex === -1) {\n return html + payload;\n }\n\n return html.slice(0, closingTagIndex) + payload + html.slice(closingTagIndex);\n}", "import type { MrsfPluginOptions } from \"./types.js\";\nimport { createMarpPlugin } from \"./shared.js\";\nimport type { MrsfMarpPlugin } from \"./shared.js\";\n\nexport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\nexport type { MrsfMarpPlugin, MarpitLike, MarpitPluginContext } from \"./shared.js\";\n\nexport const mrsfPlugin: MrsfMarpPlugin = createMarpPlugin((options: MrsfPluginOptions, env?: unknown) => {\n if (options.comments) {\n return options.comments;\n }\n\n if (options.loader) {\n try {\n return options.loader(options, env);\n } catch {\n return null;\n }\n }\n\n if (options.sidecarPath || options.documentPath) {\n console.warn(\n \"[@mrsf/marp-mrsf] sidecarPath and documentPath require Node.js. \" +\n \"Use `comments` or `loader` options in browser environments.\",\n );\n }\n\n return null;\n});\n\nexport default mrsfPlugin;"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["resolveComments", "mrsfPlugin", "payload", "extracted"]
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,21 @@ import path from "node:path";
|
|
|
4
4
|
import { parseSidecarContent } from "@mrsf/cli";
|
|
5
5
|
|
|
6
6
|
// ../shared/dist/comments.js
|
|
7
|
+
function getExtensionFields(comment) {
|
|
8
|
+
const extensions = {};
|
|
9
|
+
for (const [key, value] of Object.entries(comment)) {
|
|
10
|
+
if (key.startsWith("x_")) {
|
|
11
|
+
extensions[key] = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return extensions;
|
|
15
|
+
}
|
|
7
16
|
function toSlimComments(doc) {
|
|
8
17
|
return doc.comments.map((c) => ({
|
|
9
18
|
id: c.id,
|
|
10
19
|
author: c.author || "Unknown",
|
|
11
20
|
text: c.text || "",
|
|
12
21
|
line: c.line ?? null,
|
|
13
|
-
x_page: typeof c.x_page === "number" ? c.x_page : null,
|
|
14
22
|
end_line: c.end_line ?? null,
|
|
15
23
|
start_column: c.start_column ?? null,
|
|
16
24
|
end_column: c.end_column ?? null,
|
|
@@ -19,7 +27,8 @@ function toSlimComments(doc) {
|
|
|
19
27
|
reply_to: c.reply_to || null,
|
|
20
28
|
severity: c.severity || null,
|
|
21
29
|
type: c.type || null,
|
|
22
|
-
timestamp: c.timestamp || null
|
|
30
|
+
timestamp: c.timestamp || null,
|
|
31
|
+
...getExtensionFields(c)
|
|
23
32
|
}));
|
|
24
33
|
}
|
|
25
34
|
function groupByLine(comments) {
|
|
@@ -92,10 +101,11 @@ function mergePageScopedThreads(lineMap, comments, pageLineMap) {
|
|
|
92
101
|
replyMap.set(comment.reply_to, replies);
|
|
93
102
|
}
|
|
94
103
|
for (const comment of comments) {
|
|
95
|
-
|
|
104
|
+
const pageNumber = typeof comment.x_page === "number" ? comment.x_page : null;
|
|
105
|
+
if (comment.reply_to || comment.line != null || pageNumber == null) {
|
|
96
106
|
continue;
|
|
97
107
|
}
|
|
98
|
-
const displayLine = pageLineMap.get(
|
|
108
|
+
const displayLine = pageLineMap.get(pageNumber);
|
|
99
109
|
if (displayLine == null) {
|
|
100
110
|
continue;
|
|
101
111
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../../shared/src/comments.ts", "../src/rules/core.ts", "../src/rules/renderer.ts", "../src/shared.ts"],
|
|
4
|
-
"sourcesContent": ["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { parseSidecarContent } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions } from \"./types.js\";\nimport { createMarpPlugin } from \"./shared.js\";\nimport type { MrsfMarpPlugin } from \"./shared.js\";\n\nexport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\nexport type { MrsfMarpPlugin, MarpitLike, MarpitPluginContext } from \"./shared.js\";\n\nexport const mrsfPlugin: MrsfMarpPlugin = createMarpPlugin((options: MrsfPluginOptions, env?: unknown) => {\n if (options.comments) {\n return options.comments;\n }\n\n if (options.loader) {\n try {\n return options.loader(options, env);\n } catch {\n return null;\n }\n }\n\n if (options.sidecarPath) {\n try {\n const abs = path.resolve(options.cwd || process.cwd(), options.sidecarPath);\n const content = readFileSync(abs, \"utf-8\");\n return parseSidecarContent(content, abs);\n } catch {\n return null;\n }\n }\n\n if (options.documentPath) {\n try {\n const cwd = options.cwd || process.cwd();\n const abs = path.resolve(cwd, options.documentPath);\n const yamlPath = abs + \".review.yaml\";\n const jsonPath = abs + \".review.json\";\n\n let raw: string | null = null;\n let hint: string | null = null;\n\n try {\n raw = readFileSync(yamlPath, \"utf-8\");\n hint = yamlPath;\n } catch {\n try {\n raw = readFileSync(jsonPath, \"utf-8\");\n hint = jsonPath;\n } catch {\n return null;\n }\n }\n\n if (!raw) {\n return null;\n }\n\n return parseSidecarContent(raw, hint!);\n } catch {\n return null;\n }\n }\n\n return null;\n});\n\nexport default mrsfPlugin;", "/**\n * Shared comment loading and grouping logic for MRSF rendering plugins.\n */\n\nimport type { MrsfDocument } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\n\nexport type { CommentLoader };\n\n/**\n * Convert an MrsfDocument into a slim comment array.\n */\nexport function toSlimComments(doc: MrsfDocument): SlimComment[] {\n return doc.comments.map((c) => ({\n id: c.id,\n author: c.author || \"Unknown\",\n text: c.text || \"\",\n line: c.line ?? null,\n x_page: typeof c.x_page === \"number\" ? c.x_page : null,\n end_line: c.end_line ?? null,\n start_column: c.start_column ?? null,\n end_column: c.end_column ?? null,\n selected_text: c.selected_text || null,\n resolved: !!c.resolved,\n reply_to: c.reply_to || null,\n severity: c.severity || null,\n type: c.type || null,\n timestamp: c.timestamp || null,\n }));\n}\n\n/**\n * Group comments by line number, threading replies under parents.\n */\nexport function groupByLine(comments: SlimComment[]): LineMap {\n const rootComments = comments.filter((c) => !c.reply_to && c.line != null);\n const replies = comments.filter((c) => c.reply_to);\n\n const replyMap = new Map<string, SlimComment[]>();\n for (const r of replies) {\n const list = replyMap.get(r.reply_to!) || [];\n list.push(r);\n replyMap.set(r.reply_to!, list);\n }\n\n const lineMap: LineMap = new Map();\n for (const c of rootComments) {\n const line = c.line!;\n const threads = lineMap.get(line) || [];\n threads.push({\n comment: c,\n replies: replyMap.get(c.id) || [],\n });\n lineMap.set(line, threads);\n }\n\n return lineMap;\n}\n\n/**\n * Resolve options into a filtered LineMap ready for rendering.\n * Returns null if there are no comments to render.\n */\nexport function resolveComments(\n loader: CommentLoader,\n options: MrsfPluginOptions,\n env?: unknown,\n): { lineMap: LineMap; comments: SlimComment[] } | null {\n const showResolved = options.showResolved ?? true;\n\n const doc = loader(options, env);\n if (!doc || !doc.comments || doc.comments.length === 0) {\n return null;\n }\n\n let comments = toSlimComments(doc);\n if (!showResolved) {\n comments = comments.filter((c) => !c.resolved);\n }\n\n if (comments.length === 0) return null;\n\n const lineMap = groupByLine(comments);\n return { lineMap, comments };\n}\n", "import type Token from \"markdown-it/lib/token.mjs\";\nimport type StateCore from \"markdown-it/lib/rules_core/state_core.mjs\";\nimport type { LineMap, CommentThread, SlimComment } from \"../types.js\";\n\nexport interface CoreRuleOptions {\n lineHighlight?: boolean;\n}\n\nexport interface ResolvedCommentData {\n lineMap: LineMap;\n comments: SlimComment[];\n}\n\nfunction buildPageLineMap(tokens: Token[]): Map<number, number> {\n const pageLineMap = new Map<number, number>();\n let pageNumber = 0;\n\n for (const token of tokens) {\n if (token.type !== \"marpit_slide_open\" || !token.map) {\n continue;\n }\n\n pageNumber += 1;\n pageLineMap.set(pageNumber, token.map[0] + 1);\n }\n\n return pageLineMap;\n}\n\nfunction mergePageScopedThreads(\n lineMap: LineMap,\n comments: SlimComment[],\n pageLineMap: Map<number, number>,\n): LineMap {\n const merged: LineMap = new Map(\n Array.from(lineMap.entries(), ([line, threads]) => [\n line,\n threads.map((thread) => ({\n comment: thread.comment,\n replies: [...thread.replies],\n })),\n ]),\n );\n const replyMap = new Map<string, SlimComment[]>();\n\n for (const comment of comments) {\n if (!comment.reply_to) {\n continue;\n }\n\n const replies = replyMap.get(comment.reply_to) || [];\n replies.push(comment);\n replyMap.set(comment.reply_to, replies);\n }\n\n for (const comment of comments) {\n if (comment.reply_to || comment.line != null || comment.x_page == null) {\n continue;\n }\n\n const displayLine = pageLineMap.get(comment.x_page);\n if (displayLine == null) {\n continue;\n }\n\n const threadComment: SlimComment = {\n ...comment,\n line: displayLine,\n };\n const threadReplies = (replyMap.get(comment.id) || []).map((reply) => ({\n ...reply,\n line: reply.line ?? displayLine,\n }));\n const threads = merged.get(displayLine) || [];\n\n threads.push({\n comment: threadComment,\n replies: threadReplies,\n });\n merged.set(displayLine, threads);\n }\n\n return merged;\n}\n\nexport function installCoreRule(\n md: { core: { ruler: { push: (name: string, fn: (state: StateCore) => void) => void } } },\n resolveComments: (state: StateCore) => ResolvedCommentData | null,\n options: CoreRuleOptions = {},\n): void {\n md.core.ruler.push(\"mrsf_inject\", (state: StateCore) => {\n const result = resolveComments(state);\n if (!result) return;\n\n const pageLineMap = buildPageLineMap(state.tokens);\n const lineMap = mergePageScopedThreads(result.lineMap, result.comments, pageLineMap);\n const tokens = state.tokens;\n const TokenCtor = state.Token;\n const processed = new Set<number>();\n\n for (let i = tokens.length - 1; i >= 0; i--) {\n const token = tokens[i];\n const map = token.map;\n if (!map) continue;\n\n if (token.type === \"inline\") continue;\n\n const startLine1 = map[0] + 1;\n const endLine1 = map[1];\n token.attrSet(\"data-mrsf-line\", String(startLine1));\n token.attrSet(\"data-mrsf-start-line\", String(startLine1));\n token.attrSet(\"data-mrsf-end-line\", String(endLine1));\n\n for (let line0 = map[0]; line0 < map[1]; line0++) {\n const line = line0 + 1;\n if (processed.has(line)) continue;\n processed.add(line);\n\n const threads = lineMap.get(line);\n if (threads && threads.length > 0) {\n if (options.lineHighlight) {\n const existingClass = token.attrGet(\"class\") || \"\";\n if (!existingClass.includes(\"mrsf-line-highlight\")) {\n token.attrSet(\n \"class\",\n existingClass ? `${existingClass} mrsf-line-highlight` : \"mrsf-line-highlight\",\n );\n }\n }\n token.attrSet(\"data-mrsf-line\", String(line));\n }\n }\n }\n\n const allThreads: CommentThread[] = [];\n for (const threads of lineMap.values()) {\n allThreads.push(...threads);\n }\n if (allThreads.length > 0) {\n const scriptToken = new TokenCtor(\"mrsf_data_script\", \"\", 0);\n scriptToken.meta = { threads: allThreads };\n tokens.push(scriptToken);\n }\n });\n}", "import type { CommentThread } from \"../types.js\";\n\nexport interface RendererRuleOptions {\n dataContainer?: \"script\" | \"element\";\n dataElementId?: string;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nexport function installRendererRules(\n md: { renderer: { rules: Record<string, ((...args: any[]) => string) | undefined> } },\n options: RendererRuleOptions = {},\n): void {\n md.renderer.rules[\"mrsf_data_script\"] = (\n tokens: { meta: { threads: CommentThread[] } }[],\n idx: number,\n ): string => {\n const { threads } = tokens[idx].meta;\n const payload = JSON.stringify({ threads });\n if (options.dataContainer === \"element\") {\n const elementId = options.dataElementId || \"mrsf-comment-data\";\n return `<div id=\"${escapeAttribute(elementId)}\" data-mrsf-json=\"${escapeAttribute(payload)}\" aria-hidden=\"true\"></div>`;\n }\n\n const data = payload.replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/mrsf+json\">${data}</script>`;\n };\n}", "import type MarkdownIt from \"markdown-it\";\nimport { resolveComments } from \"@mrsf/plugin-shared\";\nimport type { CommentLoader, MrsfPluginOptions } from \"./types.js\";\nimport { installCoreRule } from \"./rules/core.js\";\nimport { installRendererRules } from \"./rules/renderer.js\";\n\nexport interface MarpitRenderResult {\n html: string | string[];\n css: string;\n comments?: string[][];\n}\n\nexport interface MarpitLike {\n render(markdown: string, env?: Record<string, unknown>): MarpitRenderResult;\n use(plugin: (context: unknown, ...params: unknown[]) => unknown, ...params: unknown[]): unknown;\n markdown?: MarkdownIt;\n}\n\nexport interface MarpitPluginContext {\n marpit?: MarpitLike;\n markdown?: MarkdownIt;\n}\n\nexport type MrsfMarpPlugin = (\n context: MarpitPluginContext,\n options?: MrsfPluginOptions,\n) => void;\n\nconst patchedRenderers = new WeakSet<MarpitLike>();\n\nexport function installMarkdownMrsfPlugin(\n md: MarkdownIt,\n options: MrsfPluginOptions,\n loader: CommentLoader,\n): void {\n installCoreRule(\n md,\n (state) => resolveComments(loader, options, state.env),\n { lineHighlight: options.lineHighlight ?? false },\n );\n installRendererRules(md, {\n dataContainer: options.dataContainer,\n dataElementId: options.dataElementId,\n });\n}\n\nexport function createMarpPlugin(loader: CommentLoader): MrsfMarpPlugin {\n return function mrsfPlugin(\n context: MarpitPluginContext,\n options: MrsfPluginOptions = {},\n ): void {\n const markdown = context.markdown ?? context.marpit?.markdown;\n if (markdown) {\n installMarkdownMrsfPlugin(markdown, options, loader);\n }\n\n if (!context.marpit) {\n return;\n }\n\n patchRender(context.marpit, options);\n };\n}\n\nfunction patchRender(marpit: MarpitLike, options: MrsfPluginOptions): void {\n if (patchedRenderers.has(marpit)) {\n return;\n }\n\n const originalRender = marpit.render.bind(marpit);\n marpit.render = (markdown: string, env?: Record<string, unknown>): MarpitRenderResult => {\n const result = originalRender(markdown, env);\n const fallbackHtml = Array.isArray(result.html)\n ? originalRender(markdown, { ...(env ?? {}), htmlAsArray: false }).html\n : null;\n\n return {\n ...result,\n html: normalizeRenderedHtml(result.html, options, typeof fallbackHtml === \"string\" ? fallbackHtml : null),\n };\n };\n\n patchedRenderers.add(marpit);\n}\n\nconst SCRIPT_RE = /<script type=\"application\\/mrsf\\+json\">[\\s\\S]*?<\\/script>/g;\n\nfunction normalizeRenderedHtml(\n html: string | string[],\n options: MrsfPluginOptions,\n fallbackHtml: string | null = null,\n): string | string[] {\n if (Array.isArray(html)) {\n let payload: string | null = null;\n\n const pages = html.map((pageHtml, index) => {\n const extracted = extractPayloads(pageHtml);\n if (extracted.payloads.length > 0) {\n payload = extracted.payloads[extracted.payloads.length - 1];\n }\n\n return annotatePageFragment(extracted.html, index + 1, options);\n });\n\n if (!payload && fallbackHtml) {\n const fallback = extractPayloads(fallbackHtml);\n payload = fallback.payloads[fallback.payloads.length - 1] ?? null;\n }\n\n if (payload && pages.length > 0) {\n pages[pages.length - 1] += payload;\n }\n\n return pages;\n }\n\n const extracted = extractPayloads(html);\n const annotated = annotateSectionTags(extracted.html, options);\n\n if (extracted.payloads.length === 0) {\n return annotated;\n }\n\n const payload = extracted.payloads[extracted.payloads.length - 1];\n return insertPayloadIntoContainer(annotated, payload);\n}\n\nfunction extractPayloads(html: string): { html: string; payloads: string[] } {\n const payloads = html.match(SCRIPT_RE) ?? [];\n return {\n html: html.replace(SCRIPT_RE, \"\"),\n payloads,\n };\n}\n\nfunction annotatePageFragment(\n html: string,\n pageNumber: number,\n options: MrsfPluginOptions,\n): string {\n const attrName = resolvePageAttributeName(options);\n return html.replace(/<([a-zA-Z][\\w:-]*)(\\s|>)/, `<$1 ${attrName}=\"${pageNumber}\"$2`);\n}\n\nfunction annotateSectionTags(html: string, options: MrsfPluginOptions): string {\n if (html.includes(\"<svg\") && html.includes(\"data-marpit-svg\")) {\n return annotateSvgPageTags(html, options);\n }\n\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<section(\\s|>)/g, (_match, suffix: string) => {\n pageNumber += 1;\n return `<section ${attrName}=\"${pageNumber}\"${suffix}`;\n });\n}\n\nfunction annotateSvgPageTags(html: string, options: MrsfPluginOptions): string {\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<svg\\b([^>]*)>/g, (_match, attrs: string) => {\n if (!attrs.includes(\"data-marpit-svg\")) {\n return `<svg${attrs}>`;\n }\n\n pageNumber += 1;\n return `<svg${attrs} ${attrName}=\"${pageNumber}\">`;\n });\n}\n\nfunction resolvePageAttributeName(_options: MrsfPluginOptions): string {\n return \"data-mrsf-page\";\n}\n\nfunction insertPayloadIntoContainer(html: string, payload: string): string {\n const closingTagIndex = html.lastIndexOf(\"</\");\n if (closingTagIndex === -1) {\n return html + payload;\n }\n\n return html.slice(0, closingTagIndex) + payload + html.slice(closingTagIndex);\n}"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,oBAAoB;AAC7B,OAAO,UAAU;AACjB,SAAS,2BAA2B;;;
|
|
4
|
+
"sourcesContent": ["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { parseSidecarContent } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions } from \"./types.js\";\nimport { createMarpPlugin } from \"./shared.js\";\nimport type { MrsfMarpPlugin } from \"./shared.js\";\n\nexport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\nexport type { MrsfMarpPlugin, MarpitLike, MarpitPluginContext } from \"./shared.js\";\n\nexport const mrsfPlugin: MrsfMarpPlugin = createMarpPlugin((options: MrsfPluginOptions, env?: unknown) => {\n if (options.comments) {\n return options.comments;\n }\n\n if (options.loader) {\n try {\n return options.loader(options, env);\n } catch {\n return null;\n }\n }\n\n if (options.sidecarPath) {\n try {\n const abs = path.resolve(options.cwd || process.cwd(), options.sidecarPath);\n const content = readFileSync(abs, \"utf-8\");\n return parseSidecarContent(content, abs);\n } catch {\n return null;\n }\n }\n\n if (options.documentPath) {\n try {\n const cwd = options.cwd || process.cwd();\n const abs = path.resolve(cwd, options.documentPath);\n const yamlPath = abs + \".review.yaml\";\n const jsonPath = abs + \".review.json\";\n\n let raw: string | null = null;\n let hint: string | null = null;\n\n try {\n raw = readFileSync(yamlPath, \"utf-8\");\n hint = yamlPath;\n } catch {\n try {\n raw = readFileSync(jsonPath, \"utf-8\");\n hint = jsonPath;\n } catch {\n return null;\n }\n }\n\n if (!raw) {\n return null;\n }\n\n return parseSidecarContent(raw, hint!);\n } catch {\n return null;\n }\n }\n\n return null;\n});\n\nexport default mrsfPlugin;", "/**\n * Shared comment loading and grouping logic for MRSF rendering plugins.\n */\n\nimport type { MrsfDocument } from \"@mrsf/cli\";\nimport type { MrsfPluginOptions, SlimComment, CommentThread, LineMap, CommentLoader } from \"./types.js\";\n\nexport type { CommentLoader };\n\nfunction getExtensionFields(comment: Record<string, unknown>): Record<`x_${string}`, unknown> {\n const extensions: Record<`x_${string}`, unknown> = {};\n\n for (const [key, value] of Object.entries(comment)) {\n if (key.startsWith(\"x_\")) {\n extensions[key as `x_${string}`] = value;\n }\n }\n\n return extensions;\n}\n\n/**\n * Convert an MrsfDocument into a slim comment array.\n */\nexport function toSlimComments(doc: MrsfDocument): SlimComment[] {\n return doc.comments.map((c) => ({\n id: c.id,\n author: c.author || \"Unknown\",\n text: c.text || \"\",\n line: c.line ?? null,\n end_line: c.end_line ?? null,\n start_column: c.start_column ?? null,\n end_column: c.end_column ?? null,\n selected_text: c.selected_text || null,\n resolved: !!c.resolved,\n reply_to: c.reply_to || null,\n severity: c.severity || null,\n type: c.type || null,\n timestamp: c.timestamp || null,\n ...getExtensionFields(c as Record<string, unknown>),\n }));\n}\n\n/**\n * Group comments by line number, threading replies under parents.\n */\nexport function groupByLine(comments: SlimComment[]): LineMap {\n const rootComments = comments.filter((c) => !c.reply_to && c.line != null);\n const replies = comments.filter((c) => c.reply_to);\n\n const replyMap = new Map<string, SlimComment[]>();\n for (const r of replies) {\n const list = replyMap.get(r.reply_to!) || [];\n list.push(r);\n replyMap.set(r.reply_to!, list);\n }\n\n const lineMap: LineMap = new Map();\n for (const c of rootComments) {\n const line = c.line!;\n const threads = lineMap.get(line) || [];\n threads.push({\n comment: c,\n replies: replyMap.get(c.id) || [],\n });\n lineMap.set(line, threads);\n }\n\n return lineMap;\n}\n\n/**\n * Resolve options into a filtered LineMap ready for rendering.\n * Returns null if there are no comments to render.\n */\nexport function resolveComments(\n loader: CommentLoader,\n options: MrsfPluginOptions,\n env?: unknown,\n): { lineMap: LineMap; comments: SlimComment[] } | null {\n const showResolved = options.showResolved ?? true;\n\n const doc = loader(options, env);\n if (!doc || !doc.comments || doc.comments.length === 0) {\n return null;\n }\n\n let comments = toSlimComments(doc);\n if (!showResolved) {\n comments = comments.filter((c) => !c.resolved);\n }\n\n if (comments.length === 0) return null;\n\n const lineMap = groupByLine(comments);\n return { lineMap, comments };\n}\n", "import type Token from \"markdown-it/lib/token.mjs\";\nimport type StateCore from \"markdown-it/lib/rules_core/state_core.mjs\";\nimport type { LineMap, CommentThread, SlimComment } from \"../types.js\";\n\nexport interface CoreRuleOptions {\n lineHighlight?: boolean;\n}\n\nexport interface ResolvedCommentData {\n lineMap: LineMap;\n comments: SlimComment[];\n}\n\nfunction buildPageLineMap(tokens: Token[]): Map<number, number> {\n const pageLineMap = new Map<number, number>();\n let pageNumber = 0;\n\n for (const token of tokens) {\n if (token.type !== \"marpit_slide_open\" || !token.map) {\n continue;\n }\n\n pageNumber += 1;\n pageLineMap.set(pageNumber, token.map[0] + 1);\n }\n\n return pageLineMap;\n}\n\nfunction mergePageScopedThreads(\n lineMap: LineMap,\n comments: SlimComment[],\n pageLineMap: Map<number, number>,\n): LineMap {\n const merged: LineMap = new Map(\n Array.from(lineMap.entries(), ([line, threads]) => [\n line,\n threads.map((thread) => ({\n comment: thread.comment,\n replies: [...thread.replies],\n })),\n ]),\n );\n const replyMap = new Map<string, SlimComment[]>();\n\n for (const comment of comments) {\n if (!comment.reply_to) {\n continue;\n }\n\n const replies = replyMap.get(comment.reply_to) || [];\n replies.push(comment);\n replyMap.set(comment.reply_to, replies);\n }\n\n for (const comment of comments) {\n const pageNumber = typeof comment.x_page === \"number\" ? comment.x_page : null;\n\n if (comment.reply_to || comment.line != null || pageNumber == null) {\n continue;\n }\n\n const displayLine = pageLineMap.get(pageNumber);\n if (displayLine == null) {\n continue;\n }\n\n const threadComment: SlimComment = {\n ...comment,\n line: displayLine,\n };\n const threadReplies = (replyMap.get(comment.id) || []).map((reply) => ({\n ...reply,\n line: reply.line ?? displayLine,\n }));\n const threads = merged.get(displayLine) || [];\n\n threads.push({\n comment: threadComment,\n replies: threadReplies,\n });\n merged.set(displayLine, threads);\n }\n\n return merged;\n}\n\nexport function installCoreRule(\n md: { core: { ruler: { push: (name: string, fn: (state: StateCore) => void) => void } } },\n resolveComments: (state: StateCore) => ResolvedCommentData | null,\n options: CoreRuleOptions = {},\n): void {\n md.core.ruler.push(\"mrsf_inject\", (state: StateCore) => {\n const result = resolveComments(state);\n if (!result) return;\n\n const pageLineMap = buildPageLineMap(state.tokens);\n const lineMap = mergePageScopedThreads(result.lineMap, result.comments, pageLineMap);\n const tokens = state.tokens;\n const TokenCtor = state.Token;\n const processed = new Set<number>();\n\n for (let i = tokens.length - 1; i >= 0; i--) {\n const token = tokens[i];\n const map = token.map;\n if (!map) continue;\n\n if (token.type === \"inline\") continue;\n\n const startLine1 = map[0] + 1;\n const endLine1 = map[1];\n token.attrSet(\"data-mrsf-line\", String(startLine1));\n token.attrSet(\"data-mrsf-start-line\", String(startLine1));\n token.attrSet(\"data-mrsf-end-line\", String(endLine1));\n\n for (let line0 = map[0]; line0 < map[1]; line0++) {\n const line = line0 + 1;\n if (processed.has(line)) continue;\n processed.add(line);\n\n const threads = lineMap.get(line);\n if (threads && threads.length > 0) {\n if (options.lineHighlight) {\n const existingClass = token.attrGet(\"class\") || \"\";\n if (!existingClass.includes(\"mrsf-line-highlight\")) {\n token.attrSet(\n \"class\",\n existingClass ? `${existingClass} mrsf-line-highlight` : \"mrsf-line-highlight\",\n );\n }\n }\n token.attrSet(\"data-mrsf-line\", String(line));\n }\n }\n }\n\n const allThreads: CommentThread[] = [];\n for (const threads of lineMap.values()) {\n allThreads.push(...threads);\n }\n if (allThreads.length > 0) {\n const scriptToken = new TokenCtor(\"mrsf_data_script\", \"\", 0);\n scriptToken.meta = { threads: allThreads };\n tokens.push(scriptToken);\n }\n });\n}", "import type { CommentThread } from \"../types.js\";\n\nexport interface RendererRuleOptions {\n dataContainer?: \"script\" | \"element\";\n dataElementId?: string;\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nexport function installRendererRules(\n md: { renderer: { rules: Record<string, ((...args: any[]) => string) | undefined> } },\n options: RendererRuleOptions = {},\n): void {\n md.renderer.rules[\"mrsf_data_script\"] = (\n tokens: { meta: { threads: CommentThread[] } }[],\n idx: number,\n ): string => {\n const { threads } = tokens[idx].meta;\n const payload = JSON.stringify({ threads });\n if (options.dataContainer === \"element\") {\n const elementId = options.dataElementId || \"mrsf-comment-data\";\n return `<div id=\"${escapeAttribute(elementId)}\" data-mrsf-json=\"${escapeAttribute(payload)}\" aria-hidden=\"true\"></div>`;\n }\n\n const data = payload.replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/mrsf+json\">${data}</script>`;\n };\n}", "import type MarkdownIt from \"markdown-it\";\nimport { resolveComments } from \"@mrsf/plugin-shared\";\nimport type { CommentLoader, MrsfPluginOptions } from \"./types.js\";\nimport { installCoreRule } from \"./rules/core.js\";\nimport { installRendererRules } from \"./rules/renderer.js\";\n\nexport interface MarpitRenderResult {\n html: string | string[];\n css: string;\n comments?: string[][];\n}\n\nexport interface MarpitLike {\n render(markdown: string, env?: Record<string, unknown>): MarpitRenderResult;\n use(plugin: (context: unknown, ...params: unknown[]) => unknown, ...params: unknown[]): unknown;\n markdown?: MarkdownIt;\n}\n\nexport interface MarpitPluginContext {\n marpit?: MarpitLike;\n markdown?: MarkdownIt;\n}\n\nexport type MrsfMarpPlugin = (\n context: MarpitPluginContext,\n options?: MrsfPluginOptions,\n) => void;\n\nconst patchedRenderers = new WeakSet<MarpitLike>();\n\nexport function installMarkdownMrsfPlugin(\n md: MarkdownIt,\n options: MrsfPluginOptions,\n loader: CommentLoader,\n): void {\n installCoreRule(\n md,\n (state) => resolveComments(loader, options, state.env),\n { lineHighlight: options.lineHighlight ?? false },\n );\n installRendererRules(md, {\n dataContainer: options.dataContainer,\n dataElementId: options.dataElementId,\n });\n}\n\nexport function createMarpPlugin(loader: CommentLoader): MrsfMarpPlugin {\n return function mrsfPlugin(\n context: MarpitPluginContext,\n options: MrsfPluginOptions = {},\n ): void {\n const markdown = context.markdown ?? context.marpit?.markdown;\n if (markdown) {\n installMarkdownMrsfPlugin(markdown, options, loader);\n }\n\n if (!context.marpit) {\n return;\n }\n\n patchRender(context.marpit, options);\n };\n}\n\nfunction patchRender(marpit: MarpitLike, options: MrsfPluginOptions): void {\n if (patchedRenderers.has(marpit)) {\n return;\n }\n\n const originalRender = marpit.render.bind(marpit);\n marpit.render = (markdown: string, env?: Record<string, unknown>): MarpitRenderResult => {\n const result = originalRender(markdown, env);\n const fallbackHtml = Array.isArray(result.html)\n ? originalRender(markdown, { ...(env ?? {}), htmlAsArray: false }).html\n : null;\n\n return {\n ...result,\n html: normalizeRenderedHtml(result.html, options, typeof fallbackHtml === \"string\" ? fallbackHtml : null),\n };\n };\n\n patchedRenderers.add(marpit);\n}\n\nconst SCRIPT_RE = /<script type=\"application\\/mrsf\\+json\">[\\s\\S]*?<\\/script>/g;\n\nfunction normalizeRenderedHtml(\n html: string | string[],\n options: MrsfPluginOptions,\n fallbackHtml: string | null = null,\n): string | string[] {\n if (Array.isArray(html)) {\n let payload: string | null = null;\n\n const pages = html.map((pageHtml, index) => {\n const extracted = extractPayloads(pageHtml);\n if (extracted.payloads.length > 0) {\n payload = extracted.payloads[extracted.payloads.length - 1];\n }\n\n return annotatePageFragment(extracted.html, index + 1, options);\n });\n\n if (!payload && fallbackHtml) {\n const fallback = extractPayloads(fallbackHtml);\n payload = fallback.payloads[fallback.payloads.length - 1] ?? null;\n }\n\n if (payload && pages.length > 0) {\n pages[pages.length - 1] += payload;\n }\n\n return pages;\n }\n\n const extracted = extractPayloads(html);\n const annotated = annotateSectionTags(extracted.html, options);\n\n if (extracted.payloads.length === 0) {\n return annotated;\n }\n\n const payload = extracted.payloads[extracted.payloads.length - 1];\n return insertPayloadIntoContainer(annotated, payload);\n}\n\nfunction extractPayloads(html: string): { html: string; payloads: string[] } {\n const payloads = html.match(SCRIPT_RE) ?? [];\n return {\n html: html.replace(SCRIPT_RE, \"\"),\n payloads,\n };\n}\n\nfunction annotatePageFragment(\n html: string,\n pageNumber: number,\n options: MrsfPluginOptions,\n): string {\n const attrName = resolvePageAttributeName(options);\n return html.replace(/<([a-zA-Z][\\w:-]*)(\\s|>)/, `<$1 ${attrName}=\"${pageNumber}\"$2`);\n}\n\nfunction annotateSectionTags(html: string, options: MrsfPluginOptions): string {\n if (html.includes(\"<svg\") && html.includes(\"data-marpit-svg\")) {\n return annotateSvgPageTags(html, options);\n }\n\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<section(\\s|>)/g, (_match, suffix: string) => {\n pageNumber += 1;\n return `<section ${attrName}=\"${pageNumber}\"${suffix}`;\n });\n}\n\nfunction annotateSvgPageTags(html: string, options: MrsfPluginOptions): string {\n const attrName = resolvePageAttributeName(options);\n let pageNumber = 0;\n\n return html.replace(/<svg\\b([^>]*)>/g, (_match, attrs: string) => {\n if (!attrs.includes(\"data-marpit-svg\")) {\n return `<svg${attrs}>`;\n }\n\n pageNumber += 1;\n return `<svg${attrs} ${attrName}=\"${pageNumber}\">`;\n });\n}\n\nfunction resolvePageAttributeName(_options: MrsfPluginOptions): string {\n return \"data-mrsf-page\";\n}\n\nfunction insertPayloadIntoContainer(html: string, payload: string): string {\n const closingTagIndex = html.lastIndexOf(\"</\");\n if (closingTagIndex === -1) {\n return html + payload;\n }\n\n return html.slice(0, closingTagIndex) + payload + html.slice(closingTagIndex);\n}"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,oBAAoB;AAC7B,OAAO,UAAU;AACjB,SAAS,2BAA2B;;;ACOpC,SAAS,mBAAmB,SAAgC;AAC1D,QAAM,aAA6C,CAAA;AAEnD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,IAAI,WAAW,IAAI,GAAG;AACxB,iBAAW,GAAoB,IAAI;IACrC;EACF;AAEA,SAAO;AACT;AAKM,SAAU,eAAe,KAAiB;AAC9C,SAAO,IAAI,SAAS,IAAI,CAAC,OAAO;IAC9B,IAAI,EAAE;IACN,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,cAAc,EAAE,gBAAgB;IAChC,YAAY,EAAE,cAAc;IAC5B,eAAe,EAAE,iBAAiB;IAClC,UAAU,CAAC,CAAC,EAAE;IACd,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,aAAa;IAC1B,GAAG,mBAAmB,CAA4B;IAClD;AACJ;AAKM,SAAU,YAAY,UAAuB;AACjD,QAAM,eAAe,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ,IAAI;AACzE,QAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ;AAEjD,QAAM,WAAW,oBAAI,IAAG;AACxB,aAAW,KAAK,SAAS;AACvB,UAAM,OAAO,SAAS,IAAI,EAAE,QAAS,KAAK,CAAA;AAC1C,SAAK,KAAK,CAAC;AACX,aAAS,IAAI,EAAE,UAAW,IAAI;EAChC;AAEA,QAAM,UAAmB,oBAAI,IAAG;AAChC,aAAW,KAAK,cAAc;AAC5B,UAAM,OAAO,EAAE;AACf,UAAM,UAAU,QAAQ,IAAI,IAAI,KAAK,CAAA;AACrC,YAAQ,KAAK;MACX,SAAS;MACT,SAAS,SAAS,IAAI,EAAE,EAAE,KAAK,CAAA;KAChC;AACD,YAAQ,IAAI,MAAM,OAAO;EAC3B;AAEA,SAAO;AACT;AAMM,SAAU,gBACd,QACA,SACA,KAAa;AAEb,QAAM,eAAe,QAAQ,gBAAgB;AAE7C,QAAM,MAAM,OAAO,SAAS,GAAG;AAC/B,MAAI,CAAC,OAAO,CAAC,IAAI,YAAY,IAAI,SAAS,WAAW,GAAG;AACtD,WAAO;EACT;AAEA,MAAI,WAAW,eAAe,GAAG;AACjC,MAAI,CAAC,cAAc;AACjB,eAAW,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;EAC/C;AAEA,MAAI,SAAS,WAAW;AAAG,WAAO;AAElC,QAAM,UAAU,YAAY,QAAQ;AACpC,SAAO,EAAE,SAAS,SAAQ;AAC5B;;;ACnFA,SAAS,iBAAiB,QAAsC;AAC9D,QAAM,cAAc,oBAAI,IAAoB;AAC5C,MAAI,aAAa;AAEjB,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,uBAAuB,CAAC,MAAM,KAAK;AACpD;AAAA,IACF;AAEA,kBAAc;AACd,gBAAY,IAAI,YAAY,MAAM,IAAI,CAAC,IAAI,CAAC;AAAA,EAC9C;AAEA,SAAO;AACT;AAEA,SAAS,uBACP,SACA,UACA,aACS;AACT,QAAM,SAAkB,IAAI;AAAA,IAC1B,MAAM,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,MAAM,OAAO,MAAM;AAAA,MACjD;AAAA,MACA,QAAQ,IAAI,CAAC,YAAY;AAAA,QACvB,SAAS,OAAO;AAAA,QAChB,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,MAC7B,EAAE;AAAA,IACJ,CAAC;AAAA,EACH;AACA,QAAM,WAAW,oBAAI,IAA2B;AAEhD,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,QAAQ,UAAU;AACrB;AAAA,IACF;AAEA,UAAM,UAAU,SAAS,IAAI,QAAQ,QAAQ,KAAK,CAAC;AACnD,YAAQ,KAAK,OAAO;AACpB,aAAS,IAAI,QAAQ,UAAU,OAAO;AAAA,EACxC;AAEA,aAAW,WAAW,UAAU;AAC9B,UAAM,aAAa,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AAEzE,QAAI,QAAQ,YAAY,QAAQ,QAAQ,QAAQ,cAAc,MAAM;AAClE;AAAA,IACF;AAEA,UAAM,cAAc,YAAY,IAAI,UAAU;AAC9C,QAAI,eAAe,MAAM;AACvB;AAAA,IACF;AAEA,UAAM,gBAA6B;AAAA,MACjC,GAAG;AAAA,MACH,MAAM;AAAA,IACR;AACA,UAAM,iBAAiB,SAAS,IAAI,QAAQ,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW;AAAA,MACrE,GAAG;AAAA,MACH,MAAM,MAAM,QAAQ;AAAA,IACtB,EAAE;AACF,UAAM,UAAU,OAAO,IAAI,WAAW,KAAK,CAAC;AAE5C,YAAQ,KAAK;AAAA,MACX,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AACD,WAAO,IAAI,aAAa,OAAO;AAAA,EACjC;AAEA,SAAO;AACT;AAEO,SAAS,gBACd,IACAA,kBACA,UAA2B,CAAC,GACtB;AACN,KAAG,KAAK,MAAM,KAAK,eAAe,CAAC,UAAqB;AACtD,UAAM,SAASA,iBAAgB,KAAK;AACpC,QAAI,CAAC,OAAQ;AAEf,UAAM,cAAc,iBAAiB,MAAM,MAAM;AACjD,UAAM,UAAU,uBAAuB,OAAO,SAAS,OAAO,UAAU,WAAW;AACjF,UAAM,SAAS,MAAM;AACrB,UAAM,YAAY,MAAM;AACxB,UAAM,YAAY,oBAAI,IAAY;AAElC,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,QAAQ,OAAO,CAAC;AACtB,YAAM,MAAM,MAAM;AAClB,UAAI,CAAC,IAAK;AAEV,UAAI,MAAM,SAAS,SAAU;AAE7B,YAAM,aAAa,IAAI,CAAC,IAAI;AAC5B,YAAM,WAAW,IAAI,CAAC;AACtB,YAAM,QAAQ,kBAAkB,OAAO,UAAU,CAAC;AAClD,YAAM,QAAQ,wBAAwB,OAAO,UAAU,CAAC;AACxD,YAAM,QAAQ,sBAAsB,OAAO,QAAQ,CAAC;AAEpD,eAAS,QAAQ,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,SAAS;AAChD,cAAM,OAAO,QAAQ;AACrB,YAAI,UAAU,IAAI,IAAI,EAAG;AACzB,kBAAU,IAAI,IAAI;AAElB,cAAM,UAAU,QAAQ,IAAI,IAAI;AAChC,YAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,cAAI,QAAQ,eAAe;AACzB,kBAAM,gBAAgB,MAAM,QAAQ,OAAO,KAAK;AAChD,gBAAI,CAAC,cAAc,SAAS,qBAAqB,GAAG;AAClD,oBAAM;AAAA,gBACJ;AAAA,gBACA,gBAAgB,GAAG,aAAa,yBAAyB;AAAA,cAC3D;AAAA,YACF;AAAA,UACF;AACA,gBAAM,QAAQ,kBAAkB,OAAO,IAAI,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAA8B,CAAC;AACrC,eAAW,WAAW,QAAQ,OAAO,GAAG;AACtC,iBAAW,KAAK,GAAG,OAAO;AAAA,IAC5B;AACA,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,cAAc,IAAI,UAAU,oBAAoB,IAAI,CAAC;AAC3D,kBAAY,OAAO,EAAE,SAAS,WAAW;AACzC,aAAO,KAAK,WAAW;AAAA,IACzB;AAAA,EACF,CAAC;AACH;;;AC3IA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,MACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ;AAC3B;AAEO,SAAS,qBACd,IACA,UAA+B,CAAC,GAC1B;AACN,KAAG,SAAS,MAAM,kBAAkB,IAAI,CACtC,QACA,QACW;AACX,UAAM,EAAE,QAAQ,IAAI,OAAO,GAAG,EAAE;AAChC,UAAM,UAAU,KAAK,UAAU,EAAE,QAAQ,CAAC;AAC1C,QAAI,QAAQ,kBAAkB,WAAW;AACvC,YAAM,YAAY,QAAQ,iBAAiB;AAC3C,aAAO,YAAY,gBAAgB,SAAS,CAAC,qBAAqB,gBAAgB,OAAO,CAAC;AAAA,IAC5F;AAEA,UAAM,OAAO,QAAQ,QAAQ,MAAM,SAAS;AAC5C,WAAO,wCAAwC,IAAI;AAAA,EACrD;AACF;;;ACLA,IAAM,mBAAmB,oBAAI,QAAoB;AAE1C,SAAS,0BACd,IACA,SACA,QACM;AACN;AAAA,IACE;AAAA,IACA,CAAC,UAAU,gBAAgB,QAAQ,SAAS,MAAM,GAAG;AAAA,IACrD,EAAE,eAAe,QAAQ,iBAAiB,MAAM;AAAA,EAClD;AACA,uBAAqB,IAAI;AAAA,IACvB,eAAe,QAAQ;AAAA,IACvB,eAAe,QAAQ;AAAA,EACzB,CAAC;AACH;AAEO,SAAS,iBAAiB,QAAuC;AACtE,SAAO,SAASC,YACd,SACA,UAA6B,CAAC,GACxB;AACN,UAAM,WAAW,QAAQ,YAAY,QAAQ,QAAQ;AACrD,QAAI,UAAU;AACZ,gCAA0B,UAAU,SAAS,MAAM;AAAA,IACrD;AAEA,QAAI,CAAC,QAAQ,QAAQ;AACnB;AAAA,IACF;AAEA,gBAAY,QAAQ,QAAQ,OAAO;AAAA,EACrC;AACF;AAEA,SAAS,YAAY,QAAoB,SAAkC;AACzE,MAAI,iBAAiB,IAAI,MAAM,GAAG;AAChC;AAAA,EACF;AAEA,QAAM,iBAAiB,OAAO,OAAO,KAAK,MAAM;AAChD,SAAO,SAAS,CAAC,UAAkB,QAAsD;AACvF,UAAM,SAAS,eAAe,UAAU,GAAG;AAC3C,UAAM,eAAe,MAAM,QAAQ,OAAO,IAAI,IAC1C,eAAe,UAAU,EAAE,GAAI,OAAO,CAAC,GAAI,aAAa,MAAM,CAAC,EAAE,OACjE;AAEJ,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,sBAAsB,OAAO,MAAM,SAAS,OAAO,iBAAiB,WAAW,eAAe,IAAI;AAAA,IAC1G;AAAA,EACF;AAEA,mBAAiB,IAAI,MAAM;AAC7B;AAEA,IAAM,YAAY;AAElB,SAAS,sBACP,MACA,SACA,eAA8B,MACX;AACnB,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,QAAIC,WAAyB;AAE7B,UAAM,QAAQ,KAAK,IAAI,CAAC,UAAU,UAAU;AAC1C,YAAMC,aAAY,gBAAgB,QAAQ;AAC1C,UAAIA,WAAU,SAAS,SAAS,GAAG;AACjC,QAAAD,WAAUC,WAAU,SAASA,WAAU,SAAS,SAAS,CAAC;AAAA,MAC5D;AAEA,aAAO,qBAAqBA,WAAU,MAAM,QAAQ,GAAG,OAAO;AAAA,IAChE,CAAC;AAED,QAAI,CAACD,YAAW,cAAc;AAC5B,YAAM,WAAW,gBAAgB,YAAY;AAC7C,MAAAA,WAAU,SAAS,SAAS,SAAS,SAAS,SAAS,CAAC,KAAK;AAAA,IAC/D;AAEA,QAAIA,YAAW,MAAM,SAAS,GAAG;AAC/B,YAAM,MAAM,SAAS,CAAC,KAAKA;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,gBAAgB,IAAI;AACtC,QAAM,YAAY,oBAAoB,UAAU,MAAM,OAAO;AAE7D,MAAI,UAAU,SAAS,WAAW,GAAG;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,UAAU,SAAS,UAAU,SAAS,SAAS,CAAC;AAChE,SAAO,2BAA2B,WAAW,OAAO;AACtD;AAEA,SAAS,gBAAgB,MAAoD;AAC3E,QAAM,WAAW,KAAK,MAAM,SAAS,KAAK,CAAC;AAC3C,SAAO;AAAA,IACL,MAAM,KAAK,QAAQ,WAAW,EAAE;AAAA,IAChC;AAAA,EACF;AACF;AAEA,SAAS,qBACP,MACA,YACA,SACQ;AACR,QAAM,WAAW,yBAAyB,OAAO;AACjD,SAAO,KAAK,QAAQ,4BAA4B,OAAO,QAAQ,KAAK,UAAU,KAAK;AACrF;AAEA,SAAS,oBAAoB,MAAc,SAAoC;AAC7E,MAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,iBAAiB,GAAG;AAC7D,WAAO,oBAAoB,MAAM,OAAO;AAAA,EAC1C;AAEA,QAAM,WAAW,yBAAyB,OAAO;AACjD,MAAI,aAAa;AAEjB,SAAO,KAAK,QAAQ,mBAAmB,CAAC,QAAQ,WAAmB;AACjE,kBAAc;AACd,WAAO,YAAY,QAAQ,KAAK,UAAU,IAAI,MAAM;AAAA,EACtD,CAAC;AACH;AAEA,SAAS,oBAAoB,MAAc,SAAoC;AAC7E,QAAM,WAAW,yBAAyB,OAAO;AACjD,MAAI,aAAa;AAEjB,SAAO,KAAK,QAAQ,mBAAmB,CAAC,QAAQ,UAAkB;AAChE,QAAI,CAAC,MAAM,SAAS,iBAAiB,GAAG;AACtC,aAAO,OAAO,KAAK;AAAA,IACrB;AAEA,kBAAc;AACd,WAAO,OAAO,KAAK,IAAI,QAAQ,KAAK,UAAU;AAAA,EAChD,CAAC;AACH;AAEA,SAAS,yBAAyB,UAAqC;AACrE,SAAO;AACT;AAEA,SAAS,2BAA2B,MAAc,SAAyB;AACzE,QAAM,kBAAkB,KAAK,YAAY,IAAI;AAC7C,MAAI,oBAAoB,IAAI;AAC1B,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,KAAK,MAAM,GAAG,eAAe,IAAI,UAAU,KAAK,MAAM,eAAe;AAC9E;;;AJ7KO,IAAM,aAA6B,iBAAiB,CAAC,SAA4B,QAAkB;AACxG,MAAI,QAAQ,UAAU;AACpB,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,QAAQ,QAAQ;AAClB,QAAI;AACF,aAAO,QAAQ,OAAO,SAAS,GAAG;AAAA,IACpC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,QAAQ,aAAa;AACvB,QAAI;AACF,YAAM,MAAM,KAAK,QAAQ,QAAQ,OAAO,QAAQ,IAAI,GAAG,QAAQ,WAAW;AAC1E,YAAM,UAAU,aAAa,KAAK,OAAO;AACzC,aAAO,oBAAoB,SAAS,GAAG;AAAA,IACzC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,QAAQ,cAAc;AACxB,QAAI;AACF,YAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AACvC,YAAM,MAAM,KAAK,QAAQ,KAAK,QAAQ,YAAY;AAClD,YAAM,WAAW,MAAM;AACvB,YAAM,WAAW,MAAM;AAEvB,UAAI,MAAqB;AACzB,UAAI,OAAsB;AAE1B,UAAI;AACF,cAAM,aAAa,UAAU,OAAO;AACpC,eAAO;AAAA,MACT,QAAQ;AACN,YAAI;AACF,gBAAM,aAAa,UAAU,OAAO;AACpC,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,UAAI,CAAC,KAAK;AACR,eAAO;AAAA,MACT;AAEA,aAAO,oBAAoB,KAAK,IAAK;AAAA,IACvC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT,CAAC;AAED,IAAO,gBAAQ;",
|
|
6
6
|
"names": ["resolveComments", "mrsfPlugin", "payload", "extracted"]
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -82,7 +82,6 @@ export interface SlimComment {
|
|
|
82
82
|
author: string;
|
|
83
83
|
text: string;
|
|
84
84
|
line: number | null;
|
|
85
|
-
x_page: number | null;
|
|
86
85
|
end_line: number | null;
|
|
87
86
|
start_column: number | null;
|
|
88
87
|
end_column: number | null;
|
|
@@ -92,6 +91,7 @@ export interface SlimComment {
|
|
|
92
91
|
severity: string | null;
|
|
93
92
|
type: string | null;
|
|
94
93
|
timestamp: string | null;
|
|
94
|
+
[key: `x_${string}`]: unknown;
|
|
95
95
|
}
|
|
96
96
|
/** A root comment with its threaded replies. */
|
|
97
97
|
export interface CommentThread {
|