@hcengineering/text-markdown 0.7.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.
@@ -0,0 +1,614 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var serializer_exports = {};
21
+ __export(serializer_exports, {
22
+ MarkdownState: () => MarkdownState,
23
+ storeMarks: () => storeMarks,
24
+ storeNodes: () => storeNodes
25
+ });
26
+ module.exports = __toCommonJS(serializer_exports);
27
+ var import_text_core = require("@hcengineering/text-core");
28
+ var import_text_html = require("@hcengineering/text-html");
29
+ var import_marks = require("./marks");
30
+ var import_node = require("./node");
31
+ function backticksFor(side) {
32
+ return side ? "`" : "`";
33
+ }
34
+ __name(backticksFor, "backticksFor");
35
+ function isPlainURL(link, parent, index) {
36
+ if (link.attrs?.title !== void 0 || !/^\w+:/.test(link.attrs?.href)) return false;
37
+ const content = parent.content?.[index];
38
+ if (content === void 0) {
39
+ return false;
40
+ }
41
+ if (content.type !== import_text_core.MarkupNodeType.text || content.text !== link.attrs?.href || content.marks?.[content.marks.length - 1] !== link) {
42
+ return false;
43
+ }
44
+ return index === (parent.content?.length ?? 0) - 1 || !(0, import_marks.isInSet)(link, parent.content?.[index + 1]?.marks ?? []);
45
+ }
46
+ __name(isPlainURL, "isPlainURL");
47
+ const formatTodoItem = /* @__PURE__ */ __name((i, attrs, parentAttrs) => {
48
+ const meta = attrs?.todoid !== void 0 && attrs?.userid !== void 0 ? `<!-- todoid=${attrs?.todoid},userid=${attrs?.userid} -->` : "";
49
+ const bullet = parentAttrs?.bullet ?? "*";
50
+ return `${bullet} [${attrs?.checked === true ? "x" : " "}] ${meta}`;
51
+ }, "formatTodoItem");
52
+ const storeNodes = {
53
+ blockquote: /* @__PURE__ */ __name((state, node) => {
54
+ state.wrapBlock("> ", null, node, () => {
55
+ state.renderContent(node);
56
+ });
57
+ }, "blockquote"),
58
+ codeBlock: /* @__PURE__ */ __name((state, node) => {
59
+ state.write(`\`\`\`${(0, import_node.nodeAttrs)(node).language ?? ""}
60
+ `);
61
+ state.renderInline(node);
62
+ state.ensureNewLine();
63
+ state.write("```");
64
+ state.closeBlock(node);
65
+ }, "codeBlock"),
66
+ mermaid: /* @__PURE__ */ __name((state, node) => {
67
+ state.write("```mermaid\n");
68
+ state.renderInline(node);
69
+ state.ensureNewLine();
70
+ state.write("```");
71
+ state.closeBlock(node);
72
+ }, "mermaid"),
73
+ heading: /* @__PURE__ */ __name((state, node) => {
74
+ const attrs = (0, import_node.nodeAttrs)(node);
75
+ if (attrs.marker === "=" && attrs.level === 1) {
76
+ state.renderInline(node);
77
+ state.ensureNewLine();
78
+ state.write("===\n");
79
+ } else if (attrs.marker === "-" && attrs.level === 2) {
80
+ state.renderInline(node);
81
+ state.ensureNewLine();
82
+ state.write("---\n");
83
+ } else {
84
+ state.write(state.repeat("#", attrs.level !== void 0 ? Number(attrs.level) : 1) + " ");
85
+ state.renderInline(node);
86
+ }
87
+ state.closeBlock(node);
88
+ }, "heading"),
89
+ horizontalRule: /* @__PURE__ */ __name((state, node) => {
90
+ state.write(`${(0, import_node.nodeAttrs)(node).markup ?? "---"}`);
91
+ state.closeBlock(node);
92
+ }, "horizontalRule"),
93
+ bulletList: /* @__PURE__ */ __name((state, node) => {
94
+ state.renderList(node, " ", () => `${(0, import_node.nodeAttrs)(node).bullet ?? "*"} `);
95
+ }, "bulletList"),
96
+ taskList: /* @__PURE__ */ __name((state, node) => {
97
+ state.renderList(node, " ", () => "* [ ] ");
98
+ }, "taskList"),
99
+ todoList: /* @__PURE__ */ __name((state, node) => {
100
+ state.renderList(node, " ", formatTodoItem);
101
+ }, "todoList"),
102
+ orderedList: /* @__PURE__ */ __name((state, node) => {
103
+ let start = 1;
104
+ if ((0, import_node.nodeAttrs)(node).order !== void 0) {
105
+ start = Number((0, import_node.nodeAttrs)(node).order);
106
+ }
107
+ const maxW = String(start + (0, import_node.nodeContent)(node).length - 1).length;
108
+ const space = state.repeat(" ", maxW + 2);
109
+ state.renderList(node, space, (i) => {
110
+ const nStr = String(start + i);
111
+ return state.repeat(" ", maxW - nStr.length) + nStr + ". ";
112
+ });
113
+ }, "orderedList"),
114
+ listItem: /* @__PURE__ */ __name((state, node) => {
115
+ state.renderContent(node);
116
+ }, "listItem"),
117
+ taskItem: /* @__PURE__ */ __name((state, node) => {
118
+ state.renderContent(node);
119
+ }, "taskItem"),
120
+ todoItem: /* @__PURE__ */ __name((state, node) => {
121
+ state.renderContent(node);
122
+ }, "todoItem"),
123
+ paragraph: /* @__PURE__ */ __name((state, node) => {
124
+ state.renderInline(node);
125
+ state.closeBlock(node);
126
+ }, "paragraph"),
127
+ subLink: /* @__PURE__ */ __name((state, node) => {
128
+ state.write("<sub>");
129
+ state.renderAHref = true;
130
+ state.renderInline(node);
131
+ state.renderAHref = false;
132
+ state.write("</sub>");
133
+ }, "subLink"),
134
+ image: /* @__PURE__ */ __name((state, node) => {
135
+ const attrs = (0, import_node.nodeAttrs)(node);
136
+ if (attrs.token != null && attrs["file-id"] != null) {
137
+ state.write(
138
+ "![" + state.esc(`${attrs.alt ?? ""}`) + "](" + (state.imageUrl + `${attrs["file-id"]}?file=${attrs["file-id"]}` + (attrs.width != null ? "&width=" + state.esc(`${attrs.width}`) : "") + (attrs.height != null ? "&height=" + state.esc(`${attrs.height}`) : "") + (attrs.token != null ? "&token=" + state.esc(`${attrs.token}`) : "")) + (attrs.title != null ? " " + state.quote(`${attrs.title}`) : "") + ")"
139
+ );
140
+ } else if (attrs["file-id"] != null) {
141
+ state.write(
142
+ "![" + state.esc(`${attrs.alt ?? ""}`) + "](" + (state.imageUrl + `${attrs["file-id"]}` + (attrs.width != null ? "&width=" + state.esc(`${attrs.width}`) : "") + (attrs.height != null ? "&height=" + state.esc(`${attrs.height}`) : "")) + (attrs.title != null ? " " + state.quote(`${attrs.title}`) : "") + ")"
143
+ );
144
+ } else {
145
+ if (attrs.width != null || attrs.height != null) {
146
+ state.write(
147
+ "<img" + (attrs.width != null ? ` width="${state.esc(`${attrs.width}`)}"` : "") + (attrs.height != null ? ` height="${state.esc(`${attrs.height}`)}"` : "") + ` src="${state.esc(`${attrs.src}`)}"` + (attrs.alt != null ? ` alt="${state.esc(`${attrs.alt}`)}"` : "") + (attrs.title != null ? ">" + state.quote(`${attrs.title}`) + "</img>" : ">")
148
+ );
149
+ } else {
150
+ state.write(
151
+ "![" + state.esc(`${attrs.alt ?? ""}`) + "](" + state.esc(`${attrs.src}`) + (attrs.title != null ? " " + state.quote(`${attrs.title}`) : "") + ")"
152
+ );
153
+ }
154
+ }
155
+ }, "image"),
156
+ reference: /* @__PURE__ */ __name((state, node) => {
157
+ const attrs = (0, import_node.nodeAttrs)(node);
158
+ let url = state.refUrl;
159
+ if (!url.includes("?")) {
160
+ url += "?";
161
+ } else {
162
+ url += "&";
163
+ }
164
+ state.write(
165
+ "[" + state.esc(`${attrs.label ?? ""}`) + `](${url}${makeQuery({
166
+ _class: attrs.objectclass,
167
+ _id: attrs.id,
168
+ label: attrs.label
169
+ })}` + (attrs.title !== void 0 ? " " + state.quote(`${attrs.title}`) : "") + ")"
170
+ );
171
+ }, "reference"),
172
+ markdown: /* @__PURE__ */ __name((state, node) => {
173
+ state.renderInline(node);
174
+ state.closeBlock(node);
175
+ }, "markdown"),
176
+ comment: /* @__PURE__ */ __name((state, node) => {
177
+ state.write("<!--");
178
+ state.renderInline(node);
179
+ state.write("-->");
180
+ }, "comment"),
181
+ hardBreak: /* @__PURE__ */ __name((state, node, parent, index) => {
182
+ const content = (0, import_node.nodeContent)(parent);
183
+ for (let i = index + 1; i < content.length; i++) {
184
+ if (content[i].type !== node.type) {
185
+ state.write("\\\n");
186
+ return;
187
+ }
188
+ }
189
+ }, "hardBreak"),
190
+ text: /* @__PURE__ */ __name((state, node) => {
191
+ state.text(node.text ?? "");
192
+ }, "text"),
193
+ emoji: /* @__PURE__ */ __name((state, node) => {
194
+ state.text(node.attrs?.emoji);
195
+ }, "emoji"),
196
+ table: /* @__PURE__ */ __name((state, node) => {
197
+ state.write(state.renderHtml(node));
198
+ state.closeBlock(node);
199
+ }, "table"),
200
+ embed: /* @__PURE__ */ __name((state, node) => {
201
+ const attrs = (0, import_node.nodeAttrs)(node);
202
+ const embedUrl = attrs.src;
203
+ state.write(`<a href="${encodeURI(embedUrl)}" data-type="embed">`);
204
+ state.write(state.htmlEsc(embedUrl).replace(/\//g, "&#x2F;"));
205
+ state.write("</a>");
206
+ }, "embed")
207
+ };
208
+ const storeMarks = {
209
+ em: {
210
+ open: "*",
211
+ close: "*",
212
+ mixable: true,
213
+ expelEnclosingWhitespace: true,
214
+ escape: true
215
+ },
216
+ italic: {
217
+ open: "*",
218
+ close: "*",
219
+ mixable: true,
220
+ expelEnclosingWhitespace: true,
221
+ escape: true
222
+ },
223
+ bold: {
224
+ open: "**",
225
+ close: "**",
226
+ mixable: true,
227
+ expelEnclosingWhitespace: true,
228
+ escape: true
229
+ },
230
+ strong: {
231
+ open: "**",
232
+ close: "**",
233
+ mixable: true,
234
+ expelEnclosingWhitespace: true,
235
+ escape: true
236
+ },
237
+ strike: {
238
+ open: "~~",
239
+ close: "~~",
240
+ mixable: true,
241
+ expelEnclosingWhitespace: true,
242
+ escape: true
243
+ },
244
+ underline: {
245
+ open: "<ins>",
246
+ close: "</ins>",
247
+ mixable: true,
248
+ expelEnclosingWhitespace: true,
249
+ escape: true
250
+ },
251
+ link: {
252
+ open: /* @__PURE__ */ __name((state, mark, parent, index) => {
253
+ if (state.renderAHref === true) {
254
+ return `<a href="${encodeURI(mark.attrs?.href)}">`;
255
+ } else {
256
+ state.inAutolink = isPlainURL(mark, parent, index);
257
+ return state.inAutolink ? "<" : "[";
258
+ }
259
+ }, "open"),
260
+ close: /* @__PURE__ */ __name((state, mark, parent, index) => {
261
+ if (state.renderAHref === true) {
262
+ return "</a>";
263
+ } else {
264
+ const { inAutolink } = state;
265
+ state.inAutolink = void 0;
266
+ const href = mark.attrs?.href ?? "";
267
+ const url = href.replace(/[\(\)"\\<>]/g, "\\$&");
268
+ const hasSpaces = url.includes(" ");
269
+ return inAutolink === true ? ">" : "](" + (hasSpaces ? `<${url}>` : url) + (mark.attrs?.title !== void 0 ? ` "${(mark.attrs?.title).replace(/"/g, '\\"')}"` : "") + ")";
270
+ }
271
+ }, "close"),
272
+ mixable: false,
273
+ expelEnclosingWhitespace: false,
274
+ escape: true
275
+ },
276
+ code: {
277
+ open: /* @__PURE__ */ __name((state, mark, parent, index) => {
278
+ return backticksFor(false);
279
+ }, "open"),
280
+ close: /* @__PURE__ */ __name((state, mark, parent, index) => {
281
+ return backticksFor(true);
282
+ }, "close"),
283
+ mixable: false,
284
+ expelEnclosingWhitespace: false,
285
+ escape: false
286
+ }
287
+ };
288
+ class MarkdownState {
289
+ static {
290
+ __name(this, "MarkdownState");
291
+ }
292
+ nodes;
293
+ marks;
294
+ delim;
295
+ out;
296
+ closed;
297
+ closedNode;
298
+ inTightList;
299
+ options;
300
+ refUrl;
301
+ imageUrl;
302
+ htmlWriter;
303
+ constructor(nodes = storeNodes, marks = storeMarks, options = { tightLists: true, refUrl: "ref://", imageUrl: "http://" }) {
304
+ this.nodes = nodes;
305
+ this.marks = marks;
306
+ this.delim = this.out = "";
307
+ this.closed = false;
308
+ this.inTightList = false;
309
+ this.refUrl = options.refUrl;
310
+ this.imageUrl = options.imageUrl;
311
+ this.htmlWriter = options.htmlWriter ?? import_text_html.markupToHtml;
312
+ this.options = options;
313
+ }
314
+ flushClose(size) {
315
+ if (this.closed) {
316
+ if (!this.atBlank()) this.out += "\n";
317
+ if (size > 1) {
318
+ this.addDelim(size);
319
+ }
320
+ this.closed = false;
321
+ }
322
+ }
323
+ addDelim(size) {
324
+ let delimMin = this.delim;
325
+ const trim = /\s+$/.exec(delimMin);
326
+ if (trim !== null) {
327
+ delimMin = delimMin.slice(0, delimMin.length - trim[0].length);
328
+ }
329
+ for (let i = 1; i < size; i++) {
330
+ this.out += delimMin + "\n";
331
+ }
332
+ }
333
+ renderHtml(node) {
334
+ return this.htmlWriter(node);
335
+ }
336
+ wrapBlock(delim, firstDelim, node, f) {
337
+ const old = this.delim;
338
+ this.write(firstDelim ?? delim);
339
+ this.delim += delim;
340
+ f();
341
+ this.delim = old;
342
+ this.closeBlock(node);
343
+ }
344
+ atBlank() {
345
+ return /(^|\n)$/.test(this.out);
346
+ }
347
+ // :: ()
348
+ // Ensure the current content ends with a newline.
349
+ ensureNewLine() {
350
+ if (!this.atBlank()) this.out += "\n";
351
+ }
352
+ // :: (?string)
353
+ // Prepare the state for writing output (closing closed paragraphs,
354
+ // adding delimiters, and so on), and then optionally add content
355
+ // (unescaped) to the output.
356
+ write(content) {
357
+ this.flushClose(2);
358
+ if (this.delim !== void 0 && this.atBlank()) this.out += this.delim;
359
+ if (content.length > 0) this.out += content;
360
+ }
361
+ // :: (Node)
362
+ // Close the block for the given node.
363
+ closeBlock(node) {
364
+ this.closedNode = node;
365
+ this.closed = true;
366
+ }
367
+ // :: (string, ?bool)
368
+ // Add the given text to the document. When escape is not `false`,
369
+ // it will be escaped.
370
+ text(text, escape = false) {
371
+ const lines = text.split("\n");
372
+ for (let i = 0; i < lines.length; i++) {
373
+ const startOfLine = this.atBlank() || this.closed;
374
+ this.write("");
375
+ this.out += escape ? this.esc(lines[i], startOfLine) : lines[i];
376
+ if (i !== lines.length - 1) this.out += "\n";
377
+ }
378
+ }
379
+ // :: (Node)
380
+ // Render the given node as a block.
381
+ render(node, parent, index) {
382
+ if (this.nodes[node.type] === void 0) {
383
+ throw new Error("Token type `" + node.type + "` not supported by Markdown renderer");
384
+ }
385
+ this.nodes[node.type](this, node, parent, index);
386
+ }
387
+ // :: (Node)
388
+ // Render the contents of `parent` as block nodes.
389
+ renderContent(parent) {
390
+ (0, import_node.nodeContent)(parent).forEach((node, i) => {
391
+ this.render(node, parent, i);
392
+ });
393
+ }
394
+ reorderMixableMark(state, mark, i, len) {
395
+ for (let j = 0; j < state.active.length; j++) {
396
+ const other = state.active[j];
397
+ if (!this.marks[other.type].mixable || this.checkSwitchMarks(i, j, state, mark, other, len)) {
398
+ break;
399
+ }
400
+ }
401
+ }
402
+ reorderMixableMarks(state, len) {
403
+ for (let i = 0; i < len; i++) {
404
+ const mark = state.marks[i];
405
+ const mm = this.marks[mark.type];
406
+ if (mm == null) {
407
+ break;
408
+ }
409
+ if (!mm.mixable) break;
410
+ this.reorderMixableMark(state, mark, i, len);
411
+ }
412
+ }
413
+ checkSwitchMarks(i, j, state, mark, other, len) {
414
+ if (!(0, import_marks.markEq)(mark, other) || i === j) {
415
+ return false;
416
+ }
417
+ this.switchMarks(i, j, state, mark, len);
418
+ return true;
419
+ }
420
+ switchMarks(i, j, state, mark, len) {
421
+ if (i > j) {
422
+ state.marks = state.marks.slice(0, j).concat(mark).concat(state.marks.slice(j, i)).concat(state.marks.slice(i + 1, len));
423
+ }
424
+ if (j > i) {
425
+ state.marks = state.marks.slice(0, i).concat(state.marks.slice(i + 1, j)).concat(mark).concat(state.marks.slice(j, len));
426
+ }
427
+ }
428
+ renderNodeInline(state, index) {
429
+ state.marks = state.node?.marks ?? [];
430
+ this.updateHardBreakMarks(state, index);
431
+ const leading = this.adjustLeading(state);
432
+ const inner = state.marks.length > 0 ? state.marks[state.marks.length - 1] : void 0;
433
+ const noEsc = inner !== void 0 && !(this.marks[inner.type]?.escape ?? false);
434
+ const len = state.marks.length - (noEsc ? 1 : 0);
435
+ this.reorderMixableMarks(state, len);
436
+ this.checkCloseMarks(state, len, index);
437
+ if (leading !== "") this.text(leading);
438
+ this.checkOpenMarks(state, len, index, inner, noEsc);
439
+ }
440
+ checkOpenMarks(state, len, index, inner, noEsc) {
441
+ if (state.node !== void 0) {
442
+ this.updateActiveMarks(state, len, index);
443
+ if (this.isNoEscapeRequire(state.node, inner, noEsc, state)) {
444
+ this.renderMarkText(inner, state, index);
445
+ } else {
446
+ this.render(state.node, state.parent, index);
447
+ }
448
+ }
449
+ }
450
+ isNoEscapeRequire(node, inner, noEsc, state) {
451
+ return inner !== void 0 && noEsc && node.type === import_text_core.MarkupNodeType.text;
452
+ }
453
+ renderMarkText(inner, state, index) {
454
+ this.text(
455
+ this.markString(inner, true, state.parent, index) + state.node?.text + this.markString(inner, false, state.parent, index + 1),
456
+ false
457
+ );
458
+ }
459
+ updateActiveMarks(state, len, index) {
460
+ while (state.active.length < len) {
461
+ const add = state.marks[state.active.length];
462
+ state.active.push(add);
463
+ this.text(this.markString(add, true, state.parent, index), false);
464
+ }
465
+ }
466
+ checkCloseMarks(state, len, index) {
467
+ let keep = 0;
468
+ while (keep < Math.min(state.active.length, len) && (0, import_marks.markEq)(state.marks[keep], state.active[keep])) {
469
+ ++keep;
470
+ }
471
+ while (keep < state.active.length) {
472
+ const mark = state.active.pop();
473
+ if (mark !== void 0) {
474
+ this.text(this.markString(mark, false, state.parent, index), false);
475
+ }
476
+ }
477
+ }
478
+ adjustLeading(state) {
479
+ let leading = state.trailing;
480
+ state.trailing = "";
481
+ const node = state?.node;
482
+ if (this.isText(node) && this.isMarksHasExpelEnclosingWhitespace(state)) {
483
+ const match = /^(\s*)(.*?)(\s*)$/m.exec(node?.text ?? "");
484
+ if (match !== null) {
485
+ const [leadMatch, innerMatch, trailMatch] = [match[1], match[2], match[3]];
486
+ leading += leadMatch;
487
+ state.trailing = trailMatch;
488
+ this.adjustLeadingTextNode(leadMatch, trailMatch, state, innerMatch, node);
489
+ }
490
+ }
491
+ return leading;
492
+ }
493
+ isMarksHasExpelEnclosingWhitespace(state) {
494
+ return state.marks.some((mark) => this.marks[mark.type]?.expelEnclosingWhitespace);
495
+ }
496
+ adjustLeadingTextNode(lead, trail, state, inner, node) {
497
+ if (lead !== "" || trail !== "") {
498
+ state.node = inner !== void 0 ? { ...node, text: inner } : void 0;
499
+ if (state.node === void 0) {
500
+ state.marks = state.active;
501
+ }
502
+ }
503
+ }
504
+ updateHardBreakMarks(state, index) {
505
+ if (state.node !== void 0 && state.node.type === import_text_core.MarkupNodeType.hard_break) {
506
+ state.marks = this.filterHardBreakMarks(state.marks, index, state);
507
+ }
508
+ }
509
+ filterHardBreakMarks(marks, index, state) {
510
+ const content = state.parent.content ?? [];
511
+ const next = content[index + 1];
512
+ if (!this.isHardbreakText(next)) {
513
+ return [];
514
+ }
515
+ return marks.filter((m) => (0, import_marks.isInSet)(m, next.marks ?? []));
516
+ }
517
+ isHardbreakText(next) {
518
+ return next !== void 0 && (next.type !== import_text_core.MarkupNodeType.text || next.text !== void 0 && /\S/.test(next.text));
519
+ }
520
+ isText(node) {
521
+ return node !== void 0 && node.type === import_text_core.MarkupNodeType.text && node.text !== void 0;
522
+ }
523
+ // :: (Node)
524
+ // Render the contents of `parent` as inline content.
525
+ renderInline(parent) {
526
+ const state = { active: [], trailing: "", parent, marks: [] };
527
+ (0, import_node.nodeContent)(parent).forEach((nde, index) => {
528
+ state.node = nde;
529
+ this.renderNodeInline(state, index);
530
+ });
531
+ state.node = void 0;
532
+ this.renderNodeInline(state, 0);
533
+ }
534
+ // :: (Node, string, (number) → string)
535
+ // Render a node's content as a list. `delim` should be the extra
536
+ // indentation added to all lines except the first in an item,
537
+ // `firstDelim` is a function going from an item index to a
538
+ // delimiter for the first line of the item.
539
+ renderList(node, delim, firstDelim) {
540
+ this.flushListClose(node);
541
+ const isTight = typeof node.attrs?.tight !== "undefined" ? node.attrs.tight === "true" : this.options.tightLists;
542
+ const prevTight = this.inTightList;
543
+ this.inTightList = isTight;
544
+ (0, import_node.nodeContent)(node).forEach((child, i) => {
545
+ this.renderListItem(node, child, i, isTight, delim, firstDelim);
546
+ });
547
+ this.inTightList = prevTight;
548
+ }
549
+ renderListItem(node, child, i, isTight, delim, firstDelim) {
550
+ if (i > 0 && isTight) this.flushClose(1);
551
+ this.wrapBlock(delim, firstDelim(i, node.content?.[i].attrs, node.attrs), node, () => {
552
+ this.render(child, node, i);
553
+ });
554
+ }
555
+ flushListClose(node) {
556
+ if (this.closed && this.closedNode?.type === node.type) {
557
+ this.flushClose(3);
558
+ } else if (this.inTightList) {
559
+ this.flushClose(1);
560
+ }
561
+ }
562
+ // :: (string, ?bool) → string
563
+ // Escape the given string so that it can safely appear in Markdown
564
+ // content. If `startOfLine` is true, also escape characters that
565
+ // has special meaning only at the start of the line.
566
+ esc(str, startOfLine = false) {
567
+ if (str == null) {
568
+ return "";
569
+ }
570
+ str = str.replace(/[`*\\~\[\]]/g, "\\$&");
571
+ if (startOfLine) {
572
+ str = str.replace(/^[:#\-*+]/, "\\$&").replace(/^(\d+)\./, "$1\\.");
573
+ }
574
+ str = str.replace(/\r?\n/g, "\\\n");
575
+ return str;
576
+ }
577
+ htmlEsc(str) {
578
+ if (str == null) {
579
+ return "";
580
+ }
581
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
582
+ }
583
+ quote(str) {
584
+ const wrap = !(str?.includes('"') ?? false) ? '""' : !(str?.includes("'") ?? false) ? "''" : "()";
585
+ return wrap[0] + str + wrap[1];
586
+ }
587
+ // :: (string, number) → string
588
+ // Repeat the given string `n` times.
589
+ repeat(str, n) {
590
+ let out = "";
591
+ for (let i = 0; i < n; i++) out += str;
592
+ return out;
593
+ }
594
+ // : (Mark, bool, string?) → string
595
+ // Get the markdown string for a given opening or closing mark.
596
+ markString(mark, open, parent, index) {
597
+ let value = mark.attrs?.marker;
598
+ if (value === void 0) {
599
+ const info = this.marks[mark.type];
600
+ if (info == null) {
601
+ throw new Error(`No info for mark ${mark.type}`);
602
+ }
603
+ value = open ? info.open : info.close;
604
+ }
605
+ return typeof value === "string" ? value : value(this, mark, parent, index) ?? "";
606
+ }
607
+ }
608
+ function makeQuery(obj) {
609
+ return Object.keys(obj).filter((it) => it[1] != null).map(function(k) {
610
+ return encodeURIComponent(k) + "=" + encodeURIComponent(obj[k]);
611
+ }).join("&");
612
+ }
613
+ __name(makeQuery, "makeQuery");
614
+ //# sourceMappingURL=serializer.js.map