From 427f3a848d3bdc2e9c4b6b7cb2b8699511339ee2 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 10 Apr 2024 19:36:37 +0100 Subject: [PATCH] [Statsig] Typecheck gates (#3467) * Typecheck gates * Lint against untyped useGate() * Alphabetic --- .eslintrc.js | 1 + eslint/index.js | 1 + eslint/use-typed-gates.js | 31 ++++++++++++++++++++++++++++++ src/lib/statsig/gates.ts | 11 ++++++++--- src/lib/statsig/statsig.tsx | 3 ++- src/view/screens/Search/Search.tsx | 4 ++-- 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 eslint/use-typed-gates.js diff --git a/.eslintrc.js b/.eslintrc.js index a999fd24..29136d5d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,6 +31,7 @@ module.exports = { }, }, ], + 'bsky-internal/use-typed-gates': 'error', 'simple-import-sort/imports': [ 'warn', { diff --git a/eslint/index.js b/eslint/index.js index daf5bd81..bb31a942 100644 --- a/eslint/index.js +++ b/eslint/index.js @@ -3,5 +3,6 @@ module.exports = { rules: { 'avoid-unwrapped-text': require('./avoid-unwrapped-text'), + 'use-typed-gates': require('./use-typed-gates'), }, } diff --git a/eslint/use-typed-gates.js b/eslint/use-typed-gates.js new file mode 100644 index 00000000..3625a7da --- /dev/null +++ b/eslint/use-typed-gates.js @@ -0,0 +1,31 @@ +'use strict' + +exports.create = function create(context) { + return { + ImportSpecifier(node) { + if ( + !node.local || + node.local.type !== 'Identifier' || + node.local.name !== 'useGate' + ) { + return + } + if ( + node.parent.type !== 'ImportDeclaration' || + !node.parent.source || + node.parent.source.type !== 'Literal' + ) { + return + } + const source = node.parent.source.value + if (source.startsWith('.') || source.startsWith('#')) { + return + } + context.report({ + node, + message: + "Use useGate() from '#/lib/statsig/statsig' instead of the one on npm.", + }) + }, + } +} diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts index fce25cb8..c755ad43 100644 --- a/src/lib/statsig/gates.ts +++ b/src/lib/statsig/gates.ts @@ -1,3 +1,8 @@ -import {useGate} from './statsig' - -export const useNewSearchGate = () => useGate('new_search') +export type Gate = + // Keep this alphabetic please. + | 'autoexpand_suggestions_on_profile_follow' + | 'disable_min_shell_on_foregrounding' + | 'disable_poll_on_discover' + | 'new_search' + | 'show_follow_back_label' + | 'start_session_with_following' diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx index c1646162..18b58d16 100644 --- a/src/lib/statsig/statsig.tsx +++ b/src/lib/statsig/statsig.tsx @@ -11,6 +11,7 @@ import { import {logger} from '#/logger' import {useSession} from '../../state/session' import {LogEvents} from './events' +import {Gate} from './gates' export type {LogEvents} @@ -69,7 +70,7 @@ export function logEvent( } } -export function useGate(gateName: string) { +export function useGate(gateName: Gate): boolean { const {isLoading, value} = useStatsigGate(gateName) if (isLoading) { // This should not happen because of waitForInitialization={true}. diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index fe7a5223..0f24252c 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -22,7 +22,7 @@ import {HITSLOP_10} from '#/lib/constants' import {usePalette} from '#/lib/hooks/usePalette' import {MagnifyingGlassIcon} from '#/lib/icons' import {NavigationProp} from '#/lib/routes/types' -import {useNewSearchGate} from '#/lib/statsig/gates' +import {useGate} from '#/lib/statsig/statsig' import {augmentSearchQuery} from '#/lib/strings/helpers' import {s} from '#/lib/styles' import {logger} from '#/logger' @@ -337,7 +337,7 @@ export function SearchScreenInner({ const {isDesktop} = useWebMediaQueries() const {_} = useLingui() - const isNewSearch = useNewSearchGate() + const isNewSearch = useGate('new_search') const onPageSelected = React.useCallback( (index: number) => {