Trouble with Templater

What I’m trying to do

Hi all! I’m very much in out of my depth here. I’m trying to tackle a really large (but fun) project and have banging my head against a wall for awhile here trying to get this figured out. The goal of this small piece of my project is to automate the addition of golf course information in a yaml format so that I can use dataview to pull a bunch of queries against it. I looked into the core template function and it’s not going to be able to do what I need. Using actions for obsidian and datajar, I am piping in a JSON object into the front matter of a note and then trying to have Templater format that according to the way that I want it to look. The problem that I have is that while I am a hobbyist with python, I have absolutely no knowledge of Javascript, so I have to rely on some AI models to try to help me write and format my templates. I have dug into them, but can’t quite figure out the issues that I am having with them. Posting my template and note with sample data below to try to figure out where my issue is.

<%*

console.log(“Template execution started”);

function safeStringify(obj, indent = 2) {
let cache = ;
const retVal = JSON.stringify(
obj,
(key, value) =>
typeof value === “object” && value !== null
? cache.includes(value)
? undefined // Duplicate reference found, discard key
: cache.push(value) && value // Store value in our collection
: value,
indent
);
cache = null;
return retVal;
}

console.log(“tp.file:”, safeStringify({
path: tp.file.path,
folder: tp.file.folder(),
title: tp.file.title,
creation_date: tp.file.creation_date,
last_modified_date: tp.file.last_modified_date
}));

console.log(“tp.frontmatter:”, safeStringify(tp.frontmatter));

// Function to ensure proper YAML formatting
function yamlify(value) {
if (typeof value === ‘string’) {
if (value.match(/[:#{}]/)) {
return "${value.replace(/"/g, '\\"')}";
}
return value;
}
if (typeof value === ‘object’ && value !== null) {
if (Array.isArray(value)) {
return value.map(yamlify).join(', ');
}
let result = ‘\n’;
for (const [k, v] of Object.entries(value)) {
result += ${k}: ${yamlify(v)}\n;
}
return result;
}
return value;
}

let courseData;
try {
console.log(“Frontmatter contents:”, safeStringify(tp.frontmatter));
if (tp.frontmatter.courseData === undefined) {
throw new Error(“courseData is not defined in the frontmatter”);
}
courseData = typeof tp.frontmatter.courseData === ‘string’
? JSON.parse(tp.frontmatter.courseData)
: tp.frontmatter.courseData;
console.log(“Parsed courseData:”, safeStringify(courseData));
} catch (error) {
console.error(“Error parsing courseData:”, error);
tR += Error: ${error.message}. Please check your frontmatter.\n;
tR += Frontmatter contents: ${safeStringify(tp.frontmatter)}\n;
return;
}

// Define ordered lists for each section
const basicInfoOrder = [‘name’, ‘city’, ‘state’, ‘course_type’, ‘phone_number’, ‘phone_tree’, ‘elevation’];
const teesOrder = [‘Tee Name’, ‘Par’, ‘Course Rating’, ‘Slope Rating’, ‘Yardage’];
const holesOrder = [‘Hole’, ‘Par’, ‘Men's HCP’];

// Generate YAML
let yaml = ‘—\n’;

// Basic course info
basicInfoOrder.forEach(key => {
if (courseData[key] !== undefined) {
yaml += ${key}: ${yamlify(courseData[key])}\n;
}
});

// Dates
yaml += date_added: ${tp.date.now("YYYY-MM-DD")}\n;
yaml += last_played: ${tp.date.now("YYYY-MM-DD")}\n;

// Tees
yaml += ‘tees:\n’;
courseData.tees.forEach(tee => {
yaml += ’ -';
teesOrder.forEach(key => {
if (tee[key] !== undefined) {
yaml += ${key}: ${yamlify(tee[key])};
}
});
yaml += ‘\n’;
});

// Holes
yaml += ‘holes:\n’;
courseData.holes.forEach(hole => {
yaml += ’ -';

// First, add the ordered keys
holesOrder.forEach(key => {
    if (hole[key] !== undefined) {
        yaml += ` ${key}: ${yamlify(hole[key])}`;
    }
});

// Then, sort and add the yardage keys
const yardageKeys = Object.keys(hole).filter(key => !holesOrder.includes(key));
yardageKeys.sort((a, b) => hole[b] - hole[a]);  // Sort in descending order

yardageKeys.forEach(key => {
    yaml += ` ${key}: ${yamlify(hole[key])}`;
});
yaml += '\n';

});

yaml += ‘—\n\n’;

// Output the generated YAML
tR += yaml;

// Add the course name as a header
tR += # ${courseData.name}\n;
%>

Then as a separate note, here’s my sample course file I’m trying to run the template against


courseData: ‘{“name”:“Sample Golf Course”,“city”:“Sampleville”,“state”:“ST”,“course_type”:“Public”,“phone_number”:“(123) 456-7890”,“elevation”:100,“phone_tree”:{“1”:“Pro Shop”,“2”:“Tee Times”},“tees”:[{“Tee Name”:“Blue”,“Par”:72,“Course Rating”:72.5,“Slope Rating”:132,“Yardage”:6800},{“Tee Name”:“White”,“Par”:72,“Course Rating”:71.2,“Slope Rating”:128,“Yardage”:6500}],“holes”:[{“Hole”:1,“Par”:4,“Men's HCP”:7,“Blue”:400,“White”:380,“Gold”:360,“Red”:340},{“Hole”:2,“Par”:3,“Men's HCP”:15,“Blue”:180,“White”:170,“Gold”:160,“Red”:150}]}’

Things I have tried

banging my head against a wall trying to tear through error messages

I forgot to include the Console log, which was throwing an error that included the Yaml key courseData. Here is the console log- Frontmatter contents: {}
Error parsing courseData: Error: courseData is not defined in the frontmatter
at eval (eval at (plugin:templater-obsidian:1:1), :58:15)
at eval (plugin:templater-obsidian:10:4705)
at rn (plugin:templater-obsidian:10:236)
at Co.r.wbg.__wbg_call_168da88779e35f61 (plugin:templater-obsidian:10:4674)
at 00032406:0xa737
at 00032406:0x5c9b
at 00032406:0x8cd8
at Ft.render_content (plugin:templater-obsidian:10:3041)
at nn.parse_commands (plugin:templater-obsidian:10:74295)
at Wt.parse_template (plugin:templater-obsidian:10:75300)

I did however find this issue here. The problem is that I needed to include the await javascript operator in my template. Here is the line in my script that I use to do so

let fileContent = await app.vault.read(app.workspace.getActiveFile());

I’m going to mark this issue as fixed instead of deleting it and leaving a “never mind, I fixed it”. Best of luck future internet traveler, and thank XKCD for guiding the way - xkcd: Wisdom of the Ancients

it’s an abandoned software that the author declined to help longtime ago.
i will seek other solutions instead.