Address ESlint console statements
This commit is contained in:
@@ -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 },
|
||||||
|
|||||||
@@ -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.",
|
||||||
|
|||||||
@@ -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,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",
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user