import type { Hook, Manifest } from "../types.ts"; import type { DocumentEditorT } from "@silverbulletmd/silverbullet/type/manifest"; import type { System } from "../system.ts"; import type { DocumentEditorCallback } from "@silverbulletmd/silverbullet/type/client"; export class DocumentEditorHook implements Hook { documentEditors = new Map< string, { extensions: string[]; callback: DocumentEditorCallback } >(); collectAllDocumentEditors(system: System) { this.documentEditors.clear(); for (const plug of system.loadedPlugs.values()) { for (const [name, functionDef] of Object.entries( plug.manifest!.functions, )) { if (!functionDef.editor) { continue; } const keys = Array.isArray(functionDef.editor) ? functionDef.editor : [functionDef.editor]; const conflict = Array.from(this.documentEditors.entries()).find( ([_, { extensions }]) => keys.some((key) => extensions.includes(key)), ); if (conflict) { console.log( `Extension definition of document editor ${name}: [${keys}] conflicts with the one from ${ conflict[0] }: [${conflict[1].extensions}]! Using the latter.`, ); } this.documentEditors.set(name, { extensions: keys, callback: () => plug.invoke(name, []), }); } } } apply(system: System): void { this.collectAllDocumentEditors(system); system.on({ plugLoaded: () => { this.collectAllDocumentEditors(system); }, }); } validateManifest(manifest: Manifest): string[] { const errors = []; for (const functionDef of Object.values(manifest.functions)) { if (!functionDef.editor) { continue; } if ( typeof functionDef.editor !== "string" && !Array.isArray(functionDef.editor) ) { errors.push( `Document editors require a string name or an array of string names.`, ); } } return errors; } }