Skip to content

Commit 081ab3b

Browse files
committed
feat: fix biome linting
1 parent 03b1972 commit 081ab3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+784
-784
lines changed

.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ yarn.lock
3737
*.tsbuildinfo
3838
next-env.d.ts
3939

40-
# vscode
41-
.vscode
4240

4341
# intellij
4442
.idea

.vscode/extensions.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"recommendations": [
3+
"yoavbls.pretty-ts-errors",
4+
"bradlc.vscode-tailwindcss",
5+
"biomejs.biome"
6+
]
7+
}
8+

.vscode/settings.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"editor.codeActionsOnSave": {
3+
"source.organizeImports.biome": "explicit",
4+
"source.fixAll.biome": "explicit",
5+
// "quickfix.biome": "explicit"
6+
},
7+
"editor.defaultFormatter": "biomejs.biome",
8+
"editor.formatOnSave": true,
9+
"tailwindCSS.experimental.classRegex": [
10+
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
11+
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
12+
],
13+
"typescript.enablePromptUseWorkspaceTsdk": true,
14+
"typescript.tsdk": "node_modules/typescript/lib",
15+
16+
"typescript.preferences.autoImportFileExcludePatterns": [
17+
"next/router.d.ts",
18+
"next/dist/client/router.d.ts"
19+
],
20+
"[typescriptreact]": {
21+
"editor.defaultFormatter": "biomejs.biome"
22+
},
23+
"[typescript]": {
24+
"editor.defaultFormatter": "biomejs.biome"
25+
},
26+
"[json]": {
27+
"editor.defaultFormatter": "vscode.json-language-features"
28+
}
29+
}

apps/web/app/api/generate/route.ts

+51-57
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,129 @@
1-
import OpenAI from 'openai';
2-
import { OpenAIStream, StreamingTextResponse } from 'ai';
3-
import { kv } from '@vercel/kv';
4-
import { Ratelimit } from '@upstash/ratelimit';
5-
import { match } from 'ts-pattern';
6-
import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs';
1+
import { Ratelimit } from "@upstash/ratelimit";
2+
import { kv } from "@vercel/kv";
3+
import { OpenAIStream, StreamingTextResponse } from "ai";
4+
import OpenAI from "openai";
5+
import type { ChatCompletionMessageParam } from "openai/resources/index.mjs";
6+
import { match } from "ts-pattern";
77

88
// Create an OpenAI API client (that's edge friendly!)
9-
// Using LLamma's OpenAI client:
109

1110
// IMPORTANT! Set the runtime to edge: https://vercel.com/docs/functions/edge-functions/edge-runtime
12-
export const runtime = 'edge';
13-
14-
const llama = new OpenAI({
15-
apiKey: 'ollama',
16-
baseURL: 'http://localhost:11434/v1',
17-
});
11+
export const runtime = "edge";
1812

1913
export async function POST(req: Request): Promise<Response> {
2014
const openai = new OpenAI({
2115
apiKey: process.env.OPENAI_API_KEY,
22-
baseURL: process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1',
16+
baseURL: process.env.OPENAI_BASE_URL || "https://api.openai.com/v1",
2317
});
2418
// Check if the OPENAI_API_KEY is set, if not return 400
25-
if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY === '') {
26-
return new Response('Missing OPENAI_API_KEY - make sure to add it to your .env file.', {
19+
if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY === "") {
20+
return new Response("Missing OPENAI_API_KEY - make sure to add it to your .env file.", {
2721
status: 400,
2822
});
2923
}
3024
if (process.env.KV_REST_API_URL && process.env.KV_REST_API_TOKEN) {
31-
const ip = req.headers.get('x-forwarded-for');
25+
const ip = req.headers.get("x-forwarded-for");
3226
const ratelimit = new Ratelimit({
3327
redis: kv,
34-
limiter: Ratelimit.slidingWindow(50, '1 d'),
28+
limiter: Ratelimit.slidingWindow(50, "1 d"),
3529
});
3630

3731
const { success, limit, reset, remaining } = await ratelimit.limit(`novel_ratelimit_${ip}`);
3832

3933
if (!success) {
40-
return new Response('You have reached your request limit for the day.', {
34+
return new Response("You have reached your request limit for the day.", {
4135
status: 429,
4236
headers: {
43-
'X-RateLimit-Limit': limit.toString(),
44-
'X-RateLimit-Remaining': remaining.toString(),
45-
'X-RateLimit-Reset': reset.toString(),
37+
"X-RateLimit-Limit": limit.toString(),
38+
"X-RateLimit-Remaining": remaining.toString(),
39+
"X-RateLimit-Reset": reset.toString(),
4640
},
4741
});
4842
}
4943
}
5044

5145
const { prompt, option, command } = await req.json();
5246
const messages = match(option)
53-
.with('continue', () => [
47+
.with("continue", () => [
5448
{
55-
role: 'system',
49+
role: "system",
5650
content:
57-
'You are an AI writing assistant that continues existing text based on context from prior text. ' +
58-
'Give more weight/priority to the later characters than the beginning ones. ' +
59-
'Limit your response to no more than 200 characters, but make sure to construct complete sentences.' +
60-
'Use Markdown formatting when appropriate.',
51+
"You are an AI writing assistant that continues existing text based on context from prior text. " +
52+
"Give more weight/priority to the later characters than the beginning ones. " +
53+
"Limit your response to no more than 200 characters, but make sure to construct complete sentences." +
54+
"Use Markdown formatting when appropriate.",
6155
},
6256
{
63-
role: 'user',
57+
role: "user",
6458
content: prompt,
6559
},
6660
])
67-
.with('improve', () => [
61+
.with("improve", () => [
6862
{
69-
role: 'system',
63+
role: "system",
7064
content:
71-
'You are an AI writing assistant that improves existing text. ' +
72-
'Limit your response to no more than 200 characters, but make sure to construct complete sentences.' +
73-
'Use Markdown formatting when appropriate.',
65+
"You are an AI writing assistant that improves existing text. " +
66+
"Limit your response to no more than 200 characters, but make sure to construct complete sentences." +
67+
"Use Markdown formatting when appropriate.",
7468
},
7569
{
76-
role: 'user',
70+
role: "user",
7771
content: `The existing text is: ${prompt}`,
7872
},
7973
])
80-
.with('shorter', () => [
74+
.with("shorter", () => [
8175
{
82-
role: 'system',
76+
role: "system",
8377
content:
84-
'You are an AI writing assistant that shortens existing text. ' + 'Use Markdown formatting when appropriate.',
78+
"You are an AI writing assistant that shortens existing text. " + "Use Markdown formatting when appropriate.",
8579
},
8680
{
87-
role: 'user',
81+
role: "user",
8882
content: `The existing text is: ${prompt}`,
8983
},
9084
])
91-
.with('longer', () => [
85+
.with("longer", () => [
9286
{
93-
role: 'system',
87+
role: "system",
9488
content:
95-
'You are an AI writing assistant that lengthens existing text. ' +
96-
'Use Markdown formatting when appropriate.',
89+
"You are an AI writing assistant that lengthens existing text. " +
90+
"Use Markdown formatting when appropriate.",
9791
},
9892
{
99-
role: 'user',
93+
role: "user",
10094
content: `The existing text is: ${prompt}`,
10195
},
10296
])
103-
.with('fix', () => [
97+
.with("fix", () => [
10498
{
105-
role: 'system',
99+
role: "system",
106100
content:
107-
'You are an AI writing assistant that fixes grammar and spelling errors in existing text. ' +
108-
'Limit your response to no more than 200 characters, but make sure to construct complete sentences.' +
109-
'Use Markdown formatting when appropriate.',
101+
"You are an AI writing assistant that fixes grammar and spelling errors in existing text. " +
102+
"Limit your response to no more than 200 characters, but make sure to construct complete sentences." +
103+
"Use Markdown formatting when appropriate.",
110104
},
111105
{
112-
role: 'user',
106+
role: "user",
113107
content: `The existing text is: ${prompt}`,
114108
},
115109
])
116-
.with('zap', () => [
110+
.with("zap", () => [
117111
{
118-
role: 'system',
112+
role: "system",
119113
content:
120-
'You area an AI writing assistant that generates text based on a prompt. ' +
121-
'You take an input from the user and a command for manipulating the text' +
122-
'Use Markdown formatting when appropriate.',
114+
"You area an AI writing assistant that generates text based on a prompt. " +
115+
"You take an input from the user and a command for manipulating the text" +
116+
"Use Markdown formatting when appropriate.",
123117
},
124118
{
125-
role: 'user',
119+
role: "user",
126120
content: `For this text: ${prompt}. You have to respect the command: ${command}`,
127121
},
128122
])
129123
.run() as ChatCompletionMessageParam[];
130124

131125
const response = await openai.chat.completions.create({
132-
model: 'gpt-3.5-turbo',
126+
model: "gpt-3.5-turbo",
133127
stream: true,
134128
messages,
135129
temperature: 0.7,

apps/web/app/api/upload/route.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { put } from '@vercel/blob';
2-
import { NextResponse } from 'next/server';
1+
import { put } from "@vercel/blob";
2+
import { NextResponse } from "next/server";
33

4-
export const runtime = 'edge';
4+
export const runtime = "edge";
55

66
export async function POST(req: Request) {
77
if (!process.env.BLOB_READ_WRITE_TOKEN) {
@@ -10,16 +10,16 @@ export async function POST(req: Request) {
1010
});
1111
}
1212

13-
const file = req.body || '';
14-
const filename = req.headers.get('x-vercel-filename') || 'file.txt';
15-
const contentType = req.headers.get('content-type') || 'text/plain';
16-
const fileType = `.${contentType.split('/')[1]}`;
13+
const file = req.body || "";
14+
const filename = req.headers.get("x-vercel-filename") || "file.txt";
15+
const contentType = req.headers.get("content-type") || "text/plain";
16+
const fileType = `.${contentType.split("/")[1]}`;
1717

1818
// construct final filename based on content-type if not provided
1919
const finalName = filename.includes(fileType) ? filename : `${filename}${fileType}`;
2020
const blob = await put(finalName, file, {
2121
contentType,
22-
access: 'public',
22+
access: "public",
2323
});
2424

2525
return NextResponse.json(blob);

apps/web/app/layout.tsx

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import '@/styles/globals.css';
2-
import '@/styles/prosemirror.css';
1+
import "@/styles/globals.css";
2+
import "@/styles/prosemirror.css";
33

4-
import type { Metadata, Viewport } from 'next';
5-
import type { ReactNode } from 'react';
6-
import Providers from './providers';
4+
import type { Metadata, Viewport } from "next";
5+
import type { ReactNode } from "react";
6+
import Providers from "./providers";
77

8-
const title = 'Novel - Notion-style WYSIWYG editor with AI-powered autocompletions';
8+
const title = "Novel - Notion-style WYSIWYG editor with AI-powered autocompletions";
99
const description =
10-
'Novel is a Notion-style WYSIWYG editor with AI-powered autocompletions. Built with Tiptap, OpenAI, and Vercel AI SDK.';
10+
"Novel is a Notion-style WYSIWYG editor with AI-powered autocompletions. Built with Tiptap, OpenAI, and Vercel AI SDK.";
1111

1212
export const metadata: Metadata = {
1313
title,
@@ -19,14 +19,14 @@ export const metadata: Metadata = {
1919
twitter: {
2020
title,
2121
description,
22-
card: 'summary_large_image',
23-
creator: '@steventey',
22+
card: "summary_large_image",
23+
creator: "@steventey",
2424
},
25-
metadataBase: new URL('https://novel.sh'),
25+
metadataBase: new URL("https://novel.sh"),
2626
};
2727

2828
export const viewport: Viewport = {
29-
themeColor: '#ffffff',
29+
themeColor: "#ffffff",
3030
};
3131

3232
export default function RootLayout({ children }: { children: ReactNode }) {

apps/web/app/page.tsx

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import { Github } from '@/components/tailwind/ui/icons';
2-
import { Button } from '@/components/tailwind/ui/button';
3-
import Menu from '@/components/tailwind/ui/menu';
4-
import Link from 'next/link';
5-
import TailwindAdvancedEditor from '@/components/tailwind/advanced-editor';
6-
import { Dialog, DialogContent, DialogTrigger } from '@/components/tailwind/ui/dialog';
7-
import { ScrollArea } from '@/components/tailwind/ui/scroll-area';
8-
import { BookOpen } from 'lucide-react';
1+
import TailwindAdvancedEditor from "@/components/tailwind/advanced-editor";
2+
import { Button } from "@/components/tailwind/ui/button";
3+
import { Dialog, DialogContent, DialogTrigger } from "@/components/tailwind/ui/dialog";
4+
import Menu from "@/components/tailwind/ui/menu";
5+
import { ScrollArea } from "@/components/tailwind/ui/scroll-area";
6+
import { BookOpen, GithubIcon } from "lucide-react";
7+
import Link from "next/link";
98

109
export default function Page() {
1110
return (
1211
<div className="flex min-h-screen flex-col items-center gap-4 py-4 sm:px-5">
1312
<div className="flex w-full max-w-screen-lg items-center gap-2 px-4 sm:mb-[calc(20vh)]">
1413
<Button size="icon" variant="outline">
1514
<a href="https://github.com/steven-tey/novel" target="_blank" rel="noreferrer">
16-
<Github />
15+
<GithubIcon />
1716
</a>
1817
</Button>
1918
<Dialog>

apps/web/app/providers.tsx

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
'use client';
1+
"use client";
22

3-
import { type Dispatch, type ReactNode, type SetStateAction, createContext } from 'react';
4-
import { ThemeProvider, useTheme } from 'next-themes';
5-
import { Toaster } from 'sonner';
6-
import { Analytics } from '@vercel/analytics/react';
7-
import useLocalStorage from '@/hooks/use-local-storage';
3+
import { type Dispatch, type ReactNode, type SetStateAction, createContext } from "react";
4+
import { ThemeProvider, useTheme } from "next-themes";
5+
import { Toaster } from "sonner";
6+
import { Analytics } from "@vercel/analytics/react";
7+
import useLocalStorage from "@/hooks/use-local-storage";
88

99
export const AppContext = createContext<{
1010
font: string;
1111
setFont: Dispatch<SetStateAction<string>>;
1212
}>({
13-
font: 'Default',
13+
font: "Default",
1414
setFont: () => {},
1515
});
1616

1717
const ToasterProvider = () => {
1818
const { theme } = useTheme() as {
19-
theme: 'light' | 'dark' | 'system';
19+
theme: "light" | "dark" | "system";
2020
};
2121
return <Toaster theme={theme} />;
2222
};
2323

2424
export default function Providers({ children }: { children: ReactNode }) {
25-
const [font, setFont] = useLocalStorage<string>('novel__font', 'Default');
25+
const [font, setFont] = useLocalStorage<string>("novel__font", "Default");
2626

2727
return (
2828
<ThemeProvider attribute="class" enableSystem disableTransitionOnChange defaultTheme="system">

0 commit comments

Comments
 (0)