Templater script to moving from dataview inline to frontmatter properties

Hey everyone,

With the upcoming bases (currently in Insider builds), Dataview inline properties (like [key:: value]) aren’t directly supported.

I’ve been using dataview inline properties for my movies, books, and games notes, and I needed a way to transition them to the new frontmattere properties seamlessly. I didn’t find a tool that worked well for this, so I created a templater script.

What This Script Does

This script finds those inline properties in your notes inside a folder, moves them to the note’s frontmatter, and then replaces the old inline property in your note’s main content with a simple Dataview call like `= this.property`.

Avertissement !

:double_exclamation_mark:Always back up your vault first! This should be an automatism whenever you’re modifying a bunch of notes at once.

This script is pretty basic. It assumes your inline properties follow that standard [property:: value] format, always starting on a new line. If your syntax is a bit different, you might need to tweak the regex part of the script. It’s not magic, so some edge cases might slip through.

How to use it

  • Create a new Templater note in your templates folder (e.g., Move Inline Props.md).
  • Copy and paste the script below into it.
  • Important: At the very top of the script, change folderPath to your specific folder, and update propertiesToConvert with your exact property names..
  • Run the script: Go to the Command Palette (Ctrl/Cmd + P), find “Templater: Replaces template in the active file”.

The script

<%*
// IMPORTANT: ALWAYS BACK UP YOUR VAULT BEFORE RUNNING ANY SCRIPT THAT MODIFIES NOTES IN BULK!

// --- CONFIGURATION ---
const folderPath = "films"; // <-- CHANGE THIS: Example: "movies", "Resources/books"
const propertiesToConvert = [ // <-- CHANGE THIS: List your inline properties here
    "publié",
    "status",
    "score"
];
// --- END CONFIGURATION ---

// Utility to safely handle special characters in property names for search
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// A tiny pause to help Obsidian catch up
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

await Promise.all(
    app.vault.getMarkdownFiles()
        .filter(file => file.path.startsWith(folderPath))
        .map(async file => {
            try {
                console.log(`Starting on: ${file.path}`);
                let currentContent = await app.vault.read(file);
                let propertiesFound = {};
                let didFindAnyProperty = false;

                // 1. Find and collect the inline properties
                for (const prop of propertiesToConvert) {
                    // This regex looks for [prop:: value] at the start of a line or after a newline
                    const regex = new RegExp(`(?<=\\n|^)\\[${escapeRegExp(prop)}::\\s*(.*?)\\]`, 'g');
                    let match;
                    while ((match = regex.exec(currentContent)) !== null) {
                        const value = match[1].trim();
                        propertiesFound[prop] = value;
                        didFindAnyProperty = true;
                        console.log(`  Found "${prop}" with value "${value}"`);
                    }
                }

                if (didFindAnyProperty) {
                    console.log(`  Ready to add to frontmatter:`, propertiesFound);

                    // 2. Add properties to the Frontmatter
                    await app.fileManager.processFrontMatter(file, (frontmatter) => {
                        for (const key in propertiesFound) {
                            if (propertiesFound.hasOwnProperty(key)) {
                                frontmatter[key] = propertiesFound[key];
                                console.log(`    Added/Updated frontmatter: ${key} = "${propertiesFound[key]}"`);
                            }
                        }
                    });

                    // re-read the file after frontmatter change
                    await delay(50);
                    let contentAfterFrontmatterUpdate = await app.vault.read(file);

                    // 3. Replace inline properties in the note's body
                    let finalNoteContent = contentAfterFrontmatterUpdate;
                    let bodyContentModified = false;

                    for (const prop of propertiesToConvert) {
                        const replaceRegex = new RegExp(`(?<=\\n|^)\\[${escapeRegExp(prop)}::\\s*.*?\\]`, 'g');
                        if (finalNoteContent.match(replaceRegex)) {
                            finalNoteContent = finalNoteContent.replace(replaceRegex, `\`= this.${prop}\``);
                            bodyContentModified = true;
                            console.log(`  Replaced inline "${prop}" in body.`);
                        }
                    }

                    // 4. Save the updated note content
                    if (bodyContentModified || finalNoteContent !== contentAfterFrontmatterUpdate) {
                        await app.vault.modify(file, finalNoteContent);
                        console.log(`Successfully updated: ${file.path}`);
                    } else {
                        console.log(`No body changes needed for: ${file.path}`);
                    }

                } else {
                    console.log(`No inline properties found in: ${file.path}. Skipping.`);
                }

            } catch (err) {
                console.error(`Failed to process ${file.path}\n\n${err}`);
            }
        })
);

new Notice("Inline property conversion finished! Check your console for details.", 5000);
%>
5 Likes

I’ve been waiting for something like this. I tried it out but get this error:

Strange.
Did you make sure to copy and paste the entire script correctly (for example, using the copy button in the top right corner)? And did you run the script by using the ‘Replace Templater’ command while being on the note where you pasted the script?

Thanks. If I run “replace templater” in the note with the script, it erases the script. If I activate the template as usual, it doesn’t convert the inline properties in the specified folder.

Thanks so much! I was looking for this.
It took me a while (and some testing) to get the regex to work for my specific setup, but in the end It worked to clean up thousands of occurrences of inline properties.
My inline properties were not enclosed by brackets. For future regex-noobs like me: \\[ is what other regex-editors see as \[ and when you remove \\] at the end you can replace it by \n for the group to ‘read’ until the end of the line.