md-annotator 0.7.0 → 0.8.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.
- package/client/dist/index.html +359 -358
- package/client/src/utils/parser.js +51 -1
- package/package.json +1 -1
|
@@ -12,6 +12,12 @@ const HTML_VOID_TAGS = new Set([
|
|
|
12
12
|
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
|
13
13
|
])
|
|
14
14
|
|
|
15
|
+
// HTML tags that can contain markdown content (e.g. <div align="center">)
|
|
16
|
+
const HTML_MIXED_CONTENT_TAGS = new Set([
|
|
17
|
+
'div', 'section', 'details', 'aside', 'article', 'figure', 'figcaption',
|
|
18
|
+
'header', 'footer', 'main', 'nav', 'center'
|
|
19
|
+
])
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Simplified markdown parser that splits content into linear blocks.
|
|
17
23
|
* Designed for predictable text-anchoring (not AST-based).
|
|
@@ -215,12 +221,56 @@ export function parseMarkdownToBlocks(markdown) {
|
|
|
215
221
|
flush()
|
|
216
222
|
const tagName = tagMatch[1].toLowerCase()
|
|
217
223
|
const htmlStartLine = currentLineNum
|
|
218
|
-
const htmlLines = [line]
|
|
219
224
|
|
|
220
225
|
const isSelfClosing = trimmed.endsWith('/>')
|
|
221
226
|
const isVoid = HTML_VOID_TAGS.has(tagName)
|
|
222
227
|
const hasSameLineClose = new RegExp(`</${tagName}\\s*>`, 'i').test(trimmed)
|
|
223
228
|
|
|
229
|
+
if (!isSelfClosing && !isVoid && !hasSameLineClose && HTML_MIXED_CONTENT_TAGS.has(tagName)) {
|
|
230
|
+
// Mixed content wrapper: split into open tag + inner markdown + close tag
|
|
231
|
+
const closePattern = new RegExp(`</${tagName}\\s*>`, 'i')
|
|
232
|
+
const openPattern = new RegExp(`<${tagName}[\\s>/]`, 'i')
|
|
233
|
+
const innerLines = []
|
|
234
|
+
let closingLine = null
|
|
235
|
+
let depth = 1
|
|
236
|
+
i++
|
|
237
|
+
while (i < lines.length) {
|
|
238
|
+
if (openPattern.test(lines[i].trim())) { depth++ }
|
|
239
|
+
if (closePattern.test(lines[i].trim())) {
|
|
240
|
+
depth--
|
|
241
|
+
if (depth === 0) { closingLine = lines[i]; break }
|
|
242
|
+
}
|
|
243
|
+
innerLines.push(lines[i])
|
|
244
|
+
i++
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Emit opening tag
|
|
248
|
+
blocks.push({
|
|
249
|
+
id: `block-${currentId++}`,
|
|
250
|
+
type: 'html',
|
|
251
|
+
content: line,
|
|
252
|
+
order: currentId,
|
|
253
|
+
startLine: htmlStartLine
|
|
254
|
+
})
|
|
255
|
+
// Recursively parse inner content as markdown
|
|
256
|
+
for (const inner of parseMarkdownToBlocks(innerLines.join('\n'))) {
|
|
257
|
+
blocks.push({ ...inner, id: `block-${currentId++}`, order: currentId, startLine: htmlStartLine + inner.startLine })
|
|
258
|
+
}
|
|
259
|
+
// Emit closing tag
|
|
260
|
+
if (closingLine) {
|
|
261
|
+
blocks.push({
|
|
262
|
+
id: `block-${currentId++}`,
|
|
263
|
+
type: 'html',
|
|
264
|
+
content: closingLine,
|
|
265
|
+
order: currentId,
|
|
266
|
+
startLine: htmlStartLine + innerLines.length + 1
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
continue
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Non-mixed HTML: collect everything as one opaque block
|
|
273
|
+
const htmlLines = [line]
|
|
224
274
|
if (!isSelfClosing && !isVoid && !hasSameLineClose) {
|
|
225
275
|
const closePattern = new RegExp(`</${tagName}\\s*>`, 'i')
|
|
226
276
|
const openPattern = new RegExp(`<${tagName}[\\s>/]`, 'i')
|