Re-enable ESLint rules and fix violations

Re-enable 17 ESLint rules that were disabled during the ESLint v9 migration,
and fix all violations across the codebase.

## Rules re-enabled:
- prefer-const (91 auto-fixed)
- no-var (4 auto-fixed)
- no-empty (13 fixed)
- no-irregular-whitespace (7 fixed)
- no-unsafe-optional-chaining (25 fixed)
- no-prototype-builtins (5 fixed)
- @typescript-eslint/no-unused-expressions (6 fixed)
- @typescript-eslint/no-non-null-asserted-optional-chain (3 fixed)
- @typescript-eslint/no-wrapper-object-types (1 fixed)
- @typescript-eslint/no-unsafe-function-type (1 fixed)
- no-async-promise-executor (3 fixed)
- prefer-rest-params (3 fixed)
- no-case-declarations (3 fixed)
- no-useless-escape (2 fixed)
- no-sparse-arrays (1 fixed)
- no-fallthrough (1 fixed)
- no-control-regex (1 disabled - intentional)

## Rules kept disabled (too many violations):
- @typescript-eslint/no-explicit-any (276)
- @typescript-eslint/ban-ts-comment (126)
- @typescript-eslint/no-empty-object-type (150)
- no-empty-pattern (56 - many intentional)
This commit is contained in:
Claude
2026-01-11 10:59:19 +00:00
parent c397920d60
commit fc45a779aa
103 changed files with 231 additions and 209 deletions
+2 -20
View File
@@ -180,34 +180,16 @@ export default tseslint.config(
{prefer: 'type-imports', fixStyle: 'inline-type-imports'},
],
'@typescript-eslint/no-require-imports': 'off',
// Maintain previous behavior - these are stricter in typescript-eslint v8
// Keep disabled - too many violations to fix now
'@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',
// Import rules
'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
// Turn off rules that weren't enforced in previous config
// Keep disabled - many are intentional empty destructuring patterns
'no-empty-pattern': 'off',
'no-async-promise-executor': 'off',
'no-constant-binary-expression': 'warn',
'prefer-const': 'off',
'no-empty': 'off',
'no-unsafe-optional-chaining': 'off',
'no-prototype-builtins': 'off',
'no-var': 'off',
'prefer-rest-params': 'off',
'no-case-declarations': 'off',
'no-irregular-whitespace': 'off',
'no-useless-escape': 'off',
'no-sparse-arrays': 'off',
'no-fallthrough': 'off',
'no-control-regex': 'off',
},
},
+2 -5
View File
@@ -111,13 +111,12 @@ export async function prefetchConfig() {
return
}
configPrefetchPromise = new Promise(async resolve => {
configPrefetchPromise = (async () => {
await cacheHydrationPromise
const cached = getConfigFromCache()
if (cached) {
logger.debug(`prefetchAgeAssuranceConfig: using cache`)
resolve()
} else {
try {
logger.debug(`prefetchAgeAssuranceConfig: resolving...`)
@@ -130,11 +129,9 @@ export async function prefetchConfig() {
logger.warn(`prefetchAgeAssuranceConfig: failed`, {
safeMessage: e.message,
})
} finally {
resolve()
}
}
})
})()
}
export async function refetchConfig() {
logger.debug(`refetchConfig: fetching...`)
+1
View File
@@ -8,6 +8,7 @@ import {type OtherRequiredData} from '#/ageAssurance/data'
import {IS_DEV, IS_E2E} from '#/env'
import {type Geolocation} from '#/geolocation'
// eslint-disable-next-line no-constant-binary-expression -- intentional debug toggle
export const enabled = (IS_DEV && false) || IS_E2E
export const geolocation: Geolocation | undefined = enabled
+5 -1
View File
@@ -81,7 +81,11 @@ export function Outer({
const handleBackgroundPress = React.useCallback(
async (e: GestureResponderEvent) => {
webOptions?.onBackgroundPress ? webOptions.onBackgroundPress(e) : close()
if (webOptions?.onBackgroundPress) {
webOptions.onBackgroundPress(e)
} else {
close()
}
},
[webOptions, close],
)
@@ -167,7 +167,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
const results = hasSearchText
? searchResults?.pages.flatMap(p => p.actors)
: suggestions?.actors
let _items: Item[] = []
const _items: Item[] = []
if (isFetchingSuggestions || isFetchingSearchResults) {
const placeholders: Item[] = Array(10)
+1 -1
View File
@@ -286,7 +286,7 @@ function Bubble({
left -= left + cw - maxLeft
}
let tipLeft =
const tipLeft =
targetMeasurements.x -
left +
targetMeasurements.width / 2 -
@@ -334,7 +334,7 @@ async function createProfileRecord(
imageUri && imageMime ? uploadBlob(agent, imageUri, imageMime) : undefined
await agent.upsertProfile(async existing => {
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
const next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
if (blobPromise) {
const res = await blobPromise
@@ -185,7 +185,9 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
try {
// fire off a confirmation email immediately
await requestEmailVerification()
} catch {}
} catch {
// no-op
}
}
} catch (e) {
logger.error('EmailDialog: update email failed', {safeMessage: e})
+1 -1
View File
@@ -99,7 +99,7 @@ function DialogInner({
} = useRemoveLiveStatusMutation()
const {minutesUntilExpiry, expiryDateTime} = useMemo(() => {
tick!
void tick // revalidate every minute
const expiry = new Date(status.expiresAt ?? new Date())
return {
+1 -1
View File
@@ -52,7 +52,7 @@ function DialogInner({profile}: {profile: bsky.profile.AnyProfileView}) {
const time = useCallback(
(offset: number) => {
tick!
void tick // revalidate every minute
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},
@@ -719,7 +719,7 @@ function CategoryCard({
{option.title}
</Text>
<Text
style={[a.text_sm, , a.leading_snug, t.atoms.text_contrast_medium]}>
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
{option.description}
</Text>
</View>
+4 -4
View File
@@ -67,7 +67,7 @@ export async function resolve() {
* THIS PROMISE SHOULD NEVER `reject()`! We want the app to proceed with
* startup, even if geolocation resolution fails.
*/
geolocationServicePromise = new Promise(async resolve => {
geolocationServicePromise = (async () => {
let success = false
function cacheResponseOrThrow(response: Geolocation | undefined) {
@@ -111,10 +111,10 @@ export async function resolve() {
},
)
})
} finally {
resolve({success})
}
})
return {success}
})()
}
}
+1 -1
View File
@@ -75,7 +75,7 @@ export const USRegionNameToRegionCode: {
export function normalizeDeviceLocation(
location: LocationGeocodedAddress,
): Geolocation {
let {isoCountryCode, region} = location
const {isoCountryCode, region} = location
let regionCode: string | undefined = region ?? undefined
/*
+1 -1
View File
@@ -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.did, shadowed.status, config)
+1 -1
View File
@@ -208,7 +208,7 @@ export class FeedViewPostsSlice {
getAuthors(): AuthorContext {
const feedPost = this._feedPost
let author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author
const author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
let grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
let rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
+1 -1
View File
@@ -106,7 +106,7 @@ async function loggedOutFetch({
limit: number
cursor?: string
}) {
let contentLangs = getAppLanguageAsContentLanguage()
const contentLangs = getAppLanguageAsContentLanguage()
/**
* Copied from our root `Agent` class
+1 -1
View File
@@ -129,7 +129,7 @@ export class MergeFeedAPI implements FeedAPI {
// assemble a response by sampling from feeds with content
const posts: AppBskyFeedDefs.FeedViewPost[] = []
while (posts.length < limit) {
let slice = this.sampleItem()
const slice = this.sampleItem()
if (slice[0]) {
posts.push(slice[0])
} else {
+1 -1
View File
@@ -78,7 +78,7 @@ export async function post(
const writes: $Typed<ComAtprotoRepoApplyWrites.Create>[] = []
const uris: string[] = []
let now = new Date()
const now = new Date()
let tid: TID | undefined
for (let i = 0; i < thread.posts.length; i++) {
+3 -1
View File
@@ -229,5 +229,7 @@ export async function imageToThumb(
if (img) {
return await createComposerImage(img)
}
} catch {}
} catch {
// no-op
}
}
+2 -2
View File
@@ -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
}
@@ -85,7 +85,7 @@ export function isPlainObject(o: any): o is Object {
}
// If constructor does not have an Object-specific method
if (!prot.hasOwnProperty('isPrototypeOf')) {
if (!Object.prototype.hasOwnProperty.call(prot, 'isPrototypeOf')) {
return false
}
+1 -1
View File
@@ -4,7 +4,7 @@ import {getCurrentRoute} from '#/lib/routes/helpers'
export function useNavigationTabState() {
return useNavigationState(state => {
let currentRoute = state ? getCurrentRoute(state).name : 'Home'
const currentRoute = state ? getCurrentRoute(state).name : 'Home'
return {
isAtHome: currentRoute === 'Home',
isAtSearch: currentRoute === 'Search',
+1
View File
@@ -8,6 +8,7 @@ import {useCallback, useInsertionEffect, useRef} from 'react'
//
// Also, you should avoid calling the returned function during rendering
// since the values captured by it are going to lag behind.
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- generic utility needs Function type
export function useNonReactiveCallback<T extends Function>(fn: T): T {
const ref = useRef(fn)
useInsertionEffect(() => {
+1 -1
View File
@@ -18,7 +18,7 @@ export function useTabFocusEffect(
useEffect(() => {
// check if inside
let v = getTabState(state, tabName) !== TabState.Outside
const v = getTabState(state, tabName) !== TabState.Outside
if (v !== isInside) {
// fire
setIsInside(v)
+3 -3
View File
@@ -50,7 +50,7 @@ export async function saveImageToMediaLibrary(_opts: {uri: string}) {
}
export async function getImageDim(path: string): Promise<Dimensions> {
var img = document.createElement('img')
const img = document.createElement('img')
const promise = new Promise((resolve, reject) => {
img.onload = resolve
img.onerror = reject
@@ -139,8 +139,8 @@ function createResizedImage(
} else if (mode === 'contain') {
scale = img.width > img.height ? width / img.width : height / img.height
}
let w = img.width * scale
let h = img.height * scale
const w = img.width * scale
const h = img.height * scale
canvas.width = w
canvas.height = h
+1 -1
View File
@@ -39,7 +39,7 @@ export class Router<T extends Record<string, any>> {
function createRoute(pattern: string): Route {
const pathParamNames: Set<string> = new Set()
let matcherReInternal = pattern.replace(/:([\w]+)/g, (_m, name) => {
const matcherReInternal = pattern.replace(/:([\w]+)/g, (_m, name) => {
pathParamNames.add(name)
return `(?<${name}>[^/]+)`
})
+2 -2
View File
@@ -131,8 +131,8 @@ function toStringRecord<E extends keyof MetricEvents>(
metadata: MetricEvents[E] & FlatJSONRecord,
): Record<string, string> {
const record: Record<string, string> = {}
for (let key in metadata) {
if (metadata.hasOwnProperty(key)) {
for (const key in metadata) {
if (Object.hasOwn(metadata, key)) {
if (typeof metadata[key] === 'string') {
record[key] = metadata[key]
} else {
+1
View File
@@ -6,6 +6,7 @@ import {type ModerationUI} from '@atproto/api'
// \u2611 = ☑
const CHECK_MARKS_RE = /[\u2705\u2713\u2714\u2611]/gu
const CONTROL_CHARS_RE =
// eslint-disable-next-line no-control-regex -- intentionally matching control characters for sanitization
/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g
const MULTIPLE_SPACES_RE = /[\s][\s\u200B]+/g
+14 -10
View File
@@ -426,7 +426,7 @@ export function parseEmbedPlayerFromUrl(
// link shortened flickr path
if (urlp.hostname === 'flic.kr') {
const b58alph = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
let [__, type, idBase58Enc] = urlp.pathname.split('/')
const [__, type, idBase58Enc] = urlp.pathname.split('/')
let id = 0n
for (const char of idBase58Enc) {
const nextIdx = b58alph.indexOf(char)
@@ -439,7 +439,7 @@ export function parseEmbedPlayerFromUrl(
}
switch (type) {
case 'go':
case 'go': {
const formattedGroupId = `${id}`
return {
type: 'flickr_album',
@@ -449,6 +449,7 @@ export function parseEmbedPlayerFromUrl(
-2,
)}@N${formattedGroupId.slice(-2)}`,
}
}
case 's':
return {
type: 'flickr_album',
@@ -537,13 +538,13 @@ export function parseTenorGif(urlp: URL):
return {success: false}
}
let [__, id, filename] = urlp.pathname.split('/')
const [, initialId, initialFilename] = urlp.pathname.split('/')
if (!id || !filename) {
if (!initialId || !initialFilename) {
return {success: false}
}
if (!id.includes('AAAAC')) {
if (!initialId.includes('AAAAC')) {
return {success: false}
}
@@ -559,16 +560,19 @@ export function parseTenorGif(urlp: URL):
width: Number(w),
}
let id: string
let filename: string
if (isWeb) {
if (isSafari) {
id = id.replace('AAAAC', 'AAAP1')
filename = filename.replace('.gif', '.mp4')
id = initialId.replace('AAAAC', 'AAAP1')
filename = initialFilename.replace('.gif', '.mp4')
} else {
id = id.replace('AAAAC', 'AAAP3')
filename = filename.replace('.gif', '.webm')
id = initialId.replace('AAAAC', 'AAAP3')
filename = initialFilename.replace('.gif', '.webm')
}
} else {
id = id.replace('AAAAC', 'AAAAM')
id = initialId.replace('AAAAC', 'AAAAM')
filename = initialFilename
}
return {
+1 -1
View File
@@ -7,7 +7,7 @@ export function getMentionAt(
text: string,
cursorPos: number,
): FoundMention | undefined {
let re = /(^|\s)@([a-z0-9.-]*)/gi
const re = /(^|\s)@([a-z0-9.-]*)/gi
let match
while ((match = re.exec(text))) {
const spaceOffset = match[1].length
+3 -3
View File
@@ -24,9 +24,9 @@ export function niceDate(
}
export function getAge(birthDate: Date): number {
var today = new Date()
var age = today.getFullYear() - birthDate.getFullYear()
var m = today.getMonth() - birthDate.getMonth()
const today = new Date()
let age = today.getFullYear() - birthDate.getFullYear()
const m = today.getMonth() - birthDate.getMonth()
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--
}
+14 -6
View File
@@ -28,7 +28,7 @@ const TRUSTED_REGEX = new RegExp(
export function isValidDomain(str: string): boolean {
return !!TLDs.find(tld => {
let i = str.lastIndexOf(tld)
const i = str.lastIndexOf(tld)
if (i === -1) {
return false
}
@@ -123,7 +123,9 @@ export function isBskyPostUrl(url: string): boolean {
return /profile\/(?<name>[^/]+)\/post\/(?<rkey>[^/]+)/i.test(
urlp.pathname,
)
} catch {}
} catch {
// no-op
}
}
return false
}
@@ -135,7 +137,9 @@ export function isBskyCustomFeedUrl(url: string): boolean {
return /profile\/(?<name>[^/]+)\/feed\/(?<rkey>[^/]+)/i.test(
urlp.pathname,
)
} catch {}
} catch {
// no-op
}
}
return false
}
@@ -291,10 +295,14 @@ export function labelToDomain(label: string): string | undefined {
}
try {
return new URL(label).hostname.toLowerCase()
} catch {}
} catch {
// no-op
}
try {
return new URL('https://' + label).hostname.toLowerCase()
} catch {}
} catch {
// no-op
}
return undefined
}
@@ -306,7 +314,7 @@ export function isPossiblyAUrl(str: string): boolean {
if (str.startsWith('https://')) {
return true
}
const [firstWord] = str.split(/[\s\/]/)
const [firstWord] = str.split(/[\s/]/)
return isValidDomain(firstWord)
}
+5 -2
View File
@@ -11,7 +11,10 @@ if (process.env.NODE_ENV !== 'production') {
// This is a hack to get it showing as a redbox on the web so we catch it early.
const realConsoleError = console.error
const thrownErrors = new WeakSet()
console.error = function consoleErrorWrapper(msgOrError) {
console.error = function consoleErrorWrapper(
...args: Parameters<typeof console.error>
) {
const msgOrError = args[0]
if (
typeof msgOrError === 'string' &&
msgOrError.startsWith('Unexpected text node')
@@ -28,7 +31,7 @@ if (process.env.NODE_ENV !== 'production') {
thrownErrors.add(err)
throw err
} else if (!thrownErrors.has(msgOrError)) {
return realConsoleError.apply(this, arguments as any)
return realConsoleError.apply(this, args)
}
}
}
+3 -1
View File
@@ -123,7 +123,9 @@ function BookmarksInner() {
if (isFetchingNextPage || !hasNextPage || error) return
try {
await fetchNextPage()
} catch {}
} catch {
// no-op
}
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
const items = useMemo(() => {
+1 -1
View File
@@ -29,7 +29,7 @@ export function NoFeedsPinned({
const addRecommendedFeeds = React.useCallback(async () => {
let skippedTimeline = false
let skippedDiscover = false
let remainingSavedFeeds = []
const remainingSavedFeeds = []
// remove first instance of both timeline and discover, since we're going to overwrite them
for (const savedFeed of preferences.savedFeeds) {
@@ -156,7 +156,7 @@ export function MessageInputEmbed({
</View>
)
break
case 'success':
case 'success': {
const itemUrip = new AtUri(post.uri)
const itemHref = makeProfileLink(post.author, 'post', itemUrip.rkey)
@@ -203,6 +203,7 @@ export function MessageInputEmbed({
</View>
)
break
}
}
return (
@@ -144,7 +144,7 @@ export function StepFinished() {
: undefined
await agent.upsertProfile(async existing => {
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
const next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
if (blobPromise) {
const res = await blobPromise
@@ -82,7 +82,7 @@ export function StarterPackCard({
setIsFollowingAll(true)
setIsProcessing(false)
batchedUpdates(() => {
for (let did of dids) {
for (const did of dids) {
updateProfileShadow(queryClient, did, {
followingUri: followUris.get(did),
})
+3 -3
View File
@@ -375,7 +375,7 @@ export function Explore({
if (suggestedUsers.actors.length > 0 && moderationOpts) {
// Currently the responses contain duplicate items.
// Needs to be fixed on backend, but let's dedupe to be safe.
let seen = new Set()
const seen = new Set()
const profileItems: ExploreScreenItems[] = []
for (const actor of suggestedUsers.actors) {
// checking for following still necessary if search data is used
@@ -439,7 +439,7 @@ export function Explore({
if (useFullExperience) {
if (suggestedFeeds && preferences) {
let seen = new Set()
const seen = new Set()
const feedItems: ExploreScreenItems[] = []
for (const feed of suggestedFeeds.feeds) {
if (!seen.has(feed.uri)) {
@@ -527,7 +527,7 @@ export function Explore({
if (feeds && preferences) {
// Currently the responses contain duplicate items.
// Needs to be fixed on backend, but let's dedupe to be safe.
let seen = new Set()
const seen = new Set()
const feedItems: ExploreScreenItems[] = []
for (const page of feeds.pages) {
for (const feed of page.feeds) {
+1 -1
View File
@@ -248,7 +248,7 @@ let SearchScreenPostResults = ({
return results?.pages.flatMap(page => page.posts) || []
}, [results])
const items = useMemo(() => {
let temp: SearchResultSlice[] = []
const temp: SearchResultSlice[] = []
const seenUris = new Set()
for (const post of posts) {
+1 -1
View File
@@ -10,7 +10,7 @@ export function parseSearchQuery(rawQuery: string) {
}
// find remaining params in base
const rawParams = base.match(/[a-z]+:[a-z-\.@\d:"]+/gi) || []
const rawParams = base.match(/[a-z]+:[a-z-.@\d:"]+/gi) || []
for (const param of rawParams) {
base = base.replace(param, '')
+3 -3
View File
@@ -123,7 +123,7 @@ export function is18(date: Date) {
}
export function reducer(s: SignupState, a: SignupAction): SignupState {
let next = {...s}
const next = {...s}
switch (a.type) {
case 'prev': {
@@ -330,11 +330,11 @@ export function useSubmitSignup() {
/*
* Must happen last so that if the user has multiple tabs open and
* createAccount fails, one tab is not stuck in onboarding  Eric
* createAccount fails, one tab is not stuck in onboarding Eric
*/
onboardingDispatch({type: 'start'})
} catch (e: any) {
let errMsg = e.toString()
const errMsg = e.toString()
if (e instanceof ComAtprotoServerCreateAccount.InvalidInviteCodeError) {
dispatch({
type: 'setError',
@@ -377,7 +377,7 @@ function Header({
setIsProcessing(false)
batchedUpdates(() => {
for (let did of dids) {
for (const did of dids) {
updateProfileShadow(queryClient, did, {
followingUri: followUris.get(did),
})
+2 -1
View File
@@ -74,8 +74,9 @@ export function Header({
break
}
case 'author':
// TODO
// falls through
default: {
// TODO: implement author header
break
}
}
+8 -8
View File
@@ -158,7 +158,7 @@ export function updatePostShadow(
value: Partial<PostShadow>,
) {
const cachedPosts = findPostsInCache(queryClient, uri)
for (let post of cachedPosts) {
for (const post of cachedPosts) {
shadows.set(post, {...shadows.get(post), ...value})
}
batchedUpdates(() => {
@@ -170,28 +170,28 @@ function* findPostsInCache(
queryClient: QueryClient,
uri: string,
): Generator<AppBskyFeedDefs.PostView, void> {
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
for (const post of findAllPostsInFeedQueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) {
for (const post of findAllPostsInNotifsQueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInThreadV2QueryData(queryClient, uri)) {
for (const post of findAllPostsInThreadV2QueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
for (const post of findAllPostsInSearchQueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
for (const post of findAllPostsInQuoteQueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInExploreFeedPreviewsQueryData(
for (const post of findAllPostsInExploreFeedPreviewsQueryData(
queryClient,
uri,
)) {
yield post
}
for (let post of findAllPostsInBookmarksQueryData(queryClient, uri)) {
for (const post of findAllPostsInBookmarksQueryData(queryClient, uri)) {
yield post
}
}
+1 -1
View File
@@ -195,7 +195,7 @@ export function updateProfileShadow(
value: Partial<ProfileShadow>,
) {
const cachedProfiles = findProfilesInCache(queryClient, did)
for (let profile of cachedProfiles) {
for (const profile of cachedProfiles) {
shadows.set(profile, {...shadows.get(profile), ...value})
}
batchedUpdates(() => {
+1 -1
View File
@@ -276,7 +276,7 @@ function sendOrAggregateInteractionsForStats(
interactions: AppBskyFeedDefs.Interaction[],
feed: string,
) {
for (let interaction of interactions) {
for (const interaction of interactions) {
switch (interaction.event) {
// Pressing "Show more" / "Show less" is relatively uncommon so we won't aggregate them.
// This lets us send the feed context together with them.
+1 -1
View File
@@ -46,7 +46,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
)
const closeLightbox = useNonReactiveCallback(() => {
let wasActive = !!activeLightbox
const wasActive = !!activeLightbox
setActiveLightbox(null)
return wasActive
})
+5 -11
View File
@@ -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.session?.did ?? ''
if (params.placeholderData) {
this.setupPlaceholderData(params.placeholderData)
@@ -557,11 +557,7 @@ export class Convo {
async fetchConvo() {
if (this.pendingFetchConvo) return this.pendingFetchConvo
this.pendingFetchConvo = new Promise<{
convo: ChatBskyConvoDefs.ConvoView
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
recipients: ChatBskyActorDefs.ProfileViewBasic[]
}>(async (resolve, reject) => {
this.pendingFetchConvo = (async () => {
try {
const response = await networkRetry(2, () => {
return this.agent.api.chat.bsky.convo.getConvo(
@@ -574,17 +570,15 @@ export class Convo {
const convo = response.data.convo
resolve({
return {
convo,
sender: convo.members.find(m => m.did === this.senderUserDid),
recipients: convo.members.filter(m => m.did !== this.senderUserDid),
})
} catch (e) {
reject(e)
}
} finally {
this.pendingFetchConvo = undefined
}
})
})()
return this.pendingFetchConvo
}
+1 -1
View File
@@ -352,7 +352,7 @@ export class MessagesEventBus {
const {logs: events} = response.data
let needsEmit = false
let batch: ChatBskyConvoGetLog.OutputSchema['logs'] = []
const batch: ChatBskyConvoGetLog.OutputSchema['logs'] = []
for (const ev of events) {
/*
+2 -2
View File
@@ -60,7 +60,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
})
const closeModal = useNonReactiveCallback(() => {
let wasActive = activeModals.length > 0
const wasActive = activeModals.length > 0
setActiveModals(modals => {
return modals.slice(0, -1)
})
@@ -68,7 +68,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
})
const closeAllModals = useNonReactiveCallback(() => {
let wasActive = activeModals.length > 0
const wasActive = activeModals.length > 0
setActiveModals([])
return wasActive
})
+1 -1
View File
@@ -108,7 +108,7 @@ function computeSuggestions({
searched?: AppBskyActorDefs.ProfileViewBasic[]
moderationOpts: ModerationOpts
}) {
let items: AppBskyActorDefs.ProfileViewBasic[] = []
const items: AppBskyActorDefs.ProfileViewBasic[] = []
for (const item of searched) {
if (!items.find(item2 => item2.handle === item.handle)) {
items.push(item)
@@ -135,7 +135,7 @@ export function* findAllPostsInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const bookmark of page.bookmarks) {
if (
!bsky.dangerousIsType<AppBskyFeedDefs.PostView>(
+2 -2
View File
@@ -364,7 +364,7 @@ export function* findAllPostsInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.posts) {
if (didOrHandleUriMatches(atUri, item.post)) {
yield item.post
@@ -420,7 +420,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.posts) {
if (item.post.author.did === did) {
yield item.post.author
+3 -3
View File
@@ -439,7 +439,7 @@ export function usePinnedFeedsInfos() {
return [PWI_DISCOVER_FEED_STUB]
}
let resolved = new Map<string, FeedSourceInfo>()
const resolved = new Map<string, FeedSourceInfo>()
// Get all feeds. We can do this in a batch.
const pinnedFeeds = pinnedItems.filter(feed => feed.type === 'feed')
@@ -476,7 +476,7 @@ export function usePinnedFeedsInfos() {
// order the feeds/lists in the order they were pinned
const result: SavedFeedSourceInfo[] = []
for (let pinnedItem of pinnedItems) {
for (const pinnedItem of pinnedItems) {
const feedInfo = resolved.get(pinnedItem.value)
if (feedInfo) {
result.push({
@@ -590,7 +590,7 @@ export function useSavedFeeds() {
})
const result: SavedFeedItem[] = []
for (let savedItem of savedItems) {
for (const savedItem of savedItems) {
if (savedItem.type === 'timeline') {
result.push({
type: 'timeline',
+1 -1
View File
@@ -103,7 +103,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const match of page.matches) {
if (match.did === did) {
yield match
+3 -1
View File
@@ -120,7 +120,9 @@ export async function checkHandleAvailability(
logger.metric('signup:handleTaken', {typeahead}, {statsig: true})
return {available: false} as const
}
} catch {}
} catch {
// no-op
}
logger.metric('signup:handleAvailable', {typeahead}, {statsig: true})
return {available: true} as const
}
+1 -1
View File
@@ -54,7 +54,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const follow of page.followers) {
if (follow.did === did) {
yield follow
+1 -1
View File
@@ -103,7 +103,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
if (page.list.creator.did === did) {
yield page.list.creator
}
+1 -1
View File
@@ -47,7 +47,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const block of page.blocks) {
if (block.did === did) {
yield block
+2 -2
View File
@@ -21,7 +21,7 @@ export function useMyListsQuery(filter: MyListsFilter) {
staleTime: STALE.MINUTES.ONE,
queryKey: RQKEY(filter),
async queryFn() {
let lists: AppBskyGraphDefs.ListView[] = []
const lists: AppBskyGraphDefs.ListView[] = []
const promises = [
accumulate(cursor =>
agent.app.bsky.graph
@@ -66,7 +66,7 @@ export function useMyListsQuery(filter: MyListsFilter) {
}
const resultset = await Promise.all(promises)
for (const res of resultset) {
for (let list of res) {
for (const list of res) {
if (
filter === 'curate' &&
list.purpose !== 'app.bsky.graph.defs#curatelist'
+1 -1
View File
@@ -47,7 +47,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const mute of page.mutes) {
if (mute.did === did) {
yield mute
+5 -5
View File
@@ -133,7 +133,7 @@ export function useNotificationFeedQuery(opts: {
// Keep track of the last run and whether we can reuse
// some already selected pages from there.
let reusedPages = []
const reusedPages = []
if (lastRun.current) {
const {
data: lastData,
@@ -141,8 +141,8 @@ export function useNotificationFeedQuery(opts: {
result: lastResult,
} = lastRun.current
let canReuse = true
for (let key in selectArgs) {
if (selectArgs.hasOwnProperty(key)) {
for (const key in selectArgs) {
if (Object.hasOwn(selectArgs, key)) {
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
// Can't do reuse anything if any input has changed.
canReuse = false
@@ -287,7 +287,7 @@ export function* findAllPostsInQueryData(
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.items) {
if (item.type !== 'starterpack-joined') {
if (item.subject && didOrHandleUriMatches(atUri, item.subject)) {
@@ -317,7 +317,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.items) {
if (
(item.type === 'follow' || item.type === 'contact-match') &&
+1 -1
View File
@@ -71,7 +71,7 @@ export async function fetchPage({
)
// group notifications which are essentially similar (follows, likes on a post)
let notifsGrouped = groupNotifications(notifs)
const notifsGrouped = groupNotifications(notifs)
// we fetch subjects of notifications (usually posts) now instead of lazily
// in the UI to avoid relayouts
+5 -5
View File
@@ -244,7 +244,7 @@ export function usePostFeedQuery(
// Keep track of the last run and whether we can reuse
// some already selected pages from there.
let reusedPages = []
const reusedPages = []
if (lastRun.current) {
const {
data: lastData,
@@ -252,8 +252,8 @@ export function usePostFeedQuery(
result: lastResult,
} = lastRun.current
let canReuse = true
for (let key in selectArgs) {
if (selectArgs.hasOwnProperty(key)) {
for (const key in selectArgs) {
if (Object.hasOwn(selectArgs, key)) {
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
// Can't do reuse anything if any input has changed.
canReuse = false
@@ -510,7 +510,7 @@ export function* findAllPostsInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.feed) {
if (didOrHandleUriMatches(atUri, item.post)) {
yield item.post
@@ -563,7 +563,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.feed) {
if (item.post.author.did === did) {
yield item.post.author
+1 -1
View File
@@ -52,7 +52,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const like of page.likes) {
if (like.actor.did === did) {
yield like.actor
+2 -2
View File
@@ -80,7 +80,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const item of page.posts) {
if (item.author.did === did) {
yield item.author
@@ -108,7 +108,7 @@ export function* findAllPostsInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const post of page.posts) {
if (didOrHandleUriMatches(atUri, post)) {
yield post
+1 -1
View File
@@ -55,7 +55,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const repostedBy of page.repostedBy) {
if (repostedBy.did === did) {
yield repostedBy
+1 -1
View File
@@ -54,7 +54,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const follower of page.followers) {
if (follower.did === did) {
yield follower
+1 -1
View File
@@ -63,7 +63,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const follow of page.follows) {
if (follow.did === did) {
yield follow
+1 -1
View File
@@ -621,7 +621,7 @@ export function* findAllProfilesInQueryData(
if (!queryData) {
continue
}
for (let profile of queryData.profiles) {
for (const profile of queryData.profiles) {
if (profile.did === did) {
yield profile
}
+5 -5
View File
@@ -87,7 +87,7 @@ export function useSearchPostsQuery({
// Keep track of the last run and whether we can reuse
// some already selected pages from there.
let reusedPages = []
const reusedPages = []
if (lastRun.current) {
const {
data: lastData,
@@ -95,8 +95,8 @@ export function useSearchPostsQuery({
result: lastResult,
} = lastRun.current
let canReuse = true
for (let key in selectArgs) {
if (selectArgs.hasOwnProperty(key)) {
for (const key in selectArgs) {
if (Object.hasOwn(selectArgs, key)) {
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
// Can't do reuse anything if any input has changed.
canReuse = false
@@ -156,7 +156,7 @@ export function* findAllPostsInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const post of page.posts) {
if (didOrHandleUriMatches(atUri, post)) {
yield post
@@ -184,7 +184,7 @@ export function* findAllProfilesInQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const post of page.posts) {
if (post.author.did === did) {
yield post.author
+1 -2
View File
@@ -119,8 +119,7 @@ export function useCreateStarterPackMutation({
descriptionFacets = rt.facets
}
let listRes
listRes = await createStarterPackList({
const listRes = await createStarterPackList({
name,
description,
profiles,
+1 -1
View File
@@ -150,7 +150,7 @@ function* findAllProfilesInSuggestedFollowsQueryData(
if (!queryData?.pages) {
continue
}
for (const page of queryData?.pages) {
for (const page of queryData.pages) {
for (const actor of page.actors) {
if (actor.did === did) {
yield actor
+1 -1
View File
@@ -70,7 +70,7 @@ export function threadgateAllowUISettingToAllowRecordValue(
return undefined
}
let allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
const allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
if (!threadgate.find(v => v.type === 'nobody')) {
for (const rule of threadgate) {
@@ -202,7 +202,7 @@ export function getThreadPlaceholder(
uri: string,
): $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItem> | void {
let partial
for (let item of getThreadPlaceholderCandidates(queryClient, uri)) {
for (const item of getThreadPlaceholderCandidates(queryClient, uri)) {
/*
* Currently, the backend doesn't send full post info in some cases (for
* example, for quoted posts). We use missing `likeCount` as a way to
@@ -246,19 +246,19 @@ export function* getThreadPlaceholderCandidates(
* with >0 likes/reposts over a stale version with no metrics in order to
* avoid a notification->post scroll jump.
*/
for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) {
for (const post of findAllPostsInNotifsQueryData(queryClient, uri)) {
yield postViewToThreadPlaceholder(post)
}
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
for (const post of findAllPostsInFeedQueryData(queryClient, uri)) {
yield postViewToThreadPlaceholder(post)
}
for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
for (const post of findAllPostsInQuoteQueryData(queryClient, uri)) {
yield postViewToThreadPlaceholder(post)
}
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
for (const post of findAllPostsInSearchQueryData(queryClient, uri)) {
yield postViewToThreadPlaceholder(post)
}
for (let post of findAllPostsInExploreFeedPreviewsQueryData(
for (const post of findAllPostsInExploreFeedPreviewsQueryData(
queryClient,
uri,
)) {
+1 -1
View File
@@ -128,7 +128,7 @@ export type ThreadItem =
* total number of replies, the reply index, etc.
*
* The idea here is that these values should be objectively true in all cases,
* such that we can use them later either individually on in composite  to
* such that we can use them later either individually on in composite to
* drive rendering behaviors.
*/
export type TraversalMetadata = {
+1 -1
View File
@@ -1673,7 +1673,7 @@ describe('session', () => {
function run(initialState: State, actions: Action[]): State {
let state = initialState
for (let action of actions) {
for (const action of actions) {
state = reducer(state, action)
}
return state
+1 -1
View File
@@ -374,7 +374,7 @@ export class Agent extends BaseAgent {
// WARN: In the factories above, we _manually set a proxy header_ for the agent after we do whatever it is we are supposed to do.
// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it
// feels safer to just let those run as-is and set the header afterward.
let realFetch = globalThis.fetch
const realFetch = globalThis.fetch
class BskyAppAgent extends BskyAgent {
persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined =
undefined
+2 -2
View File
@@ -123,8 +123,8 @@ export function addSessionDebugLog(log: Log) {
}
}
let agentIds = new WeakMap<object, string>()
let realmId = Math.random().toString(36).slice(2)
const agentIds = new WeakMap<object, string>()
const realmId = Math.random().toString(36).slice(2)
let nextAgentId = 1
function getAgentId(agent: object) {
+1 -1
View File
@@ -107,7 +107,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
})
const closeComposer = useNonReactiveCallback(() => {
let wasOpen = !!state
const wasOpen = !!state
if (wasOpen) {
setState(undefined)
purgeTemporaryImageFiles()
+3 -1
View File
@@ -47,7 +47,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
if (isWeb) {
try {
sessionStorage.setItem('lastSelectedHomeFeed', feed)
} catch {}
} catch {
// no-op
}
}
persisted.write('lastSelectedHomeFeed', feed)
}, [])
+2 -2
View File
@@ -36,7 +36,7 @@ const consumedSources = new Map<string, PostSource>()
export function setUnstablePostSource(key: string, source: PostSource) {
assertValidDevOnly(
key,
`setUnstablePostSource key should be a URI containing a handle, received ${key} use buildPostSourceKey`,
`setUnstablePostSource key should be a URI containing a handle, received ${key} use buildPostSourceKey`,
)
logger.debug('set', {key, source})
transientSources.set(key, source)
@@ -53,7 +53,7 @@ export function useUnstablePostSource(key: string) {
const [source] = useState(() => {
assertValidDevOnly(
key,
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} be sure to use buildPostSourceKey when setting the source`,
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} be sure to use buildPostSourceKey when setting the source`,
true,
)
const source = consumedSources.get(id) || transientSources.get(key)
+3 -3
View File
@@ -519,7 +519,7 @@ export const ComposePost = ({
} finally {
if (postUri) {
let index = 0
for (let post of thread.posts) {
for (const post of thread.posts) {
logEvent('post:create', {
imageCount:
post.embed.media?.type === 'images'
@@ -619,7 +619,7 @@ export const ComposePost = ({
if (publishOnUpload) {
let erroredVideos = 0
let uploadingVideos = 0
for (let post of thread.posts) {
for (const post of thread.posts) {
if (post.embed.media?.type === 'video') {
const video = post.embed.media.video
if (video.status === 'error') {
@@ -812,7 +812,7 @@ export const ComposePost = ({
)
}
let ComposerPost = React.memo(function ComposerPost({
const ComposerPost = React.memo(function ComposerPost({
post,
dispatch,
textInput,
+1 -1
View File
@@ -413,7 +413,7 @@ export function SelectMediaButton({
msg`You can only select one GIF at a time.`,
),
[SelectedAssetError.FileTooBig]: _(
msg`One or more of your selected files are too large. Maximum size is 100 MB.`,
msg`One or more of your selected files are too large. Maximum size is 100 MB.`,
),
}[error]
})
+1 -1
View File
@@ -198,7 +198,7 @@ export function composerReducer(
const indexToRemove = state.thread.posts.findIndex(
p => p.id === action.postId,
)
let nextPosts = [...state.thread.posts]
const nextPosts = [...state.thread.posts]
if (indexToRemove !== -1) {
const postToRemove = state.thread.posts[indexToRemove]
if (postToRemove.embed.media?.type === 'video') {
+2 -2
View File
@@ -392,7 +392,7 @@ function getCompressErrorMessage(e: unknown, _: I18n['_']): string | null {
}
if (e instanceof VideoTooLargeError) {
return _(
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
)
}
logger.error('Error compressing video', {safeMessage: e})
@@ -431,7 +431,7 @@ function getUploadErrorMessage(e: unknown, _: I18n['_']): string | null {
)
case 'file size (100000001 bytes) is larger than the maximum allowed size (100000000 bytes)':
return _(
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
)
default:
return e.message
@@ -90,7 +90,7 @@ function iterateUris(str: string, cb: (from: number, to: number) => void) {
}
uri = `https://${uri}`
}
let from = str.indexOf(match[2], match.index)
const from = str.indexOf(match[2], match.index)
let to = from + match[2].length
// strip ending puncuation
if (/[.,;!?]$/.test(uri)) {
@@ -17,7 +17,9 @@ export function useWebPreloadEmoji({immediate}: {immediate?: boolean} = {}) {
try {
const data = (await import('./EmojiPickerData.json')).default
init({data})
} catch (e) {}
} catch (e) {
// no-op
}
}, [])
if (immediate) preload()
return preload
+1 -1
View File
@@ -95,7 +95,7 @@ export function ProfileFeedgens({
} else if (isEmpty) {
items = items.concat([EMPTY])
} else if (data?.pages) {
for (const page of data?.pages) {
for (const page of data.pages) {
items = items.concat(page.feeds)
}
} else if (isError && !isEmpty) {
@@ -191,7 +191,7 @@ const ImageItem = ({
.onEnd(() => {
'worklet'
// Commit just the pinch.
let t = createTransform()
const t = createTransform()
prependPinch(
t,
pinchScale.get(),
@@ -220,7 +220,7 @@ const ImageItem = ({
}
const nextPanTranslation = {x: e.translationX, y: e.translationY}
let t = createTransform()
const t = createTransform()
prependPan(t, nextPanTranslation)
prependPinch(
t,
@@ -239,7 +239,7 @@ const ImageItem = ({
.onEnd(() => {
'worklet'
// Commit just the pan.
let t = createTransform()
const t = createTransform()
prependPan(t, panTranslation.get())
prependTransform(t, committedTransform.get())
applyRounding(t)
@@ -265,7 +265,7 @@ const ImageItem = ({
const [, , committedScale] = readTransform(committedTransform.get())
if (committedScale !== 1) {
// Go back to 1:1 using the identity vector.
let t = createTransform()
const t = createTransform()
committedTransform.set(withClampedSpring(t))
return
}
@@ -317,7 +317,7 @@ const ImageItem = ({
const {scaleAndMoveTransform, isHidden} = transforms.get()
// Apply the active adjustments on top of the committed transform before the gestures.
// This is matrix multiplication, so operations are applied in the reverse order.
let t = createTransform()
const t = createTransform()
prependPan(t, panTranslation.get())
prependPinch(t, pinchScale.get(), pinchOrigin.get(), pinchTranslation.get())
prependTransform(t, committedTransform.get())
@@ -308,8 +308,8 @@ const getZoomRectAfterDoubleTap = (
// Next, we'll be calculating the rectangle to "zoom into" in screen coordinates.
// We already know the zoom level, so this gives us the rectangle size.
let rectWidth = screenSize.width / zoom
let rectHeight = screenSize.height / zoom
const rectWidth = screenSize.width / zoom
const rectHeight = screenSize.height / zoom
// Before we settle on the zoomed rect, figure out the safe area it has to be inside.
// We don't want to introduce new black bars or make existing black bars unbalanced.
+1 -1
View File
@@ -95,7 +95,7 @@ export function ProfileLists({
} else if (isEmpty) {
items = items.concat([EMPTY])
} else if (data?.pages) {
for (const page of data?.pages) {
for (const page of data.pages) {
items = items.concat(page.lists)
}
} else if (isError && !isEmpty) {
@@ -76,7 +76,7 @@ export function NotificationFeed({
if (isEmpty) {
arr = arr.concat([EMPTY_FEED_ITEM])
} else if (data) {
for (const page of data?.pages) {
for (const page of data.pages) {
arr = arr.concat(page.items)
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ export function Pager({
// case we should preserve and restore scroll), or if it is somewhere below in the
// viewport (in which case a scroll jump would be jarring). We determine this by
// measuring where the "anchor" element is (which we place just above the tabbar).
let anchorTop = anchorRef.current
const anchorTop = anchorRef.current
? (anchorRef.current as Element).getBoundingClientRect().top
: -scrollY // If there's no anchor, treat the top of the page as one.
const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
+5 -5
View File
@@ -333,14 +333,14 @@ let PostFeed = ({
}, [enabled, isEmpty, disablePoll, checkForNew])
useEffect(() => {
let cleanup1: () => void | undefined, cleanup2: () => void | undefined
const subscription = AppState.addEventListener('change', nextAppState => {
// check for new on app foreground
if (nextAppState === 'active') {
checkForNew()
}
})
cleanup1 = () => subscription.remove()
const cleanup1 = () => subscription.remove()
let cleanup2: (() => void) | undefined
if (pollInterval) {
// check for new on interval
const i = setInterval(() => {
@@ -349,7 +349,7 @@ let PostFeed = ({
cleanup2 = () => clearInterval(i)
}
return () => {
cleanup1?.()
cleanup1()
cleanup2?.()
}
}, [pollInterval, checkForNew])
@@ -402,7 +402,7 @@ let PostFeed = ({
feedKind = 'profile'
}
let arr: FeedRow[] = []
const arr: FeedRow[] = []
if (KNOWN_SHUTDOWN_FEEDS.includes(feedUriOrActorDid)) {
arr.push({
type: 'feedShutdownMsg',
@@ -481,7 +481,7 @@ let PostFeed = ({
})
}
} else {
for (const page of data?.pages) {
for (const page of data.pages) {
for (const slice of page.slices) {
sliceIndex++
+1 -1
View File
@@ -422,7 +422,7 @@ function useResizeObserver(
}
const resizeObserver = new ResizeObserver(entries => {
batchedUpdates(() => {
for (let entry of entries) {
for (const entry of entries) {
const rect = entry.contentRect
handleResize(rect.width, rect.height)
}
+4
View File
@@ -179,14 +179,18 @@ const emitter = new EventEmitter()
if (isWeb) {
const originalScroll = window.scroll
window.scroll = function () {
emitter.emit('forced-scroll')
// eslint-disable-next-line prefer-rest-params
return originalScroll.apply(this, arguments as any)
}
const originalScrollTo = window.scrollTo
window.scrollTo = function () {
emitter.emit('forced-scroll')
// eslint-disable-next-line prefer-rest-params
return originalScrollTo.apply(this, arguments as any)
}
}
+6 -2
View File
@@ -153,9 +153,13 @@ 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],
)
+3 -1
View File
@@ -53,7 +53,9 @@ export function ListsScreen({}: Props) {
name: urip.hostname,
rkey: urip.rkey,
})
} catch {}
} catch {
// no-op
}
},
[navigation],
)
+3 -1
View File
@@ -53,7 +53,9 @@ export function ModerationModlistsScreen({}: Props) {
name: urip.hostname,
rkey: urip.rkey,
})
} catch {}
} catch {
// no-op
}
},
[navigation],
)

Some files were not shown because too many files have changed in this diff Show More