1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-11-05 09:05:39 -05:00

fix eslint 9 problems, especially in vs code

This commit is contained in:
2025-03-06 08:19:37 -05:00
parent ecd45ac446
commit 3804298210
7 changed files with 92 additions and 19 deletions

36
.cursorrules Normal file
View File

@@ -0,0 +1,36 @@
You are an expert in TypeScript, Node.js, Next.js 15 App Router, and React 19.
Key Principles
- Write concise, technical TypeScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Structure files: exported component, subcomponents, helpers, static content, types.
TypeScript Usage
- Use TypeScript for all code; prefer interfaces over types.
- Avoid enums; use maps instead.
- Use functional components with TypeScript interfaces.
Syntax and Formatting
- Use declarative JSX.
- Follow Prettier and ESLint rules.
- Follow .editorconfig rules.
UI and Styling
- Use CSS Modules for components and styling.
Performance Optimization
- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).
- Wrap client components in Suspense with fallback.
- Use dynamic loading for non-critical components.
- Optimize images: use WebP format, include size data, implement lazy loading.
Key Conventions
- Optimize Web Vitals (LCP, CLS, FID).
- Limit 'use client':
- Favor server components and Next.js SSR.
- Use only for Web API access in small components.
- Avoid for data fetching or state management.
Follow Next.js docs for Data Fetching, Rendering, and Routing.

2
.npmrc Normal file
View File

@@ -0,0 +1,2 @@
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

View File

@@ -20,10 +20,10 @@ export async function sendMessage(
success: boolean; success: boolean;
message: string; message: string;
errors?: z.inferFormattedError<typeof schema>; errors?: z.inferFormattedError<typeof schema>;
payload: FormData; payload?: FormData;
}> { }> {
try { try {
const validatedFields = schema.safeParse({ ...formData }); const validatedFields = schema.safeParse(Object.fromEntries(formData));
// backup to client-side validations just in case someone squeezes through without them // backup to client-side validations just in case someone squeezes through without them
if (!validatedFields.success) { if (!validatedFields.success) {
@@ -47,7 +47,13 @@ export async function sendMessage(
remoteip: (await headers()).get("x-forwarded-for") || "", remoteip: (await headers()).get("x-forwarded-for") || "",
}), }),
cache: "no-store", cache: "no-store",
signal: AbortSignal.timeout(5000), // 5 second timeout
}); });
if (!turnstileResponse.ok) {
throw new Error(`Turnstile validation failed: ${turnstileResponse.status}`);
}
const turnstileData = await turnstileResponse?.json(); const turnstileData = await turnstileResponse?.json();
if (!turnstileData?.success) { if (!turnstileData?.success) {
@@ -70,7 +76,7 @@ export async function sendMessage(
return { success: true, message: "Thanks! You should hear from me soon.", payload: formData }; return { success: true, message: "Thanks! You should hear from me soon.", payload: formData };
} catch (error) { } catch (error) {
console.error(error); console.error("Contact form error:", error);
return { return {
success: false, success: false,

View File

@@ -12,9 +12,9 @@ import { SiMarkdown } from "react-icons/si";
import styles from "./form.module.css"; import styles from "./form.module.css";
const ContactForm = () => { const ContactForm = () => {
const [formState, formAction, pending] = useActionState<Partial<Awaited<ReturnType<typeof sendMessage>>>, FormData>( const [formState, formAction, pending] = useActionState<Awaited<ReturnType<typeof sendMessage>>, FormData>(
sendMessage, sendMessage,
{} { success: false, message: "" }
); );
return ( return (

View File

@@ -1,5 +1,6 @@
import { FlatCompat } from "@eslint/eslintrc"; import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js"; import js from "@eslint/js";
import { fixupConfigRules } from "@eslint/compat";
import prettierRecommended from "eslint-plugin-prettier/recommended"; import prettierRecommended from "eslint-plugin-prettier/recommended";
import customConfig from "@jakejarvis/eslint-config"; import customConfig from "@jakejarvis/eslint-config";
import * as mdx from "eslint-plugin-mdx"; import * as mdx from "eslint-plugin-mdx";
@@ -12,9 +13,12 @@ const compat = new FlatCompat({
export default [ export default [
{ ignores: ["README.md", ".next", ".vercel", "node_modules"] }, { ignores: ["README.md", ".next", ".vercel", "node_modules"] },
js.configs.recommended, js.configs.recommended,
...compat.extends("next/core-web-vitals", "next/typescript"),
prettierRecommended,
...customConfig, ...customConfig,
...fixupConfigRules(
// https://github.com/vercel/next.js/issues/64114#issuecomment-2325268516
compat.extends("next/core-web-vitals", "next/typescript")
),
prettierRecommended,
{ {
rules: { rules: {
"prettier/prettier": [ "prettier/prettier": [

View File

@@ -48,7 +48,7 @@
"react-dom": "19.0.0", "react-dom": "19.0.0",
"react-error-boundary": "^5.0.0", "react-error-boundary": "^5.0.0",
"react-frame-component": "^5.2.7", "react-frame-component": "^5.2.7",
"react-icons": "~5.5.0", "react-icons": "5.5.0",
"react-innertext": "^1.1.5", "react-innertext": "^1.1.5",
"react-is": "19.0.0", "react-is": "19.0.0",
"react-textarea-autosize": "^8.5.7", "react-textarea-autosize": "^8.5.7",
@@ -70,9 +70,10 @@
"zod": "^3.24.2" "zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.2.7",
"@eslint/eslintrc": "^3.3.0", "@eslint/eslintrc": "^3.3.0",
"@eslint/js": "^9.21.0", "@eslint/js": "^9.21.0",
"@jakejarvis/eslint-config": "~4.0.7", "@jakejarvis/eslint-config": "^4.0.7",
"@types/comma-number": "^2.1.2", "@types/comma-number": "^2.1.2",
"@types/mdx": "^2.0.13", "@types/mdx": "^2.0.13",
"@types/node": "^22.13.9", "@types/node": "^22.13.9",
@@ -81,11 +82,13 @@
"@types/react-dom": "^19.0.4", "@types/react-dom": "^19.0.4",
"@types/react-is": "^19.0.0", "@types/react-is": "^19.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "~9.21.0", "eslint": "^9.21.0",
"eslint-config-next": "15.2.2-canary.1", "eslint-config-next": "15.2.2-canary.1",
"eslint-config-prettier": "~10.0.2", "eslint-config-prettier": "^10.0.2",
"eslint-plugin-mdx": "~3.1.5", "eslint-plugin-mdx": "^3.1.5",
"eslint-plugin-prettier": "~5.2.3", "eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.2.0",
"lint-staged": "^15.4.3", "lint-staged": "^15.4.3",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prisma": "^6.4.1", "prisma": "^6.4.1",

34
pnpm-lock.yaml generated
View File

@@ -96,7 +96,7 @@ importers:
specifier: ^5.2.7 specifier: ^5.2.7
version: 5.2.7(prop-types@15.8.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 5.2.7(prop-types@15.8.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-icons: react-icons:
specifier: ~5.5.0 specifier: 5.5.0
version: 5.5.0(react@19.0.0) version: 5.5.0(react@19.0.0)
react-innertext: react-innertext:
specifier: ^1.1.5 specifier: ^1.1.5
@@ -156,6 +156,9 @@ importers:
specifier: ^3.24.2 specifier: ^3.24.2
version: 3.24.2 version: 3.24.2
devDependencies: devDependencies:
'@eslint/compat':
specifier: ^1.2.7
version: 1.2.7(eslint@9.21.0)
'@eslint/eslintrc': '@eslint/eslintrc':
specifier: ^3.3.0 specifier: ^3.3.0
version: 3.3.0 version: 3.3.0
@@ -163,7 +166,7 @@ importers:
specifier: ^9.21.0 specifier: ^9.21.0
version: 9.21.0 version: 9.21.0
'@jakejarvis/eslint-config': '@jakejarvis/eslint-config':
specifier: ~4.0.7 specifier: ^4.0.7
version: 4.0.7(eslint@9.21.0) version: 4.0.7(eslint@9.21.0)
'@types/comma-number': '@types/comma-number':
specifier: ^2.1.2 specifier: ^2.1.2
@@ -190,20 +193,26 @@ importers:
specifier: ^7.0.3 specifier: ^7.0.3
version: 7.0.3 version: 7.0.3
eslint: eslint:
specifier: ~9.21.0 specifier: ^9.21.0
version: 9.21.0 version: 9.21.0
eslint-config-next: eslint-config-next:
specifier: 15.2.2-canary.1 specifier: 15.2.2-canary.1
version: 15.2.2-canary.1(eslint@9.21.0)(typescript@5.7.3) version: 15.2.2-canary.1(eslint@9.21.0)(typescript@5.7.3)
eslint-config-prettier: eslint-config-prettier:
specifier: ~10.0.2 specifier: ^10.0.2
version: 10.0.2(eslint@9.21.0) version: 10.0.2(eslint@9.21.0)
eslint-plugin-mdx: eslint-plugin-mdx:
specifier: ~3.1.5 specifier: ^3.1.5
version: 3.1.5(eslint@9.21.0) version: 3.1.5(eslint@9.21.0)
eslint-plugin-prettier: eslint-plugin-prettier:
specifier: ~5.2.3 specifier: ^5.2.3
version: 5.2.3(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@9.21.0))(eslint@9.21.0)(prettier@3.5.3) version: 5.2.3(@types/eslint@9.6.1)(eslint-config-prettier@10.0.2(eslint@9.21.0))(eslint@9.21.0)(prettier@3.5.3)
eslint-plugin-react:
specifier: ^7.37.4
version: 7.37.4(eslint@9.21.0)
eslint-plugin-react-hooks:
specifier: ^5.2.0
version: 5.2.0(eslint@9.21.0)
lint-staged: lint-staged:
specifier: ^15.4.3 specifier: ^15.4.3
version: 15.4.3 version: 15.4.3
@@ -467,6 +476,15 @@ packages:
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/compat@1.2.7':
resolution: {integrity: sha512-xvv7hJE32yhegJ8xNAnb62ggiAwTYHBpUCWhRxEj/ksvgDJuSXfoDkBcRYaYNFiJ+jH0IE3K16hd+xXzhBgNbg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^9.10.0
peerDependenciesMeta:
eslint:
optional: true
'@eslint/config-array@0.19.2': '@eslint/config-array@0.19.2':
resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -4481,6 +4499,10 @@ snapshots:
'@eslint-community/regexpp@4.12.1': {} '@eslint-community/regexpp@4.12.1': {}
'@eslint/compat@1.2.7(eslint@9.21.0)':
optionalDependencies:
eslint: 9.21.0
'@eslint/config-array@0.19.2': '@eslint/config-array@0.19.2':
dependencies: dependencies:
'@eslint/object-schema': 2.1.6 '@eslint/object-schema': 2.1.6