From 432df3a6e3b6210de81811e30289b5a10147a408 Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Wed, 10 Apr 2024 16:15:39 +0200 Subject: [PATCH 1/3] progress Fixing some of the imports by Typescript standards ** Still in progress ** --- src/commands/add/auth/lucia/index.ts | 2 +- src/commands/add/auth/lucia/utils.ts | 6 +++--- src/commands/add/misc/resend/generators.ts | 4 ++-- src/commands/add/orm/drizzle/generators.ts | 2 +- src/commands/add/orm/prisma/generators.ts | 2 +- src/commands/generate/generators/apiRoute.ts | 2 +- .../generate/generators/model/schema/index.ts | 6 +++--- .../generators/views-with-server-actions.ts | 16 +++++++++++++- src/commands/generate/generators/views.ts | 21 +++++++++++++++++-- 9 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/commands/add/auth/lucia/index.ts b/src/commands/add/auth/lucia/index.ts index fef3c3f1..dc7f03bf 100644 --- a/src/commands/add/auth/lucia/index.ts +++ b/src/commands/add/auth/lucia/index.ts @@ -133,7 +133,7 @@ export const addLucia = async () => { removeExtension: false, prefix: "rootPath", }), - `import { z } from "zod"; + `import type { z } from "zod"; export const authenticationSchema = z.object({ email: z.string().email().min(5).max(31), diff --git a/src/commands/add/auth/lucia/utils.ts b/src/commands/add/auth/lucia/utils.ts index 8d8a4c50..231ecdd9 100644 --- a/src/commands/add/auth/lucia/utils.ts +++ b/src/commands/add/auth/lucia/utils.ts @@ -78,7 +78,7 @@ import { sessions, users } from "../db/schema/auth"; }; export const DrizzleLuciaSchema: { [k in DBType]: string } = { - pg: `import { z } from "zod"; + pg: `import type { z } from "zod"; import { pgTable, timestamp, text } from "drizzle-orm/pg-core"; export const users = pgTable("user", { @@ -99,7 +99,7 @@ export const sessions = pgTable("session", { }).notNull() }); `, - mysql: `import { z } from "zod"; + mysql: `import type { z } from "zod"; import { mysqlTable, varchar, datetime } from "drizzle-orm/mysql-core"; export const users = mysqlTable("user", { @@ -128,7 +128,7 @@ export const sessions = mysqlTable("session", { .references(() => users.id), expiresAt: datetime("expires_at").notNull() });`, - sqlite: `import { z } from "zod"; + sqlite: `import type { z } from "zod"; import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; export const users = sqliteTable("user", { diff --git a/src/commands/add/misc/resend/generators.ts b/src/commands/add/misc/resend/generators.ts index a850abac..41bf5651 100644 --- a/src/commands/add/misc/resend/generators.ts +++ b/src/commands/add/misc/resend/generators.ts @@ -15,7 +15,7 @@ import { emailSchema } from "${formatFilePath(resend.emailUtils, { removeExtension: true, })}"; import { useRef, useState } from "react"; -import { z } from "zod"; +import type { z } from "zod"; type FormInput = z.infer; type Errors = { [K in keyof FormInput]: string[] }; @@ -220,7 +220,7 @@ export const resend = new Resend(env.RESEND_API_KEY); }; const generateEmailUtilsTs = () => { - return `import { z } from "zod"; + return `import type { z } from "zod"; export const emailSchema = z.object({ name: z.string().min(3), diff --git a/src/commands/add/orm/drizzle/generators.ts b/src/commands/add/orm/drizzle/generators.ts index cabf2014..d6b4d9e8 100644 --- a/src/commands/add/orm/drizzle/generators.ts +++ b/src/commands/add/orm/drizzle/generators.ts @@ -859,7 +859,7 @@ const generateEnvMjs = ( blank = false ) => { return `import { createEnv } from "@t3-oss/env-nextjs"; -import { z } from "zod";${ +import type { z } from "zod";${ preferredPackageManager !== "bun" && ormType === "drizzle" ? '\nimport "dotenv/config";' : "" diff --git a/src/commands/add/orm/prisma/generators.ts b/src/commands/add/orm/prisma/generators.ts index 9d9036dc..1338b083 100644 --- a/src/commands/add/orm/prisma/generators.ts +++ b/src/commands/add/orm/prisma/generators.ts @@ -60,7 +60,7 @@ if (process.env.NODE_ENV !== "production") global.db = db; export const generatePrismaComputerModel = () => { const { alias } = readConfigFile(); return `import { computerSchema } from "${alias}/zodAutoGenSchemas"; -import { z } from "zod"; +import type { z } from "zod"; export const insertComputerSchema = computerSchema; export const insertComputerParams = computerSchema.omit({ diff --git a/src/commands/generate/generators/apiRoute.ts b/src/commands/generate/generators/apiRoute.ts index 4c6cd21d..96bdc2b1 100644 --- a/src/commands/generate/generators/apiRoute.ts +++ b/src/commands/generate/generators/apiRoute.ts @@ -24,7 +24,7 @@ const generateRouteContent = (schema: Schema, driver: DBType) => { const template = `import { NextResponse } from "next/server"; import { revalidatePath } from "next/cache"; -import { z } from "zod"; +import type { z } from "zod"; import { create${tableNameSingularCapitalised}, diff --git a/src/commands/generate/generators/model/schema/index.ts b/src/commands/generate/generators/model/schema/index.ts index 53dbce2a..be6dfa84 100644 --- a/src/commands/generate/generators/model/schema/index.ts +++ b/src/commands/generate/generators/model/schema/index.ts @@ -86,7 +86,7 @@ const generateImportStatement = ( .join(", ") .concat( `, ${mappings.tableFunc}` - )}${schema.index ? ", uniqueIndex" : ""} } from "drizzle-orm/${dbType}-core";\nimport { createInsertSchema, createSelectSchema } from "drizzle-zod";\nimport { z } from "zod";\n${ + )}${schema.index ? ", uniqueIndex" : ""} } from "drizzle-orm/${dbType}-core";\nimport { createInsertSchema, createSelectSchema } from "drizzle-zod";\nimport type { z } from "zod";\n${ referenceImports.length > 0 ? referenceImports.join("\n") : "" }${ belongsToUser && provider !== "planetscale" && authSubType !== "managed" @@ -96,7 +96,7 @@ const generateImportStatement = ( })}";` : "" } -import { type get${tableNameCapitalised} } from "${formatFilePath( +import type { get${tableNameCapitalised} } from "${formatFilePath( shared.orm.servicesDir, { prefix: "alias", removeExtension: false } )}/${tableNameCamelCase}/queries"; @@ -111,7 +111,7 @@ import { nanoid${ } if (orm === "prisma") return `import { ${tableNameSingular}Schema } from "${alias}/zodAutoGenSchemas"; -import { z } from "zod";${ +import type { z } from "zod";${ schema.includeTimestamps ? `\nimport { timestamps } from "${formatFilePath("lib/utils", { prefix: "alias", diff --git a/src/commands/generate/generators/views-with-server-actions.ts b/src/commands/generate/generators/views-with-server-actions.ts index bacf0c15..a4594696 100644 --- a/src/commands/generate/generators/views-with-server-actions.ts +++ b/src/commands/generate/generators/views-with-server-actions.ts @@ -801,7 +801,7 @@ const createFormComponent = (schema: Schema) => { ...new Set(schema.fields.map((field) => field.type)), ] as ColumnType[]; - return `import { z } from "zod"; + return `import type { z } from "zod"; import { useState, useTransition } from "react"; import { useFormStatus } from "react-dom"; @@ -933,6 +933,20 @@ const ${tableNameSingularCapitalised}Form = ({${ } }; + const onError = ( + action: Action, + data?: { error: string; values: ${tableNameSingularCapitalised} }, + ) => { + const failed = Boolean(data?.error); + if (failed) { + openModal && openModal(data?.values); + toast.error(\`Failed to \${action}\`, { + description: data?.error ?? "Error", + }); + } + return + }; + const handleSubmit = async (data: FormData) => { setErrors(null); diff --git a/src/commands/generate/generators/views.ts b/src/commands/generate/generators/views.ts index 926cbd51..4442bb5d 100644 --- a/src/commands/generate/generators/views.ts +++ b/src/commands/generate/generators/views.ts @@ -349,7 +349,7 @@ import { ${t3 ? "api as " : ""}trpc } from "${formatFilePath(trpc.trpcClient, { removeExtension: true, })}"; import { Button } from "${alias}/components/ui/button"; -import { z } from "zod";${ +import type { z } from "zod";${ schema.fields.filter((field) => field.type.toLowerCase() === "boolean") .length > 0 ? `\nimport { Checkbox } from "${alias}/components/ui/checkbox";` @@ -422,7 +422,9 @@ const ${tableNameSingularCapitalised}Form = ({ } data?: { error?: string }, ) => { if (data?.error) { - toast.error(data.error) + toast.error(\`Failed to \${action}\`, { + description: data?.error ?? "Error", + }) return; } @@ -435,6 +437,21 @@ const ${tableNameSingularCapitalised}Form = ({ } }; + const onError = async (${ + packages.includes("shadcn-ui") + ? 'action: "create" | "update" | "delete",\n' + : "" + } data?: { error?: string }, + ) => { + if (data?.error) { + toast.error(\`Failed to \${action}\`, { + description: data?.error ?? "Error", + }) + return; + } + return; + }; + const { mutate: create${tableNameSingularCapitalised}, isLoading: isCreating } = trpc.${tableNameCamelCase}.create${tableNameSingularCapitalised}.useMutation({ onSuccess${ From e8dd0ff46ad36fabdea60218687a3ce9d0361a94 Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Fri, 12 Apr 2024 06:40:57 +0200 Subject: [PATCH 2/3] more minor fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit after using kirimase, the following tend to be errors based on biome ♦ update strings returned as a concatenated string rather than a string with a variable added ♦ import types updated ♦ strongly typed if statements --- src/commands/add/auth/lucia/generators.ts | 14 +++++++------- src/commands/add/auth/shared/generators.ts | 10 +++++----- .../add/componentLib/shadcn-ui/generators.ts | 2 +- src/commands/add/misc/defaultStyles/generators.ts | 3 ++- src/commands/add/misc/navbar/generators.ts | 10 +++++----- src/commands/add/misc/trpc/generators.ts | 15 ++++++++------- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/commands/add/auth/lucia/generators.ts b/src/commands/add/auth/lucia/generators.ts index ea0c608d..ce93e8d1 100644 --- a/src/commands/add/auth/lucia/generators.ts +++ b/src/commands/add/auth/lucia/generators.ts @@ -519,8 +519,8 @@ export async function updateUser( if (!result.success) { const error = result.error.flatten().fieldErrors; - if (error.name) return { error: "Invalid name - " + error.name[0] }; - if (error.email) return { error: "Invalid email - " + error.email[0] }; + if (error.name) return { error: \`Invalid name - \${error.name[0]}\` }; + if (error.email) return { error: \`Invalid email - \${error.email[0]}\` }; return genericError; } @@ -694,10 +694,10 @@ const generateAuthDirFiles = ( const utilsTs = `import { redirect } from 'next/navigation' import { cookies } from 'next/headers' -import { type Cookie } from 'lucia' +import type { Cookie } from 'lucia' import { validateRequest } from './lucia' -import { UsernameAndPassword, authenticationSchema } from '../db/schema/auth' +import { type UsernameAndPassword, authenticationSchema } from '../db/schema/auth' export type AuthSession = { session: { @@ -735,9 +735,9 @@ export const setAuthCookie = (cookie: Cookie) => { cookies().set(cookie); } -const getErrorMessage = (errors: any): string => { +const getErrorMessage = (errors: { email?: string[] | undefined; password?: string[] | undefined }): string => { if (errors.email) return 'Invalid Email' - if (errors.password) return 'Invalid Password - ' + errors.password[0] + if (errors.password) return \`Invalid Password - \${errors.password[0]}\` return '' // return a default error message or an empty string } @@ -814,7 +814,7 @@ export const validateRequest = cache( const result = await lucia.validateSession(sessionId) // next.js throws when you attempt to set cookie when rendering page try { - if (result.session && result.session.fresh) { + if (result.session?.fresh) { const sessionCookie = lucia.createSessionCookie(result.session.id) cookies().set( sessionCookie.name, diff --git a/src/commands/add/auth/shared/generators.ts b/src/commands/add/auth/shared/generators.ts index 8d0b7784..82dc40f2 100644 --- a/src/commands/add/auth/shared/generators.ts +++ b/src/commands/add/auth/shared/generators.ts @@ -11,7 +11,7 @@ export const createUserSettingsComponent = () => { return `"use client"; import UpdateNameCard from "./UpdateNameCard"; import UpdateEmailCard from "./UpdateEmailCard"; -import { AuthSession } from "${formatFilePath(shared.auth.authUtils, { +import type { AuthSession } from "${formatFilePath(shared.auth.authUtils, { prefix: "alias", removeExtension: true, })}"; @@ -58,7 +58,7 @@ export default function UpdateNameCard({ name }: { name: string }) { }); useEffect(() => { - if (state.success == true) toast.success("Updated User"); + if (state.success === true) toast.success("Updated User"); if (state.error) toast.error("Error", { description: state.error }); }, [state]); @@ -161,7 +161,7 @@ export default function UpdateNameCard({ name }: { name: string }) { }); useEffect(() => { - if (state.success == true) alert("Updated User"); + if (state.success === true) alert("Updated User"); if (state.error) alert("Error"); }, [state]); @@ -288,7 +288,7 @@ export default function UpdateEmailCard({ email }: { email: string }) { }); useEffect(() => { - if (state.success == true) toast.success("Updated Email"); + if (state.success === true) toast.success("Updated Email"); if (state.error) toast.error("Error", { description: state.error }); }, [state]); @@ -393,7 +393,7 @@ export default function UpdateEmailCard({ email }: { email: string }) { }); useEffect(() => { - if (state.success == true) alert("Updated User"); + if (state.success === true) alert("Updated User"); if (state.error) alert("Error"); }, [state]); diff --git a/src/commands/add/componentLib/shadcn-ui/generators.ts b/src/commands/add/componentLib/shadcn-ui/generators.ts index d1d918e2..26c1a09d 100644 --- a/src/commands/add/componentLib/shadcn-ui/generators.ts +++ b/src/commands/add/componentLib/shadcn-ui/generators.ts @@ -197,7 +197,7 @@ const generateThemeProvider = () => { import * as React from "react"; import { ThemeProvider as NextThemesProvider } from "next-themes"; -import { type ThemeProviderProps } from "next-themes/dist/types"; +import type { ThemeProviderProps } from "next-themes/dist/types"; export function ThemeProvider({ children, ...props }: ThemeProviderProps) { return {children}; diff --git a/src/commands/add/misc/defaultStyles/generators.ts b/src/commands/add/misc/defaultStyles/generators.ts index 5a785130..673ef54b 100644 --- a/src/commands/add/misc/defaultStyles/generators.ts +++ b/src/commands/add/misc/defaultStyles/generators.ts @@ -200,6 +200,7 @@ const landingPage = `/** * Documentation: https://v0.dev/docs#integrating-generated-code-into-your-nextjs-app */ import Link from "next/link"; +import type { JSX,SVGProps } from "react" export default function LandingPage() { return ( @@ -359,7 +360,7 @@ export default function LandingPage() { ); } -function MountainIcon(props: any) { +function MountainIcon(props: JSX.IntrinsicAttributes & SVGProps) { return ( { const { componentLib, auth } = readConfigFile(); - return `import { SidebarLink } from "${formatFilePath( + return `import type { SidebarLink } from "${formatFilePath( "components/SidebarItems", { prefix: "alias", @@ -210,7 +210,7 @@ const generateSidebarItemsTsx = () => { import Link from "next/link"; import { usePathname } from "next/navigation"; -import { LucideIcon } from "lucide-react"; +import type { LucideIcon } from "lucide-react"; ${ componentLib === "shadcn-ui" @@ -260,7 +260,7 @@ const SidebarLinkGroup = ({ border?: boolean; }) => { const fullPathname = usePathname(); - const pathname = "/" + fullPathname.split("/")[1]; + const pathname = \`/\${fullPathname.split("/")[1]}\`; return (
@@ -347,7 +347,7 @@ import SidebarItems from "./SidebarItems";${ : null } -import { AuthSession, getUserAuth } from "${formatFilePath( +import { type AuthSession, getUserAuth } from "${formatFilePath( shared.auth.authUtils, { prefix: "alias", @@ -378,7 +378,7 @@ const UserDetails = ({ session }: { session: AuthSession }) => { if (session.session === null) return null; const { user } = session.session; - if (!user?.name || user.name.length == 0) return null; + if (!user?.name || user.name.length === 0) return null; return ( diff --git a/src/commands/add/misc/trpc/generators.ts b/src/commands/add/misc/trpc/generators.ts index 24adb779..55950a2e 100644 --- a/src/commands/add/misc/trpc/generators.ts +++ b/src/commands/add/misc/trpc/generators.ts @@ -52,7 +52,7 @@ export const protectedProcedure = t.procedure.use(enforceUserIsAuthed); `; const { trpc } = getFilePaths(); return `import { initTRPC, TRPCError } from "@trpc/server"; -import { Context } from "${formatFilePath(trpc.trpcContext, { +import type { Context } from "${formatFilePath(trpc.trpcContext, { prefix: "alias", removeExtension: true, })}"; @@ -121,7 +121,7 @@ export const apiTrpcRouteTs = () => { const { trpc, shared } = getFilePaths(); return `import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { NextRequest } from "next/server"; +import type { NextRequest } from "next/server"; import { appRouter } from "${formatFilePath(trpc.rootRouter, { prefix: "alias", removeExtension: true, @@ -166,7 +166,7 @@ export const libTrpcClientTs = () => { const { trpc } = getFilePaths(); return `import { createTRPCReact } from "@trpc/react-query"; -import { type AppRouter } from "${formatFilePath(trpc.rootRouter, { +import type { AppRouter } from "${formatFilePath(trpc.rootRouter, { prefix: "alias", removeExtension: true, })}"; @@ -180,7 +180,8 @@ export const libTrpcProviderTsx = () => { import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client"; -import React, { useState } from "react"; +import type React from "react"; +import { useState } from "react"; import { trpc } from "./client"; import { getUrl } from "./utils"; @@ -273,7 +274,7 @@ import { TRPCClientError, } from "@trpc/client"; import { callProcedure } from "@trpc/server"; -import { type TRPCErrorResponse } from "@trpc/server/rpc"; +import type { TRPCErrorResponse } from "@trpc/server/rpc"; import { observable } from "@trpc/server/observable"; import { cache } from "react"; @@ -386,7 +387,7 @@ export const libTrpcUtilsTs = () => { } export function getUrl() { - return getBaseUrl() + "/api/trpc"; + return \`\${getBaseUrl()}/api/trpc\`; }`; }; @@ -394,7 +395,7 @@ export const libTrpcApiTsBatchLink = () => { const { trpc } = getFilePaths(); return `import { cookies } from "next/headers"; -import { type AppRouter } from "${formatFilePath(trpc.rootRouter, { +import type { AppRouter } from "${formatFilePath(trpc.rootRouter, { prefix: "alias", removeExtension: true, })}"; From 96de08d732cd598df02cbcaa30fcdcfa0ab52ad7 Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Tue, 23 Apr 2024 13:13:35 +0200 Subject: [PATCH 3/3] found some errors worth fixing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ♦ defaultValues are now instead set to field values or empty string, this will remove any possible incompatible null vs unassigned ♦ when defaulting to Input fields: ``, an error occurs of incompatible field values, so deconstructing the value to `value={field.value || ''}` solves this error --- src/commands/generate/generators/views.ts | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/commands/generate/generators/views.ts b/src/commands/generate/generators/views.ts index 4442bb5d..5a98ced1 100644 --- a/src/commands/generate/generators/views.ts +++ b/src/commands/generate/generators/views.ts @@ -173,10 +173,10 @@ export default function ${tableNameSingularCapitalised}List({ ${tableNameCamelCa
    {${tableNameFirstChar}.${tableNameCamelCase}.map((${tableNameSingular}) => ( <${tableNameSingularCapitalised} ${tableNameSingular}={${tableNameSingular}} key={${ - relations.length > 0 - ? `${tableNameSingular}.${tableNameSingular}` - : tableNameSingular - }.id} /> + relations.length > 0 + ? `${tableNameSingular}.${tableNameSingular}` + : tableNameSingular + }.id} /> ))}
); @@ -191,18 +191,18 @@ const ${tableNameSingularCapitalised} = ({ ${tableNameSingular} }: { ${tableName ? `${tableNameSingular}.${tableNameSingular}` : tableNameSingular }.${toCamelCase(schema.fields[0].name)}${ - schema.fields[0].type === "date" || - schema.fields[0].type === "timestamp" || - schema.fields[0].type === "DateTime" - ? ".toString()" - : "" - }}
+ schema.fields[0].type === "date" || + schema.fields[0].type === "timestamp" || + schema.fields[0].type === "DateTime" + ? ".toString()" + : "" + }} <${tableNameSingularCapitalised}Modal ${tableNameSingular}={${ - relations.length > 0 - ? `${tableNameSingular}.${tableNameSingular}` - : tableNameSingular - }} /> + relations.length > 0 + ? `${tableNameSingular}.${tableNameSingular}` + : tableNameSingular + }} /> ); }; @@ -301,7 +301,7 @@ const createformInputComponent = (field: DBField): string => { `; return ` - + `; }; @@ -403,13 +403,13 @@ const ${tableNameSingularCapitalised}Form = ({ // open issue: https://github.com/colinhacks/zod/issues/2663 // errors locally but not in production resolver: zodResolver(insert${tableNameSingularCapitalised}Params), - defaultValues: ${tableNameSingular} ?? { + defaultValues: { ${schema.fields .map( (field) => - `${toCamelCase(field.name)}: ${ - defaultValueMappings[driver][field.type] - }` + `${toCamelCase(field.name)}: ${tableNameSingular}.${toCamelCase( + field.name + )} || ${defaultValueMappings[driver][field.type]}` ) .join(",\n ")} },