feat: add rule for eslint import & autofix (#116)

* feat: add rule for eslint import & autofix

* feat: autofix unused import

* feat: autofix unused import

* test: seems secret is not working
This commit is contained in:
lumix
2025-05-22 13:09:43 +08:00
committed by GitHub
parent f620c349e3
commit d7504fa5e6
14 changed files with 1256 additions and 325 deletions

View File

@@ -3,4 +3,5 @@ dist/
.eslintrc.cjs
tsconfig.json
vite.config.ts
vite-env.d.ts
coverage/

View File

@@ -5,7 +5,12 @@ module.exports = {
es6: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/recommended',
'plugin:import/typescript'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
@@ -13,7 +18,15 @@ module.exports = {
tsconfigRootDir: __dirname,
extraFileExtensions: ['.json'],
},
plugins: ['@typescript-eslint', 'react-hooks'],
plugins: ['@typescript-eslint', 'react-hooks', 'import', 'unused-imports'],
settings: {
'import/resolver': {
typescript: {
alwaysTryTypes: true,
project: 'tsconfig.json',
},
},
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
@@ -34,7 +47,8 @@ module.exports = {
eqeqeq: ['error', 'always'],
'no-cond-assign': 'error',
'no-duplicate-case': 'error',
'no-duplicate-imports': 'error',
// replaced by import/no-duplicates
'no-duplicate-imports': 'off',
'no-empty': [
'error',
{
@@ -66,8 +80,66 @@ module.exports = {
{ blankLine: 'any', prev: 'import', next: 'import' },
{ blankLine: 'always', prev: 'block-like', next: '*' },
{ blankLine: 'always', prev: 'block', next: '*' },
],
'import/no-unresolved': ['error', {
ignore: ['\\.svg$', 'bun']
}],
'import/named': 'warn',
'import/namespace': 'warn',
'import/default': 'warn',
'import/export': 'warn',
'import/no-duplicates': 'error',
// Detect whether there are modules that are exported but not used.
'import/no-unused-modules': 'warn',
// unused-imports should be error level so eslint can auto fix it
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'error',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_'
}
],
'@typescript-eslint/no-unused-vars': ['error', {
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_'
}],
'import/order': ['warn', {
'groups': [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
'object',
'type'
],
'newlines-between': 'always',
'alphabetize': {
'order': 'asc',
'caseInsensitive': true
},
'pathGroups': [
{
'pattern': '@/**',
'group': 'internal',
'position': 'after'
},
{
'pattern': 'src/**',
'group': 'internal',
'position': 'after'
}
],
'pathGroupsExcludedImportTypes': ['builtin']
}]
},
ignorePatterns: ['src/**/*.test.ts', '**/__tests__/**/*.json', 'package.json', '__mocks__/*.ts'],
};

View File

@@ -44,7 +44,6 @@ jobs:
with:
component: true
build: pnpm run build
start: pnpm run start
browser: chrome
env:
COVERAGE: "true"
@@ -58,7 +57,7 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.WEB_CODE_COV }}
token: cf9245e0-e136-4e21-b0ee-35755fa0c493
files: coverage/jest/lcov.info, coverage/cypress/lcov.info
flags: appflowy_web
name: codecov-umbrella

View File

@@ -1,10 +1,11 @@
import path from 'path';
import * as fs from 'fs';
import pino from 'pino';
import { type CheerioAPI, load } from 'cheerio';
import path from 'path';
// @ts-expect-error no bun
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import { fetch } from 'bun';
import { type CheerioAPI, load } from 'cheerio';
import pino from 'pino';
const distDir = path.join(__dirname, 'dist');
const indexPath = path.join(distDir, 'index.html');

View File

@@ -9,7 +9,7 @@
"build": "vite build",
"type-check": "tsc --noEmit --project tsconfig.web.json",
"type-check:watch": "tsc --build --watch",
"lint": "pnpm type-check && eslint --ext .js,.ts,.tsx . --ignore-path .eslintignore.web",
"lint": "pnpm type-check && eslint --quiet --ext .js,.ts,.tsx . --ignore-path .eslintignore.web",
"start": "vite preview --port 3000",
"css:variables": "node scripts/generateTailwindColors.cjs",
"analyze": "cross-env ANALYZE_MODE=true vite build",
@@ -181,9 +181,12 @@
"cypress-image-snapshot": "^4.0.1",
"cypress-real-events": "^1.13.0",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-unused-imports": "^4.1.4",
"istanbul-lib-coverage": "^3.2.2",
"jest-environment-jsdom": "^29.6.2",
"jest-node-exports-resolver": "^1.1.6",

980
pnpm-lock.yaml generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import { YDatabaseCell, YjsDatabaseKey } from '@/application/types';
import { FieldType } from '@/application/database-yjs/database.type';
import { YArray } from 'yjs/dist/src/types/YArray';
import * as Y from 'yjs';
import { Cell, CheckboxCell, DateTimeCell, FileMediaCell, FileMediaCellData } from './cell.type';
export function parseYDatabaseCommonCellToCell(cell: YDatabaseCell): Cell {
@@ -43,7 +43,7 @@ export function parseYDatabaseDateTimeCellToCell (cell: YDatabaseCell): DateTime
}
export function parseYDatabaseFileMediaCellToCell(cell: YDatabaseCell): FileMediaCell {
const data = cell.get(YjsDatabaseKey.data) as YArray<string>;
const data = cell.get(YjsDatabaseKey.data) as Y.Array<string>;
const dataJson = data.toJSON().map((item: string) => JSON.parse(item)) as FileMediaCellData;
return {

View File

@@ -2,7 +2,7 @@ import { FieldId, RowId } from '@/application/types';
import { DateFormat, TimeFormat } from '@/application/database-yjs/index';
import { FieldType } from '@/application/database-yjs/database.type';
import React from 'react';
import { YArray } from 'yjs/dist/src/types/YArray';
import * as Y from 'yjs';
export interface Cell {
createdAt: number;
@@ -97,7 +97,7 @@ export interface ChecklistCell extends Cell {
export interface RelationCell extends Cell {
fieldType: FieldType.Relation;
data: YArray<unknown>;
data: Y.Array<unknown>;
}
export type RelationCellData = RowId[];

View File

@@ -46,7 +46,7 @@ import dayjs from 'dayjs';
import { omit } from 'lodash-es';
import { nanoid } from 'nanoid';
import { notify } from '@/components/_shared/notify';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat/dist/types';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat';
export * from './gotrue';

View File

@@ -48,7 +48,7 @@ import {
YjsEditorKey,
} from '@/application/types';
import { applyYDoc } from '@/application/ydoc/apply';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat/dist/types';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat';
import { nanoid } from 'nanoid';
import * as Y from 'yjs';

View File

@@ -36,7 +36,7 @@ import {
UploadTemplatePayload,
} from '@/application/template.type';
import { AxiosInstance } from 'axios';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat/dist/types';
import { RepeatedChatMessage } from '@appflowyinc/ai-chat';
export type AFService =
PublishService

View File

@@ -5,7 +5,7 @@ import { YBlock, YjsEditorKey } from '@/application/types';
import isEqual from 'lodash-es/isEqual';
import { Editor, Element, NodeEntry } from 'slate';
import { YEvent, YMapEvent, YTextEvent } from 'yjs';
import { YText } from 'yjs/dist/src/types/YText';
import * as Y from 'yjs';
import { dataStringTOJson, getBlock, getChildrenArray, getPageId, getText } from '@/application/slate-yjs/utils/yjs';
import { findSlateEntryByBlockId } from '@/application/slate-yjs/utils/editor';
@@ -65,7 +65,7 @@ function applyUpdateBlockYEvent(editor: YjsEditor, blockId: string, event: YMapE
function applyTextYEvent(editor: YjsEditor, textId: string, event: YTextEvent) {
const { target } = event;
const yText = target as YText;
const yText = target as Y.Text;
const delta = yText.toDelta();
const slateDelta = delta.flatMap(deltaInsertToSlateNode);
const [entry] = editor.nodes({

View File

@@ -9,13 +9,15 @@ import { notify } from '@/components/_shared/notify';
import { insertDataAfterBlock } from '@/components/ai-chat/utils';
import { useEditorContext } from '@/components/editor/EditorContext';
import { getScrollParent } from '@/components/global-comment/utils';
import { AIAssistantProvider, ContextPlaceholder, WriterRequest } from '@appflowyinc/ai-chat';
import { EditorData } from '@appflowyinc/editor';
import { Portal } from '@mui/material';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Element, NodeEntry, Range, Text, Transforms } from 'slate';
import { ReactEditor, useSlate } from 'slate-react';
import BlockPopover from './components/block-popover';
import Panels from './components/panels';
import Toolbars from './components/toolbar';
@@ -143,9 +145,9 @@ function EditorOverlay({
}
}, [removeDecorate, editor]);
const [container, setContainer] = React.useState<HTMLDivElement | null>(null);
const [scrollerContainer, setScrollerContainer] = React.useState<HTMLDivElement | null>(null);
const [absoluteHeight, setAbsoluteHeight] = React.useState(0);
const [container, setContainer] = useState<HTMLDivElement | null>(null);
const [scrollerContainer, setScrollerContainer] = useState<HTMLDivElement | null>(null);
const [absoluteHeight, setAbsoluteHeight] = useState(0);
useEffect(() => {
if (endBlock) {

View File

@@ -99,6 +99,7 @@ export default defineConfig({
server: {
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
strictPort: true,
host: '0.0.0.0',
watch: {
ignored: ['node_modules'],
},