Skip to content

Commit f12755c

Browse files
marcstraubeclaude
andauthored
chore: replace blanket no-unsafe-* ESLint disables with targeted suppressions (#60)
## Summary - Remove 5 blanket `@typescript-eslint/no-unsafe-*` rule disables from `eslint.config.js` - Fix 6 of 9 violations structurally via better type annotations - Add 3 targeted per-line suppressions for intentional CSP detection code ### Structural fixes - `broadcast/BroadcastManager.ts`: type `event.data` as `unknown` (type guard validates) - `request/RequestValidation.ts`: add `readonly string[]` annotation to prevent `Array.isArray` `any[]` inference ### Targeted suppressions (DOM/CSP interop) - `csp/CspUtils.ts`: dynamic `window` property access + `Function` constructor call for CSP detection Closes #3 ## Test plan - [x] ESLint passes with 0 errors/warnings - [x] TypeScript strict mode passes - [x] All 4155 tests pass with 100% line coverage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b8e1a6c commit f12755c

4 files changed

Lines changed: 7 additions & 11 deletions

File tree

eslint.config.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,6 @@ export default [
107107
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
108108
'@typescript-eslint/prefer-optional-chain': 'warn',
109109

110-
// Relax unsafe rules for browser DOM APIs
111-
'@typescript-eslint/no-unsafe-assignment': 'off',
112-
'@typescript-eslint/no-unsafe-member-access': 'off',
113-
'@typescript-eslint/no-unsafe-argument': 'off',
114-
'@typescript-eslint/no-unsafe-call': 'off',
115-
'@typescript-eslint/no-unsafe-return': 'off',
116-
117110
// Code quality rules
118111
'no-console': ['warn', { allow: ['warn', 'error'] }],
119112
'prefer-const': 'error',

src/broadcast/BroadcastManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export const BroadcastManager = {
207207

208208
// Message handler
209209
channel.onmessage = (event: MessageEvent): void => {
210-
const data = event.data;
210+
const data: unknown = event.data;
211211

212212
if (!isValidBroadcastMessage(data)) {
213213
return;

src/csp/CspUtils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ export const CspUtils = {
179179
document.head.removeChild(script);
180180

181181
// Check if the script executed
182-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic window property access for CSP test
182+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access -- Dynamic window property access for CSP inline-script test
183183
const result = (window as any)[testKey] === true;
184-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Cleanup test property
184+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access -- Cleanup dynamic test property from window
185185
delete (window as any)[testKey];
186186

187187
cspCache.set('inlineScriptAllowed', result);
@@ -205,6 +205,7 @@ export const CspUtils = {
205205
try {
206206
// eslint-disable-next-line @typescript-eslint/no-implied-eval -- Intentionally testing if CSP allows Function constructor
207207
const fn = new Function('return true');
208+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- Function constructor returns untyped callable; intentional for CSP eval test
208209
const result = fn() === true;
209210
cspCache.set('evalAllowed', result);
210211
return result;

src/request/RequestValidation.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ export function validateContentType(
249249
const rawContentType = responseHeaders.get('content-type');
250250
const actualBase = parseBaseContentType(rawContentType);
251251

252-
const expected = Array.isArray(expectedContentType) ? expectedContentType : [expectedContentType];
252+
const expected: readonly string[] = Array.isArray(expectedContentType)
253+
? expectedContentType
254+
: [expectedContentType];
253255

254256
const normalizedExpected = expected.map((t) => t.toLowerCase().trim());
255257

0 commit comments

Comments
 (0)