Skip to content

Commit

Permalink
Add relative path support for Templater
Browse files Browse the repository at this point in the history
Signed-off-by: William So <polyipseity@gmail.com>
  • Loading branch information
polyipseity committed Aug 13, 2023
1 parent 70e94a6 commit fbcf7d2
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/slimy-timers-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"obsidian-modules": minor
---

Add relative path support for Templater.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions sources/@types/_templater-obsidian.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "templater-obsidian" { }
23 changes: 22 additions & 1 deletion sources/@types/obsidian.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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: <const I extends string>(id: I) => $Plugins.Map[I] | null
readonly loadPlugin: <const I extends string>(
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
}
}
28 changes: 28 additions & 0 deletions sources/@types/templater-obsidian.ts
Original file line number Diff line number Diff line change
@@ -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<string, unknown> {
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<string>
}
// 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"
52 changes: 52 additions & 0 deletions sources/require/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<typeof proto>
): Promise<Awaited<ReturnType<typeof proto>>> {
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<typeof proto>
): Promise<Awaited<ReturnType<typeof proto>>> {
const ret = await proto.apply(this, args)
try {
const [id] = args
if (ret && id === "templater-obsidian") {
type Proto = typeof proto<typeof id>
const ret2 = ret as NonNullable<Awaited<ReturnType<Proto>>>
patch(ret2)
}
} catch (error) {
self.console.error(error)
}
return ret
}
},
}))
const tp = plugins.getPlugin("templater-obsidian")
if (tp) { patch(tp) }
}, noop)
}
7 changes: 6 additions & 1 deletion sources/require/require.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -48,6 +52,7 @@ export function loadRequire(context: ModulesPlugin): void {
patchRequire(context, self0, resolve)))
patchContextForPreview(context)
patchContextForEditor(context)
patchContextForTemplater(context)
}

function createRequire(
Expand Down

0 comments on commit fbcf7d2

Please sign in to comment.