From fb865d9f44139782e00eb8ca69734d773d8e19c0 Mon Sep 17 00:00:00 2001 From: haishan Date: Fri, 6 Oct 2023 12:30:24 +0800 Subject: [PATCH] eslintrc package pnpm-lock configs connections fetch rule-provider rules traffic version Rules About BackendErrorFallback GitHubIcon errors types --- .eslintrc.yml | 15 +++++++++-- package.json | 1 + pnpm-lock.yaml | 23 +++++++++++++++++ src/api/configs.ts | 16 +++++++++--- src/api/connections.ts | 4 +-- src/api/fetch.ts | 25 ++++++++++++++++++- src/api/rule-provider.ts | 19 +++----------- src/api/rules.ts | 19 ++------------ src/api/traffic.ts | 6 ++--- src/api/version.ts | 21 +++------------- src/components/Rules.tsx | 2 -- src/components/about/About.tsx | 4 +-- src/components/error/BackendErrorFallback.tsx | 10 ++++---- src/components/icon/GitHubIcon.tsx | 7 ++++-- src/misc/errors.ts | 12 ++++++--- src/types.ts | 2 +- 16 files changed, 109 insertions(+), 77 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 201d0163c..c4c7605ba 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -4,8 +4,13 @@ parserOptions: project: tsconfig.json sourceType: module +settings: + react: + version: detect + plugins: - simple-import-sort + - unused-imports - jsx-a11y extends: @@ -30,8 +35,14 @@ rules: '@typescript-eslint/no-explicit-any': 'off' '@typescript-eslint/camelcase': 'off' 'no-use-before-define': 'off' - '@typescript-eslint/no-unused-vars': - - 'error' + # '@typescript-eslint/no-unused-vars': + # - 'error' + # - argsIgnorePattern: '^_' + ## disable '@typescript-eslint/no-unused-vars' and use 'unused-imports' plugin/rules instead + '@typescript-eslint/no-unused-vars': 'off' + 'unused-imports/no-unused-imports': 'error' + 'unused-imports/no-unused-vars': + - 'warn' - argsIgnorePattern: '^_' '@typescript-eslint/no-use-before-define': - error diff --git a/package.json b/package.json index 42c2e2871..59a6ff793 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-unused-imports": "3.0.0", "postcss": "8.4.31", "postcss-import": "15.1.0", "postcss-simple-vars": "^7.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ebd368a33..239fdb3cd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -195,6 +195,9 @@ devDependencies: eslint-plugin-simple-import-sort: specifier: ^10.0.0 version: 10.0.0(eslint@8.50.0) + eslint-plugin-unused-imports: + specifier: 3.0.0 + version: 3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0) postcss: specifier: 8.4.31 version: 8.4.31 @@ -3782,6 +3785,26 @@ packages: eslint: 8.50.0 dev: true + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.7.3)(eslint@8.50.0): + resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2) + eslint: 8.50.0 + eslint-rule-composer: 0.3.0 + dev: true + + /eslint-rule-composer@0.3.0: + resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} + engines: {node: '>=4.0.0'} + dev: true + /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} diff --git a/src/api/configs.ts b/src/api/configs.ts index 4fdbe565a..91e788ab7 100644 --- a/src/api/configs.ts +++ b/src/api/configs.ts @@ -2,7 +2,7 @@ import { getURLAndInit } from 'src/misc/request-helper'; import { ClashGeneralConfig } from 'src/store/types'; import { ClashAPIConfig } from 'src/types'; -import { req } from './fetch'; +import { handleFetchError, req, validateFetchResponse } from './fetch'; const endpoint = '/configs'; @@ -10,7 +10,13 @@ export async function fetchConfigs2(ctx: { queryKey: readonly [string, ClashAPIC const endpoint = ctx.queryKey[0]; const apiConfig = ctx.queryKey[1]; const { url, init } = getURLAndInit(apiConfig); - const res = await fetch(url + endpoint, init); + let res: Response; + try { + res = await req(url + endpoint, init); + } catch (err) { + handleFetchError(err, { endpoint, apiConfig }); + } + validateFetchResponse(res, { endpoint, apiConfig }); if (!res.ok) { throw new Error('TODO'); } @@ -27,7 +33,11 @@ export function updateConfigs(apiConfig: ClashAPIConfig) { export async function fetchConfigs(apiConfig: ClashAPIConfig) { const { url, init } = getURLAndInit(apiConfig); - return await req(url + endpoint, init); + try { + return await req(url + endpoint, init); + } catch (err) { + handleFetchError(err, { endpoint, apiConfig }); + } } // TODO support PUT /configs diff --git a/src/api/connections.ts b/src/api/connections.ts index a5949d421..6e2f6f3a2 100644 --- a/src/api/connections.ts +++ b/src/api/connections.ts @@ -56,13 +56,13 @@ export function fetchData(apiConfig: ClashAPIConfig, listener?: unknown): Unsubs if (ws && ws.readyState <= WebSocket.OPEN) { if (listener) return subscribe(listener); return; - }; + } const url = buildWebSocketURL(apiConfig, endpoint); ws = new WebSocket(url); const onFrozen = () => { - if (ws.readyState <= WebSocket.OPEN) ws.close() + if (ws.readyState <= WebSocket.OPEN) ws.close(); }; const onResume = () => { if (ws.readyState <= WebSocket.OPEN) return; diff --git a/src/api/fetch.ts b/src/api/fetch.ts index 6b2724c74..c02b73d87 100644 --- a/src/api/fetch.ts +++ b/src/api/fetch.ts @@ -1,7 +1,12 @@ import isNetworkError from 'is-network-error'; import { YacdBackendUnauthorizedError, YacdFetchNetworkError } from '$src/misc/errors'; -import { FetchCtx } from '$src/types'; +import { getURLAndInit } from '$src/misc/request-helper'; +import { ClashAPIConfig, FetchCtx } from '$src/types'; + +export type QueryCtx = { + queryKey: readonly [string, ClashAPIConfig]; +}; export function req(url: string, init: RequestInit) { if (import.meta.env.DEV) { @@ -10,6 +15,24 @@ export function req(url: string, init: RequestInit) { return fetch(url, init); } +export async function query(ctx: QueryCtx) { + const endpoint = ctx.queryKey[0]; + const apiConfig = ctx.queryKey[1]; + const { url, init } = getURLAndInit(apiConfig); + + let res: Response; + try { + res = await req(url + endpoint, init); + } catch (err) { + handleFetchError(err, { endpoint, apiConfig }); + } + validateFetchResponse(res, { endpoint, apiConfig }); + if (res.ok) { + return await res.json(); + } + // can return undefined +} + export function handleFetchError(err: unknown, ctx: FetchCtx) { if (isNetworkError(err)) throw new YacdFetchNetworkError('', ctx); throw err; diff --git a/src/api/rule-provider.ts b/src/api/rule-provider.ts index 4d3c3ac19..e219eb5ca 100644 --- a/src/api/rule-provider.ts +++ b/src/api/rule-provider.ts @@ -1,6 +1,8 @@ import { getURLAndInit } from 'src/misc/request-helper'; import { ClashAPIConfig } from 'src/types'; +import { query, QueryCtx } from './fetch'; + export type RuleProvider = RuleProviderAPIItem & { idx: number }; export type RuleProviderAPIItem = { @@ -31,21 +33,8 @@ function normalizeAPIResponse(data: RuleProviderAPIData) { return { byName, names }; } -export async function fetchRuleProviders(ctx: { queryKey: readonly [string, ClashAPIConfig] }) { - const endpoint = ctx.queryKey[0]; - const apiConfig = ctx.queryKey[1]; - const { url, init } = getURLAndInit(apiConfig); - let data = { providers: {} }; - try { - const res = await fetch(url + endpoint, init); - if (res.ok) { - data = await res.json(); - } - } catch (err) { - // log and ignore - // eslint-disable-next-line no-console - console.log('failed to GET /providers/rules', err); - } +export async function fetchRuleProviders(ctx: QueryCtx) { + const data = (await query(ctx)) || { providers: {} }; return normalizeAPIResponse(data); } diff --git a/src/api/rules.ts b/src/api/rules.ts index 8a439de57..d54583408 100644 --- a/src/api/rules.ts +++ b/src/api/rules.ts @@ -1,9 +1,7 @@ import invariant from 'invariant'; -import { getURLAndInit } from 'src/misc/request-helper'; import { ClashAPIConfig } from 'src/types'; -import { handleFetchError, req, validateFetchResponse } from './fetch'; -// const endpoint = '/rules'; +import { query } from './fetch'; type RuleItem = RuleAPIItem & { id: number }; @@ -24,19 +22,6 @@ function normalizeAPIResponse(json: { rules: Array }): Array { - if (ws.readyState <= WebSocket.OPEN) ws.close() + if (ws.readyState <= WebSocket.OPEN) ws.close(); }; const onResume = () => { @@ -68,12 +68,12 @@ export function fetchData(apiConfig: ClashAPIConfig) { document.addEventListener('freeze', onFrozen, { capture: true, once: true }); document.addEventListener('resume', onResume, { capture: true, once: true }); - ws.addEventListener('error', function(_ev) { + ws.addEventListener('error', function (_ev) { console.log('error', _ev); // }); // ws.addEventListener('close', (_ev) => {}); - ws.addEventListener('message', function(event) { + ws.addEventListener('message', function (event) { parseAndAppend(event.data); }); return traffic; diff --git a/src/api/version.ts b/src/api/version.ts index bbb3be456..e1d4e7b89 100644 --- a/src/api/version.ts +++ b/src/api/version.ts @@ -1,26 +1,11 @@ -import { getURLAndInit } from 'src/misc/request-helper'; -import { ClashAPIConfig } from 'src/types'; +import { query, QueryCtx } from './fetch'; type VersionData = { version?: string; premium?: boolean; }; -export async function fetchVersion( - endpoint: string, - apiConfig: ClashAPIConfig, -): Promise { - let json = {}; - try { - const { url, init } = getURLAndInit(apiConfig); - const res = await fetch(url + endpoint, init); - if (res.ok) { - json = await res.json(); - } - } catch (err) { - // log and ignore - // eslint-disable-next-line no-console - console.log(`failed to fetch ${endpoint}`, err); - } +export async function fetchVersion(ctx: QueryCtx): Promise { + const json = (await query(ctx)) || {}; return json; } diff --git a/src/components/Rules.tsx b/src/components/Rules.tsx index 812b30394..4622d0964 100644 --- a/src/components/Rules.tsx +++ b/src/components/Rules.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { areEqual, VariableSizeList } from 'react-window'; -import { toast } from 'sonner'; import { RuleProviderItem } from '$src/components/rules/RuleProviderItem'; import { useRuleAndProvider } from '$src/components/rules/rules.hooks'; @@ -15,7 +14,6 @@ import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight'; import ContentHeader from './ContentHeader'; import Rule from './Rule'; import s from './Rules.module.scss'; -import { useNavigate } from 'react-router'; const { memo } = React; diff --git a/src/components/about/About.tsx b/src/components/about/About.tsx index 1ad556bc8..c35fa6bc3 100644 --- a/src/components/about/About.tsx +++ b/src/components/about/About.tsx @@ -27,9 +27,7 @@ function Version({ name, link, version }: { name: string; link: string; version: export function About() { const apiConfig = useApiConfig(); - const { data: version } = useQuery(['/version', apiConfig], () => - fetchVersion('/version', apiConfig), - ); + const { data: version } = useQuery(['/version', apiConfig], fetchVersion); return ( <> diff --git a/src/components/error/BackendErrorFallback.tsx b/src/components/error/BackendErrorFallback.tsx index 44e11a5c4..07986ccf8 100644 --- a/src/components/error/BackendErrorFallback.tsx +++ b/src/components/error/BackendErrorFallback.tsx @@ -47,11 +47,11 @@ export function BackendUnauthorizedErrorFallback(props: { return (

Unauthorized to connect to the backend {ctx.apiConfig.baseURL}

- { - ctx.apiConfig.secret ? -

You might using a wrong secret

- :

You probably need to provide a secret

- } + {ctx.apiConfig.secret ? ( +

You might using a wrong secret

+ ) : ( +

You probably need to provide a secret

+ )}
diff --git a/src/components/icon/GitHubIcon.tsx b/src/components/icon/GitHubIcon.tsx index 54bcb35e8..2b5d8237b 100644 --- a/src/components/icon/GitHubIcon.tsx +++ b/src/components/icon/GitHubIcon.tsx @@ -1,11 +1,14 @@ import React from 'react'; -export function GitHubIcon(props: { width?: number; height?: number; size?: number; }) { +export function GitHubIcon(props: { width?: number; height?: number; size?: number }) { const width = props.width || props.size || 16; const height = props.height || props.size || 16; return ( - + ); } diff --git a/src/misc/errors.ts b/src/misc/errors.ts index 93bf7f80e..c59c95a7b 100644 --- a/src/misc/errors.ts +++ b/src/misc/errors.ts @@ -1,4 +1,4 @@ -import { ClashAPIConfig } from "$src/types"; +import { ClashAPIConfig } from '$src/types'; export const DOES_NOT_SUPPORT_FETCH = 0; @@ -12,13 +12,19 @@ export class YacdError extends Error { } export class YacdFetchNetworkError extends Error { - constructor(public message: string, public ctx: { endpoint: string; apiConfig: ClashAPIConfig; }) { + constructor( + public message: string, + public ctx: { endpoint: string; apiConfig: ClashAPIConfig }, + ) { super(message); } } export class YacdBackendUnauthorizedError extends Error { - constructor(public message: string, public ctx: { endpoint: string; apiConfig: ClashAPIConfig; }) { + constructor( + public message: string, + public ctx: { endpoint: string; apiConfig: ClashAPIConfig }, + ) { super(message); } } diff --git a/src/types.ts b/src/types.ts index a03ddc78e..716ff1186 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,4 +14,4 @@ export type RuleType = { id?: number; type?: string; payload?: string; proxy?: s export type FetchCtx = { endpoint: string; apiConfig: ClashAPIConfig; -} +};