From ad12bf84cd7894ee99bd19e881ccebe23c1941e7 Mon Sep 17 00:00:00 2001 From: John London Date: Fri, 1 May 2026 23:35:24 -0500 Subject: [PATCH] fix(vscode-companion): align package eslint config with root and style cleanup (#3782) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(vscode-companion): fix ESLint curly and eqeqeq violations Fix pre-existing lint errors in vscode-ide-companion that cause all 8 CI test matrix jobs to fail (ubuntu/macos/windows × Node 20/22/24). - extension.ts:221 — add braces to single-line if (curly rule) - WebViewProvider.ts:1740,1742 — add braces to single-line if (curly) - App.tsx:179 — replace == with === (eqeqeq) and add braces (curly) - App.tsx:215 — add braces to single-line if (curly rule) - App.tsx:1210 — add braces to single-line if return (curly rule) - App.tsx:1241 — add braces to single-line if continue (curly rule) - App.tsx:1258 — add braces to single-line if continue (curly rule) Co-Authored-By: Claude Opus 4.7 * fix(vscode-companion): revert === null to == null and align package eslint config - Revert `child === null` back to `child == null` in App.tsx:179. The == null idiom catches both null and undefined, which is the defensive pattern needed here. A future case that forgets to assign `child` would let undefined slip through with === null, desyncing childIndexMap from the rendered DOM and breaking findMessageIndex. - Align package-level eslint eqeqeq with root config by adding { null: 'ignore' }, so == null is allowed as a warning-level rule matching the project-wide ESLint policy. The curly brace additions from the prior commit are retained as style improvements (curly: 'warn' in the package config), though they were not CI-blocking violations — CI runs from root which uses curly: ['error', 'multi-line'] and permits single-line if statements. Co-Authored-By: Claude Opus 4.7 --------- Co-authored-by: Claude Opus 4.7 --- .../vscode-ide-companion/eslint.config.mjs | 2 +- .../vscode-ide-companion/src/extension.ts | 4 +++- .../vscode-ide-companion/src/webview/App.tsx | 20 ++++++++++++++----- .../src/webview/providers/WebViewProvider.ts | 8 ++++++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/vscode-ide-companion/eslint.config.mjs b/packages/vscode-ide-companion/eslint.config.mjs index 4b444a9b2..80945e52c 100644 --- a/packages/vscode-ide-companion/eslint.config.mjs +++ b/packages/vscode-ide-companion/eslint.config.mjs @@ -67,7 +67,7 @@ export default [ ], curly: 'warn', - eqeqeq: 'warn', + eqeqeq: ['warn', 'always', { null: 'ignore' }], 'no-throw-literal': 'warn', semi: 'warn', }, diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 2bfb1a1f2..4629ae932 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -218,7 +218,9 @@ export async function activate(context: vscode.ExtensionContext) { const sendCopyToActive = (action: string) => { for (const provider of chatProviderRegistry?.getPermissionAwareProviders() ?? []) { - if (provider.sendCopyCommand(action)) break; + if (provider.sendCopyCommand(action)) { + break; + } } }; context.subscriptions.push( diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 7800b33fd..167800cd2 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -177,7 +177,9 @@ const MessageList = React.memo( } // No wrapper div — message components render directly as children // of the scroll container, preserving the original CSS layout. - if (child == null) return null; + if (child == null) { + return null; + } mapping.push(index); return {child}; }); @@ -213,7 +215,9 @@ function findMessageIndex( while (directChild && directChild.parentElement !== container) { directChild = directChild.parentElement; } - if (!directChild) return -1; + if (!directChild) { + return -1; + } // Find DOM child position among container's children const children = container.children; @@ -1211,7 +1215,9 @@ export const App: React.FC = () => { useEffect(() => { const handler = (event: MessageEvent) => { const message = event.data; - if (message?.type !== 'copyCommand') return; + if (message?.type !== 'copyCommand') { + return; + } const { action } = message.data as { action: string }; @@ -1242,7 +1248,9 @@ export const App: React.FC = () => { msg.kind === 'image' && msg.imagePath ? `![image](${msg.imagePath})` : (msg.content || '').trim(); - if (!content) continue; + if (!content) { + continue; + } if (msg.role === 'user') { parts.push(`**User:** ${content}`); } else if (msg.role === 'thinking') { @@ -1255,7 +1263,9 @@ export const App: React.FC = () => { item.type === 'in-progress-tool-call' ) { const tc = item.data as ToolCallData; - if (!shouldShowToolCall(tc.kind)) continue; + if (!shouldShowToolCall(tc.kind)) { + continue; + } const text = formatToolCallForCopy(tc, true); if (text) { parts.push(`**[Tool: ${tc.kind}]**\n\n${text}`); diff --git a/packages/vscode-ide-companion/src/webview/providers/WebViewProvider.ts b/packages/vscode-ide-companion/src/webview/providers/WebViewProvider.ts index 222db5844..69ed94c96 100644 --- a/packages/vscode-ide-companion/src/webview/providers/WebViewProvider.ts +++ b/packages/vscode-ide-companion/src/webview/providers/WebViewProvider.ts @@ -1737,9 +1737,13 @@ export class WebViewProvider { * The webview resolves the content and posts back a 'copyToClipboard' message. */ sendCopyCommand(action: string): boolean { - if (WebViewProvider.lastContextMenuProvider !== this) return false; + if (WebViewProvider.lastContextMenuProvider !== this) { + return false; + } const webview = this.getActiveWebview(); - if (!webview) return false; + if (!webview) { + return false; + } webview.postMessage({ type: 'copyCommand', data: { action } }); return true; }