chore: migrate to biomejs

This commit is contained in:
BennyKok 2024-01-20 20:09:28 +08:00
parent c98a16a2dd
commit e400966117
20 changed files with 63 additions and 150 deletions

View File

@ -1,14 +1,13 @@
{ {
"recommendations": [ "recommendations": [
"DavidAnson.vscode-markdownlint", // markdown linting "DavidAnson.vscode-markdownlint", // markdown linting
"yzhang.markdown-all-in-one", // nicer markdown support
"esbenp.prettier-vscode", // prettier plugin "esbenp.prettier-vscode", // prettier plugin
"dbaeumer.vscode-eslint", // eslint plugin "dbaeumer.vscode-eslint", // eslint plugin
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind "bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
"ban.spellright", // Spell check for docs "ban.spellright", // Spell check for docs
"stripe.vscode-stripe", // stripe VSCode extension "stripe.vscode-stripe", // stripe VSCode extension
"Prisma.prisma", // syntax|format|completion for prisma
"rebornix.project-snippets", // Share useful snippets between collaborators "rebornix.project-snippets", // Share useful snippets between collaborators
"inlang.vs-code-extension" // improved i18n DX "inlang.vs-code-extension",
"biomejs.biome" // improved i18n DX
] ]
} }

View File

@ -1,8 +1,9 @@
{ {
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": false, "editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": true "quickfix.biome": true,
"source.organizeImports.biome": true
}, },
"typescript.preferences.importModuleSpecifier": "non-relative", "typescript.preferences.importModuleSpecifier": "non-relative",
"spellright.language": ["en"], "spellright.language": ["en"],

View File

@ -1,6 +0,0 @@
node_modules
**/node_modules
**/.next
**/public
packages/prisma/zod
apps/web/public/embed

View File

@ -1,95 +0,0 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: [
// "plugin:playwright/playwright-test",
"next",
// "next/core-web-vitals",
"plugin:prettier/recommended",
// "turbo",
// "plugin:you-dont-need-lodash-underscore/compatible-warn",
],
plugins: ["unused-imports"],
parserOptions: {
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
// project: ["./apps/*/tsconfig.json", "./packages/*/tsconfig.json"],
},
settings: {
next: {
// rootDir: ["apps/*/", "packages/*/"],
rootDir: ["src"],
},
},
rules: {
"@next/next/no-img-element": "off",
"@next/next/no-html-link-for-pages": "off",
"jsx-a11y/role-supports-aria-props": "off", // @see https://github.com/vercel/next.js/issues/27989#issuecomment-897638654
// "playwright/no-page-pause": "error",
"react/jsx-curly-brace-presence": [
"error",
{ props: "never", children: "never" },
],
"react/self-closing-comp": ["error", { component: true, html: true }],
"@typescript-eslint/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
},
],
"unused-imports/no-unused-imports": "error",
"no-restricted-imports": [
"error",
{
patterns: ["lodash"],
},
],
"prefer-template": "error",
},
overrides: [
{
files: ["*.ts", "*.tsx"],
extends: [
"plugin:@typescript-eslint/recommended",
// "plugin:@calcom/eslint/recommended",
],
plugins: [
"@typescript-eslint",
// "@calcom/eslint"
],
parser: "@typescript-eslint/parser",
rules: {
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: "type-imports",
// TODO: enable this once prettier supports it
// fixStyle: "inline-type-imports",
fixStyle: "separate-type-imports",
disallowTypeAnnotations: false,
},
],
},
// overrides: [
// {
// files: ["**/playwright/**/*.{tsx,ts}"],
// rules: {
// "@typescript-eslint/no-unused-vars": "off",
// "no-undef": "off",
// },
// },
// ],
},
// {
// files: ["**/playwright/**/*.{js,jsx}"],
// rules: {
// "@typescript-eslint/no-unused-vars": "off",
// "no-undef": "off",
// },
// },
],
};

18
web/biome.json Normal file
View File

@ -0,0 +1,18 @@
{
"$schema": "https://biomejs.dev/schemas/1.5.2/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
}
}

Binary file not shown.

View File

@ -12,7 +12,8 @@
"migrate-production": "bun run migrate.mts", "migrate-production": "bun run migrate.mts",
"migrate-local": "SSL=false LOCAL=true bun run migrate.mts", "migrate-local": "SSL=false LOCAL=true bun run migrate.mts",
"db-up": "docker-compose up", "db-up": "docker-compose up",
"db-dev": "bun run db-up && bun run migrate-local" "db-dev": "bun run db-up && bun run migrate-local",
"lint:fix": "bunx @biomejs/biome lint --apply ./src"
}, },
"dependencies": { "dependencies": {
"@algolia/autocomplete-core": "^1.13.0", "@algolia/autocomplete-core": "^1.13.0",
@ -105,26 +106,17 @@
"zustand": "^4.4.7" "zustand": "^4.4.7"
}, },
"devDependencies": { "devDependencies": {
"@trivago/prettier-plugin-sort-imports": "4.1.1", "@biomejs/biome": "1.5.2",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"autoprefixer": "^10.0.1", "autoprefixer": "^10.0.1",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"drizzle-kit": "^0.20.6", "drizzle-kit": "^0.20.6",
"eslint": "8.34.0", "eslint": "8.34.0",
"eslint-config-next": "^14.0.4",
"eslint-config-prettier": "^8.6.0",
"eslint-config-turbo": "latest",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unused-imports": "^3.0.0",
"postcss": "^8", "postcss": "^8",
"postgres": "^3.4.3", "postgres": "^3.4.3",
"prettier": "2.8.6",
"prettier-plugin-tailwindcss": "0.2.5",
"sharp": "^0.33.1", "sharp": "^0.33.1",
"tailwindcss": "^3.3.0", "tailwindcss": "^3.3.0",
"typescript": "^5" "typescript": "^5"

View File

@ -122,7 +122,7 @@ export function DeploymentDisplay({
<a <a
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts" href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
className="text-blue-500 hover:underline" className="text-blue-500 hover:underline"
target="_blank" target="_blank" rel="noreferrer"
> >
here here
</a> </a>

View File

@ -223,7 +223,7 @@ export const columns: ColumnDef<Machine>[] = [
href={machine.endpoint.replace( href={machine.endpoint.replace(
"comfyui-api", "comfyui-api",
"comfyui-app" "comfyui-app"
)} )} rel="noreferrer"
> >
Open ComfyUI Open ComfyUI
</a> </a>

View File

@ -98,7 +98,7 @@ export function Navbar() {
variant="outline" variant="outline"
className="rounded-full aspect-square p-2" className="rounded-full aspect-square p-2"
> >
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy"> <a target="_blank" href="https://github.com/BennyKok/comfyui-deploy" rel="noreferrer">
<Github /> <Github />
</a> </a>
</Button> </Button>

View File

@ -1,4 +1,3 @@
import { LiveStatus } from "./LiveStatus";
import { RunInputs } from "@/components/RunInputs"; import { RunInputs } from "@/components/RunInputs";
import { RunOutputs } from "@/components/RunOutputs"; import { RunOutputs } from "@/components/RunOutputs";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
@ -14,6 +13,7 @@ import { TableCell, TableRow } from "@/components/ui/table";
import { getDuration, getRelativeTime } from "@/lib/getRelativeTime"; import { getDuration, getRelativeTime } from "@/lib/getRelativeTime";
import { type findAllRuns } from "@/server/findAllRuns"; import { type findAllRuns } from "@/server/findAllRuns";
import { Suspense } from "react"; import { Suspense } from "react";
import { LiveStatus } from "./LiveStatus";
export async function RunDisplay({ export async function RunDisplay({
run, run,

View File

@ -1,6 +1,5 @@
"use client"; "use client";
import { useServerActionData } from "./useServerActionData";
import { ButtonAction } from "@/components/ButtonActionLoader"; import { ButtonAction } from "@/components/ButtonActionLoader";
import { UpdateModal } from "@/components/InsertModal"; import { UpdateModal } from "@/components/InsertModal";
import { LoadingPageWrapper } from "@/components/LoadingWrapper"; import { LoadingPageWrapper } from "@/components/LoadingWrapper";
@ -15,6 +14,7 @@ import { ExternalLink } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { useServerActionData } from "./useServerActionData";
export function SharePageSettings({ export function SharePageSettings({
deployment_id, deployment_id,

View File

@ -598,7 +598,7 @@ export function ViewWorkflowDetailsButton({
<a <a
href={group.url} href={group.url}
target="_blank" target="_blank"
className="hover:underline" className="hover:underline" rel="noreferrer"
> >
{key} {key}
<ExternalLink <ExternalLink

View File

@ -69,7 +69,7 @@ const FeedbackThanks = forwardRef<React.ElementRef<'div'>>(
) )
export function Feedback() { export function Feedback() {
let [submitted, setSubmitted] = useState(false) const [submitted, setSubmitted] = useState(false)
function onSubmit(event: React.FormEvent<HTMLFormElement>) { function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault() event.preventDefault()

View File

@ -8,7 +8,7 @@ export function Prose<T extends React.ElementType = 'div'>({
as?: T as?: T
className?: string className?: string
}) { }) {
let Component = as ?? 'div' const Component = as ?? 'div'
return ( return (
<Component <Component

View File

@ -22,9 +22,9 @@ function MoonIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
} }
export function ThemeToggle() { export function ThemeToggle() {
let { resolvedTheme, setTheme } = useTheme() const { resolvedTheme, setTheme } = useTheme()
let otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark' const otherTheme = resolvedTheme === 'dark' ? 'light' : 'dark'
let [mounted, setMounted] = useState(false) const [mounted, setMounted] = useState(false)
useEffect(() => { useEffect(() => {
setMounted(true) setMounted(true)

View File

@ -1,8 +1,10 @@
export function remToPx(remValue: number) { export function remToPx(remValue: number) {
let rootFontSize = const rootFontSize =
typeof window === 'undefined' typeof window === "undefined"
? 16 ? 16
: parseFloat(window.getComputedStyle(document.documentElement).fontSize) : parseFloat(
window.getComputedStyle(document.documentElement).fontSize,
);
return remValue * rootFontSize return remValue * rootFontSize
} }

View File

@ -27,13 +27,13 @@ function rehypeShiki() {
visit(tree, "element", (node) => { visit(tree, "element", (node) => {
if (node.tagName === "pre" && node.children[0]?.tagName === "code") { if (node.tagName === "pre" && node.children[0]?.tagName === "code") {
let codeNode = node.children[0]; const codeNode = node.children[0];
let textNode = codeNode.children[0]; const textNode = codeNode.children[0];
node.properties.code = textNode.value; node.properties.code = textNode.value;
if (node.properties.language) { if (node.properties.language) {
let tokens = highlighter.codeToThemedTokens( const tokens = highlighter.codeToThemedTokens(
textNode.value, textNode.value,
node.properties.language node.properties.language
); );
@ -53,7 +53,7 @@ function rehypeShiki() {
function rehypeSlugify() { function rehypeSlugify() {
return (tree) => { return (tree) => {
let slugify = slugifyWithCounter(); const slugify = slugifyWithCounter();
visit(tree, "element", (node) => { visit(tree, "element", (node) => {
if (node.tagName === "h2" && !node.properties.id) { if (node.tagName === "h2" && !node.properties.id) {
node.properties.id = slugify(toString(node)); node.properties.id = slugify(toString(node));
@ -64,10 +64,10 @@ function rehypeSlugify() {
function rehypeAddMDXExports(getExports) { function rehypeAddMDXExports(getExports) {
return (tree) => { return (tree) => {
let exports = Object.entries(getExports(tree)); const exports = Object.entries(getExports(tree));
for (let [name, value] of exports) { for (const [name, value] of exports) {
for (let node of tree.children) { for (const node of tree.children) {
if ( if (
node.type === "mdxjsEsm" && node.type === "mdxjsEsm" &&
new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value) new RegExp(`export\\s+const\\s+${name}\\s*=`).test(node.value)
@ -76,7 +76,7 @@ function rehypeAddMDXExports(getExports) {
} }
} }
let exportStr = `export const ${name} = ${value}`; const exportStr = `export const ${name} = ${value}`;
tree.children.push({ tree.children.push({
type: "mdxjsEsm", type: "mdxjsEsm",
@ -93,9 +93,9 @@ function rehypeAddMDXExports(getExports) {
} }
function getSections(node) { function getSections(node) {
let sections = []; const sections = [];
for (let child of node.children ?? []) { for (const child of node.children ?? []) {
if (child.type === "element" && child.tagName === "h2") { if (child.type === "element" && child.tagName === "h2") {
sections.push(`{ sections.push(`{
title: ${JSON.stringify(toString(child))}, title: ${JSON.stringify(toString(child))},

View File

@ -31,9 +31,9 @@ function extractSections() {
visit(tree, (node) => { visit(tree, (node) => {
if (node.type === "heading" || node.type === "paragraph") { if (node.type === "heading" || node.type === "paragraph") {
let content = toString(excludeObjectExpressions(node)); const content = toString(excludeObjectExpressions(node));
if (node.type === "heading" && node.depth <= 2) { if (node.type === "heading" && node.depth <= 2) {
let hash = node.depth === 1 ? null : slugify(content); const hash = node.depth === 1 ? null : slugify(content);
sections.push([content, hash, []]); sections.push([content, hash, []]);
} else { } else {
sections.at(-1)?.[2].push(content); sections.at(-1)?.[2].push(content);
@ -45,7 +45,7 @@ function extractSections() {
} }
export default function (nextConfig = {}) { export default function (nextConfig = {}) {
let cache = new Map(); const cache = new Map();
return Object.assign({}, nextConfig, { return Object.assign({}, nextConfig, {
webpack(config, options) { webpack(config, options) {
@ -53,20 +53,20 @@ export default function (nextConfig = {}) {
test: __filename, test: __filename,
use: [ use: [
createLoader(function () { createLoader(function () {
let appDir = path.resolve("./src/app/(docs)/docs"); const appDir = path.resolve("./src/app/(docs)/docs");
this.addContextDependency(appDir); this.addContextDependency(appDir);
let files = glob.sync("**/*.mdx", { cwd: appDir }); const files = glob.sync("**/*.mdx", { cwd: appDir });
let data = files.map((file) => { const data = files.map((file) => {
let url = `/${file.replace(/(^|\/)page\.mdx$/, "")}`; let url = `/${file.replace(/(^|\/)page\.mdx$/, "")}`;
let mdx = fs.readFileSync(path.join(appDir, file), "utf8"); const mdx = fs.readFileSync(path.join(appDir, file), "utf8");
let sections = []; let sections = [];
if (cache.get(file)?.[0] === mdx) { if (cache.get(file)?.[0] === mdx) {
sections = cache.get(file)[1]; sections = cache.get(file)[1];
} else { } else {
let vfile = { value: mdx, sections }; const vfile = { value: mdx, sections };
processor.runSync(processor.parse(vfile), vfile); processor.runSync(processor.parse(vfile), vfile);
cache.set(file, [mdx, sections]); cache.set(file, [mdx, sections]);
} }

View File

@ -1,4 +1,6 @@
import type { ResponseConfig } from "@asteasolutions/zod-to-openapi"; import type { ResponseConfig } from "@asteasolutions/zod-to-openapi";
import { z } from "@hono/zod-openapi"; import { z } from "@hono/zod-openapi";
export const authError = { export const authError = {