fix: frontmatter-aware top insertion for capture and apply-template#1334
Conversation
Capture 'write to top' and the apply-template 'top' insert placed content above a note's YAML frontmatter (breaking it) when the frontmatter was empty or otherwise undetected, and glued the inserted text onto the first body line. Route both through a shared, fence-safe getFrontMatterInfo-based helper (insertAtNoteBodyStart): capture inserts tightly; apply-template passes body+\n to keep its block separation. Detection is content-based (no stale metadata cache) and CRLF-aware. Closes #647
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR centralizes frontmatter-aware insertion via ChangesFrontmatter-safe note insertion refactoring
Sequence DiagramsequenceDiagram
participant TemplateInsertEngine
participant CaptureChoiceFormatter
participant insertAtNoteBodyStart
participant getFrontMatterInfo
TemplateInsertEngine->>insertAtNoteBodyStart: insertBodyIntoNoteContent (top mode)
CaptureChoiceFormatter->>insertAtNoteBodyStart: formatFileContent / createInsertAfterIfNotFound / createInsertBeforeIfNotFound / createInlineInsertAfterIfNotFound
insertAtNoteBodyStart->>getFrontMatterInfo: getBodyStartOffset
getFrontMatterInfo-->>insertAtNoteBodyStart: contentStart (body offset)
insertAtNoteBodyStart-->>TemplateInsertEngine: safe insertion at body boundary
insertAtNoteBodyStart-->>CaptureChoiceFormatter: safe insertion at body boundary
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying quickadd with
|
| Latest commit: |
55f95e2
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2327f741.quickadd.pages.dev |
| Branch Preview URL: | https://chhoumann-647-frontmatter-aw.quickadd.pages.dev |
The Obsidian docs recommend Vault.process over read+modify, and reading via cachedRead before a write is the wrong primitive (cachedRead is documented as display-only). Replace the cachedRead+modify pair in insertTemplateIntoFile with a single atomic vault.process call wrapping insertBodyIntoNoteContent. Add a process() impl to the test vaults (delegating to the modify spy).
Summary
Capture's write to top and apply template to active note → top could insert content above a note's YAML frontmatter (corrupting it) and/or glue the inserted text onto the first line of the body. This routes both paths through one frontmatter-aware insertion primitive.
The bug (two manifestations, one root cause)
A note whose frontmatter the old code couldn't see — most commonly empty frontmatter (
---\n---, e.g. after all properties are removed) — or a frontmatter-only note with no trailing newline (---\ntitle\n---) had the captured/template text written onto or above the---, breaking the block.insertBodyIntoNoteContentglued the body onto the closing fence for a frontmatter-only target with no trailing newline.Fix
New pure helper
src/utils/noteContentInsertion.ts(getBodyStartOffset/insertAtNoteBodyStart) built on Obsidian's owngetFrontMatterInfo— content-based (a stale/cold metadata cache can no longer misplace text), with leading + trailing CRLF-aware separators so the text always lands on its own line and never touches the fence.Both paths use it:
TemplateInsertEngine.insertBodyIntoNoteContent's top branch passesbody + "\n", preserving its deliberate block separation.The two callers keep distinct spacing policies (capture = tight snippet; template = separated block) over one shared, fence-safe implementation. Removed the old cache+regex detector (
getFrontmatterEndPosition,inferFrontmatterEndLineFromContent) and the now-deadpos === -1branch.Behavior change (Obsidian-consistent)
A
---fence not at offset 0 (e.g. preceded by a blank line) or closed with...is now treated as no frontmatter — matching Obsidian's own parser — so the capture lands at the very top.Testing / validation
...-close, task, repeated stacking, block-separation. Updated one capture test that had codified the old glued output.pnpm run build-with-lintclean.applyTemplateToActiveFile(..., { mode: "top" }).Also fixes a latent fence-glue bug in the apply-template-to-active-note path (the feature shipped for #526).
Closes #647
Checklist
fix:(patch)Summary by CodeRabbit
Bug Fixes
Tests