diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml index e694c69159..137208bff0 100644 --- a/.github/workflows/pr-ci.yml +++ b/.github/workflows/pr-ci.yml @@ -46,12 +46,12 @@ jobs: - name: Install Dependencies run: yarn install - - name: Format Check - run: yarn format:check - - name: Lint Check run: yarn test:lint + - name: Format Check + run: yarn format:check + - name: Type Check run: yarn typecheck diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000000..6f4accbece --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,215 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "categories": {}, + "env": { + "es2022": true + }, + "globals": {}, + "ignorePatterns": [ + "node_modules/**", + "build/**", + "dist/**", + "out/**", + "local/**", + ".yarn/**", + ".gitignore", + "scripts/cloudflare-worker.js", + "src/main/integration/nutstore/sso/lib/**", + "src/main/integration/cherryin/index.js", + "src/main/integration/nutstore/sso/lib/**", + "src/renderer/src/ui/**", + "packages/**/dist", + "eslint.config.mjs" + ], + "overrides": [ + // set different env + { + "env": { + "node": true + }, + "files": ["src/main/**", "resources/scripts/**", "scripts/**", "playwright.config.ts", "electron.vite.config.ts"] + }, + { + "env": { + "browser": true + }, + "files": [ + "src/renderer/**/*.{ts,tsx}", + "packages/aiCore/**", + "packages/extension-table-plus/**", + "resources/js/**" + ] + }, + { + "env": { + "node": true, + "vitest": true + }, + "files": ["**/__tests__/*.test.{ts,tsx}", "tests/**"] + }, + { + "env": { + "browser": true, + "node": true + }, + "files": ["src/preload/**"] + } + ], + // We don't use the React plugin here because its behavior differs slightly from that of ESLint's React plugin. + "plugins": ["unicorn", "typescript", "oxc", "import"], + "rules": { + "constructor-super": "error", + "for-direction": "error", + "getter-return": "error", + "no-array-constructor": "off", + // "import/no-cycle": "error", // tons of error, bro + "no-async-promise-executor": "error", + "no-caller": "warn", + "no-case-declarations": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-binary-expression": "error", + "no-constant-condition": "error", + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-args": "error", + "no-dupe-class-members": "error", + "no-dupe-else-if": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-empty-static-block": "error", + "no-eval": "warn", + "no-ex-assign": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "warn", + "no-func-assign": "error", + "no-global-assign": "error", + "no-import-assign": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-loss-of-precision": "error", + "no-misleading-character-class": "error", + "no-new-native-nonconstructor": "error", + "no-nonoctal-decimal-escape": "error", + "no-obj-calls": "error", + "no-octal": "error", + "no-prototype-builtins": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-self-assign": "error", + "no-setter-return": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-this-before-super": "error", + "no-unassigned-vars": "warn", + "no-undef": "error", + "no-unexpected-multiline": "error", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unsafe-optional-chaining": "error", + "no-unused-expressions": "off", // this rule disallow us to use expression to call function, like `condition && fn()` + "no-unused-labels": "error", + "no-unused-private-class-members": "error", + "no-unused-vars": ["error", { "caughtErrors": "none" }], + "no-useless-backreference": "error", + "no-useless-catch": "error", + "no-useless-escape": "error", + "no-useless-rename": "warn", + "no-with": "error", + "oxc/bad-array-method-on-arguments": "warn", + "oxc/bad-char-at-comparison": "warn", + "oxc/bad-comparison-sequence": "warn", + "oxc/bad-min-max-func": "warn", + "oxc/bad-object-literal-comparison": "warn", + "oxc/bad-replace-all-arg": "warn", + "oxc/const-comparisons": "warn", + "oxc/double-comparisons": "warn", + "oxc/erasing-op": "warn", + "oxc/missing-throw": "warn", + "oxc/number-arg-out-of-range": "warn", + "oxc/only-used-in-recursion": "off", // manually off bacause of existing warning. may turn it on in the future + "oxc/uninvoked-array-callback": "warn", + "require-yield": "error", + "typescript/await-thenable": "warn", + // "typescript/ban-ts-comment": "error", + "typescript/no-array-constructor": "error", + // "typescript/consistent-type-imports": "error", + "typescript/no-array-delete": "warn", + "typescript/no-base-to-string": "warn", + "typescript/no-duplicate-enum-values": "error", + "typescript/no-duplicate-type-constituents": "warn", + "typescript/no-empty-object-type": "off", + "typescript/no-explicit-any": "off", // not safe but too many errors + "typescript/no-extra-non-null-assertion": "error", + "typescript/no-floating-promises": "warn", + "typescript/no-for-in-array": "warn", + "typescript/no-implied-eval": "warn", + "typescript/no-meaningless-void-operator": "warn", + "typescript/no-misused-new": "error", + "typescript/no-misused-spread": "warn", + "typescript/no-namespace": "error", + "typescript/no-non-null-asserted-optional-chain": "off", // it's off now. but may turn it on. + "typescript/no-redundant-type-constituents": "warn", + "typescript/no-require-imports": "off", + "typescript/no-this-alias": "error", + "typescript/no-unnecessary-parameter-property-assignment": "warn", + "typescript/no-unnecessary-type-constraint": "error", + "typescript/no-unsafe-declaration-merging": "error", + "typescript/no-unsafe-function-type": "error", + "typescript/no-unsafe-unary-minus": "warn", + "typescript/no-useless-empty-export": "warn", + "typescript/no-wrapper-object-types": "error", + "typescript/prefer-as-const": "error", + "typescript/prefer-namespace-keyword": "error", + "typescript/require-array-sort-compare": "warn", + "typescript/restrict-template-expressions": "warn", + "typescript/triple-slash-reference": "error", + "typescript/unbound-method": "warn", + "unicorn/no-await-in-promise-methods": "warn", + "unicorn/no-empty-file": "off", // manually off bacause of existing warning. may turn it on in the future + "unicorn/no-invalid-fetch-options": "warn", + "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-new-array": "off", // manually off bacause of existing warning. may turn it on in the future + "unicorn/no-single-promise-in-promise-methods": "warn", + "unicorn/no-thenable": "off", // manually off bacause of existing warning. may turn it on in the future + "unicorn/no-unnecessary-await": "warn", + "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-useless-length-check": "warn", + "unicorn/no-useless-spread": "off", // manually off bacause of existing warning. may turn it on in the future + "unicorn/prefer-set-size": "warn", + "unicorn/prefer-string-starts-ends-with": "warn", + "use-isnan": "error", + "valid-typeof": "error" + }, + "settings": { + "jsdoc": { + "augmentsExtendsReplacesDocs": false, + "exemptDestructuredRootsFromChecks": false, + "ignoreInternal": false, + "ignorePrivate": false, + "ignoreReplacesDocs": true, + "implementsReplacesDocs": false, + "overrideReplacesDocs": true, + "tagNamePreference": {} + }, + "jsx-a11y": { + "attributes": {}, + "components": {}, + "polymorphicPropName": null + }, + "next": { + "rootDir": [] + }, + "react": { + "formComponents": [], + "linkComponents": [] + } + } +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 6e35f94739..167792154a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,7 @@ "dbaeumer.vscode-eslint", "editorconfig.editorconfig", "lokalise.i18n-ally", + "oxc.oxc-vscode", "biomejs.biome" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 51f95116fc..141179f38c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,6 +26,7 @@ "editor.codeActionsOnSave": { "source.fixAll.biome": "explicit", "source.fixAll.eslint": "explicit", + "source.fixAll.oxc": "explicit", "source.organizeImports": "never" }, "editor.formatOnSave": true, diff --git a/eslint.config.mjs b/eslint.config.mjs index bf31b25037..8eda2e6fa8 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,6 +2,7 @@ import tseslint from '@electron-toolkit/eslint-config-ts' import eslint from '@eslint/js' import eslintReact from '@eslint-react/eslint-plugin' import { defineConfig } from 'eslint/config' +import oxlint from 'eslint-plugin-oxlint' import reactHooks from 'eslint-plugin-react-hooks' import simpleImportSort from 'eslint-plugin-simple-import-sort' import unusedImports from 'eslint-plugin-unused-imports' @@ -50,7 +51,7 @@ export default defineConfig([ { // LoggerService Custom Rules - only apply to src directory files: ['src/**/*.{ts,tsx,js,jsx}'], - ignores: ['src/**/__tests__/**', 'src/**/__mocks__/**', 'src/**/*.test.*'], + ignores: ['src/**/__tests__/**', 'src/**/__mocks__/**', 'src/**/*.test.*', 'src/preload/**'], rules: { 'no-restricted-syntax': [ process.env.PRCI ? 'error' : 'warn', @@ -125,5 +126,9 @@ export default defineConfig([ 'src/renderer/src/ui/**', 'packages/**/dist' ] - } + }, + // turn off oxlint supported rules. + ...oxlint.configs['flat/eslint'], + ...oxlint.configs['flat/typescript'], + ...oxlint.configs['flat/unicorn'] ]) diff --git a/package.json b/package.json index 20e3d5840f..502775a8ba 100644 --- a/package.json +++ b/package.json @@ -63,11 +63,11 @@ "test:ui": "vitest --ui", "test:watch": "vitest", "test:e2e": "yarn playwright test", - "test:lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts", + "test:lint": "oxlint --deny-warnings && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts", "test:scripts": "vitest scripts", + "lint": "oxlint --fix && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix && yarn typecheck && yarn check:i18n", "format": "biome format --write && biome lint --write", "format:check": "biome format && biome lint", - "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix && yarn typecheck && yarn check:i18n", "prepare": "git config blame.ignoreRevsFile .git-blame-ignore-revs && husky", "claude": "dotenv -e .env -- claude" }, @@ -245,6 +245,7 @@ "emoji-picker-element": "^1.22.1", "epub": "patch:epub@npm%3A1.3.0#~/.yarn/patches/epub-npm-1.3.0-8325494ffe.patch", "eslint": "^9.22.0", + "eslint-plugin-oxlint": "^1.15.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unused-imports": "^4.1.4", @@ -280,6 +281,8 @@ "notion-helper": "^1.3.22", "npx-scope-finder": "^1.2.0", "openai": "patch:openai@npm%3A5.12.2#~/.yarn/patches/openai-npm-5.12.2-30b075401c.patch", + "oxlint": "^1.15.0", + "oxlint-tsgolint": "^0.2.0", "p-queue": "^8.1.0", "pdf-lib": "^1.17.1", "pdf-parse": "^1.1.1", diff --git a/src/main/apiServer/middleware/error.ts b/src/main/apiServer/middleware/error.ts index 65eef5e43d..6aa1819ddd 100644 --- a/src/main/apiServer/middleware/error.ts +++ b/src/main/apiServer/middleware/error.ts @@ -4,7 +4,7 @@ import { loggerService } from '../../services/LoggerService' const logger = loggerService.withContext('ApiServerErrorHandler') -// eslint-disable-next-line @typescript-eslint/no-unused-vars +// oxlint-disable-next-line @typescript-eslint/no-unused-vars export const errorHandler = (err: Error, _req: Request, res: Response, _next: NextFunction) => { logger.error('API Server Error:', err) diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 5b4f0db1e8..d889a098f8 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -11,7 +11,7 @@ import { handleZoomFactor } from '@main/utils/zoom' import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core' import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, UpgradeChannel } from '@shared/config/constant' import { IpcChannel } from '@shared/IpcChannel' -import { FileMetadata, Provider, Shortcut, ThemeMode } from '@types' +import { FileMetadata, OcrProvider, Provider, Shortcut, SupportedOcrFile, ThemeMode } from '@types' import checkDiskSpace from 'check-disk-space' import { BrowserWindow, dialog, ipcMain, ProxyConfig, session, shell, systemPreferences, webContents } from 'electron' import fontList from 'font-list' @@ -827,7 +827,9 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { ipcMain.handle(IpcChannel.CodeTools_Run, codeToolsService.run) // OCR - ipcMain.handle(IpcChannel.OCR_ocr, (_, ...args: Parameters) => ocrService.ocr(...args)) + ipcMain.handle(IpcChannel.OCR_ocr, (_, file: SupportedOcrFile, provider: OcrProvider) => + ocrService.ocr(file, provider) + ) // CherryIN ipcMain.handle(IpcChannel.Cherryin_GetSignature, (_, params) => generateSignature(params)) diff --git a/src/main/knowledge/embedjs/loader/index.ts b/src/main/knowledge/embedjs/loader/index.ts index 6d9b4c7ace..4b38418194 100644 --- a/src/main/knowledge/embedjs/loader/index.ts +++ b/src/main/knowledge/embedjs/loader/index.ts @@ -139,9 +139,9 @@ export async function addFileLoader( if (jsonParsed) { loaderReturn = await ragApplication.addLoader(new JsonLoader({ object: jsonObject }), forceReload) - break } // fallthrough - JSON 解析失败时作为文本处理 + // oxlint-disable-next-line no-fallthrough 利用switch特性,刻意不break default: // 文本类型处理(默认) // 如果是其他文本类型且尚未读取文件,则读取文件 diff --git a/src/main/knowledge/embedjs/loader/odLoader.ts b/src/main/knowledge/embedjs/loader/odLoader.ts index ad2a0e119d..03825bf4db 100644 --- a/src/main/knowledge/embedjs/loader/odLoader.ts +++ b/src/main/knowledge/embedjs/loader/odLoader.ts @@ -11,7 +11,7 @@ export enum OdType { OdtLoader = 'OdtLoader', OdsLoader = 'OdsLoader', OdpLoader = 'OdpLoader', - undefined = 'undefined' + Undefined = 'undefined' } export class OdLoader extends BaseLoader<{ type: string }> { diff --git a/src/main/services/ExportService.ts b/src/main/services/ExportService.ts index 8aa10cb466..c6dfa604cf 100644 --- a/src/main/services/ExportService.ts +++ b/src/main/services/ExportService.ts @@ -1,4 +1,4 @@ -/* eslint-disable no-case-declarations */ +/* oxlint-disable no-case-declarations */ // ExportService import { loggerService } from '@logger' diff --git a/src/main/services/MistralClientManager.ts b/src/main/services/MistralClientManager.ts index fa4aa53df8..c2efe35d1d 100644 --- a/src/main/services/MistralClientManager.ts +++ b/src/main/services/MistralClientManager.ts @@ -5,7 +5,7 @@ export class MistralClientManager { private static instance: MistralClientManager private client: Mistral | null = null - // eslint-disable-next-line @typescript-eslint/no-empty-function + // oxlint-disable-next-line @typescript-eslint/no-empty-function private constructor() {} public static getInstance(): MistralClientManager { diff --git a/src/main/services/ProxyManager.ts b/src/main/services/ProxyManager.ts index 860324bc62..0e188c1009 100644 --- a/src/main/services/ProxyManager.ts +++ b/src/main/services/ProxyManager.ts @@ -235,7 +235,7 @@ export class ProxyManager { https.request = this.bindHttpMethod(this.originalHttpsRequest, agent) } - // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type + // oxlint-disable-next-line @typescript-eslint/no-unsafe-function-type private bindHttpMethod(originalMethod: Function, agent: http.Agent | https.Agent) { return (...args: any[]) => { let url: string | URL | undefined diff --git a/src/main/services/ocr/builtin/SystemOcrService.ts b/src/main/services/ocr/builtin/SystemOcrService.ts index 34a8bb8ce9..b496df398e 100644 --- a/src/main/services/ocr/builtin/SystemOcrService.ts +++ b/src/main/services/ocr/builtin/SystemOcrService.ts @@ -1,13 +1,7 @@ import { isLinux, isWin } from '@main/constant' import { loadOcrImage } from '@main/utils/ocr' import { OcrAccuracy, recognize } from '@napi-rs/system-ocr' -import { - ImageFileMetadata, - isImageFileMetadata as isImageFileMetadata, - OcrResult, - OcrSystemConfig, - SupportedOcrFile -} from '@types' +import { ImageFileMetadata, isImageFileMetadata, OcrResult, OcrSystemConfig, SupportedOcrFile } from '@types' import { OcrBaseService } from './OcrBaseService' diff --git a/src/main/services/remotefile/FileServiceManager.ts b/src/main/services/remotefile/FileServiceManager.ts index f456ba285d..14f622757a 100644 --- a/src/main/services/remotefile/FileServiceManager.ts +++ b/src/main/services/remotefile/FileServiceManager.ts @@ -9,7 +9,7 @@ export class FileServiceManager { private static instance: FileServiceManager private services: Map = new Map() - // eslint-disable-next-line @typescript-eslint/no-empty-function + // oxlint-disable-next-line @typescript-eslint/no-empty-function private constructor() {} static getInstance(): FileServiceManager { diff --git a/src/main/utils/file.ts b/src/main/utils/file.ts index f9363a500e..5c197e8971 100644 --- a/src/main/utils/file.ts +++ b/src/main/utils/file.ts @@ -420,7 +420,7 @@ export function sanitizeFilename(fileName: string, replacement = '_'): string { // 移除或替换非法字符 let sanitized = fileName - // eslint-disable-next-line no-control-regex + // oxlint-disable-next-line no-control-regex .replace(/[<>:"/\\|?*\x00-\x1f]/g, replacement) // Windows 非法字符 .replace(/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\.|$)/i, replacement + '$2') // Windows 保留名 .replace(/[\s.]+$/, '') // 移除末尾的空格和点 diff --git a/src/main/utils/index.ts b/src/main/utils/index.ts index 4fea14c9fe..6b2ac42788 100644 --- a/src/main/utils/index.ts +++ b/src/main/utils/index.ts @@ -36,13 +36,14 @@ export function debounce(func: (...args: any[]) => void, wait: number, immediate } } -export function dumpPersistState() { - const persistState = JSON.parse(localStorage.getItem('persist:cherry-studio') || '{}') - for (const key in persistState) { - persistState[key] = JSON.parse(persistState[key]) - } - return JSON.stringify(persistState) -} +// NOTE: It's an unused function. localStorage should not be accessed in main process. +// export function dumpPersistState() { +// const persistState = JSON.parse(localStorage.getItem('persist:cherry-studio') || '{}') +// for (const key in persistState) { +// persistState[key] = JSON.parse(persistState[key]) +// } +// return JSON.stringify(persistState) +// } export const runAsyncFunction = async (fn: () => void) => { await fn() diff --git a/src/preload/index.ts b/src/preload/index.ts index 12cab36118..6633629802 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -475,13 +475,10 @@ if (process.contextIsolated) { contextBridge.exposeInMainWorld('electron', electronAPI) contextBridge.exposeInMainWorld('api', api) } catch (error) { - // eslint-disable-next-line no-restricted-syntax console.error('[Preload]Failed to expose APIs:', error as Error) } } else { - // @ts-ignore (define in dts) window.electron = electronAPI - // @ts-ignore (define in dts) window.api = api } diff --git a/src/renderer/src/aiCore/chunk/AiSdkToChunkAdapter.ts b/src/renderer/src/aiCore/chunk/AiSdkToChunkAdapter.ts index 8af4388d5f..a65c6fe790 100644 --- a/src/renderer/src/aiCore/chunk/AiSdkToChunkAdapter.ts +++ b/src/renderer/src/aiCore/chunk/AiSdkToChunkAdapter.ts @@ -314,7 +314,7 @@ export class AiSdkToChunkAdapter { // === 源和文件相关事件 === case 'source': if (chunk.sourceType === 'url') { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars const { sourceType: _, ...rest } = chunk final.webSearchResults.push(rest) } diff --git a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts index 430b9e4df7..9fb687a265 100644 --- a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts @@ -84,7 +84,7 @@ export abstract class BaseApiClient< * 用于判断客户端是否支持特定功能,避免instanceof检查的类型收窄问题 * 对于装饰器模式的客户端(如AihubmixAPIClient),应该返回其内部实际使用的客户端类型 */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars public getClientCompatibilityType(_model?: Model): string[] { // 默认返回类的名称 return [this.constructor.name] diff --git a/src/renderer/src/aiCore/legacy/clients/anthropic/AnthropicAPIClient.ts b/src/renderer/src/aiCore/legacy/clients/anthropic/AnthropicAPIClient.ts index dea98f2808..aef3e07905 100644 --- a/src/renderer/src/aiCore/legacy/clients/anthropic/AnthropicAPIClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/anthropic/AnthropicAPIClient.ts @@ -177,7 +177,7 @@ export class AnthropicAPIClient extends BaseApiClient< } // @ts-ignore sdk未提供 - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars override async generateImage(generateImageParams: GenerateImageParams): Promise { return [] } diff --git a/src/renderer/src/aiCore/legacy/clients/aws/AwsBedrockAPIClient.ts b/src/renderer/src/aiCore/legacy/clients/aws/AwsBedrockAPIClient.ts index 9bcadd0c55..1de8a724c4 100644 --- a/src/renderer/src/aiCore/legacy/clients/aws/AwsBedrockAPIClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/aws/AwsBedrockAPIClient.ts @@ -455,7 +455,7 @@ export class AwsBedrockAPIClient extends BaseApiClient< } // @ts-ignore sdk未提供 - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars override async generateImage(_generateImageParams: GenerateImageParams): Promise { return [] } diff --git a/src/renderer/src/aiCore/legacy/clients/ppio/PPIOAPIClient.ts b/src/renderer/src/aiCore/legacy/clients/ppio/PPIOAPIClient.ts index 684d550698..fd282ac815 100644 --- a/src/renderer/src/aiCore/legacy/clients/ppio/PPIOAPIClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/ppio/PPIOAPIClient.ts @@ -11,7 +11,7 @@ export class PPIOAPIClient extends OpenAIAPIClient { super(provider) } - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars override getClientCompatibilityType(_model?: Model): string[] { return ['OpenAIAPIClient'] } diff --git a/src/renderer/src/aiCore/legacy/middleware/common/LoggingMiddleware.ts b/src/renderer/src/aiCore/legacy/middleware/common/LoggingMiddleware.ts index dd79ef457d..acd371d777 100644 --- a/src/renderer/src/aiCore/legacy/middleware/common/LoggingMiddleware.ts +++ b/src/renderer/src/aiCore/legacy/middleware/common/LoggingMiddleware.ts @@ -44,7 +44,7 @@ const stringifyArgsForLogging = (args: any[]): string => { */ export const createGenericLoggingMiddleware: () => MethodMiddleware = () => { const middlewareName = 'GenericLoggingMiddleware' - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars return (_: MiddlewareAPI) => (next) => async (ctx, args) => { const methodName = ctx.methodName const logPrefix = `[${middlewareName} (${methodName})]` diff --git a/src/renderer/src/aiCore/plugins/telemetryPlugin.ts b/src/renderer/src/aiCore/plugins/telemetryPlugin.ts index 6eb66575c5..75bf6e116c 100644 --- a/src/renderer/src/aiCore/plugins/telemetryPlugin.ts +++ b/src/renderer/src/aiCore/plugins/telemetryPlugin.ts @@ -66,6 +66,7 @@ class AdapterTracer { spanName: name, topicId: this.topicId, modelName: this.modelName, + // oxlint-disable-next-line no-undef False alarm. see https://github.com/oxc-project/oxc/issues/4232 argCount: arguments.length }) diff --git a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx index 8416774406..848173e9b1 100644 --- a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx +++ b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx @@ -12,7 +12,7 @@ import { } from '@ant-design/icons' import { loggerService } from '@logger' import WindowControls from '@renderer/components/WindowControls' -import { isLinux, isMac, isWin } from '@renderer/config/constant' +import { isDev, isLinux, isMac, isWin } from '@renderer/config/constant' import { DEFAULT_MIN_APPS } from '@renderer/config/minapps' import { useBridge } from '@renderer/hooks/useBridge' import { useMinappPopup } from '@renderer/hooks/useMinappPopup' @@ -170,8 +170,6 @@ const MinappPopupContainer: React.FC = () => { const { isLeftNavbar } = useNavbarPosition() - const isInDevelopment = process.env.NODE_ENV === 'development' - const { setTimeoutTimer } = useTimer() useBridge() @@ -477,7 +475,7 @@ const MinappPopupContainer: React.FC = () => { - {isInDevelopment && ( + {isDev && ( handleOpenDevTools(appInfo.id)}> diff --git a/src/renderer/src/components/Tags/CustomTag.tsx b/src/renderer/src/components/Tags/CustomTag.tsx index 561b3edf41..3ecba381d4 100644 --- a/src/renderer/src/components/Tags/CustomTag.tsx +++ b/src/renderer/src/components/Tags/CustomTag.tsx @@ -43,7 +43,7 @@ const CustomTag: FC = ({ ...(disabled && { cursor: 'not-allowed' }), ...style }}> - {icon && icon} {children} + {icon} {children} {closable && ( = ({ citation }) => { {citation.number} {citation.content && } - {citation.content && citation.content} + {citation.content ?? ''} ) diff --git a/src/renderer/src/pages/home/Messages/MessageErrorBoundary.tsx b/src/renderer/src/pages/home/Messages/MessageErrorBoundary.tsx index 52f017aed6..c4a64d58cf 100644 --- a/src/renderer/src/pages/home/Messages/MessageErrorBoundary.tsx +++ b/src/renderer/src/pages/home/Messages/MessageErrorBoundary.tsx @@ -1,3 +1,4 @@ +import { isProd } from '@renderer/config/constant' import { Alert } from 'antd' import React from 'react' import { useTranslation } from 'react-i18next' @@ -17,9 +18,7 @@ const ErrorFallback = ({ fallback, error }: { fallback?: React.ReactNode; error? // 如果有详细错误信息,添加到描述中 const errorDescription = - process.env.NODE_ENV !== 'production' && error - ? `${t('error.render.description')}: ${error.message}` - : t('error.render.description') + !isProd && error ? `${t('error.render.description')}: ${error.message}` : t('error.render.description') return fallback || } diff --git a/src/renderer/src/pages/minapps/components/MinimalToolbar.tsx b/src/renderer/src/pages/minapps/components/MinimalToolbar.tsx index 60a43b8684..dcbe7adeff 100644 --- a/src/renderer/src/pages/minapps/components/MinimalToolbar.tsx +++ b/src/renderer/src/pages/minapps/components/MinimalToolbar.tsx @@ -8,6 +8,7 @@ import { PushpinOutlined, ReloadOutlined } from '@ant-design/icons' +import { isDev } from '@renderer/config/constant' import { DEFAULT_MIN_APPS } from '@renderer/config/minapps' import { useMinapps } from '@renderer/hooks/useMinapps' import { useSettings } from '@renderer/hooks/useSettings' @@ -37,8 +38,6 @@ const MinimalToolbar: FC = ({ app, webviewRef, currentUrl, onReload, onOp const navigate = useNavigate() const [canGoBack, setCanGoBack] = useState(false) const [canGoForward, setCanGoForward] = useState(false) - - const isInDevelopment = process.env.NODE_ENV === 'development' const canPinned = DEFAULT_MIN_APPS.some((item) => item.id === app.id) const isPinned = pinned.some((item) => item.id === app.id) const canOpenExternalLink = app.url.startsWith('http://') || app.url.startsWith('https://') @@ -139,7 +138,7 @@ const MinimalToolbar: FC = ({ app, webviewRef, currentUrl, onReload, onOp - {isInDevelopment && ( + {isDev && ( diff --git a/src/renderer/src/pages/paintings/TokenFluxPage.tsx b/src/renderer/src/pages/paintings/TokenFluxPage.tsx index 0860b62ee9..ea5e4ed47f 100644 --- a/src/renderer/src/pages/paintings/TokenFluxPage.tsx +++ b/src/renderer/src/pages/paintings/TokenFluxPage.tsx @@ -298,7 +298,7 @@ const TokenFluxPage: FC<{ Options: string[] }> = ({ Options }) => { // Set form data from painting's input params if (newPainting.inputParams) { // Filter out the prompt from inputParams since it's handled separately - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars const { prompt, ...formInputParams } = newPainting.inputParams setFormData(formInputParams) } else { diff --git a/src/renderer/src/providers/WebSearchProvider/LocalSearchProvider.ts b/src/renderer/src/providers/WebSearchProvider/LocalSearchProvider.ts index 7911646630..2a17dc3a26 100644 --- a/src/renderer/src/providers/WebSearchProvider/LocalSearchProvider.ts +++ b/src/renderer/src/providers/WebSearchProvider/LocalSearchProvider.ts @@ -95,7 +95,7 @@ export default class LocalSearchProvider extends BaseWebSearchProvider { return query } - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars protected parseValidUrls(_htmlContent: string): SearchItem[] { throw new Error('Not implemented') } diff --git a/src/renderer/src/queue/NotificationQueue.ts b/src/renderer/src/queue/NotificationQueue.ts index f256212837..9f8c9cb799 100644 --- a/src/renderer/src/queue/NotificationQueue.ts +++ b/src/renderer/src/queue/NotificationQueue.ts @@ -8,7 +8,7 @@ export class NotificationQueue { private queue = new PQueue({ concurrency: 1 }) private listeners: NotificationListener[] = [] - // eslint-disable-next-line @typescript-eslint/no-empty-function + // oxlint-disable-next-line @typescript-eslint/no-empty-function private constructor() {} public static getInstance(): NotificationQueue { diff --git a/src/renderer/src/store/messageBlock.ts b/src/renderer/src/store/messageBlock.ts index 368696a4d0..524889bb32 100644 --- a/src/renderer/src/store/messageBlock.ts +++ b/src/renderer/src/store/messageBlock.ts @@ -230,7 +230,7 @@ export const formatCitationsFromBlock = (block: CitationMessageBlock | undefined break case WebSearchSource.AISDK: formattedCitations = - (block.response.results && (block.response.results as AISDKWebSearchResult[]))?.map((result, index) => ({ + (block.response?.results as AISDKWebSearchResult[])?.map((result, index) => ({ number: index + 1, url: result.url, title: result.title || new URL(result.url).hostname, diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts index 13fb71f544..c939007d0b 100644 --- a/src/renderer/src/store/migrate.ts +++ b/src/renderer/src/store/migrate.ts @@ -1394,7 +1394,7 @@ const migrateConfig = { if (state.websearch?.providers) { state.websearch.providers = state.websearch.providers.map((provider) => { if (provider.id === 'exa' || provider.id === 'tavily') { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars const { basicAuthUsername, basicAuthPassword, ...rest } = provider return rest } diff --git a/src/renderer/src/store/thunk/messageThunk.ts b/src/renderer/src/store/thunk/messageThunk.ts index 42195eb8bb..8d7004ecc7 100644 --- a/src/renderer/src/store/thunk/messageThunk.ts +++ b/src/renderer/src/store/thunk/messageThunk.ts @@ -1171,7 +1171,7 @@ export const updateMessageAndBlocksThunk = try { // 1. 更新 Redux Store if (messageUpdates && messageId) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + // oxlint-disable-next-line @typescript-eslint/no-unused-vars const { id: msgId, ...actualMessageChanges } = messageUpdates // Separate ID from actual changes // Only dispatch message update if there are actual changes beyond the ID diff --git a/src/renderer/src/utils/translate.ts b/src/renderer/src/utils/translate.ts index 89d6726c18..f717ee015a 100644 --- a/src/renderer/src/utils/translate.ts +++ b/src/renderer/src/utils/translate.ts @@ -1,7 +1,7 @@ import { loggerService } from '@logger' import { isQwenMTModel } from '@renderer/config/models' import { LANG_DETECT_PROMPT } from '@renderer/config/prompts' -import { builtinLanguages as builtinLanguages, LanguagesEnum, UNKNOWN } from '@renderer/config/translate' +import { builtinLanguages, LanguagesEnum, UNKNOWN } from '@renderer/config/translate' import db from '@renderer/databases' import i18n from '@renderer/i18n' import { fetchChatCompletion } from '@renderer/services/ApiService' diff --git a/tests/__mocks__/MainLoggerService.ts b/tests/__mocks__/MainLoggerService.ts index 43b1f33e4a..e7c8a6f198 100644 --- a/tests/__mocks__/MainLoggerService.ts +++ b/tests/__mocks__/MainLoggerService.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ +/* oslint-disable @typescript-eslint/no-empty-function */ // Simple mock LoggerService class for main process export class MockMainLoggerService { diff --git a/tests/__mocks__/RendererLoggerService.ts b/tests/__mocks__/RendererLoggerService.ts index 40f77635eb..90769dc5b8 100644 --- a/tests/__mocks__/RendererLoggerService.ts +++ b/tests/__mocks__/RendererLoggerService.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ +/* oxlint-disable @typescript-eslint/no-empty-function */ // Simple mock LoggerService class for renderer process export class MockRendererLoggerService { diff --git a/yarn.lock b/yarn.lock index 7b6ba7b4d6..daaf739c67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7225,6 +7225,104 @@ __metadata: languageName: node linkType: hard +"@oxlint-tsgolint/darwin-arm64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/darwin-arm64@npm:0.2.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint-tsgolint/darwin-x64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/darwin-x64@npm:0.2.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@oxlint-tsgolint/linux-arm64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/linux-arm64@npm:0.2.0" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint-tsgolint/linux-x64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/linux-x64@npm:0.2.0" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@oxlint-tsgolint/win32-arm64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/win32-arm64@npm:0.2.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint-tsgolint/win32-x64@npm:0.2.0": + version: 0.2.0 + resolution: "@oxlint-tsgolint/win32-x64@npm:0.2.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@oxlint/darwin-arm64@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/darwin-arm64@npm:1.15.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/darwin-x64@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/darwin-x64@npm:1.15.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@oxlint/linux-arm64-gnu@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/linux-arm64-gnu@npm:1.15.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/linux-arm64-musl@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/linux-arm64-musl@npm:1.15.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@oxlint/linux-x64-gnu@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/linux-x64-gnu@npm:1.15.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/linux-x64-musl@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/linux-x64-musl@npm:1.15.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@oxlint/win32-arm64@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/win32-arm64@npm:1.15.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/win32-x64@npm:1.15.0": + version: 1.15.0 + resolution: "@oxlint/win32-x64@npm:1.15.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@pdf-lib/standard-fonts@npm:^1.0.0": version: 1.0.0 resolution: "@pdf-lib/standard-fonts@npm:1.0.0" @@ -13224,6 +13322,7 @@ __metadata: emoji-picker-element: "npm:^1.22.1" epub: "patch:epub@npm%3A1.3.0#~/.yarn/patches/epub-npm-1.3.0-8325494ffe.patch" eslint: "npm:^9.22.0" + eslint-plugin-oxlint: "npm:^1.15.0" eslint-plugin-react-hooks: "npm:^5.2.0" eslint-plugin-simple-import-sort: "npm:^12.1.1" eslint-plugin-unused-imports: "npm:^4.1.4" @@ -13266,6 +13365,8 @@ __metadata: officeparser: "npm:^4.2.0" openai: "patch:openai@npm%3A5.12.2#~/.yarn/patches/openai-npm-5.12.2-30b075401c.patch" os-proxy-config: "npm:^1.1.2" + oxlint: "npm:^1.15.0" + oxlint-tsgolint: "npm:^0.2.0" p-queue: "npm:^8.1.0" pdf-lib: "npm:^1.17.1" pdf-parse: "npm:^1.1.1" @@ -17046,6 +17147,15 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-oxlint@npm:^1.15.0": + version: 1.15.0 + resolution: "eslint-plugin-oxlint@npm:1.15.0" + dependencies: + jsonc-parser: "npm:^3.3.1" + checksum: 10c0/1c16e4a70fe3bc7ca4cda28393bb00f20d2b009121d5804dc3e9a247adb2773236e542078d6a0f4d4168e4ba68cb88fe5ad8efaee52bec24f72c16b1dad2990c + languageName: node + linkType: hard + "eslint-plugin-react-debug@npm:1.48.1": version: 1.48.1 resolution: "eslint-plugin-react-debug@npm:1.48.1" @@ -19922,6 +20032,13 @@ __metadata: languageName: node linkType: hard +"jsonc-parser@npm:^3.3.1": + version: 3.3.1 + resolution: "jsonc-parser@npm:3.3.1" + checksum: 10c0/269c3ae0a0e4f907a914bf334306c384aabb9929bd8c99f909275ebd5c2d3bc70b9bcd119ad794f339dec9f24b6a4ee9cd5a8ab2e6435e730ad4075388fc2ab6 + languageName: node + linkType: hard + "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -22982,6 +23099,76 @@ __metadata: languageName: node linkType: hard +"oxlint-tsgolint@npm:^0.2.0": + version: 0.2.0 + resolution: "oxlint-tsgolint@npm:0.2.0" + dependencies: + "@oxlint-tsgolint/darwin-arm64": "npm:0.2.0" + "@oxlint-tsgolint/darwin-x64": "npm:0.2.0" + "@oxlint-tsgolint/linux-arm64": "npm:0.2.0" + "@oxlint-tsgolint/linux-x64": "npm:0.2.0" + "@oxlint-tsgolint/win32-arm64": "npm:0.2.0" + "@oxlint-tsgolint/win32-x64": "npm:0.2.0" + dependenciesMeta: + "@oxlint-tsgolint/darwin-arm64": + optional: true + "@oxlint-tsgolint/darwin-x64": + optional: true + "@oxlint-tsgolint/linux-arm64": + optional: true + "@oxlint-tsgolint/linux-x64": + optional: true + "@oxlint-tsgolint/win32-arm64": + optional: true + "@oxlint-tsgolint/win32-x64": + optional: true + bin: + tsgolint: bin/tsgolint.js + checksum: 10c0/b2117a0d07c5c876a6608d710838c934ef456cf7cff668fba9455d380eb8e3a7d9841c8f3a03d59bbc77b0f1342d5dca0e69557cac361a1afa8b8eb3d1b114c6 + languageName: node + linkType: hard + +"oxlint@npm:^1.15.0": + version: 1.15.0 + resolution: "oxlint@npm:1.15.0" + dependencies: + "@oxlint/darwin-arm64": "npm:1.15.0" + "@oxlint/darwin-x64": "npm:1.15.0" + "@oxlint/linux-arm64-gnu": "npm:1.15.0" + "@oxlint/linux-arm64-musl": "npm:1.15.0" + "@oxlint/linux-x64-gnu": "npm:1.15.0" + "@oxlint/linux-x64-musl": "npm:1.15.0" + "@oxlint/win32-arm64": "npm:1.15.0" + "@oxlint/win32-x64": "npm:1.15.0" + peerDependencies: + oxlint-tsgolint: ">=0.2.0" + dependenciesMeta: + "@oxlint/darwin-arm64": + optional: true + "@oxlint/darwin-x64": + optional: true + "@oxlint/linux-arm64-gnu": + optional: true + "@oxlint/linux-arm64-musl": + optional: true + "@oxlint/linux-x64-gnu": + optional: true + "@oxlint/linux-x64-musl": + optional: true + "@oxlint/win32-arm64": + optional: true + "@oxlint/win32-x64": + optional: true + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + bin: + oxc_language_server: bin/oxc_language_server + oxlint: bin/oxlint + checksum: 10c0/3eb2a27b972f2a02200b068345ab6a3a17f7bc29c4546c6b3478727388d8d59b94a554f9b6bb1320b71a75cc598b728de0ffee5e4e70ac27457104b8efebb257 + languageName: node + linkType: hard + "p-cancelable@npm:^2.0.0": version: 2.1.1 resolution: "p-cancelable@npm:2.1.1"