From 6afe4a732a2969f5ed8aa4dabeecaa663741025d Mon Sep 17 00:00:00 2001 From: Jules Omlor Date: Fri, 24 Apr 2026 21:29:14 -0400 Subject: [PATCH] feat: expose public plugin API (refs #227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a small public API surface on the plugin instance so external plugins (specifically supercharged_links) can resolve a folder path to its folder note without reaching into internals. app.plugins.plugins['folder-notes']?.api?.getEnabledFolderNote(path) // returns TFile | null getEnabledFolderNote respects the same exclusion and detachment semantics as the plugin's own UI: it returns null for folders that wouldn't receive the .has-folder-note class. Consumers stay visually consistent with folder-notes' own behavior. The method name makes the gating explicit at the call site — external plugin authors see "enabled" and know that exclusions/ detachment are honored without needing to read documentation. Pattern mirrors the existing front-matter-title integration. No new settings, no migrations, no behavior change for existing users. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/api.ts | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.ts | 3 +++ 2 files changed, 57 insertions(+) create mode 100644 src/api.ts diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..3c6d767 --- /dev/null +++ b/src/api.ts @@ -0,0 +1,54 @@ +import { TFile } from 'obsidian'; +import type FolderNotesPlugin from './main'; +import { getFolderNote } from './functions/folderNoteFunctions'; +import { getDetachedFolder, getExcludedFolder } from './ExcludeFolders/functions/folderFunctions'; + +const API_VERSION = '1.0.0'; + +/** + * Public API exposed by the folder-notes plugin on its instance as `plugin.api`. + * + * External plugins can access it via: + * app.plugins.plugins['folder-notes']?.api + * + * The API is available after folder-notes has finished onload (settings loaded). + * It is safe to call synchronously from any point after layout-ready. + */ +export interface FolderNotesApi { + /** Semver-ish version string for feature detection. */ + version: string; + + /** + * Returns the folder note TFile for the given folder path only if the + * folder's note is enabled — i.e., the folder is not detached and not + * excluded with `disableFolderNote`. Matches the plugin's own UI + * gating (the rules that decide whether `.has-folder-note` gets + * applied in the file explorer). + * + * Returns null if: + * - the folder does not exist or has no folder note + * - the folder is detached + * - the folder is excluded with disableFolderNote + */ + getEnabledFolderNote(folderPath: string): TFile | null; +} + +export function getApi(plugin: FolderNotesPlugin): FolderNotesApi { + return { + version: getVersion(), + getEnabledFolderNote: (folderPath) => getEnabledFolderNote(plugin, folderPath), + }; +} + +function getVersion(): string { + return API_VERSION; +} + +function getEnabledFolderNote(plugin: FolderNotesPlugin, folderPath: string): TFile | null { + const note = getFolderNote(plugin, folderPath); + if (!note) return null; + if (getDetachedFolder(plugin, folderPath)) return null; + const excluded = getExcludedFolder(plugin, folderPath, true); + if (excluded?.disableFolderNote) return null; + return note; +} diff --git a/src/main.ts b/src/main.ts index 4e4b23c..7d5f002 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ import { } from './settings/SettingsTab'; import { Commands } from './Commands'; import type { FileExplorerWorkspaceLeaf } from './globals'; +import { getApi, type FolderNotesApi } from './api'; import { registerFileExplorerObserver, unregisterFileExplorerObserver, } from './events/MutationObserver'; @@ -49,10 +50,12 @@ export default class FolderNotesPlugin extends Plugin { settingsOpened = false; askModalCurrentlyOpen = false; fvIndexDB: FvIndexDB; + api!: FolderNotesApi; async onload(): Promise { console.log('loading folder notes plugin'); await this.loadSettings(); + this.api = getApi(this); this.settingsTab = new SettingsTab(this.app, this); this.addSettingTab(this.settingsTab); this.saveSettings();