BUG: Assigning objects in `processFrontMatter` causes YAML anchors to appear in the frontmatter

Making two properties point at the same object using processFrontMatter causes YAML anchors to appear in the frontmatter.

I made a minimal plugin to reproduce the issue here: GitHub - mProjectsCode/obsidian-frontmatter-reference-bug-repro

The text below is a copy of the readme of the above-mentioned repo.


Reproduction steps

1.

Install and enable this plugin in a vault.

2.

Create a new note and run the Init Frontmatter command added by this plugin.

The frontmatter of the file should look like this (in source mode):

data:
  foo:
    value: 0
  bar:
    value: 1

3.

Run the Modify Frontmatter 1 command added by this plugin, which does the following:

this.app.fileManager.processFrontMatter(activeFile, (frontmatter) => {
	// Some checks to make sure that the previous commands have been run.
	if (!frontmatter?.data?.foo || !frontmatter?.data?.bar) {
		new Notice('Please run Init Frontmatter first');
		return;
	}

	// Modify foo.value.
	frontmatter.data.foo = frontmatter.data.bar;
});

Observed Behavior

The frontmatter uses YAML anchors and references, which is very confusing to the average user and makes manual editing of the frontmatter difficult.
Further, it breaks expectations around modifying frontmatter later on, as seen in step 4.

The frontmatter looks like this (in source mode):

data:
  foo:
    &a1
    value: 1
  bar: *a1

Expected Behavior

The frontmatter should look like this (in source mode):

data:
  foo:
    value: 1
  bar:
    value: 1

4.

Run the Modify Frontmatter 2 command added by this plugin, which does the following:

this.app.fileManager.processFrontMatter(activeFile, (frontmatter) => {
	// Some checks to make sure that the previous commands have been run.
	if (!frontmatter?.data?.foo || !frontmatter?.data?.bar) {
		new Notice('Please run Init Frontmatter first');
		return;
	}
	if (frontmatter.data.foo.value !== frontmatter.data.bar.value) {
		new Notice('Please run Modify Frontmatter first');
		return;
	}

	// Modify foo.value. We expect this to not affect foo.value.
	frontmatter.data.foo.value = 2;

	// Oh no! This also changed bar.value to 2. This is not expected.
	if (frontmatter.data.bar.value === 2) {
		new Notice('Something went wrong. I modified foo.value to 2, but that also changed bar.value to 2. This is not expected.');
	}
});

Observed Behavior

The value of bar.value also changes when we change foo.value. And the last notice displays.

The frontmatter looks like this (in source mode):

data:
  foo:
    &a1
    value: 2
  bar: *a1

Expected Behavior

Edits to one property should not affect another.

The frontmatter should look like this (in source mode):

data:
  foo:
    value: 2
  bar:
    value: 1

Remarks

In essence frontmatter handles like we would expect a normal JavaScript object to handle, but this is contrary to how we would expect a serialized Object to behave.
With e.g. JSON as the serialization format, this would behave like outlined in the “Expected Behavior” sections in the reproduction steps.
In addition, few people know about YAML anchors and references and they are confusing to the average user.
In light of this, I believe this behavior to be a bug that the Obsidian team should address.

2 Likes

Clare reminded me to post my debug info, so here it is.

SYSTEM INFO:
	Obsidian version: v1.8.0
	Installer version: v1.6.5
	Operating system: #1 SMP Tue Nov 5 00:21:55 UTC 2024 5.15.167.4-microsoft-standard-WSL2
	Login status: logged in
	Language: en
	Catalyst license: supporter
	Insider build toggle: on
	Live preview: on
	Base theme: adapt to system
	Community theme: none
	Snippets enabled: 0
	Restricted mode: off
	Plugins installed: 2
	Plugins enabled: 1
		1: frontmatter-reference-bug-repro v1.0.0

RECOMMENDATIONS:
	Community plugins: for bugs, please first try updating all your plugins to latest. If still not fixed, please try to make the issue happen in the Sandbox Vault or disable community plugins.