diff --git a/eslint.config.ts b/eslint.config.ts index 1d8babc3..4c1c2e4b 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -1,15 +1,23 @@ import js from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +import pluginReactHooks from "eslint-plugin-react-hooks"; +import { defineConfig } from "eslint/config"; import globals from "globals"; import tseslint from "typescript-eslint"; -import pluginReact from "eslint-plugin-react"; -import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], - plugins: { js }, + plugins: { + js, + "react-hooks": pluginReactHooks, + }, extends: ["js/recommended"], languageOptions: { globals: globals.browser }, + rules: { + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "error", + }, }, tseslint.configs.recommended, pluginReact.configs.flat["jsx-runtime"], diff --git a/package.json b/package.json index 92adbbde..7ec4811e 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "cross-env": "^10.0.0", "eslint": "^9.35.0", "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", "glob": "^11.0.3", "globals": "^16.4.0", "https-proxy-agent": "^7.0.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54589a32..5534b76d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,6 +180,9 @@ importers: eslint-plugin-react: specifier: ^7.37.5 version: 7.37.5(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.35.0(jiti@2.5.1)) glob: specifier: ^11.0.3 version: 11.0.3 @@ -2205,6 +2208,12 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} @@ -5914,6 +5923,10 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)): + dependencies: + eslint: 9.35.0(jiti@2.5.1) + eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.5.1)): dependencies: array-includes: 3.1.9 diff --git a/src/components/base/base-search-box.tsx b/src/components/base/base-search-box.tsx index a8bd2c44..c41aaf2b 100644 --- a/src/components/base/base-search-box.tsx +++ b/src/components/base/base-search-box.tsx @@ -81,8 +81,8 @@ export const BaseSearchBox = (props: SearchProps) => { return (content: string) => { if (!searchText) return true; - let item = !matchCase ? content.toLowerCase() : content; - let searchItem = !matchCase ? searchText.toLowerCase() : searchText; + const item = !matchCase ? content.toLowerCase() : content; + const searchItem = !matchCase ? searchText.toLowerCase() : searchText; if (useRegularExpression) { return new RegExp(searchItem).test(item); diff --git a/src/components/profile/group-item.tsx b/src/components/profile/group-item.tsx index b069d187..04f7e338 100644 --- a/src/components/profile/group-item.tsx +++ b/src/components/profile/group-item.tsx @@ -19,7 +19,7 @@ interface Props { } export const GroupItem = (props: Props) => { - let { type, group, onDelete } = props; + const { type, group, onDelete } = props; const sortable = type === "prepend" || type === "append"; const { diff --git a/src/components/profile/groups-editor-viewer.tsx b/src/components/profile/groups-editor-viewer.tsx index 0c94cc37..b8d3671b 100644 --- a/src/components/profile/groups-editor-viewer.tsx +++ b/src/components/profile/groups-editor-viewer.tsx @@ -159,8 +159,8 @@ export const GroupsEditorViewer = (props: Props) => { } }; const fetchContent = async () => { - let data = await readProfileFile(property); - let obj = yaml.load(data) as ISeqProfileConfig | null; + const data = await readProfileFile(property); + const obj = yaml.load(data) as ISeqProfileConfig | null; setPrependSeq(obj?.prepend || []); setAppendSeq(obj?.append || []); @@ -174,7 +174,7 @@ export const GroupsEditorViewer = (props: Props) => { if (currData === "") return; if (visualization !== true) return; - let obj = yaml.load(currData) as { + const obj = yaml.load(currData) as { prepend: []; append: []; delete: []; @@ -209,21 +209,21 @@ export const GroupsEditorViewer = (props: Props) => { }, [prependSeq, appendSeq, deleteSeq]); const fetchProxyPolicy = async () => { - let data = await readProfileFile(profileUid); - let proxiesData = await readProfileFile(proxiesUid); - let originGroupsObj = yaml.load(data) as { + const data = await readProfileFile(profileUid); + const proxiesData = await readProfileFile(proxiesUid); + const originGroupsObj = yaml.load(data) as { "proxy-groups": IProxyGroupConfig[]; } | null; - let originProxiesObj = yaml.load(data) as { proxies: [] } | null; - let originProxies = originProxiesObj?.proxies || []; - let moreProxiesObj = yaml.load(proxiesData) as ISeqProfileConfig | null; - let morePrependProxies = moreProxiesObj?.prepend || []; - let moreAppendProxies = moreProxiesObj?.append || []; - let moreDeleteProxies = + const originProxiesObj = yaml.load(data) as { proxies: [] } | null; + const originProxies = originProxiesObj?.proxies || []; + const moreProxiesObj = yaml.load(proxiesData) as ISeqProfileConfig | null; + const morePrependProxies = moreProxiesObj?.prepend || []; + const moreAppendProxies = moreProxiesObj?.append || []; + const moreDeleteProxies = moreProxiesObj?.delete || ([] as string[] | { name: string }[]); - let proxies = morePrependProxies.concat( + const proxies = morePrependProxies.concat( originProxies.filter((proxy: any) => { if (proxy.name) { return !moreDeleteProxies.includes(proxy.name); @@ -246,28 +246,30 @@ export const GroupsEditorViewer = (props: Props) => { ); }; const fetchProfile = async () => { - let data = await readProfileFile(profileUid); - let mergeData = await readProfileFile(mergeUid); - let globalMergeData = await readProfileFile("Merge"); + const data = await readProfileFile(profileUid); + const mergeData = await readProfileFile(mergeUid); + const globalMergeData = await readProfileFile("Merge"); - let originGroupsObj = yaml.load(data) as { + const originGroupsObj = yaml.load(data) as { "proxy-groups": IProxyGroupConfig[]; } | null; - let originProviderObj = yaml.load(data) as { "proxy-providers": {} } | null; - let originProvider = originProviderObj?.["proxy-providers"] || {}; - - let moreProviderObj = yaml.load(mergeData) as { + const originProviderObj = yaml.load(data) as { "proxy-providers": {}; } | null; - let moreProvider = moreProviderObj?.["proxy-providers"] || {}; + const originProvider = originProviderObj?.["proxy-providers"] || {}; - let globalProviderObj = yaml.load(globalMergeData) as { + const moreProviderObj = yaml.load(mergeData) as { "proxy-providers": {}; } | null; - let globalProvider = globalProviderObj?.["proxy-providers"] || {}; + const moreProvider = moreProviderObj?.["proxy-providers"] || {}; - let provider = Object.assign( + const globalProviderObj = yaml.load(globalMergeData) as { + "proxy-providers": {}; + } | null; + const globalProvider = globalProviderObj?.["proxy-providers"] || {}; + + const provider = Object.assign( {}, originProvider, moreProvider, @@ -278,7 +280,7 @@ export const GroupsEditorViewer = (props: Props) => { setGroupList(originGroupsObj?.["proxy-groups"] || []); }; const getInterfaceNameList = async () => { - let list = await getNetworkInterfaces(); + const list = await getNetworkInterfaces(); setInterfaceNameList(list); }; useEffect(() => { @@ -293,7 +295,7 @@ export const GroupsEditorViewer = (props: Props) => { }, [open]); const validateGroup = () => { - let group = formIns.getValues(); + const group = formIns.getValues(); if (group.name === "") { throw new Error(t("Group Name Required")); } @@ -794,7 +796,7 @@ export const GroupsEditorViewer = (props: Props) => { } increaseViewportBy={256} itemContent={(index) => { - let shift = filteredPrependSeq.length > 0 ? 1 : 0; + const shift = filteredPrependSeq.length > 0 ? 1 : 0; if (filteredPrependSeq.length > 0 && index === 0) { return ( { ); } else if (index < filteredGroupList.length + shift) { - let newIndex = index - shift; + const newIndex = index - shift; return ( { }; // 优化:异步分片解析,避免主线程阻塞,解析完成后批量setState const handleParseAsync = (cb: (proxies: IProxyConfig[]) => void) => { - let proxies: IProxyConfig[] = []; - let names: string[] = []; + const proxies: IProxyConfig[] = []; + const names: string[] = []; let uris = ""; try { uris = atob(proxyUri); @@ -148,7 +148,7 @@ export const ProxiesEditorViewer = (props: Props) => { for (; idx < end; idx++) { const uri = lines[idx]; try { - let proxy = parseUri(uri.trim()); + const proxy = parseUri(uri.trim()); if (!names.includes(proxy.name)) { proxies.push(proxy); names.push(proxy.name); @@ -171,9 +171,9 @@ export const ProxiesEditorViewer = (props: Props) => { parseBatch(); }; const fetchProfile = async () => { - let data = await readProfileFile(profileUid); + const data = await readProfileFile(profileUid); - let originProxiesObj = yaml.load(data) as { + const originProxiesObj = yaml.load(data) as { proxies: IProxyConfig[]; } | null; @@ -181,8 +181,8 @@ export const ProxiesEditorViewer = (props: Props) => { }; const fetchContent = async () => { - let data = await readProfileFile(property); - let obj = yaml.load(data) as ISeqProfileConfig | null; + const data = await readProfileFile(property); + const obj = yaml.load(data) as ISeqProfileConfig | null; setPrependSeq(obj?.prepend || []); setAppendSeq(obj?.append || []); @@ -196,7 +196,7 @@ export const ProxiesEditorViewer = (props: Props) => { if (currData === "") return; if (visualization !== true) return; - let obj = yaml.load(currData) as { + const obj = yaml.load(currData) as { prepend: []; append: []; delete: []; @@ -342,7 +342,7 @@ export const ProxiesEditorViewer = (props: Props) => { } increaseViewportBy={256} itemContent={(index) => { - let shift = filteredPrependSeq.length > 0 ? 1 : 0; + const shift = filteredPrependSeq.length > 0 ? 1 : 0; if (filteredPrependSeq.length > 0 && index === 0) { return ( { ); } else if (index < filteredProxyList.length + shift) { - let newIndex = index - shift; + const newIndex = index - shift; return ( { - let { type, proxy, onDelete } = props; + const { type, proxy, onDelete } = props; const sortable = type === "prepend" || type === "append"; const { diff --git a/src/components/profile/rule-item.tsx b/src/components/profile/rule-item.tsx index 7544a4a8..59bb34a0 100644 --- a/src/components/profile/rule-item.tsx +++ b/src/components/profile/rule-item.tsx @@ -16,7 +16,7 @@ interface Props { } export const RuleItem = (props: Props) => { - let { type, ruleRaw, onDelete } = props; + const { type, ruleRaw, onDelete } = props; const sortable = type === "prepend" || type === "append"; const rule = ruleRaw.replace(",no-resolve", ""); diff --git a/src/components/profile/rules-editor-viewer.tsx b/src/components/profile/rules-editor-viewer.tsx index 5d165d51..0e950b42 100644 --- a/src/components/profile/rules-editor-viewer.tsx +++ b/src/components/profile/rules-editor-viewer.tsx @@ -287,8 +287,8 @@ export const RulesEditorViewer = (props: Props) => { const { active, over } = event; if (over) { if (active.id !== over.id) { - let activeIndex = prependSeq.indexOf(active.id.toString()); - let overIndex = prependSeq.indexOf(over.id.toString()); + const activeIndex = prependSeq.indexOf(active.id.toString()); + const overIndex = prependSeq.indexOf(over.id.toString()); setPrependSeq(reorder(prependSeq, activeIndex, overIndex)); } } @@ -297,15 +297,15 @@ export const RulesEditorViewer = (props: Props) => { const { active, over } = event; if (over) { if (active.id !== over.id) { - let activeIndex = appendSeq.indexOf(active.id.toString()); - let overIndex = appendSeq.indexOf(over.id.toString()); + const activeIndex = appendSeq.indexOf(active.id.toString()); + const overIndex = appendSeq.indexOf(over.id.toString()); setAppendSeq(reorder(appendSeq, activeIndex, overIndex)); } } }; const fetchContent = async () => { - let data = await readProfileFile(property); - let obj = yaml.load(data) as ISeqProfileConfig | null; + const data = await readProfileFile(property); + const obj = yaml.load(data) as ISeqProfileConfig | null; setPrependSeq(obj?.prepend || []); setAppendSeq(obj?.append || []); @@ -319,7 +319,7 @@ export const RulesEditorViewer = (props: Props) => { if (currData === "") return; if (visualization !== true) return; - let obj = yaml.load(currData) as ISeqProfileConfig | null; + const obj = yaml.load(currData) as ISeqProfileConfig | null; setPrependSeq(obj?.prepend || []); setAppendSeq(obj?.append || []); setDeleteSeq(obj?.delete || []); @@ -349,21 +349,21 @@ export const RulesEditorViewer = (props: Props) => { }, [prependSeq, appendSeq, deleteSeq]); const fetchProfile = async () => { - let data = await readProfileFile(profileUid); // 原配置文件 - let groupsData = await readProfileFile(groupsUid); // groups配置文件 - let mergeData = await readProfileFile(mergeUid); // merge配置文件 - let globalMergeData = await readProfileFile("Merge"); // global merge配置文件 + const data = await readProfileFile(profileUid); // 原配置文件 + const groupsData = await readProfileFile(groupsUid); // groups配置文件 + const mergeData = await readProfileFile(mergeUid); // merge配置文件 + const globalMergeData = await readProfileFile("Merge"); // global merge配置文件 - let rulesObj = yaml.load(data) as { rules: [] } | null; + const rulesObj = yaml.load(data) as { rules: [] } | null; - let originGroupsObj = yaml.load(data) as { "proxy-groups": [] } | null; - let originGroups = originGroupsObj?.["proxy-groups"] || []; - let moreGroupsObj = yaml.load(groupsData) as ISeqProfileConfig | null; - let morePrependGroups = moreGroupsObj?.["prepend"] || []; - let moreAppendGroups = moreGroupsObj?.["append"] || []; - let moreDeleteGroups = + const originGroupsObj = yaml.load(data) as { "proxy-groups": [] } | null; + const originGroups = originGroupsObj?.["proxy-groups"] || []; + const moreGroupsObj = yaml.load(groupsData) as ISeqProfileConfig | null; + const morePrependGroups = moreGroupsObj?.["prepend"] || []; + const moreAppendGroups = moreGroupsObj?.["append"] || []; + const moreDeleteGroups = moreGroupsObj?.["delete"] || ([] as string[] | { name: string }[]); - let groups = morePrependGroups.concat( + const groups = morePrependGroups.concat( originGroups.filter((group: any) => { if (group.name) { return !moreDeleteGroups.includes(group.name); @@ -374,27 +374,37 @@ export const RulesEditorViewer = (props: Props) => { moreAppendGroups, ); - let originRuleSetObj = yaml.load(data) as { "rule-providers": {} } | null; - let originRuleSet = originRuleSetObj?.["rule-providers"] || {}; - let moreRuleSetObj = yaml.load(mergeData) as { + const originRuleSetObj = yaml.load(data) as { "rule-providers": {} } | null; + const originRuleSet = originRuleSetObj?.["rule-providers"] || {}; + const moreRuleSetObj = yaml.load(mergeData) as { "rule-providers": {}; } | null; - let moreRuleSet = moreRuleSetObj?.["rule-providers"] || {}; - let globalRuleSetObj = yaml.load(globalMergeData) as { + const moreRuleSet = moreRuleSetObj?.["rule-providers"] || {}; + const globalRuleSetObj = yaml.load(globalMergeData) as { "rule-providers": {}; } | null; - let globalRuleSet = globalRuleSetObj?.["rule-providers"] || {}; - let ruleSet = Object.assign({}, originRuleSet, moreRuleSet, globalRuleSet); + const globalRuleSet = globalRuleSetObj?.["rule-providers"] || {}; + const ruleSet = Object.assign( + {}, + originRuleSet, + moreRuleSet, + globalRuleSet, + ); - let originSubRuleObj = yaml.load(data) as { "sub-rules": {} } | null; - let originSubRule = originSubRuleObj?.["sub-rules"] || {}; - let moreSubRuleObj = yaml.load(mergeData) as { "sub-rules": {} } | null; - let moreSubRule = moreSubRuleObj?.["sub-rules"] || {}; - let globalSubRuleObj = yaml.load(globalMergeData) as { + const originSubRuleObj = yaml.load(data) as { "sub-rules": {} } | null; + const originSubRule = originSubRuleObj?.["sub-rules"] || {}; + const moreSubRuleObj = yaml.load(mergeData) as { "sub-rules": {} } | null; + const moreSubRule = moreSubRuleObj?.["sub-rules"] || {}; + const globalSubRuleObj = yaml.load(globalMergeData) as { "sub-rules": {}; } | null; - let globalSubRule = globalSubRuleObj?.["sub-rules"] || {}; - let subRule = Object.assign({}, originSubRule, moreSubRule, globalSubRule); + const globalSubRule = globalSubRuleObj?.["sub-rules"] || {}; + const subRule = Object.assign( + {}, + originSubRule, + moreSubRule, + globalSubRule, + ); setProxyPolicyList( builtinProxyPolicies.concat(groups.map((group: any) => group.name)), ); @@ -554,7 +564,7 @@ export const RulesEditorViewer = (props: Props) => { startIcon={} onClick={() => { try { - let raw = validateRule(); + const raw = validateRule(); if (prependSeq.includes(raw)) return; setPrependSeq([raw, ...prependSeq]); } catch (err: any) { @@ -572,7 +582,7 @@ export const RulesEditorViewer = (props: Props) => { startIcon={} onClick={() => { try { - let raw = validateRule(); + const raw = validateRule(); if (appendSeq.includes(raw)) return; setAppendSeq([...appendSeq, raw]); } catch (err: any) { @@ -601,7 +611,7 @@ export const RulesEditorViewer = (props: Props) => { } increaseViewportBy={256} itemContent={(index) => { - let shift = filteredPrependSeq.length > 0 ? 1 : 0; + const shift = filteredPrependSeq.length > 0 ? 1 : 0; if (filteredPrependSeq.length > 0 && index === 0) { return ( { ); } else if (index < filteredRuleList.length + shift) { - let newIndex = index - shift; + const newIndex = index - shift; return ( ((props, ref) => { const formatHosts = (hosts: any): string => { if (!hosts || typeof hosts !== "object") return ""; - let result: string[] = []; + const result: string[] = []; Object.entries(hosts).forEach(([domain, value]) => { if (Array.isArray(value)) { diff --git a/src/components/setting/mods/tun-viewer.tsx b/src/components/setting/mods/tun-viewer.tsx index be0d64a3..3468f34a 100644 --- a/src/components/setting/mods/tun-viewer.tsx +++ b/src/components/setting/mods/tun-viewer.tsx @@ -53,7 +53,7 @@ export const TunViewer = forwardRef((props, ref) => { const onSave = useLockFn(async () => { try { - let tun = { + const tun = { stack: values.stack, device: values.device === "" @@ -97,7 +97,7 @@ export const TunViewer = forwardRef((props, ref) => { variant="outlined" size="small" onClick={async () => { - let tun = { + const tun = { stack: "gvisor", device: OS === "macos" ? "utun1024" : "Mihomo", "auto-route": true, diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 22e34287..b44e3983 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -34,7 +34,7 @@ import { useLocalStorage } from "foxact/use-local-storage"; import { LogLevel } from "@/hooks/use-log-data"; const appWindow = getCurrentWebviewWindow(); -export let portableFlag = false; +export const portableFlag = false; dayjs.extend(relativeTime); diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx index 1e7540a4..a873a124 100644 --- a/src/pages/profiles.tsx +++ b/src/pages/profiles.tsx @@ -166,7 +166,7 @@ const ProfilePage = () => { async (event: any) => { const paths = event.payload.paths; - for (let file of paths) { + for (const file of paths) { if (!file.endsWith(".yaml") && !file.endsWith(".yml")) { showNotice("error", t("Only YAML Files Supported")); continue; @@ -181,7 +181,7 @@ const ProfilePage = () => { self_proxy: false, }, } as IProfileItem; - let data = await readTextFile(file); + const data = await readTextFile(file); await createProfile(item, data); await mutateProfiles(); } diff --git a/src/pages/test.tsx b/src/pages/test.tsx index b77aed37..45797f6b 100644 --- a/src/pages/test.tsx +++ b/src/pages/test.tsx @@ -101,12 +101,12 @@ const TestPage = () => { const { active, over } = event; if (over) { if (active.id !== over.id) { - let old_index = testList.findIndex((x) => x.uid === active.id); - let new_index = testList.findIndex((x) => x.uid === over.id); + const old_index = testList.findIndex((x) => x.uid === active.id); + const new_index = testList.findIndex((x) => x.uid === over.id); if (old_index < 0 || new_index < 0) { return; } - let newList = reorder(testList, old_index, new_index); + const newList = reorder(testList, old_index, new_index); await mutateVerge({ ...verge, test_list: newList }, false); await patchVerge({ test_list: newList }); } diff --git a/src/services/cmds.ts b/src/services/cmds.ts index fc875aff..04e7bd6f 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -217,20 +217,19 @@ export async function getProxies(): Promise<{ }, []); if (global?.all) { - let globalGroups: IProxyGroupItem[] = global.all.reduce( - (acc, name) => { - if (proxyRecord[name]?.all) { - acc.push({ - ...proxyRecord[name], - all: proxyRecord[name].all!.map((item) => generateItem(item)), - }); - } - return acc; - }, - [], - ); + const globalGroups: IProxyGroupItem[] = global.all.reduce< + IProxyGroupItem[] + >((acc, name) => { + if (proxyRecord[name]?.all) { + acc.push({ + ...proxyRecord[name], + all: proxyRecord[name].all!.map((item) => generateItem(item)), + }); + } + return acc; + }, []); - let globalNames = new Set(globalGroups.map((each) => each.name)); + const globalNames = new Set(globalGroups.map((each) => each.name)); groups = groups .filter((group) => { return !globalNames.has(group.name); @@ -674,7 +673,7 @@ export async function saveWebdavConfig( } export async function listWebDavBackup() { - let list: IWebDavFile[] = await invoke("list_webdav_backup"); + const list: IWebDavFile[] = await invoke("list_webdav_backup"); list.map((item) => { item.filename = item.href.split("/").pop() as string; }); diff --git a/src/utils/uri-parser.ts b/src/utils/uri-parser.ts index 0dfd3fd8..b25696dc 100644 --- a/src/utils/uri-parser.ts +++ b/src/utils/uri-parser.ts @@ -172,7 +172,7 @@ function URI_SS(line: string): IProxyShadowsocksConfig { if (query) { if (/(&|\?)v2ray-plugin=/.test(query)) { const parsed = query.match(/(&|\?)v2ray-plugin=(.*?)(&|$)/); - let v2rayPlugin = parsed![2]; + const v2rayPlugin = parsed![2]; if (v2rayPlugin) { proxy.plugin = "v2ray-plugin"; proxy["plugin-opts"] = JSON.parse( @@ -251,7 +251,7 @@ function URI_SSR(line: string): IProxyshadowsocksRConfig { serverAndPort.substring(serverAndPort.lastIndexOf(":") + 1), ); - let params = line + const params = line .substring(splitIdx + 1) .split("/?")[0] .split(":"); @@ -354,7 +354,7 @@ function URI_VMESS(line: string): IProxyVmessConfig { ); const match = /(^[^?]+?)\/?\?(.*)$/.exec(line); if (match) { - let [_, base64Line, qs] = match; + const [_, base64Line, qs] = match; content = decodeBase64OrOriginal(base64Line); for (const addon of qs.split("&")) { @@ -370,7 +370,7 @@ function URI_VMESS(line: string): IProxyVmessConfig { const contentMatch = /(^[^:]+?):([^:]+?)@(.*):(\d+)$/.exec(content); if (contentMatch) { - let [__, cipher, uuid, server, port] = contentMatch; + const [__, cipher, uuid, server, port] = contentMatch; params.scy = cipher; params.id = uuid; @@ -501,7 +501,7 @@ function URI_VLESS(line: string): IProxyVlessConfig { let isShadowrocket; let parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; if (!parsed) { - let [_, base64, other] = /^(.*?)(\?.*?$)/.exec(line)!; + const [_, base64, other] = /^(.*?)(\?.*?$)/.exec(line)!; line = `${atob(base64)}${other}`; parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; isShadowrocket = true; @@ -636,7 +636,7 @@ function URI_VLESS(line: string): IProxyVlessConfig { if (proxy.network === "ws") { proxy.servername = proxy["ws-opts"]?.headers?.Host; } else if (proxy.network === "http") { - let httpHost = proxy["http-opts"]?.headers?.Host; + const httpHost = proxy["http-opts"]?.headers?.Host; proxy.servername = Array.isArray(httpHost) ? httpHost[0] : httpHost; } } @@ -655,7 +655,7 @@ function URI_Trojan(line: string): IProxyTrojanConfig { password = decodeURIComponent(password); - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `Trojan ${server}:${portNum}`; const proxy: IProxyTrojanConfig = { @@ -701,7 +701,7 @@ function URI_Trojan(line: string): IProxyTrojanConfig { proxy["fingerprint"] = value; break; case "encryption": - let encryption = value.split(";"); + const encryption = value.split(";"); if (encryption.length === 3) { proxy["ss-opts"] = { enabled: true, @@ -741,7 +741,7 @@ function URI_Hysteria2(line: string): IProxyHysteria2Config { } password = decodeURIComponent(password); - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `Hysteria2 ${server}:${port}`; @@ -786,7 +786,7 @@ function URI_Hysteria(line: string): IProxyHysteriaConfig { if (isNaN(portNum)) { portNum = 443; } - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `Hysteria ${server}:${port}`; @@ -884,7 +884,7 @@ function URI_TUIC(line: string): IProxyTuicConfig { portNum = 443; } password = decodeURIComponent(password); - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `TUIC ${server}:${port}`; @@ -963,7 +963,7 @@ function URI_Wireguard(line: string): IProxyWireguardConfig { portNum = 443; } privateKey = decodeURIComponent(privateKey); - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `WireGuard ${server}:${port}`; const proxy: IProxyWireguardConfig = { @@ -1047,7 +1047,7 @@ function URI_HTTP(line: string): IProxyHttpConfig { if (auth) { auth = decodeURIComponent(auth); } - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `HTTP ${server}:${portNum}`; const proxy: IProxyHttpConfig = { @@ -1111,7 +1111,7 @@ function URI_SOCKS(line: string): IProxySocks5Config { if (auth) { auth = decodeURIComponent(auth); } - let decodedName = trimStr(decodeURIComponent(name)); + const decodedName = trimStr(decodeURIComponent(name)); name = decodedName ?? `SOCKS5 ${server}:${portNum}`; const proxy: IProxySocks5Config = { type: "socks5",