How to get current file content without YAML frontmatter?

Hi,

I have found the following guide for getting the content of the current file:

const noteFile = this.app.workspace.getActiveFile(); // Currently Open Note
if(!noteFile.name) return; // Nothing Open

// Read the currently open note file. We are reading it off the HDD - we are NOT accessing the editor to do this.
let text = await this.app.vault.read(noteFile); 

This code is created by Binny V A and published in txt.binnyvs.com.

How can I remove YAML frontmatter from this? Or is there another way to get the file content so that YAML is already filtered out?

In theory, I could try to come up with a regular expression that would strip away everything that is between two --- lines (with the first --- line being the very first thing in the file). I just don’t think it’s a good idea to do this kind of thing myself, as it can be errorprone, and I would guess Obsidian already does a split like this. I just don’t know if there is API access for it.

Thank you for your support!

1 Like

I’ve been able to use the cached frontmatter information to do that

This is the relevant code (note that error checking is not present):

const file = app.workspace.getActiveFile();
let text = editor.getDoc().getValue()
let fmc = app.metadataCache.getFileCache(file)?.frontmatter;
let end = fmc.position.end.line + 1 // accont for ending ---
body = text.split("\n").slice(end).join("\n")

3 Likes

Thank you @endorama ! :heart: It took quite some time before I finally tried this. It’s working perfectly! :sunglasses:

If it’s ok to you, I’ll use this in my Shell commands plugin, where I’ll create a new variable named {{note_content}} that allows users to pass current note’s content (without YAML) as input to system commands they execute.

Here’s an updated version of the code that works in Obsidian 1.4.0 and onwards, when FrontMatterCache no longer has a position property.

const file = app.workspace.getActiveFile();
let text = editor.getDoc().getValue()
let position = app.metadataCache.getFileCache(file)?.frontmatterPosition;
let end = position.end.line + 1 // accont for ending ---
body = text.split("\n").slice(end).join("\n")

A cheap way to do this would be doing .replace(/---[\S\s]*?---/, "").

People often say that using Regex causes more problems, but this seems fairly foolproof as it’s a non-greedy match.

MetadataCache can be slightly outdated (especially when editing yaml using source mode), so I’d use @pellucid’s approach. But be careful, that pattern will also match 'before --- middle --- after' for example.

After all, all you have to do is just split the content into lines, check if the first line’s content is ---, and find the next --- line.

@ush the .replace() function only replaces the first instance of the match, and since frontmatter always occurs at the very beginning of the note there’s not any danger of extra stuff being replaced.


Also, off topic, but I think your plugins are really cool :slight_smile:

the .replace() function only replaces the first instance of the match, and since frontmatter always occurs at the very beginning of the note there’s not any danger of extra stuff being replaced.

The problem is that --- can be a horizontal rule, not a front matter.

In the example below, the “I’m interested in Obsidian” section is removed.

I think your plugins are really cool :slight_smile:

Thanks for the kind words!! I appreciate it🔥

Ah that’s true, if there’s no frontmatter but there are two horizontal rules, then it will replace content that shouldn’t be replaced.

Late to the party, for me .replace(/^---.*?\n---\n/s, "") does the work.

This regex will only match --- at the start of the note, which won’t be confused with horizontal rulers.

You could also utilise the metadataCache and check which ones a potential frontmatter occupies, and then skip these lines when reading the other content.

This would ensure a proper check against what Obsidian considers the frontmatter or not. I.e. if it’s considered a legal frontmatter or not.

The proper way to handle this now is using getFrontmatterInfo (obsidian-api/obsidian.d.ts at 8b2eda0f24285636c8aa116972643e5233a23dc1 · obsidianmd/obsidian-api · GitHub)

let { contentStart } = getFrontMatterInfo(fileContents);

// removing the frontmatter from a file
let withoutFrontmatter = fileContents.slice(contentStart);

// swapping the frontmatter
let replacedFrontmatter = '---\nfoo: bar\n---\n' + fileContents.slice(contentStart);

// prepending text to file without breaking frontmatter
let withPrependedText = fileContents.slice(0, contentStart) + 'hello' + fileContents.slice(contentStart);
2 Likes

If I understood correctly, getFrontMatterInfo() doesn’t have any caching? Just by looking at the parameter it gets, looks like it doesn’t know from which file the content is coming from, and therefore can’t do a per-file based caching?

If a single file’s content will be parsed multiple times during the same session (without the file’s content changing in between), would it still be better for performance (at least if the file is big) to use this older method that reads content from cache:

Yes, if you are not planning on modifying the file and do not need to latest version of the file contents, then getting the frontmatter info from the metadataCache is a better option.

1 Like