♻️ Replace eslint and prettier with biome (#1697)

This commit is contained in:
Luke Vella 2025-04-28 19:47:47 +01:00 committed by GitHub
parent 1577a0c5df
commit a34da49486
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
158 changed files with 450 additions and 2718 deletions

View file

@ -1,2 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -10,8 +10,7 @@
"checkout-expiry": "dotenv -e ../../.env -- tsx ./src/scripts/checkout-expiry.ts",
"subscription-data-sync": "dotenv -e ../../.env -- tsx ./src/scripts/subscription-data-sync.ts",
"sync-payment-methods": "dotenv -e ../../.env -- tsx ./src/scripts/sync-payment-methods.ts",
"type-check": "tsc --pretty --noEmit",
"lint": "eslint ./src"
"type-check": "tsc --pretty --noEmit"
},
"dependencies": {
"@radix-ui/react-radio-group": "^1.2.3",
@ -20,7 +19,6 @@
"stripe": "^13.2.0"
},
"devDependencies": {
"@rallly/eslint-config": "workspace:*",
"@rallly/tsconfig": "workspace:*"
}
}

View file

@ -1,4 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
...require("@rallly/eslint-config")(__dirname),
};

View file

@ -8,6 +8,7 @@ const prismaClientSingleton = () => {
export type ExtendedPrismaClient = ReturnType<typeof prismaClientSingleton>;
// biome-ignore lint/suspicious/noShadowRestrictedNames: Fix this later
declare const globalThis: {
prismaGlobal: ExtendedPrismaClient;
} & typeof global;

View file

@ -17,7 +17,6 @@
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"@rallly/eslint-config": "workspace:*",
"@rallly/tsconfig": "workspace:*",
"@types/node": "^18.19.41",
"prisma": "^6.4.1",

View file

@ -1,8 +1,8 @@
import { faker } from "@faker-js/faker";
import type { User } from "@prisma/client";
import { VoteType } from "@prisma/client";
import dayjs from "dayjs";
import type { VoteType } from "@prisma/client";
import { prisma } from "@rallly/database";
import dayjs from "dayjs";
import { randInt } from "./utils";

View file

@ -1,7 +1,7 @@
import { ScheduledEventInviteStatus } from "@prisma/client";
import { Prisma, ScheduledEventStatus } from "@prisma/client"; // Ensure Prisma is imported
import dayjs from "dayjs";
import { faker } from "@faker-js/faker";
import type { ScheduledEventInviteStatus } from "@prisma/client";
import { type Prisma, ScheduledEventStatus } from "@prisma/client"; // Ensure Prisma is imported
import dayjs from "dayjs";
import { prisma } from "@rallly/database";
import { randInt } from "./utils";

View file

@ -1,5 +1,5 @@
import dayjs from "dayjs";
import { prisma } from "@rallly/database";
import dayjs from "dayjs";
export async function seedUsers() {
console.info("Seeding users...");

View file

@ -1,2 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -4,7 +4,6 @@
"private": true,
"scripts": {
"dev": "email dev --port 3333 --dir ./src/previews",
"lint": "eslint ./src",
"type-check": "tsc --pretty --noEmit",
"i18n:scan": "i18next-scanner --config i18next-scanner.config.js"
},

View file

@ -10,7 +10,7 @@ import {
import { Trans } from "react-i18next/TransWithoutContext";
import type { EmailContext } from "../types";
import { darkTextColor, fontFamily, Link, Text } from "./styled-components";
import { Link, Text, darkTextColor, fontFamily } from "./styled-components";
export interface EmailLayoutProps {
preview: string;

View file

@ -97,7 +97,7 @@ export class EmailClient {
const subject = Template.getSubject?.(options.props, ctx);
const component = (
<Template
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: Fix this later
{...(options.props as any)}
ctx={ctx}
/>
@ -134,7 +134,7 @@ export class EmailClient {
}
async sendEmail(options: Mail.Options) {
if (!process.env["SUPPORT_EMAIL"]) {
if (!process.env.SUPPORT_EMAIL) {
console.info(" SUPPORT_EMAIL not configured - skipping email send");
return;
}
@ -170,21 +170,21 @@ export class EmailClient {
break;
}
case "smtp": {
const hasAuth = process.env["SMTP_USER"] || process.env["SMTP_PWD"];
const hasAuth = process.env.SMTP_USER || process.env.SMTP_PWD;
this.cachedTransport = createTransport({
host: process.env["SMTP_HOST"],
port: process.env["SMTP_PORT"]
? parseInt(process.env["SMTP_PORT"])
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT
? Number.parseInt(process.env.SMTP_PORT)
: undefined,
secure: process.env["SMTP_SECURE"] === "true",
secure: process.env.SMTP_SECURE === "true",
auth: hasAuth
? {
user: process.env["SMTP_USER"],
pass: process.env["SMTP_PWD"],
user: process.env.SMTP_USER,
pass: process.env.SMTP_PWD,
}
: undefined,
tls: {
rejectUnauthorized: process.env["SMTP_TLS_ENABLED"] === "true",
rejectUnauthorized: process.env.SMTP_TLS_ENABLED === "true",
},
});
break;

View file

@ -133,14 +133,11 @@ AbandonedCheckoutEmail.getSubject = (
props: AbandonedCheckoutEmailProps,
ctx: EmailContext,
) => {
return (
"🎉 " +
ctx.t("abandoned_checkout_subject", {
defaultValue: "Get {{discount}}% off your first year of Rallly Pro",
discount: props.discount,
ns: "emails",
})
);
return `🎉 ${ctx.t("abandoned_checkout_subject", {
defaultValue: "Get {{discount}}% off your first year of Rallly Pro",
discount: props.discount,
ns: "emails",
})}`;
};
export default AbandonedCheckoutEmail;

View file

@ -3,10 +3,10 @@ import { Trans } from "react-i18next/TransWithoutContext";
import { EmailLayout } from "../components/email-layout";
import {
borderColor,
Button,
Heading,
Text,
borderColor,
} from "../components/styled-components";
import type { EmailContext } from "../types";

View file

@ -3,10 +3,10 @@ import { Trans } from "react-i18next/TransWithoutContext";
import { EmailLayout } from "../components/email-layout";
import {
borderColor,
Button,
Heading,
Text,
borderColor,
} from "../components/styled-components";
import type { EmailContext } from "../types";

View file

@ -1,8 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["turbo"],
env: {
node: true,
},
};

View file

@ -1,11 +0,0 @@
const preset = require("./preset");
/** @return {import("eslint").Linter.Config} */
module.exports = function (workspaceDirPath) {
const baseConfig = preset(workspaceDirPath);
return {
...baseConfig,
extends: [...baseConfig.extends, "next"],
};
};

View file

@ -1,19 +0,0 @@
{
"name": "@rallly/eslint-config",
"version": "0.0.0",
"exports": {
"./*": "./*.js"
},
"private": true,
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0",
"eslint-config-next": "^14.0.1",
"eslint-config-turbo": "^2.0.3",
"eslint-import-resolver-typescript": "^2.7.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0"
}
}

View file

@ -1,52 +0,0 @@
/** @return {import("eslint").Linter.Config} */
module.exports = function (workspaceDirPath) {
return {
root: true,
extends: ["turbo"],
plugins: [
"eslint-plugin-import",
"simple-import-sort",
"@typescript-eslint",
],
env: {
es6: true,
},
ignorePatterns: ["dist/", "playwright-report/"],
globals: {
React: true,
JSX: true,
},
parserOptions: {
tsconfigRootDir: workspaceDirPath,
project: workspaceDirPath + "/tsconfig.json",
},
overrides: [
{
files: ["**/*.ts", "**/*.tsx"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
extends: ["plugin:@typescript-eslint/recommended"],
rules: {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: "type-imports",
fixStyle: "separate-type-imports",
disallowTypeAnnotations: true,
},
],
},
},
],
rules: {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
"no-console": ["error", { allow: ["warn", "error", "info"] }],
"no-unused-vars": "error",
},
};
};

View file

@ -1,20 +0,0 @@
const preset = require("./preset");
/** @return {import("eslint").Linter.Config} */
module.exports = function (workspaceDirPath) {
const baseConfig = preset(workspaceDirPath);
return {
...baseConfig,
extends: [
...baseConfig.extends,
"plugin:react/recommended",
"plugin:react-hooks/recommended",
],
settings: {
react: {
version: "detect",
},
},
};
};

View file

@ -1,6 +1,6 @@
import languages, { defaultLocale } from "./index";
import Negotiator from "negotiator";
import { match } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";
import languages, { defaultLocale } from "./index";
const locales = Object.keys(languages);

View file

@ -1,2 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -8,7 +8,6 @@
"./utils": "./src/utils.ts"
},
"scripts": {
"lint": "eslint ./src",
"type-check": "tsc --noEmit"
},
"dependencies": {
@ -17,7 +16,6 @@
"posthog-node": "^4.10.2"
},
"devDependencies": {
"@rallly/eslint-config": "workspace:*",
"@rallly/tsconfig": "workspace:*",
"@types/js-cookie": "^3.0.1"
}

View file

@ -1,2 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -6,7 +6,6 @@
"types": "src/index.ts",
"scripts": {
"ui:add": "npx shadcn-ui@latest add",
"lint": "eslint .",
"type-check": "tsc --noEmit"
},
"exports": {
@ -46,7 +45,6 @@
"tailwind-merge": "^1.12.0"
},
"devDependencies": {
"@rallly/eslint-config": "workspace:*",
"@rallly/tsconfig": "workspace:*",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"

View file

@ -1,5 +1,5 @@
import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react";
import type * as React from "react";
import { cn } from "./lib/utils";

View file

@ -63,7 +63,6 @@ const BreadcrumbPage = React.forwardRef<
>(({ className, ...props }, ref) => (
<span
ref={ref}
role="link"
aria-disabled="true"
aria-current="page"
className={cn("text-foreground font-normal", className)}

View file

@ -1,7 +1,7 @@
import type React from "react";
type ComponentPropsAs<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: Fix this later
C extends React.ElementType<any>,
T extends React.ComponentPropsWithoutRef<C>["as"],
> = Omit<

View file

@ -91,6 +91,7 @@ export const reducer = (state: State, action: Action): State => {
if (toastId) {
addToRemoveQueue(toastId);
} else {
// biome-ignore lint/complexity/noForEach: Fix this later
state.toasts.forEach((toast) => {
addToRemoveQueue(toast.id);
});
@ -128,6 +129,7 @@ let memoryState: State = { toasts: [] };
function dispatch(action: Action) {
memoryState = reducer(memoryState, action);
// biome-ignore lint/complexity/noForEach: Fix this later
listeners.forEach((listener) => {
listener(memoryState);
});
@ -167,6 +169,7 @@ function toast({ ...props }: Toast) {
function useToast() {
const [state, setState] = React.useState<State>(memoryState);
// biome-ignore lint/correctness/useExhaustiveDependencies: I think this needs to be here
React.useEffect(() => {
listeners.push(setState);
return () => {

View file

@ -102,7 +102,7 @@ const SidebarProvider = React.forwardRef<
return isMobile
? setOpenMobile((open) => !open)
: setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]);
}, [isMobile, setOpen]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
@ -134,15 +134,7 @@ const SidebarProvider = React.forwardRef<
setOpenMobile,
toggleSidebar,
}),
[
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
],
[state, open, setOpen, isMobile, openMobile, toggleSidebar],
);
return (

View file

@ -1,4 +1,4 @@
import { cn } from "./lib/utils"
import { cn } from "./lib/utils";
function Skeleton({
className,
@ -9,7 +9,7 @@ function Skeleton({
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
)
);
}
export { Skeleton }
export { Skeleton };

View file

@ -14,20 +14,16 @@ export function Toaster() {
return (
<ToastProvider duration={2000}>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
);
})}
{toasts.map(({ id, title, description, action, ...props }) => (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && <ToastDescription>{description}</ToastDescription>}
</div>
{action}
<ToastClose />
</Toast>
))}
<ToastViewport />
</ToastProvider>
);

View file

@ -1,2 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -4,7 +4,6 @@
"private": true,
"scripts": {
"test:unit": "vitest run",
"lint": "eslint ./src",
"type-check": "tsc --noEmit"
},
"exports": {

View file

@ -7,6 +7,7 @@ describe("absoluteUrl", () => {
});
afterAll(() => {
// biome-ignore lint/performance/noDelete: Setting to undefined doesn't work
delete process.env.NEXT_PUBLIC_BASE_URL;
});
@ -37,10 +38,6 @@ describe("absoluteUrl", () => {
process.env.NEXT_PUBLIC_VERCEL_URL = "example.vercel.com";
});
afterAll(() => {
delete process.env.NEXT_PUBLIC_VERCEL_URL;
});
it("should return the correct absolute URL with a subpath and query params", () => {
expect(absoluteUrl("/test", { test: "test" })).toBe(
"https://example.vercel.com/test?test=test",

View file

@ -23,6 +23,7 @@ export function absoluteUrl(subpath = "", query: Record<string, string> = {}) {
const url = new URL(subpath, baseUrl);
// biome-ignore lint/complexity/noForEach: Fix this later
Object.entries(query).forEach(([key, value]) => {
url.searchParams.set(key, value);
});

View file

@ -1,4 +1,4 @@
import path from "path";
import path from "node:path";
import { defineConfig } from "vitest/config";
export default defineConfig({