Update ESLint configuration and schemas to use Zod library

- Changed ESLint configuration to target TypeScript files and added parser options for better integration.
- Updated various schemas across the application to replace `nestjs-zod/z` imports with `zod` for consistency.
- Refactored password validation in authentication schemas to use `z.string()` instead of `z.password()`.
- Enhanced date handling in user and resume schemas by introducing a new `dateSchema` utility.
- Updated `.ncurc.json` to target minor upgrades for dependencies.
This commit is contained in:
Amruth Pillai
2025-01-12 17:34:45 +01:00
parent 6fb0a72a56
commit 0053d696ff
28 changed files with 103 additions and 41 deletions
+1
View File
@@ -1,6 +1,7 @@
{ {
"$schema": "https://raw.githubusercontent.com/raineorshine/npm-check-updates/main/src/types/RunOptions.json", "$schema": "https://raw.githubusercontent.com/raineorshine/npm-check-updates/main/src/types/RunOptions.json",
"upgrade": true, "upgrade": true,
"target": "minor",
"install": "always", "install": "always",
"packageManager": "pnpm", "packageManager": "pnpm",
"reject": [ "reject": [
+57 -3
View File
@@ -3,11 +3,14 @@
"ignorePatterns": ["!**/*"], "ignorePatterns": ["!**/*"],
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "files": ["*.ts", "*.tsx"],
"extends": [ "extends": [
"plugin:tailwindcss/recommended", "plugin:tailwindcss/recommended",
"plugin:@tanstack/eslint-plugin-query/recommended" "plugin:@tanstack/eslint-plugin-query/recommended"
], ],
"parserOptions": {
"projectService": "./apps/client/tsconfig.json"
},
"settings": { "settings": {
"tailwindcss": { "tailwindcss": {
"callees": ["cn", "clsx", "cva"], "callees": ["cn", "clsx", "cva"],
@@ -39,8 +42,59 @@
"lingui/no-unlocalized-strings": [ "lingui/no-unlocalized-strings": [
2, 2,
{ {
"ignoreFunction": ["cn"], "ignore": [
"ignoreAttribute": ["alt"] // Ignore strings which are a single "word" (no spaces)
// and doesn't start with an uppercase letter
"^(?![A-Z])\\S+$",
// Ignore UPPERCASE literals
// Example: const test = "FOO"
"^[A-Z0-9_-]+$"
],
"ignoreNames": [
// Ignore matching className (case-insensitive)
{ "regex": { "pattern": "className", "flags": "i" } },
// Ignore UPPERCASE names
// Example: test.FOO = "ola!"
{ "regex": { "pattern": "^[A-Z0-9_-]+$" } },
"id",
"src",
"srcSet",
"styleName",
"placeholder",
"alt",
"type",
"width",
"height",
"displayName",
"Authorization"
],
"ignoreFunctions": [
"cn",
"cva",
"track",
"Error",
"console.*",
"*headers.set",
"*.addEventListener",
"*.removeEventListener",
"*.postMessage",
"*.getElementById",
"*.dispatch",
"*.commit",
"*.includes",
"*.indexOf",
"*.endsWith",
"*.startsWith",
"require"
],
// Following settings require typed linting https://typescript-eslint.io/getting-started/typed-linting/
"useTsTypes": true,
"ignoreMethodsOnTypes": [
// Ignore specified methods on Map and Set types
"Map.get",
"Map.has",
"Set.has"
]
} }
], ],
"lingui/t-call-in-function": 2, "lingui/t-call-in-function": 2,
@@ -18,7 +18,7 @@ import {
verticalListSortingStrategy, verticalListSortingStrategy,
} from "@dnd-kit/sortable"; } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities"; import { CSS } from "@dnd-kit/utilities";
import { t, Trans } from "@lingui/macro"; import { t } from "@lingui/macro";
import { ArrowCounterClockwise, DotsSixVertical, Plus, TrashSimple } from "@phosphor-icons/react"; import { ArrowCounterClockwise, DotsSixVertical, Plus, TrashSimple } from "@phosphor-icons/react";
import { defaultMetadata } from "@reactive-resume/schema"; import { defaultMetadata } from "@reactive-resume/schema";
import { Button, Portal, Tooltip } from "@reactive-resume/ui"; import { Button, Portal, Tooltip } from "@reactive-resume/ui";
@@ -92,9 +92,7 @@ type SectionProps = {
}; };
const Section = ({ id, isDragging = false }: SectionProps) => { const Section = ({ id, isDragging = false }: SectionProps) => {
const name = useResumeStore((state) => const name = useResumeStore((state) => get(state.resume.data.sections, `${id}.name`, id));
get(state.resume.data.sections, `${id}.name`, id),
) as string;
return ( return (
<div <div
@@ -229,13 +227,12 @@ export const LayoutSection = () => {
const main = page[0]; const main = page[0];
const sidebar = page[1]; const sidebar = page[1];
const pageNumber = pageIndex + 1;
return ( return (
<div key={pageIndex} className="rounded border p-3 pb-4"> <div key={pageIndex} className="rounded border p-3 pb-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="mb-3 text-xs font-bold"> <p className="mb-3 text-xs font-bold">{t`Page ${pageNumber}`}</p>
<Trans>Page {pageIndex + 1}</Trans>
</p>
{pageIndex !== 0 && ( {pageIndex !== 0 && (
<Tooltip content={t`Remove Page`}> <Tooltip content={t`Remove Page`}>
+1 -1
View File
@@ -1,5 +1,5 @@
import { idSchema } from "@reactive-resume/schema"; import { idSchema } from "@reactive-resume/schema";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const payloadSchema = z.object({ export const payloadSchema = z.object({
id: idSchema, id: idSchema,
+1 -1
View File
@@ -1,4 +1,4 @@
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const configSchema = z.object({ export const configSchema = z.object({
NODE_ENV: z.enum(["development", "production"]).default("production"), NODE_ENV: z.enum(["development", "production"]).default("production"),
+1 -1
View File
@@ -114,7 +114,7 @@ export class ResumeService {
title: updateResumeDto.title, title: updateResumeDto.title,
slug: updateResumeDto.slug, slug: updateResumeDto.slug,
visibility: updateResumeDto.visibility, visibility: updateResumeDto.visibility,
data: updateResumeDto.data as unknown as Prisma.JsonObject, data: updateResumeDto.data as Prisma.JsonObject,
}, },
where: { userId_id: { userId, id } }, where: { userId_id: { userId, id } },
}); });
+2 -1
View File
@@ -12,6 +12,7 @@
"@reactive-resume/utils": "*", "@reactive-resume/utils": "*",
"@reactive-resume/schema": "*", "@reactive-resume/schema": "*",
"nestjs-zod": "^3.0.0", "nestjs-zod": "^3.0.0",
"@swc/helpers": "~0.5.11" "@swc/helpers": "~0.5.11",
"zod": "^3.24.1"
} }
} }
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const forgotPasswordSchema = z.object({ email: z.string().email() }); export const forgotPasswordSchema = z.object({ email: z.string().email() });
+2 -2
View File
@@ -1,12 +1,12 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
import { usernameSchema } from "../user"; import { usernameSchema } from "../user";
export const loginSchema = z export const loginSchema = z
.object({ .object({
identifier: z.string().transform((value) => value.toLowerCase()), identifier: z.string().transform((value) => value.toLowerCase()),
password: z.password().min(6), password: z.string().min(6),
}) })
.refine( .refine(
(value) => { (value) => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const messageSchema = z.object({ message: z.string() }); export const messageSchema = z.object({ message: z.string() });
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
const authProvidersSchema = z.array(z.enum(["email", "github", "google"])); const authProvidersSchema = z.array(z.enum(["email", "github", "google"]));
+2 -2
View File
@@ -1,10 +1,10 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
import { userSchema } from "../user"; import { userSchema } from "../user";
export const registerSchema = userSchema export const registerSchema = userSchema
.pick({ name: true, email: true, username: true, locale: true }) .pick({ name: true, email: true, username: true, locale: true })
.extend({ password: z.password().min(6) }); .extend({ password: z.string().min(6) });
export class RegisterDto extends createZodDto(registerSchema) {} export class RegisterDto extends createZodDto(registerSchema) {}
+2 -2
View File
@@ -1,9 +1,9 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const resetPasswordSchema = z.object({ export const resetPasswordSchema = z.object({
token: z.string(), token: z.string(),
password: z.password().min(6), password: z.string().min(6),
}); });
export class ResetPasswordDto extends createZodDto(resetPasswordSchema) {} export class ResetPasswordDto extends createZodDto(resetPasswordSchema) {}
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
import { userSchema } from "../user"; import { userSchema } from "../user";
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const twoFactorSchema = z.object({ export const twoFactorSchema = z.object({
code: z code: z
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const updatePasswordSchema = z.object({ export const updatePasswordSchema = z.object({
password: z.string().min(6), password: z.string().min(6),
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const contributorSchema = z.object({ export const contributorSchema = z.object({
id: z.number(), id: z.number(),
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const featureSchema = z.object({ export const featureSchema = z.object({
isSignupsDisabled: z.boolean().default(false), isSignupsDisabled: z.boolean().default(false),
+1 -1
View File
@@ -1,6 +1,6 @@
import { kebabCase } from "@reactive-resume/utils"; import { kebabCase } from "@reactive-resume/utils";
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const createResumeSchema = z.object({ export const createResumeSchema = z.object({
title: z.string().min(1), title: z.string().min(1),
+1 -1
View File
@@ -1,6 +1,6 @@
import { idSchema } from "@reactive-resume/schema"; import { idSchema } from "@reactive-resume/schema";
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const deleteResumeSchema = z.object({ export const deleteResumeSchema = z.object({
id: idSchema, id: idSchema,
+1 -1
View File
@@ -1,7 +1,7 @@
import { resumeDataSchema } from "@reactive-resume/schema"; import { resumeDataSchema } from "@reactive-resume/schema";
import { kebabCase } from "@reactive-resume/utils"; import { kebabCase } from "@reactive-resume/utils";
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const importResumeSchema = z.object({ export const importResumeSchema = z.object({
title: z.string().optional(), title: z.string().optional(),
+4 -3
View File
@@ -1,6 +1,7 @@
import { defaultResumeData, idSchema, resumeDataSchema } from "@reactive-resume/schema"; import { defaultResumeData, idSchema, resumeDataSchema } from "@reactive-resume/schema";
import { dateSchema } from "@reactive-resume/utils";
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
import { userSchema } from "../user"; import { userSchema } from "../user";
@@ -13,8 +14,8 @@ export const resumeSchema = z.object({
locked: z.boolean().default(false), locked: z.boolean().default(false),
userId: idSchema, userId: idSchema,
user: userSchema.optional(), user: userSchema.optional(),
createdAt: z.date().or(z.dateString()), createdAt: dateSchema,
updatedAt: z.date().or(z.dateString()), updatedAt: dateSchema,
}); });
export class ResumeDto extends createZodDto(resumeSchema) {} export class ResumeDto extends createZodDto(resumeSchema) {}
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const urlSchema = z.object({ url: z.string().url() }); export const urlSchema = z.object({ url: z.string().url() });
+1 -1
View File
@@ -1,5 +1,5 @@
import { idSchema } from "@reactive-resume/schema"; import { idSchema } from "@reactive-resume/schema";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const secretsSchema = z.object({ export const secretsSchema = z.object({
id: idSchema, id: idSchema,
+1 -1
View File
@@ -1,5 +1,5 @@
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
export const statisticsSchema = z.object({ export const statisticsSchema = z.object({
views: z.number().int().default(0), views: z.number().int().default(0),
+4 -3
View File
@@ -1,6 +1,7 @@
import { idSchema } from "@reactive-resume/schema"; import { idSchema } from "@reactive-resume/schema";
import { dateSchema } from "@reactive-resume/utils";
import { createZodDto } from "nestjs-zod/dto"; import { createZodDto } from "nestjs-zod/dto";
import { z } from "nestjs-zod/z"; import { z } from "zod";
import { secretsSchema } from "../secrets"; import { secretsSchema } from "../secrets";
@@ -26,8 +27,8 @@ export const userSchema = z.object({
emailVerified: z.boolean().default(false), emailVerified: z.boolean().default(false),
twoFactorEnabled: z.boolean().default(false), twoFactorEnabled: z.boolean().default(false),
provider: z.enum(["email", "github", "google"]).default("email"), provider: z.enum(["email", "github", "google"]).default("email"),
createdAt: z.date().or(z.dateString()), createdAt: dateSchema,
updatedAt: z.date().or(z.dateString()), updatedAt: dateSchema,
}); });
export class UserDto extends createZodDto(userSchema) {} export class UserDto extends createZodDto(userSchema) {}
+2 -1
View File
@@ -14,6 +14,7 @@
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"tailwind-merge": "^2.3.0", "tailwind-merge": "^2.3.0",
"@swc/helpers": "~0.5.11" "@swc/helpers": "~0.5.11",
"zod": "^3.24.1"
} }
} }
+6
View File
@@ -1,4 +1,10 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import { z } from "zod";
export const dateSchema = z.union([z.date(), z.string().datetime()]).transform((value) => {
if (typeof value === "string") return dayjs(value).toDate();
return value;
});
export const sortByDate = <T>(a: T, b: T, key: keyof T, desc = true) => { export const sortByDate = <T>(a: T, b: T, key: keyof T, desc = true) => {
if (!a[key] || !b[key]) return 0; if (!a[key] || !b[key]) return 0;