From 716f2d9f9ef3e9dc67aa12c4e05a7bf7fa5cfd37 Mon Sep 17 00:00:00 2001 From: Christian Bager Bach Houmann Date: Wed, 28 Jan 2026 16:17:47 +0100 Subject: [PATCH] fix: restore compatibility with Templater 2.18.0 Templater 2.18.0 introduced a breaking change in its `parse_template` API. The `RunningConfig` type now requires a `frontmatter` field, which QuickAdd was not providing. This caused `Object.keys(undefined)` to throw when Templater's `merge_objects` attempted to process the missing field. Root cause: Templater commit db9a91e added frontmatter merging support for `tp.file.include`. The new code path calls `merge_objects(frontmatter, config.frontmatter)` unconditionally, but QuickAdd passed only `{ target_file, run_mode }`. Fix: - Use `create_running_config()` when available (Templater 2.18.0+) to get a properly initialized config with all required fields - Fall back to manual config with `frontmatter: {}` for older versions This approach is forward-compatible: future Templater releases that add new required fields to RunningConfig will be handled automatically via `create_running_config()`. Closes #1085 Closes #1086 --- src/utilityObsidian.ts | 53 +++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/utilityObsidian.ts b/src/utilityObsidian.ts index 472be16b..7672f984 100644 --- a/src/utilityObsidian.ts +++ b/src/utilityObsidian.ts @@ -31,9 +31,14 @@ export type TemplaterPluginLike = { templater?: { overwrite_file_commands?: (f: TFile) => Promise; parse_template?: ( - opt: { target_file: TFile; run_mode: number }, + opt: { target_file: TFile; run_mode: number; frontmatter?: Record }, content: string, ) => Promise; + create_running_config?: ( + template_file: TFile | undefined, + target_file: TFile, + run_mode: number, + ) => { target_file: TFile; run_mode: number; frontmatter: Record }; files_with_pending_templates?: Set; functions_generator?: { teardown?: () => Promise }; }; @@ -400,13 +405,19 @@ export async function templaterParseTemplate( if (!plugin || !templater || typeof parseTemplate !== "function") return templateContent; - // Preserve Templater's internal `this` context. - return await parseTemplate.call( - templater, - // `run_mode: 4` maps to Templater's internal `RunMode.DynamicProcessor`. - { target_file: targetFile, run_mode: 4 }, - templateContent, - ); + // Use Templater's create_running_config if available for forward compatibility. + // This ensures we get a properly initialized config object with all required fields, + // even if Templater adds new required fields in future versions. + // Fallback to manual config for older Templater versions. + const createConfig = templater.create_running_config; + const config = + typeof createConfig === "function" + ? createConfig.call(templater, undefined, targetFile, 4) + : // `run_mode: 4` = RunMode.DynamicProcessor + // `frontmatter: {}` required since Templater 2.18.0 + { target_file: targetFile, run_mode: 4, frontmatter: {} }; + + return await parseTemplate.call(templater, config, templateContent); } export async function jumpToNextTemplaterCursorIfPossible( @@ -677,9 +688,9 @@ function convertLinkToEmbed(link: string): string { } /** - * Inserts a link to the specified file into the active view, respecting + * Inserts a link to the specified file into the active view, respecting * Obsidian's "New link format" setting. - * + * * @param app - The Obsidian app instance * @param file - The file to link to * @param linkOptions - Options controlling link insertion behavior @@ -765,26 +776,26 @@ export type OpenFileOptions = FileOpenOptions; /** * Open a file (by TFile or vault path) with precise control over location and mode. - * + * * @example * // Open in a new tab * await openFile(app, "daily/2024-01-01.md", { location: "tab" }); - * + * * @example * // Split vertically in source mode - * await openFile(app, file, { - * location: "split", - * direction: "vertical", - * mode: "source" + * await openFile(app, file, { + * location: "split", + * direction: "vertical", + * mode: "source" * }); - * + * * @example * // Open in sidebar without focus - * await openFile(app, file, { - * location: "right-sidebar", - * focus: false + * await openFile(app, file, { + * location: "right-sidebar", + * focus: false * }); - * + * * @returns The leaf it opened into. */ export async function openFile(