looser eslint rules (#63511)

Turn off 2 low-value eslint rules that add a lot of noise:

- `@typescript-eslint/no-explicit-any` because if you mean to use `any`
then you probably mean to. We still have eslint warnings for `any`
member access, which is indeed riskier.
- `@typescript-eslint/no-non-null-assertion` because if you type `!`
then you mean it.

Both of these have hundreds of warnings in our current codebase, so this
significantly reduces the eslint noise and makes it so that the
higher-value eslint rules are more noticeable.
This commit is contained in:
Quinn Slack 2024-06-27 01:42:51 -07:00 committed by GitHub
parent 74f030b3ca
commit 7e7de5ffb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 35 additions and 69 deletions

View File

@ -90,6 +90,8 @@ const config = {
'@typescript-eslint/no-misused-promises': 'off',
'@typescript-eslint/no-unnecessary-qualifier': 'off',
'@typescript-eslint/no-unused-vars': 'off', // also duplicated by tsconfig noUnused{Locals,Parameters}
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'etc/no-deprecated': 'off',
'no-restricted-imports': [

View File

@ -1,20 +1,20 @@
import { basename } from 'path'
import {
autocompletion,
startCompletion,
completionKeymap,
type CompletionResult,
type Completion,
snippet,
type CompletionSource,
acceptCompletion,
selectedCompletion,
autocompletion,
completionKeymap,
currentCompletions,
selectedCompletion,
setSelectedCompletion,
snippet,
startCompletion,
type Completion,
type CompletionResult,
type CompletionSource,
} from '@codemirror/autocomplete'
import { type Extension, Prec } from '@codemirror/state'
import { keymap, EditorView } from '@codemirror/view'
import { Prec, type Extension } from '@codemirror/state'
import { EditorView, keymap } from '@codemirror/view'
import {
mdiCodeArray,
mdiCodeBraces,
@ -56,8 +56,8 @@ import {
regexInsertText,
repositoryInsertText,
} from '@sourcegraph/shared/src/search/query/completion-utils'
import { decorate, type DecoratedToken, toDecoration } from '@sourcegraph/shared/src/search/query/decoratedToken'
import { FILTERS, type FilterType, filterTypeKeys, resolveFilter } from '@sourcegraph/shared/src/search/query/filters'
import { decorate, toDecoration, type DecoratedToken } from '@sourcegraph/shared/src/search/query/decoratedToken'
import { FILTERS, filterTypeKeys, resolveFilter, type FilterType } from '@sourcegraph/shared/src/search/query/filters'
import { getSuggestionQuery } from '@sourcegraph/shared/src/search/query/providers-utils'
import { scanSearchQuery } from '@sourcegraph/shared/src/search/query/scanner'
import type { Filter, Token } from '@sourcegraph/shared/src/search/query/token'
@ -175,7 +175,7 @@ export function searchQueryAutocompletion(
// This renders the completion icon
{
render(completion) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (enableJumpToSuggestion && navigate && (completion as any)?.url) {
return createSVGIcon(mdiLightningBoltCircle, '')
}
@ -265,7 +265,7 @@ export function searchQueryAutocompletion(
key: 'Enter',
run(view) {
const selected = selectedCompletion(view.state)
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const url = (selected as any)?.url
if (enableJumpToSuggestion && navigate && typeof url === 'string') {
navigate(url)

View File

@ -18,7 +18,6 @@ iframeNode.addEventListener('load', () => {
// Detect dark or light mode preference
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
setDarkMode(true)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
document.body.parentElement!.className = 'dark'
}

View File

@ -44,7 +44,6 @@ const ColorPalette = ({
}
for (const [key, value] of Object.entries(light)) {
if (colors.has(key)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
colors.get(key)!.light = value
} else {
colors.set(key, { dark: null, light: value })

View File

@ -2,7 +2,7 @@ import { basename, dirname, extname } from 'path'
import type { Context } from '@sourcegraph/template-parser'
import { type SettingsCascadeOrError, isSettingsValid } from '../../../../settings/settings'
import { isSettingsValid, type SettingsCascadeOrError } from '../../../../settings/settings'
import type { ViewerWithPartialModel } from '../../../viewerTypes'
export type ContributionScope =
@ -15,7 +15,6 @@ export type ContributionScope =
/**
* Compute the full context data based on the environment, including keys such as `resource.uri`.
*
* @param activeEditor the currently visible editor (if any)
* @param settings the settings for the viewer
* @param context manually specified context keys
@ -69,13 +68,13 @@ export function computeContext<T>(
// See above for why we disable eslint rules related to `any`.
//
data['component.selections'] = component.selections as any // eslint-disable-line @typescript-eslint/no-explicit-any
data['component.selections'] = component.selections as any
if (component.selections.length > 0) {
data['component.selection'] = (component.selections[0] || null) as any // eslint-disable-line @typescript-eslint/no-explicit-any
data['component.selection'] = (component.selections[0] || null) as any
data['component.selection.start'] = (component.selections[0] ? component.selections[0].start : null) as any // eslint-disable-line @typescript-eslint/no-explicit-any
data['component.selection.start'] = (component.selections[0] ? component.selections[0].start : null) as any
data['component.selection.end'] = (component.selections[0] ? component.selections[0].end : null) as any // eslint-disable-line @typescript-eslint/no-explicit-any
data['component.selection.end'] = (component.selections[0] ? component.selections[0].end : null) as any
data['component.selection.start.line'] = component.selections[0] ? component.selections[0].start.line : null
data['component.selection.start.character'] = component.selections[0]
? component.selections[0].start.character

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import pTimeout from 'p-timeout'
import { Subject } from 'rxjs'
import { describe, expect, it, test } from 'vitest'

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { lastValueFrom, type Observable, type Unsubscribable } from 'rxjs'
import type { GraphQLResult } from '@sourcegraph/http-client'

View File

@ -62,7 +62,6 @@ interface RangeWindow {
*/
export function makeRangeWindowFactory(
hasImplementationsField: boolean,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryGraphQL: QueryGraphQLFn<any> = sgQueryGraphQL
): Promise<RangeWindowFactoryFn> {
const disabled = sourcegraph.getSetting<boolean>('codeIntel.disableRangeQueries')
@ -135,7 +134,6 @@ export async function findOverlappingWindows(
position: sourcegraph.Position,
rangeWindows: RangeWindow[],
hasImplementationsField: boolean,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryGraphQL: QueryGraphQLFn<any> = sgQueryGraphQL
): Promise<CodeIntelligenceRange[] | null> {
let index = -1

View File

@ -9,7 +9,6 @@ export const cache = <Arguments extends unknown[], V>(
return (...args) => {
const key = stringify(args)
if (lru.has(key)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lru.get(key)!
}
const value = func(...args)

View File

@ -1,21 +1,21 @@
import React, {
forwardRef,
type MutableRefObject,
type RefObject,
useEffect,
useImperativeHandle,
useMemo,
useRef,
type MutableRefObject,
type RefObject,
} from 'react'
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language'
import {
type ChangeSpec,
Compartment,
EditorState,
StateEffect,
type ChangeSpec,
type EditorStateConfig,
type Extension,
StateEffect,
} from '@codemirror/state'
import { EditorView } from '@codemirror/view'
import { tags } from '@lezer/highlight'
@ -26,7 +26,7 @@ if (process.env.INTEGRATION_TESTS) {
// Typecast "as any" is used to avoid TypeScript complaining about window
// not having this property. We decided that it's fine to use this in a test
// context
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
;(window as any).CodeMirrorFindFromDOM = (element: HTMLElement): ReturnType<typeof EditorView['findFromDOM']> =>
EditorView.findFromDOM(element)
}
@ -170,11 +170,10 @@ export function replaceValue(view: EditorView, newValue: string): ChangeSpec | u
* Use `useMemo` to compute the extension from some input:
*
* const extension = useCompartment(
* editorRef,
* useMemo(() => EditorView.darkTheme(isLightTheme === false), [isLightTheme])
* editorRef,
* useMemo(() => EditorView.darkTheme(isLightTheme === false), [isLightTheme])
* )
* const editor = useCodeMirror(..., ..., extension)
*
* @param editorRef - Ref object to the editor instance
* @param extension - the dynamic extension(s) to add to the editor
* @returns a compartmentalized extension

View File

@ -5,7 +5,6 @@ const originalPackageJson = fs.readFileSync('package.json').toString()
try {
childProcess.execSync('pnpm build-inline-extensions && pnpm build', { stdio: 'inherit' })
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const packageJson: any = JSON.parse(originalPackageJson)
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
packageJson.name = 'sourcegraph'

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import childProcess from 'child_process'

View File

@ -29,7 +29,6 @@ export const requestGraphQLFromVSCode = async <R, V = object>(
// Debt: intercepted requests in integration tests
// have 0 status codes, so don't check in test environment.
const checkFunction = process.env.IS_TEST ? <T>(value: T): T => value : checkOk
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const options: any = {
agent: getProxyAgent(),
body: JSON.stringify({

View File

@ -211,7 +211,6 @@ export function getSourcegraphFileUrl(
function getRemoteUrlReplacements(): Record<string, string> {
// has default value
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const replacements = vscode.workspace
.getConfiguration('sourcegraph')
.get<Record<string, string>>('remoteUrlReplacements')!
@ -220,7 +219,6 @@ function getRemoteUrlReplacements(): Record<string, string> {
export function getDefaultBranch(): string {
// has default value
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return vscode.workspace.getConfiguration('sourcegraph').get<string>('defaultBranch')!
}

View File

@ -3,7 +3,6 @@ import vscode from 'vscode'
const outputChannel = vscode.window.createOutputChannel('Sourcegraph')
export const log = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: (what: string, error?: any): void => {
outputChannel.appendLine(`ERROR ${errorMessage(what, error)}`)
},
@ -21,8 +20,6 @@ export const log = {
outputChannel.appendLine(message)
},
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function errorMessage(what: string, error?: any): string {
const errorMessage =
error instanceof Error

View File

@ -60,7 +60,6 @@ export const FileDiffNode: React.FunctionComponent<React.PropsWithChildren<FileD
// By process of elimination (that TypeScript is unfortunately unable to infer, except
// by reorganizing this code in a way that's much more complex to humans), node.oldPath
// is non-null.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
path = <span title={node.oldPath!}>{node.oldPath}</span>
}

View File

@ -1,4 +1,4 @@
import { type Dispatch, type SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState, type Dispatch, type SetStateAction } from 'react'
import type { ApolloClient } from '@apollo/client'
import type * as H from 'history'
@ -151,7 +151,7 @@ export class FuzzyTabs {
public entries(): [FuzzyTabKey, Tab][] {
const result: [FuzzyTabKey, Tab][] = []
for (const key of Object.keys(this.underlying)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const value = (this.underlying as any)[key as keyof Tab] as Tab
if (value.isEnabled) {
result.push([key as FuzzyTabKey, value])

View File

@ -113,7 +113,6 @@ const buildWorkspacesQuery =
// the snapshot, since the timer in ExecuteBatchSpecPage is live in that case.
const EXECUTING_BATCH_SPEC_WITH_END_TIME = {
...EXECUTING_BATCH_SPEC,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
finishedAt: addMinutes(Date.parse(EXECUTING_BATCH_SPEC.startedAt!), 15).toISOString(),
}
@ -141,7 +140,6 @@ export const Executing: StoryFn = () => (
// the snapshot, since the timer in the workspace details section is live in that case.
const PROCESSING_WORKSPACE_WITH_END_TIMES = {
...PROCESSING_WORKSPACE,
/* eslint-disable @typescript-eslint/no-non-null-assertion */
finishedAt: addMinutes(Date.parse(PROCESSING_WORKSPACE.startedAt!), 15).toISOString(),
steps: [
PROCESSING_WORKSPACE.steps[0]!,
@ -151,7 +149,6 @@ const PROCESSING_WORKSPACE_WITH_END_TIMES = {
},
PROCESSING_WORKSPACE.steps[2]!,
],
/* eslint-enable @typescript-eslint/no-non-null-assertion */
}
export const ExecuteWithAWorkspaceSelected: StoryFn = () => (

View File

@ -74,7 +74,6 @@ const MOCKS = new WildcardMockLink([
])
const queryWorkspacesList: typeof _queryWorkspacesList = () =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
of(mockWorkspaces(50).node.workspaceResolution!.workspaces)
const queryEmptyFileDiffs = () => of({ totalCount: 0, pageInfo: { endCursor: null, hasNextPage: false }, nodes: [] })

View File

@ -17,7 +17,6 @@ const config: Meta = {
export default config
const queryWorkspacesList: typeof _queryWorkspacesList = () =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
of(mockWorkspaces(50).node.workspaceResolution!.workspaces)
export const WorkspacesStory: StoryFn = () => (

View File

@ -19,7 +19,6 @@ const actionableBatchSpecStates = [
type ActionableBatchSpecState = typeof actionableBatchSpecStates[number]
const isLatestExecutionActionable = (executionState: BatchSpecState): executionState is ActionableBatchSpecState =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
actionableBatchSpecStates.includes(executionState as any)
export interface BatchChangeStatePillProps {

View File

@ -408,7 +408,6 @@ const cache = <Arguments extends unknown[], V>(
return (...args) => {
const key = stringify(args)
if (lru.has(key)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lru.get(key)!
}
const value = func(...args)

View File

@ -4,7 +4,7 @@ import type { Page } from 'puppeteer'
import type { SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations'
import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import { type Driver, percySnapshot } from '@sourcegraph/shared/src/testing/driver'
import { percySnapshot, type Driver } from '@sourcegraph/shared/src/testing/driver'
import { readEnvironmentBoolean } from '@sourcegraph/shared/src/testing/utils'
import type { WebGraphQlOperations } from '../graphql-operations'
@ -245,7 +245,7 @@ const editors: Record<Editor, (driver: Driver, rootSelector: string) => EditorAP
// Typecast "as any" is used to avoid TypeScript complaining
// about window not having this property. We decided that
// it's fine to use this in a test context
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const fromDOM = (window as any).CodeMirrorFindFromDOM as
| typeof EditorView['findFromDOM']
| undefined

View File

@ -1,4 +1,4 @@
// Use passive event listeners by default to improve perf and remove Chrome warning.
// https://github.com/angular/angular/blob/main/aio/content/guide/event-binding.md#binding-to-passive-events
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
;(window as any).__zone_symbol__PASSIVE_EVENTS = ['scroll', 'touchstart', 'touchmove']

View File

@ -44,7 +44,6 @@ const PROPS: React.ComponentProps<typeof GlobalNavbar> = {
describe('GlobalNavbar', () => {
if (!window.context) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
window.context = {} as any
}
const origCodeSearchEnabledOnInstance = window.context?.codeSearchEnabledOnInstance ?? true

View File

@ -29,7 +29,6 @@ const PROPS: React.ComponentProps<typeof NewGlobalNavigationBar> = {
describe('NewGlobalNavigationBar', () => {
if (!window.context) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
window.context = {} as any
}
const origCodeSearchEnabledOnInstance = window.context?.codeSearchEnabledOnInstance ?? true

View File

@ -127,7 +127,6 @@ async function createTestUser(
await driver.page.keyboard.type(testUserPassword)
await driver.page.keyboard.down(Key.Enter)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await driver.page.waitForFunction(() => document.body.textContent!.includes('Your password was reset'))
}

View File

@ -1402,7 +1402,6 @@ describe('searchResultsToFileContent', () => {
})
test('returns correct content for repo match with enableRepositoryMetadata=true', () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const [, results] = data.find(([searchType]) => searchType === 'repo')!
expect(searchResultsToFileContent(results, sourcegraphURL, true)).toEqual(
'Match type,Repository,Repository external URL,Repository metadata,Repository metadata JSON\nrepo,github.com/lorenzodifuccia/safaribooks,http://localhost:3443/github.com/lorenzodifuccia/safaribooks,"oss\ndeprecated\nsome"",non-standard-key:value","{""oss"":null,""deprecated"":null,""some\\"",non-standard-key"":""value""}"\nrepo,github.com/rfletcher/safari-json-formatter,http://localhost:3443/github.com/rfletcher/safari-json-formatter,,{}\nrepo,github.com/AdguardTeam/AdGuardForSafari,http://localhost:3443/github.com/AdguardTeam/AdGuardForSafari,,{}\nrepo,github.com/kishikawakatsumi/SourceKitForSafari,http://localhost:3443/github.com/kishikawakatsumi/SourceKitForSafari,,{}\nrepo,github.com/shaojiankui/iOS-UDID-Safari,http://localhost:3443/github.com/shaojiankui/iOS-UDID-Safari,,{}'

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useRef, useCallback } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useIsMounted } from '.'
@ -10,15 +10,10 @@ interface UseIntervalControls {
/**
* Custom hook for controlling the repeated execution of a function on an interval.
*
* @param callback The function to call on the execution interval
* @param interval The interval at which the function should be re-invoked, in ms
*/
export const useInterval = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: () => any,
interval: number
): UseIntervalControls => {
export const useInterval = (callback: () => any, interval: number): UseIntervalControls => {
const [internalInterval, setInternalInterval] = useState(interval)
// The function will continue to re-execute so long as there is a positive interval value.
const hasInterval = internalInterval > 0

View File

@ -7,7 +7,6 @@ export type ForwardReferenceExoticComponent<E, OwnProps> = React.ForwardRefExoti
>
type PropsWithChildren<P> = P &
// eslint-disable-next-line @typescript-eslint/no-explicit-any
({ children?: React.ReactNode | undefined } | { children: (...args: any[]) => React.ReactNode })
export interface ForwardReferenceComponent<

View File

@ -52,7 +52,6 @@ function anyOf<T0, T1 extends T0, T2 extends Exclude<T0, T1>>(
t1: (value: T0) => value is T1,
t2: (value: Exclude<T0, T1>) => value is T2
): (value: T0) => value is T1 | T2
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function anyOf(...typeGuards: any[]): any {
return (value: unknown) => typeGuards.some((guard: (value: unknown) => boolean) => guard(value))
}