( definition: RawServerDefinition, )
| 168 | export type RawServerDefinition = LspServerManifest; |
| 169 | |
| 170 | function sanitizeDefinition( |
| 171 | definition: RawServerDefinition, |
| 172 | ): LspServerDefinition { |
| 173 | if (!definition || typeof definition !== "object") { |
| 174 | throw new TypeError("LSP server definition must be an object"); |
| 175 | } |
| 176 | |
| 177 | const id = toKey(definition.id); |
| 178 | if (!id) throw new Error("LSP server definition requires a non-empty id"); |
| 179 | |
| 180 | const transport: RawTransportDescriptor = definition.transport ?? {}; |
| 181 | const kind = (transport.kind ?? "stdio") as |
| 182 | | "stdio" |
| 183 | | "websocket" |
| 184 | | "external"; |
| 185 | |
| 186 | if (!transport || typeof transport !== "object") { |
| 187 | throw new Error(`LSP server ${id} is missing a transport descriptor`); |
| 188 | } |
| 189 | |
| 190 | if ( |
| 191 | !("languages" in definition) || |
| 192 | !sanitizeLanguages(definition.languages).length |
| 193 | ) { |
| 194 | throw new Error(`LSP server ${id} must declare supported languages`); |
| 195 | } |
| 196 | |
| 197 | if (kind === "stdio" && !transport.command) { |
| 198 | throw new Error(`LSP server ${id} (stdio) requires a command`); |
| 199 | } |
| 200 | |
| 201 | // Websocket transport requires a URL unless a bridge is configured for auto-port discovery |
| 202 | const hasBridge = definition.launcher?.bridge?.command; |
| 203 | if (kind === "websocket" && !transport.url && !hasBridge) { |
| 204 | throw new Error( |
| 205 | `LSP server ${id} (websocket) requires a url or a launcher bridge`, |
| 206 | ); |
| 207 | } |
| 208 | |
| 209 | const transportOptions: Record<string, unknown> = |
| 210 | transport.options && typeof transport.options === "object" |
| 211 | ? { ...transport.options } |
| 212 | : {}; |
| 213 | |
| 214 | const sanitizedTransport: TransportDescriptor = { |
| 215 | kind, |
| 216 | command: transport.command, |
| 217 | args: Array.isArray(transport.args) |
| 218 | ? transport.args.map((arg) => String(arg)) |
| 219 | : undefined, |
| 220 | options: transportOptions, |
| 221 | url: transport.url, |
| 222 | protocols: undefined, |
| 223 | }; |
| 224 | |
| 225 | let launcher: LauncherConfig | undefined; |
| 226 | if (definition.launcher && typeof definition.launcher === "object") { |
| 227 | const rawLauncher = definition.launcher; |
no test coverage detected