Files
kandev/apps/web/lib/lsp/lsp-dynamic-capabilities.ts
T

68 lines
2.4 KiB
TypeScript

export type LspDynamicRegistration = {
id: string;
method: string;
registerOptions?: unknown;
};
const providerCapabilities: Record<string, string> = {
"textDocument/completion": "completionProvider",
"textDocument/hover": "hoverProvider",
"textDocument/definition": "definitionProvider",
"textDocument/references": "referencesProvider",
"textDocument/signatureHelp": "signatureHelpProvider",
"textDocument/semanticTokens": "semanticTokensProvider",
};
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
export function normalizeLspRegistrations(value: unknown): LspDynamicRegistration[] {
if (!Array.isArray(value)) return [];
return value.filter(
(registration): registration is LspDynamicRegistration =>
isRecord(registration) &&
typeof registration.id === "string" &&
typeof registration.method === "string",
);
}
export function applyLspRegistrations(
current: ReadonlyMap<string, LspDynamicRegistration>,
method: "client/registerCapability" | "client/unregisterCapability",
params: unknown,
): Map<string, LspDynamicRegistration> {
const next = new Map(current);
if (!isRecord(params)) return next;
if (method === "client/registerCapability") {
for (const registration of normalizeLspRegistrations(params.registrations)) {
next.set(registration.id, registration);
}
return next;
}
let unregistrations: unknown[] = [];
if (Array.isArray(params.unregistrations)) unregistrations = params.unregistrations;
else if (Array.isArray(params.unregisterations)) unregistrations = params.unregisterations;
for (const registration of unregistrations) {
if (isRecord(registration) && typeof registration.id === "string") {
next.delete(registration.id);
}
}
return next;
}
export function effectiveLspCapabilities(
staticCapabilities: Record<string, unknown> | null,
registrations: ReadonlyMap<string, LspDynamicRegistration>,
): Record<string, unknown> | null {
if (!staticCapabilities && registrations.size === 0) return null;
const effective = { ...(staticCapabilities ?? {}) };
for (const registration of registrations.values()) {
const capability = providerCapabilities[registration.method];
if (!capability) continue;
effective[capability] = registration.registerOptions ?? true;
}
return effective;
}