Skip to content

T-W7D5-rebase-markdown-extract-navigation-on-markdown-contract

Status: closed/done · Impact: low · Complexity: medium

plugin/lib/util/markdown_extract.ts already parses through markdown-contract (its parseMarkdown wrapper keeps mc’s .mdast), but sectionBody still hand-iterates parsed.tree.children, matches a heading by plain text, then scans forward for the next same-or-shallower heading and slices parsed.source between the two offsets. mc 0.2.0 (already vendored) exposes section-navigation helpers that return exactly those boundaries, so the bespoke child-iteration plus source slicing can be deleted in favour of the shared front-end. This is the read-side follow-on to the T-K1A8 rebase that first routed this module through mc.

LocationRole today
plugin/lib/util/markdown_extract.ts#sectionBodyHand-iterates parsed.tree.children, matches a depth-N heading by plain text, forward-scans for the next heading of the same or shallower depth, and slices parsed.source between the heading offsets, then trims
plugin/lib/util/markdown_extract.ts#hasBlockIdRegex-tests parsed.body for a trailing Obsidian ^blockId token
plugin/lib/util/markdown_extract.ts#extractBlockIdTextRegex-locates the block whose last line carries ^blockId and returns its text
plugin/lib/util/markdown_extract.ts#parseMarkdownThe mc-backed wrapper: calls mc parse, keeps .mdast as tree, plus source/body/frontmatter
plugin/lib/util/tests/markdown_extract.test.tsBehavioural suite pinning sectionBody and block-id output

sectionBody resolves its section through mc’s navigation helpers rather than a manual mdast child walk. parseMarkdown (or sectionBody directly) also holds mc’s section-tree root (SectionNode) alongside the existing .mdast, so findSection / sectionSpans / sectionForLine / sectionsAt can locate the target section and its body extent. The returned string is byte-identical to today’s output for every input, including the trim and the same-or-shallower heading boundary. No hand-rolled next-sibling offset scan remains in sectionBody.

  1. Expose mc’s section-tree root from the parse wrapper: have parseMarkdown also retain the SectionNode root that mc parse returns (today it keeps only .mdast), or call mc parse inside sectionBody. Add it to the ParsedMarkdown shape if callers benefit.
  2. Rewrite sectionBody to locate the target with findSection(root, headingText, { depth }) and derive its body extent from the section node (via sectionSpans / the node’s own pos). The mc section tree nests by heading depth, so a depth-N section’s extent already ends at the next same-or-shallower heading — this reproduces the current <= depth boundary without a flat same-depth filter.
  3. Slice parsed.source to the resolved extent and .trim(), matching the current return exactly (return null when no such heading exists).
  4. Delete the manual parsed.tree.children loop and next-sibling offset scan.
  5. Leave hasBlockId / extractBlockIdText bespoke: mc 0.2.0 exports no block-id lookup helper (its index exports section, table, block, and code-fence helpers only), and it owns the Obsidian dialect at parse time but surfaces no ^blockId navigation. Block-id handling stays as-is; note this in the PR so a future mc release can revisit it.
  6. Run the suite; confirm byte-identical sectionBody output.
LocationKindChange
plugin/lib/util/markdown_extract.ts#sectionBodymodifyReplace the manual mdast child-iteration + source slicing with mc findSection / sectionSpans navigation; keep byte-identical output
plugin/lib/util/markdown_extract.ts#parseMarkdownmodifyRetain mc’s SectionNode root (alongside .mdast) so the navigation helpers have a root to query
plugin/lib/util/tests/markdown_extract.test.tsmodifyExtend or confirm coverage that sectionBody output is unchanged across depths and the shallower-heading boundary
  • AC-1: sectionBody contains no hand-rolled iteration over parsed.tree.children and no manual next-heading offset scan; it resolves its section through mc’s findSection / sectionSpans (or the sibling sectionForLine / sectionsAt) navigation helpers.
  • AC-2: sectionBody output is byte-identical to the pre-change output for every input the suite exercises, including the trim and the same-or-shallower heading boundary and the null-on-absent case.
  • AC-3: plugin/lib/util/tests/markdown_extract.test.ts passes unchanged (or with additions only, no expectation weakened).
  • AC-4: hasBlockId / extractBlockIdText are either rebased onto an mc block-id helper OR left bespoke with a one-line note in the PR stating mc 0.2.0 exposes no block-id equivalent.
  • Block-id handling (hasBlockId / extractBlockIdText) — stays bespoke unless a mc block-id helper exists; see AC-4.
  • The services/docs copy of markdown_extract behaviour and its own test file.
  • Frontmatter reading, entityFiles / entityDirs, or any non-section helper.
  • none — enabled by the already-vendored markdown-contract 0.2.0 (vendor/markdown-contract-0.2.0.tgz); no re-vendor needed. The sibling rebases T-K1A8 (this module onto mc parse), T-ZGO4, and T-FN18 are already shipped (closed/done), so this is additive read-side cleanup with no blocking predecessor.
  • Surfaced by a read-side audit of remaining bespoke markdown navigation after the markdown-contract adoption (milestone M-0009). sectionBody was the one navigation path T-K1A8 left hand-rolled when it routed this module’s parse through mc.

← Back to Tasks