diff --git a/.changeset/slimy-timers-confess.md b/.changeset/slimy-timers-confess.md new file mode 100644 index 0000000..ddd7fe0 --- /dev/null +++ b/.changeset/slimy-timers-confess.md @@ -0,0 +1,5 @@ +--- +"obsidian-modules": minor +--- + +Add relative path support for Templater. diff --git a/README.md b/README.md index b283ae8..6447914 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ await self.require.import("../relative/path/to/a module.js") // relative path await self.require.import("[omitted or whatever](markdown/link/to/a%20module.js.md)") // Markdown link await self.require.import("[[wikilink/to/a module|ommited or whatever]]") // wikilink // You can workaround the inability to infer the current directory. -await self.require.import("../relative/path/to/a module.js", { cwd: tp.file.folder(true) }) +await self.require.import("../relative/path/to/a module.js", { cwd: context.currentDirectory }) // If `await` is not supported, use `require` instead. It has less support for loading modules, however. self.require("obsidian") @@ -77,7 +77,7 @@ self.require("../relative/path/to/a module.js") self.require("[ommited or whatever](markdown/link/to/a%20module.js.md)") self.require("[[wikilink/to/a module|omitted or whatever]]") // You can workaround the inability to infer the current directory. -self.require("../relative/path/to/a module.js", { cwd: tp.file.folder(true) }) +self.require("../relative/path/to/a module.js", { cwd: context.currentDirectory }) ``` - To use entities in a module: ```JavaScript diff --git a/sources/@types/_templater-obsidian.d.ts b/sources/@types/_templater-obsidian.d.ts new file mode 100644 index 0000000..9fc3941 --- /dev/null +++ b/sources/@types/_templater-obsidian.d.ts @@ -0,0 +1 @@ +declare module "templater-obsidian" { } diff --git a/sources/@types/obsidian.ts b/sources/@types/obsidian.ts index 96bfb6d..039db4d 100644 --- a/sources/@types/obsidian.ts +++ b/sources/@types/obsidian.ts @@ -1,10 +1,13 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ declare module "obsidian" { + interface App extends Private<$App, PrivateKey> { } interface MarkdownPreviewRenderer extends Private<$MarkdownPreviewRenderer, PrivateKey> { } + interface Plugins extends Private<$Plugins, PrivateKey> { } } -import type { MarkdownPreviewView } from "obsidian" +import type { MarkdownPreviewView, Plugin, Plugins } from "obsidian" import type { Private } from "@polyipseity/obsidian-plugin-library" +import type { TemplaterPlugin } from "templater-obsidian" declare const PRIVATE_KEY: unique symbol type PrivateKey = typeof PRIVATE_KEY @@ -14,7 +17,25 @@ declare module "@polyipseity/obsidian-plugin-library" { } } +interface $App { + readonly plugins: Plugins +} + interface $MarkdownPreviewRenderer { readonly owner: MarkdownPreviewView readonly onRender: () => void } + +interface $Plugins { + readonly getPlugin: (id: I) => $Plugins.Map[I] | null + readonly loadPlugin: ( + id: I, + ) => PromiseLike<$Plugins.Map[I] | null> +} +namespace $Plugins { + export interface Map { + readonly [_: string]: Plugin + // eslint-disable-next-line @typescript-eslint/naming-convention + readonly "templater-obsidian": TemplaterPlugin + } +} diff --git a/sources/@types/templater-obsidian.ts b/sources/@types/templater-obsidian.ts new file mode 100644 index 0000000..7473e4a --- /dev/null +++ b/sources/@types/templater-obsidian.ts @@ -0,0 +1,28 @@ +declare module "templater-obsidian" { + // https://silentvoid13.github.io/Templater/internal-functions/internal-modules/file-module.html + interface FileModule { + readonly folder: (relative?: boolean) => string + } + // https://silentvoid13.github.io/Templater/internal-functions/overview.html + interface FunctionsObject extends Record { + readonly file: FileModule + } + // https://github.com/SilentVoid13/Templater/blob/487805b5ad1fd7fbc145040ed82b4c41fc2c48e2/src/core/parser/Parser.ts#L7 + interface Parser { + // eslint-disable-next-line @typescript-eslint/naming-convention + readonly parse_commands: ( + content: string, + context: FunctionsObject, + ) => PromiseLike + } + // https://github.com/SilentVoid13/Templater/blob/487805b5ad1fd7fbc145040ed82b4c41fc2c48e2/src/core/Templater.ts#L39 + interface Templater { + readonly parser: Parser + } + // https://github.com/SilentVoid13/Templater/blob/487805b5ad1fd7fbc145040ed82b4c41fc2c48e2/src/main.ts#L15 + interface TemplaterPlugin extends Plugin { + readonly templater: Templater + } +} +import type { } from "templater-obsidian" +import type { Plugin } from "obsidian" diff --git a/sources/require/context.ts b/sources/require/context.ts index 44034ca..847f7f8 100644 --- a/sources/require/context.ts +++ b/sources/require/context.ts @@ -7,6 +7,7 @@ import { isUndefined, noop } from "lodash-es" import { EditorView } from "@codemirror/view" import type { ModulesPlugin } from "../main.js" import type { StateField } from "@codemirror/state" +import type { TemplaterPlugin } from "templater-obsidian" import { around } from "monkey-around" import { getWD } from "./resolve.js" import { revealPrivate } from "@polyipseity/obsidian-plugin-library" @@ -62,3 +63,54 @@ export function patchContextForEditor(context: ModulesPlugin): void { }, })) } + +export function patchContextForTemplater(context: ModulesPlugin): void { + function patch(plugin: TemplaterPlugin): void { + const { templater: { parser } } = plugin + plugin.register(around(parser, { + // eslint-disable-next-line @typescript-eslint/naming-convention, camelcase + parse_commands(proto) { + return async function fn( + this: typeof parser, + ...args: Parameters + ): Promise>> { + const { api: { requires } } = context, + req = requires.get(self), + [, tp] = args + req?.context.cwds.push(tp.file.folder(true)) + try { + return await proto.apply(this, args) + } finally { + req?.context.cwds.pop() + } + } + }, + })) + } + revealPrivate(context, [context.app], app2 => { + const { plugins } = app2 + context.register(around(plugins, { + loadPlugin(proto) { + return async function fn( + this: typeof plugins, + ...args: Parameters + ): Promise>> { + const ret = await proto.apply(this, args) + try { + const [id] = args + if (ret && id === "templater-obsidian") { + type Proto = typeof proto + const ret2 = ret as NonNullable>> + patch(ret2) + } + } catch (error) { + self.console.error(error) + } + return ret + } + }, + })) + const tp = plugins.getPlugin("templater-obsidian") + if (tp) { patch(tp) } + }, noop) +} diff --git a/sources/require/require.ts b/sources/require/require.ts index 7a35af1..ac97216 100644 --- a/sources/require/require.ts +++ b/sources/require/require.ts @@ -26,7 +26,11 @@ import type { Resolved, } from "obsidian-modules" import { constant, isObject, isUndefined, noop } from "lodash-es" -import { patchContextForEditor, patchContextForPreview } from "./context.js" +import { + patchContextForEditor, + patchContextForPreview, + patchContextForTemplater, +} from "./context.js" import { MarkdownTranspile } from "./transpile.js" import type { ModulesPlugin } from "../main.js" import { around } from "monkey-around" @@ -48,6 +52,7 @@ export function loadRequire(context: ModulesPlugin): void { patchRequire(context, self0, resolve))) patchContextForPreview(context) patchContextForEditor(context) + patchContextForTemplater(context) } function createRequire(