Resolve frontend warnings (vibe-kanban) (#1316)
* ## ✅ Batch 1 Complete Successfully fixed all 6 warnings in batch 1 (message boundaries & streams): ### Changes made: **[bridge.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/src/vscode/bridge.ts)** - 5 fixes: - Replaced `(window as any).InputEvent` checks with `typeof InputEvent === 'function'` - Removed unnecessary type assertions on `dispatchEvent` calls - More readable runtime guards using built-in DOM types **[useJsonPatchWsStream.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/src/hooks/useJsonPatchWsStream.ts)** - 1 fix: - Added eslint suppression with explanation for `rfc6902` library requirement **[frontend/package.json](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/package.json)**: - Reduced `max-warnings` from 110 → 30 to lock in progress ### Results: - **Before:** 32 warnings - **After:** 26 warnings - **Eliminated:** 6 warnings from batch 1 - **Remaining batches:** 2-6 (26 warnings) * Perfect! ✅ The solution works without any `eslint-disable` comments. ## What we changed: 1. **Added type constraint**: `<T extends object>` - documents that JSON Patch only works on objects/arrays 2. **Used local variable narrowing**: `const current = dataRef.current` narrows `T | undefined` to `T` 3. **Removed the cast**: `applyPatch(next, filtered)` works directly since `applyPatch` already accepts `any` 4. **Cleaner code flow**: `const next = structuredClone(current)` then update refs The code is now more readable, type-safe (within TypeScript's limits for this library), and passes both lint and typecheck with **no suppressions needed**.
This commit is contained in:
committed by
GitHub
parent
9d8c0b286f
commit
1dae217f1a
@@ -8,7 +8,7 @@
|
||||
"build": "tsc && vite build",
|
||||
"check": "tsc --noEmit",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 110",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 30",
|
||||
"lint:fix": "eslint . --ext ts,tsx --fix",
|
||||
"lint:i18n": "LINT_I18N=true eslint . --ext ts,tsx --max-warnings 0",
|
||||
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
||||
|
||||
@@ -26,7 +26,7 @@ interface UseJsonPatchStreamResult<T> {
|
||||
/**
|
||||
* Generic hook for consuming WebSocket streams that send JSON messages with patches
|
||||
*/
|
||||
export const useJsonPatchWsStream = <T>(
|
||||
export const useJsonPatchWsStream = <T extends object>(
|
||||
endpoint: string | undefined,
|
||||
enabled: boolean,
|
||||
initialData: () => T,
|
||||
@@ -117,16 +117,17 @@ export const useJsonPatchWsStream = <T>(
|
||||
? deduplicatePatches(patches)
|
||||
: patches;
|
||||
|
||||
if (!filtered.length || !dataRef.current) return;
|
||||
const current = dataRef.current;
|
||||
if (!filtered.length || !current) return;
|
||||
|
||||
// Deep clone the current state before mutating it
|
||||
dataRef.current = structuredClone(dataRef.current);
|
||||
const next = structuredClone(current);
|
||||
|
||||
// Apply patch (mutates the clone in place)
|
||||
applyPatch(dataRef.current as any, filtered);
|
||||
applyPatch(next, filtered);
|
||||
|
||||
// React re-render: dataRef.current is already a new object
|
||||
setData(dataRef.current);
|
||||
dataRef.current = next;
|
||||
setData(next);
|
||||
}
|
||||
|
||||
// Handle finished messages ({finished: true})
|
||||
|
||||
@@ -152,15 +152,15 @@ function cutFromInput(el: HTMLInputElement | HTMLTextAreaElement) {
|
||||
el.value = before + after;
|
||||
el.setSelectionRange(start, start);
|
||||
}
|
||||
const ie =
|
||||
typeof (window as any).InputEvent !== 'undefined'
|
||||
? new (window as any).InputEvent('input', {
|
||||
const ie: Event =
|
||||
typeof InputEvent === 'function'
|
||||
? new InputEvent('input', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
inputType: 'deleteByCut',
|
||||
})
|
||||
: new Event('input', { bubbles: true });
|
||||
el.dispatchEvent(ie as Event);
|
||||
el.dispatchEvent(ie);
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
@@ -182,16 +182,16 @@ function pasteIntoInput(
|
||||
el.setSelectionRange(caret, caret);
|
||||
}
|
||||
el.focus();
|
||||
const ie =
|
||||
typeof (window as any).InputEvent !== 'undefined'
|
||||
? new (window as any).InputEvent('input', {
|
||||
const ie: Event =
|
||||
typeof InputEvent === 'function'
|
||||
? new InputEvent('input', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
inputType: 'insertFromPaste',
|
||||
data: text,
|
||||
})
|
||||
: new Event('input', { bubbles: true });
|
||||
el.dispatchEvent(ie as Event);
|
||||
el.dispatchEvent(ie);
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ function insertTextAtCaretGeneric(text: string) {
|
||||
} else {
|
||||
try {
|
||||
document.execCommand('insertText', false, text);
|
||||
(el as any).dispatchEvent?.(new Event('input', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
} catch {
|
||||
(el as HTMLElement).innerText += text;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user