mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-20 22:03:48 +00:00
fix(lint): close type-check gaps in client scripts and tooling
Remove unused import flagged by CI lint, then harden the toolchain so such issues are caught before push: - lint-staged now also matches .tsx/.jsx (previously .tsx files skipped the pre-commit eslint pass, which is how the error reached CI) - eslint ignores generated client bundles (gitignored, not worth linting) - typecheck now also runs the client tsconfig; the hand-written browser source was excluded from the root config and never type-checked - consolidate the window global augmentations (showToast, parseJsonResponseOrThrow) into a single client globals.d.ts; the inline declare-global blocks failed (non-module files) and masked real errors Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@ import prettier from "eslint-config-prettier";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist/", "coverage/"] },
|
||||
{ ignores: ["dist/", "coverage/", "src/scripts/generated/"] },
|
||||
...tseslint.configs.recommended,
|
||||
prettier,
|
||||
{
|
||||
|
||||
+3
-2
@@ -16,11 +16,12 @@
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typecheck": "tsc --noEmit && npm run typecheck:client",
|
||||
"typecheck:client": "tsc -p src/scripts/client/tsconfig.json --noEmit",
|
||||
"prepare": "husky && npm run build:client"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,js}": [
|
||||
"*.{ts,tsx,js,jsx}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
updateFeedInList,
|
||||
removeFeedFromList,
|
||||
removeFeedsFromListBulk,
|
||||
deleteKeysWithConcurrency,
|
||||
purgeFeedKeysStep,
|
||||
} from "./helpers";
|
||||
|
||||
@@ -45,7 +44,12 @@ const updateFeedSchema = z.object({
|
||||
});
|
||||
|
||||
const senderFilterSchema = z.object({
|
||||
action: z.enum(["allow_sender", "allow_domain", "block_sender", "block_domain"]),
|
||||
action: z.enum([
|
||||
"allow_sender",
|
||||
"allow_domain",
|
||||
"block_sender",
|
||||
"block_domain",
|
||||
]),
|
||||
value: z.string().min(1),
|
||||
});
|
||||
|
||||
@@ -668,7 +672,9 @@ feedsRouter.post("/bulk-delete", async (c) => {
|
||||
|
||||
const deletedFeedIds = await removeFeedsFromListBulk(emailStorage, okIds);
|
||||
if (deletedFeedIds.length > 0) {
|
||||
await bumpCounters(emailStorage, { feeds_deleted: deletedFeedIds.length });
|
||||
await bumpCounters(emailStorage, {
|
||||
feeds_deleted: deletedFeedIds.length,
|
||||
});
|
||||
}
|
||||
|
||||
const removed = new Set(deletedFeedIds);
|
||||
@@ -720,7 +726,9 @@ feedsRouter.post("/bulk-delete", async (c) => {
|
||||
|
||||
const deletedFeedIds = await removeFeedsFromListBulk(emailStorage, okIds);
|
||||
if (deletedFeedIds.length > 0) {
|
||||
await bumpCounters(emailStorage, { feeds_deleted: deletedFeedIds.length });
|
||||
await bumpCounters(emailStorage, {
|
||||
feeds_deleted: deletedFeedIds.length,
|
||||
});
|
||||
}
|
||||
|
||||
return c.redirect(
|
||||
|
||||
@@ -341,21 +341,6 @@ function refreshFeedRowCache(): void {
|
||||
updateFeedSelectionState();
|
||||
}
|
||||
|
||||
interface ToastHandle {
|
||||
update?: (msg: string, opts?: Record<string, unknown>) => void;
|
||||
dismiss?: () => void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
showToast?: (msg: string, opts?: Record<string, unknown>) => ToastHandle;
|
||||
parseJsonResponseOrThrow?: (
|
||||
res: Response,
|
||||
opts?: Record<string, unknown>,
|
||||
) => Promise<Record<string, unknown>>;
|
||||
}
|
||||
}
|
||||
|
||||
function setupFeedDeleteButtons(): void {
|
||||
const buttons = Array.from(
|
||||
document.querySelectorAll<HTMLButtonElement>(
|
||||
|
||||
@@ -321,21 +321,6 @@ function refreshEmailRowCache(): void {
|
||||
updateEmailSelectionState();
|
||||
}
|
||||
|
||||
interface ToastHandle {
|
||||
update?: (msg: string, opts?: Record<string, unknown>) => void;
|
||||
dismiss?: () => void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
showToast?: (msg: string, opts?: Record<string, unknown>) => ToastHandle;
|
||||
parseJsonResponseOrThrow?: (
|
||||
res: Response,
|
||||
opts?: Record<string, unknown>,
|
||||
) => Promise<Record<string, unknown>>;
|
||||
}
|
||||
}
|
||||
|
||||
function setupEmailDeleteButtons(): void {
|
||||
Array.from(
|
||||
document.querySelectorAll<HTMLButtonElement>(
|
||||
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
// Ambient declarations for browser globals injected at runtime via inline
|
||||
// <script> bundles (see src/scripts/toast.ts and src/scripts/httpErrors.ts).
|
||||
// Those helpers attach themselves to window rather than being importable, so the
|
||||
// client TypeScript needs them declared here to type-check.
|
||||
|
||||
interface ToastOptions {
|
||||
type?: "info" | "success" | "warning" | "error" | (string & {});
|
||||
loading?: boolean;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
interface ToastHandle {
|
||||
dismiss: () => void;
|
||||
update: (message: string, opts?: ToastOptions) => void;
|
||||
}
|
||||
|
||||
interface ParseJsonOptions {
|
||||
prefix?: string;
|
||||
allowText?: boolean;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
showToast: (message: string, opts?: ToastOptions) => ToastHandle;
|
||||
parseJsonResponseOrThrow: (
|
||||
res: Response,
|
||||
opts?: ParseJsonOptions,
|
||||
) => Promise<Record<string, unknown>>;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
Reference in New Issue
Block a user