From bef0317577f12a1a62bc6dcf43ca8a1d73f86eb3 Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Sun, 26 Apr 2026 10:18:06 -0400 Subject: [PATCH 1/8] more lint --- shared/eslint.config.mjs | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/shared/eslint.config.mjs b/shared/eslint.config.mjs index 36efc12c25a9..b65b4efe700f 100644 --- a/shared/eslint.config.mjs +++ b/shared/eslint.config.mjs @@ -29,7 +29,16 @@ const ignores = [ const rules = { '@typescript-eslint/await-thenable': 'error', - '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + minimumDescriptionLength: 3, + 'ts-check': false, + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': true, + 'ts-nocheck': true, + }, + ], '@typescript-eslint/class-literal-property-style': 'error', '@typescript-eslint/consistent-type-assertions': 'error', '@typescript-eslint/consistent-type-exports': 'error', @@ -56,7 +65,7 @@ const rules = { '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', '@typescript-eslint/no-redeclare': 'error', - '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'error', '@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/no-restricted-imports': 'error', '@typescript-eslint/no-this-alias': 'error', @@ -72,13 +81,13 @@ const rules = { '@typescript-eslint/no-unsafe-enum-comparison': 'warn', '@typescript-eslint/no-unsafe-member-access': 'warn', '@typescript-eslint/no-unsafe-return': 'warn', - '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'error', '@typescript-eslint/no-unused-vars': [ 'error', {argsIgnorePattern: '^_', varsIgnorePattern: '^_', ignoreRestSiblings: true}, ], '@typescript-eslint/no-useless-constructor': 'error', - '@typescript-eslint/only-throw-error': 'off', + '@typescript-eslint/only-throw-error': 'error', '@typescript-eslint/prefer-as-const': 'error', '@typescript-eslint/prefer-for-of': 'error', '@typescript-eslint/prefer-function-type': 'error', @@ -86,13 +95,22 @@ const rules = { '@typescript-eslint/prefer-literal-enum-member': 'error', '@typescript-eslint/prefer-namespace-keyword': 'error', '@typescript-eslint/prefer-optional-chain': 'error', - '@typescript-eslint/prefer-promise-reject-errors': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'error', '@typescript-eslint/prefer-reduce-type-parameter': 'warn', '@typescript-eslint/prefer-return-this-type': 'error', '@typescript-eslint/prefer-string-starts-ends-with': 'error', '@typescript-eslint/promise-function-async': 'error', '@typescript-eslint/require-await': 'error', - '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/restrict-plus-operands': [ + 'error', + { + allowAny: false, + allowBoolean: false, + allowNullish: false, + allowNumberAndString: false, + allowRegExp: false, + }, + ], '@typescript-eslint/restrict-template-expressions': 'error', '@typescript-eslint/switch-exhaustiveness-check': ['error', {considerDefaultExhaustiveForUnions: true}], '@typescript-eslint/triple-slash-reference': 'error', @@ -100,7 +118,7 @@ const rules = { '@typescript-eslint/unified-signatures': 'error', 'array-callback-return': 'error', 'no-constant-condition': ['warn', {checkLoops: false}], - 'no-empty': 'off', + 'no-empty': ['error', {allowEmptyCatch: true}], 'no-implied-eval': 'error', 'no-script-url': 'error', 'no-self-compare': 'error', @@ -109,7 +127,7 @@ const rules = { 'promise/catch-or-return': 'error', 'promise/no-new-statics': 'error', 'promise/no-return-in-finally': 'error', - 'promise/always-return': 'off', + 'promise/always-return': ['error', {ignoreLastCallback: true}], 'promise/no-return-wrap': 'error', 'promise/param-names': 'error', 'promise/valid-params': 'error', @@ -223,11 +241,13 @@ export default [ rules: { 'array-callback-return': 'error', 'no-constant-condition': ['warn', {checkLoops: false}], + 'no-empty': ['error', {allowEmptyCatch: true}], 'no-implied-eval': 'error', 'no-script-url': 'error', - 'no-undef': 'off', 'no-self-compare': 'error', 'no-sequences': 'error', + 'no-undef': 'error', + 'no-unused-expressions': 'error', 'prefer-const': 'error', 'sort-keys': ['error', 'asc', {caseSensitive: true, natural: false}], strict: ['error', 'global'], From 7a44bdd868080f3a2fec1d089ced9b5d3438a8cb Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Sun, 26 Apr 2026 10:50:21 -0400 Subject: [PATCH 2/8] lint fixes --- shared/app/global-errors.tsx | 4 ++- shared/app/index.native.tsx | 4 ++- shared/app/out-of-date.tsx | 2 ++ .../attachment-fullscreen/index.desktop.tsx | 8 +++-- .../attachment-fullscreen/index.native.tsx | 3 +- .../conversation/attachment-get-titles.tsx | 9 +++--- shared/chat/conversation/bot/install.tsx | 6 +++- shared/chat/conversation/command-status.tsx | 2 +- .../conversation/info-panel/add-people.tsx | 6 ++-- shared/chat/conversation/info-panel/menu.tsx | 6 ++-- .../input-area/location-popup.native.tsx | 5 +-- .../input-area/normal/input.desktop.tsx | 8 +++-- .../input-area/suggestors/channels.tsx | 8 ++--- .../input-area/suggestors/commands.tsx | 6 ++-- .../input-area/suggestors/common.tsx | 4 ++- .../input-area/suggestors/users.tsx | 8 +++-- .../conversation/list-area/index.desktop.tsx | 10 ++++-- .../conversation/list-area/index.native.tsx | 2 +- .../messages/attachment/audio.tsx | 4 ++- .../conversation/messages/attachment/file.tsx | 4 ++- .../messages/attachment/shared.tsx | 4 ++- .../messages/message-popup/attachment.tsx | 4 ++- .../messages/message-popup/text.tsx | 4 ++- .../conversation/messages/reactions-rows.tsx | 4 ++- .../messages/special-top-message.tsx | 4 ++- .../messages/system-create-team/container.tsx | 3 +- .../messages/system-profile-reset-notice.tsx | 4 ++- .../messages/text/coinflip/index.tsx | 4 ++- .../text/unfurl/unfurl-list/image/index.tsx | 4 ++- .../conversation/messages/text/wrapper.tsx | 4 ++- .../messages/wrapper/exploding-meta.tsx | 7 ++-- .../conversation/messages/wrapper/wrapper.tsx | 4 ++- shared/chat/conversation/pinned-message.tsx | 4 ++- shared/chat/emoji-picker/container.tsx | 3 +- shared/chat/emoji-picker/index.tsx | 3 +- shared/chat/inbox/index.desktop.tsx | 5 ++- shared/chat/location-map.desktop.tsx | 4 ++- shared/chat/location-map.native.tsx | 4 ++- shared/chat/pdf/index.desktop.tsx | 4 ++- shared/chat/send-to-chat/index.tsx | 4 ++- .../avatar/icon-to-img-set.tsx | 2 +- shared/common-adapters/banner.tsx | 4 ++- shared/common-adapters/check-circle.tsx | 4 ++- .../menu-layout/index.desktop.tsx | 4 ++- .../menu-layout/index.native.tsx | 6 ++-- shared/common-adapters/index-impl.js | 6 ++-- shared/common-adapters/markdown/react.tsx | 2 +- shared/common-adapters/name-with-icon.tsx | 4 ++- shared/common-adapters/phone-input.tsx | 4 +-- .../relative-floating-box.desktop.tsx | 4 ++- shared/common-adapters/search-filter.tsx | 10 ++++-- shared/common-adapters/section-list.tsx | 4 ++- shared/common-adapters/skip-animations.js | 2 ++ shared/common-adapters/video.desktop.tsx | 6 +++- shared/common-adapters/web-view.desktop.tsx | 16 ++++------ shared/common-adapters/web-view.native.tsx | 4 ++- .../zoomable-image.desktop.tsx | 4 ++- shared/constants/chat/message.tsx | 4 ++- shared/constants/deeplinks.tsx | 4 ++- shared/constants/init/index.native.tsx | 6 ++-- shared/constants/router.tsx | 32 ++++++++++++++----- shared/constants/teams.tsx | 2 +- shared/desktop/app/ipc-handlers.desktop.tsx | 15 ++++++--- shared/desktop/app/menu-bar.desktop.tsx | 6 ++-- shared/desktop/app/node.desktop.tsx | 4 ++- shared/desktop/package.desktop.mts | 6 ++-- .../remote/use-serialize-props.desktop.tsx | 4 ++- shared/desktop/yarn-helper/font.mts | 10 ++++-- shared/engine/listener.tsx | 4 +-- shared/fs/banner/conflict-banner.tsx | 2 +- shared/fs/browser/rows/sort.tsx | 2 +- shared/fs/common/hooks.tsx | 16 +++++++--- .../path-item-action/menu-container.tsx | 16 +++++++--- shared/fs/common/path-status-icon.tsx | 2 +- shared/fs/common/rpc-state.tsx | 4 ++- shared/fs/footer/download-wrapper.native.tsx | 6 +++- shared/fs/index.tsx | 4 ++- shared/fs/nav-header/actions.tsx | 4 ++- shared/fs/nav-header/title.tsx | 9 ++++-- shared/git/index.tsx | 6 +++- shared/git/row.tsx | 10 ++++-- shared/ignored-modules.js | 2 ++ shared/incoming-share/index.tsx | 15 ++++++--- shared/index.android.js | 2 ++ shared/index.ios.js | 2 ++ shared/jest.config.js | 2 ++ shared/jest.setup.js | 2 ++ shared/logger/index.tsx | 4 ++- shared/login/recover-password/error-modal.tsx | 6 +++- shared/login/recover-password/error.tsx | 6 +++- shared/menubar/index.desktop.tsx | 6 ++-- shared/null-module.js | 2 ++ shared/people/container.tsx | 4 ++- shared/people/index.shared.tsx | 4 ++- shared/people/todo.tsx | 16 +++++++--- shared/perf/compare-perf.js | 1 + shared/perf/desktop-perf-inject.js | 2 ++ shared/perf/run-desktop-cdp-profile.js | 3 +- shared/perf/run-desktop-perf.js | 1 + shared/perf/visual-diff-take.js | 1 + shared/profile/generic/proofs-list.tsx | 12 +++++-- shared/profile/showcase-team-offer.tsx | 2 +- shared/profile/user/actions/index.tsx | 4 ++- shared/profile/user/index.tsx | 2 +- shared/provision/code-page/container.tsx | 8 +++-- shared/provision/set-public-name.tsx | 4 ++- shared/provision/username-or-email.tsx | 4 ++- shared/router-v2/common.desktop.tsx | 2 +- shared/router-v2/common.native.tsx | 2 +- shared/router-v2/header/index.desktop.tsx | 4 ++- shared/settings/archive/index.tsx | 2 +- shared/settings/logout.tsx | 6 +++- shared/settings/root-phone.tsx | 2 +- .../settings/screenprotector/index.native.tsx | 2 +- shared/signup/email.tsx | 12 +++++-- shared/signup/routes.tsx | 6 +++- shared/stores/chat.tsx | 2 +- shared/stores/config.tsx | 4 ++- shared/stores/convostate.tsx | 7 ++-- shared/stores/fs.tsx | 7 ++-- shared/stores/router.tsx | 4 ++- shared/stores/team-building.tsx | 4 ++- shared/styles/index.native.tsx | 2 +- shared/team-building/recs-and-recos.tsx | 3 +- .../search-result/people-result.tsx | 8 +++-- .../add-contacts.native.tsx | 12 +++++-- shared/teams/channel/rows.tsx | 11 ++++--- shared/teams/common/channel-hooks.tsx | 3 +- shared/teams/common/use-autocompleter.tsx | 4 ++- shared/teams/emojis/add-alias.tsx | 3 +- shared/teams/emojis/add-emoji.tsx | 11 +++++-- .../new-team/wizard/add-subteam-members.tsx | 6 +++- shared/teams/team/member/index.new.tsx | 5 +-- shared/teams/team/rows/emoji-row/item.tsx | 3 +- shared/teams/team/rows/invite-row/request.tsx | 4 ++- shared/teams/team/rows/member-row.tsx | 11 +++++-- .../team/settings-tab/retention/index.tsx | 3 +- shared/teams/team/team-info.tsx | 2 +- shared/teams/use-teams-list.tsx | 6 ++-- shared/test/mocks/file.js | 1 + shared/test/mocks/logger.js | 1 + shared/test/mocks/react-native.js | 1 + shared/test/mocks/react-navigation-core.js | 1 + shared/test/mocks/style.js | 1 + shared/tracker/remote-proxy.desktop.tsx | 4 ++- shared/tracker/use-profile.tsx | 4 ++- shared/util/errors.tsx | 25 +++++++++++++++ .../util/platform-specific/index.native.tsx | 2 +- .../input-monitor.desktop.tsx | 32 ++++++++++++++----- shared/util/safe-submit.tsx | 1 - shared/util/uint8array.tsx | 2 +- .../use-intersection-observer.desktop.tsx | 12 ++++--- shared/util/use-resize-observer.desktop.tsx | 15 +++++---- shared/util/why-did-you-render-enabled.js | 1 + 154 files changed, 597 insertions(+), 240 deletions(-) diff --git a/shared/app/global-errors.tsx b/shared/app/global-errors.tsx index 7c18969de0d1..b768ef909740 100644 --- a/shared/app/global-errors.tsx +++ b/shared/app/global-errors.tsx @@ -51,7 +51,9 @@ const useData = () => { const size: Size = error ? (expandedError === error ? 'Big' : 'Small') : 'Closed' const clearCountdown = () => { - countdownTimerRef.current && clearTimeout(countdownTimerRef.current) + if (countdownTimerRef.current) { + clearTimeout(countdownTimerRef.current) + } countdownTimerRef.current = undefined } diff --git a/shared/app/index.native.tsx b/shared/app/index.native.tsx index 783d0376645e..70c9ae276980 100644 --- a/shared/app/index.native.tsx +++ b/shared/app/index.native.tsx @@ -59,7 +59,9 @@ const useDarkHookup = () => { React.useEffect(() => { const appStateChangeSub = AppState.addEventListener('change', nextAppState => { appStateRef.current = nextAppState - nextAppState !== 'unknown' && nextAppState !== 'extension' && setMobileAppState(nextAppState) + if (nextAppState !== 'unknown' && nextAppState !== 'extension') { + setMobileAppState(nextAppState) + } if (nextAppState === 'active') { setSystemDarkMode(Appearance.getColorScheme() === 'dark') diff --git a/shared/app/out-of-date.tsx b/shared/app/out-of-date.tsx index ded171bafb8b..4f1fa0ec0e42 100644 --- a/shared/app/out-of-date.tsx +++ b/shared/app/out-of-date.tsx @@ -44,9 +44,11 @@ const OutOfDate = () => { setMobileCritical(false) setMobileMessage('') } + return undefined }) .catch(e => { logger.warn("Can't call critical check", e) + return undefined }) ) }, 60_000) // don't bother checking during startup diff --git a/shared/chat/conversation/attachment-fullscreen/index.desktop.tsx b/shared/chat/conversation/attachment-fullscreen/index.desktop.tsx index 1c5f3a97a9d9..5da826fd8f36 100644 --- a/shared/chat/conversation/attachment-fullscreen/index.desktop.tsx +++ b/shared/chat/conversation/attachment-fullscreen/index.desktop.tsx @@ -55,8 +55,12 @@ const Fullscreen = function Fullscreen(p: Props) { const vidRef = React.useRef(null) const onHotKey = (cmd: string) => { - cmd === 'left' && onPreviousAttachment() - cmd === 'right' && onNextAttachment() + if (cmd === 'left') { + onPreviousAttachment() + } + if (cmd === 'right') { + onNextAttachment() + } } Kb.useHotKey(['left', 'right'], onHotKey) const isDownloadError = !!message.transferErrMsg diff --git a/shared/chat/conversation/attachment-fullscreen/index.native.tsx b/shared/chat/conversation/attachment-fullscreen/index.native.tsx index 3b78e5caa338..6ba9ac29f712 100644 --- a/shared/chat/conversation/attachment-fullscreen/index.native.tsx +++ b/shared/chat/conversation/attachment-fullscreen/index.native.tsx @@ -169,12 +169,13 @@ const Fullscreen = function Fullscreen(p: Props) { }, []) React.useEffect(() => { - fadeAnim && + if (fadeAnim) { Animated.timing(fadeAnim, { duration: 240, toValue: showHeader ? 1 : 0, useNativeDriver: true, }).start() + } }, [showHeader, fadeAnim]) return ( diff --git a/shared/chat/conversation/attachment-get-titles.tsx b/shared/chat/conversation/attachment-get-titles.tsx index 36cdf0e0266f..66cdee73ede1 100644 --- a/shared/chat/conversation/attachment-get-titles.tsx +++ b/shared/chat/conversation/attachment-get-titles.tsx @@ -62,9 +62,11 @@ const Container = (ownProps: OwnProps) => { const attachFromDragAndDrop = ConvoState.useChatContext(s => s.dispatch.attachFromDragAndDrop) const _onSubmit = (titles: Array, spoiler: boolean) => { - tlfName || noDragDrop - ? attachmentsUpload(pathAndOutboxIDs, titles, tlfName, spoiler) - : attachFromDragAndDrop(pathAndOutboxIDs, titles) + if (tlfName || noDragDrop) { + attachmentsUpload(pathAndOutboxIDs, titles, tlfName, spoiler) + } else { + attachFromDragAndDrop(pathAndOutboxIDs, titles) + } clearModals() if (selectConversationWithReason) { @@ -86,7 +88,6 @@ const Container = (ownProps: OwnProps) => { const [index, setIndex] = React.useState(0) const [titles, setTitles] = React.useState(pathAndInfos.map((_, idx) => _titles?.[idx] ?? '')) const [spoiler, setSpoiler] = React.useState(false) - setSpoiler // TODO commented out const onNext = (e?: React.BaseSyntheticEvent) => { e?.preventDefault() diff --git a/shared/chat/conversation/bot/install.tsx b/shared/chat/conversation/bot/install.tsx index 84f6d2e0909b..3d172b359215 100644 --- a/shared/chat/conversation/bot/install.tsx +++ b/shared/chat/conversation/bot/install.tsx @@ -543,7 +543,11 @@ const InstallBotPopup = (props: Props) => { } else if (installScreen) { setInstallScreen(false) } else { - Kb.Styles.isMobile ? navigateUp() : clearModals() + if (Kb.Styles.isMobile) { + navigateUp() + } else { + clearModals() + } } } useModalHeaderState.setState({ diff --git a/shared/chat/conversation/command-status.tsx b/shared/chat/conversation/command-status.tsx index e19041010399..bc0b92e2a863 100644 --- a/shared/chat/conversation/command-status.tsx +++ b/shared/chat/conversation/command-status.tsx @@ -18,7 +18,7 @@ const Container = () => { setCommandStatusInfo() } const props = { - actions: _info.actions.map((a: T.RPCChat.UICommandStatusActionTyp | unknown) => { + actions: _info.actions.map(a => { switch (a) { case T.RPCChat.UICommandStatusActionTyp.appsettings: return { diff --git a/shared/chat/conversation/info-panel/add-people.tsx b/shared/chat/conversation/info-panel/add-people.tsx index 6c8f953c217c..23c40b357164 100644 --- a/shared/chat/conversation/info-panel/add-people.tsx +++ b/shared/chat/conversation/info-panel/add-people.tsx @@ -13,8 +13,9 @@ const AddPeople = (p: Props) => { const teamID = ConvoState.useChatContext(s => s.meta.teamID) const navigateAppend = ConvoState.useChatNavigateAppend() const onAddPeople = () => { - teamID && + if (teamID) { C.Router2.navigateAppend({name: 'teamAddToTeamFromWhere', params: {wizard: makeAddMembersWizard(teamID)}}) + } } const onAddToChannel = () => { navigateAppend(conversationIDKey => ({name: 'chatAddToChannel', params: {conversationIDKey, teamID}})) @@ -22,8 +23,7 @@ const AddPeople = (p: Props) => { let directAction: undefined | (() => void) let directLabel: string | undefined - if (!isGeneralChannel) { - } else { + if (isGeneralChannel) { directAction = onAddPeople directLabel = 'Add people to team' } diff --git a/shared/chat/conversation/info-panel/menu.tsx b/shared/chat/conversation/info-panel/menu.tsx index e7cf743114fe..21f2f92e1d65 100644 --- a/shared/chat/conversation/info-panel/menu.tsx +++ b/shared/chat/conversation/info-panel/menu.tsx @@ -97,11 +97,12 @@ const InfoPanelMenuConnector = function InfoPanelMenuConnector(p: OwnProps) { const routerNavigateAppend = C.Router2.navigateAppend const canAddPeople = yourOperations.manageMembers const onAddPeople = () => { - teamID && + if (teamID) { routerNavigateAppend({ name: 'teamAddToTeamFromWhere', params: {wizard: makeAddMembersWizard(teamID)}, }) + } } const chatNavigateAppend = ConvoState.useChatNavigateAppend() const onBlockConv = () => { @@ -294,13 +295,14 @@ const InfoPanelMenuConnector = function InfoPanelMenuConnector(p: OwnProps) { onClick: onBlockConv, title: 'Block', } as const) - conversationIDKey && + if (conversationIDKey) { items.push({ icon: 'iconfont-folder-downloads', iconIsVisible: false, onClick: onArchive, title: 'Backup conversation', } as const) + } } else { if (hasChannelSection) { items.push(channelHeader) diff --git a/shared/chat/conversation/input-area/location-popup.native.tsx b/shared/chat/conversation/input-area/location-popup.native.tsx index 3f12f5d0fcc8..ceeb93d0d7c2 100644 --- a/shared/chat/conversation/input-area/location-popup.native.tsx +++ b/shared/chat/conversation/input-area/location-popup.native.tsx @@ -77,10 +77,11 @@ const useWatchPosition = ( unsub = () => sub.remove() } catch (_error) { const error = _error as {message?: string} - logger.info('failed to get location: ' + error.message) + const errorMessage = String(error.message) + logger.info('failed to get location: ' + errorMessage) setCommandStatusInfo({ actions: [T.RPCChat.UICommandStatusActionTyp.appsettings], - displayText: `Failed to access location. ${error.message}`, + displayText: `Failed to access location. ${errorMessage}`, displayType: T.RPCChat.UICommandStatusDisplayTyp.error, }) } diff --git a/shared/chat/conversation/input-area/normal/input.desktop.tsx b/shared/chat/conversation/input-area/normal/input.desktop.tsx index f8ac1c093399..c13a571738ba 100644 --- a/shared/chat/conversation/input-area/normal/input.desktop.tsx +++ b/shared/chat/conversation/input-area/normal/input.desktop.tsx @@ -332,7 +332,9 @@ const FileButton = function FileButton(p: {setHtmlInputRef: (i: HTMLInputElement const pickFile = () => { const paths = htmlInputRef.current?.files ? fileListToPaths(htmlInputRef.current.files) : undefined const pathAndOutboxIDs = paths?.reduce>((arr, path: string) => { - path && arr.push({path}) + if (path) { + arr.push({path}) + } return arr }, []) if (pathAndOutboxIDs?.length) { @@ -493,7 +495,9 @@ const PlatformInput = function PlatformInput(p: Props) { const checkEnterOnKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !(e.altKey || e.shiftKey || e.metaKey)) { e.preventDefault() - inputRef.current && onSubmit(inputRef.current.value) + if (inputRef.current) { + onSubmit(inputRef.current.value) + } } } diff --git a/shared/chat/conversation/input-area/suggestors/channels.tsx b/shared/chat/conversation/input-area/suggestors/channels.tsx index 349b4a639971..a5bce24e4e98 100644 --- a/shared/chat/conversation/input-area/suggestors/channels.tsx +++ b/shared/chat/conversation/input-area/suggestors/channels.tsx @@ -62,9 +62,9 @@ const getChannelSuggestions = ( const suggestions = (Chat.useChatState.getState().inboxLayout?.bigTeams ?? []).reduce< Array<{channelname: string; teamname: string}> >((arr, t) => { - t.state === T.RPCChat.UIInboxBigTeamRowTyp.channel && - mutualTeams.has(t.channel.teamname) && + if (t.state === T.RPCChat.UIInboxBigTeamRowTyp.channel && mutualTeams.has(t.channel.teamname)) { arr.push({channelname: t.channel.channelname, teamname: t.channel.teamname}) + } return arr }, []) @@ -75,9 +75,9 @@ const getChannelSuggestions = ( const suggestions = (Chat.useChatState.getState().inboxLayout?.bigTeams ?? []).reduce< Array<{channelname: string}> >((arr, t) => { - t.state === T.RPCChat.UIInboxBigTeamRowTyp.channel && - t.channel.teamname === teamname && + if (t.state === T.RPCChat.UIInboxBigTeamRowTyp.channel && t.channel.teamname === teamname) { arr.push({channelname: t.channel.channelname}) + } return arr }, []) diff --git a/shared/chat/conversation/input-area/suggestors/commands.tsx b/shared/chat/conversation/input-area/suggestors/commands.tsx index 4c07743aeee3..b8a94aefa1f1 100644 --- a/shared/chat/conversation/input-area/suggestors/commands.tsx +++ b/shared/chat/conversation/input-area/suggestors/commands.tsx @@ -20,7 +20,7 @@ export const transformer = ( return Common.standardTransformer(`${prefix}${command.name}`, tData, preview) } -const keyExtractor = (c: T.RPCChat.ConversationCommand) => c.name + c.username +const keyExtractor = (c: T.RPCChat.ConversationCommand) => c.name + String(c.username) const getBotRestrictBlockMap = ( settings: ReadonlyMap, @@ -55,7 +55,9 @@ const ItemRenderer = (p: Common.ItemRendererProps) => { const botRestrictMap = getBotRestrictBlockMap(botSettings, s.id, [ ...suggestBotCommands .reduce((s, c) => { - c.username && s.add(c.username) + if (c.username) { + s.add(c.username) + } return s }, new Set()) .values(), diff --git a/shared/chat/conversation/input-area/suggestors/common.tsx b/shared/chat/conversation/input-area/suggestors/common.tsx index 01f10b296b4a..e091debad17c 100644 --- a/shared/chat/conversation/input-area/suggestors/common.tsx +++ b/shared/chat/conversation/input-area/suggestors/common.tsx @@ -89,7 +89,9 @@ export function List(p: ListProps) { const onSubmit = () => { const sel = items[selectedIndex] - sel && onSelected(sel, true) + if (sel) { + onSelected(sel, true) + } return !!sel } diff --git a/shared/chat/conversation/input-area/suggestors/users.tsx b/shared/chat/conversation/input-area/suggestors/users.tsx index 268346325939..711024750596 100644 --- a/shared/chat/conversation/input-area/suggestors/users.tsx +++ b/shared/chat/conversation/input-area/suggestors/users.tsx @@ -127,12 +127,16 @@ const filterAndJoin = ( const getTeams = (layout?: T.RPCChat.UIInboxLayout) => { const bigTeams = layout?.bigTeams?.reduce>((arr, l) => { - l.state === T.RPCChat.UIInboxBigTeamRowTyp.label && arr.push(l.label.name) + if (l.state === T.RPCChat.UIInboxBigTeamRowTyp.label) { + arr.push(l.label.name) + } return arr }, []) ?? [] const smallTeams = layout?.smallTeams?.reduce>((arr, l) => { - l.isTeam && arr.push(l.name) + if (l.isTeam) { + arr.push(l.name) + } return arr }, []) ?? [] return bigTeams.concat(smallTeams).map(teamname => ({channelname: '', teamname})) diff --git a/shared/chat/conversation/list-area/index.desktop.tsx b/shared/chat/conversation/list-area/index.desktop.tsx index 237c8945d496..27b74d304d2c 100644 --- a/shared/chat/conversation/list-area/index.desktop.tsx +++ b/shared/chat/conversation/list-area/index.desktop.tsx @@ -133,20 +133,22 @@ const useScrolling = (p: { const [scrollDown] = React.useState(() => () => { const list = listRef.current - list && + if (list) { adjustScrollAndIgnoreOnScroll(() => { list.scrollTop += list.clientHeight }) + } }) const [scrollUp] = React.useState(() => () => { lockedToBottomRef.current = false const list = listRef.current - list && + if (list) { adjustScrollAndIgnoreOnScroll(() => { list.scrollTop -= list.clientHeight checkForLoadMoreThrottled() }) + } }) const scrollCheckRef = React.useRef>(undefined) @@ -505,7 +507,9 @@ const ThreadWrapper = function ThreadWrapper() { }) const tc = tempDiv.textContent - tc && copyToClipboard(tc) + if (tc) { + copyToClipboard(tc) + } tempDiv.remove() } const {focusInput} = React.useContext(FocusContext) diff --git a/shared/chat/conversation/list-area/index.native.tsx b/shared/chat/conversation/list-area/index.native.tsx index 62b4c6706133..6b3755a98da0 100644 --- a/shared/chat/conversation/list-area/index.native.tsx +++ b/shared/chat/conversation/list-area/index.native.tsx @@ -260,7 +260,7 @@ const ConversationList = function ConversationList() { key={conversationIDKey} testID="messageList" onScrollToIndexFailed={noop} - // @ts-ignore LegendList/FlashList prop; ignored by FlatList + // @ts-expect-error LegendList/FlashList prop; ignored by FlatList estimatedItemSize={72} ListHeaderComponent={SpecialBottomMessage} ListFooterComponent={SpecialTopMessage} diff --git a/shared/chat/conversation/messages/attachment/audio.tsx b/shared/chat/conversation/messages/attachment/audio.tsx index fab51fd665f1..138f11a3ad5b 100644 --- a/shared/chat/conversation/messages/attachment/audio.tsx +++ b/shared/chat/conversation/messages/attachment/audio.tsx @@ -15,7 +15,9 @@ const AudioAttachment = ({message}: {message: T.Chat.MessageAttachment}) => { const progressLabel = Chat.messageAttachmentTransferStateToProgressLabel(message.transferState) const hasProgress = messageAttachmentHasProgress(message) const onShowInFinder = () => { - message.downloadPath && openLocalPathInSystemFileManagerDesktop(message.downloadPath) + if (message.downloadPath) { + openLocalPathInSystemFileManagerDesktop(message.downloadPath) + } } const url = !message.submitState && message.fileURL.length > 0 ? `${message.fileURL}&contentforce=true` : '' const showInFinder = !!message.downloadPath && !Kb.Styles.isMobile diff --git a/shared/chat/conversation/messages/attachment/file.tsx b/shared/chat/conversation/messages/attachment/file.tsx index b02d63e82009..681bf711892b 100644 --- a/shared/chat/conversation/messages/attachment/file.tsx +++ b/shared/chat/conversation/messages/attachment/file.tsx @@ -57,7 +57,9 @@ function FileContainer(p: OwnProps) { ) } const _onShowInFinder = () => { - downloadPath && openLocalPathInSystemFileManagerDesktop(downloadPath) + if (downloadPath) { + openLocalPathInSystemFileManagerDesktop(downloadPath) + } } const onDownload = () => { diff --git a/shared/chat/conversation/messages/attachment/shared.tsx b/shared/chat/conversation/messages/attachment/shared.tsx index 31a8b75070a4..55efba05955a 100644 --- a/shared/chat/conversation/messages/attachment/shared.tsx +++ b/shared/chat/conversation/messages/attachment/shared.tsx @@ -88,7 +88,9 @@ export const TransferIcon = (p: { } const onFinder = () => { - downloadPath && openLocalPathInSystemFileManagerDesktop(downloadPath) + if (downloadPath) { + openLocalPathInSystemFileManagerDesktop(downloadPath) + } } switch (state) { diff --git a/shared/chat/conversation/messages/message-popup/attachment.tsx b/shared/chat/conversation/messages/message-popup/attachment.tsx index 901d6d8331c1..f7771fa1d46f 100644 --- a/shared/chat/conversation/messages/message-popup/attachment.tsx +++ b/shared/chat/conversation/messages/message-popup/attachment.tsx @@ -86,7 +86,9 @@ const PopAttach = (ownProps: OwnProps) => { const onShareAttachment = C.isMobile ? _onShareAttachment : undefined const _onShowInFinder = () => { - downloadPath && openLocalPathInSystemFileManagerDesktop(downloadPath) + if (downloadPath) { + openLocalPathInSystemFileManagerDesktop(downloadPath) + } } const onShowInFinder = !C.isMobile && message.downloadPath ? _onShowInFinder : undefined diff --git a/shared/chat/conversation/messages/message-popup/text.tsx b/shared/chat/conversation/messages/message-popup/text.tsx index 315365a75b30..02e0dc27d719 100644 --- a/shared/chat/conversation/messages/message-popup/text.tsx +++ b/shared/chat/conversation/messages/message-popup/text.tsx @@ -78,7 +78,9 @@ const PopText = (ownProps: OwnProps) => { const canReplyPrivately = ['small', 'big'].includes(teamType) || numPart > 2 const navigateAppend = C.Router2.navigateAppend const onCopy = () => { - text && copyToClipboard(text) + if (text) { + copyToClipboard(text) + } } const _onReplyPrivately = () => { diff --git a/shared/chat/conversation/messages/reactions-rows.tsx b/shared/chat/conversation/messages/reactions-rows.tsx index 96cc532c7cd6..d4f64c3014bf 100644 --- a/shared/chat/conversation/messages/reactions-rows.tsx +++ b/shared/chat/conversation/messages/reactions-rows.tsx @@ -65,7 +65,9 @@ function RowItem(p: IProps) { const [showingPopup, setShowingPopup] = React.useState(false) const showPopup = () => { - Kb.Styles.isMobile && Keyboard.dismiss() + if (Kb.Styles.isMobile) { + Keyboard.dismiss() + } setShowingPopup(true) } const hidePopup = () => { diff --git a/shared/chat/conversation/messages/special-top-message.tsx b/shared/chat/conversation/messages/special-top-message.tsx index feb4143413de..015ecbdee329 100644 --- a/shared/chat/conversation/messages/special-top-message.tsx +++ b/shared/chat/conversation/messages/special-top-message.tsx @@ -158,7 +158,9 @@ function SpecialTopMessage() { if (ordinal !== lastOrdinalRef.current) { setAllowDigging(false) lastOrdinalRef.current = ordinal - digTimerRef.current && clearTimeout(digTimerRef.current) + if (digTimerRef.current) { + clearTimeout(digTimerRef.current) + } digTimerRef.current = setTimeout(() => { setAllowDigging(true) }, 3000) diff --git a/shared/chat/conversation/messages/system-create-team/container.tsx b/shared/chat/conversation/messages/system-create-team/container.tsx index 476e348b2569..07085f083587 100644 --- a/shared/chat/conversation/messages/system-create-team/container.tsx +++ b/shared/chat/conversation/messages/system-create-team/container.tsx @@ -60,8 +60,9 @@ const AddInvite = (props: {teamID: T.Teams.TeamID; isAdmin: boolean}) => { const {teamID, isAdmin} = props const navigateAppend = C.Router2.navigateAppend const onAddInvite = () => { - teamID && + if (teamID) { navigateAppend({name: 'teamAddToTeamFromWhere', params: {wizard: makeAddMembersWizard(teamID)}}) + } } const textType = 'BodySmallSemiboldPrimaryLink' if (isAdmin) { diff --git a/shared/chat/conversation/messages/system-profile-reset-notice.tsx b/shared/chat/conversation/messages/system-profile-reset-notice.tsx index 1a8260b181f5..420c11c05106 100644 --- a/shared/chat/conversation/messages/system-profile-reset-notice.tsx +++ b/shared/chat/conversation/messages/system-profile-reset-notice.tsx @@ -12,7 +12,9 @@ const SystemProfileResetNotice = () => { C.Router2.navigateToThread(conversationIDKey, 'jumpToReset') } const onOpenOlderConversation = () => { - prevConversationIDKey && _onOpenOlderConversation(prevConversationIDKey) + if (prevConversationIDKey) { + _onOpenOlderConversation(prevConversationIDKey) + } } return ( diff --git a/shared/chat/conversation/messages/text/coinflip/index.tsx b/shared/chat/conversation/messages/text/coinflip/index.tsx index 7d4b27abef8a..7bcfda2f62d3 100644 --- a/shared/chat/conversation/messages/text/coinflip/index.tsx +++ b/shared/chat/conversation/messages/text/coinflip/index.tsx @@ -22,7 +22,9 @@ function CoinFlipContainer() { ) const status = ConvoState.useChatContext(s => s.flipStatusMap.get(flipGameID)) const onFlipAgain = () => { - text && sendMessage(text.stringValue()) + if (text) { + sendMessage(text.stringValue()) + } } const phase = status?.phase const errorInfo = phase === T.RPCChat.UICoinFlipPhase.error ? status?.errorInfo : undefined diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx index 89a5573a6b2d..0dedcb846ef0 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx @@ -21,7 +21,9 @@ const UnfurlImage = (p: Props) => { const {autoplayVideo, isVideo, linkURL, onClick, url, style, widthPadding} = p const onOpenURL = () => { - linkURL && openURL(linkURL) + if (linkURL) { + openURL(linkURL) + } } const maxSize = Math.min(maxWidth, 320) - (widthPadding || 0) const {height, width} = clampImageSize(p.width, p.height, maxSize, 320) diff --git a/shared/chat/conversation/messages/text/wrapper.tsx b/shared/chat/conversation/messages/text/wrapper.tsx index 59602f283178..04d293e3404f 100644 --- a/shared/chat/conversation/messages/text/wrapper.tsx +++ b/shared/chat/conversation/messages/text/wrapper.tsx @@ -62,7 +62,9 @@ function WrapperText(p: Props) { }) const onReplyClick = () => { const id = replyTo?.id ?? 0 - id && messageData.replyJump(id) + if (id) { + messageData.replyJump(id) + } } const reply = useReply(replyTo, onReplyClick) diff --git a/shared/chat/conversation/messages/wrapper/exploding-meta.tsx b/shared/chat/conversation/messages/wrapper/exploding-meta.tsx index 9f85639ad012..367f8fd5eab3 100644 --- a/shared/chat/conversation/messages/wrapper/exploding-meta.tsx +++ b/shared/chat/conversation/messages/wrapper/exploding-meta.tsx @@ -122,7 +122,9 @@ function ExplodingMetaInner(p: ExplodingMetaInnerProps) { if (!exploded || mode !== 'boom') { return undefined } - sharedTimerIDRef.current && SharedTimer.removeObserver(messageKey, sharedTimerIDRef.current) + if (sharedTimerIDRef.current) { + SharedTimer.removeObserver(messageKey, sharedTimerIDRef.current) + } sharedTimerKeyRef.current = messageKey sharedTimerIDRef.current = SharedTimer.addObserver( () => setTimerState(state => ({...state, mode: 'hidden'})), @@ -133,8 +135,9 @@ function ExplodingMetaInner(p: ExplodingMetaInnerProps) { ) return () => { - sharedTimerIDRef.current && + if (sharedTimerIDRef.current) { SharedTimer.removeObserver(sharedTimerKeyRef.current, sharedTimerIDRef.current) + } } }, [exploded, messageKey, mode]) diff --git a/shared/chat/conversation/messages/wrapper/wrapper.tsx b/shared/chat/conversation/messages/wrapper/wrapper.tsx index c7f853047988..65a85f678fed 100644 --- a/shared/chat/conversation/messages/wrapper/wrapper.tsx +++ b/shared/chat/conversation/messages/wrapper/wrapper.tsx @@ -653,7 +653,9 @@ function EditCancelRetry(p: { setEditing(ordinal) } const onRetry = () => { - outboxID && messageRetry(outboxID) + if (outboxID) { + messageRetry(outboxID) + } } const cancel = diff --git a/shared/chat/conversation/pinned-message.tsx b/shared/chat/conversation/pinned-message.tsx index 5068372e04d0..2f26edc12f98 100644 --- a/shared/chat/conversation/pinned-message.tsx +++ b/shared/chat/conversation/pinned-message.tsx @@ -33,7 +33,9 @@ const PinnedMessage = function PinnedMessage() { const dismissUnpins = yourMessage || canAdminDelete const onClick = () => { - messageID && replyJump(messageID) + if (messageID) { + replyJump(messageID) + } } const onUnpin = () => { pinMessage() diff --git a/shared/chat/emoji-picker/container.tsx b/shared/chat/emoji-picker/container.tsx index 6b73748b139a..ded43ac44de2 100644 --- a/shared/chat/emoji-picker/container.tsx +++ b/shared/chat/emoji-picker/container.tsx @@ -13,6 +13,7 @@ import {type RenderableEmoji, emojiData} from '@/common-adapters/emoji' import {usePickerState, type PickKey} from './use-picker' import {Keyboard} from 'react-native' import {useUserEmoji} from '@/chat/user-emoji' +import {ensureError} from '@/util/errors' type Props = { disableCustomEmoji?: boolean @@ -61,7 +62,7 @@ const useSkinTone = () => { [{skinTone: T.Chat.EmojiSkinToneToRPC(emojiSkinTone)}], res => updateUserReacjis(res), err => { - throw err + throw ensureError(err) } ) } diff --git a/shared/chat/emoji-picker/index.tsx b/shared/chat/emoji-picker/index.tsx index 811cd9010cd4..325e3460a034 100644 --- a/shared/chat/emoji-picker/index.tsx +++ b/shared/chat/emoji-picker/index.tsx @@ -170,12 +170,13 @@ const getSectionsAndBookmarks = ( getEmojiSections(emojisPerLine).forEach(section => { const categoryIcon = emojiData.categoryIcons[section.title] as Kb.IconType | undefined - categoryIcon && + if (categoryIcon) { bookmarks.push({ coveredSectionKeys: new Set([section.key]), iconType: categoryIcon, sectionIndex: sections.length, }) + } sections.push(section) }) diff --git a/shared/chat/inbox/index.desktop.tsx b/shared/chat/inbox/index.desktop.tsx index ecfa55b093ee..9308c2960fbc 100644 --- a/shared/chat/inbox/index.desktop.tsx +++ b/shared/chat/inbox/index.desktop.tsx @@ -75,10 +75,9 @@ const DragLine = (p: { const newSmallRows = deltaNewSmallRows() let expandingRows: Array = [] let removingRows: Array = [] - if (newSmallRows === 0) { - } else if (newSmallRows > 0) { + if (newSmallRows > 0) { expandingRows = new Array(newSmallRows).fill('') - } else { + } else if (newSmallRows < 0) { removingRows = new Array(-newSmallRows).fill('') } diff --git a/shared/chat/location-map.desktop.tsx b/shared/chat/location-map.desktop.tsx index cb6757ef214d..4017add5f1e6 100644 --- a/shared/chat/location-map.desktop.tsx +++ b/shared/chat/location-map.desktop.tsx @@ -14,7 +14,9 @@ const LocationMap = (props: Props) => { const [mapLoaded, setMapLoaded] = React.useState(false) const onLoad = () => { setMapLoaded(true) - !!props.onLoad && props.onLoad() + if (props.onLoad) { + props.onLoad() + } } return ( diff --git a/shared/chat/location-map.native.tsx b/shared/chat/location-map.native.tsx index 0a459b9b2f24..fa260941c884 100644 --- a/shared/chat/location-map.native.tsx +++ b/shared/chat/location-map.native.tsx @@ -14,7 +14,9 @@ const LocationMap = (props: Props) => { const [mapLoaded, setMapLoaded] = React.useState(false) const onLoad = () => { setMapLoaded(true) - !!props.onLoad && props.onLoad() + if (props.onLoad) { + props.onLoad() + } } return ( diff --git a/shared/chat/pdf/index.desktop.tsx b/shared/chat/pdf/index.desktop.tsx index dcc22277245d..a20bbc581c42 100644 --- a/shared/chat/pdf/index.desktop.tsx +++ b/shared/chat/pdf/index.desktop.tsx @@ -15,7 +15,9 @@ const ChatPDF = (props: Props) => { const attachmentDownload = ConvoState.useChatContext(s => s.dispatch.attachmentDownload) const onDownload = () => { - message && attachmentDownload(message.ordinal) + if (message) { + attachmentDownload(message.ordinal) + } openLocalPathInSystemFileManagerDesktop(C.downloadFolder) } diff --git a/shared/chat/send-to-chat/index.tsx b/shared/chat/send-to-chat/index.tsx index 44062ee8a6de..8518f7cfdc89 100644 --- a/shared/chat/send-to-chat/index.tsx +++ b/shared/chat/send-to-chat/index.tsx @@ -34,7 +34,9 @@ export const MobileSendToChat = (props: Props) => { const navigateAppend = C.Router2.navigateAppend const clearModals = C.Router2.clearModals const onSelect = (conversationIDKey: T.Chat.ConversationIDKey, tlfName: string) => { - text && ConvoState.getConvoUIState(conversationIDKey).dispatch.injectIntoInput(text) + if (text) { + ConvoState.getConvoUIState(conversationIDKey).dispatch.injectIntoInput(text) + } if (sendPaths?.length) { navigateAppend({ name: 'chatAttachmentGetTitles', diff --git a/shared/common-adapters/avatar/icon-to-img-set.tsx b/shared/common-adapters/avatar/icon-to-img-set.tsx index 4f0c2cc8429d..ff4a1cd30822 100644 --- a/shared/common-adapters/avatar/icon-to-img-set.tsx +++ b/shared/common-adapters/avatar/icon-to-img-set.tsx @@ -24,7 +24,7 @@ function getMultsMap(imgMap: {[size: string]: unknown}, targetSize: number): Mul const ssizes = Object.keys(imgMap) if (!ssizes.length) return {} - const sizeKey = targetSize + ']' + ssizes.join(':') + const sizeKey = `${targetSize}]${ssizes.join(':')}` if (_getMultsMapCache[sizeKey]) return _getMultsMapCache[sizeKey] const sizes = ssizes.map(s => parseInt(s, 10)).sort((a: number, b: number) => a - b) diff --git a/shared/common-adapters/banner.tsx b/shared/common-adapters/banner.tsx index 1ff3acfd132e..f0b1075ce013 100644 --- a/shared/common-adapters/banner.tsx +++ b/shared/common-adapters/banner.tsx @@ -27,7 +27,9 @@ export const BannerParagraph = (props: BannerParagraphProps) => ( > {(Array.isArray(props.content) ? props.content : [props.content]) .reduce>((arr, s) => { - s && arr.push(s) + if (s) { + arr.push(s) + } return arr }, []) .map(segment => (typeof segment === 'string' ? {text: segment} : segment)) diff --git a/shared/common-adapters/check-circle.tsx b/shared/common-adapters/check-circle.tsx index 991b3713baea..06c73c80732d 100644 --- a/shared/common-adapters/check-circle.tsx +++ b/shared/common-adapters/check-circle.tsx @@ -24,7 +24,9 @@ type Props = { const CheckCircle = (props: Props) => { const onClick = () => { if (props.onCheck) { - !props.disabled && props.onCheck(!props.checked) + if (!props.disabled) { + props.onCheck(!props.checked) + } } } diff --git a/shared/common-adapters/floating-menu/menu-layout/index.desktop.tsx b/shared/common-adapters/floating-menu/menu-layout/index.desktop.tsx index 76e543127392..b2cc909ddbb2 100644 --- a/shared/common-adapters/floating-menu/menu-layout/index.desktop.tsx +++ b/shared/common-adapters/floating-menu/menu-layout/index.desktop.tsx @@ -93,7 +93,9 @@ const MenuLayout = (props: MenuLayoutProps) => { if (item === 'Divider' && arr.length && arr.at(-1) === 'Divider') { return arr } - item && arr.push(item) + if (item) { + arr.push(item) + } return arr }, []) diff --git a/shared/common-adapters/floating-menu/menu-layout/index.native.tsx b/shared/common-adapters/floating-menu/menu-layout/index.native.tsx index 6a187dad8c20..b5ad9c8e14be 100644 --- a/shared/common-adapters/floating-menu/menu-layout/index.native.tsx +++ b/shared/common-adapters/floating-menu/menu-layout/index.native.tsx @@ -45,8 +45,10 @@ const MenuRow = (props: MenuRowProps) => ( { - props.onHidden && !props.unWrapped && props.onHidden() // auto hide after a selection - props.onClick && !props.unWrapped && props.onClick() + if (!props.unWrapped) { + props.onHidden?.() // auto hide after a selection + props.onClick?.() + } }} style={Styles.collapseStyles([ styles.itemContainer, diff --git a/shared/common-adapters/index-impl.js b/shared/common-adapters/index-impl.js index 036e0501316f..b636bd06dbd6 100644 --- a/shared/common-adapters/index-impl.js +++ b/shared/common-adapters/index-impl.js @@ -1,3 +1,5 @@ +/* global module, require */ + // this is to defer actually importing these modules until you actually use them // this file is ignored by ts module.exports = { @@ -73,14 +75,14 @@ module.exports = { get ConnectedNameWithIcon() { // explicitly require this to make popup work if it's not been imported // explicitly - require('./profile-card').default + require('./profile-card') return require('./name-with-icon').default }, get ConnectedUsernames() { // explicitly require this to make popup work if it's not been imported // explicitly - require('./profile-card').default + require('./profile-card') return require('./usernames').default }, diff --git a/shared/common-adapters/markdown/react.tsx b/shared/common-adapters/markdown/react.tsx index 57878fda5364..7467c961ae11 100644 --- a/shared/common-adapters/markdown/react.tsx +++ b/shared/common-adapters/markdown/react.tsx @@ -212,7 +212,7 @@ const reactComponentsForMarkdownType = { // nodes together into a single string output. let lastResult: React.ReactNode = null for (let i = 0; i < arr.length; i++) { - state.key = '' + i + state.key = String(i) const nodeOut = output(arr[i]!, state) if (typeof nodeOut === 'string' && typeof lastResult === 'string') { lastResult = lastResult + nodeOut diff --git a/shared/common-adapters/name-with-icon.tsx b/shared/common-adapters/name-with-icon.tsx index 63303060ac45..9216995ab049 100644 --- a/shared/common-adapters/name-with-icon.tsx +++ b/shared/common-adapters/name-with-icon.tsx @@ -66,7 +66,9 @@ const NameWithIcon = (props: NameWithIconProps) => { const _onClickWrapper = onClick ? (event: React.BaseSyntheticEvent) => { if (!event.defaultPrevented) { - username && onClick(username) + if (username) { + onClick(username) + } } } : undefined diff --git a/shared/common-adapters/phone-input.tsx b/shared/common-adapters/phone-input.tsx index 5e6987b4ed75..3f8ced4261a7 100644 --- a/shared/common-adapters/phone-input.tsx +++ b/shared/common-adapters/phone-input.tsx @@ -519,7 +519,7 @@ const PhoneInput = (p: Props) => { ? !prefix ? '- Pick a country -' : '- Invalid country prefix -' - : countryData()[country]?.emoji + ' ' + countryData()[country]?.name} + : `${String(countryData()[country]?.emoji)} ${String(countryData()[country]?.name)}`} ) } @@ -530,7 +530,7 @@ const PhoneInput = (p: Props) => { {getCountryEmoji(country)} - {'+' + prefix} + {'+' + String(prefix)} ) diff --git a/shared/common-adapters/popup/floating-box/relative-floating-box.desktop.tsx b/shared/common-adapters/popup/floating-box/relative-floating-box.desktop.tsx index 14719365be47..ed335b3fb685 100644 --- a/shared/common-adapters/popup/floating-box/relative-floating-box.desktop.tsx +++ b/shared/common-adapters/popup/floating-box/relative-floating-box.desktop.tsx @@ -321,7 +321,9 @@ export const RelativeFloatingBox = (props: ModalPositionRelativeProps) => { const handleClick = (e: MouseEvent) => { if (popupNode && e.target instanceof HTMLElement && !popupNode.contains(e.target)) { - !propagateOutsideClicks && e.stopPropagation() + if (!propagateOutsideClicks) { + e.stopPropagation() + } onClosePopup() } } diff --git a/shared/common-adapters/search-filter.tsx b/shared/common-adapters/search-filter.tsx index 656e57f46b24..3766e8ffb16d 100644 --- a/shared/common-adapters/search-filter.tsx +++ b/shared/common-adapters/search-filter.tsx @@ -121,7 +121,11 @@ function SearchFilter(props: Props & {ref?: React.Ref}) { const cancel = (e?: React.BaseSyntheticEvent) => { blur() - onCancel ? onCancel() : clear() + if (onCancel) { + onCancel() + } else { + clear() + } e?.stopPropagation() } @@ -137,7 +141,9 @@ function SearchFilter(props: Props & {ref?: React.Ref}) { Kb.useHotKey(props.hotkey && !props.onClick ? `mod+${props.hotkey}` : '', onHotkey) const onKeyDown = (e: React.KeyboardEvent) => { - e.key === 'Escape' && cancel(e) + if (e.key === 'Escape') { + cancel(e) + } _onKeyDown?.(e) } diff --git a/shared/common-adapters/section-list.tsx b/shared/common-adapters/section-list.tsx index 03b68fe4f7ff..05fb616b15f4 100644 --- a/shared/common-adapters/section-list.tsx +++ b/shared/common-adapters/section-list.tsx @@ -40,7 +40,9 @@ function SectionListImpl( const onViewableItemsChanged = onSectionChange ? (e: {viewableItems: ViewToken[]}) => { const section = e.viewableItems[0]?.section as SectionT | undefined - section && onSectionChange(section) + if (section) { + onSectionChange(section) + } } : undefined diff --git a/shared/common-adapters/skip-animations.js b/shared/common-adapters/skip-animations.js index a48a6a242870..30cc7be3fc3e 100644 --- a/shared/common-adapters/skip-animations.js +++ b/shared/common-adapters/skip-animations.js @@ -1,3 +1,5 @@ +/* global console, module */ + // used by babel.config so has to be a js file. restart packager if you change this const skipAnimations = false module.exports = skipAnimations diff --git a/shared/common-adapters/video.desktop.tsx b/shared/common-adapters/video.desktop.tsx index 8d05ff4207a2..5385d1c32ad2 100644 --- a/shared/common-adapters/video.desktop.tsx +++ b/shared/common-adapters/video.desktop.tsx @@ -33,7 +33,11 @@ const Video = (props: Props) => { const onVideoClick = () => { if (videoRef.current) { - videoRef.current.paused ? videoRef.current.play().catch(() => {}) : videoRef.current.pause() + if (videoRef.current.paused) { + videoRef.current.play().catch(() => {}) + } else { + videoRef.current.pause() + } } } diff --git a/shared/common-adapters/web-view.desktop.tsx b/shared/common-adapters/web-view.desktop.tsx index a6aa5fad8b48..2f13bb9c4eb4 100644 --- a/shared/common-adapters/web-view.desktop.tsx +++ b/shared/common-adapters/web-view.desktop.tsx @@ -16,16 +16,12 @@ const WebView = (props: WebViewProps) => { const onDomReady = () => { if (!ref) return - css && - ref - .insertCSS(css) - .then(() => {}) - .catch(() => {}) - javaScript && - ref - .executeJavaScript(javaScript) - .then(() => {}) - .catch(() => {}) + if (css) { + ref.insertCSS(css).catch(() => {}) + } + if (javaScript) { + ref.executeJavaScript(javaScript).catch(() => {}) + } ref.removeEventListener('dom-ready', onDomReady) } diff --git a/shared/common-adapters/web-view.native.tsx b/shared/common-adapters/web-view.native.tsx index 551145b9bbf4..b134c491d62f 100644 --- a/shared/common-adapters/web-view.native.tsx +++ b/shared/common-adapters/web-view.native.tsx @@ -85,7 +85,9 @@ const KBWebViewBase = (props: WebViewProps) => { } // With links from the Files tab, URL can change because of the // token. So only open the URL when navigationType is 'click'. - request.navigationType === 'click' && openURL(request.url) + if (request.navigationType === 'click') { + openURL(request.url) + } return false } : undefined diff --git a/shared/common-adapters/zoomable-image.desktop.tsx b/shared/common-adapters/zoomable-image.desktop.tsx index 22283fb577e4..b5ee5944643e 100644 --- a/shared/common-adapters/zoomable-image.desktop.tsx +++ b/shared/common-adapters/zoomable-image.desktop.tsx @@ -93,7 +93,9 @@ function ZoomableImage(p: Props) { } const handleWheel = (e: React.WheelEvent) => { - e.cancelable && e.preventDefault() + if (e.cancelable) { + e.preventDefault() + } if (dragPan && !allowPan) return if (!dragPan && !isZoomedRef.current) return diff --git a/shared/constants/chat/message.tsx b/shared/constants/chat/message.tsx index 34e0284f9c22..b32c618071a3 100644 --- a/shared/constants/chat/message.tsx +++ b/shared/constants/chat/message.tsx @@ -876,7 +876,9 @@ const validUIMessagetoMessage = ( ? payments.reduce((arr: Array, p) => { if (p.result.resultTyp === T.RPCChat.TextPaymentResultTyp.sent) { const s = p.result.sent - s && arr.push(s) + if (s) { + arr.push(s) + } } return arr }, []) diff --git a/shared/constants/deeplinks.tsx b/shared/constants/deeplinks.tsx index 824481f41b6b..1a8db452c00e 100644 --- a/shared/constants/deeplinks.tsx +++ b/shared/constants/deeplinks.tsx @@ -68,7 +68,9 @@ const handleKeybaseLink = (link: string) => { return } if (parts[1] === 'new-proof' && (parts.length === 3 || parts.length === 4)) { - parts.length === 4 && parts[3] && navToProfile(parts[3]) + if (parts.length === 4 && parts[3]) { + navToProfile(parts[3]) + } navigateAppend({name: 'profileProofsList', params: {platform: parts[2]!, reason: 'appLink'}}) return } diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 77c3c9b002ef..6e8eff8373bc 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -175,10 +175,11 @@ const onChatWatchPosition = async ( await requestLocationPermission(action.payload.params.perm) } catch (_error) { const error = _error as {message?: string} - logger.info('failed to get location perms: ' + error.message) + const message = String(error.message) + logger.info('failed to get location perms: ' + message) setPermissionDeniedCommandStatus( T.Chat.conversationIDToKey(action.payload.params.convID), - `Failed to access location. ${error.message}` + `Failed to access location. ${message}` ) } @@ -286,7 +287,6 @@ export const initPlatformListener = () => { cacheDirOverride: fsCacheDir, downloadDirOverride: fsDownloadDir, }) - .then(() => {}) .catch((e: unknown) => { logger.error(`[Android cache override] Failed to configure: ${String(e)}`) }) diff --git a/shared/constants/router.tsx b/shared/constants/router.tsx index d8e2cf6dd546..ef5e77b2374b 100644 --- a/shared/constants/router.tsx +++ b/shared/constants/router.tsx @@ -262,7 +262,9 @@ export function makeScreen>( } export const clearModals = () => { - DEBUG_NAV && console.log('[Nav] clearModals') + if (DEBUG_NAV) { + console.log('[Nav] clearModals') + } const n = _getNavigator() if (!n) return const ns = getRootState() @@ -286,13 +288,17 @@ export const clearModals = () => { } export const navigateUp = () => { - DEBUG_NAV && console.log('[Nav] navigateUp') + if (DEBUG_NAV) { + console.log('[Nav] navigateUp') + } const n = _getNavigator() return n?.dispatch(CommonActions.goBack()) } export const popStack = () => { - DEBUG_NAV && console.log('[Nav] popStack') + if (DEBUG_NAV) { + console.log('[Nav] popStack') + } const n = _getNavigator() n?.dispatch(StackActions.popToTop()) } @@ -300,7 +306,9 @@ export const popStack = () => { export function navUpToScreen(name: RouteKeys): void export function navUpToScreen(path: NavigateAppendType, replaceIfMissing?: boolean): void export function navUpToScreen(nameOrPath: RouteKeys | NavigateAppendType, replaceIfMissing = false) { - DEBUG_NAV && console.log('[Nav] navUpToScreen', {nameOrPath, replaceIfMissing}) + if (DEBUG_NAV) { + console.log('[Nav] navUpToScreen', {nameOrPath, replaceIfMissing}) + } const n = _getNavigator() if (!n) return const activeStackState = getActiveStackState() @@ -350,7 +358,9 @@ export function navUpToScreen(nameOrPath: RouteKeys | NavigateAppendType, replac } export function navigateAppend(path: NavigateAppendType, replace?: boolean) { - DEBUG_NAV && console.log('[Nav] navigateAppend', {path}) + if (DEBUG_NAV) { + console.log('[Nav] navigateAppend', {path}) + } const n = _getNavigator() if (!n) { return @@ -363,7 +373,9 @@ export function navigateAppend(path: NavigateAppendType, replace?: boolean) { const routeName = typeof nextPath.name === 'string' ? nextPath.name : String(nextPath.name) const params = nextPath.params if (!routeName) { - DEBUG_NAV && console.log('[Nav] navigateAppend no routeName bail', routeName) + if (DEBUG_NAV) { + console.log('[Nav] navigateAppend no routeName bail', routeName) + } return } const vp = getVisiblePath(ns) @@ -389,7 +401,9 @@ export function navigateAppend(path: NavigateAppendType, replace?: boolean) { } export const switchTab = (name: Tabs.AppTab) => { - DEBUG_NAV && console.log('[Nav] switchTab', {name}) + if (DEBUG_NAV) { + console.log('[Nav] switchTab', {name}) + } const n = _getNavigator() if (!n) return const ns = getRootState() @@ -729,7 +743,9 @@ export type NavigateToThreadReason = | 'teamMention' const navToThread = (conversationIDKey: T.Chat.ConversationIDKey, navParams?: ThreadNavParams) => { - DEBUG_NAV && console.log('[Nav] navToThread', conversationIDKey) + if (DEBUG_NAV) { + console.log('[Nav] navToThread', conversationIDKey) + } const n = _getNavigator() if (!n) return const rs = getRootState() diff --git a/shared/constants/teams.tsx b/shared/constants/teams.tsx index 476d164b7906..e5cdb56627d6 100644 --- a/shared/constants/teams.tsx +++ b/shared/constants/teams.tsx @@ -398,7 +398,7 @@ export const getTeamRowBadgeCount = ( } const canUserPerformCache: {[key: string]: T.Teams.TeamOperations} = {} -const canUserPerformCacheKey = (t: T.Teams.TeamRoleAndDetails) => t.role + t.implicitAdmin +const canUserPerformCacheKey = (t: T.Teams.TeamRoleAndDetails) => `${t.role}${String(t.implicitAdmin)}` export const deriveCanPerform = (roleAndDetails?: T.Teams.TeamRoleAndDetails): T.Teams.TeamOperations => { if (!roleAndDetails) { return initialCanUserPerform diff --git a/shared/desktop/app/ipc-handlers.desktop.tsx b/shared/desktop/app/ipc-handlers.desktop.tsx index 7432d980eed3..6e3300faeb14 100644 --- a/shared/desktop/app/ipc-handlers.desktop.tsx +++ b/shared/desktop/app/ipc-handlers.desktop.tsx @@ -14,6 +14,7 @@ import {ctlQuit} from './ctl.desktop' import logger from '@/logger' import {htmlURL, preloadPath} from './html-root.desktop' import * as RPCTypes from '@/constants/rpc/rpc-gen' +import {ensureError} from '@/util/errors' import type {Action} from '../app/ipctypes' import type {Engine} from '@/engine' import {showDevTools, skipSecondaryDevtools, allowMultipleInstances} from '@/local-debug.desktop' @@ -38,7 +39,7 @@ const winCheckRPCOwnership = async () => { execFile(binPath, args, {windowsHide: true}, (error, stdout) => { if (error) { logger.info(`pipeowner check result: ${stdout.toString()}`) - reject(error) + reject(ensureError(error)) return } const result = JSON.parse(stdout.toString()) as undefined | {isOwner?: unknown} @@ -160,7 +161,7 @@ const openInDefaultDirectory = async (openPath: string) => { resolve() }) .catch((err: unknown) => { - reject(err) + reject(ensureError(err)) }) }) }) @@ -207,7 +208,7 @@ export const setupIPCHandlers = (deps: { logger.info('Invoking dokan installer') execFile(dokanPath, [], err => { if (err) { - reject(err) + reject(ensureError(err)) return } // restart the service, particularly kbfsdokan @@ -432,7 +433,11 @@ export const setupIPCHandlers = (deps: { case 'toggleMaximizeWindow': { const win = Electron.BrowserWindow.getFocusedWindow() if (win) { - win.isMaximized() ? win.unmaximize() : win.maximize() + if (win.isMaximized()) { + win.unmaximize() + } else { + win.maximize() + } } return } @@ -502,7 +507,7 @@ export const setupIPCHandlers = (deps: { {encoding: 'utf8'} ) } catch (e) { - console.warn('update app state failed' + e) + console.warn('update app state failed' + String(e)) } break case 'appStartedUp': diff --git a/shared/desktop/app/menu-bar.desktop.tsx b/shared/desktop/app/menu-bar.desktop.tsx index 21eb9e3648c9..437a39a36e81 100644 --- a/shared/desktop/app/menu-bar.desktop.tsx +++ b/shared/desktop/app/menu-bar.desktop.tsx @@ -91,7 +91,7 @@ const MenuBar = () => { try { mb.tray.setImage(getIcon()) } catch (err) { - console.error('menu icon err: ' + err) + console.error('menu icon err: ' + String(err)) } } @@ -123,7 +123,9 @@ const MenuBar = () => { action.payload.desktopAppBadgeCount > 0 ? fsAssetRoot + 'images/icons/icon-windows-badge.png' : null - overlay && mw?.setOverlayIcon(Electron.nativeImage.createFromPath(overlay), 'new activity') + if (overlay) { + mw?.setOverlayIcon(Electron.nativeImage.createFromPath(overlay), 'new activity') + } } }) diff --git a/shared/desktop/app/node.desktop.tsx b/shared/desktop/app/node.desktop.tsx index ce9a0609ea0d..31952b1cde3e 100644 --- a/shared/desktop/app/node.desktop.tsx +++ b/shared/desktop/app/node.desktop.tsx @@ -113,7 +113,9 @@ const startApp = () => { flushDeferredLaunch(runtime, getStartupProcessArgs) installer(err => { - err && console.log('Error: ', err) + if (err) { + console.log('Error: ', err) + } R.remoteDispatch(RemoteGen.createInstallerRan()) }) }, diff --git a/shared/desktop/package.desktop.mts b/shared/desktop/package.desktop.mts index fd93a69a88fc..dd6ad83b4564 100644 --- a/shared/desktop/package.desktop.mts +++ b/shared/desktop/package.desktop.mts @@ -166,8 +166,7 @@ async function main() { copySync('Icon.png', 'build/desktop/Icon.png') copySync('Icon@2x.png', 'build/desktop/Icon@2x.png') await copySyncFolder('../images', 'build/images', ['.gif', '.png']) - if (TEMP_SKIP_BUILD) { - } else { + if (!TEMP_SKIP_BUILD) { fs.removeSync(desktopPath('build/images/folders')) fs.removeSync(desktopPath('build/images/iconfont')) fs.removeSync(desktopPath('build/images/mock')) @@ -193,8 +192,7 @@ async function startPack() { process.env['APP_VERSION'] = appVersion const webpackConfig: Array = rootConfig(null, {mode: 'production'}) try { - if (TEMP_SKIP_BUILD) { - } else { + if (!TEMP_SKIP_BUILD) { const stats = await new Promise((resolve, reject) => { webpack(webpackConfig, (err: Error | null, stats: webpack.MultiStats | undefined) => { if (err) { diff --git a/shared/desktop/remote/use-serialize-props.desktop.tsx b/shared/desktop/remote/use-serialize-props.desktop.tsx index 51e3405efbd8..7f4b9a393ed5 100644 --- a/shared/desktop/remote/use-serialize-props.desktop.tsx +++ b/shared/desktop/remote/use-serialize-props.desktop.tsx @@ -29,7 +29,9 @@ export default function useSerializeProps

( const throttledSend = C.useThrottledCallback( (nextPropsStr: string, forceUpdateVersion: number) => { if (nextPropsStr === lastSent.current && forceUpdateVersion === lastForceUpdate.current) return - debugSerializer && console.log('[useSerializeProps]: throttled send', nextPropsStr.length) + if (debugSerializer) { + console.log('[useSerializeProps]: throttled send', nextPropsStr.length) + } rendererNewProps?.({propsStr: nextPropsStr, windowComponent, windowParam}) lastSent.current = nextPropsStr lastForceUpdate.current = forceUpdateVersion diff --git a/shared/desktop/yarn-helper/font.mts b/shared/desktop/yarn-helper/font.mts index 316b3ec47492..62d7e9c2bad9 100644 --- a/shared/desktop/yarn-helper/font.mts +++ b/shared/desktop/yarn-helper/font.mts @@ -117,14 +117,18 @@ function updateIconFont(web: boolean) { try { execSync('fontforge') } catch (error_) { - const error = error_ as {message: string} - if (error.message.includes('not found')) { + const error = error_ as {message?: string} + const message = String(error.message) + if (message.includes('not found')) { throw new Error( 'FontForge is required to generate the icon font. Run `yarn`, install FontForge CLI globally, and try again.', {cause: error_} ) } - throw error + if (error_ instanceof Error) { + throw error_ + } + throw new Error(message, {cause: error_}) } } diff --git a/shared/engine/listener.tsx b/shared/engine/listener.tsx index 6ca568e74c72..fb148beb6c7d 100644 --- a/shared/engine/listener.tsx +++ b/shared/engine/listener.tsx @@ -1,5 +1,5 @@ import {getEngine} from './require' -import {RPCError} from '@/util/errors' +import {ensureError, RPCError} from '@/util/errors' import {printOutstandingRPCs} from '@/local-debug' import type {CommonResponseHandler} from './types' import {wrapErrors} from '@/util/debug' @@ -127,7 +127,7 @@ async function listener(p: { } if (error) { - reject(error) + reject(ensureError(error)) } else { resolve(params) } diff --git a/shared/fs/banner/conflict-banner.tsx b/shared/fs/banner/conflict-banner.tsx index b4d9229fd9bb..a77994859f85 100644 --- a/shared/fs/banner/conflict-banner.tsx +++ b/shared/fs/banner/conflict-banner.tsx @@ -128,7 +128,7 @@ const ConnectedBanner = (ownProps: OwnProps) => { ) } default: - return {'Unknown conflictState: ' + conflictState} + return {'Unknown conflictState: ' + String(conflictState)} } } diff --git a/shared/fs/browser/rows/sort.tsx b/shared/fs/browser/rows/sort.tsx index 059747a34c4e..4ae4f2213c07 100644 --- a/shared/fs/browser/rows/sort.tsx +++ b/shared/fs/browser/rows/sort.tsx @@ -80,7 +80,7 @@ const getComparerBySortBy = (sortBy: 'name' | 'time'): PathItemComparer => { return (a: SortableRowItem, b: SortableRowItem): number => getLastModifiedTimeStamp(b) - getLastModifiedTimeStamp(a) default: - throw new Error('invalid SortBy: ' + sortBy) + throw new Error('invalid SortBy: ' + String(sortBy)) } } diff --git a/shared/fs/common/hooks.tsx b/shared/fs/common/hooks.tsx index 2bf043c6b99a..943123c2d37a 100644 --- a/shared/fs/common/hooks.tsx +++ b/shared/fs/common/hooks.tsx @@ -294,7 +294,9 @@ export const FsDataProvider = ({children}: {children: React.ReactNode}) => { }) setPathSoftError(path) const tlfPath = FS.getTlfPath(path) - tlfPath && setTlfSoftError(tlfPath) + if (tlfPath) { + setTlfSoftError(tlfPath) + } } catch (error) { errorToActionOrThrow(error, path) } finally { @@ -485,7 +487,9 @@ const useFsLoadOnMountAndFocus = ({ loadOnMountAndFocus() }) React.useEffect(() => { - connected && enabled && loadOnMountAndFocus() + if (connected && enabled) { + loadOnMountAndFocus() + } }, [connected, enabled, reloadKey]) C.Router2.useSafeFocusEffect(stableLoadOnMountAndFocus) } @@ -845,7 +849,9 @@ export const useFsTlf = (path: T.FS.Path, options?: {loadOnMount?: boolean}) => FS.getTlfFromPathInFavoritesOnly(tlfs, tlfPath) === FS.unknownTlf && options?.loadOnMount !== false const loadCurrentTlf = React.useEffectEvent(() => { - active && loadAdditionalTlf(tlfPath) + if (active && loadAdditionalTlf && tlfPath) { + loadAdditionalTlf(tlfPath) + } }) const [stableLoadCurrentTlf] = React.useState(() => () => { loadCurrentTlf() @@ -1045,7 +1051,9 @@ export const useFsFileContext = ( const requestReloadKey = reloadKey const f = async () => { try { - urlError && logger.info(`urlError: ${urlError}`) + if (urlError) { + logger.info(`urlError: ${urlError}`) + } const res = await T.RPCGen.SimpleFSSimpleFSGetGUIFileContextRpcPromise({ path: FS.pathToRPCPath(path).kbfs, }) diff --git a/shared/fs/common/path-item-action/menu-container.tsx b/shared/fs/common/path-item-action/menu-container.tsx index 5ab36c0c37e6..7606599343bd 100644 --- a/shared/fs/common/path-item-action/menu-container.tsx +++ b/shared/fs/common/path-item-action/menu-container.tsx @@ -73,7 +73,9 @@ const Container = (op: OwnProps) => { const getLayout = view === T.FS.PathItemActionMenuView.Share ? getShareLayout : getRootLayout const layout = getLayout(mode, path, pathItem, fileContext, username) const cancel = () => { - C.isMobile && downloadID && cancelDownload(downloadID) + if (C.isMobile && downloadID) { + cancelDownload(downloadID) + } } const navigateAppend = C.Router2.navigateAppend const saving = downloadID && downloadIntent === T.FS.DownloadIntent.CameraRoll @@ -174,7 +176,9 @@ const Container = (op: OwnProps) => { { icon: 'iconfont-chat', onClick: hideAndCancelAfter(() => { - path && navigateAppend({name: 'chatSendToChat', params: {sendPaths: [path]}}) + if (path) { + navigateAppend({name: 'chatSendToChat', params: {sendPaths: [path]}}) + } }), subTitle: `The ${ pathItem.type === T.FS.PathType.Folder ? 'folder' : 'file' @@ -339,12 +343,16 @@ const Container = (op: OwnProps) => { const justDoneWithIntent = useFsWatchDownloadForMobile(downloadID || '', downloadIntent) React.useEffect(() => { - justDoneWithIntent && hide() + if (justDoneWithIntent) { + hide() + } }, [justDoneWithIntent, hide]) const userInitiatedHide = () => { hide() - downloadID && dismissDownload(downloadID) + if (downloadID) { + dismissDownload(downloadID) + } } return ( diff --git a/shared/fs/common/path-status-icon.tsx b/shared/fs/common/path-status-icon.tsx index 87fcf7d2e489..99a6bdd590ea 100644 --- a/shared/fs/common/path-status-icon.tsx +++ b/shared/fs/common/path-status-icon.tsx @@ -45,7 +45,7 @@ function getColor(status: T.FS.LocalConflictStatusType | T.FS.NonUploadStaticSyn function getTooltip(statusIcon: T.FS.PathStatusIcon, isFolder: boolean): string { if (typeof statusIcon === 'number') { - return 'Syncing ' + Math.floor(statusIcon * 100) + '%...' + return 'Syncing ' + String(Math.floor(statusIcon * 100)) + '%...' } switch (statusIcon) { diff --git a/shared/fs/common/rpc-state.tsx b/shared/fs/common/rpc-state.tsx index 46bb8b300288..7de7ffc44817 100644 --- a/shared/fs/common/rpc-state.tsx +++ b/shared/fs/common/rpc-state.tsx @@ -76,7 +76,9 @@ const rpcConflictStateToConflictState = (rpcConflictState?: T.RPCGen.ConflictSta const nv = rpcConflictState.normalview return makeConflictStateNormalView({ localViewTlfPaths: (nv.localViews || []).reduce>((arr, p) => { - p.PathType === T.RPCGen.PathType.kbfs && arr.push(rpcPathToPath(p.kbfs)) + if (p.PathType === T.RPCGen.PathType.kbfs) { + arr.push(rpcPathToPath(p.kbfs)) + } return arr }, []), resolvingConflict: nv.resolvingConflict, diff --git a/shared/fs/footer/download-wrapper.native.tsx b/shared/fs/footer/download-wrapper.native.tsx index 4f2511d7cb73..027c00a3ff23 100644 --- a/shared/fs/footer/download-wrapper.native.tsx +++ b/shared/fs/footer/download-wrapper.native.tsx @@ -33,7 +33,11 @@ const DownloadNativeWrapper: React.FC = props => { } React.useEffect(() => { - props.isFirst && props.done ? ensureStarted() : ensureStopped() + if (props.isFirst && props.done) { + ensureStarted() + } else { + ensureStopped() + } return () => { ensureStopped() diff --git a/shared/fs/index.tsx b/shared/fs/index.tsx index a7ed66ebd35c..0af832f8df54 100644 --- a/shared/fs/index.tsx +++ b/shared/fs/index.tsx @@ -23,7 +23,9 @@ const ChooseComponent = (props: ChooseComponentProps) => { const viewType: T.RPCGen.GUIViewType = fileContext.viewType const bare = C.isMobile && viewType === T.RPCGen.GUIViewType.image React.useEffect(() => { - bare && emitBarePreview() + if (bare) { + emitBarePreview() + } }, [bare, emitBarePreview]) Kbfs.useFsOnlineStatus() diff --git a/shared/fs/nav-header/actions.tsx b/shared/fs/nav-header/actions.tsx index 99c54c11c1ca..adaceb2f91ce 100644 --- a/shared/fs/nav-header/actions.tsx +++ b/shared/fs/nav-header/actions.tsx @@ -20,7 +20,9 @@ const FsNavHeaderRightActionsInner = (props: Props) => { ) const hasSoftError = !!Kbfs.useFsSoftError(props.path) React.useEffect(() => { - !Kb.Styles.isMobile && setFolderViewFilter() // mobile is handled in mobile-header.tsx + if (!Kb.Styles.isMobile) { + setFolderViewFilter() // mobile is handled in mobile-header.tsx + } }, [setFolderViewFilter, props.path]) // clear if path changes or it's a new layer of mount return !hasSoftError ? ( diff --git a/shared/fs/nav-header/title.tsx b/shared/fs/nav-header/title.tsx index c2d37ddbd70a..81d845c63301 100644 --- a/shared/fs/nav-header/title.tsx +++ b/shared/fs/nav-header/title.tsx @@ -23,13 +23,16 @@ const Breadcrumb = (props: Props) => { const {inDestinationPicker} = props const nav = useSafeNavigation() const onOpenPath = (path: T.FS.Path) => { - inDestinationPicker - ? props.destinationPickerSource && + if (inDestinationPicker) { + if (props.destinationPickerSource) { nav.safeNavigateAppend({ name: 'destinationPicker', params: {parentPath: path, source: props.destinationPickerSource}, }) - : nav.safeNavigateAppend({name: 'fsRoot', params: {path}}) + } + } else { + nav.safeNavigateAppend({name: 'fsRoot', params: {path}}) + } } const makePopup = (p: Kb.Popup2Parms) => { diff --git a/shared/git/index.tsx b/shared/git/index.tsx index f465dda6e22b..a509ce241df3 100644 --- a/shared/git/index.tsx +++ b/shared/git/index.tsx @@ -151,7 +151,11 @@ const Container = (ownProps: OwnProps) => { const toggleExpand = (id: string) => { setExpandedState(state => { const nextExpandedSet = new Set(state.expandedSet) - nextExpandedSet.has(id) ? nextExpandedSet.delete(id) : nextExpandedSet.add(id) + if (nextExpandedSet.has(id)) { + nextExpandedSet.delete(id) + } else { + nextExpandedSet.add(id) + } return {...state, expandedSet: nextExpandedSet} }) } diff --git a/shared/git/row.tsx b/shared/git/row.tsx index 2a9ecca4e58a..c64ee4bfe0f3 100644 --- a/shared/git/row.tsx +++ b/shared/git/row.tsx @@ -36,19 +36,21 @@ function ConnectedRow(ownProps: OwnProps) { const {canDelete, devicename, lastEditTime, lastEditUser, name} = git const onArchiveGitRepo = () => { - gitURL && + if (gitURL) { navigateAppend({ name: 'archiveModal', params: {gitURL, type: 'git' as const}, }) + } } const _onOpenChannelSelection = () => { - teamID && + if (teamID) { navigateAppend({ name: 'gitSelectChannel', params: {repoID, selected: channelName || 'general', teamID, teamname: teamname ?? ''}, }) + } } const onToggleChatEnabled = () => { @@ -91,7 +93,9 @@ function ConnectedRow(ownProps: OwnProps) { const onToggleExpand = () => onToggleExpand_(id) const onClickDevice = () => { - lastEditUser && openURL(`https://keybase.io/${lastEditUser}/devices`) + if (lastEditUser) { + openURL(`https://keybase.io/${lastEditUser}/devices`) + } } const onChannelClick = (e: React.BaseSyntheticEvent) => { diff --git a/shared/ignored-modules.js b/shared/ignored-modules.js index 39527fd711df..e3830e0cbb39 100644 --- a/shared/ignored-modules.js +++ b/shared/ignored-modules.js @@ -1 +1,3 @@ +/* global module */ + module.exports = ['net', 'tls', 'msgpack', 'process', 'purepack', '@khanacademy/perseus-core'] diff --git a/shared/incoming-share/index.tsx b/shared/incoming-share/index.tsx index e46265e66ee9..f44384acce9b 100644 --- a/shared/incoming-share/index.tsx +++ b/shared/incoming-share/index.tsx @@ -8,6 +8,7 @@ import {MobileSendToChat} from '../chat/send-to-chat' import {settingsFeedbackTab} from '@/constants/settings' import * as FS from '@/stores/fs' import {useConfigState} from '@/stores/config' +import {ensureError} from '@/util/errors' export const OriginalOrCompressedButton = ({incomingShareItems}: IncomingShareProps) => { const originalTotalSize = incomingShareItems.reduce((bytes, item) => bytes + (item.originalSize ?? 0), 0) @@ -30,7 +31,9 @@ export const OriginalOrCompressedButton = ({incomingShareItems}: IncomingSharePr // If it's original only, set original in store. React.useEffect(() => { - originalOnly && setUseOriginalInStore(true) + if (originalOnly) { + setUseOriginalInStore(true) + } }, [originalOnly, setUseOriginalInStore]) // From service to store, but only if this is not original only. @@ -44,7 +47,7 @@ export const OriginalOrCompressedButton = ({incomingShareItems}: IncomingSharePr pref.compressPreference === T.RPCGen.IncomingShareCompressPreference.original ), err => { - throw err + throw ensureError(err) } ) } @@ -57,7 +60,9 @@ export const OriginalOrCompressedButton = ({incomingShareItems}: IncomingSharePr const makePopup = (p: Kb.Popup2Parms) => { const {hidePopup} = p const setUseOriginalFromUI = (useOriginal: boolean) => { - !originalOnly && setUseOriginalInStore(useOriginal) + if (!originalOnly) { + setUseOriginalInStore(useOriginal) + } setUseOriginalInService(useOriginal) } @@ -195,7 +200,9 @@ const IncomingShare = (props: IncomingShareWithSelectionProps) => { React.useEffect(() => { if (!canDirectNav || hasNavigatedRef.current) return hasNavigatedRef.current = true - text && ConvoState.getConvoUIState(selectedConversationIDKey).dispatch.injectIntoInput(text) + if (text) { + ConvoState.getConvoUIState(selectedConversationIDKey).dispatch.injectIntoInput(text) + } C.Router2.navigateToThread(selectedConversationIDKey, 'extension') if (sendPaths.length > 0) { const meta = ConvoState.getConvoState(selectedConversationIDKey).meta diff --git a/shared/index.android.js b/shared/index.android.js index eb7ca05fbbd0..cd72e46f23e4 100644 --- a/shared/index.android.js +++ b/shared/index.android.js @@ -1,3 +1,5 @@ +/* global console, require */ + // React-native tooling assumes this file is here, so we just require our real entry point import './app/globals.native' try { diff --git a/shared/index.ios.js b/shared/index.ios.js index 2f0a53c7b63b..a3aa65d456fc 100644 --- a/shared/index.ios.js +++ b/shared/index.ios.js @@ -1,3 +1,5 @@ +/* global console, require */ + // React-native tooling assumes this file is here, so we just require our real entry point import './app/globals.native' try { diff --git a/shared/jest.config.js b/shared/jest.config.js index 2aab5e645614..0f72e3c4a4c8 100644 --- a/shared/jest.config.js +++ b/shared/jest.config.js @@ -1,3 +1,5 @@ +/* global module */ + module.exports = { moduleFileExtensions: [ 'desktop.tsx', diff --git a/shared/jest.setup.js b/shared/jest.setup.js index d9c5cca84f27..3e97586b09e4 100644 --- a/shared/jest.setup.js +++ b/shared/jest.setup.js @@ -1,3 +1,5 @@ +/* global global, require */ + const {enableMapSet, setUseStrictIteration} = require('immer') const {TextDecoder, TextEncoder} = require('util') diff --git a/shared/logger/index.tsx b/shared/logger/index.tsx index 88c0f9eae6e2..7d0e5012e91e 100644 --- a/shared/logger/index.tsx +++ b/shared/logger/index.tsx @@ -60,7 +60,9 @@ class AggregateLoggerImpl { private timerID: undefined | ReturnType private resetPeriodic = () => { - this.timerID && clearTimeout(this.timerID) + if (this.timerID) { + clearTimeout(this.timerID) + } // we wait, then want a good opportunity this.timerID = setTimeout(() => { requestIdleCallback( diff --git a/shared/login/recover-password/error-modal.tsx b/shared/login/recover-password/error-modal.tsx index 6f76d561fdbb..e59275843348 100644 --- a/shared/login/recover-password/error-modal.tsx +++ b/shared/login/recover-password/error-modal.tsx @@ -30,7 +30,11 @@ const ConnectedErrorModal = ({route}: Props) => { const popStack = C.Router2.popStack const navigateUp = C.Router2.navigateUp const onBack = () => { - loggedIn ? navigateUp() : popStack() + if (loggedIn) { + navigateUp() + } else { + popStack() + } } return ( diff --git a/shared/login/recover-password/error.tsx b/shared/login/recover-password/error.tsx index 4cabd3427c8f..370181f9d9db 100644 --- a/shared/login/recover-password/error.tsx +++ b/shared/login/recover-password/error.tsx @@ -12,7 +12,11 @@ const ConnectedError = ({route}: Props) => { const popStack = C.Router2.popStack const navigateUp = C.Router2.navigateUp const onBack = () => { - loggedIn ? navigateUp() : popStack() + if (loggedIn) { + navigateUp() + } else { + popStack() + } } return ( ; fol const {participants, teamname} = FsUtil.tlfToParticipantsOrTeamname(tlf) const tlfType = T.FS.getPathVisibility(update.tlf) || T.FS.TlfType.Private return ( - + { const {navBadges, showBadges} = p const openApp = (tab?: C.Tabs.AppTab) => { R.remoteDispatch(RemoteGen.createShowMain()) - tab && R.remoteDispatch(RemoteGen.createSwitchTab({tab})) + if (tab) { + R.remoteDispatch(RemoteGen.createSwitchTab({tab})) + } } const menuItems = useMenuItems({...p, openApp}) diff --git a/shared/null-module.js b/shared/null-module.js index 45db11f14141..3380f0dac492 100644 --- a/shared/null-module.js +++ b/shared/null-module.js @@ -1,2 +1,4 @@ +/* global module */ + // used in RN metro.config.js to ignore certain modules module.exports = null diff --git a/shared/people/container.tsx b/shared/people/container.tsx index 048abdc183bb..7ed5d1c796b6 100644 --- a/shared/people/container.tsx +++ b/shared/people/container.tsx @@ -387,7 +387,9 @@ const usePeoplePageState = () => { skipTodoRPC( [{t: T.RPCGen.HomeScreenTodoType[type]}], () => { - mountedRef.current && queueLoadPeople(false) + if (mountedRef.current) { + queueLoadPeople(false) + } }, _ => {} ) diff --git a/shared/people/index.shared.tsx b/shared/people/index.shared.tsx index 1a671c87a6c1..b9ec6d27a9d8 100644 --- a/shared/people/index.shared.tsx +++ b/shared/people/index.shared.tsx @@ -77,7 +77,9 @@ function EmailVerificationBanner(props: {signupEmail: string}) { () => // Only have a cleanup function () => { - signupEmail && clearSignupEmail() + if (signupEmail) { + clearSignupEmail() + } }, [signupEmail] ) diff --git a/shared/people/todo.tsx b/shared/people/todo.tsx index 49d6645177b6..5758c129d84e 100644 --- a/shared/people/todo.tsx +++ b/shared/people/todo.tsx @@ -47,7 +47,9 @@ type TodoOwnProps = { const installLinkURL = 'https://keybase.io/download' const useOnSkipTodo = (skipTodo: (type: T.People.TodoType) => void, type?: T.People.TodoType) => () => { - type && skipTodo(type) + if (type) { + skipTodo(type) + } } function makeDefaultButtons( @@ -117,7 +119,9 @@ const SettingsAccountTask = ({ const onConfirm = () => { switchTab(C.Tabs.settingsTab) navigateAppend({name: settingsAccountTab, params: {}}) - destination && navigateAppend({name: destination, params: {}}) + if (destination) { + navigateAppend({name: destination, params: {}}) + } } return } @@ -262,7 +266,9 @@ const VerifyAllPhoneNumberTask = (props: TodoOwnProps) => { label: 'Verify', onClick: () => { const meta = props.metadata - meta?.type === 'phone' && onConfirm(meta.phone) + if (meta?.type === 'phone') { + onConfirm(meta.phone) + } }, type: 'Success' as const, }, @@ -293,7 +299,9 @@ const LegacyEmailVisibilityTask = (props: TodoOwnProps) => { label: 'Make searchable', onClick: () => { const meta = props.metadata - meta?.type === 'email' && onConfirm(meta.email) + if (meta?.type === 'email') { + onConfirm(meta.email) + } }, type: 'Success' as const, }, diff --git a/shared/perf/compare-perf.js b/shared/perf/compare-perf.js index bfe14587e016..88b708c2c285 100644 --- a/shared/perf/compare-perf.js +++ b/shared/perf/compare-perf.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +/* global __dirname, console, module, process, require */ // Unified perf baseline comparison — handles both iOS and desktop baseline dirs. // // iOS baseline: maestro-fps.json + react-profiler.json diff --git a/shared/perf/desktop-perf-inject.js b/shared/perf/desktop-perf-inject.js index 44066591a5a0..c251a04f8fc5 100644 --- a/shared/perf/desktop-perf-inject.js +++ b/shared/perf/desktop-perf-inject.js @@ -1,3 +1,5 @@ +/* global PerformanceObserver, cancelAnimationFrame, clearInterval, document, performance, requestAnimationFrame, setInterval, window */ + // Desktop performance measurement script — inject via browser_evaluate in Electron. // Creates window.__perf with start(), scrollContainer(), and stop() methods. ;(function () { diff --git a/shared/perf/run-desktop-cdp-profile.js b/shared/perf/run-desktop-cdp-profile.js index 3c10e9a07a51..ce312097f8cd 100755 --- a/shared/perf/run-desktop-cdp-profile.js +++ b/shared/perf/run-desktop-cdp-profile.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +/* global __dirname, console, process, require, setTimeout */ // CDP CPU profiler for the Keybase Electron app. // Connects to the Chrome DevTools Protocol on localhost:9222, // records a CPU profile, and saves a .cpuprofile file. @@ -116,7 +117,7 @@ async function main() { await send('Profiler.start') console.log(`Profiling for ${duration}ms...`) - await new Promise(resolve => setTimeout(resvolve, duration)) + await new Promise(resolve => setTimeout(resolve, duration)) // 4. Stop and save const result = await send('Profiler.stop') diff --git a/shared/perf/run-desktop-perf.js b/shared/perf/run-desktop-perf.js index d15fd49ef74b..d4b64bb32753 100644 --- a/shared/perf/run-desktop-perf.js +++ b/shared/perf/run-desktop-perf.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +/* global __dirname, console, process, require, window */ // Automated desktop performance test. // Connects to a running Electron app via CDP, navigates to a screen, scrolls, and saves FPS + React render stats. // diff --git a/shared/perf/visual-diff-take.js b/shared/perf/visual-diff-take.js index 0a2b027f0648..0e7f9bf6f55e 100644 --- a/shared/perf/visual-diff-take.js +++ b/shared/perf/visual-diff-take.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +/* global Buffer, console, process, require, setTimeout */ // Takes screenshots of all 8 desktop app tabs via Chrome DevTools Protocol. // Usage: node visual-diff-take.js // diff --git a/shared/profile/generic/proofs-list.tsx b/shared/profile/generic/proofs-list.tsx index 1cc233d0fceb..44f2a06468fa 100644 --- a/shared/profile/generic/proofs-list.tsx +++ b/shared/profile/generic/proofs-list.tsx @@ -532,7 +532,9 @@ const Container = ({platform, reason = 'profile'}: Props) => { submit() return } - step.sigID && ignorePromise(checkProofAndNavigate(step.platform, step.sigID, step.username, step.proofText)) + if (step.sigID) { + ignorePromise(checkProofAndNavigate(step.platform, step.sigID, step.username, step.proofText)) + } }} step={step} /> @@ -928,7 +930,9 @@ const PostProof = ({ gap="small" onCopyCapture={e => { e.preventDefault() - proofText && copyToClipboard(proofText) + if (proofText) { + copyToClipboard(proofText) + } }} > {!!step.error && ( @@ -973,7 +977,9 @@ const PostProof = ({ { setShowSubmit(true) - url && openUrl(url) + if (url) { + openUrl(url) + } }} label={proofActionText} /> diff --git a/shared/profile/showcase-team-offer.tsx b/shared/profile/showcase-team-offer.tsx index 7c2e59ca9517..5fbe578609e0 100644 --- a/shared/profile/showcase-team-offer.tsx +++ b/shared/profile/showcase-team-offer.tsx @@ -75,7 +75,7 @@ const TeamRow = (p: RowProps) => { )} - {membercount + ' member' + (membercount !== 1 ? 's' : '')} + {String(membercount) + ' member' + (membercount !== 1 ? 's' : '')} {showcased || canShowcase || waiting ? ( diff --git a/shared/profile/user/actions/index.tsx b/shared/profile/user/actions/index.tsx index f0dd2fb77ed9..51f552e64602 100644 --- a/shared/profile/user/actions/index.tsx +++ b/shared/profile/user/actions/index.tsx @@ -189,7 +189,9 @@ const DropdownButton = (p: DropdownProps) => { title: blockedOrHidFromFollowers ? 'Manage blocking' : 'Block', }, ].reduce((arr, i) => { - i && arr.push(i as Kb.MenuItem) + if (i) { + arr.push(i as Kb.MenuItem) + } return arr }, []) return ( diff --git a/shared/profile/user/index.tsx b/shared/profile/user/index.tsx index 381516220c41..ff8c27da48f9 100644 --- a/shared/profile/user/index.tsx +++ b/shared/profile/user/index.tsx @@ -488,7 +488,7 @@ const User = (props: {username: string}) => { if (item.type === 'bioTeamProofs') return null if (item.type === 'friend') { return ( - + ) } return p.notAUser ? null : ( diff --git a/shared/provision/code-page/container.tsx b/shared/provision/code-page/container.tsx index 8608a04ec207..4c34c8fe0df4 100644 --- a/shared/provision/code-page/container.tsx +++ b/shared/provision/code-page/container.tsx @@ -38,7 +38,9 @@ const CodePageContainer = () => { const onBack = navigateUp const _onSubmitTextCode = (code: string) => { - !waiting && submitTextCode?.(code) + if (!waiting) { + submitTextCode?.(code) + } } const [code, setCode] = React.useState('') @@ -336,7 +338,9 @@ const EnterText = (props: { const {onSubmitTextCode} = props const onSubmit = (e?: React.KeyboardEvent) => { e?.preventDefault() - code && onSubmitTextCode(code) + if (code) { + onSubmitTextCode(code) + } } return ( diff --git a/shared/provision/set-public-name.tsx b/shared/provision/set-public-name.tsx index 2a1d5b8e56b8..7c4580d9d18a 100644 --- a/shared/provision/set-public-name.tsx +++ b/shared/provision/set-public-name.tsx @@ -15,7 +15,9 @@ const SetPublicName = () => { const ponBack = useSafeSubmit(navigateUp, !!error) const psetDeviceName = Provision.useProvisionState(s => s.dispatch.dynamic.setDeviceName) const ponSubmit = (name: string) => { - !waiting && psetDeviceName?.(name) + if (!waiting) { + psetDeviceName?.(name) + } } const iconNumbers = T.Devices.nextDeviceIconNumbers(devices) const deviceIconNumber = C.isMobile ? iconNumbers.mobile : iconNumbers.desktop diff --git a/shared/provision/username-or-email.tsx b/shared/provision/username-or-email.tsx index 51958953bfea..f2893b90d4b6 100644 --- a/shared/provision/username-or-email.tsx +++ b/shared/provision/username-or-email.tsx @@ -51,7 +51,9 @@ const UsernameOrEmailContainer = (op: OwnProps) => { const requestAutoInvite = useRequestAutoInvite() const _setUsername = useProvisionState(s => s.dispatch.dynamic.setUsername) const _onSubmit = (username: string) => { - !waiting && _setUsername?.(username) + if (!waiting) { + _setUsername?.(username) + } } const [username, setUsername] = React.useState(op.username ?? _username) React.useEffect(() => { diff --git a/shared/router-v2/common.desktop.tsx b/shared/router-v2/common.desktop.tsx index f68429f22a73..d8e037dea7f7 100644 --- a/shared/router-v2/common.desktop.tsx +++ b/shared/router-v2/common.desktop.tsx @@ -65,7 +65,7 @@ export const useSubnavTabAction: typeof useSubnavTabActionType = (navigation, st ? navRef.current.emit({ canPreventDefault: true, target: key, - // @ts-ignore tabPress is valid but not in the emit type + // @ts-expect-error tabPress is valid but not in the emit type type: 'tabPress', }) : {defaultPrevented: false} diff --git a/shared/router-v2/common.native.tsx b/shared/router-v2/common.native.tsx index a6c0acb0ea2a..00c9aec6c5e9 100644 --- a/shared/router-v2/common.native.tsx +++ b/shared/router-v2/common.native.tsx @@ -96,7 +96,7 @@ export const useSubnavTabAction = (navigation: SubnavNavigation, state: NavState ? navigation.emit({ canPreventDefault: true, target: route.key, - // @ts-ignore tabPress is valid but not in the emit type + // @ts-expect-error tabPress is valid but not in the emit type type: 'tabPress', }) : {defaultPrevented: false} diff --git a/shared/router-v2/header/index.desktop.tsx b/shared/router-v2/header/index.desktop.tsx index 154468aa4580..49e68779ab79 100644 --- a/shared/router-v2/header/index.desktop.tsx +++ b/shared/router-v2/header/index.desktop.tsx @@ -115,7 +115,9 @@ function DesktopHeader(p: Props) { const {headerTransparent, headerShadowVisible, headerBottomStyle, headerStyle, headerLeft} = options const pop = () => { - back && navigation.pop() + if (back) { + navigation.pop() + } } if (headerMode === 'none') { diff --git a/shared/settings/archive/index.tsx b/shared/settings/archive/index.tsx index b6526cfb636d..be4cfea4fc02 100644 --- a/shared/settings/archive/index.tsx +++ b/shared/settings/archive/index.tsx @@ -317,7 +317,7 @@ function KBFSJob(p: {index: number; job: KBFSArchiveJob}) { gap="tiny" > - {Math.round(progress * 100) + '%'} + {String(Math.round(progress * 100)) + '%'} {errorStr && ( diff --git a/shared/settings/logout.tsx b/shared/settings/logout.tsx index 7fd570405661..5385049fed0d 100644 --- a/shared/settings/logout.tsx +++ b/shared/settings/logout.tsx @@ -88,7 +88,11 @@ const LogoutContainer = () => { { - checkPasswordIsCorrect ? logOut() : onCheckPassword(password) + if (checkPasswordIsCorrect) { + logOut() + } else { + onCheckPassword(password) + } }} onChangeText={setPassword} placeholder="Your password" diff --git a/shared/settings/root-phone.tsx b/shared/settings/root-phone.tsx index 223fadfc9111..47455937666a 100644 --- a/shared/settings/root-phone.tsx +++ b/shared/settings/root-phone.tsx @@ -207,7 +207,7 @@ function SettingsNav() { ) : item.text ? ( item.onClick()} selected={false} diff --git a/shared/settings/screenprotector/index.native.tsx b/shared/settings/screenprotector/index.native.tsx index d3e5f486bd2e..15e523f9cfb4 100644 --- a/shared/settings/screenprotector/index.native.tsx +++ b/shared/settings/screenprotector/index.native.tsx @@ -10,8 +10,8 @@ const Screenprotector = () => { getSecureFlagSetting() .then(secureFlag => { setSecureFlag(secureFlag) + return undefined }) - .then(() => {}) .catch(() => {}) }) diff --git a/shared/signup/email.tsx b/shared/signup/email.tsx index 5868fb85b75d..c4ab01753d80 100644 --- a/shared/signup/email.tsx +++ b/shared/signup/email.tsx @@ -17,13 +17,21 @@ const ConnectedEnterEmail = () => { const onSkip = () => { _onSkip() - _showPushPrompt ? navigateAppend({name: 'settingsPushPrompt', params: {}}, true) : clearModals() + if (_showPushPrompt) { + navigateAppend({name: 'settingsPushPrompt', params: {}}, true) + } else { + clearModals() + } } const onCreate = (email: string, searchable: boolean) => { submitEmail(email, searchable, addedEmail => { setSignupEmail(addedEmail) - _showPushPrompt ? navigateAppend({name: 'settingsPushPrompt', params: {}}, true) : clearModals() + if (_showPushPrompt) { + navigateAppend({name: 'settingsPushPrompt', params: {}}, true) + } else { + clearModals() + } }) } diff --git a/shared/signup/routes.tsx b/shared/signup/routes.tsx index ec96ab5558c2..593f865c68f4 100644 --- a/shared/signup/routes.tsx +++ b/shared/signup/routes.tsx @@ -15,7 +15,11 @@ const EmailSkipButton = () => { type="BodyBigLink" onClick={() => { setSignupEmail(C.noEmail) - showPushPrompt ? navigateAppend({name: 'settingsPushPrompt', params: {}}, true) : clearModals() + if (showPushPrompt) { + navigateAppend({name: 'settingsPushPrompt', params: {}}, true) + } else { + clearModals() + } }} > Skip diff --git a/shared/stores/chat.tsx b/shared/stores/chat.tsx index 946919622f07..d42d7a1668fc 100644 --- a/shared/stores/chat.tsx +++ b/shared/stores/chat.tsx @@ -248,7 +248,7 @@ export const useChatState = Z.createZustand('chat', (set, get) => { s.inboxRetriedOnCurrentEmpty = false } } catch (e) { - logger.info('failed to JSON parse inbox layout: ' + e) + logger.info('failed to JSON parse inbox layout: ' + String(e)) } }) }, diff --git a/shared/stores/config.tsx b/shared/stores/config.tsx index d33b5c0b179a..f085f8b2e5ea 100644 --- a/shared/stores/config.tsx +++ b/shared/stores/config.tsx @@ -174,7 +174,9 @@ export const useConfigState = Z.createZustand('config', (set, get) => { const items = state.items || [] const goodState = items.reduce>( (arr, {md, item}) => { - md && item && arr.push({item, md}) + if (md && item) { + arr.push({item, md}) + } return arr }, [] diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index 1315f345481f..9431aef6d926 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -858,7 +858,7 @@ export const syncGregorExplodingModes = ( ) getConvoState(conversationIDKey).dispatch.setExplodingMode(seconds, true) } catch (error) { - logger.info('Error parsing exploding' + error) + logger.info('Error parsing exploding' + String(error)) } }) } @@ -2926,8 +2926,9 @@ const createSlice = } }) } catch (err) { - logger.error('Failed to save attachment: ' + err) - throw new Error('Failed to save attachment: ' + err, {cause: err}) + const errString = String(err) + logger.error('Failed to save attachment: ' + errString) + throw new Error('Failed to save attachment: ' + errString, {cause: err}) } } ignorePromise(f()) diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index 37a4d1d006cf..24810891d81e 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -3,6 +3,7 @@ import {ignorePromise, timeoutPromise} from '@/constants/utils' import * as T from '@/constants/types' import * as Z from '@/util/zustand' import {NotifyPopup} from '@/util/misc' +import {ensureError} from '@/util/errors' import logger from '@/logger' import {isMobile} from '@/constants/platform' import isObject from 'lodash/isObject' @@ -108,7 +109,7 @@ export const errorToActionOrThrowWithHandlers = ( redbar('A user in this shared folder has deleted their account.') return } - throw error + throw ensureError(error) } export const errorToActionOrThrow = (error: unknown, path?: T.FS.Path) => { @@ -223,7 +224,9 @@ export const useFSState = Z.createZustand('fs', (set, get) => { const unsubscribeAll = () => { const subscriptionIDs = [settingsSub.id, uploadStatusSub.id, journalStatusSub.id] subscriptionIDs.forEach(subscriptionID => { - subscriptionID && unsubscribe(subscriptionID) + if (subscriptionID) { + unsubscribe(subscriptionID) + } }) clearSubscriptions() } diff --git a/shared/stores/router.tsx b/shared/stores/router.tsx index 3831820c845c..ab421dbef069 100644 --- a/shared/stores/router.tsx +++ b/shared/stores/router.tsx @@ -29,7 +29,9 @@ export const useRouterState = Z.createZustand('router', (set, get) => { }, setNavState: next => { const DEBUG_NAV = __DEV__ && (false as boolean) - DEBUG_NAV && console.log('[Nav] setNavState') + if (DEBUG_NAV) { + console.log('[Nav] setNavState') + } const prev = get().navState as Util.NavState if (prev === next) return set(s => { diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index 9351c021d4d2..62987b4fc3ce 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -158,7 +158,9 @@ const apiSearch = async ( ) return (results || []).reduce>((arr, r) => { const u = parseRawResultToUser(r, service) - u && arr.push(u) + if (u) { + arr.push(u) + } return arr }, []) } catch (error) { diff --git a/shared/styles/index.native.tsx b/shared/styles/index.native.tsx index bcb43f364735..0bc3cfcf747b 100644 --- a/shared/styles/index.native.tsx +++ b/shared/styles/index.native.tsx @@ -57,7 +57,7 @@ export const styleSheetCreate = (f: () => MapToStyles): unknown => export const collapseStyles = ( styles: ReadonlyArray -): undefined | unknown | ReadonlyArray => { +): undefined | object | ReadonlyArray => { // if we have no / singular values we pass those on in the hopes they're consts const nonNull = styles.filter(s => { if (!s) { diff --git a/shared/team-building/recs-and-recos.tsx b/shared/team-building/recs-and-recos.tsx index e98ea6118730..0b1c1ba1ab78 100644 --- a/shared/team-building/recs-and-recos.tsx +++ b/shared/team-building/recs-and-recos.tsx @@ -104,12 +104,13 @@ export const RecsAndRecos = (props: RecsAndRecosProps) => { const highlightDetails = listIndexToSectionAndLocalIndex(highlightedIndex, recommendations) React.useEffect(() => { - highlightedIndex >= 0 && + if (highlightedIndex >= 0) { sectionListRef.current?.scrollToLocation({ itemIndex: highlightedIndex, sectionIndex: 0, viewPosition: 0, }) + } }, [highlightedIndex]) return ( diff --git a/shared/team-building/search-result/people-result.tsx b/shared/team-building/search-result/people-result.tsx index 5df7215a2799..d1c86af89e5e 100644 --- a/shared/team-building/search-result/people-result.tsx +++ b/shared/team-building/search-result/people-result.tsx @@ -24,7 +24,9 @@ const PeopleResult = function PeopleResult(props: ResultProps) { const navigateAppend = C.Router2.navigateAppend const onMenuAddToTeam = () => { - keybaseUsername && navigateAppend({name: 'profileAddToTeam', params: {username: keybaseUsername}}) + if (keybaseUsername) { + navigateAppend({name: 'profileAddToTeam', params: {username: keybaseUsername}}) + } } const navigateUp = C.Router2.navigateUp @@ -41,7 +43,9 @@ const PeopleResult = function PeopleResult(props: ResultProps) { } const onManageBlocking = () => { - keybaseUsername && navigateAppend({name: 'chatBlockingModal', params: {username: keybaseUsername}}) + if (keybaseUsername) { + navigateAppend({name: 'chatBlockingModal', params: {username: keybaseUsername}}) + } } const previewConversation = C.Router2.previewConversation diff --git a/shared/teams/add-members-wizard/add-contacts.native.tsx b/shared/teams/add-members-wizard/add-contacts.native.tsx index fabf3ec83061..097cc6b7807b 100644 --- a/shared/teams/add-members-wizard/add-contacts.native.tsx +++ b/shared/teams/add-members-wizard/add-contacts.native.tsx @@ -21,10 +21,18 @@ const AddContacts = ({wizard}: {wizard: AddMembersWizard}) => { const onSelectContact = (contact: Contact, checked: boolean) => { if (contact.type === 'phone') { - checked ? selectedPhones.add(contact.value) : selectedPhones.delete(contact.value) + if (checked) { + selectedPhones.add(contact.value) + } else { + selectedPhones.delete(contact.value) + } setSelectedPhones(new Set(selectedPhones)) } else { - checked ? selectedEmails.add(contact.value) : selectedEmails.delete(contact.value) + if (checked) { + selectedEmails.add(contact.value) + } else { + selectedEmails.delete(contact.value) + } setSelectedEmails(new Set(selectedEmails)) } } diff --git a/shared/teams/channel/rows.tsx b/shared/teams/channel/rows.tsx index 2fd60af73210..8a4accd9612a 100644 --- a/shared/teams/channel/rows.tsx +++ b/shared/teams/channel/rows.tsx @@ -95,13 +95,15 @@ const ChannelMemberRow = (props: Props) => { } const previewConversation = C.Router2.previewConversation const onChat = () => { - username && previewConversation({participants: [username], reason: 'teamMember'}) + if (username) { + previewConversation({participants: [username], reason: 'teamMember'}) + } } const navigateAppend = C.Router2.navigateAppend const onEditMember = () => { - yourOperations.manageMembers && - username && + if (yourOperations.manageMembers && username) { navigateAppend({name: 'teamMember', params: {teamID, username}}) + } } const checkCircle = ( { params: {conversationIDKey, members: [username], teamID}, }) const onBlock = () => { - username && + if (username) { setUserBlocks( [ { @@ -165,6 +167,7 @@ const ChannelMemberRow = (props: Props) => { () => {}, () => {} ) + } } const menuItems: Kb.MenuItems = [ diff --git a/shared/teams/common/channel-hooks.tsx b/shared/teams/common/channel-hooks.tsx index 4b2a8d72196a..ae8855d3322a 100644 --- a/shared/teams/common/channel-hooks.tsx +++ b/shared/teams/common/channel-hooks.tsx @@ -4,6 +4,7 @@ import * as Chat from '@/stores/chat' import * as ConvoState from '@/stores/convostate' import * as React from 'react' import logger from '@/logger' +import {ensureError} from '@/util/errors' import {useEngineActionListener} from '@/engine/action-listener' import {useLoadedTeam} from '../team/use-loaded-team' import {createCachedResourceCache, type CachedResourceCache, useCachedResource} from '../use-cached-resource' @@ -82,7 +83,7 @@ export const useAllChannelMetas = ( }, new Array<[string, T.Chat.ConversationMeta]>()) ), }), - error => reject(error) + error => reject(ensureError(error)) ) }), onError: error => { diff --git a/shared/teams/common/use-autocompleter.tsx b/shared/teams/common/use-autocompleter.tsx index 37747d8d35ba..a6930da4c844 100644 --- a/shared/teams/common/use-autocompleter.tsx +++ b/shared/teams/common/use-autocompleter.tsx @@ -74,7 +74,9 @@ function useAutocompleter( break case 'Enter': setSelected(0) - selectedItem?.value && onSelect(selectedItem.value) + if (selectedItem?.value) { + onSelect(selectedItem.value) + } return } let newSelected = selected + diff diff --git a/shared/teams/emojis/add-alias.tsx b/shared/teams/emojis/add-alias.tsx index 38718a7b17f9..a3f7d797afd6 100644 --- a/shared/teams/emojis/add-alias.tsx +++ b/shared/teams/emojis/add-alias.tsx @@ -13,6 +13,7 @@ import { import {AliasInput, Modal, type AliasRef} from './common' import {useEmojiState} from './use-emoji' import {usePickerState} from '@/chat/emoji-picker/use-picker' +import {ensureError} from '@/util/errors' type Props = {defaultSelected?: EmojiData} @@ -106,7 +107,7 @@ const AddAliasModal = (props: Props) => { refreshEmoji() }, err => { - throw err + throw ensureError(err) } ) } diff --git a/shared/teams/emojis/add-emoji.tsx b/shared/teams/emojis/add-emoji.tsx index e182f148a23f..7e1449fff996 100644 --- a/shared/teams/emojis/add-emoji.tsx +++ b/shared/teams/emojis/add-emoji.tsx @@ -10,6 +10,7 @@ import {useEmojiState} from './use-emoji' import {HeaderLeftButton} from '@/common-adapters/header-buttons' import {useNavigation} from '@react-navigation/native' import KB2 from '@/util/electron' +import {ensureError} from '@/util/errors' const {getPathForFile} = KB2.functions @@ -66,7 +67,9 @@ const useDoAddEmojis = ( removeFilePath(new Set(res.successFilenames)) } const failedFilenamesKeys = Object.keys(res.failedFilenames ?? {}) - !failedFilenamesKeys.length && clearModals() + if (!failedFilenamesKeys.length) { + clearModals() + } setErrors( new Map(failedFilenamesKeys.map(key => [key, res.failedFilenames?.[key]?.uidisplay ?? ''])) ) @@ -74,7 +77,7 @@ const useDoAddEmojis = ( setWaitingAddEmojis(false) }, err => { - throw err + throw ensureError(err) } ) } @@ -227,7 +230,9 @@ const usePickFiles = (addFiles: (filePaths: Array) => void) => { .filter(file => file.type.startsWith('image/')) .map(file => getPathForFile?.(file) ?? '') .filter(Boolean) - filesToAdd.length && addFiles(filesToAdd) + if (filesToAdd.length) { + addFiles(filesToAdd) + } setDragOver(false) } const pick = () => { diff --git a/shared/teams/new-team/wizard/add-subteam-members.tsx b/shared/teams/new-team/wizard/add-subteam-members.tsx index 7afba0017843..f943e5463a30 100644 --- a/shared/teams/new-team/wizard/add-subteam-members.tsx +++ b/shared/teams/new-team/wizard/add-subteam-members.tsx @@ -66,7 +66,11 @@ const AddSubteamMembers = ({wizard: wizardState}: Props) => { const selected = selectedMembers.has(m.username) const onSelect = () => { // TODO: ensure performance (see Y2K-1666) - !selected ? selectedMembers.add(m.username) : selectedMembers.delete(m.username) + if (!selected) { + selectedMembers.add(m.username) + } else { + selectedMembers.delete(m.username) + } setSelectedMembers(new Set([...selectedMembers])) } diff --git a/shared/teams/team/member/index.new.tsx b/shared/teams/team/member/index.new.tsx index 1f3c8048fa77..266df8e39b32 100644 --- a/shared/teams/team/member/index.new.tsx +++ b/shared/teams/team/member/index.new.tsx @@ -103,6 +103,7 @@ const useTeamTreeMemberships = (targetTeamID: T.Teams.TeamID, username: string) }) return {...prev, lastActivity: nextLastActivity} }) + return undefined }) .catch(error => { logger.info(`loadTeamTreeActivity: unable to get activity for ${teamID}:${username}`, error) @@ -357,8 +358,8 @@ const TeamMember = (props: OwnProps) => { } let failedAtStr: string if (failedAt.length > 1) { - const last = failedAt.pop() - failedAtStr = failedAt.join(', ') + ', and ' + last + const last = failedAt.pop() ?? '' + failedAtStr = `${failedAt.join(', ')}, and ${last}` } else { failedAtStr = failedAt[0] ?? '' } diff --git a/shared/teams/team/rows/emoji-row/item.tsx b/shared/teams/team/rows/emoji-row/item.tsx index 6403029cdd66..3bf4f9d3d6d7 100644 --- a/shared/teams/team/rows/emoji-row/item.tsx +++ b/shared/teams/team/rows/emoji-row/item.tsx @@ -8,6 +8,7 @@ import {useEmojiState} from '@/teams/emojis/use-emoji' import {useLoadedTeam} from '@/teams/team/use-loaded-team' import {useSafeNavigation} from '@/util/safe-navigation' import {useCurrentUserState} from '@/stores/current-user' +import {ensureError} from '@/util/errors' type OwnProps = { conversationIDKey: T.Chat.ConversationIDKey @@ -46,7 +47,7 @@ const ItemRow = ({conversationIDKey, emoji, firstItem, teamID}: OwnProps) => { ], () => refreshEmoji(), err => { - throw err + throw ensureError(err) } ) } diff --git a/shared/teams/team/rows/invite-row/request.tsx b/shared/teams/team/rows/invite-row/request.tsx index d44275ff51c4..e030454a9e2c 100644 --- a/shared/teams/team/rows/invite-row/request.tsx +++ b/shared/teams/team/rows/invite-row/request.tsx @@ -281,7 +281,9 @@ const Container = (ownProps: OwnProps) => { } const previewConversation = C.Router2.previewConversation const onChat = () => { - username && previewConversation({participants: [username], reason: 'teamInvite'}) + if (username) { + previewConversation({participants: [username], reason: 'teamInvite'}) + } } const onOpenProfile = () => { navToProfile(username) diff --git a/shared/teams/team/rows/member-row.tsx b/shared/teams/team/rows/member-row.tsx index 0236f43b7b71..2741e50ddd07 100644 --- a/shared/teams/team/rows/member-row.tsx +++ b/shared/teams/team/rows/member-row.tsx @@ -310,23 +310,28 @@ const Container = (ownProps: OwnProps) => { const waitingForRemove = C.Waiting.useAnyWaiting(C.waitingKeyTeamsRemoveMember(teamID, username)) const setUserBlocks = C.useRPC(T.RPCGen.userSetUserBlocksRpcPromise) const onBlock = () => { - username && + if (username) { setUserBlocks( [{blocks: [{setChatBlock: true, setFollowBlock: true, username}]}, C.waitingKeyUsersSetUserBlocks], () => {}, () => {} ) + } } const previewConversation = C.Router2.previewConversation const onChat = () => { - username && previewConversation({participants: [username], reason: 'teamMember'}) + if (username) { + previewConversation({participants: [username], reason: 'teamMember'}) + } } const navigateAppend = C.Router2.navigateAppend const onClick = () => { navigateAppend({name: 'teamMember', params: {teamID, username}}) } const onOpenProfile = () => { - username && navToProfile(username) + if (username) { + navToProfile(username) + } } const onReAddToTeam = () => { reAddToTeam(teamID, username) diff --git a/shared/teams/team/settings-tab/retention/index.tsx b/shared/teams/team/settings-tab/retention/index.tsx index ed3230104ada..567576c7bd2b 100644 --- a/shared/teams/team/settings-tab/retention/index.tsx +++ b/shared/teams/team/settings-tab/retention/index.tsx @@ -512,8 +512,7 @@ const Container = (ownProps: OwnProps) => { let loading = false let teamPolicy: T.Retention.RetentionPolicy | undefined - if (_cid) { - } else if (!entityType.endsWith('team')) { + if (!_cid && !entityType.endsWith('team')) { throw new Error(`RetentionPicker needs a conversationIDKey to set ${entityType} retention policies`) } const conversationIDKey = _cid ?? Chat.noConversationIDKey diff --git a/shared/teams/team/team-info.tsx b/shared/teams/team/team-info.tsx index ce027aa1f110..b2f179712c56 100644 --- a/shared/teams/team/team-info.tsx +++ b/shared/teams/team/team-info.tsx @@ -55,7 +55,7 @@ const TeamInfo = (props: Props) => { renameTeamRPC( [ { - newName: {parts: (parentTeamNameWithDot + newName).split('.')}, + newName: {parts: (String(parentTeamNameWithDot) + newName).split('.')}, prevName: {parts: teamname.split('.')}, }, C.waitingKeyTeamsRename, diff --git a/shared/teams/use-teams-list.tsx b/shared/teams/use-teams-list.tsx index a099e91fcc3c..8e396ee4c4a7 100644 --- a/shared/teams/use-teams-list.tsx +++ b/shared/teams/use-teams-list.tsx @@ -3,6 +3,7 @@ import logger from '@/logger' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import * as Teams from '@/constants/teams' +import {ensureError} from '@/util/errors' import {useEngineActionListener} from '@/engine/action-listener' import * as React from 'react' import * as T from '@/constants/types' @@ -28,6 +29,7 @@ const emptyTeamRoleMap = Object.freeze({teams: u const TeamsListContext = React.createContext(null) const TeamsRoleMapContext = React.createContext(null) const teamsListReloadStaleMs = 5 * 60_000 + const teamsListInvalidationListeners = new Set<() => void>() const teamsRoleMapInvalidationListeners = new Set<() => void>() const teamsListCache = createCachedResourceCache, string | undefined>( @@ -73,7 +75,7 @@ const useTeamsListRaw = (enabled = true): TeamsList => { loadTeamsRPC( [{includeImplicitTeams: false, userAssertion: username}, C.waitingKeyTeamsLoaded], result => resolve(teamListToArray(result.teams ?? [])), - error => reject(error) + error => reject(ensureError(error)) ) }), onError: error => { @@ -144,7 +146,7 @@ const useTeamsRoleMapRaw = (enabled = true): TeamsRoleMap => { loadRoleMapRPC( [undefined], result => resolve(result), - error => reject(error) + error => reject(ensureError(error)) ) }), onError: error => { diff --git a/shared/test/mocks/file.js b/shared/test/mocks/file.js index 681feb4f02f8..40483e699863 100644 --- a/shared/test/mocks/file.js +++ b/shared/test/mocks/file.js @@ -1 +1,2 @@ +/* global module */ module.exports = 'test-file' diff --git a/shared/test/mocks/logger.js b/shared/test/mocks/logger.js index d6f5f220929a..ee679cd97df7 100644 --- a/shared/test/mocks/logger.js +++ b/shared/test/mocks/logger.js @@ -1,3 +1,4 @@ +/* global console, module */ const bind = fn => (...args) => fn(...args) const logger = { diff --git a/shared/test/mocks/react-native.js b/shared/test/mocks/react-native.js index 159354498941..d79c5df83846 100644 --- a/shared/test/mocks/react-native.js +++ b/shared/test/mocks/react-native.js @@ -1,3 +1,4 @@ +/* global exports */ exports.Dimensions = { get: () => ({fontScale: 1, height: 900, scale: 1, width: 1440}), } diff --git a/shared/test/mocks/react-navigation-core.js b/shared/test/mocks/react-navigation-core.js index 02e9c3b9cfd2..fc357479a8df 100644 --- a/shared/test/mocks/react-navigation-core.js +++ b/shared/test/mocks/react-navigation-core.js @@ -1,3 +1,4 @@ +/* global exports, require */ /* eslint-disable react/prop-types */ const React = require('react') diff --git a/shared/test/mocks/style.js b/shared/test/mocks/style.js index 4ba52ba2c8df..0da662c33c8d 100644 --- a/shared/test/mocks/style.js +++ b/shared/test/mocks/style.js @@ -1 +1,2 @@ +/* global module */ module.exports = {} diff --git a/shared/tracker/remote-proxy.desktop.tsx b/shared/tracker/remote-proxy.desktop.tsx index 8d3a6ac1ced9..93c28fe4317c 100644 --- a/shared/tracker/remote-proxy.desktop.tsx +++ b/shared/tracker/remote-proxy.desktop.tsx @@ -128,7 +128,9 @@ const RemoteTrackers = () => { setPopupState(prev => { const showTrackerSet = new Set(prev.showTrackerSet) const usernameToDetails = new Map(prev.usernameToDetails) - forceDisplay && showTrackerSet.add(assertion) + if (forceDisplay) { + showTrackerSet.add(assertion) + } const details = cloneDetails(usernameToDetails.get(assertion) ?? makeDetails(assertion)) usernameToDetails.set(assertion, { ...details, diff --git a/shared/tracker/use-profile.tsx b/shared/tracker/use-profile.tsx index 44405bc38352..2e3deed93b7c 100644 --- a/shared/tracker/use-profile.tsx +++ b/shared/tracker/use-profile.tsx @@ -200,7 +200,9 @@ export const useTrackerProfile = (username: string, options?: Options) => { ) React.useEffect(() => { - username && loadProfile() + if (username) { + loadProfile() + } }, [loadProfile, username]) C.Router2.useSafeFocusEffect( diff --git a/shared/util/errors.tsx b/shared/util/errors.tsx index c6bd77a36344..2f519fe53e81 100644 --- a/shared/util/errors.tsx +++ b/shared/util/errors.tsx @@ -32,6 +32,31 @@ export function convertToError(err: unknown, method?: string): Error | RPCError } } +const errorMessage = (error: unknown) => { + if (error && typeof error === 'object') { + const message = (error as {message?: unknown}).message + if (typeof message === 'string') { + return message + } + const desc = (error as {desc?: unknown}).desc + if (typeof desc === 'string') { + return desc + } + } + return String(error) +} + +export function ensureError(error: unknown): Error { + if (error instanceof Error) { + return error + } + const nativeError = new Error(errorMessage(error), {cause: error}) + if (error && typeof error === 'object') { + Object.assign(nativeError, error) + } + return nativeError +} + type RPCErrorLike = { code: number desc: string diff --git a/shared/util/platform-specific/index.native.tsx b/shared/util/platform-specific/index.native.tsx index 94601a8f854e..3c4c83fac6e6 100644 --- a/shared/util/platform-specific/index.native.tsx +++ b/shared/util/platform-specific/index.native.tsx @@ -65,7 +65,7 @@ export async function saveAttachmentToCameraRoll(filePath: string, mimeType: str body: `Failed to save ${saveType} to camera roll`, id: Math.floor(Math.random() * 2 ** 32).toString(), }).catch(() => {}) - logger.debug(logPrefix + 'failed to save: ' + e) + logger.debug(logPrefix + 'failed to save: ' + String(e)) throw e } finally { try { diff --git a/shared/util/platform-specific/input-monitor.desktop.tsx b/shared/util/platform-specific/input-monitor.desktop.tsx index 94c43764d81a..25d217515908 100644 --- a/shared/util/platform-specific/input-monitor.desktop.tsx +++ b/shared/util/platform-specific/input-monitor.desktop.tsx @@ -62,16 +62,22 @@ class InputMonitor { break case 'appActive': this.notifyActive?.(true) - DEBUG_LOG && console.log('InputMonitor: 5 minute timeout') + if (DEBUG_LOG) { + console.log('InputMonitor: 5 minute timeout') + } this.timeoutID = setTimeout(() => this.transition('timeout'), timeToConsiderActiveForAwhile) break case 'afterActiveCheck': this.listenForMouseKeyboard() - DEBUG_LOG && console.log('InputMonitor: 1 minute timeout') + if (DEBUG_LOG) { + console.log('InputMonitor: 1 minute timeout') + } this.timeoutID = setTimeout(() => this.transition('timeout'), timeToConsiderInactive) break case 'appInactive': - DEBUG_LOG && console.log('InputMonitor: Inactive') + if (DEBUG_LOG) { + console.log('InputMonitor: Inactive') + } this.listenForMouseKeyboard() this.notifyActive?.(false) break @@ -80,9 +86,13 @@ class InputMonitor { private clearTimers = () => { // always kill timers - this.timeoutID && clearTimeout(this.timeoutID) + if (this.timeoutID) { + clearTimeout(this.timeoutID) + } this.timeoutID = undefined - DEBUG_LOG && console.log('InputMonitor: Timer cleared') + if (DEBUG_LOG) { + console.log('InputMonitor: Timer cleared') + } } private listenerOptions = { @@ -92,13 +102,17 @@ class InputMonitor { private listenForMouseKeyboard = () => { this.unlistenForMouseKeyboard() - DEBUG_LOG && console.log('InputMonitor: adding mouseKeyboard events') + if (DEBUG_LOG) { + console.log('InputMonitor: adding mouseKeyboard events') + } window.addEventListener('mousemove', this.onMouseKeyboard, this.listenerOptions) window.addEventListener('keypress', this.onMouseKeyboard, this.listenerOptions) } private unlistenForMouseKeyboard = () => { - DEBUG_LOG && console.log('InputMonitor: removing mouseKeyboard events') + if (DEBUG_LOG) { + console.log('InputMonitor: removing mouseKeyboard events') + } window.removeEventListener('mousemove', this.onMouseKeyboard, this.listenerOptions) window.removeEventListener('keypress', this.onMouseKeyboard, this.listenerOptions) } @@ -107,7 +121,9 @@ class InputMonitor { this.clearTimers() const nextState = this.nextState(reason) - DEBUG_LOG && console.log('InputMonitor: transition', this.state, nextState) + if (DEBUG_LOG) { + console.log('InputMonitor: transition', this.state, nextState) + } if (nextState === this.state) return this.exitState(this.state) this.enterState(nextState) diff --git a/shared/util/safe-submit.tsx b/shared/util/safe-submit.tsx index a6f0c8a41e89..cb002d063f06 100644 --- a/shared/util/safe-submit.tsx +++ b/shared/util/safe-submit.tsx @@ -13,7 +13,6 @@ export function useSafeSubmit) => void>(f: F, should if (safeToCallRef.current) { safeToCallRef.current = false f(...args) - } else { } } diff --git a/shared/util/uint8array.tsx b/shared/util/uint8array.tsx index ed8f5d15770e..beb815ec6c67 100644 --- a/shared/util/uint8array.tsx +++ b/shared/util/uint8array.tsx @@ -66,7 +66,7 @@ export const uint8ArrayToHex = (array: Uint8Array): string => { let hexString = '' // eslint-disable-next-line @typescript-eslint/prefer-for-of -- Keep the indexed loop for parity with the upstream hot path. for (let index = 0; index < array.length; index++) { - hexString += byteToHexLookupTable[array[index]!] + hexString += byteToHexLookupTable[array[index]!]! } return hexString diff --git a/shared/util/use-intersection-observer.desktop.tsx b/shared/util/use-intersection-observer.desktop.tsx index baaf4a57d61e..109bd8056dc1 100644 --- a/shared/util/use-intersection-observer.desktop.tsx +++ b/shared/util/use-intersection-observer.desktop.tsx @@ -47,9 +47,10 @@ function useIntersectionObserver( // eslint-disable-next-line for (let i = 0; i < entries.length; i++) { const entry = entries[i] - // @ts-ignore + if (!entry) { + continue + } if (entry.target === targetEl) { - // @ts-ignore setEntry(entry) } } @@ -81,10 +82,11 @@ function createIntersectionObserver({ for (const callback of callbacks) callback(entries, observer) }, {root, rootMargin, threshold} - ) - // @ts-ignore + ) as IntersectionObserver & { + POLL_INTERVAL?: number | null + USE_MUTATION_OBSERVER?: boolean + } observer.POLL_INTERVAL = pollInterval - // @ts-ignore observer.USE_MUTATION_OBSERVER = useMutationObserver return { diff --git a/shared/util/use-resize-observer.desktop.tsx b/shared/util/use-resize-observer.desktop.tsx index 505639dd9022..1b51601b5df8 100644 --- a/shared/util/use-resize-observer.desktop.tsx +++ b/shared/util/use-resize-observer.desktop.tsx @@ -45,14 +45,15 @@ function createResizeObserver() { const triggered = new Set() // eslint-disable-next-line for (let i = 0; i < allEntries.length; i++) { - // @ts-ignore - if (triggered.has(allEntries[i].target)) continue - // @ts-ignore - triggered.add(allEntries[i].target) - // @ts-ignore - const cbs = callbacks.get(allEntries[i].target) + const entry = allEntries[i] + if (!entry) { + continue + } + if (triggered.has(entry.target)) continue + triggered.add(entry.target) + const cbs = callbacks.get(entry.target) // eslint-disable-next-line - cbs?.forEach(cb => cb(allEntries[i]!, obs)) + cbs?.forEach(cb => cb(entry, obs)) } allEntries = [] ticking = false diff --git a/shared/util/why-did-you-render-enabled.js b/shared/util/why-did-you-render-enabled.js index f6b439dd6e46..a32b89a35ecd 100644 --- a/shared/util/why-did-you-render-enabled.js +++ b/shared/util/why-did-you-render-enabled.js @@ -1 +1,2 @@ +/* global module */ module.exports = false From cf4eea9488a273d018d080f13f35abe2f1402f9e Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Sun, 26 Apr 2026 10:55:44 -0400 Subject: [PATCH 3/8] WIP --- .../conversation/attachment-get-titles.tsx | 10 +--------- shared/chat/conversation/command-status.tsx | 18 ++++-------------- shared/fs/common/hooks.tsx | 14 ++++++++------ shared/styles/index.native.tsx | 2 +- 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/shared/chat/conversation/attachment-get-titles.tsx b/shared/chat/conversation/attachment-get-titles.tsx index 66cdee73ede1..78bf23091de3 100644 --- a/shared/chat/conversation/attachment-get-titles.tsx +++ b/shared/chat/conversation/attachment-get-titles.tsx @@ -87,7 +87,7 @@ const Container = (ownProps: OwnProps) => { const [index, setIndex] = React.useState(0) const [titles, setTitles] = React.useState(pathAndInfos.map((_, idx) => _titles?.[idx] ?? '')) - const [spoiler, setSpoiler] = React.useState(false) + const spoiler = false const onNext = (e?: React.BaseSyntheticEvent) => { e?.preventDefault() @@ -205,14 +205,6 @@ const Container = (ownProps: OwnProps) => { containerStyle={styles.inputBare} inputStyle={styles.input} /> - {/* ( - - )*/} diff --git a/shared/chat/conversation/command-status.tsx b/shared/chat/conversation/command-status.tsx index bc0b92e2a863..2c1467a7fbe5 100644 --- a/shared/chat/conversation/command-status.tsx +++ b/shared/chat/conversation/command-status.tsx @@ -18,20 +18,10 @@ const Container = () => { setCommandStatusInfo() } const props = { - actions: _info.actions.map(a => { - switch (a) { - case T.RPCChat.UICommandStatusActionTyp.appsettings: - return { - displayText: 'View App Settings', - onClick: openAppSettings, - } - default: - return { - displayText: '???', - onClick: () => {}, - } - } - }), + actions: _info.actions.map(() => ({ + displayText: 'View App Settings', + onClick: openAppSettings, + })), displayText: _info.displayText, displayType: _info.displayType, onCancel, diff --git a/shared/fs/common/hooks.tsx b/shared/fs/common/hooks.tsx index 943123c2d37a..16ffcc9c9f12 100644 --- a/shared/fs/common/hooks.tsx +++ b/shared/fs/common/hooks.tsx @@ -842,15 +842,17 @@ export const useFsTlf = (path: T.FS.Path, options?: {loadOnMount?: boolean}) => const tlfs = useFsTlfs() const tlf = FS.getTlfFromPath(tlfs, path) const loadAdditionalTlf = routeData?.loadAdditionalTlf - const active = - !!loadAdditionalTlf && - !!tlfPath && + const tlfPathToLoad = + tlfPath && tlfs.loaded && FS.getTlfFromPathInFavoritesOnly(tlfs, tlfPath) === FS.unknownTlf && options?.loadOnMount !== false + ? tlfPath + : undefined + const active = !!loadAdditionalTlf && !!tlfPathToLoad const loadCurrentTlf = React.useEffectEvent(() => { - if (active && loadAdditionalTlf && tlfPath) { - loadAdditionalTlf(tlfPath) + if (loadAdditionalTlf && tlfPathToLoad) { + loadAdditionalTlf(tlfPathToLoad) } }) const [stableLoadCurrentTlf] = React.useState(() => () => { @@ -864,7 +866,7 @@ export const useFsTlf = (path: T.FS.Path, options?: {loadOnMount?: boolean}) => ) React.useEffect(() => { loadCurrentTlf() - }, [active, loadAdditionalTlf, tlfPath, tlfs.loaded]) + }, [active, loadAdditionalTlf, tlfPathToLoad]) C.Router2.useSafeFocusEffect(stableLoadCurrentTlf) return tlf } diff --git a/shared/styles/index.native.tsx b/shared/styles/index.native.tsx index 0bc3cfcf747b..8893815c5df4 100644 --- a/shared/styles/index.native.tsx +++ b/shared/styles/index.native.tsx @@ -74,7 +74,7 @@ export const collapseStyles = ( } if (nonNull.length === 1) { const s = nonNull[0] - if (typeof s === 'object') { + if (s && typeof s === 'object') { return s } } From db31cde940d6a5c7fbb5e83af494a71954efcc57 Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Sun, 26 Apr 2026 10:56:31 -0400 Subject: [PATCH 4/8] WIP --- shared/tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 2e12ded21b16..5d197d8e8769 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -11,9 +11,11 @@ "lib": ["ESNext", "dom"], "module": "preserve", "moduleResolution": "bundler", + "exactOptionalPropertyTypes": true, "noEmit": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, + "noImplicitOverride": true, "noImplicitReturns": true, "noImplicitThis": true, "noPropertyAccessFromIndexSignature": true, From 4718d75a0b94fe2e82d5ea82b7bd879a90b33201 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Sun, 26 Apr 2026 14:36:32 -0400 Subject: [PATCH 5/8] WIP --- shared/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 5d197d8e8769..48140b19d857 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -11,7 +11,7 @@ "lib": ["ESNext", "dom"], "module": "preserve", "moduleResolution": "bundler", - "exactOptionalPropertyTypes": true, + "exactOptionalPropertyTypes": false, "noEmit": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, From c3c40931219aa9be01ec1b5ccd15c25d9169d5de Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Sun, 26 Apr 2026 14:38:08 -0400 Subject: [PATCH 6/8] WIP --- shared/common-adapters/error-boundary.tsx | 6 +++--- shared/engine/index.platform.desktop.tsx | 8 ++++---- shared/engine/rpc-transport.test.ts | 2 +- shared/engine/transport-shared.tsx | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/shared/common-adapters/error-boundary.tsx b/shared/common-adapters/error-boundary.tsx index 4e283d323012..258ff7557280 100644 --- a/shared/common-adapters/error-boundary.tsx +++ b/shared/common-adapters/error-boundary.tsx @@ -23,13 +23,13 @@ type BareState = { } export class BareErrorBoundary extends React.Component { - state: BareState = {} + override state: BareState = {} static getDerivedStateFromError(error: Error): BareState { return {error} } - componentDidCatch(error: Error, info: React.ErrorInfo) { + override componentDidCatch(error: Error, info: React.ErrorInfo) { this.props.onError?.(error, info) } @@ -37,7 +37,7 @@ export class BareErrorBoundary extends React.Component { this.setState({error: undefined}) } - render(): React.ReactNode { + override render(): React.ReactNode { const {children, fallback, fallbackRender} = this.props const {error} = this.state diff --git a/shared/engine/index.platform.desktop.tsx b/shared/engine/index.platform.desktop.tsx index be32975b396e..b993493cf356 100644 --- a/shared/engine/index.platform.desktop.tsx +++ b/shared/engine/index.platform.desktop.tsx @@ -25,7 +25,7 @@ class NativeTransport extends TransportShared { this.needsConnect = true } - protected isConnected() { + protected override isConnected() { return !!this._socket } @@ -40,7 +40,7 @@ class NativeTransport extends TransportShared { this._socket.write(Buffer.from(framed)) } - connect(cb: (err?: unknown) => void) { + override connect(cb: (err?: unknown) => void) { this.clearExplicitClose() if (this._socket) { cb() @@ -49,14 +49,14 @@ class NativeTransport extends TransportShared { this.connectOnce(cb) } - packetizeData(m: Uint8Array) { + override packetizeData(m: Uint8Array) { if (printRPCBytes) { logger.debug('[RPC] Read', m.length) } mainWindowDispatchEngineIncoming?.(m) } - close() { + override close() { this.markExplicitClose() if (this._reconnectTimer) { clearTimeout(this._reconnectTimer) diff --git a/shared/engine/rpc-transport.test.ts b/shared/engine/rpc-transport.test.ts index 789a24165415..a5f635b0ed5c 100644 --- a/shared/engine/rpc-transport.test.ts +++ b/shared/engine/rpc-transport.test.ts @@ -17,7 +17,7 @@ class TestTransport extends RPCTransport { this._connected = p?.connected ?? true } - protected isConnected() { + protected override isConnected() { return this._connected } diff --git a/shared/engine/transport-shared.tsx b/shared/engine/transport-shared.tsx index c7ac77c752f8..fe736c66162b 100644 --- a/shared/engine/transport-shared.tsx +++ b/shared/engine/transport-shared.tsx @@ -100,7 +100,7 @@ abstract class TransportShared extends RPCTransport { } // add logging / multiple call checking - invoke(method: string, args: [object], cb: (err: unknown, data: unknown) => void) { + override invoke(method: string, args: [object], cb: (err: unknown, data: unknown) => void) { const extra = args[0] if (printRPC) { rpcLog({extra, method, reason: '[+calling]', type: 'engineToServer'}) @@ -131,14 +131,14 @@ abstract class LocalTransport extends TransportShared { super(connectCallback, disconnectCallback, incomingRPCCallback) this.needsConnect = false } - connect(cb: (err?: unknown) => void) { + override connect(cb: (err?: unknown) => void) { cb() } - protected isConnected() { + protected override isConnected() { return true } - reset() {} - close() {} + override reset() {} + override close() {} } function sharedCreateClient(nativeTransport: TransportShared): {invoke: InvokeType; transport: TransportShared} { From 0306040671db62447e58d94a84b59946a8f4e632 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Sun, 26 Apr 2026 14:41:52 -0400 Subject: [PATCH 7/8] WIP --- shared/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 48140b19d857..5d197d8e8769 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -11,7 +11,7 @@ "lib": ["ESNext", "dom"], "module": "preserve", "moduleResolution": "bundler", - "exactOptionalPropertyTypes": false, + "exactOptionalPropertyTypes": true, "noEmit": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, From 3abd5ca6202552dde1d124d8d32f15918656117e Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Sun, 26 Apr 2026 14:51:36 -0400 Subject: [PATCH 8/8] WIP --- shared/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 5d197d8e8769..48140b19d857 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -11,7 +11,7 @@ "lib": ["ESNext", "dom"], "module": "preserve", "moduleResolution": "bundler", - "exactOptionalPropertyTypes": true, + "exactOptionalPropertyTypes": false, "noEmit": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true,