From 77d9db6043525be54aeaa46d604c5911230201ad Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Mon, 16 May 2022 00:23:20 +0800 Subject: [PATCH] lint: resolve lint issues --- package.json | 8 ++++++- src/components/Clippy.tsx | 6 ++--- src/components/FileExplorer/DiffStatText.tsx | 2 +- src/components/FileExplorer/ListView.tsx | 4 ++-- src/components/FileExplorer/Node.tsx | 3 ++- .../FileExplorer/hooks/useNodeRenderers.tsx | 2 +- .../hooks/useOnVisibleNodesGeneratorReady.tsx | 4 +++- .../FileExplorer/hooks/useSetupTree.tsx | 3 ++- src/components/FileExplorer/index.tsx | 6 ++--- src/components/IIFC.tsx | 8 ------- src/components/SelectInput.tsx | 2 +- src/components/SideBar.tsx | 23 +++++++++--------- src/components/SideBarBodyWrapper.tsx | 24 +++++++++++-------- src/components/SimpleToggleField.tsx | 7 +++++- src/components/SizeObserver.tsx | 18 +++++--------- src/components/ToggleShowButton.tsx | 2 +- src/components/searchModes/fuzzyMode.test.ts | 4 +++- src/components/searchModes/fuzzyMode.tsx | 2 +- .../settings/AccessTokenSettings.tsx | 18 +++++++------- src/components/settings/FileTreeSettings.tsx | 4 +--- src/components/settings/Footer.tsx | 3 ++- src/components/settings/SettingsBar.tsx | 12 ++++++++-- src/components/settings/SidebarSettings.tsx | 8 +++---- src/platforms/Gitee/components.tsx | 12 ++++++++-- 24 files changed, 101 insertions(+), 84 deletions(-) delete mode 100644 src/components/IIFC.tsx diff --git a/package.json b/package.json index 674bcaa..b07075f 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,9 @@ }, "eslintConfig": { "root": true, + "env": { + "browser": true + }, "parser": "@typescript-eslint/parser", "plugins": [ "@typescript-eslint" @@ -105,7 +108,10 @@ "plugin:@typescript-eslint/recommended", "plugin:react/recommended", "plugin:react-hooks/recommended" - ] + ], + "rules": { + "@typescript-eslint/ban-types": "off" + } }, "resolutions": { "@types/react": "^18.0.9", diff --git a/src/components/Clippy.tsx b/src/components/Clippy.tsx index 2508ade..53038fa 100644 --- a/src/components/Clippy.tsx +++ b/src/components/Clippy.tsx @@ -25,13 +25,13 @@ export function Clippy({ codeSnippetElement }: Props) { React.useEffect(() => { const element = elementRef.current if (element) { - function onClippyClick() { + const onClippyClick = () => setState(copyElementContent(codeSnippetElement) ? 'success' : 'fail') - } + element.addEventListener('click', onClippyClick) return () => element.removeEventListener('click', onClippyClick) } - }, []) + }, [codeSnippetElement]) return (
diff --git a/src/components/FileExplorer/DiffStatText.tsx b/src/components/FileExplorer/DiffStatText.tsx index 338535d..bcf5e39 100644 --- a/src/components/FileExplorer/DiffStatText.tsx +++ b/src/components/FileExplorer/DiffStatText.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { Icon } from '../Icon' export function DiffStatText({ - diff: { status, changes, additions, deletions }, + diff: { status, additions, deletions }, }: { diff: Required['diff'] }) { diff --git a/src/components/FileExplorer/ListView.tsx b/src/components/FileExplorer/ListView.tsx index 80aa362..ec55af2 100644 --- a/src/components/FileExplorer/ListView.tsx +++ b/src/components/FileExplorer/ListView.tsx @@ -44,7 +44,7 @@ export function ListView({ const goToCurrentItem = React.useCallback(() => { const targetPath = platform.getCurrentPath(metaData.branchName) if (targetPath) expandTo(targetPath) - }, [metaData.branchName]) + }, [metaData.branchName, expandTo]) useOnLocationChange(goToCurrentItem) useOnPJAXDone(goToCurrentItem) @@ -52,7 +52,7 @@ export function ListView({ const { compactFileTree } = useConfigs().value return ( - ref={listRef} itemKey={(index, { visibleNodes }) => visibleNodes?.nodes[index]?.path} itemData={nodeRendererContext} diff --git a/src/components/FileExplorer/Node.tsx b/src/components/FileExplorer/Node.tsx index e788791..45f5a25 100644 --- a/src/components/FileExplorer/Node.tsx +++ b/src/components/FileExplorer/Node.tsx @@ -47,6 +47,7 @@ export function Node({ style={{ ...style, paddingLeft: `${10 + (compact ? 10 : 20) * depth}px` }} title={node.path} target={node.type === 'commit' ? '_blank' : undefined} + rel="noopener noreferrer" {...platform.delegatePJAXProps?.({ node })} >
@@ -71,7 +72,7 @@ const NodeItemIcon = React.memo(function NodeItemIcon({ const src = React.useMemo( () => (node.type === 'tree' ? getFolderIconURL(node, open) : getFileIconURL(node)), - [open], + [node, open], ) if (icons === 'native') return diff --git a/src/components/FileExplorer/hooks/useNodeRenderers.tsx b/src/components/FileExplorer/hooks/useNodeRenderers.tsx index 7b5c9df..08bf1e9 100644 --- a/src/components/FileExplorer/hooks/useNodeRenderers.tsx +++ b/src/components/FileExplorer/hooks/useNodeRenderers.tsx @@ -14,7 +14,7 @@ export function useNodeRenderers(allRenderers: (NodeRenderer | null | undefined) ? (node: TreeNode) => renderers.map((render, i) => {render(node)}) : undefined - }, allRenderers) + }, allRenderers) // eslint-disable-line react-hooks/exhaustive-deps } export function useRenderFileStatus() { diff --git a/src/components/FileExplorer/hooks/useOnVisibleNodesGeneratorReady.tsx b/src/components/FileExplorer/hooks/useOnVisibleNodesGeneratorReady.tsx index 16cc3e5..81e858c 100644 --- a/src/components/FileExplorer/hooks/useOnVisibleNodesGeneratorReady.tsx +++ b/src/components/FileExplorer/hooks/useOnVisibleNodesGeneratorReady.tsx @@ -15,6 +15,8 @@ export function useVisibleNodesGeneratorMethods( const goTo = useGoTo(visibleNodesGenerator, updateSearchKey, expandTo) const toggleExpansion = useToggleExpansion(visibleNodesGenerator) const focusNode = useFocusNode(visibleNodesGenerator) + + // Only run when visibleNodesGenerator changes useEffect(() => { if (!visibleNodesGenerator) return @@ -26,7 +28,7 @@ export function useVisibleNodesGeneratorMethods( const targetPath = getCurrentPath() if (targetPath) goTo(targetPath) } - }, [visibleNodesGenerator]) + }, [visibleNodesGenerator]) // eslint-disable-line react-hooks/exhaustive-deps return { expandTo, diff --git a/src/components/FileExplorer/hooks/useSetupTree.tsx b/src/components/FileExplorer/hooks/useSetupTree.tsx index f830885..521b429 100644 --- a/src/components/FileExplorer/hooks/useSetupTree.tsx +++ b/src/components/FileExplorer/hooks/useSetupTree.tsx @@ -17,6 +17,7 @@ export function useVisibleNodesGenerator(metaData: MetaData) { const accessToken = config.accessToken const setStateContext = useLoadedContext(SideBarStateContext).onChange + // Only run when metadata or accessToken changes useSequentialEffect( useCallback( checker => { @@ -54,7 +55,7 @@ export function useVisibleNodesGenerator(metaData: MetaData) { setStateContext('tree-rendered') }) }, - [metaData, accessToken], + [metaData, accessToken], // eslint-disable-line react-hooks/exhaustive-deps ), ) diff --git a/src/components/FileExplorer/index.tsx b/src/components/FileExplorer/index.tsx index bc85622..e4fe6d0 100644 --- a/src/components/FileExplorer/index.tsx +++ b/src/components/FileExplorer/index.tsx @@ -116,9 +116,9 @@ export function FileExplorer({ freeze, metaData }: Props) { )} )} - - {({ width = 0, height = 0 }) => ( -
+ > + {({ width = 0, height = 0 }, ref) => ( +
{children()} -} diff --git a/src/components/SelectInput.tsx b/src/components/SelectInput.tsx index 48479a4..ff3a130 100644 --- a/src/components/SelectInput.tsx +++ b/src/components/SelectInput.tsx @@ -16,7 +16,7 @@ export function SelectInput({ onChange={e => { const key = e.target.value const option = options.find(option => option.key === key) - onChange(option!?.value) + if (option) onChange(option.value) }} value={options.find(option => option.value === value)?.key} {...selectProps} diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 185d580..00c193c 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -31,9 +31,8 @@ export function SideBar() { const accessToken = configContext.value.accessToken || '' const [baseSize] = React.useState(() => configContext.value.sideBarWidth) - const $showSettings = useStateIO(false) - const showSettings = $showSettings.value - const toggleShowSettings = React.useCallback(() => $showSettings.onChange(show => !show), []) + const [showSettings, setShowSettings] = React.useState(false) + const toggleShowSettings = React.useCallback(() => setShowSettings(show => !show), []) const $logoContainerElement = useStateIO(null) @@ -41,12 +40,12 @@ export function SideBar() { React.useEffect(() => { if (hasMetaData) { DOMHelper.markGitakoReadyState(true) - $showSettings.onChange(false) + setShowSettings(false) $logoContainerElement.onChange(DOMHelper.insertLogoMountPoint()) } else { DOMHelper.markGitakoReadyState(false) } - }, [hasMetaData]) + }, [hasMetaData]) // eslint-disable-line react-hooks/exhaustive-deps React.useEffect(() => { if (detectBrowser() === 'Safari') DOMHelper.markGitakoSafariFlag() @@ -79,7 +78,7 @@ export function SideBar() { if (intelligentToggle !== null) { configContext.onChange({ intelligentToggle: shouldShow }) } - }, [shouldShow, intelligentToggle]) + }, [shouldShow, intelligentToggle]) // eslint-disable-line react-hooks/exhaustive-deps const error = useLoadedContext(SideBarErrorContext).value // Lock shouldShow on error @@ -87,25 +86,25 @@ export function SideBar() { if (error && shouldShow) { $shouldShow.onChange(false) } - }, [error]) + }, [error]) // eslint-disable-line react-hooks/exhaustive-deps const setShowSideBar = React.useCallback( - (show: typeof $shouldShow.value) => { + (show: boolean) => { if (!error) $shouldShow.onChange(show) }, - [error], + [error], // eslint-disable-line react-hooks/exhaustive-deps ) const toggleShowSideBar = React.useCallback(() => { if (!error) $shouldShow.onChange(show => !show) - }, [error]) + }, [error]) // eslint-disable-line react-hooks/exhaustive-deps useToggleSideBarWithKeyboard(state, configContext, toggleShowSideBar) const updateSideBarVisibility = React.useCallback(() => { if (intelligentToggle === null && sidebarToggleMode === 'persistent') { setShowSideBar(platform.shouldShow()) } - }, [intelligentToggle, sidebarToggleMode]) + }, [intelligentToggle, sidebarToggleMode, setShowSideBar]) useOnPJAXDone(updateSideBarVisibility) @@ -120,7 +119,7 @@ export function SideBar() { if (hideSidebarOnInvalidToken) { setShowSideBar(false) } - }, [hideSidebarOnInvalidToken]) + }, [hideSidebarOnInvalidToken, setShowSideBar]) return ( diff --git a/src/components/SideBarBodyWrapper.tsx b/src/components/SideBarBodyWrapper.tsx index fff4d2a..78e502b 100644 --- a/src/components/SideBarBodyWrapper.tsx +++ b/src/components/SideBarBodyWrapper.tsx @@ -40,7 +40,7 @@ export function SideBarBodyWrapper({ const heightForSafari = useConditionalHook( () => detectBrowser() === 'Safari', - () => useWindowSize().height, + () => useWindowSize().height, // eslint-disable-line react-hooks/rules-of-hooks ) React.useEffect(() => { @@ -55,7 +55,10 @@ export function SideBarBodyWrapper({ const bodyWrapperRef = React.useRef(null) useDebounce(() => configContext.onChange({ sideBarWidth: size }), 100, [size]) - function apply(sizeVariableMountPoint: HTMLElement | undefined, size: number) { + const applySizeToCSSVariables = React.useCallback(function apply( + sizeVariableMountPoint: HTMLElement | undefined, + size: number, + ) { if (sizeVariableMountPoint) setCSSVariable( '--gitako-width', @@ -69,12 +72,13 @@ export function SideBarBodyWrapper({ sizeVariableMountPoint ? undefined : `${size}px`, bodyWrapperRef.current, ) - } + }, + []) // Update size using useEffect would cause delay const onResize = React.useMemo(() => { - let sizeToApply: number, - applied = true + let sizeToApply: number + let applied = true return ([size]: number[]) => { // do NOT merge this with the above similar effect, side bar will jump otherwise sizeToApply = getSafeSize(size, width) @@ -84,15 +88,15 @@ export function SideBarBodyWrapper({ applied = false requestAnimationFrame(() => { applied = true - apply(sizeVariableMountPoint, sizeToApply) + applySizeToCSSVariables(sizeVariableMountPoint, sizeToApply) }) } } - }, [width, sizeVariableMountPoint]) + }, [width, sizeVariableMountPoint, applySizeToCSSVariables]) React.useEffect(() => { - apply(sizeVariableMountPoint, size) - }, [sizeVariableMountPoint]) + applySizeToCSSVariables(sizeVariableMountPoint, size) + }, [sizeVariableMountPoint, size, applySizeToCSSVariables]) const onMouseLeave = React.useCallback( (e: React.MouseEvent) => { @@ -116,7 +120,7 @@ export function SideBarBodyWrapper({ onResize={onResize} onResetSize={() => { setSize(defaultConfigs.sideBarWidth) - apply(sizeVariableMountPoint, defaultConfigs.sideBarWidth) + applySizeToCSSVariables(sizeVariableMountPoint, defaultConfigs.sideBarWidth) }} onResizeStateChange={state => { blockLeaveRef.current = state === 'resizing' diff --git a/src/components/SimpleToggleField.tsx b/src/components/SimpleToggleField.tsx index 7e0ec27..529a584 100644 --- a/src/components/SimpleToggleField.tsx +++ b/src/components/SimpleToggleField.tsx @@ -33,7 +33,12 @@ export function SimpleToggleField({ field, onChange }: <> {field.label}{' '} {field.wikiLink ? ( - + (?) ) : field.description ? ( diff --git a/src/components/SizeObserver.tsx b/src/components/SizeObserver.tsx index 0b24933..26347e6 100644 --- a/src/components/SizeObserver.tsx +++ b/src/components/SizeObserver.tsx @@ -6,16 +6,12 @@ type Size = { height: number } -type Props = Override< - React.HTMLAttributes, - { - type?: string | React.ComponentType - children(size: Partial): React.ReactNode - } -> +type Props = { + children(size: Partial, ref: React.MutableRefObject): React.ReactNode +} -export function SizeObserver({ type = 'div', children, ...rest }: Props) { - const ref = React.useRef() +export function SizeObserver({ children }: Props) { + const ref = React.useRef(null) const [size, setSize] = React.useState>({ width: undefined, @@ -42,7 +38,5 @@ export function SizeObserver({ type = 'div', children, ...rest }: Props) { } }, []) - const props: any = { ...rest, ref } // :) - - return React.createElement(type, props, children(size)) + return <>{children(size, ref)} } diff --git a/src/components/ToggleShowButton.tsx b/src/components/ToggleShowButton.tsx index baf0fe8..5e51750 100644 --- a/src/components/ToggleShowButton.tsx +++ b/src/components/ToggleShowButton.tsx @@ -41,7 +41,7 @@ export function ToggleShowButton({ error, className, onClick, onHover }: Props) if (ref.current) { ref.current.style.top = distance + 'px' } - }, [height]) + }, [height]) // eslint-disable-line react-hooks/exhaustive-deps // And this repositions on drag const { onPointerDown } = useResizeHandler( diff --git a/src/components/searchModes/fuzzyMode.test.ts b/src/components/searchModes/fuzzyMode.test.ts index 5a82b6c..57469af 100644 --- a/src/components/searchModes/fuzzyMode.test.ts +++ b/src/components/searchModes/fuzzyMode.test.ts @@ -1,10 +1,12 @@ +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { fuzzyMode } from './fuzzyMode' type TreeNodeSource = { [key: string]: true | TreeNodeSource } -function createTreeNode(source: TreeNodeSource, name: string = '', paths: string[] = []): TreeNode { +function createTreeNode(source: TreeNodeSource, name = '', paths: string[] = []): TreeNode { const subPaths = paths.concat(name) return { name, diff --git a/src/components/searchModes/fuzzyMode.tsx b/src/components/searchModes/fuzzyMode.tsx index ad71595..291a529 100644 --- a/src/components/searchModes/fuzzyMode.tsx +++ b/src/components/searchModes/fuzzyMode.tsx @@ -57,7 +57,7 @@ function fuzzyMatch(input: string, sample: string) { } } -function fuzzyMatchIndexes(input: string, sample: string, shift: number = 0) { +function fuzzyMatchIndexes(input: string, sample: string, shift = 0) { const indexes: number[] = [] let i = 0, j = 0 diff --git a/src/components/settings/AccessTokenSettings.tsx b/src/components/settings/AccessTokenSettings.tsx index e26980c..b53414a 100644 --- a/src/components/settings/AccessTokenSettings.tsx +++ b/src/components/settings/AccessTokenSettings.tsx @@ -10,31 +10,28 @@ import { SettingsSection } from './SettingsSection' const ACCESS_TOKEN_REGEXP = /^([0-9a-fA-F]+|gh[pousr]_[A-Za-z0-9_]+)$/ -type Props = {} - -export function AccessTokenSettings(props: React.PropsWithChildren) { +export function AccessTokenSettings() { const configContext = useConfigs() const hasAccessToken = Boolean(configContext.value.accessToken) - const $useAccessToken = useStateIO('') + const [accessToken, setAccessToken] = React.useState('') const useAccessTokenHint = useStateIO('') const focusInput = useStateIO(false) const { value: accessTokenHint } = useAccessTokenHint - const { value: accessToken } = $useAccessToken React.useEffect(() => { // clear input when access token updates - $useAccessToken.onChange('') + setAccessToken('') }, [configContext.value.accessToken]) const onInputAccessToken = React.useCallback( ({ currentTarget: { value } }: React.FormEvent) => { - $useAccessToken.onChange(value) + setAccessToken(value) useAccessTokenHint.onChange( ACCESS_TOKEN_REGEXP.test(value) ? '' : 'Gitako does not recognize the token.', ) }, - [], + [], // eslint-disable-line react-hooks/exhaustive-deps ) const saveToken = React.useCallback( @@ -50,11 +47,11 @@ export function AccessTokenSettings(props: React.PropsWithChildren) { ) => { if (accessToken) { configContext.onChange({ accessToken }) - $useAccessToken.onChange('') + setAccessToken('') useAccessTokenHint.onChange(hint) } }, - [accessToken], + [accessToken], // eslint-disable-line react-hooks/exhaustive-deps ) const onPressAccessToken = React.useCallback( @@ -73,6 +70,7 @@ export function AccessTokenSettings(props: React.PropsWithChildren) { href={wikiLinks.createAccessToken} title="A token is required to access private repositories or bypass API rate limits" target="_blank" + rel="noopener noreferrer" > (?) diff --git a/src/components/settings/FileTreeSettings.tsx b/src/components/settings/FileTreeSettings.tsx index 3b79af5..96ab893 100644 --- a/src/components/settings/FileTreeSettings.tsx +++ b/src/components/settings/FileTreeSettings.tsx @@ -38,9 +38,7 @@ const recursiveToggleFolderOptions: Option[] = }, ] -type Props = {} - -export function FileTreeSettings(props: React.PropsWithChildren) { +export function FileTreeSettings() { const configContext = useConfigs() return ( diff --git a/src/components/settings/Footer.tsx b/src/components/settings/Footer.tsx index 23ed12b..7542476 100644 --- a/src/components/settings/Footer.tsx +++ b/src/components/settings/Footer.tsx @@ -15,8 +15,9 @@ export function Footer(props: Props) { {VERSION} diff --git a/src/components/settings/SettingsBar.tsx b/src/components/settings/SettingsBar.tsx index 254215a..669993e 100644 --- a/src/components/settings/SettingsBar.tsx +++ b/src/components/settings/SettingsBar.tsx @@ -72,11 +72,19 @@ export function SettingsBarContent({ toggleShow }: { toggleShow: () => void }) { )} - + Report bug {' / '} - + Discuss feature diff --git a/src/components/settings/SidebarSettings.tsx b/src/components/settings/SidebarSettings.tsx index 8d2f403..20c8335 100644 --- a/src/components/settings/SidebarSettings.tsx +++ b/src/components/settings/SidebarSettings.tsx @@ -8,9 +8,7 @@ import * as keyHelper from 'utils/keyHelper' import { Field } from './Field' import { SettingsSection } from './SettingsSection' -type Props = {} - -export function SidebarSettings(props: React.PropsWithChildren) { +export function SidebarSettings() { const configContext = useConfigs() const useToggleShowSideBarShortcut = useStateIO(configContext.value.shortcut) const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut @@ -18,7 +16,7 @@ export function SidebarSettings(props: React.PropsWithChildren) { React.useEffect(() => { useToggleShowSideBarShortcut.onChange(configContext.value.shortcut) - }, [configContext.value.shortcut]) + }, [configContext.value.shortcut]) // eslint-disable-line react-hooks/exhaustive-deps return ( @@ -38,7 +36,7 @@ export function SidebarSettings(props: React.PropsWithChildren) { // Clear shortcut with backspace const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e) useToggleShowSideBarShortcut.onChange(shortcut) - }, [])} + }, [])} // eslint-disable-line react-hooks/exhaustive-deps readOnly /> {configContext.value.shortcut === toggleShowSideBarShortcut ? ( diff --git a/src/platforms/Gitee/components.tsx b/src/platforms/Gitee/components.tsx index 945f11d..bd4472a 100644 --- a/src/platforms/Gitee/components.tsx +++ b/src/platforms/Gitee/components.tsx @@ -24,11 +24,19 @@ export function GiteeAccessDeniedError({ hasToken }: { hasToken: boolean }) { ) : (

Gitako needs access token to read this project due to{' '} - + GitHub rate limiting {' '} and{' '} - + auth needs . Please setup access token in the settings panel below.