-
-
Save aidenlx/6067c943fbec8ead230f2b163bfd3bc8 to your computer and use it in GitHub Desktop.
Example for inter-plugin API declaration in obisidian
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import API | |
import "your-package-name"; // if no export member used | |
// --- OR --- | |
import { exportMember } from "your-package-name"; | |
// NOTE: Calling `import` in any files will apply type declarations | |
// in `declare global` and `declare module obsidian` globally | |
// Access API with Method 1 | |
import { API_NAME } from "your-package-name"; | |
window[API_NAME]; | |
// Access API with Method 2 (need access to App object) | |
app.plugins.enabledPlugins.has("your-plugin-id"); // check if enabled | |
app.plugins.plugins["your-plugin-id"]?.api; // check if api available directly |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Required if you need to extend obsidian's declarations | |
import "obsidian"; | |
// NOTE: Don't export Obsidian undocumented APIs used internally, | |
// export them only when they are required for api consumer | |
// API INTERFACE | |
// ------------------------ | |
export interface SomeApi { } | |
// EXPOSE API | |
// ------------------------ | |
// Method 1: Export API to global scope | |
// Can use varible name to indicate major version | |
// Remember to use an unique name for your API variable | |
// (avoid using general name like: parse to prevent global namespace pollution) | |
declare global { | |
// Must use var, no const/let | |
var SomeApiv0: SomeApi | undefined; | |
} | |
export type API_NAME = "SomeApiv0" | |
// exported type API_NAME and global api name need to be synced manually for now | |
// Method 2: Access API via app.plugins | |
// Hard to access, but no risk of global namespace pollution | |
declare module "obsidian" { | |
interface App { | |
plugins: { | |
enabledPlugins: Set<string>; | |
plugins: { | |
["your-plugin-id"]?: { | |
api: SomeApi; | |
}; | |
}; | |
}; | |
} | |
} | |
// CUSTOM EVENTS | |
// ------------------------ | |
// Convert tuple to arguments of Event.on | |
type OnArgs<T> = T extends [infer A, ...infer B] | |
? A extends string | |
? [name: A, callback: (...args: B) => any] | |
: never | |
: never; | |
export type YourPluginEvents = | |
| [name: "your-plugin-id:ready", api: SomeApi] | |
| [name: "your-plugin-id:event-name"] | |
| [name: "your-plugin-id:event-with-data-name", data: string]; | |
type EventsOnArgs = OnArgs<YourPluginEvents>; | |
declare module "obsidian" { | |
interface Vault { | |
on(...args: EventsOnArgs): EventRef; | |
} | |
} | |
// If your api declaration contains no export member, | |
// add this line to the end | |
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Plugin } from "obsidian"; | |
import { YourPluginEvents, SomeApi } from "./api"; | |
// --- Method 1 --- | |
import { API_NAME } from "./api"; | |
const API_NAME: API_NAME extends keyof typeof window ? API_NAME : never = | |
"SomeApiv0" as const; // this line will throw error if name out of sync | |
export default class extends Plugin { | |
trigger(...args: YourPluginEvents): void { | |
const [name, ...data] = args; | |
this.app.vault.trigger(name, ...data); | |
} | |
// If API need to be initialized | |
api?: SomeApi; | |
onload() { | |
const api = {}; | |
this.api = api; | |
window[API_NAME] = api; | |
this.register(() => (window[API_NAME] = undefined)); | |
this.trigger("your-plugin-id:ready", api); | |
} | |
// --- OR --- | |
// If API is available when plugin is constrcuted | |
api: SomeApi; | |
constructor(app: any, manifest: any) { | |
super(app, manifest); | |
const api = {}; | |
this.api = api; | |
window[API_NAME] = api; | |
this.register(() => (window[API_NAME] = undefined)); | |
this.trigger("your-plugin-id:ready", api); | |
} | |
} | |
// --- Method 2 --- | |
export default class extends Plugin { | |
trigger(...args: YourPluginEvents): void { | |
const [name, ...data] = args; | |
this.app.vault.trigger(name, ...data); | |
} | |
// If API need to be initialized | |
api?: SomeApi; | |
onload() { | |
this.api = {}; | |
this.trigger("your-plugin-id:ready", api); | |
} | |
// --- OR --- | |
// If API is available when class is constrcuted | |
api: SomeApi = {} | |
onload() { | |
this.trigger("your-plugin-id:ready", api); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "your-package-name", | |
"version": "0.0.0", | |
"types": "src/api.d.ts", | |
"files": ["src/api.d.ts"], | |
"dependencies": { | |
"obsidian": "^0.12.11" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Folder structure for plugin in this example: