Enable ESLint errors and suppress existing violations (#10490)

This commit is contained in:
DS Boyce
2026-06-03 11:27:44 -07:00
committed by GitHub
parent cdad723ea1
commit 84d1785e12
16 changed files with 1879 additions and 68 deletions
+3 -23
View File
@@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
job: [lint, prettier]
job: [lint, prettier, typecheck]
steps:
- name: Check out Git repository
uses: actions/checkout@v5
@@ -62,6 +62,8 @@ jobs:
command: pnpm install --frozen-lockfile
attempt_limit: 3
attempt_delay: 2000
- name: Check & compile i18n
run: pnpm intl:build
- name: Lint checks
run: pnpm ${{ matrix.job }}
# Aggregates the matrix results into a single stable check name so branch
@@ -80,28 +82,6 @@ jobs:
run: |
echo "linting result: $RESULT"
test "$RESULT" = "success"
typechecking:
name: Run typecheck
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v5
- uses: pnpm/action-setup@v6
- name: Install node
uses: actions/setup-node@v6
with:
node-version-file: package.json
cache: pnpm
- name: pnpm install
uses: Wandalen/wretry.action@master
with:
command: pnpm install --frozen-lockfile
attempt_limit: 3
attempt_delay: 2000
- name: Check & compile i18n
run: pnpm intl:build
- name: Type check
run: pnpm typecheck
testing:
name: Run tests
runs-on: ubuntu-latest
+1833 -1
View File
File diff suppressed because it is too large Load Diff
+18 -20
View File
@@ -134,11 +134,10 @@ export default defineConfig(
'react-native/no-inline-styles': 'off',
...reactNativeA11y.configs.all.rules,
'react-compiler/react-compiler': 'warn',
// TODO: Fix these and set to error
'react-hooks/set-state-in-effect': 'warn',
'react-hooks/purity': 'warn',
'react-hooks/refs': 'warn',
'react-hooks/immutability': 'warn',
'react-hooks/set-state-in-effect': 'error',
'react-hooks/purity': 'error',
'react-hooks/refs': 'error',
'react-hooks/immutability': 'error',
/**
* Import sorting
@@ -235,9 +234,8 @@ export default defineConfig(
},
],
/**
* Maintain previous behavior - these are stricter in typescript-eslint
* v8 `warn` ones are probably worth fixing. `off` ones are a bit too
* nit-picky
* Maintain previous behavior via eslint-suppressions.json - these are
* stricter in typescript-eslint v8. `off` ones are a bit too nit-picky.
*/
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/ban-ts-comment': 'off',
@@ -247,18 +245,18 @@ export default defineConfig(
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-misused-promises': 'warn',
'@typescript-eslint/require-await': 'warn',
'@typescript-eslint/no-unsafe-enum-comparison': 'warn',
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
'@typescript-eslint/no-redundant-type-constituents': 'warn',
'@typescript-eslint/no-duplicate-type-constituents': 'warn',
'@typescript-eslint/no-base-to-string': 'warn',
'@typescript-eslint/prefer-promise-reject-errors': 'warn',
'@typescript-eslint/await-thenable': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/prefer-promise-reject-errors': 'error',
'@typescript-eslint/await-thenable': 'error',
'no-restricted-imports': [
'error',
+4 -2
View File
@@ -8,8 +8,10 @@ import {
type UninheritableButtonProps,
} from '#/components/Button'
import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheck} from '#/components/icons/CircleCheck'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo'
import {
CircleInfo_Stroke2_Corner0_Rounded as CircleInfo,
CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon,
} from '#/components/icons/CircleInfo'
import {type Props as SVGIconProps} from '#/components/icons/common'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import {dismiss} from '#/components/Toast/sonner'
+6 -6
View File
@@ -58,12 +58,12 @@ export function dateDiff(
if (diffSeconds < NOW) {
diff = {
value: 0,
unit: 'now' as DateDiff['unit'],
unit: 'now',
}
} else if (diffSeconds < MINUTE) {
diff = {
value: diffSeconds,
unit: 'second' as DateDiff['unit'],
unit: 'second',
}
} else if (diffSeconds < HOUR) {
const value =
@@ -72,7 +72,7 @@ export function dateDiff(
: Math.floor(diffSeconds / MINUTE)
diff = {
value,
unit: 'minute' as DateDiff['unit'],
unit: 'minute',
}
} else if (diffSeconds < DAY) {
const value =
@@ -81,7 +81,7 @@ export function dateDiff(
: Math.floor(diffSeconds / HOUR)
diff = {
value,
unit: 'hour' as DateDiff['unit'],
unit: 'hour',
}
} else if (diffSeconds < MONTH_30) {
const value =
@@ -90,7 +90,7 @@ export function dateDiff(
: Math.floor(diffSeconds / DAY)
diff = {
value,
unit: 'day' as DateDiff['unit'],
unit: 'day',
}
} else {
const value =
@@ -99,7 +99,7 @@ export function dateDiff(
: Math.floor(diffSeconds / MONTH_30)
diff = {
value,
unit: 'month' as DateDiff['unit'],
unit: 'month',
}
}
+2 -2
View File
@@ -19,8 +19,8 @@ export function makeProfileLink(
export function makeCustomFeedLink(
did: string,
rkey: string,
segment?: string | undefined,
feedCacheKey?: 'discover' | 'explore' | undefined,
segment?: string,
feedCacheKey?: 'discover' | 'explore',
) {
return (
[`/profile`, did, 'feed', rkey, ...(segment ? [segment] : [])].join('/') +
@@ -129,7 +129,7 @@ function getAppIconName(icon: string | false): DynamicAppIcon.IconName {
if (!icon || icon === 'DEFAULT') {
return 'default_light'
} else {
return icon as DynamicAppIcon.IconName
return icon
}
}
@@ -151,7 +151,7 @@ function Group({
values={[value]}
maxSelections={1}
onChange={vals => {
if (vals[0]) onChange(vals[0] as DynamicAppIcon.IconName)
if (vals[0]) onChange(vals[0])
}}>
<View style={[a.flex_1, a.rounded_md, a.overflow_hidden]}>
{children}
@@ -23,8 +23,7 @@ import {
import {useEventListener} from 'expo'
import {type VideoPlayer} from 'expo-video'
import {tokens} from '#/alf'
import {atoms as a} from '#/alf'
import {atoms as a, tokens} from '#/alf'
import {formatTime} from '#/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils'
import {Text} from '#/components/Typography'
+1 -1
View File
@@ -298,7 +298,7 @@ export function* findAllPostsInQueryData(
if (AppBskyFeedDefs.isPostView(item.subject)) {
const quotedPost = getEmbeddedPost(item.subject?.embed)
if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
yield embedViewRecordToPostView(quotedPost!)
yield embedViewRecordToPostView(quotedPost)
}
}
}
+1 -1
View File
@@ -34,7 +34,7 @@ export function parseAppNux(nux: AppBskyActorDefs.Nux): AppNux | undefined {
export function serializeAppNux(nux: AppNux): AppBskyActorDefs.Nux {
const {data, ...rest} = nux
const schema = NuxSchemas[nux.id as Nux]
const schema = NuxSchemas[nux.id]
const result: AppBskyActorDefs.Nux = {
...rest,
+1 -1
View File
@@ -85,7 +85,7 @@ export function useSuggestedFollowsByActorWithDismiss({
const profiles = useMemo(() => {
return (data?.suggestions ?? []).map(profile => ({
actor: profile as bsky.profile.AnyProfileView,
actor: profile,
recId: data?.recId,
}))
}, [data?.suggestions, data?.recId])
+1 -1
View File
@@ -196,7 +196,7 @@ export function sortAndAnnotateThreadItems(
* `repliesSeenCounter` later on, since `repliesSeenCounter`
* is 1-indexed and `replyIndex` is 0-indexed.
*/
childMetadata!.replyIndex =
childMetadata.replyIndex =
childParentMetadata.repliesSeenCounter
}
+3 -3
View File
@@ -470,11 +470,11 @@ export async function draftToComposerPosts(
height,
mime: 'image/jpeg',
},
} as ComposerImage
} satisfies ComposerImage
})
const images = (await Promise.all(imagePromises)).filter(
(img): img is ComposerImage => img !== null,
(img): img is NonNullable<typeof img> => img !== null,
)
if (images.length > 0) {
embed.media = {type: 'images', images}
@@ -511,7 +511,7 @@ export async function draftToComposerPosts(
tinygif: mediaObject,
preview: mediaObject,
},
} as Gif,
},
alt: gifData.alt,
}
break
+1 -1
View File
@@ -55,7 +55,7 @@ export function TestCtrls() {
accessibilityLabel="Text input field"
accessibilityHint="Enter proxy header"
testID="e2eProxyHeaderInput"
onChangeText={val => setProxyHeader(val as any)}
onChangeText={val => setProxyHeader(val)}
autoComplete="off"
autoCorrect={false}
autoCapitalize="none"
+1 -1
View File
@@ -3,9 +3,9 @@ import {
Pressable,
type PressableProps,
type StyleProp,
type View,
type ViewStyle,
} from 'react-native'
import {type View} from 'react-native'
import {addStyle} from '#/lib/styles'
import {useInteractionState} from '#/components/hooks/useInteractionState'
@@ -171,7 +171,7 @@ function NativeStackNavigator({
}
// Evicted screens get a lightweight placeholder instead of their full tree
finalDescriptors = {} as typeof descriptors
finalDescriptors = {}
for (const key in descriptors) {
if (mountSet.has(key)) {
finalDescriptors[key] = descriptors[key]