enable typechecked rules, switch them to warn
This commit is contained in:
+34
-9
@@ -1,9 +1,12 @@
|
||||
// @ts-check
|
||||
import js from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import react from 'eslint-plugin-react'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
// @ts-expect-error no types
|
||||
import reactNative from 'eslint-plugin-react-native'
|
||||
// @ts-expect-error no types
|
||||
import reactNativeA11y from 'eslint-plugin-react-native-a11y'
|
||||
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
||||
import importX from 'eslint-plugin-import-x'
|
||||
@@ -11,8 +14,9 @@ import lingui from 'eslint-plugin-lingui'
|
||||
import reactCompiler from 'eslint-plugin-react-compiler'
|
||||
import bskyInternal from 'eslint-plugin-bsky-internal'
|
||||
import globals from 'globals'
|
||||
import tsParser from '@typescript-eslint/parser'
|
||||
|
||||
export default tseslint.config(
|
||||
export default defineConfig(
|
||||
// Global ignores
|
||||
{
|
||||
ignores: [
|
||||
@@ -40,18 +44,25 @@ export default tseslint.config(
|
||||
js.configs.recommended,
|
||||
|
||||
// TypeScript rules
|
||||
...tseslint.configs.recommended,
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
|
||||
// React Hooks rules
|
||||
reactHooks.configs.flat.recommended,
|
||||
|
||||
// Import X
|
||||
// @ts-expect-error https://github.com/un-ts/eslint-plugin-import-x/issues/439
|
||||
importX.flatConfigs.recommended,
|
||||
importX.flatConfigs.typescript,
|
||||
importX.flatConfigs['react-native'],
|
||||
|
||||
// Main configuration for all JS/TS/JSX/TSX files
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
plugins: {
|
||||
react,
|
||||
'react-hooks': reactHooks,
|
||||
'react-native': reactNative,
|
||||
'react-native-a11y': reactNativeA11y,
|
||||
'simple-import-sort': simpleImportSort,
|
||||
'import-x': importX,
|
||||
lingui,
|
||||
'react-compiler': reactCompiler,
|
||||
'bsky-internal': bskyInternal,
|
||||
@@ -65,6 +76,8 @@ export default tseslint.config(
|
||||
...globals.es2021,
|
||||
},
|
||||
parserOptions: {
|
||||
parser: tsParser,
|
||||
projectService: true,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
@@ -83,8 +96,6 @@ export default tseslint.config(
|
||||
'react/no-unescaped-entities': 'off',
|
||||
'react/prop-types': 'off',
|
||||
|
||||
// React Hooks rules
|
||||
...reactHooks.configs.recommended.rules,
|
||||
|
||||
// React Native rules
|
||||
'react-native/no-inline-styles': 'off',
|
||||
@@ -188,13 +199,27 @@ export default tseslint.config(
|
||||
],
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
// Maintain previous behavior - these are stricter in typescript-eslint v8
|
||||
// `warn` ones are probably worth fixing. `off` ones are a bit too nit-picky
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'off',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@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',
|
||||
|
||||
// Import rules
|
||||
'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
"babel-plugin-react-compiler": "^19.1.0-rc.3",
|
||||
"babel-preset-expo": "~54.0.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-bsky-internal": "link:./eslint",
|
||||
"eslint-plugin-import-x": "^4.16.1",
|
||||
"eslint-plugin-lingui": "^0.11.0",
|
||||
|
||||
@@ -80,9 +80,8 @@ export function Outer({
|
||||
)
|
||||
|
||||
const handleBackgroundPress = React.useCallback(
|
||||
async (e: GestureResponderEvent) => {
|
||||
webOptions?.onBackgroundPress ? webOptions.onBackgroundPress(e) : close()
|
||||
},
|
||||
async (e: GestureResponderEvent) =>
|
||||
webOptions?.onBackgroundPress ? webOptions.onBackgroundPress(e) : close(),
|
||||
[webOptions, close],
|
||||
)
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export function Text({
|
||||
if (__DEV__) {
|
||||
if (!emoji && childHasEmoji(children)) {
|
||||
logger.warn(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string
|
||||
`Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add <Text emoji />'`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ function DialogInner({
|
||||
} = useRemoveLiveStatusMutation()
|
||||
|
||||
const {minutesUntilExpiry, expiryDateTime} = useMemo(() => {
|
||||
tick!
|
||||
void tick
|
||||
|
||||
const expiry = new Date(status.expiresAt ?? new Date())
|
||||
return {
|
||||
|
||||
@@ -13,7 +13,11 @@ import {Admonition} from '#/components/Admonition'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import {getLiveServiceNames} from '#/components/live/utils'
|
||||
import {
|
||||
displayDuration,
|
||||
getLiveServiceNames,
|
||||
useDebouncedValue,
|
||||
} from '#/components/live/utils'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import * as Select from '#/components/Select'
|
||||
@@ -21,7 +25,6 @@ import {Text} from '#/components/Typography'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {LinkPreview} from './LinkPreview'
|
||||
import {useLiveLinkMetaQuery, useUpsertLiveStatusMutation} from './queries'
|
||||
import {displayDuration, useDebouncedValue} from './utils'
|
||||
|
||||
export function GoLiveDialog({
|
||||
control,
|
||||
@@ -57,7 +60,7 @@ function DialogInner({profile}: {profile: bsky.profile.AnyProfileView}) {
|
||||
|
||||
const time = useCallback(
|
||||
(offset: number) => {
|
||||
tick!
|
||||
void tick
|
||||
|
||||
const date = new Date()
|
||||
date.setMinutes(date.getMinutes() + offset)
|
||||
|
||||
@@ -211,8 +211,8 @@ function Inner(props: ReportDialogProps) {
|
||||
logger.metric(
|
||||
'reportDialog:success',
|
||||
{
|
||||
reason: state.selectedOption?.reason!,
|
||||
labeler: state.selectedLabeler?.creator.handle!,
|
||||
reason: state.selectedOption?.reason ?? '',
|
||||
labeler: state.selectedLabeler?.creator.handle ?? '',
|
||||
details: !!state.details,
|
||||
},
|
||||
{statsig: false},
|
||||
|
||||
@@ -9,7 +9,7 @@ import {Admonition} from '#/components/Admonition'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as toast from '#/components/Toast'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Span, Text} from '#/components/Typography'
|
||||
import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences'
|
||||
import {
|
||||
@@ -61,14 +61,14 @@ function Inner({
|
||||
feed,
|
||||
metricContext,
|
||||
onUpdateSuccess({undoAction}) {
|
||||
toast.show(
|
||||
<toast.Outer>
|
||||
<toast.Icon />
|
||||
<toast.Text>
|
||||
Toast.show(
|
||||
<Toast.Outer>
|
||||
<Toast.Icon />
|
||||
<Toast.Text>
|
||||
<Trans>Your live event preferences have been updated.</Trans>
|
||||
</toast.Text>
|
||||
</Toast.Text>
|
||||
{undoAction && (
|
||||
<toast.Action
|
||||
<Toast.Action
|
||||
label={_(msg`Undo`)}
|
||||
onPress={() => {
|
||||
if (undoAction) {
|
||||
@@ -76,12 +76,10 @@ function Inner({
|
||||
}
|
||||
}}>
|
||||
<Trans>Undo</Trans>
|
||||
</toast.Action>
|
||||
</Toast.Action>
|
||||
)}
|
||||
</toast.Outer>,
|
||||
{
|
||||
type: 'success',
|
||||
},
|
||||
</Toast.Outer>,
|
||||
{type: 'success'},
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
@@ -128,7 +128,7 @@ export function useGeolocationServiceResponse() {
|
||||
|
||||
useEffect(() => {
|
||||
return onGeolocationServiceResponseUpdate(config => {
|
||||
setConfig(config!)
|
||||
setConfig(config)
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
||||
const config = useLiveNowConfig()
|
||||
|
||||
return useMemo(() => {
|
||||
tick! // revalidate every minute
|
||||
void tick // revalidate every minute
|
||||
|
||||
if (shadowed && 'status' in shadowed && shadowed.status) {
|
||||
const isValid = validateStatus(shadowed.status, config)
|
||||
|
||||
@@ -67,7 +67,7 @@ export function isPlainArray(value: unknown) {
|
||||
}
|
||||
|
||||
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
||||
export function isPlainObject(o: any): o is Object {
|
||||
export function isPlainObject(o: any): o is object {
|
||||
if (!hasObjectPrototype(o)) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export class Convo {
|
||||
this.convoId = params.convoId
|
||||
this.agent = params.agent
|
||||
this.events = params.events
|
||||
this.senderUserDid = params.agent.session?.did!
|
||||
this.senderUserDid = params.agent.assertDid
|
||||
|
||||
if (params.placeholderData) {
|
||||
this.setupPlaceholderData(params.placeholderData)
|
||||
|
||||
@@ -22,6 +22,8 @@ const UPDATE_EVENT = 'BSKY_UPDATE'
|
||||
let _state: Schema = defaults
|
||||
const _emitter = new EventEmitter()
|
||||
|
||||
// async, to match native implementation
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export async function init() {
|
||||
broadcast.onmessage = onBroadcastMessage
|
||||
window.onstorage = onStorage
|
||||
@@ -37,6 +39,7 @@ export function get<K extends keyof Schema>(key: K): Schema[K] {
|
||||
}
|
||||
get satisfies PersistedApi['get']
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export async function write<K extends keyof Schema>(
|
||||
key: K,
|
||||
value: Schema[K],
|
||||
@@ -82,6 +85,7 @@ export function onUpdate<K extends keyof Schema>(
|
||||
}
|
||||
onUpdate satisfies PersistedApi['onUpdate']
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export async function clearStorage() {
|
||||
try {
|
||||
localStorage.removeItem(BSKY_STORAGE)
|
||||
@@ -102,6 +106,7 @@ function onStorage() {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async function onBroadcastMessage({data}: MessageEvent) {
|
||||
if (
|
||||
typeof data === 'object' &&
|
||||
|
||||
@@ -23,7 +23,7 @@ export {
|
||||
useExternalEmbedsPrefs,
|
||||
useSetExternalEmbedPref,
|
||||
} from './external-embeds-prefs'
|
||||
export * from './hidden-posts'
|
||||
export {useHiddenPosts, useHiddenPostsApi} from './hidden-posts'
|
||||
export {useLabelDefinitions} from './label-defs'
|
||||
export {useLanguagePrefs, useLanguagePrefsApi} from './languages'
|
||||
export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles'
|
||||
|
||||
@@ -15,6 +15,12 @@ export type UsePreferencesQueryResponse = Omit<
|
||||
}
|
||||
|
||||
export type ThreadViewPreferences = {
|
||||
sort: 'hotness' | 'oldest' | 'newest' | 'most-likes' | 'random' | string
|
||||
sort:
|
||||
| 'hotness'
|
||||
| 'oldest'
|
||||
| 'newest'
|
||||
| 'most-likes'
|
||||
| 'random'
|
||||
| (string & {})
|
||||
lab_treeViewEnabled?: boolean
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ type Controls = {
|
||||
/**
|
||||
* The did of the account to populate the login form with.
|
||||
*/
|
||||
requestedAccount?: string | 'none' | 'new' | 'starterpack'
|
||||
requestedAccount?: (string & {}) | 'none' | 'new' | 'starterpack'
|
||||
}) => void
|
||||
/**
|
||||
* Clears the requested account so that next time the logged out view is
|
||||
|
||||
@@ -14,7 +14,9 @@ import {
|
||||
import {AppBskyRichtextFacet, RichText} from '@atproto/api'
|
||||
import PasteInput, {
|
||||
type PastedFile,
|
||||
type PasteInputRef, // @ts-expect-error no types when installing from github
|
||||
type PasteInputRef,
|
||||
// @ts-expect-error no types when installing from github
|
||||
// eslint-disable-next-line import-x/no-unresolved
|
||||
} from '@mattermost/react-native-paste-input'
|
||||
|
||||
import {POST_IMG_MAX} from '#/lib/constants'
|
||||
|
||||
@@ -153,9 +153,9 @@ export function Button({
|
||||
async (event: GestureResponderEvent) => {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
withLoading && setIsLoading(true)
|
||||
if (withLoading) setIsLoading(true)
|
||||
await onPress?.(event)
|
||||
withLoading && setIsLoading(false)
|
||||
if (withLoading) setIsLoading(false)
|
||||
},
|
||||
[onPress, withLoading],
|
||||
)
|
||||
|
||||
@@ -51,6 +51,7 @@ function Text_DEPRECATED({
|
||||
if (__DEV__) {
|
||||
if (!emoji && childHasEmoji(children)) {
|
||||
logger.warn(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string
|
||||
`Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add <Text emoji />'`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11176,7 +11176,7 @@ eslint-config-prettier@^8.5.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11"
|
||||
integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==
|
||||
|
||||
eslint-import-context@^0.1.9:
|
||||
eslint-import-context@^0.1.8, eslint-import-context@^0.1.9:
|
||||
version "0.1.9"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-context/-/eslint-import-context-0.1.9.tgz#967b0b2f0a90ef4b689125e088f790f0b7756dbe"
|
||||
integrity sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==
|
||||
@@ -11184,6 +11184,19 @@ eslint-import-context@^0.1.9:
|
||||
get-tsconfig "^4.10.1"
|
||||
stable-hash-x "^0.2.0"
|
||||
|
||||
eslint-import-resolver-typescript@^4.4.4:
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz#3e83a9c25f4a053fe20e1b07b47e04e8519a8720"
|
||||
integrity sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==
|
||||
dependencies:
|
||||
debug "^4.4.1"
|
||||
eslint-import-context "^0.1.8"
|
||||
get-tsconfig "^4.10.1"
|
||||
is-bun-module "^2.0.0"
|
||||
stable-hash-x "^0.2.0"
|
||||
tinyglobby "^0.2.14"
|
||||
unrs-resolver "^1.7.11"
|
||||
|
||||
"eslint-plugin-bsky-internal@link:./eslint":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
@@ -13321,6 +13334,13 @@ is-boolean-object@^1.2.1:
|
||||
call-bound "^1.0.3"
|
||||
has-tostringtag "^1.0.2"
|
||||
|
||||
is-bun-module@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-2.0.0.tgz#4d7859a87c0fcac950c95e666730e745eae8bddd"
|
||||
integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==
|
||||
dependencies:
|
||||
semver "^7.7.1"
|
||||
|
||||
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
|
||||
@@ -18141,7 +18161,7 @@ semver@^7.6.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
|
||||
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
|
||||
|
||||
semver@^7.7.2, semver@^7.7.3:
|
||||
semver@^7.7.1, semver@^7.7.2, semver@^7.7.3:
|
||||
version "7.7.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
|
||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||
@@ -19291,7 +19311,7 @@ thunky@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
|
||||
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
|
||||
|
||||
tinyglobby@^0.2.11, tinyglobby@^0.2.15:
|
||||
tinyglobby@^0.2.11, tinyglobby@^0.2.14, tinyglobby@^0.2.15:
|
||||
version "0.2.15"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2"
|
||||
integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==
|
||||
@@ -19777,7 +19797,7 @@ unraw@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/unraw/-/unraw-3.0.0.tgz#73443ed70d2ab09ccbac2b00525602d5991fbbe3"
|
||||
integrity sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==
|
||||
|
||||
unrs-resolver@^1.9.2:
|
||||
unrs-resolver@^1.7.11, unrs-resolver@^1.9.2:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9"
|
||||
integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==
|
||||
|
||||
Reference in New Issue
Block a user