diff --git a/.github/workflows/prcheck.yml b/.github/workflows/prcheck.yml index d63ab2d88..ea7239a69 100644 --- a/.github/workflows/prcheck.yml +++ b/.github/workflows/prcheck.yml @@ -21,6 +21,8 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' + - name: Check Lint + run: npm run lint - name: Install dependencies run: npm install env: @@ -28,8 +30,7 @@ jobs: npm_config_arch: ${{ matrix.arch }} - name: Install Sharp run: npm install --cpu=wasm32 sharp - - name: Build - run: npm run build - - name: Check translations run: npm run i18n && npm run i18n:en + - name: Build + run: npm run build diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 000000000..56b9105dd --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,17 @@ +{ + "ignorePatterns": [ + "**/node_modules", + "**/dist", + "**/out", + ".gitignore", + ".github", + ".cursor", + ".vscode", + "build", + "resources", + "scripts", + "runtime", + "docs", + "tests" + ] +} diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 020a96f3f..000000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,57 +0,0 @@ -import tseslint from '@electron-toolkit/eslint-config-ts' -import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier' -import eslintPluginVue from 'eslint-plugin-vue' -import vueParser from 'vue-eslint-parser' - -export default tseslint.config( - { - ignores: [ - '**/node_modules', - '**/dist', - '**/out', - '.gitignore', - '.github', - '.cursor', - '.vscode', - 'build', - 'resources', - 'runtime', - 'scripts', - 'src/renderer/src/components/ui/', - 'tailwind.config.*', - 'src/renderer/src/i18n/' - ] - }, - tseslint.configs.recommended, - eslintPluginVue.configs['flat/recommended'], - { - files: ['**/*.vue'], - languageOptions: { - parser: vueParser, - parserOptions: { - ecmaFeatures: { - jsx: true - }, - extraFileExtensions: ['.vue'], - parser: tseslint.parser - } - } - }, - { - files: ['**/*.{ts,mts,tsx,vue}'], - rules: { - 'vue/require-default-prop': 'off', - 'vue/multi-word-component-names': 'off', - 'vue/block-lang': [ - 'error', - { - script: { - lang: 'ts' - } - } - ], - '@typescript-eslint/explicit-function-return-type': 'off' - } - }, - eslintConfigPrettier -) diff --git a/package.json b/package.json index facc78209..5ca94d44d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "type": "module", "scripts": { "format": "prettier --write .", - "lint": "eslint --cache .", + "lint": "npx -y oxlint .", "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false", "typecheck": "npm run typecheck:node && npm run typecheck:web", @@ -74,8 +74,6 @@ "zod": "^3.24.3" }, "devDependencies": { - "@electron-toolkit/eslint-config-prettier": "3.0.0", - "@electron-toolkit/eslint-config-ts": "^3.0.0", "@electron-toolkit/tsconfig": "^1.0.1", "@electron/notarize": "^2.5.0", "@iconify-json/lucide": "^1.2.39", @@ -83,7 +81,6 @@ "@iconify/vue": "^5.0.0", "@lingual/i18n-check": "^0.8.4", "@radix-icons/vue": "^1.0.0", - "@rushstack/eslint-patch": "^1.10.3", "@tailwindcss/typography": "^0.5.16", "@tailwindcss/vite": "^4.0.4", "@tiptap/core": "^2.11.7", @@ -104,8 +101,6 @@ "@types/node": "^22.14.1", "@types/xlsx": "^0.0.35", "@vitejs/plugin-vue": "^5.2.3", - "@vue/eslint-config-prettier": "^10.2.0", - "@vue/eslint-config-typescript": "^14.5.0", "@vueuse/core": "^12.7.0", "autoprefixer": "^10.4.20", "class-variance-authority": "^0.7.1", @@ -114,8 +109,6 @@ "electron": "^35.4.0", "electron-builder": "26.0.12", "electron-vite": "^3.1.0", - "eslint": "^9.24.0", - "eslint-plugin-vue": "^10.1.0", "lucide-vue-next": "^0.511.0", "mermaid": "^11.6.0", "minimatch": "^10.0.1", @@ -135,7 +128,6 @@ "vite-plugin-vue-devtools": "^7.7.6", "vite-svg-loader": "^5.1.0", "vue": "^3.5.14", - "vue-eslint-parser": "^10.1.3", "vue-i18n": "^11.1.3", "vue-renderer-markdown": "^0.0.29", "vue-router": "4", diff --git a/src/main/presenter/filePresenter/CsvFileAdapter.ts b/src/main/presenter/filePresenter/CsvFileAdapter.ts index b2ba3f0f3..6d5e51d0b 100644 --- a/src/main/presenter/filePresenter/CsvFileAdapter.ts +++ b/src/main/presenter/filePresenter/CsvFileAdapter.ts @@ -20,7 +20,7 @@ export class CsvFileAdapter extends BaseFileAdapter { const rows = content .split('\n') .map((row) => row.split(',').map((cell) => cell.trim().replace(/^["'](.*)["']$/, '$1'))) - return rows.filter((row) => row.length > 0 && row.some((cell) => cell.length > 0)) + return rows.filter((row) => row.some((cell) => cell.length > 0)) } private generateTableMarkdown(rows: string[][]): string { diff --git a/src/main/presenter/filePresenter/FilePresenter.ts b/src/main/presenter/filePresenter/FilePresenter.ts index 1fbe2c7b1..eee57cafd 100644 --- a/src/main/presenter/filePresenter/FilePresenter.ts +++ b/src/main/presenter/filePresenter/FilePresenter.ts @@ -205,7 +205,7 @@ export class FilePresenter implements IFilePresenter { const fullPath = path.join(absPath) const stats = await fs.stat(fullPath) return stats.isDirectory() - } catch (error) { + } catch { // If the path doesn't exist or there's any other error, return false return false } diff --git a/src/main/presenter/githubCopilotDeviceFlow.ts b/src/main/presenter/githubCopilotDeviceFlow.ts index f58e17580..de9ffb679 100644 --- a/src/main/presenter/githubCopilotDeviceFlow.ts +++ b/src/main/presenter/githubCopilotDeviceFlow.ts @@ -46,7 +46,8 @@ export class GitHubCopilotDeviceFlow { return accessToken } catch (error) { - throw error + console.error('Failed to start device flow', error) + throw new Error('Failed to start device flow') } } @@ -265,9 +266,10 @@ export class GitHubCopilotDeviceFlow { if (mainWindow) { mainWindow.webContents.executeJavaScript(`window.api.copyText('${msg.text}')`) } - } - } catch (e) {} + } catch { + // ignore + } }) instructionWindow.show() @@ -303,6 +305,10 @@ export class GitHubCopilotDeviceFlow { const poll = async () => { pollCount++ + if (pollCount > 50) { + reject(new Error('Poll count exceeded')) + return + } // 检查是否超时 if (Date.now() >= expiresAt) { @@ -378,7 +384,9 @@ export class GitHubCopilotDeviceFlow { resolve(data.access_token) return } - } catch (error) {} + } catch { + // ignore + } } // 开始轮询 @@ -418,4 +426,3 @@ export function createGitHubCopilotDeviceFlow(): GitHubCopilotDeviceFlow { return new GitHubCopilotDeviceFlow(config) } - diff --git a/src/main/presenter/llamaCppPresenter/llama.ts b/src/main/presenter/llamaCppPresenter/llama.ts index c9aa62a2b..513bc35c0 100644 --- a/src/main/presenter/llamaCppPresenter/llama.ts +++ b/src/main/presenter/llamaCppPresenter/llama.ts @@ -144,3 +144,4 @@ // }) // } // }) +console.log('llama') diff --git a/src/main/presenter/mcpPresenter/inMemoryServers/filesystem.ts b/src/main/presenter/mcpPresenter/inMemoryServers/filesystem.ts index bb23be935..a55d0a780 100644 --- a/src/main/presenter/mcpPresenter/inMemoryServers/filesystem.ts +++ b/src/main/presenter/mcpPresenter/inMemoryServers/filesystem.ts @@ -175,7 +175,7 @@ export class FileSystemServer { throw new Error('Access denied - symlink target outside allowed directories') } return realPath - } catch (error) { + } catch { // For new files that don't exist yet, verify parent directory const parentDir = path.dirname(absolute) try { diff --git a/src/main/presenter/proxyConfig.ts b/src/main/presenter/proxyConfig.ts index 0b76bd7fd..82cedd22b 100644 --- a/src/main/presenter/proxyConfig.ts +++ b/src/main/presenter/proxyConfig.ts @@ -147,7 +147,7 @@ export class ProxyConfig { try { // 检查URL格式,确保开头是http://或https:// const urlPattern = - /^(http|https):\/\/(?:([^:@\/]+)(?::([^@\/]*))?@)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(:[0-9]+)?(\/[^\s]*)?$/ + /^(http|https):\/\/(?:([^:@/]+)(?::([^@/]*))?@)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(:[0-9]+)?(\/[^\s]*)?$/ if (!urlPattern.test(url)) { return false } diff --git a/src/main/presenter/sqlitePresenter/importData.ts b/src/main/presenter/sqlitePresenter/importData.ts index a2fe3d4c2..5540725b2 100644 --- a/src/main/presenter/sqlitePresenter/importData.ts +++ b/src/main/presenter/sqlitePresenter/importData.ts @@ -99,9 +99,9 @@ export class DataImporter { try { // 执行事务并返回导入的会话数量 return importTransaction() - } catch (error) { + } catch { // 事务会自动回滚,直接抛出错误 - throw error + throw new Error('Failed to import data') } } diff --git a/src/main/presenter/threadPresenter/contentEnricher.ts b/src/main/presenter/threadPresenter/contentEnricher.ts index ac2b05487..0aa13a8b6 100644 --- a/src/main/presenter/threadPresenter/contentEnricher.ts +++ b/src/main/presenter/threadPresenter/contentEnricher.ts @@ -330,7 +330,7 @@ export class ContentEnricher { let url = href try { url = href.startsWith('http') ? href : new URL(href, baseUrl).toString() - } catch (error) { + } catch { // 如果URL构建失败,使用原始href } markdown += `- [${text}](${url})\n` @@ -348,7 +348,7 @@ export class ContentEnricher { let imageUrl = src try { imageUrl = src.startsWith('http') ? src : new URL(src, baseUrl).toString() - } catch (error) { + } catch { // 如果URL构建失败,使用原始src } markdown += `![${alt}](${imageUrl})\n` diff --git a/src/main/presenter/threadPresenter/messageManager.ts b/src/main/presenter/threadPresenter/messageManager.ts index c079a84b2..59138916f 100644 --- a/src/main/presenter/threadPresenter/messageManager.ts +++ b/src/main/presenter/threadPresenter/messageManager.ts @@ -96,7 +96,11 @@ export class MessageManager implements IMessageManager { const msg = this.convertToMessage(message) eventBus.sendToRenderer(CONVERSATION_EVENTS.MESSAGE_EDITED, SendTarget.ALL_WINDOWS, messageId) if (msg.parentId) { - eventBus.sendToRenderer(CONVERSATION_EVENTS.MESSAGE_EDITED, SendTarget.ALL_WINDOWS, msg.parentId) + eventBus.sendToRenderer( + CONVERSATION_EVENTS.MESSAGE_EDITED, + SendTarget.ALL_WINDOWS, + msg.parentId + ) } return msg } @@ -279,7 +283,7 @@ export class MessageManager implements IMessageManager { let content: AssistantMessageBlock[] = [] try { content = message.content as AssistantMessageBlock[] - } catch (e) { + } catch { content = [] } diff --git a/src/renderer/src/components/settings/CommonSettings.vue b/src/renderer/src/components/settings/CommonSettings.vue index 36656b850..c0b57a7e9 100644 --- a/src/renderer/src/components/settings/CommonSettings.vue +++ b/src/renderer/src/components/settings/CommonSettings.vue @@ -482,7 +482,7 @@ const validateProxyUrl = () => { } const urlPattern = - /^(http|https):\/\/(?:([^:@\/]+)(?::([^@\/]*))?@)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(:[0-9]+)?(\/[^\s]*)?$/ + /^(http|https):\/\/(?:([^:@/]+)(?::([^@/]*))?@)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(:[0-9]+)?(\/[^\s]*)?$/ const isValid = urlPattern.test(customProxyUrl.value) diff --git a/src/renderer/src/i18n/fr-FR/index.ts b/src/renderer/src/i18n/fr-FR/index.ts index 3a7eed5d8..f3f63726b 100644 --- a/src/renderer/src/i18n/fr-FR/index.ts +++ b/src/renderer/src/i18n/fr-FR/index.ts @@ -28,7 +28,7 @@ const others = { DashScope: 'Alibaba Bailian', Hunyuan: 'Hunyuan', searchDisclaimer: - 'DeepChat est uniquement un outil d\'assistance qui organise et résume les données publiques retournées par les moteurs de recherche lorsque les utilisateurs initient activement des recherches, aidant les utilisateurs à visualiser et comprendre plus facilement les résultats de recherche.\n1. Utilisation des données publiques\nCe logiciel ne traite que les données accessibles publiquement sur les sites cibles ou les moteurs de recherche sans nécessiter de connexion. Avant utilisation, veuillez consulter et respecter les conditions d\'utilisation du site ou du moteur de recherche cible pour garantir la légalité de votre utilisation.\n2. Exactitude et responsabilité des informations\nLe contenu organisé et généré par ce logiciel est fourni à titre de référence uniquement et ne constitue en aucun cas un conseil juridique, commercial ou autre. Les développeurs ne garantissent pas l\'exactitude, l\'exhaustivité, l\'actualité ou la légalité des résultats de recherche, et toute conséquence découlant de l\'utilisation de ce logiciel relève de la seule responsabilité de l\'utilisateur.\n3. Clause de non-responsabilité\nCe logiciel est fourni \"en l\'état\", et les développeurs n\'assument aucune garantie expresse ou implicite quant à ses performances, sa stabilité ou son applicabilité. Lors de l\'utilisation de ce logiciel, les développeurs n\'assument aucune responsabilité pour tout litige, perte ou responsabilité légale résultant de violations des lois et règlements applicables ou des règles du site cible.\n4. Autodiscipline de l\'utilisateur\nAvant d\'utiliser ce logiciel, les utilisateurs doivent pleinement comprendre et confirmer que leur utilisation ne porte pas atteinte aux droits de propriété intellectuelle, aux secrets commerciaux ou à d\'autres droits légitimes d\'autrui. Tout litige ou conséquence juridique résultant d\'une utilisation inappropriée de ce logiciel par les utilisateurs relève de leur seule responsabilité.\nL\'utilisation de ce logiciel indique que l\'utilisateur a lu, compris et accepté toutes les conditions de cette clause de non-responsabilité. En cas de doute, veuillez consulter un conseiller juridique professionnel.' + 'DeepChat est uniquement un outil d\'assistance qui organise et résume les données publiques retournées par les moteurs de recherche lorsque les utilisateurs initient activement des recherches, aidant les utilisateurs à visualiser et comprendre plus facilement les résultats de recherche.\n1. Utilisation des données publiques\nCe logiciel ne traite que les données accessibles publiquement sur les sites cibles ou les moteurs de recherche sans nécessiter de connexion. Avant utilisation, veuillez consulter et respecter les conditions d\'utilisation du site ou du moteur de recherche cible pour garantir la légalité de votre utilisation.\n2. Exactitude et responsabilité des informations\nLe contenu organisé et généré par ce logiciel est fourni à titre de référence uniquement et ne constitue en aucun cas un conseil juridique, commercial ou autre. Les développeurs ne garantissent pas l\'exactitude, l\'exhaustivité, l\'actualité ou la légalité des résultats de recherche, et toute conséquence découlant de l\'utilisation de ce logiciel relève de la seule responsabilité de l\'utilisateur.\n3. Clause de non-responsabilité\nCe logiciel est fourni "en l\'état", et les développeurs n\'assument aucune garantie expresse ou implicite quant à ses performances, sa stabilité ou son applicabilité. Lors de l\'utilisation de ce logiciel, les développeurs n\'assument aucune responsabilité pour tout litige, perte ou responsabilité légale résultant de violations des lois et règlements applicables ou des règles du site cible.\n4. Autodiscipline de l\'utilisateur\nAvant d\'utiliser ce logiciel, les utilisateurs doivent pleinement comprendre et confirmer que leur utilisation ne porte pas atteinte aux droits de propriété intellectuelle, aux secrets commerciaux ou à d\'autres droits légitimes d\'autrui. Tout litige ou conséquence juridique résultant d\'une utilisation inappropriée de ce logiciel par les utilisateurs relève de leur seule responsabilité.\nL\'utilisation de ce logiciel indique que l\'utilisateur a lu, compris et accepté toutes les conditions de cette clause de non-responsabilité. En cas de doute, veuillez consulter un conseiller juridique professionnel.' } export default {