Address ESlint console statements

This commit is contained in:
adilallo
2026-01-28 11:49:56 -07:00
parent 6b8d646f8a
commit 29a3bd3824
10 changed files with 73 additions and 18 deletions
+5 -4
View File
@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { logger } from "../../../lib/logger";
const WEB_VITALS_DIR = path.join(process.cwd(), ".next", "web-vitals"); const WEB_VITALS_DIR = path.join(process.cwd(), ".next", "web-vitals");
@@ -65,7 +66,7 @@ export async function POST(request: NextRequest) {
existingData = JSON.parse(fileContent) as WebVitalData[]; existingData = JSON.parse(fileContent) as WebVitalData[];
} catch (error) { } catch (error) {
const err = error as Error; const err = error as Error;
console.warn("Could not parse existing vitals data:", err.message); logger.warn("Could not parse existing vitals data:", err.message);
} }
} }
@@ -79,13 +80,13 @@ export async function POST(request: NextRequest) {
fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2)); fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2));
// Log for monitoring // Log for monitoring
console.log( logger.info(
`Web Vital received: ${metric} = ${data.value}ms (${data.rating})`, `Web Vital received: ${metric} = ${data.value}ms (${data.rating})`,
); );
return NextResponse.json({ success: true }); return NextResponse.json({ success: true });
} catch (error) { } catch (error) {
console.error("Error processing web vital:", error); logger.error("Error processing web vital:", error);
return NextResponse.json( return NextResponse.json(
{ error: "Internal server error" }, { error: "Internal server error" },
{ status: 500 }, { status: 500 },
@@ -141,7 +142,7 @@ export async function GET() {
return NextResponse.json({ metrics }); return NextResponse.json({ metrics });
} catch (error) { } catch (error) {
console.error("Error fetching web vitals:", error); logger.error("Error fetching web vitals:", error);
return NextResponse.json( return NextResponse.json(
{ error: "Internal server error" }, { error: "Internal server error" },
{ status: 500 }, { status: 500 },
+3 -2
View File
@@ -6,6 +6,7 @@ import {
getAllBlogPosts as getAllPosts, getAllBlogPosts as getAllPosts,
type BlogPost, type BlogPost,
} from "../../../lib/content"; } from "../../../lib/content";
import { logger } from "../../../lib/logger";
import ContentBanner from "../../components/ContentBanner"; import ContentBanner from "../../components/ContentBanner";
import AskOrganizer from "../../components/AskOrganizer"; import AskOrganizer from "../../components/AskOrganizer";
import { getAssetPath, ASSETS } from "../../../lib/assetUtils"; import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
@@ -44,7 +45,7 @@ export async function generateStaticParams() {
slug: post.slug, slug: post.slug,
})); }));
} catch (error) { } catch (error) {
console.error("Error generating static params:", error); logger.error("Error generating static params:", error);
return []; return [];
} }
} }
@@ -87,7 +88,7 @@ export async function generateMetadata({
}, },
}; };
} catch (error) { } catch (error) {
console.error("Error generating metadata:", error); logger.error("Error generating metadata:", error);
return { return {
title: "Blog Post", title: "Blog Post",
description: "A blog post from our community.", description: "A blog post from our community.",
+2 -1
View File
@@ -1,6 +1,7 @@
"use client"; "use client";
import React, { Component, type ReactNode } from "react"; import React, { Component, type ReactNode } from "react";
import { logger } from "../../lib/logger";
interface ErrorBoundaryProps { interface ErrorBoundaryProps {
children: ReactNode; children: ReactNode;
@@ -24,7 +25,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Log the error to an error reporting service // Log the error to an error reporting service
console.error("ErrorBoundary caught an error:", error, errorInfo); logger.error("ErrorBoundary caught an error:", error, errorInfo);
} }
render() { render() {
+3 -2
View File
@@ -3,6 +3,7 @@
import { useState, memo } from "react"; import { useState, memo } from "react";
import Image from "next/image"; import Image from "next/image";
import QuoteDecor from "./QuoteDecor"; import QuoteDecor from "./QuoteDecor";
import { logger } from "../../lib/logger";
interface QuoteBlockProps { interface QuoteBlockProps {
variant?: "compact" | "standard" | "extended"; variant?: "compact" | "standard" | "extended";
@@ -109,7 +110,7 @@ const QuoteBlock = memo<QuoteBlockProps>(
// Error handling functions // Error handling functions
const handleImageError = (error: unknown) => { const handleImageError = (error: unknown) => {
console.warn( logger.warn(
`QuoteBlock: Failed to load avatar image for ${author}:`, `QuoteBlock: Failed to load avatar image for ${author}:`,
error, error,
); );
@@ -135,7 +136,7 @@ const QuoteBlock = memo<QuoteBlockProps>(
// Validate required props // Validate required props
if (!quote || !author) { if (!quote || !author) {
console.error("QuoteBlock: Missing required props (quote or author)"); logger.error("QuoteBlock: Missing required props (quote or author)");
if (onError) { if (onError) {
onError({ onError({
type: "missing_props", type: "missing_props",
+2 -1
View File
@@ -5,6 +5,7 @@ import Image from "next/image";
import RuleCard from "./RuleCard"; import RuleCard from "./RuleCard";
import Button from "./Button"; import Button from "./Button";
import { getAssetPath } from "../../lib/assetUtils"; import { getAssetPath } from "../../lib/assetUtils";
import { logger } from "../../lib/logger";
interface RuleStackProps { interface RuleStackProps {
className?: string; className?: string;
@@ -38,7 +39,7 @@ const RuleStack = memo<RuleStackProps>(({ className = "" }) => {
}); });
} }
} }
console.log(`${templateName} template clicked`); logger.debug(`${templateName} template clicked`);
}; };
return ( return (
+2 -1
View File
@@ -1,6 +1,7 @@
"use client"; "use client";
import { useState, useEffect, memo } from "react"; import { useState, useEffect, memo } from "react";
import { logger } from "../../lib/logger";
interface VitalData { interface VitalData {
value: number; value: number;
@@ -50,7 +51,7 @@ const WebVitalsDashboard = memo(() => {
const data = (await response.json()) as { metrics?: Metrics }; const data = (await response.json()) as { metrics?: Metrics };
setMetrics(data.metrics || {}); setMetrics(data.metrics || {});
} catch (error) { } catch (error) {
console.error("Error fetching web vitals:", error); logger.error("Error fetching web vitals:", error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
+20 -1
View File
@@ -129,7 +129,26 @@ const eslintConfig = [
rules: { rules: {
// Basic rules // Basic rules
"react/no-unescaped-entities": "off", "react/no-unescaped-entities": "off",
"no-console": "warn", // Default: discourage console usage, but allow warn/error as "standard practice"
"no-console": ["warn", { allow: ["warn", "error"] }],
},
},
// App/lib code: no console.* (enforced)
{
files: ["app/**/*.{ts,tsx,js,jsx}", "lib/**/*.{ts,tsx,js,jsx}"],
rules: {
"no-console": "error",
},
},
// Tests/Storybook/scripts: console is acceptable
{
files: [
"tests/**/*.{ts,tsx,js,jsx}",
"stories/**/*.{ts,tsx,js,jsx}",
"scripts/**/*.{ts,js}",
],
rules: {
"no-console": "off",
}, },
}, },
// Config files - allow Node.js globals // Config files - allow Node.js globals
+5 -3
View File
@@ -2,6 +2,8 @@
* Content caching utilities for improved performance * Content caching utilities for improved performance
*/ */
import { logger } from "./logger";
// In-memory cache for blog posts // In-memory cache for blog posts
const blogPostCache = new Map<string, CacheEntry<unknown>>(); const blogPostCache = new Map<string, CacheEntry<unknown>>();
const blogListCache = new Map<string, CacheEntry<unknown[]>>(); const blogListCache = new Map<string, CacheEntry<unknown[]>>();
@@ -243,9 +245,9 @@ export async function warmCache<T>(
cacheBlogPost(postWithSlug.slug, post); cacheBlogPost(postWithSlug.slug, post);
}); });
console.log("Cache warmed up successfully"); logger.info("Cache warmed up successfully");
} catch (error) { } catch (error) {
console.error("Error warming up cache:", error); logger.error("Error warming up cache:", error);
} }
} }
@@ -258,7 +260,7 @@ export function isCacheHealthy(): boolean {
clearExpiredCache(); clearExpiredCache();
return blogPostCache.size < MAX_CACHE_SIZE; return blogPostCache.size < MAX_CACHE_SIZE;
} catch (error) { } catch (error) {
console.error("Cache health check failed:", error); logger.error("Cache health check failed:", error);
return false; return false;
} }
} }
+4 -3
View File
@@ -3,6 +3,7 @@ import path from "path";
import matter from "gray-matter"; import matter from "gray-matter";
import { validateBlogPost, sanitizeBlogPost } from "./validation"; import { validateBlogPost, sanitizeBlogPost } from "./validation";
import type { BlogPostFrontmatter } from "./validation"; import type { BlogPostFrontmatter } from "./validation";
import { logger } from "./logger";
/** /**
* Content processing utilities for blog posts * Content processing utilities for blog posts
@@ -73,7 +74,7 @@ export function getBlogPostFiles(): string[] {
(file) => file.endsWith(".md") || file.endsWith(".mdx"), (file) => file.endsWith(".md") || file.endsWith(".mdx"),
); );
} catch (error) { } catch (error) {
console.error("Error reading blog content directory:", error); logger.error("Error reading blog content directory:", error);
return []; return [];
} }
} }
@@ -92,7 +93,7 @@ export function parseBlogPost(filePath: string): BlogPost | null {
const validationResult = validateBlogPost(data); const validationResult = validateBlogPost(data);
if (!validationResult.isValid) { if (!validationResult.isValid) {
console.error( logger.error(
`Validation errors for ${filePath}:`, `Validation errors for ${filePath}:`,
validationResult.errors, validationResult.errors,
); );
@@ -111,7 +112,7 @@ export function parseBlogPost(filePath: string): BlogPost | null {
lastModified: fs.statSync(fullPath).mtime, lastModified: fs.statSync(fullPath).mtime,
}; };
} catch (error) { } catch (error) {
console.error(`Error parsing blog post file ${filePath}:`, error); logger.error(`Error parsing blog post file ${filePath}:`, error);
return null; return null;
} }
} }
+27
View File
@@ -0,0 +1,27 @@
/* eslint-disable no-console */
/**
* Minimal logger wrapper.
*
* - Centralizes logging so we can swap implementations later (e.g. pino/sentry).
* - Avoids sprinkling `console.*` throughout app code.
*/
type LoggerArgs = unknown[];
const isProd = process.env.NODE_ENV === "production";
export const logger = {
debug: (...args: LoggerArgs) => {
if (!isProd) console.debug(...args);
},
info: (...args: LoggerArgs) => {
console.info(...args);
},
warn: (...args: LoggerArgs) => {
console.warn(...args);
},
error: (...args: LoggerArgs) => {
console.error(...args);
},
};