import type { CapabilityToken } from "./capabilities.js"; /** @internal */ export interface ProvidedCapability { /** @internal */ token: CapabilityToken; /** @internal */ value: T; } /** @internal */ export function createCapabilityAccessor(provided: readonly ProvidedCapability[] = []): { /** @internal */ provide(token: CapabilityToken, value: T): void; /** @internal */ get(token: CapabilityToken): T | T[] | undefined; /** @internal */ require(token: CapabilityToken): T | T[]; } { const singleCapabilities = new Map(); const multiCapabilities = new Map(); for (const entry of provided) { if (entry.token.cardinality === "multi") { const list = multiCapabilities.get(entry.token.id) ?? []; list.push(entry.value); multiCapabilities.set(entry.token.id, list); continue; } singleCapabilities.set(entry.token.id, entry.value); } return { provide(token, value) { if (token.cardinality === "multi") { const list = multiCapabilities.get(token.id) ?? []; list.push(value); multiCapabilities.set(token.id, list); return; } if (singleCapabilities.has(token.id)) { throw new Error(`Capability '${token.id}' is already provided`); } singleCapabilities.set(token.id, value); }, get(token: CapabilityToken): T | T[] | undefined { if (token.cardinality === "multi") { return [...(multiCapabilities.get(token.id) ?? [])] as T[]; } return singleCapabilities.get(token.id) as T | undefined; }, require(token: CapabilityToken): T | T[] { const value = this.get(token); if ( value === undefined || (Array.isArray(value) && token.cardinality === "multi" && value.length === 0) ) { throw new Error(`Required capability '${token.id}' is not available`); } return value; }, }; }