/** * Plugin layout availability resolution (ticket #43, F4, carnet v2 §3.4). * * A `customPluginLayout` top-level {@link LayoutNode} is opaque domain state — * the provider plugin may be missing, disabled, or incompatible with the * running IdeA version at any given session. Availability is never stored in * the layout itself; it's derived here, purely, from the loaded runtime * registry, so it's trivially testable without React. */ import type { CustomPluginLayoutCell, PluginAdmin, PluginLayoutAvailability } from "@/domain"; import type { PluginRuntimeRegistry } from "@/plugins/runtime"; export function resolvePluginLayoutAvailability( registry: PluginRuntimeRegistry, cell: CustomPluginLayoutCell, /** * Optional admin list (from `PluginGateway.listPlugins()`) to tell "known but * disabled" apart from "not installed at all" — the runtime registry alone * only ever holds *loaded* (enabled) plugins (carnet §1.3), so it can't make * that distinction by itself. Omit it to fall back to "plugin-missing" for * both cases (still correct, just less precise fallback copy). */ installedPlugins?: PluginAdmin[], ): PluginLayoutAvailability { const plugin = registry.get(cell.pluginId); if (!plugin) { const known = installedPlugins?.find((p) => p.id === cell.pluginId); return known && !known.enabled ? "plugin-disabled" : "plugin-missing"; } const declaresType = plugin.contributes.layouts.some((l) => l.type === cell.layoutType); if (!declaresType) return "incompatible"; const component = plugin.layouts.get(cell.layoutType); if (!component) return "incompatible"; return "available"; }