1
0
mirror of synced 2025-12-19 18:10:59 -05:00

Migrate to ESLint 9 with flat config (#57110)

This commit is contained in:
Kevin Heis
2025-08-18 15:39:23 -07:00
committed by GitHub
parent 71436fa5db
commit bb58717a48
15 changed files with 1539 additions and 867 deletions

227
eslint.config.js Normal file
View File

@@ -0,0 +1,227 @@
import js from '@eslint/js'
import tseslint from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
import github from 'eslint-plugin-github'
import importPlugin from 'eslint-plugin-import'
import jsxA11y from 'eslint-plugin-jsx-a11y'
import primerReact from 'eslint-plugin-primer-react'
import eslintComments from 'eslint-plugin-eslint-comments'
import i18nText from 'eslint-plugin-i18n-text'
import filenames from 'eslint-plugin-filenames'
import noOnlyTests from 'eslint-plugin-no-only-tests'
import prettierPlugin from 'eslint-plugin-prettier'
import prettier from 'eslint-config-prettier'
import globals from 'globals'
export default [
// JavaScript and MJS files configuration
{
files: ['**/*.{js,mjs}'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
...globals.commonjs,
...globals.es2020,
},
parserOptions: {
requireConfigFile: false,
},
},
settings: {
'import/resolver': {
typescript: true,
node: true,
},
},
plugins: {
github,
import: importPlugin,
'eslint-comments': eslintComments,
'i18n-text': i18nText,
filenames,
'no-only-tests': noOnlyTests,
prettier: prettierPlugin,
},
rules: {
// ESLint recommended rules
...js.configs.recommended.rules,
// GitHub plugin recommended rules
...github.configs.recommended.rules,
// Import plugin error rules
...importPlugin.configs.errors.rules,
// JavaScript-specific overrides
'import/no-extraneous-dependencies': [
'error',
{
packageDir: '.',
},
],
'import/extensions': 'off',
'no-console': 'off',
camelcase: 'off',
'no-shadow': 'off',
'prefer-template': 'off',
'no-constant-condition': 'off',
'no-unused-vars': 'off',
'import/no-named-as-default-member': 'off',
'one-var': 'off',
'import/no-namespace': 'off',
'import/no-anonymous-default-export': 'off',
'object-shorthand': 'off',
'no-empty': 'off',
'prefer-const': 'off',
'import/no-named-as-default': 'off',
'no-useless-concat': 'off',
'func-style': 'off',
// Disable GitHub plugin rules that were disabled in original config
'github/array-foreach': 'off',
'github/no-then': 'off',
// Disable rules that might not exist or cause issues initially
'i18n-text/no-en': 'off',
'filenames/match-regex': 'off',
'eslint-comments/no-use': 'off',
'eslint-comments/no-unused-disable': 'off',
'eslint-comments/no-unlimited-disable': 'off',
// Disable new ESLint 9 rules that are causing issues
'no-constant-binary-expression': 'off',
},
},
// TypeScript and TSX files configuration
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
...globals.commonjs,
...globals.es2020,
},
parserOptions: {
requireConfigFile: false,
},
},
settings: {
'import/resolver': {
typescript: true,
node: true,
},
},
plugins: {
github,
import: importPlugin,
'eslint-comments': eslintComments,
'i18n-text': i18nText,
filenames,
'no-only-tests': noOnlyTests,
prettier: prettierPlugin,
'@typescript-eslint': tseslint,
'primer-react': primerReact,
'jsx-a11y': jsxA11y,
},
rules: {
// ESLint recommended rules
...js.configs.recommended.rules,
// GitHub plugin recommended rules
...github.configs.recommended.rules,
// Import plugin error rules
...importPlugin.configs.errors.rules,
// TypeScript ESLint recommended rules
...tseslint.configs.recommended.rules,
// Primer React recommended rules
...primerReact.configs.recommended.rules,
// JSX A11y recommended rules
...jsxA11y.configs.recommended.rules,
// TypeScript-specific overrides
'import/no-extraneous-dependencies': [
'error',
{
packageDir: '.',
},
],
'import/extensions': 'off',
'no-console': 'off',
camelcase: 'off',
'no-shadow': 'off',
'prefer-template': 'off',
'no-constant-condition': 'off',
'no-unused-vars': 'off',
'no-undef': 'off',
'no-use-before-define': 'off',
'no-redeclare': 'off', // Allow function overloads in TypeScript
'import/no-named-as-default-member': 'off',
'one-var': 'off',
'import/no-namespace': 'off',
'import/no-anonymous-default-export': 'off',
'object-shorthand': 'off',
'no-empty': 'off',
'prefer-const': 'off',
'import/no-named-as-default': 'off',
'no-useless-concat': 'off',
'func-style': 'off',
// TypeScript ESLint specific rules
'@typescript-eslint/no-unused-vars': 'error',
// Disable GitHub plugin rules that were disabled in original config
'github/array-foreach': 'off',
'github/no-then': 'off',
// Disable rules that might not exist or cause issues initially
'i18n-text/no-en': 'off',
'filenames/match-regex': 'off',
'eslint-comments/no-use': 'off',
'eslint-comments/no-unused-disable': 'off',
'eslint-comments/no-unlimited-disable': 'off',
// Disable new ESLint 9 rules that are causing issues
'no-constant-binary-expression': 'off',
// Disable stricter TypeScript rules initially
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-wrapper-object-types': 'off',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'@typescript-eslint/no-unsafe-function-type': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/prefer-as-const': 'off',
// React/JSX specific rules
'jsx-a11y/no-onchange': 'off',
},
},
// Ignored patterns
{
ignores: [
'tmp/*',
'.next/',
'src/bookmarklets/*',
'rest-api-description/',
'docs-internal-data/',
'src/code-scanning/scripts/generate-code-scanning-query-list.ts',
],
},
// Prettier config (should be last to override formatting rules)
prettier,
]

2018
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -154,101 +154,10 @@
}
]
},
"eslintConfig": {
"env": {
"browser": true,
"commonjs": true,
"es2020": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2022,
"requireConfigFile": "false",
"sourceType": "module"
},
"settings": {
"import/resolver": {
"typescript": true,
"node": true
}
},
"extends": [
"eslint:recommended",
"plugin:github/recommended",
"plugin:import/errors",
"prettier"
],
"rules": {
"import/no-extraneous-dependencies": [
"error",
{
"packageDir": "."
}
],
"import/extensions": "off",
"no-console": "off",
"github/array-foreach": "off",
"camelcase": "off",
"i18n-text/no-en": "off",
"no-shadow": "off",
"prefer-template": "off",
"filenames/match-regex": "off",
"no-constant-condition": "off",
"no-unused-vars": "off",
"github/no-then": "off",
"import/no-named-as-default-member": "off",
"one-var": "off",
"import/no-namespace": "off",
"import/no-anonymous-default-export": "off",
"object-shorthand": "off",
"eslint-comments/no-use": "off",
"no-empty": "off",
"prefer-const": "off",
"import/no-named-as-default": "off",
"eslint-comments/no-unused-disable": "off",
"no-useless-concat": "off",
"func-style": "off",
"eslint-comments/no-unlimited-disable": "off"
},
"overrides": [
{
"files": [
"**/*.tsx",
"**/*.ts"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"primer-react",
"jsx-a11y"
],
"extends": [
"plugin:primer-react/recommended",
"plugin:jsx-a11y/recommended"
],
"rules": {
"camelcase": "off",
"no-undef": "off",
"no-unused-vars": "off",
"no-use-before-define": "off",
"@typescript-eslint/no-unused-vars": "error",
"jsx-a11y/no-onchange": "off"
}
}
],
"ignorePatterns": [
"tmp/*",
"!/.*",
"/.next/",
"src/bookmarklets/*",
"rest-api-description/",
"docs-internal-data/",
"src/code-scanning/scripts/generate-code-scanning-query-list.ts"
]
},
"dependencies": {
"@elastic/elasticsearch": "8.13.1",
"@github/failbot": "0.8.3",
"@gr2m/gray-matter": "4.0.3-with-pr-137",
"@horizon-rs/language-guesser": "0.1.1",
"@octokit/plugin-retry": "8.0.1",
"@octokit/request-error": "7.0.0",
@@ -282,7 +191,6 @@
"github-slugger": "^2.0.0",
"glob": "11.0.2",
"got": "^14.4.7",
"@gr2m/gray-matter": "4.0.3-with-pr-137",
"hast-util-from-parse5": "^8.0.3",
"hast-util-to-string": "^3.0.1",
"hastscript": "^9.0.1",
@@ -343,6 +251,7 @@
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@axe-core/playwright": "^4.10.1",
"@eslint/js": "^9.33.0",
"@github/markdownlint-github": "^0.6.3",
"@graphql-inspector/core": "^6.1.0",
"@graphql-tools/load": "^8.0.19",
@@ -375,14 +284,21 @@
"cross-env": "^10.0.0",
"csp-parse": "0.0.2",
"csv-parse": "6.1.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.0.3",
"eslint": "^9.33.0",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.2",
"eslint-plugin-github": "^5.0.2",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-escompat": "^3.11.4",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^6.0.0",
"eslint-plugin-i18n-text": "^1.0.1",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-primer-react": "^7.0.2",
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-primer-react": "^8.0.0",
"event-to-promise": "^0.8.0",
"globals": "^16.3.0",
"graphql": "^16.9.0",
"http-status-code": "^2.1.0",
"husky": "^9.1.7",

View File

@@ -1,8 +1,6 @@
import path from 'path'
import { escapeRegExp } from 'lodash-es'
/* eslint-disable prefer-regex-literals */
// slash at the beginning of a filename
const leadingPathSeparator = new RegExp(`^${escapeRegExp(path.sep)}`)
const windowsLeadingPathSeparator = new RegExp('^/')

View File

@@ -44,7 +44,7 @@ describe('get-data', () => {
const jaTranslationsRoot = path.join(dd.root, 'translations', 'ja-JP')
fs.mkdirSync(jaTranslationsRoot, { recursive: true })
languages.ja.dir = jaTranslationsRoot
new DataDirectory( // eslint-disable-line no-new
new DataDirectory(
{
data: {
ui: {
@@ -242,7 +242,7 @@ describe('get-data on corrupt translations', () => {
const jaTranslationsRoot = path.join(dd.root, 'translations', 'ja-JP')
fs.mkdirSync(jaTranslationsRoot, { recursive: true })
languages.ja.dir = jaTranslationsRoot
new DataDirectory( // eslint-disable-line no-new
new DataDirectory(
{
data: {
variables: {

View File

@@ -1,4 +1,3 @@
/* eslint-disable camelcase */
import Cookies from '@/frame/components/lib/cookies'
import { parseUserAgent } from './user-agent'
import { Router } from 'next/router'

View File

@@ -3,7 +3,7 @@ import { allVersionKeys } from '@/versions/lib/all-versions'
import { productIds } from '@/products/lib/all-products'
import { allTools } from '@/tools/lib/all-tools'
const versionPattern = '^\\d+(\\.\\d+)?(\\.\\d+)?$' // eslint-disable-line
const versionPattern = '^\\d+(\\.\\d+)?(\\.\\d+)?$'
const context = {
type: 'object',

View File

@@ -12,11 +12,8 @@ type UseQueryParamReturn<T extends string | boolean> = {
}
// Overloads so we can use this for a boolean or string query param
// eslint-disable-next-line no-redeclare
export function useQueryParam(queryParamKey: string, isBoolean: true): UseQueryParamReturn<boolean>
// eslint-disable-next-line no-redeclare
export function useQueryParam(queryParamKey: string, isBoolean?: false): UseQueryParamReturn<string>
// eslint-disable-next-line no-redeclare
export function useQueryParam(
queryParamKey: string,
isBoolean?: boolean,

View File

@@ -358,7 +358,6 @@ const semverRange = {
format: 'semver',
// This is JSON pointer syntax with ajv so we can specify the bad version
// in the error message.
// eslint-disable-next-line no-template-curly-in-string
errorMessage: 'Must be a valid SemVer range: ${0}',
}

View File

@@ -1,12 +1,10 @@
import fs from 'fs'
import path from 'path'
// eslint-disable-next-line import/named
import { visit, Test } from 'unist-util-visit'
import { fromMarkdown } from 'mdast-util-from-markdown'
import { toMarkdown } from 'mdast-util-to-markdown'
import yaml from 'js-yaml'
// eslint-disable-next-line import/no-unresolved
import { type Node, type Nodes, type Definition, type Link } from 'mdast'
import frontmatter from '@/frame/lib/read-frontmatter'

View File

@@ -1,4 +1,3 @@
/* eslint-disable import/no-extraneous-dependencies */
import fs from 'fs'
/* Writes string to file to be uploaded as an action artifact.

View File

@@ -1,5 +1,3 @@
/* eslint-disable no-invalid-this */
/* eslint-disable prettier/prettier */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { getAutomaticRequestLogger } from '@/observability/logger/middleware/get-automatic-request-logger'
import type { Request, Response, NextFunction } from 'express'

View File

@@ -1,4 +1,3 @@
/* eslint-disable prettier/prettier */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { createLogger } from '@/observability/logger'
import { initLoggerContext, updateLoggerContext } from '@/observability/logger/lib/logger-context'

View File

@@ -1,4 +1,3 @@
/* eslint-disable prettier/prettier */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { createLogger } from '@/observability/logger'

View File

@@ -3,6 +3,17 @@ import dereferenceJsonSchema from 'dereference-json-schema'
import { existsSync } from 'fs'
import { readFile, readdir } from 'fs/promises'
// OpenAPI 3.0 schema interface with the properties we need to access
// The dereference-json-schema library returns a DereferencedJSONSchema type
// but the actual object contains OpenAPI-specific properties that aren't in that type
interface OpenAPISchema {
openapi?: string
info?: any
servers?: any[]
paths?: Record<string, Record<string, any>>
[key: string]: any
}
export const MODELS_GATEWAY_ROOT = 'models-gateway'
const MODELS_GATEWAY_PATH = 'docs/api'
@@ -40,14 +51,16 @@ export async function injectModelsSchema(schema: any, schemaName: string): Promi
const deferencedYaml = dereferenceJsonSchema.dereferenceSync(loadedYaml)
// Copy over top-level OpenAPI fields
schema.openapi = schema.openapi || deferencedYaml.openapi
schema.info = schema.info || deferencedYaml.info
schema.servers = schema.servers || deferencedYaml.servers
// Cast to OpenAPISchema because dereference-json-schema doesn't include OpenAPI-specific properties in its type
const openApiYaml = deferencedYaml as OpenAPISchema
schema.openapi = schema.openapi || openApiYaml.openapi
schema.info = schema.info || openApiYaml.info
schema.servers = schema.servers || openApiYaml.servers
// Process each path and operation in the YAML
for (const path of Object.keys(deferencedYaml.paths)) {
for (const operation of Object.keys(deferencedYaml.paths[path])) {
const operationObject = deferencedYaml.paths[path][operation]
for (const path of Object.keys(openApiYaml.paths || {})) {
for (const operation of Object.keys(openApiYaml.paths![path])) {
const operationObject = openApiYaml.paths![path][operation]
// Use values from the YAML where possible
const name = operationObject.summary || ''
@@ -85,8 +98,8 @@ export async function injectModelsSchema(schema: any, schemaName: string): Promi
// Preserve operation-level servers if present
// !Needed! to use models.github.ai instead of api.github.com
if (deferencedYaml.servers) {
enhancedOperation.servers = deferencedYaml.servers
if (openApiYaml.servers) {
enhancedOperation.servers = openApiYaml.servers
}
// Add the enhanced operation to the schema