@liveblocks/react-ui 3.3.4 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/_private/index.d.cts +3 -4
  2. package/dist/_private/index.d.ts +3 -4
  3. package/dist/components/AiChat.cjs +3 -2
  4. package/dist/components/AiChat.cjs.map +1 -1
  5. package/dist/components/AiChat.js +3 -2
  6. package/dist/components/AiChat.js.map +1 -1
  7. package/dist/components/AiTool.cjs +15 -6
  8. package/dist/components/AiTool.cjs.map +1 -1
  9. package/dist/components/AiTool.js +15 -6
  10. package/dist/components/AiTool.js.map +1 -1
  11. package/dist/components/Comment.cjs +5 -2
  12. package/dist/components/Comment.cjs.map +1 -1
  13. package/dist/components/Comment.js +5 -2
  14. package/dist/components/Comment.js.map +1 -1
  15. package/dist/components/Composer.cjs +5 -2
  16. package/dist/components/Composer.cjs.map +1 -1
  17. package/dist/components/Composer.js +5 -2
  18. package/dist/components/Composer.js.map +1 -1
  19. package/dist/components/Thread.cjs +1 -2
  20. package/dist/components/Thread.cjs.map +1 -1
  21. package/dist/components/Thread.js +2 -3
  22. package/dist/components/Thread.js.map +1 -1
  23. package/dist/components/internal/AiChatAssistantMessage.cjs +1 -0
  24. package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
  25. package/dist/components/internal/AiChatAssistantMessage.js +1 -0
  26. package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
  27. package/dist/components/internal/AiChatUserMessage.cjs +16 -14
  28. package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
  29. package/dist/components/internal/AiChatUserMessage.js +16 -14
  30. package/dist/components/internal/AiChatUserMessage.js.map +1 -1
  31. package/dist/components/internal/CodeBlock.cjs +1 -1
  32. package/dist/components/internal/CodeBlock.cjs.map +1 -1
  33. package/dist/components/internal/CodeBlock.js +1 -1
  34. package/dist/components/internal/CodeBlock.js.map +1 -1
  35. package/dist/components/internal/Prose.cjs +3 -1
  36. package/dist/components/internal/Prose.cjs.map +1 -1
  37. package/dist/components/internal/Prose.js +3 -1
  38. package/dist/components/internal/Prose.js.map +1 -1
  39. package/dist/index.d.cts +4 -3
  40. package/dist/index.d.ts +4 -3
  41. package/dist/primitives/AiMessage/tool-invocation.cjs +5 -2
  42. package/dist/primitives/AiMessage/tool-invocation.cjs.map +1 -1
  43. package/dist/primitives/AiMessage/tool-invocation.js +5 -2
  44. package/dist/primitives/AiMessage/tool-invocation.js.map +1 -1
  45. package/dist/primitives/Composer/slate/plugins/custom-links.cjs +2 -9
  46. package/dist/primitives/Composer/slate/plugins/custom-links.cjs.map +1 -1
  47. package/dist/primitives/Composer/slate/plugins/custom-links.js +1 -8
  48. package/dist/primitives/Composer/slate/plugins/custom-links.js.map +1 -1
  49. package/dist/primitives/Markdown.cjs +409 -61
  50. package/dist/primitives/Markdown.cjs.map +1 -1
  51. package/dist/primitives/Markdown.js +410 -62
  52. package/dist/primitives/Markdown.js.map +1 -1
  53. package/dist/version.cjs +1 -1
  54. package/dist/version.js +1 -1
  55. package/package.json +4 -4
  56. package/src/styles/dark/index.css +26 -0
  57. package/src/styles/index.css +178 -45
  58. package/styles/dark/attributes.css +1 -1
  59. package/styles/dark/attributes.css.map +1 -1
  60. package/styles/dark/media-query.css +1 -1
  61. package/styles/dark/media-query.css.map +1 -1
  62. package/styles.css +1 -1
  63. package/styles.css.map +1 -1
  64. package/dist/utils/find-last-index.cjs +0 -16
  65. package/dist/utils/find-last-index.cjs.map +0 -1
  66. package/dist/utils/find-last-index.js +0 -14
  67. package/dist/utils/find-last-index.js.map +0 -1
@@ -1,9 +1,22 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { assertNever, sanitizeUrl } from '@liveblocks/core';
2
+ import { assertNever, sanitizeUrl, isUrl } from '@liveblocks/core';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import { Lexer } from 'marked';
5
5
  import { forwardRef, useMemo, memo } from 'react';
6
6
 
7
+ const LIST_ITEM_CHECKBOX_REGEX = /^\[\s?(x)?\]?$/i;
8
+ const PARTIAL_LINK_IMAGE_REGEX = /(?<!\\)(?<image>!)?\[(?!\^)(?<text>[^\]]*)(?:\](?:\((?<url>[^)]*)?)?)?$/;
9
+ const PARTIAL_TABLE_HEADER_REGEX = /^\s*\|(?:[^|\n]+(?:\|[^|\n]+)*?)?\|?\s*(?:\n\s*\|\s*[-:|\s]*\s*)?$/;
10
+ const PARTIAL_EMOJI_REGEX = /(?:\u200D|\uFE0F|\u20E3|\p{Regional_Indicator}|\p{Emoji_Presentation}|\p{Emoji_Modifier_Base}|\p{Emoji_Modifier})+$/u;
11
+ const TRAILING_NON_WHITESPACE_REGEX = /^\S*/;
12
+ const WHITESPACE_REGEX = /\s/;
13
+ const NEWLINE_REGEX = /\r\n?/g;
14
+ const BUFFERED_CHARACTERS_REGEX = /(?<!\\)((\*+|_+|~+|`+|\++|-{0,2}|={0,2}|\\|!|<\/?)\s*)$/;
15
+ const SINGLE_CHARACTER_REGEX = /^\s*(\S\s*)$/;
16
+ const LEFT_ANGLE_BRACKET_REGEX = /</g;
17
+ const RIGHT_ANGLE_BRACKET_REGEX = />/g;
18
+ const AMPERSAND_REGEX = /&(?!#?[0-9A-Za-z]+;)/g;
19
+ const DEFAULT_PARTIAL_LINK_URL = "#";
7
20
  const defaultComponents = {
8
21
  Paragraph: ({ children }) => {
9
22
  return /* @__PURE__ */ jsx("p", {
@@ -99,20 +112,8 @@ const defaultComponents = {
99
112
  const List = type === "ordered" ? "ol" : "ul";
100
113
  return /* @__PURE__ */ jsx(List, {
101
114
  start: start === 1 ? void 0 : start,
102
- children: items.map((item, index) => /* @__PURE__ */ jsxs("li", {
103
- children: [
104
- item.checked !== void 0 && /* @__PURE__ */ jsxs(Fragment, {
105
- children: [
106
- /* @__PURE__ */ jsx("input", {
107
- type: "checkbox",
108
- disabled: true,
109
- checked: item.checked
110
- }),
111
- " "
112
- ]
113
- }),
114
- item.children
115
- ]
115
+ children: items.map((item, index) => /* @__PURE__ */ jsx("li", {
116
+ children: item.children
116
117
  }, index))
117
118
  });
118
119
  },
@@ -121,18 +122,22 @@ const defaultComponents = {
121
122
  }
122
123
  };
123
124
  const Markdown = forwardRef(
124
- ({ content, components, asChild, ...props }, forwardedRef) => {
125
+ ({ content, partial, components, asChild, ...props }, forwardedRef) => {
125
126
  const Component = asChild ? Slot : "div";
126
127
  const tokens = useMemo(() => {
127
- return new Lexer().lex(content);
128
- }, [content]);
128
+ if (!content) {
129
+ return [];
130
+ }
131
+ return partial ? tokenizePartial(content) : tokenize(content);
132
+ }, [content, partial]);
129
133
  return /* @__PURE__ */ jsx(Component, {
130
134
  ...props,
131
135
  ref: forwardedRef,
132
136
  children: tokens.map((token, index) => {
133
137
  return /* @__PURE__ */ jsx(MemoizedMarkdownToken, {
134
138
  token,
135
- components
139
+ components,
140
+ partial
136
141
  }, index);
137
142
  })
138
143
  });
@@ -151,22 +156,25 @@ const MemoizedMarkdownToken = memo(
151
156
  (previousProps, nextProps) => {
152
157
  const previousToken = previousProps.token;
153
158
  const nextToken = nextProps.token;
154
- if (previousToken.raw.length !== nextToken.raw.length) {
159
+ if (previousToken.type !== nextToken.type || previousProps.partial !== nextProps.partial) {
155
160
  return false;
156
161
  }
157
- if (previousToken.type !== nextToken.type) {
162
+ let previousContent = previousToken.raw;
163
+ let nextContent = nextToken.raw;
164
+ if ("text" in previousToken && "text" in nextToken) {
165
+ previousContent = previousToken.text;
166
+ nextContent = nextToken.text;
167
+ }
168
+ if (previousContent.length !== nextContent.length) {
158
169
  return false;
159
170
  }
160
- return previousToken.raw === nextToken.raw;
171
+ return previousContent === nextContent;
161
172
  }
162
173
  );
163
174
  function MarkdownToken({
164
175
  token,
165
176
  components
166
177
  }) {
167
- if (!isMarkedToken(token)) {
168
- return null;
169
- }
170
178
  switch (token.type) {
171
179
  case "escape": {
172
180
  return token.text;
@@ -264,12 +272,12 @@ function MarkdownToken({
264
272
  case "code": {
265
273
  let language = void 0;
266
274
  if (token.lang !== void 0) {
267
- language = token.lang.match(/^\S*/)?.[0] ?? void 0;
275
+ language = token.lang.match(TRAILING_NON_WHITESPACE_REGEX)?.[0] ?? void 0;
268
276
  }
269
277
  const CodeBlock = components?.CodeBlock ?? defaultComponents.CodeBlock;
270
278
  return /* @__PURE__ */ jsx(CodeBlock, {
271
279
  language,
272
- code: token.text
280
+ code: token.text || " "
273
281
  });
274
282
  }
275
283
  case "blockquote": {
@@ -285,12 +293,23 @@ function MarkdownToken({
285
293
  case "list": {
286
294
  const List = components?.List ?? defaultComponents.List;
287
295
  const items = token.items.map((item) => {
296
+ let tokens = item.tokens;
297
+ if (item.task) {
298
+ tokens = [
299
+ {
300
+ type: "checkbox",
301
+ checked: Boolean(item.checked),
302
+ raw: `[${item.checked ? "x" : " "}]`
303
+ },
304
+ ...tokens
305
+ ];
306
+ }
288
307
  return {
289
308
  checked: item.task ? item.checked : void 0,
290
309
  children: /* @__PURE__ */ jsx(MarkdownTokens, {
291
- tokens: item.tokens,
310
+ tokens,
292
311
  components,
293
- normalizeToBlockTokens: item.loose
312
+ normalizeToBlockTokens: item.tokens.length > 0 ? item.loose : false
294
313
  })
295
314
  };
296
315
  });
@@ -299,6 +318,18 @@ function MarkdownToken({
299
318
  ...props
300
319
  });
301
320
  }
321
+ case "checkbox": {
322
+ return /* @__PURE__ */ jsxs(Fragment, {
323
+ children: [
324
+ /* @__PURE__ */ jsx("input", {
325
+ type: "checkbox",
326
+ disabled: true,
327
+ checked: token.checked
328
+ }),
329
+ " "
330
+ ]
331
+ });
332
+ }
302
333
  case "table": {
303
334
  const Table = components?.Table ?? defaultComponents.Table;
304
335
  const headings = token.header.map(
@@ -340,7 +371,9 @@ function MarkdownToken({
340
371
  const Separator = components?.Separator ?? defaultComponents.Separator;
341
372
  return /* @__PURE__ */ jsx(Separator, {});
342
373
  }
343
- case "html":
374
+ case "html": {
375
+ return parseHtmlEntities(token.text);
376
+ }
344
377
  default: {
345
378
  return null;
346
379
  }
@@ -351,64 +384,379 @@ function MarkdownTokens({
351
384
  components,
352
385
  normalizeToBlockTokens = false
353
386
  }) {
354
- const normalizedTokens = [];
387
+ assertTokens(tokens);
388
+ let normalizedTokens = [];
355
389
  if (normalizeToBlockTokens) {
390
+ let leadingCheckboxToken = tokens[0]?.type === "checkbox" ? tokens[0] : null;
356
391
  for (let i = 0; i < tokens.length; i++) {
357
392
  const token = tokens[i];
358
393
  switch (token.type) {
359
394
  case "text": {
360
- const texts = [token];
395
+ const paragraphTextTokens = [token];
361
396
  while (i + 1 < tokens.length && tokens[i + 1].type === "text") {
362
397
  i++;
363
- texts.push(tokens[i]);
398
+ paragraphTextTokens.push(tokens[i]);
364
399
  }
400
+ const paragraphRaw = paragraphTextTokens.map((text) => text.raw).join("");
401
+ const paragraphText = paragraphTextTokens.map((text) => text.text).join("");
365
402
  normalizedTokens.push({
366
403
  type: "paragraph",
367
- tokens: texts,
368
- raw: texts.map((text) => text.raw).join(""),
369
- text: texts.map((text) => text.text).join("")
404
+ tokens: leadingCheckboxToken ? [leadingCheckboxToken, ...paragraphTextTokens] : paragraphTextTokens,
405
+ raw: paragraphRaw,
406
+ text: paragraphText
370
407
  });
408
+ leadingCheckboxToken = null;
371
409
  break;
372
410
  }
411
+ case "checkbox":
412
+ break;
373
413
  default: {
374
414
  normalizedTokens.push(token);
375
415
  }
376
416
  }
377
417
  }
418
+ } else {
419
+ normalizedTokens = tokens;
378
420
  }
379
- return tokens.map((token, index) => /* @__PURE__ */ jsx(MarkdownToken, {
421
+ return normalizedTokens.map((token, index) => /* @__PURE__ */ jsx(MarkdownToken, {
380
422
  token,
381
423
  components
382
424
  }, index));
383
425
  }
384
- const markedTokenTypes = [
385
- "blockquote",
386
- "br",
387
- "code",
388
- "codespan",
389
- "def",
390
- "del",
391
- "em",
392
- "escape",
393
- "heading",
394
- "hr",
395
- "html",
396
- "image",
397
- "link",
398
- "list",
399
- "list_item",
400
- "paragraph",
401
- "space",
402
- "strong",
403
- "table",
404
- "text"
405
- ];
406
- function isMarkedToken(token) {
407
- return typeof token === "object" && token !== null && "type" in token && markedTokenTypes.includes(token.type);
426
+ function assertTokens(_) {
427
+ }
428
+ function isBlockToken(token) {
429
+ return token.type === "paragraph" || token.type === "heading" || token.type === "blockquote" || token.type === "list_item";
430
+ }
431
+ function tokenize(markdown) {
432
+ return new Lexer().lex(markdown);
433
+ }
434
+ function tokenizePartial(markdown) {
435
+ const preprocessedContent = trimPartialMarkdown(normalizeNewlines(markdown));
436
+ const tokens = tokenize(preprocessedContent);
437
+ try {
438
+ return completePartialTokens(tokens);
439
+ } catch {
440
+ return tokens;
441
+ }
442
+ }
443
+ function findPotentiallyPartialToken(tokens, parentToken) {
444
+ if (tokens.length === 0) {
445
+ return parentToken;
446
+ }
447
+ assertTokens(tokens);
448
+ const lastIndex = tokens.length - 1;
449
+ let lastToken = tokens[lastIndex];
450
+ if (lastToken.type === "space") {
451
+ const penultimateToken = tokens[lastIndex - 1];
452
+ if (!penultimateToken) {
453
+ return parentToken;
454
+ }
455
+ lastToken = penultimateToken;
456
+ }
457
+ if (lastToken.type === "list") {
458
+ const listToken = lastToken;
459
+ const lastListItem = listToken.items[listToken.items.length - 1];
460
+ if (!lastListItem) {
461
+ return parentToken;
462
+ }
463
+ const lastListItemTokens = lastListItem.tokens;
464
+ if (lastListItemTokens.some((token) => token.type === "space") && lastListItemTokens.length > 0) {
465
+ const lastListItemLastToken = lastListItemTokens[lastListItemTokens.length - 1];
466
+ if (lastListItemLastToken) {
467
+ if (lastListItemLastToken.type === "text") {
468
+ return lastListItemLastToken;
469
+ }
470
+ if (isBlockToken(lastListItemLastToken)) {
471
+ return findPotentiallyPartialToken(
472
+ lastListItemLastToken.tokens,
473
+ lastListItemLastToken
474
+ );
475
+ }
476
+ return void 0;
477
+ }
478
+ }
479
+ return findPotentiallyPartialToken(lastListItem.tokens, lastListItem);
480
+ }
481
+ if (lastToken.type === "table") {
482
+ const tableToken = lastToken;
483
+ const lastTableRow = tableToken.rows[tableToken.rows.length - 1];
484
+ if (!lastTableRow) {
485
+ return parentToken;
486
+ }
487
+ const firstEmptyTableCellIndex = lastTableRow.findIndex(
488
+ (cell) => cell.tokens.length === 0
489
+ );
490
+ const lastNonEmptyTableCell = firstEmptyTableCellIndex === -1 ? void 0 : firstEmptyTableCellIndex === 0 ? lastTableRow[firstEmptyTableCellIndex] : lastTableRow[firstEmptyTableCellIndex - 1];
491
+ if (!lastNonEmptyTableCell) {
492
+ return parentToken;
493
+ }
494
+ return findPotentiallyPartialToken(
495
+ lastNonEmptyTableCell.tokens,
496
+ lastNonEmptyTableCell
497
+ );
498
+ }
499
+ if (isBlockToken(lastToken)) {
500
+ return findPotentiallyPartialToken(lastToken.tokens, lastToken);
501
+ }
502
+ return parentToken;
503
+ }
504
+ function normalizeNewlines(string) {
505
+ return string.replace(NEWLINE_REGEX, "\n");
506
+ }
507
+ function trimPartialMarkdown(markdown) {
508
+ const lines = markdown.split("\n");
509
+ if (lines.length === 0) {
510
+ return markdown;
511
+ }
512
+ const [singleCharacterMatch] = lines[lines.length - 1].match(SINGLE_CHARACTER_REGEX) ?? [];
513
+ if (singleCharacterMatch) {
514
+ lines[lines.length - 1] = lines[lines.length - 1].slice(
515
+ 0,
516
+ -singleCharacterMatch.length
517
+ );
518
+ return lines.join("\n");
519
+ }
520
+ const [bufferedCharactersMatch] = lines[lines.length - 1].match(BUFFERED_CHARACTERS_REGEX) ?? [];
521
+ if (bufferedCharactersMatch) {
522
+ lines[lines.length - 1] = lines[lines.length - 1].slice(
523
+ 0,
524
+ -bufferedCharactersMatch.length
525
+ );
526
+ return lines.join("\n");
527
+ }
528
+ return markdown;
529
+ }
530
+ function completePartialInlineMarkdown(markdown, options = {}) {
531
+ const stack = [];
532
+ const allowLinksImages = options.allowLinksImages ?? true;
533
+ let completedMarkdown = markdown;
534
+ const partialEmojiMatch = completedMarkdown.match(PARTIAL_EMOJI_REGEX);
535
+ if (partialEmojiMatch) {
536
+ const partialEmoji = partialEmojiMatch[0];
537
+ completedMarkdown = completedMarkdown.slice(0, -partialEmoji.length);
538
+ if (partialEmoji.includes("\uFE0F") || partialEmoji.includes("\u20E3")) {
539
+ const codepoints = Array.from(completedMarkdown);
540
+ if (codepoints.length > 0) {
541
+ completedMarkdown = codepoints.slice(0, -1).join("");
542
+ }
543
+ }
544
+ }
545
+ for (let i = 0; i < completedMarkdown.length; i++) {
546
+ const character = completedMarkdown[i];
547
+ const isEscaped = i > 0 ? completedMarkdown[i - 1] === "\\" : false;
548
+ if (isEscaped) {
549
+ continue;
550
+ }
551
+ if (character === "`") {
552
+ const lastDelimiter = stack[stack.length - 1];
553
+ const isClosingPreviousDelimiter = lastDelimiter?.string === "`" && i > lastDelimiter.index;
554
+ if (isClosingPreviousDelimiter) {
555
+ stack.pop();
556
+ } else {
557
+ const characterAfterDelimiter = completedMarkdown[i + 1];
558
+ if (characterAfterDelimiter && !WHITESPACE_REGEX.test(characterAfterDelimiter)) {
559
+ stack.push({ string: "`", length: 1, index: i });
560
+ }
561
+ }
562
+ continue;
563
+ }
564
+ if (character === "*" || character === "_" || character === "~") {
565
+ const isInsideInlineCode = stack[stack.length - 1]?.string === "`";
566
+ let j = i;
567
+ while (j < completedMarkdown.length && completedMarkdown[j] === character) {
568
+ j++;
569
+ }
570
+ const consecutiveDelimiterCharacters = j - i;
571
+ if (isInsideInlineCode) {
572
+ i += consecutiveDelimiterCharacters - 1;
573
+ continue;
574
+ }
575
+ let remainingConsecutiveDelimiterCharacters = consecutiveDelimiterCharacters;
576
+ let consecutiveDelimiterCharacterIndex = 0;
577
+ while (remainingConsecutiveDelimiterCharacters > 0) {
578
+ const lastDelimiter = stack[stack.length - 1];
579
+ if (!lastDelimiter || lastDelimiter.string[0] !== character) {
580
+ break;
581
+ }
582
+ if (remainingConsecutiveDelimiterCharacters >= lastDelimiter.length) {
583
+ stack.pop();
584
+ remainingConsecutiveDelimiterCharacters -= lastDelimiter.length;
585
+ consecutiveDelimiterCharacterIndex += lastDelimiter.length;
586
+ continue;
587
+ }
588
+ break;
589
+ }
590
+ if (remainingConsecutiveDelimiterCharacters > 0) {
591
+ if (i + consecutiveDelimiterCharacters >= completedMarkdown.length) {
592
+ completedMarkdown = completedMarkdown.slice(
593
+ 0,
594
+ completedMarkdown.length - remainingConsecutiveDelimiterCharacters
595
+ );
596
+ break;
597
+ }
598
+ const characterAfterDelimiters = completedMarkdown[i + consecutiveDelimiterCharacters];
599
+ if (characterAfterDelimiters && !WHITESPACE_REGEX.test(characterAfterDelimiters)) {
600
+ let delimiterStartIndex = i + consecutiveDelimiterCharacterIndex;
601
+ if (remainingConsecutiveDelimiterCharacters % 2 === 1) {
602
+ stack.push({
603
+ string: character,
604
+ length: 1,
605
+ index: delimiterStartIndex
606
+ });
607
+ delimiterStartIndex += 1;
608
+ remainingConsecutiveDelimiterCharacters -= 1;
609
+ }
610
+ while (remainingConsecutiveDelimiterCharacters >= 2) {
611
+ stack.push({
612
+ string: character + character,
613
+ length: 2,
614
+ index: delimiterStartIndex
615
+ });
616
+ delimiterStartIndex += 2;
617
+ remainingConsecutiveDelimiterCharacters -= 2;
618
+ }
619
+ }
620
+ }
621
+ i += consecutiveDelimiterCharacters - 1;
622
+ continue;
623
+ }
624
+ }
625
+ if (allowLinksImages) {
626
+ const partialLinkImageMatch = completedMarkdown.match(
627
+ PARTIAL_LINK_IMAGE_REGEX
628
+ );
629
+ if (partialLinkImageMatch) {
630
+ const linkImageStartIndex = partialLinkImageMatch.index;
631
+ const linkImageEndIndex = linkImageStartIndex + partialLinkImageMatch[0].length;
632
+ const isInsideInlineCode = stack.some(
633
+ (delimiter) => delimiter.string === "`" && delimiter.index < linkImageStartIndex
634
+ );
635
+ if (!isInsideInlineCode) {
636
+ const partialLinkImageContent = partialLinkImageMatch[0];
637
+ const {
638
+ text: partialLinkText,
639
+ url: partialLinkUrl,
640
+ image: isImage
641
+ } = partialLinkImageMatch.groups;
642
+ if (isImage) {
643
+ completedMarkdown = completedMarkdown.slice(
644
+ 0,
645
+ -partialLinkImageContent.length
646
+ );
647
+ } else {
648
+ for (let i = stack.length - 1; i >= 0; i--) {
649
+ const delimiter = stack[i];
650
+ if (delimiter.index >= linkImageStartIndex && delimiter.index < linkImageEndIndex) {
651
+ stack.splice(i, 1);
652
+ }
653
+ }
654
+ const completedLinkText = partialLinkText ? partialLinkUrl ? partialLinkText : completePartialInlineMarkdown(partialLinkText, {
655
+ allowLinksImages: false
656
+ }) : "";
657
+ const completedLinkUrl = partialLinkUrl && !WHITESPACE_REGEX.test(partialLinkUrl) && isUrl(partialLinkUrl) ? partialLinkUrl : DEFAULT_PARTIAL_LINK_URL;
658
+ const completedLink = `[${completedLinkText}](${completedLinkUrl})`;
659
+ completedMarkdown = completedMarkdown.slice(
660
+ 0,
661
+ -partialLinkImageContent.length
662
+ );
663
+ completedMarkdown += completedLink;
664
+ }
665
+ }
666
+ }
667
+ }
668
+ for (let i = stack.length - 1; i >= 0; i--) {
669
+ const delimiter = stack[i];
670
+ if (delimiter.index + delimiter.length >= completedMarkdown.length) {
671
+ completedMarkdown = completedMarkdown.slice(0, delimiter.index);
672
+ continue;
673
+ }
674
+ if (delimiter.string !== "`") {
675
+ completedMarkdown = completedMarkdown.trimEnd();
676
+ }
677
+ completedMarkdown += delimiter.string;
678
+ }
679
+ return completedMarkdown;
680
+ }
681
+ function completePartialTableMarkdown(markdown) {
682
+ const tableLines = markdown.split("\n");
683
+ if (tableLines.length === 0) {
684
+ return void 0;
685
+ }
686
+ const tableHeader = tableLines[0];
687
+ if (tableHeader === "|") {
688
+ return void 0;
689
+ }
690
+ const tableHeadings = tableHeader.split("|").map((cell) => cell.trim()).filter((cell) => cell !== "");
691
+ if (tableHeadings.length === 0) {
692
+ return void 0;
693
+ }
694
+ if (!tableHeader.endsWith("|")) {
695
+ const lastTableHeading = tableHeadings[tableHeadings.length - 1];
696
+ const completedLastTableHeading = completePartialInlineMarkdown(lastTableHeading);
697
+ tableHeadings[tableHeadings.length - 1] = completedLastTableHeading;
698
+ }
699
+ return `| ${tableHeadings.join(" | ")} |
700
+ | ${tableHeadings.map(() => "---").join(" | ")} |`;
701
+ }
702
+ function completePartialTokens(tokens) {
703
+ const potentiallyPartialToken = findPotentiallyPartialToken(tokens);
704
+ if (!potentiallyPartialToken) {
705
+ return tokens;
706
+ }
707
+ if (potentiallyPartialToken.type === "paragraph" || potentiallyPartialToken.type === "text") {
708
+ if (PARTIAL_TABLE_HEADER_REGEX.test(potentiallyPartialToken.raw)) {
709
+ const completedTableMarkdown = completePartialTableMarkdown(
710
+ potentiallyPartialToken.raw
711
+ );
712
+ if (completedTableMarkdown) {
713
+ const completedTable = tokenize(completedTableMarkdown)[0];
714
+ if (completedTable) {
715
+ const table = potentiallyPartialToken;
716
+ table.type = "table";
717
+ table.header = completedTable.header;
718
+ table.align = completedTable.align;
719
+ table.rows = completedTable.rows;
720
+ return tokens;
721
+ }
722
+ } else {
723
+ potentiallyPartialToken.text = "";
724
+ potentiallyPartialToken.tokens = [];
725
+ }
726
+ }
727
+ }
728
+ if (potentiallyPartialToken.type === "list_item") {
729
+ const listItem = potentiallyPartialToken;
730
+ const listItemTokens = listItem.tokens;
731
+ if (!listItem.task && listItemTokens.length === 1 && listItemTokens[0].type === "text") {
732
+ const listItemText = listItemTokens[0];
733
+ const checkboxMatch = listItemText.text.match(LIST_ITEM_CHECKBOX_REGEX);
734
+ if (checkboxMatch) {
735
+ listItem.task = true;
736
+ if (checkboxMatch[1] === "x") {
737
+ listItem.checked = true;
738
+ } else {
739
+ listItem.checked = false;
740
+ }
741
+ listItem.text = "";
742
+ listItem.tokens = [];
743
+ }
744
+ }
745
+ }
746
+ if (potentiallyPartialToken.text.length === 0) {
747
+ return tokens;
748
+ }
749
+ const completedMarkdown = completePartialInlineMarkdown(
750
+ potentiallyPartialToken.text
751
+ );
752
+ const completedMarkdownTokens = tokenize(completedMarkdown)[0]?.tokens ?? [];
753
+ potentiallyPartialToken.text = completedMarkdown;
754
+ potentiallyPartialToken.tokens = completedMarkdownTokens;
755
+ return tokens;
408
756
  }
409
757
  function parseHtmlEntities(input) {
410
758
  const document = new DOMParser().parseFromString(
411
- `<!doctype html><body>${input}`,
759
+ `<!doctype html><body>${input.replace(AMPERSAND_REGEX, "&amp;").replace(LEFT_ANGLE_BRACKET_REGEX, "&lt;").replace(RIGHT_ANGLE_BRACKET_REGEX, "&gt;")}`,
412
760
  "text/html"
413
761
  );
414
762
  return document.body.textContent;