|
@@ -107,24 +107,59 @@ function collectParagraphs(doc: ProsemirrorNode): ParagraphInfo[] {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Build the combined text (joined by \n\n) and boundary offsets.
|
|
|
|
|
|
|
+ * Check if text looks like a GFM table row (starts with |, contains more |).
|
|
|
|
|
+ */
|
|
|
|
|
+function isTableRow(text: string): boolean {
|
|
|
|
|
+ const trimmed = text.trim()
|
|
|
|
|
+ return trimmed.startsWith("|") && trimmed.indexOf("|", 1) !== -1
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Check if text is a GFM table delimiter row (e.g., |---|---|).
|
|
|
|
|
+ */
|
|
|
|
|
+function isTableDelimiter(text: string): boolean {
|
|
|
|
|
+ const trimmed = text.trim()
|
|
|
|
|
+ if (!trimmed.startsWith("|") || !trimmed.endsWith("|")) return false
|
|
|
|
|
+ const inner = trimmed.slice(1, -1).trim()
|
|
|
|
|
+ return /^[-:| ]+$/.test(inner) && inner.includes("---")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Determine the separator between paragraph i and i+1.
|
|
|
|
|
+ * Table rows stay joined with \n so GFM recognizes the full table.
|
|
|
|
|
+ * Everything else uses \n\n so GFM sees them as separate paragraphs
|
|
|
|
|
+ * (needed for task/callout detection).
|
|
|
|
|
+ */
|
|
|
|
|
+function separatorBetween(paragraphs: ParagraphInfo[], i: number): string {
|
|
|
|
|
+ if (i >= paragraphs.length - 1) return ""
|
|
|
|
|
+ const cur = paragraphs[i]!.text.trim()
|
|
|
|
|
+ const nxt = paragraphs[i + 1]!.text.trim()
|
|
|
|
|
+ if (isTableRow(cur) && (isTableDelimiter(nxt) || isTableRow(nxt))) return "\n"
|
|
|
|
|
+ if (isTableDelimiter(cur) && isTableRow(nxt)) return "\n"
|
|
|
|
|
+ return "\n\n"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Build the combined text and paragraph boundary offsets.
|
|
|
|
|
+ * Uses dynamic separators: \n between table rows, \n\n elsewhere.
|
|
|
* boundaries[0] = 0, boundaries[i] = start offset of paragraph i,
|
|
* boundaries[0] = 0, boundaries[i] = start offset of paragraph i,
|
|
|
- * boundaries[N] = total length (last para end, no trailing \n).
|
|
|
|
|
|
|
+ * boundaries[N] = total length (last para end, no trailing separator).
|
|
|
*/
|
|
*/
|
|
|
function buildCombinedText(paragraphs: ParagraphInfo[]): {
|
|
function buildCombinedText(paragraphs: ParagraphInfo[]): {
|
|
|
text: string
|
|
text: string
|
|
|
boundaries: number[]
|
|
boundaries: number[]
|
|
|
} {
|
|
} {
|
|
|
- const parts: string[] = []
|
|
|
|
|
const boundaries: number[] = [0]
|
|
const boundaries: number[] = [0]
|
|
|
|
|
+ let text = ""
|
|
|
for (let i = 0; i < paragraphs.length; i++) {
|
|
for (let i = 0; i < paragraphs.length; i++) {
|
|
|
- parts.push(paragraphs[i]!.text)
|
|
|
|
|
- const sepLen = i < paragraphs.length - 1 ? 2 : 1
|
|
|
|
|
- boundaries.push(
|
|
|
|
|
- boundaries[boundaries.length - 1]! + paragraphs[i]!.text.length + sepLen,
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ text += paragraphs[i]!.text
|
|
|
|
|
+ const sepLen = i < paragraphs.length - 1 ? separatorBetween(paragraphs, i).length : 1
|
|
|
|
|
+ boundaries.push(text.length + sepLen)
|
|
|
|
|
+ if (i < paragraphs.length - 1) {
|
|
|
|
|
+ text += separatorBetween(paragraphs, i)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- return { text: parts.join("\n\n"), boundaries }
|
|
|
|
|
|
|
+ return { text, boundaries }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|