objectionary/eo-lsp-server

`SemanticTokensProvider` constructor uses non-null assertions on optional `textDocument.semanticTokens` capabilities; crashes minimal `initialize`

開放

#321 建立於 2026年5月11日

 (2 則留言) (0 個反應) (0 位負責人)TypeScript (9 個分叉)github user discovery
bughelp wanted

倉庫指標

星標
 (6 顆星)
PR 合併指標
 (平均合併 4天 17小時) (30 天內合併 5 個 PR)

描述

What happens

In src/server.ts, the initialize handler constructs the SemanticTokensProvider by force-asserting two optional client capabilities:

provider = new SemanticTokensProvider(
    params.capabilities.textDocument!.semanticTokens!
);

Per LSP 3.17, both ClientCapabilities.textDocument and textDocument.semanticTokens are optional. A conformant minimal client (test harness, editor without semantic-token support, or any custom integration that does not advertise the capability) sends capabilities: {}. Reading .textDocument then yields undefined, and the next .semanticTokens access throws:

TypeError: Cannot read properties of undefined (reading 'semanticTokens')

The provider is constructed unconditionally on line 54, before any hasTokensSupport check happens later in onInitialized (line 108). So the crash happens during the very first round-trip of the LSP lifecycle, before the client has a chance to even register handlers.

What should happen

Either gate the construction behind the existing clientCapsAnalyzer.hasTokensSupport check, or default to an empty capability:

const tokenCaps = params.capabilities.textDocument?.semanticTokens;
if (tokenCaps) {
    provider = new SemanticTokensProvider(tokenCaps);
}

And drive the corresponding entries in InitializeResult.capabilities from the same condition. Result: a minimal client that does not advertise semantic-token support can initialize the server successfully, instead of crashing it during initialize.

貢獻者指南