victor HF Staff commited on
Commit
f1df9ee
·
1 Parent(s): f7b33d7

Skip formatting inside incomplete code blocks

Browse files

Adds logic to prevent incomplete bold, italic, and bold-italic markdown formatting from being processed if the marker is inside an incomplete code block. This avoids incorrectly modifying text that is meant to be inside code blocks, improving the robustness of markdown parsing.

src/lib/utils/parseIncompleteMarkdown.ts CHANGED
@@ -18,6 +18,29 @@ const hasCompleteCodeBlock = (text: string): boolean => {
18
  return tripleBackticks > 0 && tripleBackticks % 2 === 0 && text.includes("\n");
19
  };
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  // Handles incomplete links and images by preserving them with a special marker
22
  const handleIncompleteLinksAndImages = (text: string): string => {
23
  // First check for incomplete URLs: [text](partial-url or ![text](partial-url without closing )
@@ -84,6 +107,11 @@ const handleIncompleteBold = (text: string): string => {
84
  // Check if the bold marker is in a list item context
85
  // Find the position of the matched bold marker
86
  const markerIndex = text.lastIndexOf(boldMatch[1]);
 
 
 
 
 
87
  const beforeMarker = text.substring(0, markerIndex);
88
  const lastNewlineBeforeMarker = beforeMarker.lastIndexOf("\n");
89
  const lineStart = lastNewlineBeforeMarker === -1 ? 0 : lastNewlineBeforeMarker + 1;
@@ -111,6 +139,11 @@ const handleIncompleteBold = (text: string): string => {
111
 
112
  // Completes incomplete italic formatting with double underscores (__)
113
  const handleIncompleteDoubleUnderscoreItalic = (text: string): string => {
 
 
 
 
 
114
  const italicMatch = text.match(italicPattern);
115
 
116
  if (italicMatch) {
@@ -125,6 +158,11 @@ const handleIncompleteDoubleUnderscoreItalic = (text: string): string => {
125
  // Check if the underscore marker is in a list item context
126
  // Find the position of the matched underscore marker
127
  const markerIndex = text.lastIndexOf(italicMatch[1]);
 
 
 
 
 
128
  const beforeMarker = text.substring(0, markerIndex);
129
  const lastNewlineBeforeMarker = beforeMarker.lastIndexOf("\n");
130
  const lineStart = lastNewlineBeforeMarker === -1 ? 0 : lastNewlineBeforeMarker + 1;
@@ -210,6 +248,11 @@ const handleIncompleteSingleAsteriskItalic = (text: string): string => {
210
  return text;
211
  }
212
 
 
 
 
 
 
213
  // Get content after the first single asterisk
214
  const contentAfterFirstAsterisk = text.substring(firstSingleAsteriskIndex + 1);
215
 
@@ -329,6 +372,11 @@ const handleIncompleteSingleUnderscoreItalic = (text: string): string => {
329
  return text;
330
  }
331
 
 
 
 
 
 
332
  // Get content after the first single underscore
333
  const contentAfterFirstUnderscore = text.substring(firstSingleUnderscoreIndex + 1);
334
 
@@ -535,6 +583,14 @@ const handleIncompleteBoldItalic = (text: string): string => {
535
  return text;
536
  }
537
 
 
 
 
 
 
 
 
 
538
  const tripleAsteriskCount = countTripleAsterisks(text);
539
  if (tripleAsteriskCount % 2 === 1) {
540
  return `${text}***`;
 
18
  return tripleBackticks > 0 && tripleBackticks % 2 === 0 && text.includes("\n");
19
  };
20
 
21
+ // Helper function to check if a position is inside an incomplete code block
22
+ const isInsideIncompleteCodeBlock = (text: string, markerIndex: number): boolean => {
23
+ const tripleBackticks = (text.match(/```/g) || []).length;
24
+ // If even number or no backticks, no incomplete code block
25
+ if (tripleBackticks === 0 || tripleBackticks % 2 === 0) {
26
+ return false;
27
+ }
28
+ // Find the position of the last (opening) ```
29
+ let lastBacktickIndex = -1;
30
+ let count = 0;
31
+ for (let i = 0; i <= text.length - 3; i++) {
32
+ if (text.substring(i, i + 3) === "```") {
33
+ count++;
34
+ if (count === tripleBackticks) {
35
+ lastBacktickIndex = i;
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ // If the marker is after the last ```, it's inside the incomplete code block
41
+ return markerIndex > lastBacktickIndex;
42
+ };
43
+
44
  // Handles incomplete links and images by preserving them with a special marker
45
  const handleIncompleteLinksAndImages = (text: string): string => {
46
  // First check for incomplete URLs: [text](partial-url or ![text](partial-url without closing )
 
107
  // Check if the bold marker is in a list item context
108
  // Find the position of the matched bold marker
109
  const markerIndex = text.lastIndexOf(boldMatch[1]);
110
+
111
+ // Don't process if the marker is inside an incomplete code block
112
+ if (isInsideIncompleteCodeBlock(text, markerIndex)) {
113
+ return text;
114
+ }
115
  const beforeMarker = text.substring(0, markerIndex);
116
  const lastNewlineBeforeMarker = beforeMarker.lastIndexOf("\n");
117
  const lineStart = lastNewlineBeforeMarker === -1 ? 0 : lastNewlineBeforeMarker + 1;
 
139
 
140
  // Completes incomplete italic formatting with double underscores (__)
141
  const handleIncompleteDoubleUnderscoreItalic = (text: string): string => {
142
+ // Don't process if inside a complete code block
143
+ if (hasCompleteCodeBlock(text)) {
144
+ return text;
145
+ }
146
+
147
  const italicMatch = text.match(italicPattern);
148
 
149
  if (italicMatch) {
 
158
  // Check if the underscore marker is in a list item context
159
  // Find the position of the matched underscore marker
160
  const markerIndex = text.lastIndexOf(italicMatch[1]);
161
+
162
+ // Don't process if the marker is inside an incomplete code block
163
+ if (isInsideIncompleteCodeBlock(text, markerIndex)) {
164
+ return text;
165
+ }
166
  const beforeMarker = text.substring(0, markerIndex);
167
  const lastNewlineBeforeMarker = beforeMarker.lastIndexOf("\n");
168
  const lineStart = lastNewlineBeforeMarker === -1 ? 0 : lastNewlineBeforeMarker + 1;
 
248
  return text;
249
  }
250
 
251
+ // Don't process if the marker is inside an incomplete code block
252
+ if (isInsideIncompleteCodeBlock(text, firstSingleAsteriskIndex)) {
253
+ return text;
254
+ }
255
+
256
  // Get content after the first single asterisk
257
  const contentAfterFirstAsterisk = text.substring(firstSingleAsteriskIndex + 1);
258
 
 
372
  return text;
373
  }
374
 
375
+ // Don't process if the marker is inside an incomplete code block
376
+ if (isInsideIncompleteCodeBlock(text, firstSingleUnderscoreIndex)) {
377
+ return text;
378
+ }
379
+
380
  // Get content after the first single underscore
381
  const contentAfterFirstUnderscore = text.substring(firstSingleUnderscoreIndex + 1);
382
 
 
583
  return text;
584
  }
585
 
586
+ // Find the position of the matched bold-italic marker
587
+ const markerIndex = text.lastIndexOf(boldItalicMatch[1]);
588
+
589
+ // Don't process if the marker is inside an incomplete code block
590
+ if (isInsideIncompleteCodeBlock(text, markerIndex)) {
591
+ return text;
592
+ }
593
+
594
  const tripleAsteriskCount = countTripleAsterisks(text);
595
  if (tripleAsteriskCount % 2 === 1) {
596
  return `${text}***`;