1
0
mirror of https://github.com/badges/shields.git synced 2025-04-17 08:37:04 +03:00

Migrate to ESLint 9 (#10762)

* update ESLint related packages

* migrate to flat config format

* Fix prefer-const error

Fixes
'overrideLogoSize' is never reassigned. Use 'const' instead

* remove irrelevant eslint-disable comment

These comments came from a swizzled upstream
component but never did anything in our codebase.

ESLint 9 does not allow disable comments
for rules that are not registered.

* remove irrelevant eslint-disable comments

These were here because in the past we were applying
mocha lint rules to files which contained no tests

ESLint 9 now flags eslint-disable comments
that aren't doing anythings

* remove irrelevant eslint-disable comment

ESLint 9 now flags eslint-disable comments
that aren't doing anything

* there are no .tsx files in our code any more

* include .mjs files in linting and formatting

* update sort-class-members rule for openApi property

and update the handful of files violating it
This commit is contained in:
chris48s 2024-12-31 13:54:25 +00:00 committed by GitHub
parent 7108e08670
commit c567f6cde4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1491 additions and 752 deletions

View File

@ -1,7 +0,0 @@
/api-docs/
/build
/coverage
/__snapshots__
public
badge-maker/node_modules/
!.github/

View File

@ -1,189 +0,0 @@
extends:
- standard
- standard-jsx
- standard-react
- prettier
- eslint:recommended
globals:
JSX: 'readonly'
parserOptions:
# Override eslint-config-standard, which incorrectly sets this to "module",
# though that setting is only for ES6 modules, not CommonJS modules.
sourceType: 'script'
settings:
react:
version: '16.8'
jsdoc:
mode: typescript
plugins:
- chai-friendly
- jsdoc
- mocha
- icedfrisby
- no-extension-in-require
- sort-class-members
- import
- react-hooks
- promise
overrides:
# For simplicity's sake, when possible prefer to add rules to the top-level
# list of rules, even if they only apply to certain files. That way the
# rules listed here are only ones which conflict.
- files:
- 'badge-maker/**/*.js'
- '**/*.cjs'
env:
node: true
es6: true
- files:
- '**/*.js'
- '!frontend/**/*.js'
- '!badge-maker/**/*.js'
env:
node: true
es6: true
parserOptions:
sourceType: 'module'
parser: '@typescript-eslint/parser'
rules:
no-console: 'off'
- files:
- '**/*.ts'
parserOptions:
sourceType: 'module'
parser: '@typescript-eslint/parser'
- files:
- 'frontend/**/*.js'
parserOptions:
sourceType: 'module'
env:
browser: true
rules:
import/extensions:
['error', 'never', { 'json': 'always', 'yml': 'always' }]
- files:
- 'core/base-service/**/*.js'
- 'services/**/*.js'
rules:
sort-class-members/sort-class-members:
[
'error',
{
order:
[
'name',
'category',
'isDeprecated',
'route',
'auth',
'examples',
'_cacheLength',
'defaultBadgeData',
'render',
'constructor',
'fetch',
'transform',
'handle',
],
},
]
- files:
- '**/*.spec.@(js|ts|tsx)'
- '**/*.integration.js'
- '**/test-helpers.js'
- 'core/service-test-runner/**/*.js'
env:
mocha: true
rules:
mocha/no-exclusive-tests: 'error'
mocha/no-skipped-tests: 'error'
mocha/no-mocha-arrows: 'error'
mocha/prefer-arrow-callback: 'error'
- files:
- 'services/**/*.tester.js'
rules:
icedfrisby/no-exclusive-tests: 'error'
icedfrisby/no-skipped-tests: 'error'
rules:
# Disable some rules from eslint:recommended.
no-empty: ['error', { 'allowEmptyCatch': true }]
no-use-before-define: 'off'
# These should be disabled by eslint-config-prettier, but are not.
no-extra-semi: 'off'
# Shields additions.
no-var: 'error'
prefer-const: 'error'
arrow-body-style: ['error', 'as-needed']
no-extension-in-require/main: 'error'
object-shorthand: ['error', 'properties']
prefer-template: 'error'
promise/prefer-await-to-then: 'error'
func-style: ['error', 'declaration', { 'allowArrowFunctions': true }]
new-cap: ['error', { 'capIsNew': true }]
import/order: ['error', { 'newlines-between': 'never' }]
quotes:
['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }]
# Account for destructuring responses from upstream services,
# many of which do not follow camelcase
# Based on original rule configuration from eslint-config-standard
camelcase:
[
'error',
{
ignoreDestructuring: true,
properties: 'never',
ignoreGlobals: true,
allow: ['^UNSAFE_'],
},
]
# Chai friendly.
no-unused-expressions: 'off'
chai-friendly/no-unused-expressions: 'error'
# jsdoc plugin:
# don't require every class/function to have a docblock
jsdoc/require-jsdoc: 'off'
# allow Joi as an undefined type
jsdoc/no-undefined-types: ['error', { definedTypes: ['Joi'] }]
# all the other recommended rules as errors (not warnings)
jsdoc/check-alignment: 'error'
jsdoc/check-param-names: 'error'
jsdoc/check-tag-names: 'error'
jsdoc/check-types: 'error'
jsdoc/implements-on-classes: 'error'
jsdoc/tag-lines: ['error', 'any', { 'startLines': 1 }]
jsdoc/require-param: 'error'
jsdoc/require-param-description: 'error'
jsdoc/require-param-name: 'error'
jsdoc/require-param-type: 'error'
jsdoc/require-returns: 'error'
jsdoc/require-returns-check: 'error'
jsdoc/require-returns-description: 'error'
jsdoc/require-returns-type: 'error'
jsdoc/valid-types: 'error'
react/prop-types: 'off'
react/jsx-sort-props: 'error'
react-hooks/rules-of-hooks: 'error'
react-hooks/exhaustive-deps: 'error'
jsx-quotes: ['error', 'prefer-double']

View File

@ -47,13 +47,13 @@ export default function coalesceBadge(
label: overrideLabel,
logo: overrideLogo,
logoColor: overrideLogoColor,
logoSize: overrideLogoSize,
link: overrideLink,
colorB: legacyOverrideColor,
colorA: legacyOverrideLabelColor,
} = overrides
let {
logoWidth: overrideLogoWidth,
logoSize: overrideLogoSize,
color: overrideColor,
labelColor: overrideLabelColor,
} = overrides

View File

@ -115,7 +115,6 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
const result = handlerOptions.handler(
filteredQueryParams,
match,
// eslint-disable-next-line mocha/prefer-arrow-callback
function sendBadge(format, badgeData) {
if (serverUnresponsive) {
return
@ -128,7 +127,6 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
makeSend(format, ask.res, end)(svg)
},
)
// eslint-disable-next-line promise/prefer-await-to-then
if (result && result.catch) {
// eslint-disable-next-line promise/prefer-await-to-then
result.catch(err => {

View File

@ -83,7 +83,7 @@ class ServiceTester {
.before(() => {
this.beforeEach()
})
// eslint-disable-next-line mocha/prefer-arrow-callback, promise/prefer-await-to-then
// eslint-disable-next-line promise/prefer-await-to-then
.finally(function () {
// `this` is the IcedFrisby instance.
let responseBody

249
eslint.config.js Normal file
View File

@ -0,0 +1,249 @@
import chaiFriendlyPlugin from 'eslint-plugin-chai-friendly'
import cypressPlugin from 'eslint-plugin-cypress/flat'
import jsdocPlugin from 'eslint-plugin-jsdoc'
import mochaPlugin from 'eslint-plugin-mocha'
import icedfrisbyPlugin from 'eslint-plugin-icedfrisby'
import sortClassMembersPlugin from 'eslint-plugin-sort-class-members'
import importPlugin from 'eslint-plugin-import'
import reactHooksPlugin from 'eslint-plugin-react-hooks'
import prettierConfig from 'eslint-plugin-prettier/recommended'
import promisePlugin from 'eslint-plugin-promise'
import globals from 'globals'
import neostandard from 'neostandard'
import tsParser from '@typescript-eslint/parser'
import js from '@eslint/js'
// Config that is used across the whole codebase
// and customisations to built-in ESLint rules
const globalConfig = {
plugins: {
import: importPlugin,
promise: promisePlugin,
},
rules: {
'import/order': ['error', { 'newlines-between': 'never' }],
'promise/prefer-await-to-then': 'error',
// ESLint built-in rules config
'no-empty': ['error', { allowEmptyCatch: true }],
'no-var': 'error',
'prefer-const': 'error',
'arrow-body-style': ['error', 'as-needed'],
'object-shorthand': ['error', 'properties'],
'prefer-template': 'error',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
'new-cap': ['error', { capIsNew: true }],
quotes: [
'error',
'single',
{ avoidEscape: true, allowTemplateLiterals: false },
],
camelcase: [
'error',
{
ignoreDestructuring: true,
properties: 'never',
ignoreGlobals: true,
allow: ['^UNSAFE_'],
},
],
},
}
// config specific to linting Node (CommonJS) files
const commonJsConfig = {
files: ['badge-maker/**/*.js', '**/*.cjs'],
languageOptions: {
globals: {
...globals.node,
},
},
}
// config specific to linting Node (ESModules) files
const nodeEsmConfig = {
files: ['**/*.@(js|mjs)', '!frontend/**/*.js', '!badge-maker/**/*.js'],
languageOptions: {
globals: {
...globals.node,
},
parser: tsParser,
sourceType: 'module',
},
rules: {
'no-console': 'off',
},
}
// config specific to linting Frontend (ESModules) files
const frontendConfig = {
files: ['frontend/**/*.js'],
plugins: {
'react-hooks': reactHooksPlugin,
},
languageOptions: {
globals: {
...globals.browser,
},
sourceType: 'module',
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
},
}
// config specific to linting Services
const servicesConfig = {
files: ['core/base-service/**/*.js', 'services/**/*.js'],
plugins: {
'sort-class-members': sortClassMembersPlugin,
},
rules: {
'sort-class-members/sort-class-members': [
'error',
{
order: [
'name',
'category',
'isDeprecated',
'route',
'auth',
'openApi',
'_cacheLength',
'defaultBadgeData',
'render',
'constructor',
'fetch',
'transform',
'handle',
],
},
],
},
}
// config specific to linting Mocha tests
const mochaConfig = {
files: [
'**/*.spec.@(js|mjs|ts)',
'**/*.integration.js',
'**/test-helpers.js',
'core/service-test-runner/**/*.js',
],
plugins: {
mocha: mochaPlugin,
},
languageOptions: {
globals: {
...globals.mocha,
},
},
rules: {
'mocha/no-exclusive-tests': 'error',
'mocha/no-skipped-tests': 'error',
'mocha/no-mocha-arrows': 'error',
'mocha/prefer-arrow-callback': 'error',
'no-unused-expressions': 'off',
},
}
// config specific to linting Cypress tests
const cypressConfig = {
files: ['**/*.cy.@(js|ts)'],
...cypressPlugin.configs.recommended,
}
// append these to cypress.configs.recommended, without overwriting
cypressConfig.plugins.mocha = mochaPlugin
cypressConfig.rules['mocha/no-exclusive-tests'] = 'error'
cypressConfig.rules['mocha/no-skipped-tests'] = 'error'
cypressConfig.rules['mocha/no-mocha-arrows'] = 'off'
// config specific to linting Service tests (IcedFrisby)
const serviceTestsConfig = {
files: ['services/**/*.tester.js'],
plugins: {
icedfrisby: icedfrisbyPlugin,
},
rules: {
'icedfrisby/no-exclusive-tests': 'error',
'icedfrisby/no-skipped-tests': 'error',
'no-unused-expressions': 'off',
},
}
// config specific to linting JSDoc comments
const jsDocConfig = {
plugins: {
jsdoc: jsdocPlugin,
},
rules: {
'jsdoc/require-jsdoc': 'off',
'jsdoc/no-undefined-types': ['error', { definedTypes: ['Joi'] }],
'jsdoc/check-alignment': 'error',
'jsdoc/check-param-names': 'error',
'jsdoc/check-tag-names': 'error',
'jsdoc/check-types': 'error',
'jsdoc/implements-on-classes': 'error',
'jsdoc/tag-lines': ['error', 'any', { startLines: 1 }],
'jsdoc/require-param': 'error',
'jsdoc/require-param-description': 'error',
'jsdoc/require-param-name': 'error',
'jsdoc/require-param-type': 'error',
'jsdoc/require-returns': 'error',
'jsdoc/require-returns-check': 'error',
'jsdoc/require-returns-description': 'error',
'jsdoc/require-returns-type': 'error',
'jsdoc/valid-types': 'error',
},
}
const config = [
{
ignores: [
'api-docs/',
'build',
'coverage',
'__snapshots__',
'public',
'badge-maker/node_modules/',
'!.github/',
'frontend/.docusaurus/**',
],
},
js.configs.recommended,
chaiFriendlyPlugin.configs.recommendedFlat,
...neostandard({ noStyle: true }),
globalConfig,
commonJsConfig,
nodeEsmConfig,
frontendConfig,
servicesConfig,
mochaConfig,
cypressConfig,
serviceTestsConfig,
jsDocConfig,
// register prettierConfig last, as per
// https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
prettierConfig,
]
export default config

View File

@ -261,7 +261,6 @@ function Curl({ postman, codeSamples }) {
{tokens.map((line, i) => (
// this <span> does have a key but eslint fails
// to detect it because it is an arg to getLineProps()
// eslint-disable-next-line react/jsx-key
<span
{...getLineProps({
line,
@ -276,7 +275,6 @@ function Curl({ postman, codeSamples }) {
return (
// this <span> does have a key but eslint fails
// to detect it because it is an arg to getLineProps()
// eslint-disable-next-line react/jsx-key
<span
{...getTokenProps({
token,

View File

@ -1,5 +1,3 @@
/* eslint-disable camelcase */
exports.shorthands = undefined
exports.up = pgm => {

1703
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -82,9 +82,9 @@
"coverage:report:generate": "c8 report",
"coverage:report:open": "open-cli coverage/lcov-report/index.html",
"coverage:report": "run-s --silent coverage:report:generate coverage:report:open",
"lint": "eslint \"**/*.@(cjs|js|ts|tsx)\"",
"prettier": "prettier --write \"**/*.@(cjs|js|ts|tsx|md|json|yml)\"",
"prettier:check": "prettier --check \"**/*.@(cjs|js|ts|tsx|md|json|yml)\"",
"lint": "eslint \"**/*.@(cjs|mjs|js|ts)\"",
"prettier": "prettier --write \"**/*.@(cjs|mjs|js|ts|md|json|yml)\"",
"prettier:check": "prettier --check \"**/*.@(cjs|mjs|js|ts|md|json|yml)\"",
"danger": "danger",
"test:e2e": "cypress run",
"test:core": "cross-env TZ='UTC' NODE_CONFIG_ENV=test mocha \"core/**/*.spec.js\" \"lib/**/*.spec.js\" \"services/**/*.spec.js\"",
@ -124,7 +124,7 @@
"docusaurus:clear": "docusaurus clear frontend"
},
"lint-staged": {
"**/*.@(js|ts|tsx)": [
"**/*.@(cjs|mjs|js|ts)": [
"eslint --fix",
"prettier --write"
],
@ -164,24 +164,20 @@
"danger": "^12.3.3",
"deepmerge": "^4.3.1",
"docusaurus-preset-openapi": "0.7.5",
"eslint": "8.57.1",
"eslint": "9.17.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "17.1.0",
"eslint-config-standard-jsx": "11.0.0",
"eslint-config-standard-react": "13.0.0",
"eslint-plugin-chai-friendly": "^1.0.1",
"eslint-plugin-cypress": "^3.6.0",
"eslint-plugin-icedfrisby": "^0.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsdoc": "^50.6.1",
"eslint-plugin-mocha": "^10.5.0",
"eslint-plugin-no-extension-in-require": "^0.2.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-react": "^7.37.3",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-sort-class-members": "^1.21.0",
"eslint-plugin-chai-friendly": "1.0.1",
"eslint-plugin-cypress": "4.1.0",
"eslint-plugin-icedfrisby": "0.2.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jsdoc": "50.6.1",
"eslint-plugin-mocha": "10.5.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-promise": "7.2.1",
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-sort-class-members": "1.21.0",
"form-data": "^4.0.1",
"globals": "15.14.0",
"icedfrisby": "4.0.0",
"icedfrisby-nock": "^2.1.0",
"is-svg": "^5.1.0",
@ -193,6 +189,7 @@
"mocha-env-reporter": "^4.0.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-yaml-loader": "^1.0.3",
"neostandard": "0.12.0",
"nock": "13.5.6",
"node-mocks-http": "^1.16.2",
"nodemon": "^3.1.9",

View File

@ -9,14 +9,6 @@ const description = `<p>This badge indicates whether the package supports the <b
export default class NodeCurrentVersion extends NodeVersionBase {
static route = this.buildRoute('node/v', { withTag: true })
static defaultBadgeData = {
label: 'node',
}
static type = 'current'
static colorResolver = versionColorForRangeCurrent
static openApi = {
'/node/v/{packageName}': {
get: {
@ -57,4 +49,12 @@ export default class NodeCurrentVersion extends NodeVersionBase {
},
},
}
static defaultBadgeData = {
label: 'node',
}
static type = 'current'
static colorResolver = versionColorForRangeCurrent
}

View File

@ -9,14 +9,6 @@ const description = `<p>This badge indicates whether the package supports <b>all
export default class NodeLtsVersion extends NodeVersionBase {
static route = this.buildRoute('node/v-lts', { withTag: true })
static defaultBadgeData = {
label: 'node-lts',
}
static type = 'lts'
static colorResolver = versionColorForRangeLts
static openApi = {
'/node/v-lts/{packageName}': {
get: {
@ -57,4 +49,12 @@ export default class NodeLtsVersion extends NodeVersionBase {
},
},
}
static defaultBadgeData = {
label: 'node-lts',
}
static type = 'lts'
static colorResolver = versionColorForRangeLts
}

View File

@ -28,8 +28,6 @@ export class NpmLastUpdateWithTag extends NpmBase {
queryParamSchema,
}
static defaultBadgeData = { label: 'last updated' }
static openApi = {
'/npm/last-update/{packageName}/{tag}': {
get: {
@ -53,6 +51,8 @@ export class NpmLastUpdateWithTag extends NpmBase {
},
}
static defaultBadgeData = { label: 'last updated' }
async handle(namedParams, queryParams) {
const { scope, packageName, tag, registryUrl } =
this.constructor.unpackParams(namedParams, queryParams)
@ -79,8 +79,6 @@ export class NpmLastUpdate extends NpmBase {
static route = this.buildRoute('npm/last-update', { withTag: false })
static defaultBadgeData = { label: 'last updated' }
static openApi = {
'/npm/last-update/{packageName}': {
get: {
@ -100,6 +98,8 @@ export class NpmLastUpdate extends NpmBase {
},
}
static defaultBadgeData = { label: 'last updated' }
async handle(namedParams, queryParams) {
const { scope, packageName, registryUrl } = this.constructor.unpackParams(
namedParams,

View File

@ -32,8 +32,6 @@ export default class SnapcraftLastUpdate extends SnapcraftBase {
queryParamSchema,
}
static defaultBadgeData = { label: 'last updated' }
static openApi = {
'/snapcraft/last-update/{package}/{track}/{risk}': {
get: {
@ -55,6 +53,8 @@ export default class SnapcraftLastUpdate extends SnapcraftBase {
},
}
static defaultBadgeData = { label: 'last updated' }
static transform(apiData, track, risk, arch) {
const channelMap = apiData['channel-map']
let filteredChannelMap = channelMap.filter(

View File

@ -32,8 +32,6 @@ export default class SnapcraftVersion extends SnapcraftBase {
queryParamSchema,
}
static defaultBadgeData = { label: 'snapcraft' }
static openApi = {
'/snapcraft/v/{package}/{track}/{risk}': {
get: {
@ -55,6 +53,8 @@ export default class SnapcraftVersion extends SnapcraftBase {
},
}
static defaultBadgeData = { label: 'snapcraft' }
static render({ version }) {
return renderVersionBadge({ version })
}