@vielzeug/scribe 26.11.13 → 26.11.14
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/_policy.cjs +1 -1
- package/dist/_policy.cjs.map +1 -1
- package/dist/_policy.d.ts +5 -15
- package/dist/_policy.d.ts.map +1 -1
- package/dist/_policy.js +1 -49
- package/dist/_policy.js.map +1 -1
- package/dist/_text.cjs +2 -0
- package/dist/_text.cjs.map +1 -0
- package/dist/_text.d.ts +20 -0
- package/dist/_text.d.ts.map +1 -0
- package/dist/_text.js +52 -0
- package/dist/_text.js.map +1 -0
- package/dist/parse.cjs +7 -7
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.ts +1 -1
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +35 -18
- package/dist/parse.js.map +1 -1
- package/dist/render.cjs +7 -7
- package/dist/render.cjs.map +1 -1
- package/dist/render.d.ts +4 -4
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +31 -30
- package/dist/render.js.map +1 -1
- package/dist/scribe.cjs +1 -1
- package/dist/scribe.cjs.map +1 -1
- package/dist/scribe.iife.js +1 -1
- package/dist/scribe.iife.js.map +1 -1
- package/dist/scribe.js +21 -4
- package/dist/scribe.js.map +1 -1
- package/package.json +1 -1
package/dist/parse.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./_dev.js";
|
|
2
|
-
import {
|
|
2
|
+
import { sanitizeDestination as e } from "./_policy.js";
|
|
3
|
+
import { inlineText as t } from "./_text.js";
|
|
3
4
|
import { ScribeLimitError as n } from "./errors.js";
|
|
4
5
|
// src/parse.ts
|
|
5
6
|
var r = 2e5, i = 32, a = [
|
|
@@ -231,37 +232,53 @@ function parseInline(r, a) {
|
|
|
231
232
|
}
|
|
232
233
|
s += "`".repeat(e), c += e;
|
|
233
234
|
} else if (n === "<") {
|
|
234
|
-
let
|
|
235
|
-
if (
|
|
236
|
-
let n = t
|
|
237
|
-
if (n !== null) {
|
|
235
|
+
let t = /^<([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})>/.exec(r.slice(c));
|
|
236
|
+
if (t !== null) {
|
|
237
|
+
let n = `mailto:${t[1]}`;
|
|
238
|
+
if (e(n, a.protocols) !== null) {
|
|
238
239
|
flush(), o.push({
|
|
239
240
|
children: [{
|
|
240
|
-
text:
|
|
241
|
+
text: t[1],
|
|
241
242
|
type: "text"
|
|
242
243
|
}],
|
|
243
244
|
href: n,
|
|
244
245
|
type: "link"
|
|
245
|
-
}), c +=
|
|
246
|
+
}), c += t[0].length;
|
|
246
247
|
continue;
|
|
247
248
|
}
|
|
248
|
-
`${
|
|
249
|
+
`${n}`;
|
|
250
|
+
}
|
|
251
|
+
let n = /^<([A-Za-z][A-Za-z0-9+.-]*:[^<>\n]*)>/.exec(r.slice(c));
|
|
252
|
+
if (n !== null) {
|
|
253
|
+
let t = e(n[1], a.protocols);
|
|
254
|
+
if (t !== null) {
|
|
255
|
+
flush(), o.push({
|
|
256
|
+
children: [{
|
|
257
|
+
text: n[1],
|
|
258
|
+
type: "text"
|
|
259
|
+
}],
|
|
260
|
+
href: t,
|
|
261
|
+
type: "link"
|
|
262
|
+
}), c += n[0].length;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
`${n[1]}`, s += "<", c += 1;
|
|
249
266
|
continue;
|
|
250
267
|
}
|
|
251
268
|
s += "<", c += 1;
|
|
252
269
|
} else if (n === "!" && r[c + 1] === "[" || n === "[") {
|
|
253
270
|
let r = linkLike(n === "!" ? c + 1 : c);
|
|
254
271
|
if (r !== null) {
|
|
255
|
-
let i =
|
|
272
|
+
let i = e(r.dest, a.protocols);
|
|
256
273
|
if (flush(), i !== null) {
|
|
257
274
|
if (n === "!") {
|
|
258
|
-
let
|
|
259
|
-
alt:
|
|
275
|
+
let e = {
|
|
276
|
+
alt: t(parseInline(r.label, a)),
|
|
260
277
|
src: i,
|
|
261
278
|
type: "image"
|
|
262
279
|
};
|
|
263
|
-
o.push(r.title === void 0 ?
|
|
264
|
-
...
|
|
280
|
+
o.push(r.title === void 0 ? e : {
|
|
281
|
+
...e,
|
|
265
282
|
title: r.title
|
|
266
283
|
});
|
|
267
284
|
} else {
|
|
@@ -276,7 +293,7 @@ function parseInline(r, a) {
|
|
|
276
293
|
});
|
|
277
294
|
}
|
|
278
295
|
} else `${r.dest}`, n === "!" ? o.push({
|
|
279
|
-
text:
|
|
296
|
+
text: t(parseInline(r.label, a)),
|
|
280
297
|
type: "text"
|
|
281
298
|
}) : o.push(...parseInline(r.label, a));
|
|
282
299
|
c = r.end;
|
|
@@ -302,11 +319,11 @@ function parseInline(r, a) {
|
|
|
302
319
|
s += n.repeat(e), c += e;
|
|
303
320
|
} else {
|
|
304
321
|
if ((n === "h" || n === "H") && (c === 0 || /[\s_([{]/.test(r[c - 1]))) {
|
|
305
|
-
let
|
|
306
|
-
if (
|
|
307
|
-
let n =
|
|
322
|
+
let t = /^https?:\/\/\S+/.exec(r.slice(c));
|
|
323
|
+
if (t !== null) {
|
|
324
|
+
let n = t[0].replace(/[.,;:!?]+$/, "");
|
|
308
325
|
n.endsWith(")") && !n.includes("(") && (n = n.slice(0, -1));
|
|
309
|
-
let r =
|
|
326
|
+
let r = e(n, a.protocols);
|
|
310
327
|
if (r !== null) {
|
|
311
328
|
flush(), o.push({
|
|
312
329
|
children: [{
|
package/dist/parse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","names":["MAX_INPUT_LENGTH","MAX_DEPTH","DEFAULT_PROTOCOLS","RE_BLANK","RE_FENCE","RE_HEADING","RE_HR","RE_QUOTE","RE_UL","RE_OL","RE_TABLE_DELIM","RE_LANG","column","char","line","lines","index","text","row","cells","cell","i","delimiterRow","ctx","ScribeLimitError","blocks","paragraph","node","fence","marker","fenceIndent","lang","closeRe","content","heading","quoted","quote","list","header","alignments","rows","ul","ol","a","b","contentIndent","initial","items","loose","pendingBlanks","current","start","isItemStart","token","RE_PUNCT","tokens","buffer","src","at","depth","close","k","j","dest","title","angleEnd","parenDepth","bare","run","rest","found","autolink","href","sanitizeDestination","parsed","image","inlineText","link","prev","next","leftFlanking","rightFlanking","canOpen","canClose","url","trailing","resolved","ci","closer","oi","opener","strong","consumed","inner","wrapped","replacement","out","nodes","last","value","markdown","options","protocol"],"sources":["../src/parse.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { inlineText, sanitizeDestination } from './_policy';\nimport { ScribeLimitError } from './errors';\nimport type {\n ProseAlignment,\n ProseBlock,\n ProseCodeSpan,\n ProseDoc,\n ProseEmphasis,\n ProseHardBreak,\n ProseHeading,\n ProseHeadingLevel,\n ProseImage,\n ProseInline,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseParagraph,\n ProseParseOptions,\n ProseSoftBreak,\n ProseStrikethrough,\n ProseStrong,\n ProseTable,\n ProseTableCell,\n ProseText,\n ProseThematicBreak,\n} from './types';\n\n/** Inputs beyond this size are rejected outright; prose documents never reach it. */\nconst MAX_INPUT_LENGTH = 200_000;\n/** Block/inline nesting (blockquote in list in blockquote …) is bounded to keep recursion shallow. */\nconst MAX_DEPTH = 32;\nconst DEFAULT_PROTOCOLS: readonly string[] = ['http', 'https', 'mailto'];\n\ninterface Ctx {\n depth: number;\n readonly protocols: ReadonlySet<string>;\n}\n\n// ---------------------------------------------------------------------------\n// Block-level patterns (indentation is counted in expanded-tab columns)\n// ---------------------------------------------------------------------------\n\nconst RE_BLANK = /^[ \\t]*$/;\nconst RE_FENCE = /^ {0,3}(`{3,}|~{3,})(.*)$/;\nconst RE_HEADING = /^ {0,3}(#{1,6})(?:[ \\t]+(.*?))?(?:[ \\t]+#+)?[ \\t]*$/;\nconst RE_HR = /^(?: {0,3}(?:\\*[ \\t]*){3,}| {0,3}(?:-[ \\t]*){3,}| {0,3}(?:_[ \\t]*){3,})$/;\nconst RE_QUOTE = /^ {0,3}>[ \\t]?(.*)$/;\nconst RE_UL = /^( {0,3})([-+*])([ \\t]+)(.*)$/;\nconst RE_OL = /^( {0,3})(\\d{1,9})([.)])([ \\t]+)(.*)$/;\nconst RE_TABLE_DELIM = /^[ \\t]*\\|?[ \\t]*:?-+:?[ \\t]*(?:\\|[ \\t]*:?-+:?[ \\t]*)*\\|?[ \\t]*$/;\nconst RE_LANG = /^[\\p{L}\\p{N}_-]+/u;\n\nfunction indentOf(line: string): number {\n let column = 0;\n for (const char of line) {\n if (char === ' ') column += 1;\n else if (char === '\\t') column += 4;\n else break;\n }\n return column;\n}\n\nfunction isTableStart(lines: readonly string[], index: number): boolean {\n return lines[index].includes('|') && lines[index + 1] !== undefined && RE_TABLE_DELIM.test(lines[index + 1]);\n}\n\n/** Split a GFM table row on unescaped pipes, dropping one optional leading/trailing pipe. */\nfunction splitCells(row: string): string[] {\n let text = row.trim();\n if (text.startsWith('|')) text = text.slice(1);\n if (text.endsWith('|') && !text.endsWith('\\\\|')) text = text.slice(0, -1);\n const cells: string[] = [];\n let cell = '';\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i];\n if (char === '\\\\' && text[i + 1] === '|') {\n cell += '|';\n i += 1;\n } else if (char === '|') {\n cells.push(cell.trim());\n cell = '';\n } else {\n cell += char;\n }\n }\n cells.push(cell.trim());\n return cells;\n}\n\nfunction parseDelimAlignments(delimiterRow: string): ProseAlignment[] {\n return splitCells(delimiterRow).map((cell) => {\n if (cell.startsWith(':') && cell.endsWith(':')) return 'center';\n if (cell.endsWith(':')) return 'right';\n return 'left';\n });\n}\n\n// ---------------------------------------------------------------------------\n// Block parser\n// ---------------------------------------------------------------------------\n\nfunction parseBlocks(lines: readonly string[], ctx: Ctx): ProseBlock[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`block nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const blocks: ProseBlock[] = [];\n let paragraph: string[] = [];\n let i = 0;\n\n const flushParagraph = (): void => {\n if (paragraph.length === 0) return;\n const node: ProseParagraph = { children: parseInline(paragraph.join('\\n'), ctx), type: 'paragraph' };\n blocks.push(node);\n paragraph = [];\n };\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n flushParagraph();\n i += 1;\n continue;\n }\n\n const fence = RE_FENCE.exec(line);\n if (fence) {\n flushParagraph();\n const marker = fence[1];\n const fenceIndent = fence[0].indexOf(marker[0]);\n const lang = RE_LANG.exec(fence[2].trim())?.[0];\n const closeRe = new RegExp(`^ {0,3}\\\\${marker[0]}{${marker.length},}[ \\\\t]*$`);\n const content: string[] = [];\n i += 1;\n while (i < lines.length && !closeRe.test(lines[i])) {\n content.push(lines[i].slice(Math.min(indentOf(lines[i]), fenceIndent)));\n i += 1;\n }\n i += 1; // closing fence (or EOF)\n blocks.push(\n lang === undefined\n ? { text: content.join('\\n'), type: 'codeBlock' }\n : { language: lang, text: content.join('\\n'), type: 'codeBlock' },\n );\n continue;\n }\n\n const heading = RE_HEADING.exec(line);\n if (heading) {\n flushParagraph();\n blocks.push({\n children: parseInline(heading[2] ?? '', ctx),\n level: heading[1].length as ProseHeadingLevel,\n type: 'heading',\n } satisfies ProseHeading);\n i += 1;\n continue;\n }\n\n if (RE_HR.test(line)) {\n flushParagraph();\n blocks.push({ type: 'thematicBreak' } satisfies ProseThematicBreak);\n i += 1;\n continue;\n }\n\n if (RE_QUOTE.test(line)) {\n flushParagraph();\n const quoted: string[] = [];\n while (i < lines.length) {\n const quote = RE_QUOTE.exec(lines[i]);\n if (quote === null) break;\n quoted.push(quote[1]);\n i += 1;\n }\n blocks.push({ children: parseBlocks(quoted, ctx), type: 'blockquote' });\n continue;\n }\n\n const marker = matchListMarker(line);\n // A bullet list, or an ordered list starting at 1, may start (and interrupt a paragraph);\n // a line like `2. more` right below a paragraph is a paragraph continuation.\n if (marker !== null && (!marker.ordered || marker.start === 1 || paragraph.length === 0)) {\n flushParagraph();\n const list = parseList(lines, i, ctx, marker);\n blocks.push(list.block);\n i = list.next;\n continue;\n }\n\n if (paragraph.length === 0 && indentOf(line) >= 4) {\n const content: string[] = [];\n while (i < lines.length && (RE_BLANK.test(lines[i]) || indentOf(lines[i]) >= 4)) {\n if (RE_BLANK.test(lines[i]) && !(i + 1 < lines.length && indentOf(lines[i + 1]) >= 4)) break;\n content.push(lines[i].slice(4));\n i += 1;\n }\n blocks.push({ text: content.join('\\n'), type: 'codeBlock' });\n continue;\n }\n\n if (paragraph.length === 0 && isTableStart(lines, i)) {\n const header = splitCells(lines[i]);\n const alignments = parseDelimAlignments(lines[i + 1]);\n i += 2;\n const rows: ProseTableCell[][] = [];\n while (i < lines.length && !RE_BLANK.test(lines[i]) && lines[i].includes('|')) {\n const cells = splitCells(lines[i]);\n while (cells.length < alignments.length) cells.push('');\n rows.push(cells.slice(0, alignments.length).map((cell) => [...parseInline(cell, ctx)]));\n i += 1;\n }\n blocks.push({\n alignments,\n header: header\n .slice(0, alignments.length)\n .map((cell) => [...parseInline(cell, ctx)]) satisfies ProseTableCell[],\n rows,\n type: 'table',\n } satisfies ProseTable);\n continue;\n }\n\n paragraph.push(line);\n i += 1;\n }\n\n flushParagraph();\n ctx.depth -= 1;\n return blocks;\n}\n\ninterface ListMarker {\n /** Leading spaces before the marker, in expanded columns. */\n readonly indent: number;\n /** The bullet char (`-`, `+`, `*`) or the ordered delimiter (`.` or `)`). */\n readonly kind: string;\n readonly ordered: boolean;\n /** Spaces between marker and content. */\n readonly spaces: number;\n readonly start: number;\n /** Total marker width (`-` = 1, `12.` = 3). */\n readonly width: number;\n}\n\nfunction matchListMarker(line: string): ListMarker | null {\n const ul = RE_UL.exec(line);\n if (ul !== null) {\n return { indent: ul[1].length, kind: ul[2], ordered: false, spaces: ul[3].length, start: 1, width: 1 };\n }\n const ol = RE_OL.exec(line);\n if (ol !== null) {\n return {\n indent: ol[1].length,\n kind: ol[3],\n ordered: true,\n spaces: ol[4].length,\n start: Number(ol[2]),\n width: ol[2].length + 1,\n };\n }\n return null;\n}\n\nfunction sameMarker(a: ListMarker, b: ListMarker): boolean {\n return a.ordered === b.ordered && a.kind === b.kind;\n}\n\nfunction parseList(\n lines: readonly string[],\n start: number,\n ctx: Ctx,\n initial: ListMarker,\n): { block: ProseList; next: number } {\n // Content column after the marker; >=5 spaces after the marker keep an extra indent so the\n // first line can still be an indented code block, matching CommonMark's tab rule.\n const contentIndent = initial.indent + initial.width + (initial.spaces >= 5 ? 1 : initial.spaces);\n\n const items: ProseListItem[] = [];\n let loose = false;\n let pendingBlanks = 0;\n let current: string[] | null = null;\n let i = start;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n if (current !== null) pendingBlanks += 1;\n i += 1;\n continue;\n }\n\n // A marker strictly left of the content column is a sibling item; one at or beyond the\n // content column is item content (a nested list).\n const marker = indentOf(line) < contentIndent ? matchListMarker(line) : null;\n const isItemStart = marker !== null && sameMarker(marker, initial) && (current === null || i > start);\n\n if (isItemStart && current !== null) {\n if (pendingBlanks > 0) loose = true;\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n current = null;\n }\n\n if (isItemStart) {\n current = [line.slice(contentIndent)];\n pendingBlanks = 0;\n i += 1;\n continue;\n }\n\n if (current !== null && indentOf(line) >= contentIndent) {\n if (pendingBlanks > 0) loose = true;\n pendingBlanks = 0;\n current.push(line.slice(contentIndent));\n i += 1;\n continue;\n }\n\n break; // no lazy continuation: the list ends here\n }\n\n if (current !== null) {\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n }\n\n return {\n block: {\n items,\n ordered: initial.ordered,\n start: initial.start,\n tight: !loose,\n type: 'list',\n } satisfies ProseList,\n next: i,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline parser\n// ---------------------------------------------------------------------------\n\ninterface DelimTok {\n readonly canClose: boolean;\n readonly canOpen: boolean;\n readonly char: '*' | '_' | '~';\n count: number;\n readonly kind: 'delim';\n}\n\ntype Tok = ProseInline | DelimTok;\n\nconst isDelim = (token: Tok): token is DelimTok => 'kind' in token;\nconst RE_PUNCT = /[\\p{P}\\p{S}]/u;\n\nfunction parseInline(src: string, ctx: Ctx): ProseInline[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`inline nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const tokens: Tok[] = [];\n let buffer = '';\n\n const flush = (): void => {\n if (buffer === '') return;\n tokens.push({ text: buffer, type: 'text' } satisfies ProseText);\n buffer = '';\n };\n\n const linkLike = (at: number): { label: string; dest: string; title?: string; end: number } | null => {\n if (src[at] !== '[') return null;\n let depth = 0;\n let close = -1;\n for (let k = at; k < src.length; k += 1) {\n if (src[k] === '\\\\') k += 1;\n else if (src[k] === '[') depth += 1;\n else if (src[k] === ']') {\n depth -= 1;\n if (depth === 0) {\n close = k;\n break;\n }\n }\n }\n if (close === -1 || src[close + 1] !== '(') return null;\n let j = close + 2;\n let dest = '';\n let title: string | undefined;\n if (src[j] === '<') {\n const angleEnd = src.indexOf('>', j + 1);\n if (angleEnd === -1) return null;\n dest = src.slice(j + 1, angleEnd);\n j = angleEnd + 1;\n } else {\n let parenDepth = 0;\n while (j < src.length && !/\\s/.test(src[j])) {\n if (src[j] === ')' && parenDepth === 0) break;\n if (src[j] === '(') parenDepth += 1;\n else if (src[j] === ')') parenDepth -= 1;\n dest += src[j];\n j += 1;\n }\n }\n const quoted = /^\\s+(['\"])(.*?)\\1\\s*\\)/.exec(src.slice(j));\n if (quoted !== null) {\n title = quoted[2];\n j += quoted[0].length;\n } else {\n const bare = /^\\s*\\)/.exec(src.slice(j));\n if (bare === null) return null;\n j += bare[0].length;\n }\n return { dest, end: j, label: src.slice(at + 1, close), title };\n };\n\n let i = 0;\n while (i < src.length) {\n const char = src[i];\n\n if (char === '\\\\' && RE_PUNCT.test(src[i + 1] ?? '')) {\n buffer += src[i + 1];\n i += 2;\n continue;\n }\n if (char === '\\\\' && src[i + 1] === '\\n') {\n flush();\n tokens.push({ type: 'hardBreak' } satisfies ProseHardBreak);\n i += 2;\n continue;\n }\n\n if (char === '`') {\n let run = 0;\n while (src[i + run] === '`') run += 1;\n const rest = src.slice(i + run);\n const closeRe = new RegExp(`(?<!\\`)\\`{${run}}(?!\\`)`);\n const found = closeRe.exec(rest);\n if (found !== null) {\n let content = rest.slice(0, found.index);\n if (content.length >= 2 && content.startsWith(' ') && content.endsWith(' ') && !/^ +$/.test(content)) {\n content = content.slice(1, -1);\n }\n flush();\n tokens.push({ text: content, type: 'codeSpan' } satisfies ProseCodeSpan);\n i += run + found.index + run;\n continue;\n }\n buffer += '`'.repeat(run);\n i += run;\n continue;\n }\n\n if (char === '<') {\n const autolink = /^<([A-Za-z][A-Za-z0-9+.-]*:[^<>\\n]*)>/.exec(src.slice(i));\n if (autolink !== null) {\n const href = sanitizeDestination(autolink[1], ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({\n children: [{ text: autolink[1], type: 'text' }],\n href,\n type: 'link',\n } satisfies ProseLink);\n i += autolink[0].length;\n continue;\n }\n warn(`rejected autolink destination \"${autolink[1]}\"`);\n buffer += '<';\n i += 1;\n continue;\n }\n buffer += '<';\n i += 1;\n continue;\n }\n\n if ((char === '!' && src[i + 1] === '[') || char === '[') {\n const at = char === '!' ? i + 1 : i;\n const parsed = linkLike(at);\n if (parsed !== null) {\n const href = sanitizeDestination(parsed.dest, ctx.protocols);\n flush();\n if (href !== null) {\n if (char === '!') {\n const image: ProseImage = { alt: inlineText(parseInline(parsed.label, ctx)), src: href, type: 'image' };\n tokens.push(parsed.title === undefined ? image : { ...image, title: parsed.title });\n } else {\n const link: ProseLink = { children: parseInline(parsed.label, ctx), href, type: 'link' };\n tokens.push(parsed.title === undefined ? link : { ...link, title: parsed.title });\n }\n } else {\n warn(`rejected link destination \"${parsed.dest}\"`);\n if (char === '!') {\n tokens.push({ text: inlineText(parseInline(parsed.label, ctx)), type: 'text' } satisfies ProseText);\n } else {\n tokens.push(...parseInline(parsed.label, ctx));\n }\n }\n i = parsed.end;\n continue;\n }\n buffer += char;\n i += 1;\n continue;\n }\n\n if (char === '*' || char === '_' || char === '~') {\n let run = 0;\n while (src[i + run] === char) run += 1;\n if (char !== '~' || run === 2) {\n const prev = i === 0 ? ' ' : src[i - 1];\n const next = src[i + run] ?? ' ';\n const leftFlanking = !/\\s/.test(next) && (!RE_PUNCT.test(next) || /\\s/.test(prev) || RE_PUNCT.test(prev));\n const rightFlanking = !/\\s/.test(prev) && (!RE_PUNCT.test(prev) || /\\s/.test(next) || RE_PUNCT.test(next));\n const canOpen = char === '_' ? leftFlanking && (!rightFlanking || RE_PUNCT.test(prev)) : leftFlanking;\n const canClose = char === '_' ? rightFlanking && (!leftFlanking || RE_PUNCT.test(next)) : rightFlanking;\n if (canOpen || canClose) {\n flush();\n tokens.push({ canClose, canOpen, char, count: run, kind: 'delim' });\n i += run;\n continue;\n }\n }\n buffer += char.repeat(run);\n i += run;\n continue;\n }\n\n if ((char === 'h' || char === 'H') && (i === 0 || /[\\s_([{]/.test(src[i - 1]))) {\n const bare = /^https?:\\/\\/\\S+/.exec(src.slice(i));\n if (bare !== null) {\n let url = bare[0].replace(/[.,;:!?]+$/, '');\n if (url.endsWith(')') && !url.includes('(')) url = url.slice(0, -1);\n const href = sanitizeDestination(url, ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({ children: [{ text: url, type: 'text' }], href, type: 'link' } satisfies ProseLink);\n i += url.length;\n continue;\n }\n }\n }\n\n if (char === '\\n') {\n const trailing = /[ \\t]*$/.exec(buffer)?.[0] ?? '';\n if (trailing !== '') buffer = buffer.slice(0, -trailing.length);\n flush();\n tokens.push(\n (trailing.length >= 2 ? { type: 'hardBreak' } : { type: 'softBreak' }) satisfies\n | ProseHardBreak\n | ProseSoftBreak,\n );\n i += 1;\n continue;\n }\n\n buffer += char;\n i += 1;\n }\n\n flush();\n const resolved = resolveEmphasis(tokens);\n ctx.depth -= 1;\n return mergeText(resolved);\n}\n\n/** Match delimiter runs left-to-right; leftover delimiters become literal text. */\nfunction resolveEmphasis(tokens: Tok[]): ProseInline[] {\n for (let ci = 0; ci < tokens.length; ci += 1) {\n const closer = tokens[ci];\n if (!isDelim(closer) || !closer.canClose || closer.count === 0) continue;\n for (let oi = ci - 1; oi >= 0; oi -= 1) {\n const opener = tokens[oi];\n if (!isDelim(opener) || !opener.canOpen || opener.count === 0 || opener.char !== closer.char) continue;\n if (closer.char === '~' && (opener.count !== 2 || closer.count !== 2)) continue;\n const strong = closer.char !== '~' && opener.count >= 2 && closer.count >= 2;\n const consumed = closer.char === '~' ? 2 : strong ? 2 : 1;\n const inner = resolveRemainder(tokens.slice(oi + 1, ci));\n const wrapped: ProseStrong | ProseEmphasis | ProseStrikethrough = strong\n ? { children: inner, type: 'strong' }\n : closer.char === '~'\n ? { children: inner, type: 'strikethrough' }\n : { children: inner, type: 'emphasis' };\n const replacement: Tok[] = [];\n if (opener.count > consumed) {\n replacement.push({\n canClose: false,\n canOpen: true,\n char: opener.char,\n count: opener.count - consumed,\n kind: 'delim',\n });\n }\n replacement.push(wrapped);\n if (closer.count > consumed) {\n replacement.push({\n canClose: true,\n canOpen: false,\n char: closer.char,\n count: closer.count - consumed,\n kind: 'delim',\n });\n }\n tokens.splice(oi, ci - oi + 1, ...replacement);\n ci = oi - 1;\n break;\n }\n }\n return resolveRemainder(tokens);\n}\n\nfunction resolveRemainder(tokens: readonly Tok[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const token of tokens) {\n if (isDelim(token)) {\n if (token.count > 0) out.push({ text: token.char.repeat(token.count), type: 'text' });\n continue;\n }\n out.push(token);\n }\n return mergeText(out);\n}\n\nfunction mergeText(nodes: readonly ProseInline[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const node of nodes) {\n const last = out[out.length - 1];\n if (node.type === 'text' && last !== undefined && last.type === 'text') {\n out[out.length - 1] = { text: last.text + node.text, type: 'text' };\n } else {\n out.push(node);\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const inner of Object.values(value as Record<string, unknown>)) deepFreeze(inner);\n Object.freeze(value);\n }\n return value;\n}\n\n/**\n * Parse `markdown` into a frozen {@link ProseDoc}.\n *\n * The profile is a fixed GFM-flavored subset: ATX headings, paragraphs, fenced and indented\n * code, blockquotes, ordered/unordered lists, GFM pipe tables, thematic breaks, code spans,\n * emphasis/strong, strikethrough, inline links and images, autolinks (angle and bare `http(s)`),\n * and hard/soft breaks. Raw HTML, reference links, setext headings, HTML entities, footnotes,\n * and task lists are **not** part of the profile: they render as literal text. Tabs are\n * expanded to four spaces. Blockquotes and list items require every line to carry its marker\n * or content indent (no lazy paragraph continuation), and a GFM table must start on its own\n * line after a blank line.\n *\n * Link and image destinations are policy-checked here: relative URLs are always allowed,\n * `data:` is always rejected, and other schemes must appear in `options.linkProtocols`\n * (default `http`, `https`, `mailto`). A rejected destination degrades to the link's label\n * text (or the image's alt text) and logs a dev-only warning; it never throws.\n *\n * @throws {ScribeLimitError} when the input exceeds 200,000 characters or nests beyond\n * 32 block/inline levels.\n */\nexport function parseProse(markdown: string, options: ProseParseOptions = {}): ProseDoc {\n if (markdown.length > MAX_INPUT_LENGTH) {\n throw new ScribeLimitError(`input exceeds the ${MAX_INPUT_LENGTH}-character limit`);\n }\n const ctx: Ctx = {\n depth: 0,\n protocols: new Set((options.linkProtocols ?? DEFAULT_PROTOCOLS).map((protocol) => protocol.toLowerCase())),\n };\n const lines = markdown.replace(/\\r\\n?/g, '\\n').replaceAll('\\t', ' ').split('\\n');\n return deepFreeze({ blocks: parseBlocks(lines, ctx) });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parse.js","names":["MAX_INPUT_LENGTH","MAX_DEPTH","DEFAULT_PROTOCOLS","RE_BLANK","RE_FENCE","RE_HEADING","RE_HR","RE_QUOTE","RE_UL","RE_OL","RE_TABLE_DELIM","RE_LANG","column","char","line","lines","index","text","row","cells","cell","i","delimiterRow","ctx","ScribeLimitError","blocks","paragraph","node","fence","marker","fenceIndent","lang","closeRe","content","heading","quoted","quote","list","header","alignments","rows","ul","ol","a","b","contentIndent","initial","items","loose","pendingBlanks","current","start","isItemStart","token","RE_PUNCT","tokens","buffer","src","at","depth","close","k","j","dest","title","angleEnd","parenDepth","bare","run","rest","found","email","mailto","sanitizeDestination","autolink","href","parsed","image","inlineText","link","prev","next","leftFlanking","rightFlanking","canOpen","canClose","url","trailing","resolved","ci","closer","oi","opener","strong","consumed","inner","wrapped","replacement","out","nodes","last","value","markdown","options","protocol"],"sources":["../src/parse.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { sanitizeDestination } from './_policy';\nimport { inlineText } from './_text';\nimport { ScribeLimitError } from './errors';\nimport type {\n ProseAlignment,\n ProseBlock,\n ProseCodeSpan,\n ProseDoc,\n ProseEmphasis,\n ProseHardBreak,\n ProseHeading,\n ProseHeadingLevel,\n ProseImage,\n ProseInline,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseParagraph,\n ProseParseOptions,\n ProseSoftBreak,\n ProseStrikethrough,\n ProseStrong,\n ProseTable,\n ProseTableCell,\n ProseText,\n ProseThematicBreak,\n} from './types';\n\n/** Inputs beyond this size are rejected outright; prose documents never reach it. */\nconst MAX_INPUT_LENGTH = 200_000;\n/** Block/inline nesting (blockquote in list in blockquote …) is bounded to keep recursion shallow. */\nconst MAX_DEPTH = 32;\nconst DEFAULT_PROTOCOLS: readonly string[] = ['http', 'https', 'mailto'];\n\ninterface Ctx {\n depth: number;\n readonly protocols: ReadonlySet<string>;\n}\n\n// ---------------------------------------------------------------------------\n// Block-level patterns (indentation is counted in expanded-tab columns)\n// ---------------------------------------------------------------------------\n\nconst RE_BLANK = /^[ \\t]*$/;\nconst RE_FENCE = /^ {0,3}(`{3,}|~{3,})(.*)$/;\nconst RE_HEADING = /^ {0,3}(#{1,6})(?:[ \\t]+(.*?))?(?:[ \\t]+#+)?[ \\t]*$/;\nconst RE_HR = /^(?: {0,3}(?:\\*[ \\t]*){3,}| {0,3}(?:-[ \\t]*){3,}| {0,3}(?:_[ \\t]*){3,})$/;\nconst RE_QUOTE = /^ {0,3}>[ \\t]?(.*)$/;\nconst RE_UL = /^( {0,3})([-+*])([ \\t]+)(.*)$/;\nconst RE_OL = /^( {0,3})(\\d{1,9})([.)])([ \\t]+)(.*)$/;\nconst RE_TABLE_DELIM = /^[ \\t]*\\|?[ \\t]*:?-+:?[ \\t]*(?:\\|[ \\t]*:?-+:?[ \\t]*)*\\|?[ \\t]*$/;\nconst RE_LANG = /^[\\p{L}\\p{N}_-]+/u;\n\nfunction indentOf(line: string): number {\n let column = 0;\n for (const char of line) {\n if (char === ' ') column += 1;\n else if (char === '\\t') column += 4;\n else break;\n }\n return column;\n}\n\nfunction isTableStart(lines: readonly string[], index: number): boolean {\n return lines[index].includes('|') && lines[index + 1] !== undefined && RE_TABLE_DELIM.test(lines[index + 1]);\n}\n\n/** Split a GFM table row on unescaped pipes, dropping one optional leading/trailing pipe. */\nfunction splitCells(row: string): string[] {\n let text = row.trim();\n if (text.startsWith('|')) text = text.slice(1);\n if (text.endsWith('|') && !text.endsWith('\\\\|')) text = text.slice(0, -1);\n const cells: string[] = [];\n let cell = '';\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i];\n if (char === '\\\\' && text[i + 1] === '|') {\n cell += '|';\n i += 1;\n } else if (char === '|') {\n cells.push(cell.trim());\n cell = '';\n } else {\n cell += char;\n }\n }\n cells.push(cell.trim());\n return cells;\n}\n\nfunction parseDelimAlignments(delimiterRow: string): ProseAlignment[] {\n return splitCells(delimiterRow).map((cell) => {\n if (cell.startsWith(':') && cell.endsWith(':')) return 'center';\n if (cell.endsWith(':')) return 'right';\n return 'left';\n });\n}\n\n// ---------------------------------------------------------------------------\n// Block parser\n// ---------------------------------------------------------------------------\n\nfunction parseBlocks(lines: readonly string[], ctx: Ctx): ProseBlock[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`block nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const blocks: ProseBlock[] = [];\n let paragraph: string[] = [];\n let i = 0;\n\n const flushParagraph = (): void => {\n if (paragraph.length === 0) return;\n const node: ProseParagraph = { children: parseInline(paragraph.join('\\n'), ctx), type: 'paragraph' };\n blocks.push(node);\n paragraph = [];\n };\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n flushParagraph();\n i += 1;\n continue;\n }\n\n const fence = RE_FENCE.exec(line);\n if (fence) {\n flushParagraph();\n const marker = fence[1];\n const fenceIndent = fence[0].indexOf(marker[0]);\n const lang = RE_LANG.exec(fence[2].trim())?.[0];\n const closeRe = new RegExp(`^ {0,3}\\\\${marker[0]}{${marker.length},}[ \\\\t]*$`);\n const content: string[] = [];\n i += 1;\n while (i < lines.length && !closeRe.test(lines[i])) {\n content.push(lines[i].slice(Math.min(indentOf(lines[i]), fenceIndent)));\n i += 1;\n }\n i += 1; // closing fence (or EOF)\n blocks.push(\n lang === undefined\n ? { text: content.join('\\n'), type: 'codeBlock' }\n : { language: lang, text: content.join('\\n'), type: 'codeBlock' },\n );\n continue;\n }\n\n const heading = RE_HEADING.exec(line);\n if (heading) {\n flushParagraph();\n blocks.push({\n children: parseInline(heading[2] ?? '', ctx),\n level: heading[1].length as ProseHeadingLevel,\n type: 'heading',\n } satisfies ProseHeading);\n i += 1;\n continue;\n }\n\n if (RE_HR.test(line)) {\n flushParagraph();\n blocks.push({ type: 'thematicBreak' } satisfies ProseThematicBreak);\n i += 1;\n continue;\n }\n\n if (RE_QUOTE.test(line)) {\n flushParagraph();\n const quoted: string[] = [];\n while (i < lines.length) {\n const quote = RE_QUOTE.exec(lines[i]);\n if (quote === null) break;\n quoted.push(quote[1]);\n i += 1;\n }\n blocks.push({ children: parseBlocks(quoted, ctx), type: 'blockquote' });\n continue;\n }\n\n const marker = matchListMarker(line);\n // A bullet list, or an ordered list starting at 1, may start (and interrupt a paragraph);\n // a line like `2. more` right below a paragraph is a paragraph continuation.\n if (marker !== null && (!marker.ordered || marker.start === 1 || paragraph.length === 0)) {\n flushParagraph();\n const list = parseList(lines, i, ctx, marker);\n blocks.push(list.block);\n i = list.next;\n continue;\n }\n\n if (paragraph.length === 0 && indentOf(line) >= 4) {\n const content: string[] = [];\n while (i < lines.length && (RE_BLANK.test(lines[i]) || indentOf(lines[i]) >= 4)) {\n if (RE_BLANK.test(lines[i]) && !(i + 1 < lines.length && indentOf(lines[i + 1]) >= 4)) break;\n content.push(lines[i].slice(4));\n i += 1;\n }\n blocks.push({ text: content.join('\\n'), type: 'codeBlock' });\n continue;\n }\n\n if (paragraph.length === 0 && isTableStart(lines, i)) {\n const header = splitCells(lines[i]);\n const alignments = parseDelimAlignments(lines[i + 1]);\n i += 2;\n const rows: ProseTableCell[][] = [];\n while (i < lines.length && !RE_BLANK.test(lines[i]) && lines[i].includes('|')) {\n const cells = splitCells(lines[i]);\n while (cells.length < alignments.length) cells.push('');\n rows.push(cells.slice(0, alignments.length).map((cell) => [...parseInline(cell, ctx)]));\n i += 1;\n }\n blocks.push({\n alignments,\n header: header\n .slice(0, alignments.length)\n .map((cell) => [...parseInline(cell, ctx)]) satisfies ProseTableCell[],\n rows,\n type: 'table',\n } satisfies ProseTable);\n continue;\n }\n\n paragraph.push(line);\n i += 1;\n }\n\n flushParagraph();\n ctx.depth -= 1;\n return blocks;\n}\n\ninterface ListMarker {\n /** Leading spaces before the marker, in expanded columns. */\n readonly indent: number;\n /** The bullet char (`-`, `+`, `*`) or the ordered delimiter (`.` or `)`). */\n readonly kind: string;\n readonly ordered: boolean;\n /** Spaces between marker and content. */\n readonly spaces: number;\n readonly start: number;\n /** Total marker width (`-` = 1, `12.` = 3). */\n readonly width: number;\n}\n\nfunction matchListMarker(line: string): ListMarker | null {\n const ul = RE_UL.exec(line);\n if (ul !== null) {\n return { indent: ul[1].length, kind: ul[2], ordered: false, spaces: ul[3].length, start: 1, width: 1 };\n }\n const ol = RE_OL.exec(line);\n if (ol !== null) {\n return {\n indent: ol[1].length,\n kind: ol[3],\n ordered: true,\n spaces: ol[4].length,\n start: Number(ol[2]),\n width: ol[2].length + 1,\n };\n }\n return null;\n}\n\nfunction sameMarker(a: ListMarker, b: ListMarker): boolean {\n return a.ordered === b.ordered && a.kind === b.kind;\n}\n\nfunction parseList(\n lines: readonly string[],\n start: number,\n ctx: Ctx,\n initial: ListMarker,\n): { block: ProseList; next: number } {\n // Content column after the marker; >=5 spaces after the marker keep an extra indent so the\n // first line can still be an indented code block, matching CommonMark's tab rule.\n const contentIndent = initial.indent + initial.width + (initial.spaces >= 5 ? 1 : initial.spaces);\n\n const items: ProseListItem[] = [];\n let loose = false;\n let pendingBlanks = 0;\n let current: string[] | null = null;\n let i = start;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n if (current !== null) pendingBlanks += 1;\n i += 1;\n continue;\n }\n\n // A marker strictly left of the content column is a sibling item; one at or beyond the\n // content column is item content (a nested list).\n const marker = indentOf(line) < contentIndent ? matchListMarker(line) : null;\n const isItemStart = marker !== null && sameMarker(marker, initial) && (current === null || i > start);\n\n if (isItemStart && current !== null) {\n if (pendingBlanks > 0) loose = true;\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n current = null;\n }\n\n if (isItemStart) {\n current = [line.slice(contentIndent)];\n pendingBlanks = 0;\n i += 1;\n continue;\n }\n\n if (current !== null && indentOf(line) >= contentIndent) {\n if (pendingBlanks > 0) loose = true;\n pendingBlanks = 0;\n current.push(line.slice(contentIndent));\n i += 1;\n continue;\n }\n\n break; // no lazy continuation: the list ends here\n }\n\n if (current !== null) {\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n }\n\n return {\n block: {\n items,\n ordered: initial.ordered,\n start: initial.start,\n tight: !loose,\n type: 'list',\n } satisfies ProseList,\n next: i,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline parser\n// ---------------------------------------------------------------------------\n\ninterface DelimTok {\n readonly canClose: boolean;\n readonly canOpen: boolean;\n readonly char: '*' | '_' | '~';\n count: number;\n readonly kind: 'delim';\n}\n\ntype Tok = ProseInline | DelimTok;\n\nconst isDelim = (token: Tok): token is DelimTok => 'kind' in token;\nconst RE_PUNCT = /[\\p{P}\\p{S}]/u;\n\nfunction parseInline(src: string, ctx: Ctx): ProseInline[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`inline nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const tokens: Tok[] = [];\n let buffer = '';\n\n const flush = (): void => {\n if (buffer === '') return;\n tokens.push({ text: buffer, type: 'text' } satisfies ProseText);\n buffer = '';\n };\n\n const linkLike = (at: number): { label: string; dest: string; title?: string; end: number } | null => {\n if (src[at] !== '[') return null;\n let depth = 0;\n let close = -1;\n for (let k = at; k < src.length; k += 1) {\n if (src[k] === '\\\\') k += 1;\n else if (src[k] === '[') depth += 1;\n else if (src[k] === ']') {\n depth -= 1;\n if (depth === 0) {\n close = k;\n break;\n }\n }\n }\n if (close === -1 || src[close + 1] !== '(') return null;\n let j = close + 2;\n let dest = '';\n let title: string | undefined;\n if (src[j] === '<') {\n const angleEnd = src.indexOf('>', j + 1);\n if (angleEnd === -1) return null;\n dest = src.slice(j + 1, angleEnd);\n j = angleEnd + 1;\n } else {\n let parenDepth = 0;\n while (j < src.length && !/\\s/.test(src[j])) {\n if (src[j] === ')' && parenDepth === 0) break;\n if (src[j] === '(') parenDepth += 1;\n else if (src[j] === ')') parenDepth -= 1;\n dest += src[j];\n j += 1;\n }\n }\n const quoted = /^\\s+(['\"])(.*?)\\1\\s*\\)/.exec(src.slice(j));\n if (quoted !== null) {\n title = quoted[2];\n j += quoted[0].length;\n } else {\n const bare = /^\\s*\\)/.exec(src.slice(j));\n if (bare === null) return null;\n j += bare[0].length;\n }\n return { dest, end: j, label: src.slice(at + 1, close), title };\n };\n\n let i = 0;\n while (i < src.length) {\n const char = src[i];\n\n if (char === '\\\\' && RE_PUNCT.test(src[i + 1] ?? '')) {\n buffer += src[i + 1];\n i += 2;\n continue;\n }\n if (char === '\\\\' && src[i + 1] === '\\n') {\n flush();\n tokens.push({ type: 'hardBreak' } satisfies ProseHardBreak);\n i += 2;\n continue;\n }\n\n if (char === '`') {\n let run = 0;\n while (src[i + run] === '`') run += 1;\n const rest = src.slice(i + run);\n const closeRe = new RegExp(`(?<!\\`)\\`{${run}}(?!\\`)`);\n const found = closeRe.exec(rest);\n if (found !== null) {\n let content = rest.slice(0, found.index);\n if (content.length >= 2 && content.startsWith(' ') && content.endsWith(' ') && !/^ +$/.test(content)) {\n content = content.slice(1, -1);\n }\n flush();\n tokens.push({ text: content, type: 'codeSpan' } satisfies ProseCodeSpan);\n i += run + found.index + run;\n continue;\n }\n buffer += '`'.repeat(run);\n i += run;\n continue;\n }\n\n if (char === '<') {\n const email = /^<([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})>/.exec(src.slice(i));\n if (email !== null) {\n const mailto = `mailto:${email[1]}`;\n if (sanitizeDestination(mailto, ctx.protocols) !== null) {\n flush();\n tokens.push({\n children: [{ text: email[1], type: 'text' }],\n href: mailto,\n type: 'link',\n } satisfies ProseLink);\n i += email[0].length;\n continue;\n }\n warn(`rejected autolink destination \"${mailto}\"`);\n }\n const autolink = /^<([A-Za-z][A-Za-z0-9+.-]*:[^<>\\n]*)>/.exec(src.slice(i));\n if (autolink !== null) {\n const href = sanitizeDestination(autolink[1], ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({\n children: [{ text: autolink[1], type: 'text' }],\n href,\n type: 'link',\n } satisfies ProseLink);\n i += autolink[0].length;\n continue;\n }\n warn(`rejected autolink destination \"${autolink[1]}\"`);\n buffer += '<';\n i += 1;\n continue;\n }\n buffer += '<';\n i += 1;\n continue;\n }\n\n if ((char === '!' && src[i + 1] === '[') || char === '[') {\n const at = char === '!' ? i + 1 : i;\n const parsed = linkLike(at);\n if (parsed !== null) {\n const href = sanitizeDestination(parsed.dest, ctx.protocols);\n flush();\n if (href !== null) {\n if (char === '!') {\n const image: ProseImage = { alt: inlineText(parseInline(parsed.label, ctx)), src: href, type: 'image' };\n tokens.push(parsed.title === undefined ? image : { ...image, title: parsed.title });\n } else {\n const link: ProseLink = { children: parseInline(parsed.label, ctx), href, type: 'link' };\n tokens.push(parsed.title === undefined ? link : { ...link, title: parsed.title });\n }\n } else {\n warn(`rejected link destination \"${parsed.dest}\"`);\n if (char === '!') {\n tokens.push({ text: inlineText(parseInline(parsed.label, ctx)), type: 'text' } satisfies ProseText);\n } else {\n tokens.push(...parseInline(parsed.label, ctx));\n }\n }\n i = parsed.end;\n continue;\n }\n buffer += char;\n i += 1;\n continue;\n }\n\n if (char === '*' || char === '_' || char === '~') {\n let run = 0;\n while (src[i + run] === char) run += 1;\n if (char !== '~' || run === 2) {\n const prev = i === 0 ? ' ' : src[i - 1];\n const next = src[i + run] ?? ' ';\n const leftFlanking = !/\\s/.test(next) && (!RE_PUNCT.test(next) || /\\s/.test(prev) || RE_PUNCT.test(prev));\n const rightFlanking = !/\\s/.test(prev) && (!RE_PUNCT.test(prev) || /\\s/.test(next) || RE_PUNCT.test(next));\n const canOpen = char === '_' ? leftFlanking && (!rightFlanking || RE_PUNCT.test(prev)) : leftFlanking;\n const canClose = char === '_' ? rightFlanking && (!leftFlanking || RE_PUNCT.test(next)) : rightFlanking;\n if (canOpen || canClose) {\n flush();\n tokens.push({ canClose, canOpen, char, count: run, kind: 'delim' });\n i += run;\n continue;\n }\n }\n buffer += char.repeat(run);\n i += run;\n continue;\n }\n\n if ((char === 'h' || char === 'H') && (i === 0 || /[\\s_([{]/.test(src[i - 1]))) {\n const bare = /^https?:\\/\\/\\S+/.exec(src.slice(i));\n if (bare !== null) {\n let url = bare[0].replace(/[.,;:!?]+$/, '');\n if (url.endsWith(')') && !url.includes('(')) url = url.slice(0, -1);\n const href = sanitizeDestination(url, ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({ children: [{ text: url, type: 'text' }], href, type: 'link' } satisfies ProseLink);\n i += url.length;\n continue;\n }\n }\n }\n\n if (char === '\\n') {\n const trailing = /[ \\t]*$/.exec(buffer)?.[0] ?? '';\n if (trailing !== '') buffer = buffer.slice(0, -trailing.length);\n flush();\n tokens.push(\n (trailing.length >= 2 ? { type: 'hardBreak' } : { type: 'softBreak' }) satisfies\n | ProseHardBreak\n | ProseSoftBreak,\n );\n i += 1;\n continue;\n }\n\n buffer += char;\n i += 1;\n }\n\n flush();\n const resolved = resolveEmphasis(tokens);\n ctx.depth -= 1;\n return mergeText(resolved);\n}\n\n/** Match delimiter runs left-to-right; leftover delimiters become literal text. */\nfunction resolveEmphasis(tokens: Tok[]): ProseInline[] {\n for (let ci = 0; ci < tokens.length; ci += 1) {\n const closer = tokens[ci];\n if (!isDelim(closer) || !closer.canClose || closer.count === 0) continue;\n for (let oi = ci - 1; oi >= 0; oi -= 1) {\n const opener = tokens[oi];\n if (!isDelim(opener) || !opener.canOpen || opener.count === 0 || opener.char !== closer.char) continue;\n if (closer.char === '~' && (opener.count !== 2 || closer.count !== 2)) continue;\n const strong = closer.char !== '~' && opener.count >= 2 && closer.count >= 2;\n const consumed = closer.char === '~' ? 2 : strong ? 2 : 1;\n const inner = resolveRemainder(tokens.slice(oi + 1, ci));\n const wrapped: ProseStrong | ProseEmphasis | ProseStrikethrough = strong\n ? { children: inner, type: 'strong' }\n : closer.char === '~'\n ? { children: inner, type: 'strikethrough' }\n : { children: inner, type: 'emphasis' };\n const replacement: Tok[] = [];\n if (opener.count > consumed) {\n replacement.push({\n canClose: false,\n canOpen: true,\n char: opener.char,\n count: opener.count - consumed,\n kind: 'delim',\n });\n }\n replacement.push(wrapped);\n if (closer.count > consumed) {\n replacement.push({\n canClose: true,\n canOpen: false,\n char: closer.char,\n count: closer.count - consumed,\n kind: 'delim',\n });\n }\n tokens.splice(oi, ci - oi + 1, ...replacement);\n ci = oi - 1;\n break;\n }\n }\n return resolveRemainder(tokens);\n}\n\nfunction resolveRemainder(tokens: readonly Tok[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const token of tokens) {\n if (isDelim(token)) {\n if (token.count > 0) out.push({ text: token.char.repeat(token.count), type: 'text' });\n continue;\n }\n out.push(token);\n }\n return mergeText(out);\n}\n\nfunction mergeText(nodes: readonly ProseInline[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const node of nodes) {\n const last = out[out.length - 1];\n if (node.type === 'text' && last !== undefined && last.type === 'text') {\n out[out.length - 1] = { text: last.text + node.text, type: 'text' };\n } else {\n out.push(node);\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const inner of Object.values(value as Record<string, unknown>)) deepFreeze(inner);\n Object.freeze(value);\n }\n return value;\n}\n\n/**\n * Parse `markdown` into a frozen {@link ProseDoc}.\n *\n * The profile is a fixed GFM-flavored subset: ATX headings, paragraphs, fenced and indented\n * code, blockquotes, ordered/unordered lists, GFM pipe tables, thematic breaks, code spans,\n * emphasis/strong, strikethrough, inline links and images, autolinks (angle-bracket URIs, angle-bracket emails as `mailto:`, and bare `http(s)`),\n * and hard/soft breaks. Raw HTML, reference links, setext headings, HTML entities, footnotes,\n * and task lists are **not** part of the profile: they render as literal text. Tabs are\n * expanded to four spaces. Blockquotes and list items require every line to carry its marker\n * or content indent (no lazy paragraph continuation), and a GFM table must start on its own\n * line after a blank line.\n *\n * Link and image destinations are policy-checked here: relative URLs are always allowed,\n * `data:` is always rejected, and other schemes must appear in `options.linkProtocols`\n * (default `http`, `https`, `mailto`). A rejected destination degrades to the link's label\n * text (or the image's alt text) and logs a dev-only warning; it never throws.\n *\n * @throws {ScribeLimitError} when the input exceeds 200,000 characters or nests beyond\n * 32 block/inline levels.\n */\nexport function parseProse(markdown: string, options: ProseParseOptions = {}): ProseDoc {\n if (markdown.length > MAX_INPUT_LENGTH) {\n throw new ScribeLimitError(`input exceeds the ${MAX_INPUT_LENGTH}-character limit`);\n }\n const ctx: Ctx = {\n depth: 0,\n protocols: new Set((options.linkProtocols ?? DEFAULT_PROTOCOLS).map((protocol) => protocol.toLowerCase())),\n };\n const lines = markdown.replace(/\\r\\n?/g, '\\n').replaceAll('\\t', ' ').split('\\n');\n return deepFreeze({ blocks: parseBlocks(lines, ctx) });\n}\n"],"mappings":"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"}
|
package/dist/render.cjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
const e=require("./_policy.cjs");function titleAttr(t){return t===void 0?``:` title="${e.escapeHtml(t)}"`}function inlineHtml(t){let n=``;for(let r of t)switch(r.type){case`text`:n+=e.escapeHtml(r.text);break;case`codeSpan`:n+=`<code>${e.escapeHtml(r.text)}</code>`;break;case`strong`:n+=`<strong>${inlineHtml(r.children)}</strong>`;break;case`emphasis`:n+=`<em>${inlineHtml(r.children)}</em>`;break;case`strikethrough`:n+=`<del>${inlineHtml(r.children)}</del>`;break;case`link`:n+=`<a href="${e.escapeHtml(r.href)}"${titleAttr(r.title)}>${inlineHtml(r.children)}</a>`;break;case`image`:n+=`<img src="${e.escapeHtml(r.src)}" alt="${e.escapeHtml(r.alt)}"${titleAttr(r.title)}>`;break;case`softBreak`:n+=`
|
|
1
|
+
const e=require("./_policy.cjs"),t=require("./_text.cjs");function titleAttr(t){return t===void 0?``:` title="${e.escapeHtml(t)}"`}function inlineHtml(t){let n=``;for(let r of t)switch(r.type){case`text`:n+=e.escapeHtml(r.text);break;case`codeSpan`:n+=`<code>${e.escapeHtml(r.text)}</code>`;break;case`strong`:n+=`<strong>${inlineHtml(r.children)}</strong>`;break;case`emphasis`:n+=`<em>${inlineHtml(r.children)}</em>`;break;case`strikethrough`:n+=`<del>${inlineHtml(r.children)}</del>`;break;case`link`:n+=`<a href="${e.escapeHtml(r.href)}"${titleAttr(r.title)}>${inlineHtml(r.children)}</a>`;break;case`image`:n+=`<img src="${e.escapeHtml(r.src)}" alt="${e.escapeHtml(r.alt)}"${titleAttr(r.title)}>`;break;case`softBreak`:n+=`
|
|
2
2
|
`;break;case`hardBreak`:n+=`<br />
|
|
3
|
-
`}return n}function headingAttrs(
|
|
3
|
+
`}return n}function headingAttrs(e,n,r){return r?` id="${n.slug(t.inlineText(e))}"`:``}function blocksHtml(t,n,r,i){let a=[];for(let o of t)switch(o.type){case`paragraph`:{let e=inlineHtml(o.children);a.push(i?e:`<p>${e}</p>`);break}case`heading`:{let e=o.level;a.push(`<h${e}${headingAttrs(o.children,n,r)}>${inlineHtml(o.children)}</h${e}>`);break}case`codeBlock`:{let t=o.language===void 0?``:` class="language-${e.escapeHtml(o.language)}"`;a.push(`<pre><code${t}>${e.escapeHtml(o.text)}\n</code></pre>`);break}case`blockquote`:a.push(`<blockquote>\n${blocksHtml(o.children,n,r,!1)}\n</blockquote>`);break;case`list`:{let e=o.ordered?`ol`:`ul`,t=o.ordered&&o.start!==1?` start="${o.start}"`:``,i=o.items.map(e=>`<li>${blocksHtml(e.children,n,r,o.tight)}</li>`).join(`
|
|
4
4
|
`);a.push(`<${e}${t}>\n${i}\n</${e}>`);break}case`thematicBreak`:a.push(`<hr />`);break;case`table`:{let cellAttrs=e=>{let t=o.alignments[e];return t===void 0||t===`left`?``:` align="${t}"`},e=`<tr>${o.header.map((e,t)=>`<th${cellAttrs(t)}>${inlineHtml(e)}</th>`).join(``)}</tr>`,t=o.rows.map(e=>`<tr>${e.map((e,t)=>`<td${cellAttrs(t)}>${inlineHtml(e)}</td>`).join(``)}</tr>`).join(`
|
|
5
5
|
`);a.push(`<table>\n<thead>\n${e}\n</thead>\n<tbody>\n${t.length===0?``:`${t}\n`}</tbody>\n</table>`);break}}return a.join(`
|
|
6
|
-
`)}function renderProseHtml(
|
|
7
|
-
`));break;case`hardBreak`:n.push(e.createElement(`br`))}return n}function blocksDom(
|
|
6
|
+
`)}function renderProseHtml(e,n={}){return blocksHtml(e.blocks,t.createSlugger(),n.headingIds===!0,!1)}function inlineDom(e,t){let n=[];for(let r of t)switch(r.type){case`text`:n.push(e.createTextNode(r.text));break;case`codeSpan`:{let t=e.createElement(`code`);t.append(e.createTextNode(r.text)),n.push(t);break}case`strong`:case`emphasis`:case`strikethrough`:{let t=e.createElement(r.type===`strikethrough`?`del`:r.type===`strong`?`strong`:`em`);t.append(...inlineDom(e,r.children)),n.push(t);break}case`link`:{let t=e.createElement(`a`);t.setAttribute(`href`,r.href),r.title!==void 0&&t.setAttribute(`title`,r.title),t.append(...inlineDom(e,r.children)),n.push(t);break}case`image`:{let t=e.createElement(`img`);t.setAttribute(`src`,r.src),t.setAttribute(`alt`,r.alt),r.title!==void 0&&t.setAttribute(`title`,r.title),n.push(t);break}case`softBreak`:n.push(e.createTextNode(`
|
|
7
|
+
`));break;case`hardBreak`:n.push(e.createElement(`br`))}return n}function blocksDom(e,n,r,i,a){let o=e.createDocumentFragment();for(let s of n)switch(s.type){case`paragraph`:if(a)o.append(...inlineDom(e,s.children));else{let t=e.createElement(`p`);t.append(...inlineDom(e,s.children)),o.append(t)}break;case`heading`:{let n=e.createElement(`h${s.level}`);i&&n.setAttribute(`id`,r.slug(t.inlineText(s.children))),n.append(...inlineDom(e,s.children)),o.append(n);break}case`codeBlock`:{let t=e.createElement(`pre`),n=e.createElement(`code`);s.language!==void 0&&n.classList.add(`language-${s.language}`),n.append(e.createTextNode(s.text)),t.append(n),o.append(t);break}case`blockquote`:{let t=e.createElement(`blockquote`);t.append(blocksDom(e,s.children,r,i,!1)),o.append(t);break}case`list`:{let t=e.createElement(s.ordered?`ol`:`ul`);s.ordered&&s.start!==1&&t.setAttribute(`start`,String(s.start));for(let n of s.items){let a=e.createElement(`li`);a.append(blocksDom(e,n.children,r,i,s.tight)),t.append(a)}o.append(t);break}case`thematicBreak`:o.append(e.createElement(`hr`));break;case`table`:{let t=e.createElement(`table`),n=e.createElement(`thead`),r=e.createElement(`tr`);s.header.forEach((t,n)=>{let i=e.createElement(`th`),a=s.alignments[n];a!==void 0&&a!==`left`&&i.setAttribute(`align`,a),i.append(...inlineDom(e,t)),r.append(i)}),n.append(r);let i=e.createElement(`tbody`);for(let t of s.rows){let n=e.createElement(`tr`);t.forEach((t,r)=>{let i=e.createElement(`td`),a=s.alignments[r];a!==void 0&&a!==`left`&&i.setAttribute(`align`,a),i.append(...inlineDom(e,t)),n.append(i)}),i.append(n)}t.append(n,i),o.append(t);break}}return o}function renderProseDom(e,n={}){return blocksDom(document,e.blocks,t.createSlugger(),n.headingIds===!0,!1)}function blockText(e){switch(e.type){case`paragraph`:return t.inlineText(e.children);case`heading`:return t.inlineText(e.children);case`codeBlock`:return e.text;case`blockquote`:return e.children.map(blockText).join(`
|
|
8
8
|
|
|
9
|
-
`);case`list`:return
|
|
9
|
+
`);case`list`:return e.items.map((t,n)=>(e.ordered?`${e.start+n}. `:`- `)+t.children.map(blockText).join(`
|
|
10
10
|
|
|
11
11
|
`)).join(`
|
|
12
|
-
`);case`thematicBreak`:return``;case`table`:return[
|
|
12
|
+
`);case`thematicBreak`:return``;case`table`:return[e.header,...e.rows].map(e=>e.map(e=>t.inlineText(e)).join(` | `)).join(`
|
|
13
13
|
`)}}function proseToText(e){return e.blocks.map(blockText).filter(e=>e!==``).join(`
|
|
14
14
|
|
|
15
|
-
`)}function proseOutline(
|
|
15
|
+
`)}function proseOutline(e,n={}){return t.collectOutline(e.blocks,t.createSlugger(),n.maxLevel??6)}exports.proseOutline=proseOutline,exports.proseToText=proseToText,exports.renderProseDom=renderProseDom,exports.renderProseHtml=renderProseHtml;
|
|
16
16
|
//# sourceMappingURL=render.cjs.map
|
package/dist/render.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.cjs","names":["escapeHtml","inlineText","createSlugger","collectOutline","require__policy","title","out","node","nodes","emitIds","slugger","children","parts","block","blocks","inner","unwrapParagraphs","level","cls","tag","startAttr","items","item","alignment","index","headerRow","cell","bodyRows","row","doc","options","code","element","anchor","image","fragment","p","heading","pre","quote","list","li","table","thead","th","tbody","tr","td","text"],"sources":["../src/render.ts"],"sourcesContent":["import { collectOutline, createSlugger, escapeHtml, inlineText, type ProseSlugger } from './_policy';\nimport type {\n ProseBlock,\n ProseDoc,\n ProseInline,\n ProseOutlineEntry,\n ProseOutlineOptions,\n ProseRenderOptions,\n} from './types';\n\nfunction titleAttr(title: string | undefined): string {\n return title === undefined ? '' : ` title=\"${escapeHtml(title)}\"`;\n}\n\nfunction inlineHtml(nodes: readonly ProseInline[]): string {\n let out = '';\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out += escapeHtml(node.text);\n break;\n case 'codeSpan':\n out += `<code>${escapeHtml(node.text)}</code>`;\n break;\n case 'strong':\n out += `<strong>${inlineHtml(node.children)}</strong>`;\n break;\n case 'emphasis':\n out += `<em>${inlineHtml(node.children)}</em>`;\n break;\n case 'strikethrough':\n out += `<del>${inlineHtml(node.children)}</del>`;\n break;\n case 'link':\n out += `<a href=\"${escapeHtml(node.href)}\"${titleAttr(node.title)}>${inlineHtml(node.children)}</a>`;\n break;\n case 'image':\n out += `<img src=\"${escapeHtml(node.src)}\" alt=\"${escapeHtml(node.alt)}\"${titleAttr(node.title)}>`;\n break;\n case 'softBreak':\n out += '\\n';\n break;\n case 'hardBreak':\n out += '<br />\\n';\n break;\n }\n }\n return out;\n}\n\nfunction headingAttrs(children: readonly ProseInline[], slugger: ProseSlugger, emitIds: boolean): string {\n return emitIds ? ` id=\"${slugger.slug(inlineText(children))}\"` : '';\n}\n\nfunction blocksHtml(\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): string {\n const parts: string[] = [];\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n const inner = inlineHtml(block.children);\n parts.push(unwrapParagraphs ? inner : `<p>${inner}</p>`);\n break;\n }\n case 'heading': {\n const level = block.level;\n parts.push(\n `<h${level}${headingAttrs(block.children, slugger, emitIds)}>${inlineHtml(block.children)}</h${level}>`,\n );\n break;\n }\n case 'codeBlock': {\n const cls = block.language === undefined ? '' : ` class=\"language-${escapeHtml(block.language)}\"`;\n parts.push(`<pre><code${cls}>${escapeHtml(block.text)}\\n</code></pre>`);\n break;\n }\n case 'blockquote':\n parts.push(`<blockquote>\\n${blocksHtml(block.children, slugger, emitIds, false)}\\n</blockquote>`);\n break;\n case 'list': {\n const tag = block.ordered ? 'ol' : 'ul';\n const startAttr = block.ordered && block.start !== 1 ? ` start=\"${block.start}\"` : '';\n const items = block.items\n .map((item) => `<li>${blocksHtml(item.children, slugger, emitIds, block.tight)}</li>`)\n .join('\\n');\n parts.push(`<${tag}${startAttr}>\\n${items}\\n</${tag}>`);\n break;\n }\n case 'thematicBreak':\n parts.push('<hr />');\n break;\n case 'table': {\n const cellAttrs = (index: number): string => {\n const alignment = block.alignments[index];\n return alignment === undefined || alignment === 'left' ? '' : ` align=\"${alignment}\"`;\n };\n const headerRow = `<tr>${block.header\n .map((cell, index) => `<th${cellAttrs(index)}>${inlineHtml(cell)}</th>`)\n .join('')}</tr>`;\n const bodyRows = block.rows\n .map(\n (row) => `<tr>${row.map((cell, index) => `<td${cellAttrs(index)}>${inlineHtml(cell)}</td>`).join('')}</tr>`,\n )\n .join('\\n');\n parts.push(\n `<table>\\n<thead>\\n${headerRow}\\n</thead>\\n<tbody>\\n${bodyRows.length === 0 ? '' : `${bodyRows}\\n`}</tbody>\\n</table>`,\n );\n break;\n }\n }\n }\n return parts.join('\\n');\n}\n\n/**\n * Render a parsed document to an HTML string. Every dynamic value is escaped; the only tags\n * emitted are the fixed set the renderer itself writes. Pair with a Content-Security-Policy\n * that disallows inline handlers for defense in depth — the string itself carries none.\n *\n * Requires a browser (or DOM) environment for {@link renderProseDom}; Node can use this\n * string renderer directly.\n */\nexport function renderProseHtml(doc: ProseDoc, options: ProseRenderOptions = {}): string {\n return blocksHtml(doc.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction inlineDom(doc: Document, nodes: readonly ProseInline[]): (Element | Text)[] {\n const out: (Element | Text)[] = [];\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out.push(doc.createTextNode(node.text));\n break;\n case 'codeSpan': {\n const code = doc.createElement('code');\n code.append(doc.createTextNode(node.text));\n out.push(code);\n break;\n }\n case 'strong':\n case 'emphasis':\n case 'strikethrough': {\n const element = doc.createElement(\n node.type === 'strikethrough' ? 'del' : node.type === 'strong' ? 'strong' : 'em',\n );\n element.append(...inlineDom(doc, node.children));\n out.push(element);\n break;\n }\n case 'link': {\n const anchor = doc.createElement('a');\n anchor.setAttribute('href', node.href);\n if (node.title !== undefined) anchor.setAttribute('title', node.title);\n anchor.append(...inlineDom(doc, node.children));\n out.push(anchor);\n break;\n }\n case 'image': {\n const image = doc.createElement('img');\n image.setAttribute('src', node.src);\n image.setAttribute('alt', node.alt);\n if (node.title !== undefined) image.setAttribute('title', node.title);\n out.push(image);\n break;\n }\n case 'softBreak':\n out.push(doc.createTextNode('\\n'));\n break;\n case 'hardBreak':\n out.push(doc.createElement('br'));\n break;\n }\n }\n return out;\n}\n\nfunction blocksDom(\n doc: Document,\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): DocumentFragment {\n const fragment = doc.createDocumentFragment();\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n if (unwrapParagraphs) {\n fragment.append(...inlineDom(doc, block.children));\n } else {\n const p = doc.createElement('p');\n p.append(...inlineDom(doc, block.children));\n fragment.append(p);\n }\n break;\n }\n case 'heading': {\n const heading = doc.createElement(`h${block.level}`);\n if (emitIds) heading.setAttribute('id', slugger.slug(inlineText(block.children)));\n heading.append(...inlineDom(doc, block.children));\n fragment.append(heading);\n break;\n }\n case 'codeBlock': {\n const pre = doc.createElement('pre');\n const code = doc.createElement('code');\n if (block.language !== undefined) code.classList.add(`language-${block.language}`);\n code.append(doc.createTextNode(block.text));\n pre.append(code);\n fragment.append(pre);\n break;\n }\n case 'blockquote': {\n const quote = doc.createElement('blockquote');\n quote.append(blocksDom(doc, block.children, slugger, emitIds, false));\n fragment.append(quote);\n break;\n }\n case 'list': {\n const list = doc.createElement(block.ordered ? 'ol' : 'ul');\n if (block.ordered && block.start !== 1) list.setAttribute('start', String(block.start));\n for (const item of block.items) {\n const li = doc.createElement('li');\n li.append(blocksDom(doc, item.children, slugger, emitIds, block.tight));\n list.append(li);\n }\n fragment.append(list);\n break;\n }\n case 'thematicBreak':\n fragment.append(doc.createElement('hr'));\n break;\n case 'table': {\n const table = doc.createElement('table');\n const thead = doc.createElement('thead');\n const headerRow = doc.createElement('tr');\n block.header.forEach((cell, index) => {\n const th = doc.createElement('th');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') th.setAttribute('align', alignment);\n th.append(...inlineDom(doc, cell));\n headerRow.append(th);\n });\n thead.append(headerRow);\n const tbody = doc.createElement('tbody');\n for (const row of block.rows) {\n const tr = doc.createElement('tr');\n row.forEach((cell, index) => {\n const td = doc.createElement('td');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') td.setAttribute('align', alignment);\n td.append(...inlineDom(doc, cell));\n tr.append(td);\n });\n tbody.append(tr);\n }\n table.append(thead, tbody);\n fragment.append(table);\n break;\n }\n }\n }\n return fragment;\n}\n\n/**\n * Render a parsed document to a `DocumentFragment`. Text reaches the DOM exclusively through\n * `createTextNode`, so document content can never execute: no `innerHTML`, no attribute is ever\n * sourced from Markdown beyond `href`/`src`/`alt`/`title`/slug `id`s, and those already passed\n * the parse-time protocol policy. Requires a DOM environment.\n */\nexport function renderProseDom(doc: ProseDoc, options: ProseRenderOptions = {}): DocumentFragment {\n return blocksDom(document, doc.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction blockText(block: ProseBlock): string {\n switch (block.type) {\n case 'paragraph':\n return inlineText(block.children);\n case 'heading':\n return inlineText(block.children);\n case 'codeBlock':\n return block.text;\n case 'blockquote':\n return block.children.map(blockText).join('\\n\\n');\n case 'list':\n return block.items\n .map((item, index) => {\n const marker = block.ordered ? `${block.start + index}. ` : '- ';\n return marker + item.children.map(blockText).join('\\n\\n');\n })\n .join('\\n');\n case 'thematicBreak':\n return '';\n case 'table': {\n const rows = [block.header, ...block.rows].map((row) => row.map((cell) => inlineText(cell)).join(' | '));\n return rows.join('\\n');\n }\n }\n}\n\n/**\n * Render the document as plain text: for notifications, search indexing, and previews.\n * Links keep their label text, images their alt text.\n */\nexport function proseToText(doc: ProseDoc): string {\n return doc.blocks\n .map(blockText)\n .filter((text) => text !== '')\n .join('\\n\\n');\n}\n\n/**\n * The document's headings with stable slug ids, traversed exactly as `renderProse*` does with\n * `headingIds` (including headings nested in blockquotes and lists), so outline ids always\n * match the rendered document. Use for tables of contents.\n */\nexport function proseOutline(doc: ProseDoc, options: ProseOutlineOptions = {}): readonly ProseOutlineEntry[] {\n return collectOutline(doc.blocks, createSlugger(), options.maxLevel ?? 6);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"render.cjs","names":["escapeHtml","inlineText","createSlugger","collectOutline","require__policy","require__text","title","out","node","nodes","emitIds","slugger","children","parts","block","blocks","inner","unwrapParagraphs","level","cls","tag","startAttr","items","item","alignment","index","headerRow","cell","bodyRows","row","prose","options","doc","code","element","anchor","image","fragment","p","heading","pre","quote","list","li","table","thead","th","tbody","tr","td","text"],"sources":["../src/render.ts"],"sourcesContent":["import { escapeHtml } from './_policy';\nimport { collectOutline, createSlugger, inlineText, type ProseSlugger } from './_text';\nimport type {\n ProseBlock,\n ProseDoc,\n ProseInline,\n ProseOutlineEntry,\n ProseOutlineOptions,\n ProseRenderOptions,\n} from './types';\n\nfunction titleAttr(title: string | undefined): string {\n return title === undefined ? '' : ` title=\"${escapeHtml(title)}\"`;\n}\n\nfunction inlineHtml(nodes: readonly ProseInline[]): string {\n let out = '';\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out += escapeHtml(node.text);\n break;\n case 'codeSpan':\n out += `<code>${escapeHtml(node.text)}</code>`;\n break;\n case 'strong':\n out += `<strong>${inlineHtml(node.children)}</strong>`;\n break;\n case 'emphasis':\n out += `<em>${inlineHtml(node.children)}</em>`;\n break;\n case 'strikethrough':\n out += `<del>${inlineHtml(node.children)}</del>`;\n break;\n case 'link':\n out += `<a href=\"${escapeHtml(node.href)}\"${titleAttr(node.title)}>${inlineHtml(node.children)}</a>`;\n break;\n case 'image':\n out += `<img src=\"${escapeHtml(node.src)}\" alt=\"${escapeHtml(node.alt)}\"${titleAttr(node.title)}>`;\n break;\n case 'softBreak':\n out += '\\n';\n break;\n case 'hardBreak':\n out += '<br />\\n';\n break;\n }\n }\n return out;\n}\n\nfunction headingAttrs(children: readonly ProseInline[], slugger: ProseSlugger, emitIds: boolean): string {\n return emitIds ? ` id=\"${slugger.slug(inlineText(children))}\"` : '';\n}\n\nfunction blocksHtml(\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): string {\n const parts: string[] = [];\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n const inner = inlineHtml(block.children);\n parts.push(unwrapParagraphs ? inner : `<p>${inner}</p>`);\n break;\n }\n case 'heading': {\n const level = block.level;\n parts.push(\n `<h${level}${headingAttrs(block.children, slugger, emitIds)}>${inlineHtml(block.children)}</h${level}>`,\n );\n break;\n }\n case 'codeBlock': {\n const cls = block.language === undefined ? '' : ` class=\"language-${escapeHtml(block.language)}\"`;\n parts.push(`<pre><code${cls}>${escapeHtml(block.text)}\\n</code></pre>`);\n break;\n }\n case 'blockquote':\n parts.push(`<blockquote>\\n${blocksHtml(block.children, slugger, emitIds, false)}\\n</blockquote>`);\n break;\n case 'list': {\n const tag = block.ordered ? 'ol' : 'ul';\n const startAttr = block.ordered && block.start !== 1 ? ` start=\"${block.start}\"` : '';\n const items = block.items\n .map((item) => `<li>${blocksHtml(item.children, slugger, emitIds, block.tight)}</li>`)\n .join('\\n');\n parts.push(`<${tag}${startAttr}>\\n${items}\\n</${tag}>`);\n break;\n }\n case 'thematicBreak':\n parts.push('<hr />');\n break;\n case 'table': {\n const cellAttrs = (index: number): string => {\n const alignment = block.alignments[index];\n return alignment === undefined || alignment === 'left' ? '' : ` align=\"${alignment}\"`;\n };\n const headerRow = `<tr>${block.header\n .map((cell, index) => `<th${cellAttrs(index)}>${inlineHtml(cell)}</th>`)\n .join('')}</tr>`;\n const bodyRows = block.rows\n .map(\n (row) => `<tr>${row.map((cell, index) => `<td${cellAttrs(index)}>${inlineHtml(cell)}</td>`).join('')}</tr>`,\n )\n .join('\\n');\n parts.push(\n `<table>\\n<thead>\\n${headerRow}\\n</thead>\\n<tbody>\\n${bodyRows.length === 0 ? '' : `${bodyRows}\\n`}</tbody>\\n</table>`,\n );\n break;\n }\n }\n }\n return parts.join('\\n');\n}\n\n/**\n * Render a parsed document to an HTML string. Every dynamic value is escaped; the only tags\n * emitted are the fixed set the renderer itself writes. Pair with a Content-Security-Policy\n * that disallows inline handlers for defense in depth — the string itself carries none.\n *\n * Requires a browser (or DOM) environment for {@link renderProseDom}; Node can use this\n * string renderer directly.\n */\nexport function renderProseHtml(prose: ProseDoc, options: ProseRenderOptions = {}): string {\n return blocksHtml(prose.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction inlineDom(doc: Document, nodes: readonly ProseInline[]): (Element | Text)[] {\n const out: (Element | Text)[] = [];\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out.push(doc.createTextNode(node.text));\n break;\n case 'codeSpan': {\n const code = doc.createElement('code');\n code.append(doc.createTextNode(node.text));\n out.push(code);\n break;\n }\n case 'strong':\n case 'emphasis':\n case 'strikethrough': {\n const element = doc.createElement(\n node.type === 'strikethrough' ? 'del' : node.type === 'strong' ? 'strong' : 'em',\n );\n element.append(...inlineDom(doc, node.children));\n out.push(element);\n break;\n }\n case 'link': {\n const anchor = doc.createElement('a');\n anchor.setAttribute('href', node.href);\n if (node.title !== undefined) anchor.setAttribute('title', node.title);\n anchor.append(...inlineDom(doc, node.children));\n out.push(anchor);\n break;\n }\n case 'image': {\n const image = doc.createElement('img');\n image.setAttribute('src', node.src);\n image.setAttribute('alt', node.alt);\n if (node.title !== undefined) image.setAttribute('title', node.title);\n out.push(image);\n break;\n }\n case 'softBreak':\n out.push(doc.createTextNode('\\n'));\n break;\n case 'hardBreak':\n out.push(doc.createElement('br'));\n break;\n }\n }\n return out;\n}\n\nfunction blocksDom(\n doc: Document,\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): DocumentFragment {\n const fragment = doc.createDocumentFragment();\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n if (unwrapParagraphs) {\n fragment.append(...inlineDom(doc, block.children));\n } else {\n const p = doc.createElement('p');\n p.append(...inlineDom(doc, block.children));\n fragment.append(p);\n }\n break;\n }\n case 'heading': {\n const heading = doc.createElement(`h${block.level}`);\n if (emitIds) heading.setAttribute('id', slugger.slug(inlineText(block.children)));\n heading.append(...inlineDom(doc, block.children));\n fragment.append(heading);\n break;\n }\n case 'codeBlock': {\n const pre = doc.createElement('pre');\n const code = doc.createElement('code');\n if (block.language !== undefined) code.classList.add(`language-${block.language}`);\n code.append(doc.createTextNode(block.text));\n pre.append(code);\n fragment.append(pre);\n break;\n }\n case 'blockquote': {\n const quote = doc.createElement('blockquote');\n quote.append(blocksDom(doc, block.children, slugger, emitIds, false));\n fragment.append(quote);\n break;\n }\n case 'list': {\n const list = doc.createElement(block.ordered ? 'ol' : 'ul');\n if (block.ordered && block.start !== 1) list.setAttribute('start', String(block.start));\n for (const item of block.items) {\n const li = doc.createElement('li');\n li.append(blocksDom(doc, item.children, slugger, emitIds, block.tight));\n list.append(li);\n }\n fragment.append(list);\n break;\n }\n case 'thematicBreak':\n fragment.append(doc.createElement('hr'));\n break;\n case 'table': {\n const table = doc.createElement('table');\n const thead = doc.createElement('thead');\n const headerRow = doc.createElement('tr');\n block.header.forEach((cell, index) => {\n const th = doc.createElement('th');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') th.setAttribute('align', alignment);\n th.append(...inlineDom(doc, cell));\n headerRow.append(th);\n });\n thead.append(headerRow);\n const tbody = doc.createElement('tbody');\n for (const row of block.rows) {\n const tr = doc.createElement('tr');\n row.forEach((cell, index) => {\n const td = doc.createElement('td');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') td.setAttribute('align', alignment);\n td.append(...inlineDom(doc, cell));\n tr.append(td);\n });\n tbody.append(tr);\n }\n table.append(thead, tbody);\n fragment.append(table);\n break;\n }\n }\n }\n return fragment;\n}\n\n/**\n * Render a parsed document to a `DocumentFragment`. Text reaches the DOM exclusively through\n * `createTextNode`, so document content can never execute: no `innerHTML`, no attribute is ever\n * sourced from Markdown beyond `href`/`src`/`alt`/`title`/slug `id`s, and those already passed\n * the parse-time protocol policy. Requires a DOM environment.\n */\nexport function renderProseDom(prose: ProseDoc, options: ProseRenderOptions = {}): DocumentFragment {\n return blocksDom(document, prose.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction blockText(block: ProseBlock): string {\n switch (block.type) {\n case 'paragraph':\n return inlineText(block.children);\n case 'heading':\n return inlineText(block.children);\n case 'codeBlock':\n return block.text;\n case 'blockquote':\n return block.children.map(blockText).join('\\n\\n');\n case 'list':\n return block.items\n .map((item, index) => {\n const marker = block.ordered ? `${block.start + index}. ` : '- ';\n return marker + item.children.map(blockText).join('\\n\\n');\n })\n .join('\\n');\n case 'thematicBreak':\n return '';\n case 'table': {\n const rows = [block.header, ...block.rows].map((row) => row.map((cell) => inlineText(cell)).join(' | '));\n return rows.join('\\n');\n }\n }\n}\n\n/**\n * Render the document as plain text: for notifications, search indexing, and previews.\n * Links keep their label text, images their alt text.\n */\nexport function proseToText(prose: ProseDoc): string {\n return prose.blocks\n .map(blockText)\n .filter((text) => text !== '')\n .join('\\n\\n');\n}\n\n/**\n * The document's headings with stable slug ids, traversed exactly as `renderProse*` does with\n * `headingIds` (including headings nested in blockquotes and lists), so outline ids always\n * match the rendered document. Use for tables of contents.\n */\nexport function proseOutline(prose: ProseDoc, options: ProseOutlineOptions = {}): readonly ProseOutlineEntry[] {\n return collectOutline(prose.blocks, createSlugger(), options.maxLevel ?? 6);\n}\n"],"mappings":"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"}
|
package/dist/render.d.ts
CHANGED
|
@@ -7,23 +7,23 @@ import type { ProseDoc, ProseOutlineEntry, ProseOutlineOptions, ProseRenderOptio
|
|
|
7
7
|
* Requires a browser (or DOM) environment for {@link renderProseDom}; Node can use this
|
|
8
8
|
* string renderer directly.
|
|
9
9
|
*/
|
|
10
|
-
export declare function renderProseHtml(
|
|
10
|
+
export declare function renderProseHtml(prose: ProseDoc, options?: ProseRenderOptions): string;
|
|
11
11
|
/**
|
|
12
12
|
* Render a parsed document to a `DocumentFragment`. Text reaches the DOM exclusively through
|
|
13
13
|
* `createTextNode`, so document content can never execute: no `innerHTML`, no attribute is ever
|
|
14
14
|
* sourced from Markdown beyond `href`/`src`/`alt`/`title`/slug `id`s, and those already passed
|
|
15
15
|
* the parse-time protocol policy. Requires a DOM environment.
|
|
16
16
|
*/
|
|
17
|
-
export declare function renderProseDom(
|
|
17
|
+
export declare function renderProseDom(prose: ProseDoc, options?: ProseRenderOptions): DocumentFragment;
|
|
18
18
|
/**
|
|
19
19
|
* Render the document as plain text: for notifications, search indexing, and previews.
|
|
20
20
|
* Links keep their label text, images their alt text.
|
|
21
21
|
*/
|
|
22
|
-
export declare function proseToText(
|
|
22
|
+
export declare function proseToText(prose: ProseDoc): string;
|
|
23
23
|
/**
|
|
24
24
|
* The document's headings with stable slug ids, traversed exactly as `renderProse*` does with
|
|
25
25
|
* `headingIds` (including headings nested in blockquotes and lists), so outline ids always
|
|
26
26
|
* match the rendered document. Use for tables of contents.
|
|
27
27
|
*/
|
|
28
|
-
export declare function proseOutline(
|
|
28
|
+
export declare function proseOutline(prose: ProseDoc, options?: ProseOutlineOptions): readonly ProseOutlineEntry[];
|
|
29
29
|
//# sourceMappingURL=render.d.ts.map
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,QAAQ,EAER,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AA8GjB;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAEzF;AA6ID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,kBAAuB,GAAG,gBAAgB,CAElG;AA4BD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAKnD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,mBAAwB,GAAG,SAAS,iBAAiB,EAAE,CAE7G"}
|
package/dist/render.js
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { escapeHtml as e } from "./_policy.js";
|
|
2
|
+
import { collectOutline as t, createSlugger as n, inlineText as r } from "./_text.js";
|
|
2
3
|
// src/render.ts
|
|
3
|
-
function titleAttr(
|
|
4
|
-
return
|
|
4
|
+
function titleAttr(t) {
|
|
5
|
+
return t === void 0 ? "" : ` title="${e(t)}"`;
|
|
5
6
|
}
|
|
6
|
-
function inlineHtml(
|
|
7
|
-
let
|
|
8
|
-
for (let r of
|
|
7
|
+
function inlineHtml(t) {
|
|
8
|
+
let n = "";
|
|
9
|
+
for (let r of t) switch (r.type) {
|
|
9
10
|
case "text":
|
|
10
|
-
|
|
11
|
+
n += e(r.text);
|
|
11
12
|
break;
|
|
12
13
|
case "codeSpan":
|
|
13
|
-
|
|
14
|
+
n += `<code>${e(r.text)}</code>`;
|
|
14
15
|
break;
|
|
15
16
|
case "strong":
|
|
16
|
-
|
|
17
|
+
n += `<strong>${inlineHtml(r.children)}</strong>`;
|
|
17
18
|
break;
|
|
18
19
|
case "emphasis":
|
|
19
|
-
|
|
20
|
+
n += `<em>${inlineHtml(r.children)}</em>`;
|
|
20
21
|
break;
|
|
21
22
|
case "strikethrough":
|
|
22
|
-
|
|
23
|
+
n += `<del>${inlineHtml(r.children)}</del>`;
|
|
23
24
|
break;
|
|
24
25
|
case "link":
|
|
25
|
-
|
|
26
|
+
n += `<a href="${e(r.href)}"${titleAttr(r.title)}>${inlineHtml(r.children)}</a>`;
|
|
26
27
|
break;
|
|
27
28
|
case "image":
|
|
28
|
-
|
|
29
|
+
n += `<img src="${e(r.src)}" alt="${e(r.alt)}"${titleAttr(r.title)}>`;
|
|
29
30
|
break;
|
|
30
31
|
case "softBreak":
|
|
31
|
-
|
|
32
|
+
n += "\n";
|
|
32
33
|
break;
|
|
33
|
-
case "hardBreak":
|
|
34
|
+
case "hardBreak": n += "<br />\n";
|
|
34
35
|
}
|
|
35
|
-
return
|
|
36
|
+
return n;
|
|
36
37
|
}
|
|
37
38
|
function headingAttrs(e, t, n) {
|
|
38
39
|
return n ? ` id="${t.slug(r(e))}"` : "";
|
|
39
40
|
}
|
|
40
|
-
function blocksHtml(
|
|
41
|
+
function blocksHtml(t, n, r, i) {
|
|
41
42
|
let a = [];
|
|
42
|
-
for (let o of
|
|
43
|
+
for (let o of t) switch (o.type) {
|
|
43
44
|
case "paragraph": {
|
|
44
45
|
let e = inlineHtml(o.children);
|
|
45
46
|
a.push(i ? e : `<p>${e}</p>`);
|
|
@@ -47,20 +48,20 @@ function blocksHtml(e, t, r, i) {
|
|
|
47
48
|
}
|
|
48
49
|
case "heading": {
|
|
49
50
|
let e = o.level;
|
|
50
|
-
a.push(`<h${e}${headingAttrs(o.children,
|
|
51
|
+
a.push(`<h${e}${headingAttrs(o.children, n, r)}>${inlineHtml(o.children)}</h${e}>`);
|
|
51
52
|
break;
|
|
52
53
|
}
|
|
53
54
|
case "codeBlock": {
|
|
54
|
-
let
|
|
55
|
-
a.push(`<pre><code${
|
|
55
|
+
let t = o.language === void 0 ? "" : ` class="language-${e(o.language)}"`;
|
|
56
|
+
a.push(`<pre><code${t}>${e(o.text)}\n</code></pre>`);
|
|
56
57
|
break;
|
|
57
58
|
}
|
|
58
59
|
case "blockquote":
|
|
59
|
-
a.push(`<blockquote>\n${blocksHtml(o.children,
|
|
60
|
+
a.push(`<blockquote>\n${blocksHtml(o.children, n, r, !1)}\n</blockquote>`);
|
|
60
61
|
break;
|
|
61
62
|
case "list": {
|
|
62
|
-
let e = o.ordered ? "ol" : "ul",
|
|
63
|
-
a.push(`<${e}${
|
|
63
|
+
let e = o.ordered ? "ol" : "ul", t = o.ordered && o.start !== 1 ? ` start="${o.start}"` : "", i = o.items.map((e) => `<li>${blocksHtml(e.children, n, r, o.tight)}</li>`).join("\n");
|
|
64
|
+
a.push(`<${e}${t}>\n${i}\n</${e}>`);
|
|
64
65
|
break;
|
|
65
66
|
}
|
|
66
67
|
case "thematicBreak":
|
|
@@ -77,8 +78,8 @@ function blocksHtml(e, t, r, i) {
|
|
|
77
78
|
}
|
|
78
79
|
return a.join("\n");
|
|
79
80
|
}
|
|
80
|
-
function renderProseHtml(e,
|
|
81
|
-
return blocksHtml(e.blocks,
|
|
81
|
+
function renderProseHtml(e, t = {}) {
|
|
82
|
+
return blocksHtml(e.blocks, n(), t.headingIds === !0, !1);
|
|
82
83
|
}
|
|
83
84
|
function inlineDom(e, t) {
|
|
84
85
|
let n = [];
|
|
@@ -173,8 +174,8 @@ function blocksDom(e, t, n, i, a) {
|
|
|
173
174
|
}
|
|
174
175
|
return o;
|
|
175
176
|
}
|
|
176
|
-
function renderProseDom(e,
|
|
177
|
-
return blocksDom(document, e.blocks,
|
|
177
|
+
function renderProseDom(e, t = {}) {
|
|
178
|
+
return blocksDom(document, e.blocks, n(), t.headingIds === !0, !1);
|
|
178
179
|
}
|
|
179
180
|
function blockText(e) {
|
|
180
181
|
switch (e.type) {
|
|
@@ -190,8 +191,8 @@ function blockText(e) {
|
|
|
190
191
|
function proseToText(e) {
|
|
191
192
|
return e.blocks.map(blockText).filter((e) => e !== "").join("\n\n");
|
|
192
193
|
}
|
|
193
|
-
function proseOutline(
|
|
194
|
-
return e
|
|
194
|
+
function proseOutline(e, r = {}) {
|
|
195
|
+
return t(e.blocks, n(), r.maxLevel ?? 6);
|
|
195
196
|
}
|
|
196
197
|
export { proseOutline, proseToText, renderProseDom, renderProseHtml };
|
|
197
198
|
|