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