tangled mirror of catsky-🐱 Soothing soft social-app fork with all the niche toggles! (Unofficial); for issues and PRs please put them on github:NekoDrone/catsky-social

Tighten up eslint rule to catch unused `const {_} = useLingui()` (#9122)

* tighten eslint config to catch unused `useLingui`s

* fix now-invalid uses of _

* remove unused function that produces a ton of eslint warnings

* upgrade react compiler plugin

authored by samuel.fm and committed by GitHub 77bf49f2 02b189a4

+1 -1
.eslintrc.js
··· 89 89 'no-unused-vars': 'off', 90 90 '@typescript-eslint/no-unused-vars': [ 91 91 'error', 92 - {argsIgnorePattern: '^_', varsIgnorePattern: '^_'}, 92 + {argsIgnorePattern: '^_', varsIgnorePattern: '^_.+'}, 93 93 ], 94 94 '@typescript-eslint/consistent-type-imports': [ 95 95 'warn',
+2 -2
package.json
··· 246 246 "babel-jest": "^29.7.0", 247 247 "babel-plugin-macros": "^3.1.0", 248 248 "babel-plugin-module-resolver": "^5.0.2", 249 - "babel-plugin-react-compiler": "^19.1.0-rc.1", 249 + "babel-plugin-react-compiler": "^19.1.0-rc.3", 250 250 "babel-preset-expo": "~54.0.0", 251 251 "eslint": "^8.19.0", 252 252 "eslint-plugin-bsky-internal": "link:./eslint", ··· 254 254 "eslint-plugin-import": "^2.31.0", 255 255 "eslint-plugin-lingui": "^0.2.0", 256 256 "eslint-plugin-react": "^7.33.2", 257 - "eslint-plugin-react-compiler": "^19.1.0-rc.1", 257 + "eslint-plugin-react-compiler": "^19.1.0-rc.2", 258 258 "eslint-plugin-react-native-a11y": "^3.3.0", 259 259 "eslint-plugin-simple-import-sort": "^12.0.0", 260 260 "file-loader": "6.2.0",
-1
src/components/PostControls/ShareMenu/RecentChats.tsx
··· 24 24 25 25 export function RecentChats({postUri}: {postUri: string}) { 26 26 const control = useDialogContext() 27 - const {_} = useLingui() 28 27 const {currentAccount} = useSession() 29 28 const {data} = useListConvosQuery({status: 'accepted'}) 30 29 const convos = data?.pages[0]?.convos?.slice(0, 10)
-1
src/components/dialogs/StarterPackDialog.tsx
··· 47 47 targetDid, 48 48 enabled, 49 49 }: StarterPackDialogProps) { 50 - const {_} = useLingui() 51 50 const navigation = useNavigation<NavigationProp>() 52 51 const requireEmailVerification = useRequireEmailVerification() 53 52
+1 -1
src/lib/hooks/useIntentHandler.ts
··· 51 51 } 52 52 53 53 const urlp = new URL(url) 54 - const [_, intent, intentType] = urlp.pathname.split('/') 54 + const [__, intent, intentType] = urlp.pathname.split('/') 55 55 56 56 // On native, our links look like bluesky://intent/SomeIntent, so we have to check the hostname for the 57 57 // intent check. On web, we have to check the first part of the path since we have an actual hostname
+11 -11
src/lib/strings/embed-player.ts
··· 105 105 urlp.hostname === 'm.youtube.com' || 106 106 urlp.hostname === 'music.youtube.com' 107 107 ) { 108 - const [_, page, shortOrLiveVideoId] = urlp.pathname.split('/') 108 + const [__, page, shortOrLiveVideoId] = urlp.pathname.split('/') 109 109 110 110 const isShorts = page === 'shorts' 111 111 const isLive = page === 'live' ··· 137 137 window.location.hostname 138 138 : 'localhost' 139 139 140 - const [_, channelOrVideo, clipOrId, id] = urlp.pathname.split('/') 140 + const [__, channelOrVideo, clipOrId, id] = urlp.pathname.split('/') 141 141 142 142 if (channelOrVideo === 'videos') { 143 143 return { ··· 162 162 163 163 // spotify 164 164 if (urlp.hostname === 'open.spotify.com') { 165 - const [_, typeOrLocale, idOrType, id] = urlp.pathname.split('/') 165 + const [__, typeOrLocale, idOrType, id] = urlp.pathname.split('/') 166 166 167 167 if (idOrType) { 168 168 if (typeOrLocale === 'playlist' || idOrType === 'playlist') { ··· 210 210 urlp.hostname === 'soundcloud.com' || 211 211 urlp.hostname === 'www.soundcloud.com' 212 212 ) { 213 - const [_, user, trackOrSets, set] = urlp.pathname.split('/') 213 + const [__, user, trackOrSets, set] = urlp.pathname.split('/') 214 214 215 215 if (user && trackOrSets) { 216 216 if (trackOrSets === 'sets' && set) { ··· 270 270 } 271 271 272 272 if (urlp.hostname === 'vimeo.com' || urlp.hostname === 'www.vimeo.com') { 273 - const [_, videoId] = urlp.pathname.split('/') 273 + const [__, videoId] = urlp.pathname.split('/') 274 274 if (videoId) { 275 275 return { 276 276 type: 'vimeo_video', ··· 281 281 } 282 282 283 283 if (urlp.hostname === 'giphy.com' || urlp.hostname === 'www.giphy.com') { 284 - const [_, gifs, nameAndId] = urlp.pathname.split('/') 284 + const [__, gifs, nameAndId] = urlp.pathname.split('/') 285 285 286 286 /* 287 287 * nameAndId is a string that consists of the name (dash separated) and the id of the gif (the last part of the name) ··· 309 309 // These can include (presumably) a tracking id in the path name, so we have to check for that as well 310 310 if (giphyRegex.test(urlp.hostname)) { 311 311 // We can link directly to the gif, if its a proper link 312 - const [_, media, trackingOrId, idOrFilename, filename] = 312 + const [__, media, trackingOrId, idOrFilename, filename] = 313 313 urlp.pathname.split('/') 314 314 315 315 if (media === 'media') { ··· 338 338 // Finally, we should see if it is a link to i.giphy.com. These links don't necessarily end in .gif but can also 339 339 // be .webp 340 340 if (urlp.hostname === 'i.giphy.com' || urlp.hostname === 'www.i.giphy.com') { 341 - const [_, mediaOrFilename, filename] = urlp.pathname.split('/') 341 + const [__, mediaOrFilename, filename] = urlp.pathname.split('/') 342 342 343 343 if (mediaOrFilename === 'media' && filename) { 344 344 const gifId = filename.split('.')[0] ··· 389 389 const path_components = urlp.pathname.slice(1, i + 1).split('/') 390 390 if (path_components.length === 4) { 391 391 // discard username - it's not relevant 392 - const [photos, _, albums, id] = path_components 392 + const [photos, __, albums, id] = path_components 393 393 if (photos === 'photos' && albums === 'albums') { 394 394 // this at least has the shape of a valid photo-album URL! 395 395 return { ··· 417 417 // link shortened flickr path 418 418 if (urlp.hostname === 'flic.kr') { 419 419 const b58alph = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' 420 - let [_, type, idBase58Enc] = urlp.pathname.split('/') 420 + let [__, type, idBase58Enc] = urlp.pathname.split('/') 421 421 let id = 0n 422 422 for (const char of idBase58Enc) { 423 423 const nextIdx = b58alph.indexOf(char) ··· 528 528 return {success: false} 529 529 } 530 530 531 - let [_, id, filename] = urlp.pathname.split('/') 531 + let [__, id, filename] = urlp.pathname.split('/') 532 532 533 533 if (!id || !filename) { 534 534 return {success: false}
-17
src/lib/strings/helpers.ts
··· 62 62 }, [splitter, maxCount, text]) 63 63 } 64 64 65 - // https://stackoverflow.com/a/52171480 66 - export function toHashCode(str: string, seed = 0): number { 67 - let h1 = 0xdeadbeef ^ seed, 68 - h2 = 0x41c6ce57 ^ seed 69 - for (let i = 0, ch; i < str.length; i++) { 70 - ch = str.charCodeAt(i) 71 - h1 = Math.imul(h1 ^ ch, 2654435761) 72 - h2 = Math.imul(h2 ^ ch, 1597334677) 73 - } 74 - h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) 75 - h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909) 76 - h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) 77 - h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909) 78 - 79 - return 4294967296 * (2097151 & h2) + (h1 >>> 0) 80 - } 81 - 82 65 export function countLines(str: string | undefined): number { 83 66 if (!str) return 0 84 67 return str.match(/\n/g)?.length ?? 0
+1 -1
src/lib/strings/starter-pack.ts
··· 46 46 } else { 47 47 const url = new URL(uri) 48 48 const parts = url.pathname.split('/') 49 - const [_, path, name, rkey] = parts 49 + const [__, path, name, rkey] = parts 50 50 51 51 if (parts.length !== 4) return null 52 52 if (path !== 'starter-pack' && path !== 'start') return null
-2
src/screens/Onboarding/StepFinished.tsx
··· 69 69 import * as bsky from '#/types/bsky' 70 70 71 71 export function StepFinished() { 72 - const {_} = useLingui() 73 72 const {state, dispatch} = useContext(Context) 74 73 const onboardDispatch = useOnboardingDispatch() 75 74 const [saving, setSaving] = useState(false) ··· 495 494 496 495 function Dot({active}: {active: boolean}) { 497 496 const t = useTheme() 498 - const {_} = useLingui() 499 497 500 498 return ( 501 499 <View
-1
src/screens/Search/Shell.tsx
··· 428 428 const {hasSession} = useSession() 429 429 const {gtTablet} = useBreakpoints() 430 430 const [activeTab, setActiveTab] = useState(0) 431 - const {_} = useLingui() 432 431 433 432 const onPageSelected = useCallback( 434 433 (index: number) => {
-1
src/screens/Search/modules/ExploreTrendingVideos.tsx
··· 31 31 } 32 32 33 33 export function ExploreTrendingVideos() { 34 - const {_} = useLingui() 35 34 const gutters = useGutters([0, 'base']) 36 35 const {data, isLoading, error} = usePostFeedQuery(FEED_DESC, FEED_PARAMS) 37 36
+5 -5
src/state/queries/post-feed.ts
··· 492 492 } 493 493 } 494 494 } else if (feedDesc.startsWith('author')) { 495 - const [_, actor, filter] = feedDesc.split('|') 495 + const [__, actor, filter] = feedDesc.split('|') 496 496 return new AuthorFeedAPI({agent, feedParams: {actor, filter}}) 497 497 } else if (feedDesc.startsWith('likes')) { 498 - const [_, actor] = feedDesc.split('|') 498 + const [__, actor] = feedDesc.split('|') 499 499 return new LikesFeedAPI({agent, feedParams: {actor}}) 500 500 } else if (feedDesc.startsWith('feedgen')) { 501 - const [_, feed] = feedDesc.split('|') 501 + const [__, feed] = feedDesc.split('|') 502 502 return new CustomFeedAPI({ 503 503 agent, 504 504 feedParams: {feed}, 505 505 userInterests, 506 506 }) 507 507 } else if (feedDesc.startsWith('list')) { 508 - const [_, list] = feedDesc.split('|') 508 + const [__, list] = feedDesc.split('|') 509 509 return new ListFeedAPI({agent, feedParams: {list}}) 510 510 } else if (feedDesc.startsWith('posts')) { 511 - const [_, uriList] = feedDesc.split('|') 511 + const [__, uriList] = feedDesc.split('|') 512 512 return new PostListFeedAPI({agent, feedParams: {uris: uriList.split(',')}}) 513 513 } else if (feedDesc === 'demo') { 514 514 return new DemoFeedAPI({agent})
+1 -1
src/state/queries/trending/useGetSuggestedUsersQuery.ts
··· 69 69 queryClient.getQueriesData<AppBskyUnspeccedGetSuggestedUsers.OutputSchema>({ 70 70 queryKey: [getSuggestedUsersQueryKeyRoot], 71 71 }) 72 - for (const [_, response] of responses) { 72 + for (const [_key, response] of responses) { 73 73 if (!response) { 74 74 continue 75 75 }
-1
src/view/com/composer/photos/EditImageDialog.web.tsx
··· 116 116 }) { 117 117 const t = useTheme() 118 118 const [isDragging, setIsDragging] = useState(false) 119 - const {_} = useLingui() 120 119 const control = Dialog.useDialogContext() 121 120 122 121 const source = image.source
+1 -1
src/view/com/composer/text-input/web/TagDecorator.ts
··· 30 30 31 31 let match 32 32 while ((match = regex.exec(textContent))) { 33 - const [matchedString, _, tag] = match 33 + const [matchedString, __, tag] = match 34 34 35 35 if (!tag || tag.replace(TRAILING_PUNCTUATION_REGEX, '').length > 64) 36 36 continue
+1 -1
src/view/com/posts/PostFeedErrorMessage.tsx
··· 126 126 })[knownError], 127 127 [_l, knownError], 128 128 ) 129 - const [_, uri] = feedDesc.split('|') 129 + const [__, uri] = feedDesc.split('|') 130 130 const [ownerDid] = safeParseFeedgenUri(uri) 131 131 const removePromptControl = Prompt.usePromptControl() 132 132 const {mutateAsync: removeFeed} = useRemoveFeedMutation()
-2
src/view/screens/ModerationMutedAccounts.tsx
··· 2 2 import {type StyleProp, View, type ViewStyle} from 'react-native' 3 3 import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 4 4 import {Trans} from '@lingui/macro' 5 - import {useLingui} from '@lingui/react' 6 5 import {useFocusEffect} from '@react-navigation/native' 7 6 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 8 7 ··· 27 26 export function ModerationMutedAccounts({}: Props) { 28 27 const t = useTheme() 29 28 const moderationOpts = useModerationOpts() 30 - const {_} = useLingui() 31 29 const setMinimalShellMode = useSetMinimalShellMode() 32 30 33 31 const [isPTRing, setIsPTRing] = useState(false)
-2
src/view/screens/ProfileFeedLikedBy.tsx
··· 1 1 import {useCallback} from 'react' 2 2 import {Trans} from '@lingui/macro' 3 - import {useLingui} from '@lingui/react' 4 3 import {useFocusEffect} from '@react-navigation/native' 5 4 6 5 import { ··· 17 16 const setMinimalShellMode = useSetMinimalShellMode() 18 17 const {name, rkey} = route.params 19 18 const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey) 20 - const {_} = useLingui() 21 19 22 20 useFocusEffect( 23 21 useCallback(() => {
+5 -12
yarn.lock
··· 8603 8603 dependencies: 8604 8604 "@babel/helper-define-polyfill-provider" "^0.6.3" 8605 8605 8606 - babel-plugin-react-compiler@^19.1.0-rc.1: 8607 - version "19.1.0-rc.1" 8608 - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.1.0-rc.1.tgz#99d131be61017e40abbaedd98321069bf8b7e54a" 8609 - integrity sha512-M4fpG+Hfq5gWzsJeeMErdRokzg0fdJ8IAk+JDhfB/WLT+U3WwJWR8edphypJrk447/JEvYu6DBFwsTn10bMW4Q== 8610 - dependencies: 8611 - "@babel/types" "^7.26.0" 8612 - 8613 - babel-plugin-react-compiler@^19.1.0-rc.2: 8606 + babel-plugin-react-compiler@^19.1.0-rc.2, babel-plugin-react-compiler@^19.1.0-rc.3: 8614 8607 version "19.1.0-rc.3" 8615 8608 resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.1.0-rc.3.tgz#45e5a282a2460b3701971e5eb8310a90a7919022" 8616 8609 integrity sha512-mjRn69WuTz4adL0bXGx8Rsyk1086zFJeKmes6aK0xPuK3aaXmDJdLHqwKKMrpm6KAI1MCoUK72d2VeqQbu8YIA== ··· 10824 10817 dependencies: 10825 10818 "@typescript-eslint/utils" "^5.61.0" 10826 10819 10827 - eslint-plugin-react-compiler@^19.1.0-rc.1: 10828 - version "19.1.0-rc.1" 10829 - resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.1.0-rc.1.tgz#e974ba9541c9a4464d77723e0505b5742bc22e56" 10830 - integrity sha512-3umw5eqZXapBl7aQGmvcjheKhUbsElb9jTETxRZg371e1LG4EPs/zCHt2JzP+wNcdaZWzjU/R730zPUJblY2zw== 10820 + eslint-plugin-react-compiler@^19.1.0-rc.2: 10821 + version "19.1.0-rc.2" 10822 + resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.1.0-rc.2.tgz#83343e7422e00fa61e729af8e8468f0ddec37925" 10823 + integrity sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw== 10831 10824 dependencies: 10832 10825 "@babel/core" "^7.24.4" 10833 10826 "@babel/parser" "^7.24.4"