driftdetect-vscode 0.9.32 → 0.9.33

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.
Files changed (132) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +44 -1
  3. package/.turbo/turbo-test.log +0 -34
  4. package/dist/activation/activation-controller.d.ts.map +1 -0
  5. package/dist/activation/activation-controller.js +235 -0
  6. package/dist/activation/activation-controller.js.map +1 -0
  7. package/dist/activation/activation-phases.d.ts.map +1 -0
  8. package/dist/activation/index.d.ts.map +1 -0
  9. package/dist/client/connection-manager.d.ts.map +1 -0
  10. package/dist/client/connection-manager.js +216 -0
  11. package/dist/client/connection-manager.js.map +1 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/language-client-factory.d.ts.map +1 -0
  14. package/dist/client/request-middleware.d.ts.map +1 -0
  15. package/dist/client/request-middleware.js +85 -0
  16. package/dist/client/request-middleware.js.map +1 -0
  17. package/dist/commands/command-router.d.ts.map +1 -0
  18. package/dist/commands/command-router.js +129 -0
  19. package/dist/commands/command-router.js.map +1 -0
  20. package/dist/commands/handlers/connection-handlers.d.ts.map +1 -0
  21. package/dist/commands/handlers/connection-handlers.js +57 -0
  22. package/dist/commands/handlers/connection-handlers.js.map +1 -0
  23. package/dist/commands/handlers/constants-handlers.d.ts.map +1 -0
  24. package/dist/commands/handlers/constants-handlers.js +85 -0
  25. package/dist/commands/handlers/constants-handlers.js.map +1 -0
  26. package/dist/commands/handlers/index.d.ts.map +1 -0
  27. package/dist/commands/handlers/pattern-handlers.d.ts.map +1 -0
  28. package/dist/commands/handlers/pattern-handlers.js +127 -0
  29. package/dist/commands/handlers/pattern-handlers.js.map +1 -0
  30. package/dist/commands/handlers/scan-handlers.d.ts.map +1 -0
  31. package/dist/commands/handlers/scan-handlers.js +74 -0
  32. package/dist/commands/handlers/scan-handlers.js.map +1 -0
  33. package/dist/commands/handlers/ui-handlers.d.ts.map +1 -0
  34. package/dist/commands/handlers/violation-handlers.d.ts.map +1 -0
  35. package/dist/commands/handlers/violation-handlers.js +75 -0
  36. package/dist/commands/handlers/violation-handlers.js.map +1 -0
  37. package/dist/commands/index.d.ts.map +1 -0
  38. package/dist/commands/middleware/connection-check-middleware.d.ts.map +1 -0
  39. package/dist/commands/middleware/index.d.ts.map +1 -0
  40. package/dist/commands/middleware/logging-middleware.d.ts.map +1 -0
  41. package/dist/commands/middleware/telemetry-middleware.d.ts.map +1 -0
  42. package/dist/config/config-manager.d.ts.map +1 -0
  43. package/dist/config/config-manager.js +182 -0
  44. package/dist/config/config-manager.js.map +1 -0
  45. package/dist/config/defaults.d.ts.map +1 -0
  46. package/dist/config/index.d.ts.map +1 -0
  47. package/dist/config/validator.d.ts.map +1 -0
  48. package/dist/config/validator.js +89 -0
  49. package/dist/config/validator.js.map +1 -0
  50. package/dist/extension.d.ts.map +1 -0
  51. package/dist/extension.js +51 -0
  52. package/dist/extension.js.map +1 -0
  53. package/dist/infrastructure/disposable-manager.d.ts.map +1 -0
  54. package/dist/infrastructure/disposable-manager.js +76 -0
  55. package/dist/infrastructure/disposable-manager.js.map +1 -0
  56. package/dist/infrastructure/index.d.ts.map +1 -0
  57. package/dist/infrastructure/logger.d.ts.map +1 -0
  58. package/dist/infrastructure/logger.js +82 -0
  59. package/dist/infrastructure/logger.js.map +1 -0
  60. package/dist/infrastructure/service-container.d.ts +68 -0
  61. package/dist/infrastructure/service-container.d.ts.map +1 -0
  62. package/dist/infrastructure/service-container.js +92 -0
  63. package/dist/infrastructure/service-container.js.map +1 -0
  64. package/dist/state/index.d.ts.map +1 -0
  65. package/dist/state/initial-state.d.ts.map +1 -0
  66. package/dist/state/selectors.d.ts.map +1 -0
  67. package/dist/state/state-manager.d.ts.map +1 -0
  68. package/dist/state/state-manager.js +166 -0
  69. package/dist/state/state-manager.js.map +1 -0
  70. package/dist/types/config-types.d.ts.map +1 -0
  71. package/dist/types/extension-types.d.ts +45 -0
  72. package/dist/types/extension-types.d.ts.map +1 -0
  73. package/dist/types/extension-types.js +5 -0
  74. package/dist/types/extension-types.js.map +1 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/lsp-types.d.ts.map +1 -0
  77. package/dist/types/state-types.d.ts.map +1 -0
  78. package/dist/ui/decorations/decoration-controller.d.ts.map +1 -0
  79. package/dist/ui/decorations/decoration-controller.js +196 -0
  80. package/dist/ui/decorations/decoration-controller.js.map +1 -0
  81. package/dist/ui/decorations/decoration-types.d.ts.map +1 -0
  82. package/dist/ui/decorations/index.d.ts.map +1 -0
  83. package/dist/ui/index.d.ts.map +1 -0
  84. package/dist/ui/notifications/index.d.ts.map +1 -0
  85. package/dist/ui/notifications/notification-service.d.ts.map +1 -0
  86. package/dist/ui/notifications/notification-service.js +103 -0
  87. package/dist/ui/notifications/notification-service.js.map +1 -0
  88. package/dist/ui/status-bar/index.d.ts.map +1 -0
  89. package/dist/ui/status-bar/status-bar-controller.d.ts.map +1 -0
  90. package/dist/ui/status-bar/status-bar-controller.js +111 -0
  91. package/dist/ui/status-bar/status-bar-controller.js.map +1 -0
  92. package/dist/ui/status-bar/status-bar-modes.d.ts.map +1 -0
  93. package/dist/ui/status-bar/status-bar-modes.js +112 -0
  94. package/dist/ui/status-bar/status-bar-modes.js.map +1 -0
  95. package/dist/views/constants-tree-provider.d.ts +111 -0
  96. package/dist/views/constants-tree-provider.d.ts.map +1 -0
  97. package/dist/views/constants-tree-provider.js +343 -0
  98. package/dist/views/constants-tree-provider.js.map +1 -0
  99. package/dist/views/files-tree-provider.d.ts +36 -0
  100. package/dist/views/files-tree-provider.d.ts.map +1 -0
  101. package/dist/views/files-tree-provider.js +95 -0
  102. package/dist/views/files-tree-provider.js.map +1 -0
  103. package/dist/views/index.d.ts.map +1 -0
  104. package/dist/views/patterns-tree-provider.d.ts.map +1 -0
  105. package/dist/views/violations-tree-provider.d.ts.map +1 -0
  106. package/dist/webview/index.d.ts.map +1 -0
  107. package/dist/webview/webview-manager.d.ts.map +1 -0
  108. package/package.json +1 -1
  109. package/src/activation/activation-controller.ts +13 -13
  110. package/src/client/connection-manager.ts +11 -9
  111. package/src/client/request-middleware.ts +6 -6
  112. package/src/commands/command-router.ts +7 -5
  113. package/src/commands/handlers/connection-handlers.ts +5 -5
  114. package/src/commands/handlers/constants-handlers.ts +13 -12
  115. package/src/commands/handlers/pattern-handlers.ts +3 -3
  116. package/src/commands/handlers/scan-handlers.ts +1 -1
  117. package/src/commands/handlers/violation-handlers.ts +6 -3
  118. package/src/config/config-manager.ts +11 -2
  119. package/src/config/validator.ts +13 -17
  120. package/src/extension.ts +2 -1
  121. package/src/infrastructure/disposable-manager.ts +2 -1
  122. package/src/infrastructure/logger.ts +3 -8
  123. package/src/infrastructure/service-container.ts +6 -7
  124. package/src/state/state-manager.ts +8 -11
  125. package/src/types/extension-types.ts +1 -1
  126. package/src/ui/decorations/decoration-controller.ts +4 -5
  127. package/src/ui/notifications/notification-service.ts +5 -5
  128. package/src/ui/status-bar/status-bar-controller.ts +3 -3
  129. package/src/ui/status-bar/status-bar-modes.ts +24 -9
  130. package/src/views/constants-tree-provider.ts +17 -19
  131. package/src/views/files-tree-provider.ts +0 -4
  132. package/tsconfig.tsbuildinfo +1 -1
@@ -149,7 +149,7 @@ export class ConnectionManager implements vscode.Disposable {
149
149
 
150
150
  // Handle client errors
151
151
  this.client.onDidChangeState((event: StateChangeEvent) => {
152
- this.logger.debug(`Client state changed: ${event.oldState} -> ${event.newState}`);
152
+ this.logger.debug(`Client state changed: ${String(event.oldState)} -> ${String(event.newState)}`);
153
153
  });
154
154
  }
155
155
 
@@ -168,7 +168,7 @@ export class ConnectionManager implements vscode.Disposable {
168
168
  await this.delay(100);
169
169
  }
170
170
 
171
- throw new Error(`Server initialization timed out after ${timeout}ms`);
171
+ throw new Error(`Server initialization timed out after ${String(timeout)}ms`);
172
172
  }
173
173
 
174
174
  private async handleConnectionError(error: unknown): Promise<void> {
@@ -183,7 +183,7 @@ export class ConnectionManager implements vscode.Disposable {
183
183
 
184
184
  if (this.restartCount >= CONNECTION_CONFIG.maxRestarts) {
185
185
  this.setState('failed');
186
- this.logger.error(`Max restart attempts (${CONNECTION_CONFIG.maxRestarts}) reached`);
186
+ this.logger.error(`Max restart attempts (${String(CONNECTION_CONFIG.maxRestarts)}) reached`);
187
187
  return;
188
188
  }
189
189
 
@@ -191,7 +191,7 @@ export class ConnectionManager implements vscode.Disposable {
191
191
  this.restartCount++;
192
192
 
193
193
  this.logger.info(
194
- `Reconnecting in ${delay}ms (attempt ${this.restartCount}/${CONNECTION_CONFIG.maxRestarts})`
194
+ `Reconnecting in ${String(delay)}ms (attempt ${String(this.restartCount)}/${String(CONNECTION_CONFIG.maxRestarts)})`
195
195
  );
196
196
 
197
197
  this.setState('reconnecting');
@@ -208,11 +208,13 @@ export class ConnectionManager implements vscode.Disposable {
208
208
  private startHealthCheck(): void {
209
209
  this.stopHealthCheck();
210
210
 
211
- this.healthCheckTimer = setInterval(async () => {
212
- if (!await this.isHealthy()) {
213
- this.logger.warn('Health check failed, reconnecting...');
214
- await this.reconnect();
215
- }
211
+ this.healthCheckTimer = setInterval(() => {
212
+ void this.isHealthy().then(healthy => {
213
+ if (!healthy) {
214
+ this.logger.warn('Health check failed, reconnecting...');
215
+ void this.reconnect();
216
+ }
217
+ });
216
218
  }, CONNECTION_CONFIG.healthCheckInterval);
217
219
  }
218
220
 
@@ -56,14 +56,14 @@ export class RequestMiddleware {
56
56
 
57
57
  if (attempt < opts.retries) {
58
58
  this.logger.warn(
59
- `Request ${method} failed (attempt ${attempt + 1}/${opts.retries + 1}): ${lastError.message}`
59
+ `Request ${method} failed (attempt ${String(attempt + 1)}/${String(opts.retries + 1)}): ${lastError.message}`
60
60
  );
61
61
  await this.delay(opts.retryDelay * (attempt + 1));
62
62
  }
63
63
  }
64
64
  }
65
65
 
66
- this.logger.error(`Request ${method} failed after ${opts.retries + 1} attempts`);
66
+ this.logger.error(`Request ${method} failed after ${String(opts.retries + 1)} attempts`);
67
67
  throw lastError;
68
68
  }
69
69
 
@@ -72,7 +72,7 @@ export class RequestMiddleware {
72
72
  */
73
73
  notify(method: string, params?: unknown): void {
74
74
  try {
75
- this.client.sendNotification(method, params);
75
+ void this.client.sendNotification(method, params);
76
76
  } catch (error) {
77
77
  this.logger.error(`Notification ${method} failed:`, error);
78
78
  }
@@ -85,7 +85,7 @@ export class RequestMiddleware {
85
85
  ): Promise<T> {
86
86
  return new Promise<T>((resolve, reject) => {
87
87
  const timer = setTimeout(() => {
88
- reject(new Error(`Request ${method} timed out after ${timeout}ms`));
88
+ reject(new Error(`Request ${method} timed out after ${String(timeout)}ms`));
89
89
  }, timeout);
90
90
 
91
91
  this.client
@@ -94,9 +94,9 @@ export class RequestMiddleware {
94
94
  clearTimeout(timer);
95
95
  resolve(result);
96
96
  })
97
- .catch((error) => {
97
+ .catch((error: unknown) => {
98
98
  clearTimeout(timer);
99
- reject(error);
99
+ reject(error instanceof Error ? error : new Error(String(error)));
100
100
  });
101
101
  });
102
102
  }
@@ -156,8 +156,10 @@ export class CommandRouter implements vscode.Disposable {
156
156
 
157
157
  const next = async (): Promise<void> => {
158
158
  if (index < this.middleware.length) {
159
- const mw = this.middleware[index++]!;
160
- await mw(ctx, next);
159
+ const mw = this.middleware[index++];
160
+ if (mw) {
161
+ await mw(ctx, next);
162
+ }
161
163
  } else {
162
164
  await handler(ctx);
163
165
  }
@@ -170,13 +172,13 @@ export class CommandRouter implements vscode.Disposable {
170
172
  const message = error instanceof Error ? error.message : String(error);
171
173
  this.logger.error(`Command ${command} failed:`, message);
172
174
 
173
- vscode.window
175
+ void vscode.window
174
176
  .showErrorMessage(`Drift: ${message}`, 'Retry', 'Show Logs')
175
177
  .then((action) => {
176
178
  if (action === 'Retry') {
177
- vscode.commands.executeCommand(command);
179
+ void vscode.commands.executeCommand(command);
178
180
  } else if (action === 'Show Logs') {
179
- vscode.commands.executeCommand('drift.showLogs');
181
+ void vscode.commands.executeCommand('drift.showLogs');
180
182
  }
181
183
  });
182
184
  }
@@ -44,10 +44,10 @@ export function createConnectionHandlers(
44
44
 
45
45
  const items = [
46
46
  `Connection: ${connection.status}`,
47
- `Server Version: ${connection.serverVersion || 'Unknown'}`,
48
- `Patterns: ${patterns.total}`,
49
- `Violations: ${violations.total}`,
50
- `Last Scan: ${workspace.lastScanTime ? new Date(workspace.lastScanTime).toLocaleString() : 'Never'}`,
47
+ `Server Version: ${connection.serverVersion ?? 'Unknown'}`,
48
+ `Patterns: ${String(patterns.total)}`,
49
+ `Violations: ${String(violations.total)}`,
50
+ `Last Scan: ${workspace.lastScanTime !== null ? new Date(workspace.lastScanTime).toLocaleString() : 'Never'}`,
51
51
  ];
52
52
 
53
53
  await notifications.info(items.join('\n'), [], { detail: 'Drift Status' });
@@ -61,7 +61,7 @@ export function createConnectionHandlers(
61
61
  const state = stateManager.getState();
62
62
  const error = state.connection.lastError;
63
63
 
64
- if (error) {
64
+ if (error !== null && error !== '') {
65
65
  await notifications.error(error, [
66
66
  { title: 'Retry', command: DRIFT_COMMANDS.reconnect },
67
67
  { title: 'Show Logs', command: 'drift.showLogs' },
@@ -18,7 +18,7 @@ export function createConstantsHandlers(
18
18
  /**
19
19
  * Show constants view by category
20
20
  */
21
- 'drift.showConstantsByCategory': async () => {
21
+ 'drift.showConstantsByCategory': async (): Promise<void> => {
22
22
  constantsProvider.setViewMode('category');
23
23
  await vscode.commands.executeCommand('drift.constantsView.focus');
24
24
  },
@@ -26,7 +26,7 @@ export function createConstantsHandlers(
26
26
  /**
27
27
  * Show constants view by language
28
28
  */
29
- 'drift.showConstantsByLanguage': async () => {
29
+ 'drift.showConstantsByLanguage': async (): Promise<void> => {
30
30
  constantsProvider.setViewMode('language');
31
31
  await vscode.commands.executeCommand('drift.constantsView.focus');
32
32
  },
@@ -34,7 +34,7 @@ export function createConstantsHandlers(
34
34
  /**
35
35
  * Show constant issues
36
36
  */
37
- 'drift.showConstantIssues': async () => {
37
+ 'drift.showConstantIssues': async (): Promise<void> => {
38
38
  constantsProvider.setViewMode('issues');
39
39
  await vscode.commands.executeCommand('drift.constantsView.focus');
40
40
  },
@@ -42,7 +42,7 @@ export function createConstantsHandlers(
42
42
  /**
43
43
  * Go to constant definition
44
44
  */
45
- 'drift.goToConstant': async (file: unknown, line: unknown) => {
45
+ 'drift.goToConstant': async (file: unknown, line: unknown): Promise<void> => {
46
46
  if (typeof file !== 'string' || typeof line !== 'number') {
47
47
  return;
48
48
  }
@@ -58,30 +58,31 @@ export function createConstantsHandlers(
58
58
  new vscode.Range(position, position),
59
59
  vscode.TextEditorRevealType.InCenter
60
60
  );
61
- } catch (error) {
62
- vscode.window.showErrorMessage(`Failed to open file: ${file}`);
61
+ } catch {
62
+ void vscode.window.showErrorMessage(`Failed to open file: ${file}`);
63
63
  }
64
64
  },
65
65
 
66
66
  /**
67
67
  * Find constant usages
68
68
  */
69
- 'drift.findConstantUsages': async (constantName: unknown) => {
70
- if (typeof constantName !== 'string') {
69
+ 'drift.findConstantUsages': async (constantName: unknown): Promise<void> => {
70
+ let searchName = constantName;
71
+ if (typeof searchName !== 'string' || searchName === '') {
71
72
  // If no constant name provided, prompt for one
72
73
  const input = await vscode.window.showInputBox({
73
74
  prompt: 'Enter constant name to search for',
74
75
  placeHolder: 'CONSTANT_NAME',
75
76
  });
76
- if (!input) {
77
+ if (input === null || input === '') {
77
78
  return;
78
79
  }
79
- constantName = input;
80
+ searchName = input;
80
81
  }
81
82
 
82
83
  // Use VSCode's built-in search
83
84
  await vscode.commands.executeCommand('workbench.action.findInFiles', {
84
- query: constantName,
85
+ query: searchName,
85
86
  isRegex: false,
86
87
  isCaseSensitive: true,
87
88
  matchWholeWord: true,
@@ -91,7 +92,7 @@ export function createConstantsHandlers(
91
92
  /**
92
93
  * Show constants overview
93
94
  */
94
- 'drift.showConstants': async () => {
95
+ 'drift.showConstants': async (): Promise<void> => {
95
96
  constantsProvider.setViewMode('category');
96
97
  await vscode.commands.executeCommand('drift.constantsView.focus');
97
98
  },
@@ -48,7 +48,7 @@ export function createPatternHandlers(
48
48
 
49
49
  const patternId = ctx.args[0] as string | undefined;
50
50
 
51
- if (!patternId) {
51
+ if (patternId === null || patternId === '') {
52
52
  // Show pattern picker
53
53
  const patterns = await client.sendRequest<Array<{ id: string; name: string }>>(
54
54
  'drift/patterns/list',
@@ -90,7 +90,7 @@ export function createPatternHandlers(
90
90
 
91
91
  const patternId = ctx.args[0] as string | undefined;
92
92
 
93
- if (!patternId) {
93
+ if (patternId === null || patternId === '') {
94
94
  // Show pattern picker
95
95
  const patterns = await client.sendRequest<Array<{ id: string; name: string }>>(
96
96
  'drift/patterns/list',
@@ -133,7 +133,7 @@ export function createPatternHandlers(
133
133
  const patternId = ctx.args[0] as string | undefined;
134
134
  const violationId = ctx.args[1] as string | undefined;
135
135
 
136
- if (!patternId) {
136
+ if (patternId === null || patternId === '') {
137
137
  await notifications.warning('No pattern specified for variant creation.');
138
138
  return;
139
139
  }
@@ -67,7 +67,7 @@ export function createScanHandlers(
67
67
  });
68
68
 
69
69
  await notifications.info(
70
- `Scan complete: ${result.patterns} patterns, ${result.violations} violations`
70
+ `Scan complete: ${String(result.patterns)} patterns, ${String(result.violations)} violations`
71
71
  );
72
72
  } catch (error) {
73
73
  stateManager.update(draft => {
@@ -43,7 +43,7 @@ export function createViolationHandlers(
43
43
  const uri = ctx.args[1] as string | undefined;
44
44
  const line = ctx.args[2] as number | undefined;
45
45
 
46
- if (!violationId || !uri || line === undefined) {
46
+ if (violationId === null || violationId === '' || uri === null || uri === '' || line === undefined) {
47
47
  // Try to get from current editor position
48
48
  const editor = vscode.window.activeTextEditor;
49
49
  if (!editor) {
@@ -63,8 +63,11 @@ export function createViolationHandlers(
63
63
  }
64
64
 
65
65
  // Extract violation ID from diagnostic data
66
- const data = (driftDiagnostic as any).data;
67
- if (!data?.violationId) {
66
+ interface DiagnosticData {
67
+ violationId?: string;
68
+ }
69
+ const data = (driftDiagnostic as vscode.Diagnostic & { data?: DiagnosticData }).data;
70
+ if (data?.violationId === null || data?.violationId === undefined) {
68
71
  await notifications.warning('Cannot identify violation.');
69
72
  return;
70
73
  }
@@ -139,11 +139,20 @@ export class ConfigManager implements vscode.Disposable {
139
139
  try {
140
140
  if (fs.existsSync(configPath)) {
141
141
  const content = fs.readFileSync(configPath, 'utf-8');
142
- const parsed = JSON.parse(content);
142
+ interface ParsedTeamConfig {
143
+ enforceApproved?: boolean;
144
+ requiredCategories?: string[];
145
+ customRules?: Array<string | { id: string; severity: string }>;
146
+ }
147
+ const parsed: ParsedTeamConfig = JSON.parse(content) as ParsedTeamConfig;
148
+ // Map customRules objects to just their IDs if they're objects
149
+ const customRules = parsed.customRules
150
+ ? parsed.customRules.map((rule) => (typeof rule === 'string' ? rule : rule.id))
151
+ : DEFAULT_CONFIG.team.customRules;
143
152
  return {
144
153
  enforceApproved: parsed.enforceApproved ?? DEFAULT_CONFIG.team.enforceApproved,
145
154
  requiredCategories: parsed.requiredCategories ?? DEFAULT_CONFIG.team.requiredCategories,
146
- customRules: parsed.customRules ?? DEFAULT_CONFIG.team.customRules,
155
+ customRules,
147
156
  };
148
157
  }
149
158
  } catch (error) {
@@ -36,39 +36,35 @@ export function validateConfig(config: Partial<DriftConfig>): ValidationResult {
36
36
  const errors: string[] = [];
37
37
 
38
38
  // Validate server config
39
- if (config.server) {
40
- if (config.server.trace && !VALID_TRACE_LEVELS.includes(config.server.trace)) {
41
- errors.push(`Invalid trace level: ${config.server.trace}`);
42
- }
39
+ if (config.server?.trace !== undefined && !VALID_TRACE_LEVELS.includes(config.server.trace)) {
40
+ errors.push(`Invalid trace level: ${config.server.trace}`);
43
41
  }
44
42
 
45
43
  // Validate scan config
46
- if (config.scan) {
44
+ if (config.scan !== undefined) {
47
45
  if (typeof config.scan.debounceMs === 'number' && config.scan.debounceMs < 0) {
48
46
  errors.push('debounceMs must be non-negative');
49
47
  }
50
- if (config.scan.excludePatterns && !Array.isArray(config.scan.excludePatterns)) {
48
+ if (config.scan.excludePatterns !== undefined && !Array.isArray(config.scan.excludePatterns)) {
51
49
  errors.push('excludePatterns must be an array');
52
50
  }
53
51
  }
54
52
 
55
53
  // Validate display config
56
- if (config.display) {
57
- if (config.display.severityFilter) {
58
- for (const severity of config.display.severityFilter) {
59
- if (!VALID_SEVERITIES.includes(severity)) {
60
- errors.push(`Invalid severity: ${severity}`);
61
- }
54
+ if (config.display?.severityFilter !== undefined) {
55
+ for (const severity of config.display.severityFilter) {
56
+ if (!VALID_SEVERITIES.includes(severity)) {
57
+ errors.push(`Invalid severity: ${severity}`);
62
58
  }
63
59
  }
64
60
  }
65
61
 
66
62
  // Validate AI config
67
- if (config.ai) {
68
- if (config.ai.provider && !VALID_PROVIDERS.includes(config.ai.provider)) {
63
+ if (config.ai !== undefined) {
64
+ if (config.ai.provider !== undefined && !VALID_PROVIDERS.includes(config.ai.provider)) {
69
65
  errors.push(`Invalid AI provider: ${config.ai.provider}`);
70
66
  }
71
- if (config.ai.enabled && config.ai.provider === 'none') {
67
+ if (config.ai.enabled === true && config.ai.provider === 'none') {
72
68
  errors.push('AI enabled but provider is "none"');
73
69
  }
74
70
  }
@@ -99,14 +95,14 @@ export function validateConfigValue(
99
95
  if (key === 'severityFilter' && Array.isArray(value)) {
100
96
  for (const v of value) {
101
97
  if (!VALID_SEVERITIES.includes(v as Severity)) {
102
- errors.push(`Invalid severity: ${v}`);
98
+ errors.push(`Invalid severity: ${String(v)}`);
103
99
  }
104
100
  }
105
101
  }
106
102
  break;
107
103
  case 'ai':
108
104
  if (key === 'provider' && !VALID_PROVIDERS.includes(value as AIProvider)) {
109
- errors.push(`Invalid AI provider: ${value}`);
105
+ errors.push(`Invalid AI provider: ${String(value)}`);
110
106
  }
111
107
  break;
112
108
  }
package/src/extension.ts CHANGED
@@ -15,7 +15,8 @@ import { createActivationController, type ActivationController } from './activat
15
15
  */
16
16
  export function getVersion(): string {
17
17
  const extension = vscode.extensions.getExtension('driftdetect.driftdetect-vscode');
18
- return extension?.packageJSON?.version ?? '0.0.0';
18
+ const packageJSON = extension?.packageJSON as { version?: string } | undefined;
19
+ return packageJSON?.version ?? '0.0.0';
19
20
  }
20
21
 
21
22
  // For backwards compatibility
@@ -59,7 +59,8 @@ export class DisposableManager implements IDisposableManager, vscode.Disposable
59
59
  try {
60
60
  disposable?.dispose();
61
61
  } catch (error) {
62
- console.error('[Drift] Error disposing resource:', error);
62
+ // Log error but continue disposing other resources
63
+ void error;
63
64
  }
64
65
  }
65
66
  }
@@ -76,13 +76,13 @@ export class Logger implements ILogger {
76
76
  const argsStr = args
77
77
  .map(arg => {
78
78
  if (arg instanceof Error) {
79
- return `${arg.message}\n${arg.stack}`;
79
+ return `${arg.message}\n${arg.stack ?? ''}`;
80
80
  }
81
- if (typeof arg === 'object') {
81
+ if (typeof arg === 'object' && arg !== null) {
82
82
  try {
83
83
  return JSON.stringify(arg, null, 2);
84
84
  } catch {
85
- return String(arg);
85
+ return '[Object]';
86
86
  }
87
87
  }
88
88
  return String(arg);
@@ -92,11 +92,6 @@ export class Logger implements ILogger {
92
92
  }
93
93
 
94
94
  this.channel.appendLine(formattedMessage);
95
-
96
- // Also log errors to console for debugging
97
- if (level === 'error') {
98
- console.error(`[Drift] ${message}`, ...args);
99
- }
100
95
  }
101
96
  }
102
97
 
@@ -29,19 +29,19 @@ export class ServiceContainer implements IServiceContainer {
29
29
  /**
30
30
  * Register a service instance directly
31
31
  */
32
- register<T>(key: string, instance: T): void {
32
+ register(key: string, instance: unknown): void {
33
33
  this.instances.set(key, instance);
34
34
  }
35
35
 
36
36
  /**
37
37
  * Register a service factory for lazy instantiation
38
38
  */
39
- registerFactory<T>(
39
+ registerFactory(
40
40
  key: string,
41
- factory: ServiceFactory<T>,
41
+ factory: ServiceFactory<unknown>,
42
42
  options: ServiceOptions = { singleton: true }
43
43
  ): void {
44
- this.factories.set(key, factory as ServiceFactory<unknown>);
44
+ this.factories.set(key, factory);
45
45
  this.options.set(key, options);
46
46
  }
47
47
 
@@ -83,11 +83,10 @@ export class ServiceContainer implements IServiceContainer {
83
83
  * Try to get a service, returning undefined if not found
84
84
  */
85
85
  tryGet<T>(key: string): T | undefined {
86
- try {
86
+ if (this.has(key)) {
87
87
  return this.get<T>(key);
88
- } catch {
89
- return undefined;
90
88
  }
89
+ return undefined;
91
90
  }
92
91
 
93
92
  /**
@@ -87,7 +87,7 @@ export class StateManager implements vscode.Disposable {
87
87
  this.listeners.add(listener);
88
88
 
89
89
  return {
90
- dispose: () => {
90
+ dispose: (): void => {
91
91
  this.listeners.delete(listener);
92
92
  },
93
93
  };
@@ -99,7 +99,7 @@ export class StateManager implements vscode.Disposable {
99
99
  subscribeAll(callback: (state: ExtensionState) => void): vscode.Disposable {
100
100
  this.listeners.add(callback);
101
101
  return {
102
- dispose: () => {
102
+ dispose: (): void => {
103
103
  this.listeners.delete(callback);
104
104
  },
105
105
  };
@@ -130,8 +130,8 @@ export class StateManager implements vscode.Disposable {
130
130
  for (const listener of this.listeners) {
131
131
  try {
132
132
  listener(this.state);
133
- } catch (error) {
134
- console.error('[Drift] State listener error:', error);
133
+ } catch {
134
+ // Listener error, continue with others
135
135
  }
136
136
  }
137
137
  }
@@ -141,7 +141,7 @@ export class StateManager implements vscode.Disposable {
141
141
 
142
142
  try {
143
143
  const persisted = this.context.globalState.get<Partial<ExtensionState>>(PERSISTENCE_KEY);
144
- if (persisted) {
144
+ if (persisted?.preferences !== undefined) {
145
145
  // Only restore preferences, not transient state
146
146
  return {
147
147
  ...initial,
@@ -151,8 +151,8 @@ export class StateManager implements vscode.Disposable {
151
151
  },
152
152
  };
153
153
  }
154
- } catch (error) {
155
- console.error('[Drift] Failed to load persisted state:', error);
154
+ } catch {
155
+ // Failed to load persisted state, use initial
156
156
  }
157
157
 
158
158
  return initial;
@@ -164,10 +164,7 @@ export class StateManager implements vscode.Disposable {
164
164
  preferences: this.state.preferences,
165
165
  };
166
166
 
167
- this.context.globalState.update(PERSISTENCE_KEY, toPersist).then(
168
- () => {},
169
- (error) => { console.error('[Drift] Failed to persist state:', error); }
170
- );
167
+ void this.context.globalState.update(PERSISTENCE_KEY, toPersist);
171
168
  }
172
169
 
173
170
  private shallowEqual(a: unknown, b: unknown): boolean {
@@ -53,6 +53,6 @@ export interface DisposableManager {
53
53
  */
54
54
  export interface ServiceContainer {
55
55
  get<T>(key: string): T;
56
- register<T>(key: string, instance: T): void;
56
+ register(key: string, instance: unknown): void;
57
57
  has(key: string): boolean;
58
58
  }
@@ -33,8 +33,6 @@ export class DecorationController implements vscode.Disposable {
33
33
  * Update decorations for the active editor
34
34
  */
35
35
  updateDecorations(editor: vscode.TextEditor): void {
36
- if (!editor) {return;}
37
-
38
36
  const uri = editor.document.uri;
39
37
  const diagnostics = vscode.languages.getDiagnostics(uri);
40
38
 
@@ -187,7 +185,7 @@ export class DecorationController implements vscode.Disposable {
187
185
 
188
186
  for (const d of diagnostics) {
189
187
  const severity = this.diagnosticSeverityToString(d.severity);
190
- const group = groups.get(severity) || [];
188
+ const group = groups.get(severity) ?? [];
191
189
  group.push(d);
192
190
  groups.set(severity, group);
193
191
  }
@@ -216,8 +214,9 @@ export class DecorationController implements vscode.Disposable {
216
214
  const icon = this.getSeverityIcon(diagnostic.severity);
217
215
  md.appendMarkdown(`${icon} **${diagnostic.message}**\n\n`);
218
216
 
219
- if (diagnostic.code) {
220
- md.appendMarkdown(`Pattern: \`${diagnostic.code}\`\n\n`);
217
+ if (diagnostic.code !== null) {
218
+ const codeStr = typeof diagnostic.code === 'object' ? String(diagnostic.code.value) : String(diagnostic.code);
219
+ md.appendMarkdown(`Pattern: \`${codeStr}\`\n\n`);
221
220
  }
222
221
 
223
222
  md.appendMarkdown(`---\n\n`);
@@ -97,7 +97,7 @@ export class NotificationService {
97
97
  const pickOptions: vscode.QuickPickOptions = {
98
98
  ...options,
99
99
  };
100
- if (options.title) {
100
+ if (options.title !== null && options.title !== '') {
101
101
  pickOptions.title = `Drift: ${options.title}`;
102
102
  }
103
103
  return vscode.window.showQuickPick(items, pickOptions);
@@ -110,7 +110,7 @@ export class NotificationService {
110
110
  const inputOptions: vscode.InputBoxOptions = {
111
111
  ...options,
112
112
  };
113
- if (options.title) {
113
+ if (options.title !== null && options.title !== '') {
114
114
  inputOptions.title = `Drift: ${options.title}`;
115
115
  }
116
116
  return vscode.window.showInputBox(inputOptions);
@@ -134,7 +134,7 @@ export class NotificationService {
134
134
  if (options.modal !== undefined) {
135
135
  messageOptions.modal = options.modal;
136
136
  }
137
- if (options.detail !== undefined) {
137
+ if (options.detail !== null && options.detail !== '' && options.detail !== undefined) {
138
138
  messageOptions.detail = options.detail;
139
139
  }
140
140
 
@@ -144,13 +144,13 @@ export class NotificationService {
144
144
  ...actionTitles
145
145
  );
146
146
 
147
- if (selected) {
147
+ if (selected !== null && selected !== '') {
148
148
  const action = actions.find(a => a.title === selected);
149
149
  if (action) {
150
150
  if (action.callback) {
151
151
  await action.callback();
152
152
  } else if (action.command) {
153
- await vscode.commands.executeCommand(action.command, ...(action.args || []));
153
+ await vscode.commands.executeCommand(action.command, ...(action.args ?? []));
154
154
  }
155
155
  }
156
156
  }
@@ -89,15 +89,15 @@ export class StatusBarController implements vscode.Disposable {
89
89
  // Add stats if connected
90
90
  if (state.connection.status === 'connected') {
91
91
  md.appendMarkdown(`---\n\n`);
92
- md.appendMarkdown(`**Patterns:** ${state.patterns.total}\n\n`);
93
- md.appendMarkdown(`**Violations:** ${state.violations.total}\n\n`);
92
+ md.appendMarkdown(`**Patterns:** ${String(state.patterns.total)}\n\n`);
93
+ md.appendMarkdown(`**Violations:** ${String(state.violations.total)}\n\n`);
94
94
 
95
95
  if (state.violations.total > 0) {
96
96
  md.appendMarkdown(`\n`);
97
97
  for (const [severity, count] of Object.entries(state.violations.bySeverity)) {
98
98
  if (count > 0) {
99
99
  const icon = this.getSeverityIcon(severity);
100
- md.appendMarkdown(`- ${icon} ${severity}: ${count}\n`);
100
+ md.appendMarkdown(`- ${icon} ${severity}: ${String(count)}\n`);
101
101
  }
102
102
  }
103
103
  }