@brett_lamy/docstream 1.2.0 → 1.2.1
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/package.json +1 -1
- package/src/gitbook/inline.ts +47 -20
package/package.json
CHANGED
package/src/gitbook/inline.ts
CHANGED
|
@@ -229,27 +229,54 @@ function serializeImage(n: InlineImageNode): string {
|
|
|
229
229
|
return n.link ? `<a href="${n.link}">${img}</a>` : img
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
// Serializes inline nodes back to markdown.
|
|
232
|
+
// Serializes inline nodes back to markdown. Emphasis (bold / italic / strike) is kept open across
|
|
233
|
+
// adjacent runs that share it, so `**bold [link](url) inside**` — three runs under one bold — comes back
|
|
234
|
+
// as written instead of `**bold ****[link](url)**** inside**`.
|
|
235
|
+
type Emphasis = "strike" | "italic" | "bold"
|
|
236
|
+
const EMPHASIS: Emphasis[] = ["strike", "italic", "bold"] // outermost → innermost
|
|
237
|
+
const MARKER: Record<Emphasis, string> = { strike: "~~", italic: "_", bold: "**" }
|
|
238
|
+
|
|
239
|
+
function textBody(n: TextNode): string {
|
|
240
|
+
const s = n.code ? n.text : escapeText(n.text)
|
|
241
|
+
return n.code ? `\`${s}\`` : s
|
|
242
|
+
}
|
|
243
|
+
|
|
233
244
|
export function serializeInline(nodes: Inline[]): string {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
let out = ""
|
|
246
|
+
const open: Emphasis[] = []
|
|
247
|
+
const closeTo = (depth: number) => {
|
|
248
|
+
while (open.length > depth) out += MARKER[open.pop()!]
|
|
249
|
+
}
|
|
250
|
+
for (const n of nodes) {
|
|
251
|
+
if (n.type !== "text") {
|
|
252
|
+
closeTo(0)
|
|
253
|
+
out += n.type === "image" ? serializeImage(n) : serializeReference(n)
|
|
254
|
+
continue
|
|
255
|
+
}
|
|
256
|
+
// bare autolink: text identical to the URL, no other marks
|
|
257
|
+
if (n.link && n.text === n.link && !n.bold && !n.italic && !n.strike && !n.code) {
|
|
258
|
+
closeTo(0)
|
|
259
|
+
out += n.link
|
|
260
|
+
continue
|
|
261
|
+
}
|
|
262
|
+
const wanted = EMPHASIS.filter((m) => n[m])
|
|
263
|
+
// A link around its emphasis (`[**x**](url)`) is self-contained: close everything, wrap this run alone.
|
|
264
|
+
if (n.link && !(n.linkInner && wanted.length)) {
|
|
265
|
+
closeTo(0)
|
|
266
|
+
let s = textBody(n)
|
|
267
|
+
for (const m of [...wanted].reverse()) s = `${MARKER[m]}${s}${MARKER[m]}`
|
|
268
|
+
out += `[${s}](${n.link})`
|
|
269
|
+
continue
|
|
270
|
+
}
|
|
271
|
+
// Keep the longest prefix of open marks this run still wants, close the rest, open what's missing.
|
|
272
|
+
let keep = 0
|
|
273
|
+
while (keep < open.length && wanted.includes(open[keep])) keep++
|
|
274
|
+
closeTo(keep)
|
|
275
|
+
for (const m of wanted) if (!open.includes(m)) { open.push(m); out += MARKER[m] }
|
|
276
|
+
out += n.link ? `[${textBody(n)}](${n.link})` : textBody(n)
|
|
277
|
+
}
|
|
278
|
+
closeTo(0)
|
|
279
|
+
return out
|
|
253
280
|
}
|
|
254
281
|
|
|
255
282
|
export function plainText(nodes: Inline[]): string {
|