chore(eslint): enforce consistent import paths (#8)

This commit is contained in:
Dominic Elm 2024-07-24 17:43:32 +02:00 committed by GitHub
parent d45b95dd11
commit 2a3d5f569e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 102 additions and 85 deletions

View File

@ -1,9 +1,10 @@
import blitzPlugin from '@blitz/eslint-plugin'; import blitzPlugin from '@blitz/eslint-plugin';
import { getNamingConventionRule } from '@blitz/eslint-plugin/dist/configs/typescript.js'; import { jsFileExtensions } from '@blitz/eslint-plugin/dist/configs/javascript.js';
import { getNamingConventionRule, tsFileExtensions } from '@blitz/eslint-plugin/dist/configs/typescript.js';
export default [ export default [
{ {
ignores: ['**/dist', '**/node_modules'], ignores: ['**/dist', '**/node_modules', '**/.wrangler', '**/bolt/build'],
}, },
...blitzPlugin.configs.recommended(), ...blitzPlugin.configs.recommended(),
{ {
@ -25,4 +26,20 @@ export default [
'@typescript-eslint/no-empty-object-type': 'off', '@typescript-eslint/no-empty-object-type': 'off',
}, },
}, },
{
files: [...tsFileExtensions, ...jsFileExtensions, '**/*.tsx'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['../'],
message: `Relative imports are not allowed. Please use '~/' instead.`,
},
],
},
],
},
},
]; ];

View File

@ -3,11 +3,11 @@ import { AnimatePresence, motion } from 'framer-motion';
import { computed } from 'nanostores'; import { computed } from 'nanostores';
import { memo, useEffect, useRef, useState } from 'react'; import { memo, useEffect, useRef, useState } from 'react';
import { createHighlighter, type BundledLanguage, type BundledTheme, type HighlighterGeneric } from 'shiki'; import { createHighlighter, type BundledLanguage, type BundledTheme, type HighlighterGeneric } from 'shiki';
import type { ActionState } from '../../lib/runtime/action-runner'; import type { ActionState } from '~/lib/runtime/action-runner';
import { chatStore } from '../../lib/stores/chat'; import { chatStore } from '~/lib/stores/chat';
import { workbenchStore } from '../../lib/stores/workbench'; import { workbenchStore } from '~/lib/stores/workbench';
import { classNames } from '../../utils/classNames'; import { classNames } from '~/utils/classNames';
import { cubicEasingFn } from '../../utils/easings'; import { cubicEasingFn } from '~/utils/easings';
const highlighterOptions = { const highlighterOptions = {
langs: ['shell'], langs: ['shell'],

View File

@ -1,9 +1,9 @@
import type { Message } from 'ai'; import type { Message } from 'ai';
import React, { type LegacyRef, type RefCallback } from 'react'; import React, { type LegacyRef, type RefCallback } from 'react';
import { ClientOnly } from 'remix-utils/client-only'; import { ClientOnly } from 'remix-utils/client-only';
import { classNames } from '../../utils/classNames'; import { IconButton } from '~/components/ui/IconButton';
import { IconButton } from '../ui/IconButton'; import { Workbench } from '~/components/workbench/Workbench.client';
import { Workbench } from '../workbench/Workbench.client'; import { classNames } from '~/utils/classNames';
import { Messages } from './Messages.client'; import { Messages } from './Messages.client';
import { SendButton } from './SendButton.client'; import { SendButton } from './SendButton.client';

View File

@ -2,11 +2,11 @@ import { useChat } from 'ai/react';
import { useAnimate } from 'framer-motion'; import { useAnimate } from 'framer-motion';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { ToastContainer, cssTransition } from 'react-toastify'; import { ToastContainer, cssTransition } from 'react-toastify';
import { useMessageParser, usePromptEnhancer, useSnapScroll } from '../../lib/hooks'; import { useMessageParser, usePromptEnhancer, useSnapScroll } from '~/lib/hooks';
import { chatStore } from '../../lib/stores/chat'; import { chatStore } from '~/lib/stores/chat';
import { workbenchStore } from '../../lib/stores/workbench'; import { workbenchStore } from '~/lib/stores/workbench';
import { cubicEasingFn } from '../../utils/easings'; import { cubicEasingFn } from '~/utils/easings';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
import { BaseChat } from './BaseChat'; import { BaseChat } from './BaseChat';
const toastAnimation = cssTransition({ const toastAnimation = cssTransition({

View File

@ -1,7 +1,7 @@
import { memo, useEffect, useState } from 'react'; import { memo, useEffect, useState } from 'react';
import { bundledLanguages, codeToHtml, isSpecialLang, type BundledLanguage, type SpecialLanguage } from 'shiki'; import { bundledLanguages, codeToHtml, isSpecialLang, type BundledLanguage, type SpecialLanguage } from 'shiki';
import { classNames } from '../../utils/classNames'; import { classNames } from '~/utils/classNames';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
import styles from './CodeBlock.module.scss'; import styles from './CodeBlock.module.scss';
const logger = createScopedLogger('CodeBlock'); const logger = createScopedLogger('CodeBlock');

View File

@ -1,8 +1,8 @@
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import ReactMarkdown, { type Components } from 'react-markdown'; import ReactMarkdown, { type Components } from 'react-markdown';
import type { BundledLanguage } from 'shiki'; import type { BundledLanguage } from 'shiki';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
import { rehypePlugins, remarkPlugins } from '../../utils/markdown'; import { rehypePlugins, remarkPlugins } from '~/utils/markdown';
import { Artifact } from './Artifact'; import { Artifact } from './Artifact';
import { CodeBlock } from './CodeBlock'; import { CodeBlock } from './CodeBlock';

View File

@ -1,8 +1,8 @@
import type { Message } from 'ai'; import type { Message } from 'ai';
import { classNames } from '../../utils/classNames'; import React from 'react';
import { classNames } from '~/utils/classNames';
import { AssistantMessage } from './AssistantMessage'; import { AssistantMessage } from './AssistantMessage';
import { UserMessage } from './UserMessage'; import { UserMessage } from './UserMessage';
import React from 'react';
interface MessagesProps { interface MessagesProps {
id?: string; id?: string;

View File

@ -14,10 +14,10 @@ import {
scrollPastEnd, scrollPastEnd,
} from '@codemirror/view'; } from '@codemirror/view';
import { memo, useEffect, useRef, useState, type MutableRefObject } from 'react'; import { memo, useEffect, useRef, useState, type MutableRefObject } from 'react';
import type { Theme } from '../../../types/theme'; import type { Theme } from '~/types/theme';
import { classNames } from '../../../utils/classNames'; import { classNames } from '~/utils/classNames';
import { debounce } from '../../../utils/debounce'; import { debounce } from '~/utils/debounce';
import { createScopedLogger, renderLogger } from '../../../utils/logger'; import { createScopedLogger, renderLogger } from '~/utils/logger';
import { BinaryContent } from './BinaryContent'; import { BinaryContent } from './BinaryContent';
import { getTheme, reconfigureTheme } from './cm-theme'; import { getTheme, reconfigureTheme } from './cm-theme';
import { indentKeyBinding } from './indent'; import { indentKeyBinding } from './indent';

View File

@ -1,7 +1,7 @@
import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language'; import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { Compartment, type Extension } from '@codemirror/state'; import { Compartment, type Extension } from '@codemirror/state';
import { EditorView } from '@codemirror/view'; import { EditorView } from '@codemirror/view';
import type { Theme } from '../../../types/theme.js'; import type { Theme } from '~/types/theme.js';
import type { EditorSettings } from './CodeMirrorEditor.js'; import type { EditorSettings } from './CodeMirrorEditor.js';
import { vscodeDarkTheme } from './themes/vscode-dark.js'; import { vscodeDarkTheme } from './themes/vscode-dark.js';

View File

@ -1,5 +1,5 @@
import { memo } from 'react'; import { memo } from 'react';
import { classNames } from '../../utils/classNames'; import { classNames } from '~/utils/classNames';
type IconSize = 'sm' | 'md' | 'xl' | 'xxl'; type IconSize = 'sm' | 'md' | 'xl' | 'xxl';

View File

@ -1,5 +1,5 @@
import { memo } from 'react'; import { memo } from 'react';
import { classNames } from '../../utils/classNames'; import { classNames } from '~/utils/classNames';
interface PanelHeaderButtonProps { interface PanelHeaderButtonProps {
className?: string; className?: string;

View File

@ -1,10 +1,6 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import type { FileMap } from '../../lib/stores/files';
import { themeStore } from '../../lib/stores/theme';
import { renderLogger } from '../../utils/logger';
import { isMobile } from '../../utils/mobile';
import { import {
CodeMirrorEditor, CodeMirrorEditor,
type EditorDocument, type EditorDocument,
@ -12,8 +8,12 @@ import {
type OnChangeCallback as OnEditorChange, type OnChangeCallback as OnEditorChange,
type OnSaveCallback as OnEditorSave, type OnSaveCallback as OnEditorSave,
type OnScrollCallback as OnEditorScroll, type OnScrollCallback as OnEditorScroll,
} from '../editor/codemirror/CodeMirrorEditor'; } from '~/components/editor/codemirror/CodeMirrorEditor';
import { PanelHeaderButton } from '../ui/PanelHeaderButton'; import { PanelHeaderButton } from '~/components/ui/PanelHeaderButton';
import type { FileMap } from '~/lib/stores/files';
import { themeStore } from '~/lib/stores/theme';
import { renderLogger } from '~/utils/logger';
import { isMobile } from '~/utils/mobile';
import { FileTreePanel } from './FileTreePanel'; import { FileTreePanel } from './FileTreePanel';
interface EditorPanelProps { interface EditorPanelProps {

View File

@ -1,7 +1,7 @@
import { memo, useEffect, useMemo, useState, type ReactNode } from 'react'; import { memo, useEffect, useMemo, useState, type ReactNode } from 'react';
import type { FileMap } from '../../lib/stores/files'; import type { FileMap } from '~/lib/stores/files';
import { classNames } from '../../utils/classNames'; import { classNames } from '~/utils/classNames';
import { renderLogger } from '../../utils/logger'; import { renderLogger } from '~/utils/logger';
const NODE_PADDING_LEFT = 12; const NODE_PADDING_LEFT = 12;
const DEFAULT_HIDDEN_FILES = [/\/node_modules\//]; const DEFAULT_HIDDEN_FILES = [/\/node_modules\//];

View File

@ -1,7 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import type { FileMap } from '../../lib/stores/files'; import type { FileMap } from '~/lib/stores/files';
import { WORK_DIR } from '../../utils/constants'; import { WORK_DIR } from '~/utils/constants';
import { renderLogger } from '../../utils/logger'; import { renderLogger } from '~/utils/logger';
import { FileTree } from './FileTree'; import { FileTree } from './FileTree';
interface FileTreePanelProps { interface FileTreePanelProps {

View File

@ -1,7 +1,7 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { memo, useEffect, useRef, useState } from 'react'; import { memo, useEffect, useRef, useState } from 'react';
import { workbenchStore } from '../../lib/stores/workbench'; import { IconButton } from '~/components/ui/IconButton';
import { IconButton } from '../ui/IconButton'; import { workbenchStore } from '~/lib/stores/workbench';
export const Preview = memo(() => { export const Preview = memo(() => {
const iframeRef = useRef<HTMLIFrameElement>(null); const iframeRef = useRef<HTMLIFrameElement>(null);

View File

@ -3,14 +3,14 @@ import { AnimatePresence, motion, type Variants } from 'framer-motion';
import { memo, useCallback, useEffect } from 'react'; import { memo, useCallback, useEffect } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { workbenchStore } from '../../lib/stores/workbench';
import { cubicEasingFn } from '../../utils/easings';
import { renderLogger } from '../../utils/logger';
import { import {
type OnChangeCallback as OnEditorChange, type OnChangeCallback as OnEditorChange,
type OnScrollCallback as OnEditorScroll, type OnScrollCallback as OnEditorScroll,
} from '../editor/codemirror/CodeMirrorEditor'; } from '~/components/editor/codemirror/CodeMirrorEditor';
import { IconButton } from '../ui/IconButton'; import { IconButton } from '~/components/ui/IconButton';
import { workbenchStore } from '~/lib/stores/workbench';
import { cubicEasingFn } from '~/utils/easings';
import { renderLogger } from '~/utils/logger';
import { EditorPanel } from './EditorPanel'; import { EditorPanel } from './EditorPanel';
import { Preview } from './Preview'; import { Preview } from './Preview';

View File

@ -1,5 +1,5 @@
import { WORK_DIR } from '../../../utils/constants'; import { WORK_DIR } from '~/utils/constants';
import { stripIndents } from '../../../utils/stripIndent'; import { stripIndents } from '~/utils/stripIndent';
export const getSystemPrompt = (cwd: string = WORK_DIR) => ` export const getSystemPrompt = (cwd: string = WORK_DIR) => `
You are Bolt, an expert AI assistant and exceptional senior software developer with vast knowledge across multiple programming languages, frameworks, and best practices. You are Bolt, an expert AI assistant and exceptional senior software developer with vast knowledge across multiple programming languages, frameworks, and best practices.

View File

@ -1,6 +1,6 @@
import { streamText as _streamText, convertToCoreMessages } from 'ai'; import { streamText as _streamText, convertToCoreMessages } from 'ai';
import { getAPIKey } from '../llm/api-key'; import { getAPIKey } from '~/lib/.server/llm/api-key';
import { getAnthropicModel } from '../llm/model'; import { getAnthropicModel } from '~/lib/.server/llm/model';
import { MAX_TOKENS } from './constants'; import { MAX_TOKENS } from './constants';
import { getSystemPrompt } from './prompts'; import { getSystemPrompt } from './prompts';

View File

@ -1,8 +1,8 @@
import type { Message } from 'ai'; import type { Message } from 'ai';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { createScopedLogger } from '../../utils/logger'; import { StreamingMessageParser } from '~/lib/runtime/message-parser';
import { StreamingMessageParser } from '../runtime/message-parser'; import { workbenchStore } from '~/lib/stores/workbench';
import { workbenchStore } from '../stores/workbench'; import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('useMessageParser'); const logger = createScopedLogger('useMessageParser');

View File

@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('usePromptEnhancement'); const logger = createScopedLogger('usePromptEnhancement');

View File

@ -1,9 +1,9 @@
import { WebContainer } from '@webcontainer/api'; import { WebContainer } from '@webcontainer/api';
import { map, type MapStore } from 'nanostores'; import { map, type MapStore } from 'nanostores';
import * as nodePath from 'node:path'; import * as nodePath from 'node:path';
import type { BoltAction } from '../../types/actions'; import type { BoltAction } from '~/types/actions';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
import { unreachable } from '../../utils/unreachable'; import { unreachable } from '~/utils/unreachable';
import type { ActionCallbackData } from './message-parser'; import type { ActionCallbackData } from './message-parser';
const logger = createScopedLogger('ActionRunner'); const logger = createScopedLogger('ActionRunner');

View File

@ -1,7 +1,7 @@
import type { ActionType, BoltAction, BoltActionData, FileAction, ShellAction } from '../../types/actions'; import type { ActionType, BoltAction, BoltActionData, FileAction, ShellAction } from '~/types/actions';
import type { BoltArtifactData } from '../../types/artifact'; import type { BoltArtifactData } from '~/types/artifact';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
import { unreachable } from '../../utils/unreachable'; import { unreachable } from '~/utils/unreachable';
const ARTIFACT_TAG_OPEN = '<boltArtifact'; const ARTIFACT_TAG_OPEN = '<boltArtifact';
const ARTIFACT_TAG_CLOSE = '</boltArtifact>'; const ARTIFACT_TAG_CLOSE = '</boltArtifact>';

View File

@ -1,5 +1,5 @@
import { atom, computed, map, type MapStore, type WritableAtom } from 'nanostores'; import { atom, computed, map, type MapStore, type WritableAtom } from 'nanostores';
import type { EditorDocument, ScrollPosition } from '../../components/editor/codemirror/CodeMirrorEditor'; import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
import type { FileMap, FilesStore } from './files'; import type { FileMap, FilesStore } from './files';
export type EditorDocuments = Record<string, EditorDocument>; export type EditorDocuments = Record<string, EditorDocument>;

View File

@ -1,9 +1,9 @@
import type { PathWatcherEvent, WebContainer } from '@webcontainer/api'; import type { PathWatcherEvent, WebContainer } from '@webcontainer/api';
import { map, type MapStore } from 'nanostores'; import { map, type MapStore } from 'nanostores';
import * as nodePath from 'node:path'; import * as nodePath from 'node:path';
import { bufferWatchEvents } from '../../utils/buffer'; import { bufferWatchEvents } from '~/utils/buffer';
import { WORK_DIR } from '../../utils/constants'; import { WORK_DIR } from '~/utils/constants';
import { createScopedLogger } from '../../utils/logger'; import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('FilesStore'); const logger = createScopedLogger('FilesStore');

View File

@ -1,9 +1,9 @@
import { atom, map, type MapStore, type ReadableAtom, type WritableAtom } from 'nanostores'; import { atom, map, type MapStore, type ReadableAtom, type WritableAtom } from 'nanostores';
import type { EditorDocument, ScrollPosition } from '../../components/editor/codemirror/CodeMirrorEditor'; import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
import { unreachable } from '../../utils/unreachable'; import { ActionRunner } from '~/lib/runtime/action-runner';
import { ActionRunner } from '../runtime/action-runner'; import type { ActionCallbackData, ArtifactCallbackData } from '~/lib/runtime/message-parser';
import type { ActionCallbackData, ArtifactCallbackData } from '../runtime/message-parser'; import { webcontainer } from '~/lib/webcontainer';
import { webcontainer } from '../webcontainer'; import { unreachable } from '~/utils/unreachable';
import { EditorStore } from './editor'; import { EditorStore } from './editor';
import { FilesStore, type FileMap } from './files'; import { FilesStore, type FileMap } from './files';
import { PreviewsStore } from './previews'; import { PreviewsStore } from './previews';

View File

@ -1,5 +1,5 @@
import { WebContainer } from '@webcontainer/api'; import { WebContainer } from '@webcontainer/api';
import { WORK_DIR_NAME } from '../../utils/constants'; import { WORK_DIR_NAME } from '~/utils/constants';
interface WebContainerContext { interface WebContainerContext {
loaded: boolean; loaded: boolean;

View File

@ -1,9 +1,9 @@
import { json, redirect, type LoaderFunctionArgs, type MetaFunction } from '@remix-run/cloudflare'; import { json, redirect, type LoaderFunctionArgs, type MetaFunction } from '@remix-run/cloudflare';
import { ClientOnly } from 'remix-utils/client-only'; import { ClientOnly } from 'remix-utils/client-only';
import { BaseChat } from '../components/chat/BaseChat'; import { BaseChat } from '~/components/chat/BaseChat';
import { Chat } from '../components/chat/Chat.client'; import { Chat } from '~/components/chat/Chat.client';
import { Header } from '../components/Header'; import { Header } from '~/components/Header';
import { isAuthenticated } from '../lib/.server/sessions'; import { isAuthenticated } from '~/lib/.server/sessions';
export const meta: MetaFunction = () => { export const meta: MetaFunction = () => {
return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }]; return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }];

View File

@ -1,9 +1,9 @@
import { type ActionFunctionArgs } from '@remix-run/cloudflare'; import { type ActionFunctionArgs } from '@remix-run/cloudflare';
import { StreamingTextResponse } from 'ai'; import { StreamingTextResponse } from 'ai';
import { MAX_RESPONSE_SEGMENTS, MAX_TOKENS } from '../lib/.server/llm/constants'; import { MAX_RESPONSE_SEGMENTS, MAX_TOKENS } from '~/lib/.server/llm/constants';
import { CONTINUE_PROMPT } from '../lib/.server/llm/prompts'; import { CONTINUE_PROMPT } from '~/lib/.server/llm/prompts';
import { streamText, type Messages, type StreamingOptions } from '../lib/.server/llm/stream-text'; import { streamText, type Messages, type StreamingOptions } from '~/lib/.server/llm/stream-text';
import SwitchableStream from '../lib/.server/llm/switchable-stream'; import SwitchableStream from '~/lib/.server/llm/switchable-stream';
export async function action({ context, request }: ActionFunctionArgs) { export async function action({ context, request }: ActionFunctionArgs) {
const { messages } = await request.json<{ messages: Messages }>(); const { messages } = await request.json<{ messages: Messages }>();

View File

@ -1,7 +1,7 @@
import { type ActionFunctionArgs } from '@remix-run/cloudflare'; import { type ActionFunctionArgs } from '@remix-run/cloudflare';
import { StreamingTextResponse, parseStreamPart } from 'ai'; import { StreamingTextResponse, parseStreamPart } from 'ai';
import { streamText } from '../lib/.server/llm/stream-text'; import { streamText } from '~/lib/.server/llm/stream-text';
import { stripIndents } from '../utils/stripIndent'; import { stripIndents } from '~/utils/stripIndent';
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const decoder = new TextDecoder(); const decoder = new TextDecoder();

View File

@ -6,8 +6,8 @@ import {
type TypedResponse, type TypedResponse,
} from '@remix-run/cloudflare'; } from '@remix-run/cloudflare';
import { Form, useActionData } from '@remix-run/react'; import { Form, useActionData } from '@remix-run/react';
import { verifyPassword } from '../lib/.server/login'; import { verifyPassword } from '~/lib/.server/login';
import { createUserSession, isAuthenticated } from '../lib/.server/sessions'; import { createUserSession, isAuthenticated } from '~/lib/.server/sessions';
interface Errors { interface Errors {
password?: string; password?: string;

View File

@ -2,7 +2,7 @@ import type { ServerBuild } from '@remix-run/cloudflare';
import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages'; import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages';
// @ts-ignore because the server build file is generated by `remix vite:build` // @ts-ignore because the server build file is generated by `remix vite:build`
import * as serverBuild from '../build/server'; import * as serverBuild from '~/build/server';
export const onRequest = createPagesFunctionHandler({ export const onRequest = createPagesFunctionHandler({
build: serverBuild as unknown as ServerBuild, build: serverBuild as unknown as ServerBuild,