use @typescript-eslint projectService for faster eslint (#57851)

See https://github.com/typescript-eslint/typescript-eslint/pull/6754.

Also removes needless `.eslintrc.js` files (now that we can use the root `tsconfig.all.json` for linting and it's still fast enough).

Some of our eslint rules were unintentionally made ineffective in `client/web`, and this commit also re-enables them and in some cases suppresses the eslint warning where a fix is not urgent.
This commit is contained in:
Quinn Slack 2023-10-23 18:40:40 -07:00 committed by GitHub
parent 131ad5019f
commit 07f29c98d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 79 additions and 376 deletions

View File

@ -1,15 +0,0 @@
**/graphql-operations.ts
**/node_modules/**
out/
dist/
src/schema/*
src/graphql-operations.ts
GH2SG.bookmarklet.js
**/vendor/*.js
svelte.config.js
vite.config.ts
playwright.config.ts
.vscode-test
**/*.json
**/*.d.ts
eslint-relative-formatter.js

View File

@ -1,6 +1,32 @@
// @ts-check
// Use faster experimental way of doing multi-project TypeScript linting. See
// https://github.com/typescript-eslint/typescript-eslint/pull/6754.
process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER = 'true'
const config = {
root: true,
ignorePatterns: [
'**/graphql-operations.ts',
'**/node_modules/**',
'out/',
'dist/',
'src/schema/*',
'graphql-operations.ts',
'GH2SG.bookmarklet.js',
'**/vendor/*.js',
'svelte.config.js',
'vite.config.ts',
'playwright.config.ts',
'.vscode-test',
'**/*.json',
'**/*.d.ts',
'eslint-relative-formatter.js',
'jest.config.js',
'gulpfile.js',
'typedoc.js',
'bundlesize.config.js',
],
extends: ['@sourcegraph/eslint-config', 'plugin:storybook/recommended'],
env: {
browser: true,
@ -13,8 +39,8 @@ const config = {
ecmaFeatures: {
jsx: true,
},
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
project: __dirname + '/tsconfig.eslint.json',
EXPERIMENTAL_projectService: true,
project: __dirname + '/tsconfig.all.json',
},
settings: {
react: {
@ -119,6 +145,11 @@ See https://handbook.sourcegraph.com/community/faq#is-all-of-sourcegraph-open-so
message:
"Please don't import stuff from the 'out' directory. Its generated code. Remove the 'out/' part and you should be good go to.",
},
{
group: ['!@sourcegraph/cody-shared/*', '!@sourcegraph/cody-ui/*'],
message:
"Allowed imports from @sourcegraph/cody-* packages while those packages' APIs are being stabilized.",
},
],
},
],
@ -289,11 +320,31 @@ See https://handbook.sourcegraph.com/community/faq#is-all-of-sourcegraph-open-so
},
},
{
files: ['**/gulpfile.js', '**/story/**.tsx', '**/story/**.ts', '*.story.tsx'],
files: [
'**/dev/**/*.ts',
'**/gulpfile.js',
'**/story/**.tsx',
'**/story/**.ts',
'*.story.tsx',
'client/build-config/**',
],
rules: {
'no-console': 'off',
'no-sync': 'off',
},
},
{
files: ['client/vscode/**', 'client/browser/**', 'client/jetbrains/**'],
rules: {
'no-console': 'off',
},
},
// client/web
{
files: ['client/web/src/stores/**.ts', 'client/web/src/__mocks__/zustand.ts'],
rules: { 'no-restricted-imports': 'off' },
},
],
}

View File

@ -56,8 +56,8 @@ ts_config(
)
ts_config(
name = "tsconfig-eslint",
src = "tsconfig.eslint.json",
name = "tsconfig-all",
src = "tsconfig.all.json",
visibility = ["//visibility:public"],
deps = [
":tsconfig",
@ -179,7 +179,6 @@ js_library(
".eslintrc.js",
],
data = [
".eslintignore",
"package.json",
":eslint-relative-formatter",
],
@ -204,7 +203,7 @@ js_library(
":node_modules/eslint-plugin-unicorn",
":node_modules/eslint-plugin-unused-imports",
":node_modules/react", # required to resolve the react version for eslint-plugin-react
":tsconfig-eslint",
":tsconfig-all",
"//:node_modules/tslib",
],
)

View File

@ -1,29 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: [
...baseConfig.overrides,
{
files: 'dev/**/*.ts',
rules: {
'no-sync': 'off',
},
},
],
rules: {
'react/react-in-jsx-scope': 'off',
'react/jsx-filename-extension': [1, { extensions: ['.ts', '.tsx'] }],
'id-length': 'off',
'no-console': 'off',
'no-void': ['error', { allowAsStatement: true }],
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
'react/forbid-elements': 'off',
'unicorn/filename-case': 'off',
},
}

View File

@ -39,6 +39,7 @@ const appShellReady = (payload: AppShellReadyPayload): void => {
}
logger.log('app-shell-ready', payload)
launchWithSignInUrl(payload.sign_in_url).catch(error =>
// eslint-disable-next-line no-console
console.error(`failed to launch with sign-in URL: ${error}`)
)
}

View File

@ -1,2 +0,0 @@
out/
src/graphql-operations.ts

View File

@ -1,10 +0,0 @@
// eslint-disable-next-line import/extensions
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: baseConfig.overrides,
}

View File

@ -1,12 +0,0 @@
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json', __dirname + '/src/end-to-end/tsconfig.json'],
},
rules: {
'no-console': 'off',
},
overrides: baseConfig.overrides,
}

View File

@ -1,15 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {
'no-console': 'off',
},
overrides: baseConfig.overrides,
}

View File

@ -1,12 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: baseConfig.overrides,
}

View File

@ -1,19 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {},
overrides: [
...baseConfig.overrides,
{
files: ['src/*.test.*', 'src/testutils/**'],
rules: {
'import/extensions': ['error', 'never', { html: 'always' }],
},
},
],
}

View File

@ -1,12 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: baseConfig.overrides,
}

View File

@ -16,7 +16,6 @@ export interface FetchCacheRequest extends RequestInit {
url: string
/**
* maximum allowed cached item age in milliseconds
*
* @example "60000" will allow using cached item within last minute
*/
cacheMaxAge: number
@ -27,7 +26,6 @@ let isEnabled = true
/**
* fetch API with cache
*
* @description Caches same argument requests for 1 minute
*/
export const fetchCache = async <T = any>({

View File

@ -3,7 +3,6 @@ import { Observable } from 'rxjs'
/**
* Highlights a node using recursive node walking.
*
* @param node the node to highlight
* @param start the current character position (starts at 0).
* @param length the number of characters to highlight.
@ -31,7 +30,6 @@ export function highlightNode(node: HTMLElement, start: number, length: number):
/**
* Highlights match ranges within visibleRows, with support for highlighting match ranges that span multiple lines.
*
* @param visibleRows the visible rows of the HTML table containing the code excerpt
* @param startRow the row within the table where highlighting should begin
* @param endRow the row within the table where highlighting should end
@ -77,7 +75,6 @@ interface HighlightResult {
/**
* Highlights a node using recursive node walking.
*
* @param currNode the current node being walked.
* @param currOffset the current character position (starts at 0).
* @param start the offset character where highlting starts.

View File

@ -1,6 +1,5 @@
/**
* Determines if the value describes an encoded SVG image.
*
* @param value The raw value.
*/
@ -10,7 +9,6 @@ export function isEncodedSVG(value: string): boolean {
/**
* Determines if the value describes an encoded PNG image.
*
* @param value The raw value.
*/
export function isEncodedPNG(value: string): boolean {
@ -21,7 +19,6 @@ const imageValidators = [isEncodedSVG, isEncodedPNG]
/**
* Determines if an icon can be used as the src of an image element.
*
* @param value The raw icon value.
*/
export function isEncodedImage(value: string): boolean {

View File

@ -53,7 +53,6 @@ const defaultFormattingOptions: FormattingOptions = {
/**
* Simplified jsonc API method to modify jsonc object.
*
* @param originalContent Original content (settings)
* @param path - path to the field which will be modified
* @param value - new value for modify field

View File

@ -1,6 +1,5 @@
/**
* Returns the sum of the number of matches of the patterns in the string.
*
* @param patterns Patterns to match in the string.
*/
export function count(string: string, ...patterns: RegExp[]): number {
@ -42,7 +41,6 @@ export function dedupeWhitespace(value: string): string {
/**
* Checks whether a given string is quoted.
*
* @param value string to check against
*/
export function isQuoted(value: string): boolean {
@ -51,7 +49,6 @@ export function isQuoted(value: string): boolean {
/**
* Replaces a substring within a string.
*
* @param string Original string
* @param range The range in of the substring to be replaced
* @param replacement an optional replacement string

View File

@ -1,6 +1,5 @@
/**
* Identity-function helper to ensure a value `T` is a subtype of `U`.
*
* @template U The type to check for (explicitly specify this)
* @template T The actual type (inferred, don't specify this)
*/
@ -12,7 +11,6 @@ export const subtypeOf =
/**
* Returns a type guard that checks whether the given value is strictly equal to a specific value.
* This can for example be used with `isNot()` to exclude string literals like `"loading"`.
*
* @param constant The value to compare to. Pass this with `as const` to improve type inference.
*/
export const isExactly =
@ -24,7 +22,6 @@ export const isExactly =
* Negates a type guard.
* Returns a function that returns `true` when the input is **not** the type checked for by the given type guard.
* It therefor excludes a type from a union type.
*
* @param isType The type guard that checks whether the given input value should be excluded.
*/
export const isNot =
@ -34,7 +31,6 @@ export const isNot =
/**
* Returns a function that returns `true` if the given `key` of the object passes the given type guard.
*
* @param key The key of the property to check.
*/
export const hasProperty =
@ -44,14 +40,12 @@ export const hasProperty =
/**
* Returns a function that returns `true` if the given `key` exists in the given object, narrowing down the type of the _key_.
*
* @param key The key of the property to check.
*/
export const keyExistsIn = <O extends object>(key: string | number | symbol, object: O): key is keyof O => key in object
/**
* Returns a function that returns `true` if the given `key` of the object passes the given type guard.
*
* @param key The key of the property to check.
* @param isType The type guard to evalute on the property value.
*/
@ -70,7 +64,6 @@ export const isTaggedUnionMember =
/**
* Returns a function that returns `true` if the given value is an instance of the given class.
*
* @param constructor A reference to a class, e.g. `HTMLElement`
*/
export const isInstanceOf =

View File

@ -4,7 +4,6 @@ import { tryCatch } from '../errors'
/**
* Provide one.
*
* @param position either 1-indexed partial position
* @param range or 1-indexed partial range spec
*/

View File

@ -1,10 +0,0 @@
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: __dirname + '/tsconfig.json',
},
overrides: baseConfig.overrides,
}

View File

@ -1,10 +0,0 @@
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: __dirname + '/tsconfig.eslint.json',
},
overrides: baseConfig.overrides,
}

View File

@ -11,18 +11,7 @@ package(default_visibility = ["//visibility:public"])
npm_link_all_packages(name = "node_modules")
eslint_config_and_lint_root(
config_deps = [":tsconfig-eslint"],
)
ts_config(
name = "tsconfig-eslint",
src = "tsconfig.eslint.json",
visibility = ["//client:__subpackages__"],
deps = [
"//:tsconfig",
],
)
eslint_config_and_lint_root()
ts_config(
name = "tsconfig",

View File

@ -1,9 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "out",
"rootDir": "src",
},
"include": ["src", "*.js"],
}

View File

@ -1,13 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {},
overrides: baseConfig.overrides,
}

View File

@ -1,13 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: { 'no-console': 'off' },
overrides: baseConfig.overrides,
}

View File

@ -1,13 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {},
overrides: baseConfig.overrides,
}

View File

@ -1,16 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {
'no-console': 'off',
'jsdoc/check-indentation': 'off',
},
overrides: baseConfig.overrides,
}

View File

@ -1,16 +0,0 @@
// eslint-disable-next-line import/extensions
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json', __dirname + '/src/testing/tsconfig.json'],
},
overrides: [
...baseConfig.overrides,
{
files: ['dev/**/*.*'],
rules: { 'no-console': 'off' },
},
],
}

View File

@ -1,13 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {},
overrides: baseConfig.overrides,
}

View File

@ -1,12 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: baseConfig.overrides,
}

View File

@ -1,12 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
overrides: baseConfig.overrides,
}

View File

@ -1,15 +0,0 @@
// @ts-check
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {
'no-console': 'off',
},
overrides: baseConfig.overrides,
}

View File

@ -1,33 +0,0 @@
const baseConfig = require('../../.eslintrc')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json', __dirname + '/src/**/tsconfig.json'],
},
overrides: [
...baseConfig.overrides,
{
files: ['src/stores/**.ts', 'src/__mocks__/zustand.ts'],
rules: { 'no-restricted-imports': 'off' },
},
{
files: 'dev/**/*.ts',
rules: {
'no-console': 'off',
'no-sync': 'off',
},
},
],
rules: {
'no-restricted-imports': [
'error',
{
// Allow any imports from @sourcegraph/cody-* packages while those packages' APIs are being
// stabilized.
patterns: ['!@sourcegraph/cody-shared/*', '!@sourcegraph/cody-ui/*'],
},
],
},
}

View File

@ -1,6 +1,7 @@
import { mdiCog } from '@mdi/js'
import { Icon } from '@sourcegraph/wildcard'
// eslint-disable-next-line no-restricted-imports
import type { BreadcrumbItem } from '@sourcegraph/wildcard/src/components/PageHeader'
import type { ExternalServiceFieldsWithConfig } from './backend'

View File

@ -1,9 +1,19 @@
import React, { type FC, useState, useCallback, useRef, useEffect } from 'react'
import { noop } from 'lodash'
import { Link } from 'react-router-dom'
import { Alert, Container, Button, Input, Label, Text, PageHeader, ButtonLink, Checkbox } from '@sourcegraph/wildcard'
import {
Alert,
Container,
Button,
Input,
Label,
Text,
PageHeader,
ButtonLink,
Checkbox,
Link,
} from '@sourcegraph/wildcard'
import { GitHubAppDomain } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'

View File

@ -23,6 +23,7 @@ import {
Grid,
AnchorLink,
} from '@sourcegraph/wildcard'
// eslint-disable-next-line no-restricted-imports
import type { BreadcrumbItem } from '@sourcegraph/wildcard/src/components/PageHeader'
import { GitHubAppDomain, type GitHubAppByIDResult, type GitHubAppByIDVariables } from '../../graphql-operations'

View File

@ -4,6 +4,7 @@ import { mdiChevronRight, mdiChevronLeft } from '@mdi/js'
import classNames from 'classnames'
// We're using marked import here to access the `marked` package type definitions.
// eslint-disable-next-line no-restricted-imports
import { type marked, Slugger } from 'marked'
import ReactDOM from 'react-dom'

View File

@ -1,6 +1,7 @@
import { escapeRegExp } from 'lodash'
// We're using marked import here to access the `marked` package type definitions.
// eslint-disable-next-line no-restricted-imports
import { type marked, Renderer } from 'marked'
import { type Observable, forkJoin, of } from 'rxjs'
import { startWith, catchError, mapTo, map, switchMap } from 'rxjs/operators'

View File

@ -4,6 +4,7 @@ import { Prec } from '@codemirror/state'
// This component makes the experimental search input accessible in the web app
// eslint-disable-next-line no-restricted-imports
import {
type Action,
CodeMirrorQueryInputWrapper,

View File

@ -4,6 +4,7 @@ import { byLengthAsc, extendedMatch, Fzf, type FzfOptions, type FzfResultItem }
// This module implements suggestions for the experimental search input
// eslint-disable-next-line no-restricted-imports
import {
type Group,
type Option,

View File

@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react'
// eslint-disable-next-line no-restricted-imports
import { logger } from '@sourcegraph/common/src/util/logger'
import { useMutation, useQuery } from '@sourcegraph/http-client'
import { ErrorAlert, Text, H3, LoadingSpinner, PageHeader, Input, Container } from '@sourcegraph/wildcard'

View File

@ -1,14 +0,0 @@
// @ts-check
// eslint-disable-next-line import/extensions
const baseConfig = require('../../.eslintrc.js')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
...baseConfig.parserOptions,
project: [__dirname + '/tsconfig.json'],
},
rules: {},
overrides: baseConfig.overrides,
}

View File

@ -30,9 +30,8 @@ def eslint_config_and_lint_root(name = "eslint_config", config_deps = [], root_j
js_library(
name = name,
testonly = True,
srcs = [".eslintrc.js"],
srcs = ["//:eslint_config"],
data = [
".eslintignore",
"package.json",
":tsconfig",
],

View File

@ -1,8 +0,0 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"allowJs": true
},
"include": ["./*", "./.*", "client/*/*", "client/*/.*"]
}