@lspeasy/server 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/capability-guard.d.ts +56 -0
- package/dist/capability-guard.d.ts.map +1 -0
- package/dist/capability-guard.js +212 -0
- package/dist/capability-guard.js.map +1 -0
- package/dist/capability-proxy.d.ts +19 -0
- package/dist/capability-proxy.d.ts.map +1 -0
- package/dist/capability-proxy.js +121 -0
- package/dist/capability-proxy.js.map +1 -0
- package/dist/dispatcher.d.ts +52 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +174 -0
- package/dist/dispatcher.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +39 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +66 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/progress.d.ts +40 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +50 -0
- package/dist/progress.js.map +1 -0
- package/dist/server.d.ts +176 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +530 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +24 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +59 -0
- package/dist/validation.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Pradeep Mouli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# @lspeasy/server
|
|
2
|
+
|
|
3
|
+
Build Language Server Protocol (LSP) servers with a simple, type-safe API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lspeasy/server @lspeasy/core
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @lspeasy/server @lspeasy/core
|
|
11
|
+
# or
|
|
12
|
+
yarn add @lspeasy/server @lspeasy/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For WebSocket server transports, install `ws`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add ws
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
Create a minimal hover server in less than 30 lines:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { LSPServer, StdioTransport } from '@lspeasy/server';
|
|
27
|
+
import type { HoverParams, Hover } from '@lspeasy/server';
|
|
28
|
+
|
|
29
|
+
// Create server
|
|
30
|
+
const server = new LSPServer({
|
|
31
|
+
name: 'my-language-server',
|
|
32
|
+
version: '1.0.0'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Set capabilities
|
|
36
|
+
server.setCapabilities({
|
|
37
|
+
hoverProvider: true
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Register hover handler
|
|
41
|
+
server.onRequest<'textDocument/hover', HoverParams, Hover | null>(
|
|
42
|
+
'textDocument/hover',
|
|
43
|
+
async (params, token) => {
|
|
44
|
+
return {
|
|
45
|
+
contents: {
|
|
46
|
+
kind: 'markdown',
|
|
47
|
+
value: `# Hover\nLine ${params.position.line}`
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Start server
|
|
54
|
+
const transport = new StdioTransport();
|
|
55
|
+
await server.listen(transport);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
- **Type-Safe Handlers**: Fully typed request and notification handlers with IntelliSense support
|
|
61
|
+
- **Automatic Validation**: Built-in parameter validation using Zod schemas
|
|
62
|
+
- **Lifecycle Management**: Automatic initialize/shutdown handshake handling
|
|
63
|
+
- **Cancellation Support**: Built-in cancellation token support for long-running operations
|
|
64
|
+
- **Error Handling**: Comprehensive error handling with LSP error codes
|
|
65
|
+
- **Chainable API**: Fluent API with method chaining
|
|
66
|
+
|
|
67
|
+
## Handler Registration
|
|
68
|
+
|
|
69
|
+
### Request Handlers
|
|
70
|
+
|
|
71
|
+
Request handlers receive parameters, a cancellation token, and return a result:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
server.onRequest<'textDocument/completion', CompletionParams, CompletionList>(
|
|
75
|
+
'textDocument/completion',
|
|
76
|
+
async (params, token, context) => {
|
|
77
|
+
// Check for cancellation
|
|
78
|
+
if (token.isCancellationRequested) {
|
|
79
|
+
return { isIncomplete: false, items: [] };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Return completions
|
|
83
|
+
return {
|
|
84
|
+
isIncomplete: false,
|
|
85
|
+
items: [
|
|
86
|
+
{ label: 'function', kind: 3 },
|
|
87
|
+
{ label: 'const', kind: 6 }
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Notification Handlers
|
|
95
|
+
|
|
96
|
+
Notification handlers receive parameters but don't return a value:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
server.onNotification('textDocument/didOpen', (params, context) => {
|
|
100
|
+
console.log('Document opened:', params.textDocument.uri);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Method Chaining
|
|
105
|
+
|
|
106
|
+
Chain multiple handler registrations:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
server
|
|
110
|
+
.onRequest('textDocument/hover', hoverHandler)
|
|
111
|
+
.onRequest('textDocument/completion', completionHandler)
|
|
112
|
+
.onNotification('textDocument/didOpen', didOpenHandler)
|
|
113
|
+
.onNotification('textDocument/didChange', didChangeHandler);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Server Options
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
interface ServerOptions {
|
|
120
|
+
// Server name (sent in initialize response)
|
|
121
|
+
name?: string;
|
|
122
|
+
|
|
123
|
+
// Server version (sent in initialize response)
|
|
124
|
+
version?: string;
|
|
125
|
+
|
|
126
|
+
// Logger instance (defaults to ConsoleLogger)
|
|
127
|
+
logger?: Logger;
|
|
128
|
+
|
|
129
|
+
// Log level (defaults to 'info')
|
|
130
|
+
logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
131
|
+
|
|
132
|
+
// Custom validation error handler
|
|
133
|
+
onValidationError?: (error: ZodError, request: RequestContext) => ResponseError;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Error Handling
|
|
138
|
+
|
|
139
|
+
Throw `ResponseError` for custom error codes:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { ResponseError, JSONRPCErrorCode } from '@lspeasy/server';
|
|
143
|
+
|
|
144
|
+
server.onRequest('custom/method', async (params) => {
|
|
145
|
+
if (!params.valid) {
|
|
146
|
+
throw new ResponseError(
|
|
147
|
+
JSONRPCErrorCode.InvalidParams,
|
|
148
|
+
'Validation failed',
|
|
149
|
+
{ details: 'Invalid input' }
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return { success: true };
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Lifecycle
|
|
157
|
+
|
|
158
|
+
The server automatically handles the LSP lifecycle:
|
|
159
|
+
|
|
160
|
+
1. **Initialize**: Client sends `initialize` request → Server responds with capabilities
|
|
161
|
+
2. **Initialized**: Client sends `initialized` notification → Server is ready
|
|
162
|
+
3. **Running**: Server processes requests and notifications
|
|
163
|
+
4. **Shutdown**: Client sends `shutdown` request → Server prepares to exit
|
|
164
|
+
5. **Exit**: Client sends `exit` notification → Server closes
|
|
165
|
+
|
|
166
|
+
### Graceful Shutdown
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Graceful shutdown (waits for pending requests)
|
|
170
|
+
await server.shutdown(5000); // 5 second timeout
|
|
171
|
+
|
|
172
|
+
// Force close
|
|
173
|
+
await server.close();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Examples
|
|
177
|
+
|
|
178
|
+
Check out the [examples directory](../../examples/server/) for complete examples:
|
|
179
|
+
|
|
180
|
+
- [minimal-server.ts](../../examples/server/minimal-server.ts) - Basic hover server
|
|
181
|
+
- [hover-server.ts](../../examples/server/hover-server.ts) - Hover + completion with document tracking
|
|
182
|
+
|
|
183
|
+
## API Reference
|
|
184
|
+
|
|
185
|
+
### LSPServer
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
class LSPServer<Capabilities extends Partial<ServerCapabilities> = ServerCapabilities>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### Methods
|
|
192
|
+
|
|
193
|
+
- `onRequest<Method, Params, Result>(method, handler)` - Register request handler
|
|
194
|
+
- `onNotification<Method, Params>(method, handler)` - Register notification handler
|
|
195
|
+
- `setCapabilities(capabilities)` - Set server capabilities
|
|
196
|
+
- `getCapabilities()` - Get current capabilities
|
|
197
|
+
- `listen(transport)` - Start server on transport
|
|
198
|
+
- `shutdown(timeout?)` - Graceful shutdown
|
|
199
|
+
- `close()` - Force close
|
|
200
|
+
|
|
201
|
+
### Handler Types
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
type RequestHandler<Params, Result> = (
|
|
205
|
+
params: Params,
|
|
206
|
+
token: CancellationToken,
|
|
207
|
+
context: RequestContext
|
|
208
|
+
) => Promise<Result> | Result;
|
|
209
|
+
|
|
210
|
+
type NotificationHandler<Params> = (
|
|
211
|
+
params: Params,
|
|
212
|
+
context: NotificationContext
|
|
213
|
+
) => void | Promise<void>;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability validation for server handlers
|
|
3
|
+
*
|
|
4
|
+
* Ensures handlers can only be registered for declared capabilities
|
|
5
|
+
*/
|
|
6
|
+
import type { ClientCapabilities, ServerCapabilities } from '@lspeasy/core';
|
|
7
|
+
import type { Logger } from '@lspeasy/core';
|
|
8
|
+
/**
|
|
9
|
+
* Validates that a handler can be registered for a method
|
|
10
|
+
* based on declared server capabilities
|
|
11
|
+
*/
|
|
12
|
+
export declare class CapabilityGuard {
|
|
13
|
+
private readonly capabilities;
|
|
14
|
+
private readonly logger;
|
|
15
|
+
private readonly strict;
|
|
16
|
+
constructor(capabilities: Partial<ServerCapabilities>, logger: Logger, strict?: boolean);
|
|
17
|
+
/**
|
|
18
|
+
* Check if handler registration is allowed for this method
|
|
19
|
+
*
|
|
20
|
+
* @param method - LSP method name
|
|
21
|
+
* @returns true if allowed, false otherwise
|
|
22
|
+
* @throws Error if strict mode enabled and capability not declared
|
|
23
|
+
*/
|
|
24
|
+
canRegisterHandler(method: string): boolean;
|
|
25
|
+
getAllowedMethods(): string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validates that server-to-client messages respect declared client capabilities
|
|
29
|
+
*/
|
|
30
|
+
export declare class ClientCapabilityGuard {
|
|
31
|
+
private readonly capabilities;
|
|
32
|
+
private readonly logger;
|
|
33
|
+
private readonly strict;
|
|
34
|
+
constructor(capabilities: Partial<ClientCapabilities>, logger: Logger, strict?: boolean);
|
|
35
|
+
/**
|
|
36
|
+
* Check if a request can be sent to the client
|
|
37
|
+
*
|
|
38
|
+
* @param method - LSP method name
|
|
39
|
+
* @returns true if allowed, false otherwise
|
|
40
|
+
* @throws Error if strict mode enabled and client capability not declared
|
|
41
|
+
*/
|
|
42
|
+
canSendRequest(method: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Check if a notification can be sent to the client
|
|
45
|
+
*
|
|
46
|
+
* @param method - LSP method name
|
|
47
|
+
* @returns true if allowed, false otherwise
|
|
48
|
+
* @throws Error if strict mode enabled and client capability not declared
|
|
49
|
+
*/
|
|
50
|
+
canSendNotification(method: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Get list of capabilities the client declared
|
|
53
|
+
*/
|
|
54
|
+
getClientCapabilities(): Partial<ClientCapabilities>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=capability-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-guard.d.ts","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AA+C5C;;;GAGG;AACH,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,YAAY,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACzC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAe,EACtC;IAEJ;;;;;;OAMG;IACH,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAuD1C;IAED,iBAAiB,IAAI,MAAM,EAAE,CAK5B;CACF;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,YACmB,YAAY,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACzC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAe,EACtC;IAEJ;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA2CtC;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA2C3C;IAED;;OAEG;IACH,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAEnD;CACF"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability validation for server handlers
|
|
3
|
+
*
|
|
4
|
+
* Ensures handlers can only be registered for declared capabilities
|
|
5
|
+
*/
|
|
6
|
+
import { LSPNotification, LSPRequest, getClientCapabilityForNotificationMethod, getClientCapabilityForRequestMethod, hasServerCapability, hasClientCapability, getCapabilityForNotificationMethod, getCapabilityForRequestMethod } from '@lspeasy/core';
|
|
7
|
+
function buildMethodSets(capabilityKey) {
|
|
8
|
+
const all = new Set();
|
|
9
|
+
const alwaysAllowed = new Set();
|
|
10
|
+
for (const namespaceDefinitions of Object.values(LSPRequest)) {
|
|
11
|
+
for (const definition of Object.values(namespaceDefinitions)) {
|
|
12
|
+
const entry = definition;
|
|
13
|
+
all.add(entry.Method);
|
|
14
|
+
if (!entry[capabilityKey]) {
|
|
15
|
+
alwaysAllowed.add(entry.Method);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (const namespaceDefinitions of Object.values(LSPNotification)) {
|
|
20
|
+
for (const definition of Object.values(namespaceDefinitions)) {
|
|
21
|
+
const entry = definition;
|
|
22
|
+
all.add(entry.Method);
|
|
23
|
+
if (!entry[capabilityKey]) {
|
|
24
|
+
alwaysAllowed.add(entry.Method);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { all, alwaysAllowed };
|
|
29
|
+
}
|
|
30
|
+
const SERVER_METHODS = buildMethodSets('ServerCapability');
|
|
31
|
+
const CLIENT_METHODS = buildMethodSets('ClientCapability');
|
|
32
|
+
/**
|
|
33
|
+
* Validates that a handler can be registered for a method
|
|
34
|
+
* based on declared server capabilities
|
|
35
|
+
*/
|
|
36
|
+
export class CapabilityGuard {
|
|
37
|
+
capabilities;
|
|
38
|
+
logger;
|
|
39
|
+
strict;
|
|
40
|
+
constructor(capabilities, logger, strict = false) {
|
|
41
|
+
this.capabilities = capabilities;
|
|
42
|
+
this.logger = logger;
|
|
43
|
+
this.strict = strict;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if handler registration is allowed for this method
|
|
47
|
+
*
|
|
48
|
+
* @param method - LSP method name
|
|
49
|
+
* @returns true if allowed, false otherwise
|
|
50
|
+
* @throws Error if strict mode enabled and capability not declared
|
|
51
|
+
*/
|
|
52
|
+
canRegisterHandler(method) {
|
|
53
|
+
if (!SERVER_METHODS.all.has(method)) {
|
|
54
|
+
if (!this.strict) {
|
|
55
|
+
this.logger.debug(`Unknown method ${method}, allowing in non-strict mode`);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
const error = `Cannot register handler for unknown method: ${method}`;
|
|
59
|
+
this.logger.error(error);
|
|
60
|
+
if (this.strict) {
|
|
61
|
+
throw new Error(error);
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (SERVER_METHODS.alwaysAllowed.has(method)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// Check if method requires a capability (try both request and notification)
|
|
69
|
+
let capabilityKey = getCapabilityForRequestMethod(method);
|
|
70
|
+
if (!capabilityKey) {
|
|
71
|
+
capabilityKey = getCapabilityForNotificationMethod(method);
|
|
72
|
+
}
|
|
73
|
+
if (!capabilityKey) {
|
|
74
|
+
// Unknown method - allow in non-strict mode
|
|
75
|
+
if (!this.strict) {
|
|
76
|
+
this.logger.debug(`Unknown method ${method}, allowing in non-strict mode`);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
const error = `Cannot register handler for unknown method: ${method}`;
|
|
80
|
+
this.logger.error(error);
|
|
81
|
+
if (this.strict) {
|
|
82
|
+
throw new Error(error);
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
if (capabilityKey === 'alwaysOn') {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
// Check if capability is declared
|
|
90
|
+
if (!hasServerCapability(this.capabilities, capabilityKey)) {
|
|
91
|
+
const error = `Cannot register handler for ${method}: server capability '${capabilityKey}' not declared`;
|
|
92
|
+
this.logger.warn(error);
|
|
93
|
+
if (this.strict) {
|
|
94
|
+
throw new Error(error);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
getAllowedMethods() {
|
|
101
|
+
// This would require iterating through all LSP methods
|
|
102
|
+
// For now, return an empty array - can be enhanced if needed
|
|
103
|
+
this.logger.warn('getAllowedMethods not fully implemented - returns empty array');
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validates that server-to-client messages respect declared client capabilities
|
|
109
|
+
*/
|
|
110
|
+
export class ClientCapabilityGuard {
|
|
111
|
+
capabilities;
|
|
112
|
+
logger;
|
|
113
|
+
strict;
|
|
114
|
+
constructor(capabilities, logger, strict = false) {
|
|
115
|
+
this.capabilities = capabilities;
|
|
116
|
+
this.logger = logger;
|
|
117
|
+
this.strict = strict;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if a request can be sent to the client
|
|
121
|
+
*
|
|
122
|
+
* @param method - LSP method name
|
|
123
|
+
* @returns true if allowed, false otherwise
|
|
124
|
+
* @throws Error if strict mode enabled and client capability not declared
|
|
125
|
+
*/
|
|
126
|
+
canSendRequest(method) {
|
|
127
|
+
if (!CLIENT_METHODS.all.has(method)) {
|
|
128
|
+
if (!this.strict) {
|
|
129
|
+
this.logger.debug(`Unknown request method ${method}, allowing in non-strict mode`);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const error = `Cannot send request for unknown method: ${method}`;
|
|
133
|
+
this.logger.error(error);
|
|
134
|
+
throw new Error(error);
|
|
135
|
+
}
|
|
136
|
+
if (CLIENT_METHODS.alwaysAllowed.has(method)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
const capabilityKey = getClientCapabilityForRequestMethod(method);
|
|
140
|
+
if (!capabilityKey) {
|
|
141
|
+
if (!this.strict) {
|
|
142
|
+
this.logger.debug(`Unknown request method ${method}, allowing in non-strict mode`);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
const error = `Cannot send request for unknown method: ${method}`;
|
|
146
|
+
this.logger.error(error);
|
|
147
|
+
throw new Error(error);
|
|
148
|
+
}
|
|
149
|
+
if (capabilityKey === 'alwaysOn') {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
if (!hasClientCapability(this.capabilities, capabilityKey)) {
|
|
153
|
+
const error = `Cannot send request ${method}: client capability '${capabilityKey}' not declared`;
|
|
154
|
+
this.logger.warn(error);
|
|
155
|
+
if (this.strict) {
|
|
156
|
+
throw new Error(error);
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check if a notification can be sent to the client
|
|
164
|
+
*
|
|
165
|
+
* @param method - LSP method name
|
|
166
|
+
* @returns true if allowed, false otherwise
|
|
167
|
+
* @throws Error if strict mode enabled and client capability not declared
|
|
168
|
+
*/
|
|
169
|
+
canSendNotification(method) {
|
|
170
|
+
if (!CLIENT_METHODS.all.has(method)) {
|
|
171
|
+
if (!this.strict) {
|
|
172
|
+
this.logger.debug(`Unknown notification method ${method}, allowing in non-strict mode`);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
const error = `Cannot send notification for unknown method: ${method}`;
|
|
176
|
+
this.logger.error(error);
|
|
177
|
+
throw new Error(error);
|
|
178
|
+
}
|
|
179
|
+
if (CLIENT_METHODS.alwaysAllowed.has(method)) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
const capabilityKey = getClientCapabilityForNotificationMethod(method);
|
|
183
|
+
if (!capabilityKey) {
|
|
184
|
+
if (!this.strict) {
|
|
185
|
+
this.logger.debug(`Unknown notification method ${method}, allowing in non-strict mode`);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
const error = `Cannot send notification for unknown method: ${method}`;
|
|
189
|
+
this.logger.error(error);
|
|
190
|
+
throw new Error(error);
|
|
191
|
+
}
|
|
192
|
+
if (capabilityKey === 'alwaysOn') {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (!hasClientCapability(this.capabilities, capabilityKey)) {
|
|
196
|
+
const error = `Cannot send notification ${method}: client capability '${capabilityKey}' not declared`;
|
|
197
|
+
this.logger.warn(error);
|
|
198
|
+
if (this.strict) {
|
|
199
|
+
throw new Error(error);
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get list of capabilities the client declared
|
|
207
|
+
*/
|
|
208
|
+
getClientCapabilities() {
|
|
209
|
+
return { ...this.capabilities };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=capability-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-guard.js","sourceRoot":"","sources":["../src/capability-guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EACL,eAAe,EACf,UAAU,EACV,wCAAwC,EACxC,mCAAmC,EACnC,mBAAmB,EACnB,mBAAmB,EACnB,kCAAkC,EAClC,6BAA6B,EAC9B,MAAM,eAAe,CAAC;AAIvB,SAAS,eAAe,CAAC,aAA4B,EAGnD;IACA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAExC,KAAK,MAAM,oBAAoB,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7D,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC7D,MAAM,KAAK,GAAG,UAA4E,CAAC;YAC3F,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACtB,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC1B,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,oBAAoB,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;QAClE,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC7D,MAAM,KAAK,GAAG,UAA4E,CAAC;YAC3F,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACtB,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC1B,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC;AAAA,CAC/B;AAED,MAAM,cAAc,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAC;AAC3D,MAAM,cAAc,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,OAAO,eAAe;IAEP,YAAY;IACZ,MAAM;IACN,MAAM;IAHzB,YACmB,YAAyC,EACzC,MAAc,EACd,MAAM,GAAY,KAAK,EACxC;4BAHiB,YAAY;sBACZ,MAAM;sBACN,MAAM;IACtB,CAAC;IAEJ;;;;;;OAMG;IACH,kBAAkB,CAAC,MAAc,EAAW;QAC1C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,MAAM,+BAA+B,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,+CAA+C,MAAM,EAAE,CAAC;YACtE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,4EAA4E;QAC5E,IAAI,aAAa,GAAG,6BAA6B,CAAC,MAAa,CAAC,CAAC;QACjE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,kCAAkC,CAAC,MAAa,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,4CAA4C;YAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,MAAM,+BAA+B,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,+CAA+C,MAAM,EAAE,CAAC;YACtE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kCAAkC;QAClC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,+BAA+B,MAAM,wBAAwB,aAAa,gBAAgB,CAAC;YACzG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAExB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IAAA,CACb;IAED,iBAAiB,GAAa;QAC5B,uDAAuD;QACvD,6DAA6D;QAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;QAClF,OAAO,EAAE,CAAC;IAAA,CACX;CACF;AAED;;GAEG;AACH,MAAM,OAAO,qBAAqB;IAEb,YAAY;IACZ,MAAM;IACN,MAAM;IAHzB,YACmB,YAAyC,EACzC,MAAc,EACd,MAAM,GAAY,KAAK,EACxC;4BAHiB,YAAY;sBACZ,MAAM;sBACN,MAAM;IACtB,CAAC;IAEJ;;;;;;OAMG;IACH,cAAc,CAAC,MAAc,EAAW;QACtC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,+BAA+B,CAAC,CAAC;gBACnF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,2CAA2C,MAAM,EAAE,CAAC;YAClE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,mCAAmC,CAAC,MAAa,CAAC,CAAC;QACzE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,+BAA+B,CAAC,CAAC;gBACnF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,2CAA2C,MAAM,EAAE,CAAC;YAClE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,aAAoB,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,uBAAuB,MAAM,wBAAwB,aAAa,gBAAgB,CAAC;YACjG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAExB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IAAA,CACb;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,MAAc,EAAW;QAC3C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,+BAA+B,CAAC,CAAC;gBACxF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,gDAAgD,MAAM,EAAE,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,wCAAwC,CAAC,MAAa,CAAC,CAAC;QAC9E,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,MAAM,+BAA+B,CAAC,CAAC;gBACxF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,gDAAgD,MAAM,EAAE,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,aAAoB,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,4BAA4B,MAAM,wBAAwB,aAAa,gBAAgB,CAAC;YACtG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAExB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IAAA,CACb;IAED;;OAEG;IACH,qBAAqB,GAAgC;QACnD,OAAO,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;IAAA,CACjC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability-aware dynamic method injection for server
|
|
3
|
+
*
|
|
4
|
+
* Dynamically adds handler registration methods and send methods to the server
|
|
5
|
+
* based on declared capabilities
|
|
6
|
+
*/
|
|
7
|
+
import type { LSPServer } from './server.js';
|
|
8
|
+
import type { ServerCapabilities } from '@lspeasy/core';
|
|
9
|
+
/**
|
|
10
|
+
* Initialize capability-aware handler registration methods on the server
|
|
11
|
+
* Creates namespace.onMethod() style methods for registering handlers
|
|
12
|
+
*/
|
|
13
|
+
export declare function initializeServerHandlerMethods<Capabilities extends Partial<ServerCapabilities>>(server: LSPServer<Capabilities>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize capability-aware send methods on the server
|
|
16
|
+
* Creates namespace.method() style methods for sending requests/notifications to client
|
|
17
|
+
*/
|
|
18
|
+
export declare function initializeServerSendMethods<Capabilities extends Partial<ServerCapabilities>>(server: LSPServer<Capabilities>): void;
|
|
19
|
+
//# sourceMappingURL=capability-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-proxy.d.ts","sourceRoot":"","sources":["../src/capability-proxy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIxD;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,SAAS,OAAO,CAAC,kBAAkB,CAAC,EAC7F,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC,GAC9B,IAAI,CAyEN;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,SAAS,OAAO,CAAC,kBAAkB,CAAC,EAC1F,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC,GAC9B,IAAI,CAoDN"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability-aware dynamic method injection for server
|
|
3
|
+
*
|
|
4
|
+
* Dynamically adds handler registration methods and send methods to the server
|
|
5
|
+
* based on declared capabilities
|
|
6
|
+
*/
|
|
7
|
+
import { LSPRequest, LSPNotification, hasServerCapability } from '@lspeasy/core';
|
|
8
|
+
import camelCase from 'camelcase';
|
|
9
|
+
/**
|
|
10
|
+
* Initialize capability-aware handler registration methods on the server
|
|
11
|
+
* Creates namespace.onMethod() style methods for registering handlers
|
|
12
|
+
*/
|
|
13
|
+
export function initializeServerHandlerMethods(server) {
|
|
14
|
+
const capabilities = server.getServerCapabilities();
|
|
15
|
+
// Add handler registration methods for requests
|
|
16
|
+
for (const [namespaceName, namespaceDefinitions] of Object.entries(LSPRequest)) {
|
|
17
|
+
const clientPropertyName = camelCase(namespaceName);
|
|
18
|
+
const namespace = {};
|
|
19
|
+
for (const [methodKey, definition] of Object.entries(namespaceDefinitions)) {
|
|
20
|
+
const def = definition;
|
|
21
|
+
// Only add methods for clientToServer or both directions
|
|
22
|
+
if (def.Direction !== 'clientToServer' && def.Direction !== 'both') {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
// Check if capability is satisfied
|
|
26
|
+
if (def.ServerCapability) {
|
|
27
|
+
// Skip if capability is not set
|
|
28
|
+
if (!hasServerCapability(capabilities, def.ServerCapability)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Create handler registration method: onMethod
|
|
33
|
+
const handlerMethodName = `on${methodKey}`;
|
|
34
|
+
namespace[handlerMethodName] = function (handler) {
|
|
35
|
+
return server.onRequest(def.Method, handler);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Only add namespace if it has at least one method
|
|
39
|
+
if (Object.keys(namespace).length > 0) {
|
|
40
|
+
if (!server[clientPropertyName]) {
|
|
41
|
+
server[clientPropertyName] = {};
|
|
42
|
+
}
|
|
43
|
+
Object.assign(server[clientPropertyName], namespace);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Add handler registration methods for notifications
|
|
47
|
+
for (const [namespaceName, namespaceDefinitions] of Object.entries(LSPNotification)) {
|
|
48
|
+
const clientPropertyName = camelCase(namespaceName);
|
|
49
|
+
const namespace = {};
|
|
50
|
+
for (const [methodKey, definition] of Object.entries(namespaceDefinitions)) {
|
|
51
|
+
const def = definition;
|
|
52
|
+
// Only add methods for clientToServer or both directions
|
|
53
|
+
if (def.Direction !== 'clientToServer' && def.Direction !== 'both') {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Check if notification requires capability
|
|
57
|
+
if (def.ServerCapability && !hasServerCapability(capabilities, def.ServerCapability)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
// Create handler registration method: onMethod
|
|
61
|
+
const handlerMethodName = `on${methodKey}`;
|
|
62
|
+
namespace[handlerMethodName] = function (handler) {
|
|
63
|
+
return server.onNotification(def.Method, handler);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Only add namespace if it has at least one method
|
|
67
|
+
if (Object.keys(namespace).length > 0) {
|
|
68
|
+
if (!server[clientPropertyName]) {
|
|
69
|
+
server[clientPropertyName] = {};
|
|
70
|
+
}
|
|
71
|
+
Object.assign(server[clientPropertyName], namespace);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Initialize capability-aware send methods on the server
|
|
77
|
+
* Creates namespace.method() style methods for sending requests/notifications to client
|
|
78
|
+
*/
|
|
79
|
+
export function initializeServerSendMethods(server) {
|
|
80
|
+
// Add send methods for server-to-client requests
|
|
81
|
+
for (const [namespaceName, namespaceDefinitions] of Object.entries(LSPRequest)) {
|
|
82
|
+
const clientPropertyName = camelCase(namespaceName);
|
|
83
|
+
if (!server[clientPropertyName]) {
|
|
84
|
+
server[clientPropertyName] = {};
|
|
85
|
+
}
|
|
86
|
+
const namespace = server[clientPropertyName];
|
|
87
|
+
for (const [methodKey, definition] of Object.entries(namespaceDefinitions)) {
|
|
88
|
+
const def = definition;
|
|
89
|
+
// Only add methods for serverToClient or both directions
|
|
90
|
+
if (def.Direction !== 'serverToClient' && def.Direction !== 'both') {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// Create send method
|
|
94
|
+
const sendMethodName = camelCase(methodKey);
|
|
95
|
+
namespace[sendMethodName] = async function (params) {
|
|
96
|
+
return server.sendRequest(def.Method, params);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Add send methods for server-to-client notifications
|
|
101
|
+
for (const [namespaceName, namespaceDefinitions] of Object.entries(LSPNotification)) {
|
|
102
|
+
const clientPropertyName = camelCase(namespaceName);
|
|
103
|
+
if (!server[clientPropertyName]) {
|
|
104
|
+
server[clientPropertyName] = {};
|
|
105
|
+
}
|
|
106
|
+
const namespace = server[clientPropertyName];
|
|
107
|
+
for (const [methodKey, definition] of Object.entries(namespaceDefinitions)) {
|
|
108
|
+
const def = definition;
|
|
109
|
+
// Only add methods for serverToClient or both directions
|
|
110
|
+
if (def.Direction !== 'serverToClient' && def.Direction !== 'both') {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Create send method
|
|
114
|
+
const sendMethodName = camelCase(methodKey);
|
|
115
|
+
namespace[sendMethodName] = async function (params) {
|
|
116
|
+
return server.sendNotification(def.Method, params);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=capability-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-proxy.js","sourceRoot":"","sources":["../src/capability-proxy.ts"],"names":[],"mappings":"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"}
|