driftdetect-vscode 0.8.2
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +138 -0
- package/.vscode/launch.json +17 -0
- package/.vscode/tasks.json +15 -0
- package/LICENSE +121 -0
- package/dist/activation/activation-controller.d.ts +61 -0
- package/dist/activation/activation-controller.d.ts.map +1 -0
- package/dist/activation/activation-controller.js +235 -0
- package/dist/activation/activation-controller.js.map +1 -0
- package/dist/activation/activation-phases.d.ts +28 -0
- package/dist/activation/activation-phases.d.ts.map +1 -0
- package/dist/activation/activation-phases.js +80 -0
- package/dist/activation/activation-phases.js.map +1 -0
- package/dist/activation/index.d.ts +6 -0
- package/dist/activation/index.d.ts.map +1 -0
- package/dist/activation/index.js +6 -0
- package/dist/activation/index.js.map +1 -0
- package/dist/client/connection-config.d.ts +50 -0
- package/dist/client/connection-config.d.ts.map +1 -0
- package/dist/client/connection-config.js +56 -0
- package/dist/client/connection-config.js.map +1 -0
- package/dist/client/connection-manager.d.ts +70 -0
- package/dist/client/connection-manager.d.ts.map +1 -0
- package/dist/client/connection-manager.js +214 -0
- package/dist/client/connection-manager.js.map +1 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +8 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/language-client-factory.d.ts +29 -0
- package/dist/client/language-client-factory.d.ts.map +1 -0
- package/dist/client/language-client-factory.js +76 -0
- package/dist/client/language-client-factory.js.map +1 -0
- package/dist/client/request-middleware.d.ts +38 -0
- package/dist/client/request-middleware.d.ts.map +1 -0
- package/dist/client/request-middleware.js +85 -0
- package/dist/client/request-middleware.js.map +1 -0
- package/dist/commands/command-definitions.d.ts +53 -0
- package/dist/commands/command-definitions.d.ts.map +1 -0
- package/dist/commands/command-definitions.js +212 -0
- package/dist/commands/command-definitions.js.map +1 -0
- package/dist/commands/command-router.d.ts +80 -0
- package/dist/commands/command-router.d.ts.map +1 -0
- package/dist/commands/command-router.js +127 -0
- package/dist/commands/command-router.js.map +1 -0
- package/dist/commands/handlers/connection-handlers.d.ts +14 -0
- package/dist/commands/handlers/connection-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/connection-handlers.js +57 -0
- package/dist/commands/handlers/connection-handlers.js.map +1 -0
- package/dist/commands/handlers/constants-handlers.d.ts +11 -0
- package/dist/commands/handlers/constants-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/constants-handlers.js +84 -0
- package/dist/commands/handlers/constants-handlers.js.map +1 -0
- package/dist/commands/handlers/index.d.ts +10 -0
- package/dist/commands/handlers/index.d.ts.map +1 -0
- package/dist/commands/handlers/index.js +10 -0
- package/dist/commands/handlers/index.js.map +1 -0
- package/dist/commands/handlers/pattern-handlers.d.ts +13 -0
- package/dist/commands/handlers/pattern-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/pattern-handlers.js +127 -0
- package/dist/commands/handlers/pattern-handlers.js.map +1 -0
- package/dist/commands/handlers/scan-handlers.d.ts +15 -0
- package/dist/commands/handlers/scan-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/scan-handlers.js +74 -0
- package/dist/commands/handlers/scan-handlers.js.map +1 -0
- package/dist/commands/handlers/ui-handlers.d.ts +12 -0
- package/dist/commands/handlers/ui-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/ui-handlers.js +74 -0
- package/dist/commands/handlers/ui-handlers.js.map +1 -0
- package/dist/commands/handlers/violation-handlers.d.ts +13 -0
- package/dist/commands/handlers/violation-handlers.d.ts.map +1 -0
- package/dist/commands/handlers/violation-handlers.js +76 -0
- package/dist/commands/handlers/violation-handlers.js.map +1 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/middleware/connection-check-middleware.d.ts +12 -0
- package/dist/commands/middleware/connection-check-middleware.d.ts.map +1 -0
- package/dist/commands/middleware/connection-check-middleware.js +34 -0
- package/dist/commands/middleware/connection-check-middleware.js.map +1 -0
- package/dist/commands/middleware/index.d.ts +7 -0
- package/dist/commands/middleware/index.d.ts.map +1 -0
- package/dist/commands/middleware/index.js +7 -0
- package/dist/commands/middleware/index.js.map +1 -0
- package/dist/commands/middleware/logging-middleware.d.ts +12 -0
- package/dist/commands/middleware/logging-middleware.d.ts.map +1 -0
- package/dist/commands/middleware/logging-middleware.js +24 -0
- package/dist/commands/middleware/logging-middleware.js.map +1 -0
- package/dist/commands/middleware/telemetry-middleware.d.ts +22 -0
- package/dist/commands/middleware/telemetry-middleware.d.ts.map +1 -0
- package/dist/commands/middleware/telemetry-middleware.js +30 -0
- package/dist/commands/middleware/telemetry-middleware.js.map +1 -0
- package/dist/config/config-manager.d.ts +53 -0
- package/dist/config/config-manager.d.ts.map +1 -0
- package/dist/config/config-manager.js +178 -0
- package/dist/config/config-manager.js.map +1 -0
- package/dist/config/defaults.d.ts +11 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +43 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/validator.d.ts +22 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +93 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/extension.d.ts +32 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +50 -0
- package/dist/extension.js.map +1 -0
- package/dist/infrastructure/disposable-manager.d.ts +43 -0
- package/dist/infrastructure/disposable-manager.d.ts.map +1 -0
- package/dist/infrastructure/disposable-manager.js +75 -0
- package/dist/infrastructure/disposable-manager.js.map +1 -0
- package/dist/infrastructure/event-bus.d.ts +85 -0
- package/dist/infrastructure/event-bus.d.ts.map +1 -0
- package/dist/infrastructure/event-bus.js +74 -0
- package/dist/infrastructure/event-bus.js.map +1 -0
- package/dist/infrastructure/index.d.ts +10 -0
- package/dist/infrastructure/index.d.ts.map +1 -0
- package/dist/infrastructure/index.js +10 -0
- package/dist/infrastructure/index.js.map +1 -0
- package/dist/infrastructure/logger.d.ts +37 -0
- package/dist/infrastructure/logger.d.ts.map +1 -0
- package/dist/infrastructure/logger.js +86 -0
- package/dist/infrastructure/logger.js.map +1 -0
- package/dist/infrastructure/service-container.d.ts +68 -0
- package/dist/infrastructure/service-container.d.ts.map +1 -0
- package/dist/infrastructure/service-container.js +94 -0
- package/dist/infrastructure/service-container.js.map +1 -0
- package/dist/state/index.d.ts +7 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +7 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/initial-state.d.ts +11 -0
- package/dist/state/initial-state.d.ts.map +1 -0
- package/dist/state/initial-state.js +58 -0
- package/dist/state/initial-state.js.map +1 -0
- package/dist/state/selectors.d.ts +41 -0
- package/dist/state/selectors.d.ts.map +1 -0
- package/dist/state/selectors.js +61 -0
- package/dist/state/selectors.js.map +1 -0
- package/dist/state/state-manager.d.ts +54 -0
- package/dist/state/state-manager.d.ts.map +1 -0
- package/dist/state/state-manager.js +166 -0
- package/dist/state/state-manager.js.map +1 -0
- package/dist/types/config-types.d.ts +69 -0
- package/dist/types/config-types.d.ts.map +1 -0
- package/dist/types/config-types.js +5 -0
- package/dist/types/config-types.js.map +1 -0
- package/dist/types/extension-types.d.ts +45 -0
- package/dist/types/extension-types.d.ts.map +1 -0
- package/dist/types/extension-types.js +5 -0
- package/dist/types/extension-types.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/lsp-types.d.ts +70 -0
- package/dist/types/lsp-types.d.ts.map +1 -0
- package/dist/types/lsp-types.js +5 -0
- package/dist/types/lsp-types.js.map +1 -0
- package/dist/types/state-types.d.ts +82 -0
- package/dist/types/state-types.d.ts.map +1 -0
- package/dist/types/state-types.js +5 -0
- package/dist/types/state-types.js.map +1 -0
- package/dist/types/vscode-types.d.ts +36 -0
- package/dist/types/vscode-types.d.ts.map +1 -0
- package/dist/types/vscode-types.js +7 -0
- package/dist/types/vscode-types.js.map +1 -0
- package/dist/ui/decorations/decoration-controller.d.ts +45 -0
- package/dist/ui/decorations/decoration-controller.d.ts.map +1 -0
- package/dist/ui/decorations/decoration-controller.js +198 -0
- package/dist/ui/decorations/decoration-controller.js.map +1 -0
- package/dist/ui/decorations/decoration-types.d.ts +28 -0
- package/dist/ui/decorations/decoration-types.d.ts.map +1 -0
- package/dist/ui/decorations/decoration-types.js +98 -0
- package/dist/ui/decorations/decoration-types.js.map +1 -0
- package/dist/ui/decorations/index.d.ts +7 -0
- package/dist/ui/decorations/index.d.ts.map +1 -0
- package/dist/ui/decorations/index.js +6 -0
- package/dist/ui/decorations/index.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/notifications/index.d.ts +5 -0
- package/dist/ui/notifications/index.d.ts.map +1 -0
- package/dist/ui/notifications/index.js +5 -0
- package/dist/ui/notifications/index.js.map +1 -0
- package/dist/ui/notifications/notification-service.d.ts +66 -0
- package/dist/ui/notifications/notification-service.d.ts.map +1 -0
- package/dist/ui/notifications/notification-service.js +103 -0
- package/dist/ui/notifications/notification-service.js.map +1 -0
- package/dist/ui/status-bar/index.d.ts +6 -0
- package/dist/ui/status-bar/index.d.ts.map +1 -0
- package/dist/ui/status-bar/index.js +6 -0
- package/dist/ui/status-bar/index.js.map +1 -0
- package/dist/ui/status-bar/status-bar-controller.d.ts +37 -0
- package/dist/ui/status-bar/status-bar-controller.d.ts.map +1 -0
- package/dist/ui/status-bar/status-bar-controller.js +111 -0
- package/dist/ui/status-bar/status-bar-controller.js.map +1 -0
- package/dist/ui/status-bar/status-bar-modes.d.ts +26 -0
- package/dist/ui/status-bar/status-bar-modes.d.ts.map +1 -0
- package/dist/ui/status-bar/status-bar-modes.js +97 -0
- package/dist/ui/status-bar/status-bar-modes.js.map +1 -0
- package/dist/views/base-tree-provider.d.ts +74 -0
- package/dist/views/base-tree-provider.d.ts.map +1 -0
- package/dist/views/base-tree-provider.js +95 -0
- package/dist/views/base-tree-provider.js.map +1 -0
- package/dist/views/constants-tree-provider.d.ts +112 -0
- package/dist/views/constants-tree-provider.d.ts.map +1 -0
- package/dist/views/constants-tree-provider.js +344 -0
- package/dist/views/constants-tree-provider.js.map +1 -0
- package/dist/views/files-tree-provider.d.ts +37 -0
- package/dist/views/files-tree-provider.d.ts.map +1 -0
- package/dist/views/files-tree-provider.js +98 -0
- package/dist/views/files-tree-provider.js.map +1 -0
- package/dist/views/index.d.ts +10 -0
- package/dist/views/index.d.ts.map +1 -0
- package/dist/views/index.js +10 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/patterns-tree-provider.d.ts +39 -0
- package/dist/views/patterns-tree-provider.d.ts.map +1 -0
- package/dist/views/patterns-tree-provider.js +139 -0
- package/dist/views/patterns-tree-provider.js.map +1 -0
- package/dist/views/violations-tree-provider.d.ts +46 -0
- package/dist/views/violations-tree-provider.d.ts.map +1 -0
- package/dist/views/violations-tree-provider.js +158 -0
- package/dist/views/violations-tree-provider.js.map +1 -0
- package/dist/webview/index.d.ts +7 -0
- package/dist/webview/index.d.ts.map +1 -0
- package/dist/webview/index.js +7 -0
- package/dist/webview/index.js.map +1 -0
- package/dist/webview/webview-manager.d.ts +57 -0
- package/dist/webview/webview-manager.d.ts.map +1 -0
- package/dist/webview/webview-manager.js +167 -0
- package/dist/webview/webview-manager.js.map +1 -0
- package/package.json +405 -0
- package/resources/drift-icon.png +0 -0
- package/resources/drift-icon.svg +5 -0
- package/resources/icons/error.svg +4 -0
- package/resources/icons/info.svg +4 -0
- package/resources/icons/lightbulb.svg +4 -0
- package/resources/icons/warning.svg +4 -0
- package/src/activation/activation-controller.ts +320 -0
- package/src/activation/activation-phases.ts +96 -0
- package/src/activation/index.ts +6 -0
- package/src/client/connection-config.ts +64 -0
- package/src/client/connection-manager.ts +263 -0
- package/src/client/index.ts +8 -0
- package/src/client/language-client-factory.ts +111 -0
- package/src/client/request-middleware.ts +117 -0
- package/src/commands/command-definitions.ts +243 -0
- package/src/commands/command-router.ts +194 -0
- package/src/commands/handlers/connection-handlers.ts +74 -0
- package/src/commands/handlers/constants-handlers.ts +99 -0
- package/src/commands/handlers/index.ts +10 -0
- package/src/commands/handlers/pattern-handlers.ts +167 -0
- package/src/commands/handlers/scan-handlers.ts +107 -0
- package/src/commands/handlers/ui-handlers.ts +88 -0
- package/src/commands/handlers/violation-handlers.ts +97 -0
- package/src/commands/index.ts +7 -0
- package/src/commands/middleware/connection-check-middleware.ts +46 -0
- package/src/commands/middleware/index.ts +7 -0
- package/src/commands/middleware/logging-middleware.ts +28 -0
- package/src/commands/middleware/telemetry-middleware.ts +46 -0
- package/src/config/config-manager.ts +213 -0
- package/src/config/defaults.ts +45 -0
- package/src/config/index.ts +7 -0
- package/src/config/validator.ts +118 -0
- package/src/extension.ts +57 -0
- package/src/infrastructure/disposable-manager.ts +87 -0
- package/src/infrastructure/event-bus.ts +121 -0
- package/src/infrastructure/index.ts +10 -0
- package/src/infrastructure/logger.ts +108 -0
- package/src/infrastructure/service-container.ts +123 -0
- package/src/state/index.ts +7 -0
- package/src/state/initial-state.ts +60 -0
- package/src/state/selectors.ts +126 -0
- package/src/state/state-manager.ts +198 -0
- package/src/types/config-types.ts +77 -0
- package/src/types/extension-types.ts +58 -0
- package/src/types/index.ts +12 -0
- package/src/types/lsp-types.ts +77 -0
- package/src/types/state-types.ts +92 -0
- package/src/types/vscode-types.ts +40 -0
- package/src/ui/decorations/decoration-controller.ts +252 -0
- package/src/ui/decorations/decoration-types.ts +129 -0
- package/src/ui/decorations/index.ts +7 -0
- package/src/ui/index.ts +7 -0
- package/src/ui/notifications/index.ts +5 -0
- package/src/ui/notifications/notification-service.ts +167 -0
- package/src/ui/status-bar/index.ts +6 -0
- package/src/ui/status-bar/status-bar-controller.ts +135 -0
- package/src/ui/status-bar/status-bar-modes.ts +119 -0
- package/src/views/base-tree-provider.ts +127 -0
- package/src/views/constants-tree-provider.ts +525 -0
- package/src/views/files-tree-provider.ts +140 -0
- package/src/views/index.ts +10 -0
- package/src/views/patterns-tree-provider.ts +179 -0
- package/src/views/violations-tree-provider.ts +210 -0
- package/src/webview/index.ts +7 -0
- package/src/webview/webview-manager.ts +238 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConnectionManager - LSP connection lifecycle management
|
|
3
|
+
*
|
|
4
|
+
* Single responsibility: Manage LSP client connection with auto-recovery.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as vscode from 'vscode';
|
|
8
|
+
|
|
9
|
+
import { CONNECTION_CONFIG } from './connection-config.js';
|
|
10
|
+
import { createLanguageClient } from './language-client-factory.js';
|
|
11
|
+
|
|
12
|
+
import type { EventBus } from '../infrastructure/event-bus.js';
|
|
13
|
+
import type { Logger } from '../infrastructure/index.js';
|
|
14
|
+
import type { ConnectionState, ServerConfig } from '../types/index.js';
|
|
15
|
+
import type { LanguageClient, StateChangeEvent } from 'vscode-languageclient/node';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Connection manager for LSP client
|
|
20
|
+
*/
|
|
21
|
+
export class ConnectionManager implements vscode.Disposable {
|
|
22
|
+
private client: LanguageClient | null = null;
|
|
23
|
+
private state: ConnectionState = 'disconnected';
|
|
24
|
+
private restartCount = 0;
|
|
25
|
+
private healthCheckTimer: NodeJS.Timeout | null = null;
|
|
26
|
+
private readonly disposables: vscode.Disposable[] = [];
|
|
27
|
+
|
|
28
|
+
private readonly stateEmitter = new vscode.EventEmitter<ConnectionState>();
|
|
29
|
+
readonly onStateChange = this.stateEmitter.event;
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly context: vscode.ExtensionContext,
|
|
33
|
+
private readonly logger: Logger,
|
|
34
|
+
private readonly eventBus: EventBus,
|
|
35
|
+
private config: ServerConfig
|
|
36
|
+
) {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get current connection state
|
|
40
|
+
*/
|
|
41
|
+
getState(): ConnectionState {
|
|
42
|
+
return this.state;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the language client (if connected)
|
|
47
|
+
*/
|
|
48
|
+
getClient(): LanguageClient | null {
|
|
49
|
+
return this.state === 'connected' ? this.client : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Connect to the LSP server
|
|
54
|
+
*/
|
|
55
|
+
async connect(): Promise<void> {
|
|
56
|
+
if (this.state === 'connected' || this.state === 'connecting') {
|
|
57
|
+
this.logger.debug('Already connected or connecting');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.setState('connecting');
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
this.client = createLanguageClient(this.context, this.logger, this.config);
|
|
65
|
+
|
|
66
|
+
// Set up client event handlers
|
|
67
|
+
this.setupClientHandlers();
|
|
68
|
+
|
|
69
|
+
// Start the client
|
|
70
|
+
await this.client.start();
|
|
71
|
+
|
|
72
|
+
// Wait for ready state
|
|
73
|
+
await this.waitForReady();
|
|
74
|
+
|
|
75
|
+
this.setState('connected');
|
|
76
|
+
this.restartCount = 0;
|
|
77
|
+
this.startHealthCheck();
|
|
78
|
+
|
|
79
|
+
this.logger.info('Connected to Drift LSP server');
|
|
80
|
+
|
|
81
|
+
} catch (error) {
|
|
82
|
+
await this.handleConnectionError(error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Disconnect from the LSP server
|
|
88
|
+
*/
|
|
89
|
+
async disconnect(): Promise<void> {
|
|
90
|
+
this.stopHealthCheck();
|
|
91
|
+
|
|
92
|
+
if (this.client) {
|
|
93
|
+
try {
|
|
94
|
+
await Promise.race([
|
|
95
|
+
this.client.stop(),
|
|
96
|
+
this.timeout(CONNECTION_CONFIG.shutdownTimeout),
|
|
97
|
+
]);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
this.logger.warn('Error during disconnect:', error);
|
|
100
|
+
}
|
|
101
|
+
this.client = null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.setState('disconnected');
|
|
105
|
+
this.logger.info('Disconnected from Drift LSP server');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Reconnect to the LSP server
|
|
110
|
+
*/
|
|
111
|
+
async reconnect(): Promise<void> {
|
|
112
|
+
await this.disconnect();
|
|
113
|
+
await this.connect();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Update server configuration
|
|
118
|
+
*/
|
|
119
|
+
updateConfig(config: ServerConfig): void {
|
|
120
|
+
this.config = config;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Dispose resources
|
|
125
|
+
*/
|
|
126
|
+
dispose(): void {
|
|
127
|
+
this.stopHealthCheck();
|
|
128
|
+
this.stateEmitter.dispose();
|
|
129
|
+
|
|
130
|
+
if (this.client) {
|
|
131
|
+
this.client.stop().catch(() => {});
|
|
132
|
+
this.client = null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const d of this.disposables) {
|
|
136
|
+
d.dispose();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private setState(state: ConnectionState): void {
|
|
141
|
+
const previousState = this.state;
|
|
142
|
+
this.state = state;
|
|
143
|
+
this.stateEmitter.fire(state);
|
|
144
|
+
this.eventBus.emit('connection:changed', { status: state, previousStatus: previousState });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private setupClientHandlers(): void {
|
|
148
|
+
if (!this.client) {return;}
|
|
149
|
+
|
|
150
|
+
// Handle client errors
|
|
151
|
+
this.client.onDidChangeState((event: StateChangeEvent) => {
|
|
152
|
+
this.logger.debug(`Client state changed: ${event.oldState} -> ${event.newState}`);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private async waitForReady(): Promise<void> {
|
|
157
|
+
if (!this.client) {
|
|
158
|
+
throw new Error('Client not initialized');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const timeout = CONNECTION_CONFIG.initializeTimeout;
|
|
162
|
+
const startTime = Date.now();
|
|
163
|
+
|
|
164
|
+
while (Date.now() - startTime < timeout) {
|
|
165
|
+
if (this.client.isRunning()) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
await this.delay(100);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
throw new Error(`Server initialization timed out after ${timeout}ms`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private async handleConnectionError(error: unknown): Promise<void> {
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
176
|
+
this.logger.error('Connection error:', errorMessage);
|
|
177
|
+
|
|
178
|
+
this.setState('error');
|
|
179
|
+
this.eventBus.emit('connection:error', {
|
|
180
|
+
error: error instanceof Error ? error : new Error(errorMessage),
|
|
181
|
+
recoverable: this.restartCount < CONNECTION_CONFIG.maxRestarts,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (this.restartCount >= CONNECTION_CONFIG.maxRestarts) {
|
|
185
|
+
this.setState('failed');
|
|
186
|
+
this.logger.error(`Max restart attempts (${CONNECTION_CONFIG.maxRestarts}) reached`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const delay = this.calculateBackoff();
|
|
191
|
+
this.restartCount++;
|
|
192
|
+
|
|
193
|
+
this.logger.info(
|
|
194
|
+
`Reconnecting in ${delay}ms (attempt ${this.restartCount}/${CONNECTION_CONFIG.maxRestarts})`
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
this.setState('reconnecting');
|
|
198
|
+
await this.delay(delay);
|
|
199
|
+
await this.connect();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private calculateBackoff(): number {
|
|
203
|
+
const delay = CONNECTION_CONFIG.restartDelay *
|
|
204
|
+
Math.pow(CONNECTION_CONFIG.backoffMultiplier, this.restartCount);
|
|
205
|
+
return Math.min(delay, CONNECTION_CONFIG.maxBackoffDelay);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private startHealthCheck(): void {
|
|
209
|
+
this.stopHealthCheck();
|
|
210
|
+
|
|
211
|
+
this.healthCheckTimer = setInterval(async () => {
|
|
212
|
+
if (!await this.isHealthy()) {
|
|
213
|
+
this.logger.warn('Health check failed, reconnecting...');
|
|
214
|
+
await this.reconnect();
|
|
215
|
+
}
|
|
216
|
+
}, CONNECTION_CONFIG.healthCheckInterval);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private stopHealthCheck(): void {
|
|
220
|
+
if (this.healthCheckTimer) {
|
|
221
|
+
clearInterval(this.healthCheckTimer);
|
|
222
|
+
this.healthCheckTimer = null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private async isHealthy(): Promise<boolean> {
|
|
227
|
+
if (!this.client?.isRunning()) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
await Promise.race([
|
|
233
|
+
this.client.sendRequest('drift/health'),
|
|
234
|
+
this.timeout(5000),
|
|
235
|
+
]);
|
|
236
|
+
return true;
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private timeout(ms: number): Promise<never> {
|
|
243
|
+
return new Promise((_, reject) => {
|
|
244
|
+
setTimeout(() => { reject(new Error('Timeout')); }, ms);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private delay(ms: number): Promise<void> {
|
|
249
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Factory function for creating connection manager
|
|
255
|
+
*/
|
|
256
|
+
export function createConnectionManager(
|
|
257
|
+
context: vscode.ExtensionContext,
|
|
258
|
+
logger: Logger,
|
|
259
|
+
eventBus: EventBus,
|
|
260
|
+
config: ServerConfig
|
|
261
|
+
): ConnectionManager {
|
|
262
|
+
return new ConnectionManager(context, logger, eventBus, config);
|
|
263
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP Client module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { ConnectionManager, createConnectionManager } from './connection-manager.js';
|
|
6
|
+
export { LanguageClientFactory, createLanguageClient } from './language-client-factory.js';
|
|
7
|
+
export { RequestMiddleware, createRequestMiddleware } from './request-middleware.js';
|
|
8
|
+
export { CONNECTION_CONFIG } from './connection-config.js';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LanguageClientFactory - Creates configured LSP clients
|
|
3
|
+
*
|
|
4
|
+
* Single responsibility: Create and configure LanguageClient instances.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
|
|
9
|
+
import * as vscode from 'vscode';
|
|
10
|
+
import {
|
|
11
|
+
LanguageClient,
|
|
12
|
+
LanguageClientOptions,
|
|
13
|
+
ServerOptions,
|
|
14
|
+
TransportKind,
|
|
15
|
+
} from 'vscode-languageclient/node';
|
|
16
|
+
|
|
17
|
+
import { DOCUMENT_SELECTORS } from './connection-config.js';
|
|
18
|
+
|
|
19
|
+
import type { Logger } from '../infrastructure/index.js';
|
|
20
|
+
import type { ServerConfig } from '../types/index.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Factory for creating language clients
|
|
24
|
+
*/
|
|
25
|
+
export class LanguageClientFactory {
|
|
26
|
+
constructor(
|
|
27
|
+
private readonly context: vscode.ExtensionContext,
|
|
28
|
+
private readonly logger: Logger
|
|
29
|
+
) {}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Create a new language client
|
|
33
|
+
*/
|
|
34
|
+
create(config: ServerConfig): LanguageClient {
|
|
35
|
+
const serverOptions = this.createServerOptions(config);
|
|
36
|
+
const clientOptions = this.createClientOptions(config);
|
|
37
|
+
|
|
38
|
+
const client = new LanguageClient(
|
|
39
|
+
'drift',
|
|
40
|
+
'Drift Language Server',
|
|
41
|
+
serverOptions,
|
|
42
|
+
clientOptions
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return client;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private createServerOptions(config: ServerConfig): ServerOptions {
|
|
49
|
+
// Use custom path if provided, otherwise use bundled server
|
|
50
|
+
const serverModule = config.path || this.getBundledServerPath();
|
|
51
|
+
|
|
52
|
+
this.logger.debug(`Server module: ${serverModule}`);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
run: {
|
|
56
|
+
module: serverModule,
|
|
57
|
+
transport: TransportKind.ipc,
|
|
58
|
+
args: config.args,
|
|
59
|
+
},
|
|
60
|
+
debug: {
|
|
61
|
+
module: serverModule,
|
|
62
|
+
transport: TransportKind.ipc,
|
|
63
|
+
args: [...config.args, '--debug'],
|
|
64
|
+
options: {
|
|
65
|
+
execArgv: ['--nolazy', '--inspect=6009'],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private createClientOptions(config: ServerConfig): LanguageClientOptions {
|
|
72
|
+
return {
|
|
73
|
+
documentSelector: DOCUMENT_SELECTORS,
|
|
74
|
+
synchronize: {
|
|
75
|
+
// Watch .drift directory for config changes
|
|
76
|
+
fileEvents: vscode.workspace.createFileSystemWatcher('**/.drift/**'),
|
|
77
|
+
},
|
|
78
|
+
outputChannel: vscode.window.createOutputChannel('Drift LSP'),
|
|
79
|
+
traceOutputChannel: vscode.window.createOutputChannel('Drift LSP Trace'),
|
|
80
|
+
initializationOptions: {
|
|
81
|
+
trace: config.trace,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private getBundledServerPath(): string {
|
|
87
|
+
// Look for the LSP server in the extension's dependencies
|
|
88
|
+
const serverPath = path.join(
|
|
89
|
+
this.context.extensionPath,
|
|
90
|
+
'node_modules',
|
|
91
|
+
'driftdetect-lsp',
|
|
92
|
+
'dist',
|
|
93
|
+
'bin',
|
|
94
|
+
'server.js'
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return serverPath;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Factory function for creating language client factory
|
|
103
|
+
*/
|
|
104
|
+
export function createLanguageClient(
|
|
105
|
+
context: vscode.ExtensionContext,
|
|
106
|
+
logger: Logger,
|
|
107
|
+
config: ServerConfig
|
|
108
|
+
): LanguageClient {
|
|
109
|
+
const factory = new LanguageClientFactory(context, logger);
|
|
110
|
+
return factory.create(config);
|
|
111
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RequestMiddleware - Request/response interceptors
|
|
3
|
+
*
|
|
4
|
+
* Single responsibility: Add retry, timeout, and logging to LSP requests.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CONNECTION_CONFIG } from './connection-config.js';
|
|
8
|
+
|
|
9
|
+
import type { Logger } from '../infrastructure/index.js';
|
|
10
|
+
import type { LanguageClient } from 'vscode-languageclient/node';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Request options
|
|
14
|
+
*/
|
|
15
|
+
export interface RequestOptions {
|
|
16
|
+
timeout?: number;
|
|
17
|
+
retries?: number;
|
|
18
|
+
retryDelay?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Default request options
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_OPTIONS: Required<RequestOptions> = {
|
|
25
|
+
timeout: CONNECTION_CONFIG.requestTimeout,
|
|
26
|
+
retries: 2,
|
|
27
|
+
retryDelay: 500,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Middleware for LSP requests with retry and timeout
|
|
32
|
+
*/
|
|
33
|
+
export class RequestMiddleware {
|
|
34
|
+
constructor(
|
|
35
|
+
private readonly client: LanguageClient,
|
|
36
|
+
private readonly logger: Logger
|
|
37
|
+
) {}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Send a request with retry and timeout
|
|
41
|
+
*/
|
|
42
|
+
async request<T>(
|
|
43
|
+
method: string,
|
|
44
|
+
params?: unknown,
|
|
45
|
+
options: RequestOptions = {}
|
|
46
|
+
): Promise<T> {
|
|
47
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
48
|
+
let lastError: Error | undefined;
|
|
49
|
+
|
|
50
|
+
for (let attempt = 0; attempt <= opts.retries; attempt++) {
|
|
51
|
+
try {
|
|
52
|
+
const result = await this.sendWithTimeout<T>(method, params, opts.timeout);
|
|
53
|
+
return result;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
56
|
+
|
|
57
|
+
if (attempt < opts.retries) {
|
|
58
|
+
this.logger.warn(
|
|
59
|
+
`Request ${method} failed (attempt ${attempt + 1}/${opts.retries + 1}): ${lastError.message}`
|
|
60
|
+
);
|
|
61
|
+
await this.delay(opts.retryDelay * (attempt + 1));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.logger.error(`Request ${method} failed after ${opts.retries + 1} attempts`);
|
|
67
|
+
throw lastError;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Send a notification (fire and forget)
|
|
72
|
+
*/
|
|
73
|
+
notify(method: string, params?: unknown): void {
|
|
74
|
+
try {
|
|
75
|
+
this.client.sendNotification(method, params);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
this.logger.error(`Notification ${method} failed:`, error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private async sendWithTimeout<T>(
|
|
82
|
+
method: string,
|
|
83
|
+
params: unknown,
|
|
84
|
+
timeout: number
|
|
85
|
+
): Promise<T> {
|
|
86
|
+
return new Promise<T>((resolve, reject) => {
|
|
87
|
+
const timer = setTimeout(() => {
|
|
88
|
+
reject(new Error(`Request ${method} timed out after ${timeout}ms`));
|
|
89
|
+
}, timeout);
|
|
90
|
+
|
|
91
|
+
this.client
|
|
92
|
+
.sendRequest<T>(method, params)
|
|
93
|
+
.then((result) => {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
resolve(result);
|
|
96
|
+
})
|
|
97
|
+
.catch((error) => {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
reject(error);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private delay(ms: number): Promise<void> {
|
|
105
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Factory function for creating request middleware
|
|
111
|
+
*/
|
|
112
|
+
export function createRequestMiddleware(
|
|
113
|
+
client: LanguageClient,
|
|
114
|
+
logger: Logger
|
|
115
|
+
): RequestMiddleware {
|
|
116
|
+
return new RequestMiddleware(client, logger);
|
|
117
|
+
}
|