Skip to content

Commit f9854c6

Browse files
authored
chore: eslint flat config (#2940)
* initial migration output * try to rewrite the config so it's less horrible * convert to ts * clean it up some more * fix warnings due to oxlint-only things * upgrade the prettier plugins * license
1 parent bd1703d commit f9854c6

File tree

7 files changed

+675
-571
lines changed

7 files changed

+675
-571
lines changed

.eslintrc.cjs

Lines changed: 0 additions & 144 deletions
This file was deleted.

app/api/__tests__/hooks.spec.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ describe('useApiQuery', () => {
116116

117117
function BadApiCall() {
118118
try {
119-
// this disable is for for oxlint
120-
// eslint-disable-next-line react-hooks/rules-of-hooks
119+
// oxlint-disable-next-line react-hooks/rules-of-hooks
121120
useApiQuery('projectView', { path: { project: 'nonexistent' } })
122121
} catch (e) {
123122
onError(e)

app/forms/firewall-rules-common.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ import { type FirewallRuleValues } from './firewall-rules-util'
6868

6969
type TargetAndHostFilterType =
7070
| VpcFirewallRuleTarget['type']
71-
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
71+
// oxlint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
7272
| VpcFirewallRuleHostFilter['type']
7373

7474
type TargetAndHostFormValues = {

app/hooks/use-crumbs.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ function hasCrumb(m: UIMatch): m is MatchWithCrumb {
4747
* `createRoutesFromChildren` rejects a custom Route component.
4848
*/
4949
function checkCrumbType(m: MatchWithCrumb): MatchWithCrumb {
50-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5150
const crumbType = typeof m.handle.crumb
5251
invariant(
5352
crumbType === 'string' || crumbType === 'function',

eslint.config.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
5+
*
6+
* Copyright Oxide Computer Company
7+
*/
8+
import { fixupConfigRules } from '@eslint/compat'
9+
import { FlatCompat } from '@eslint/eslintrc'
10+
import js from '@eslint/js'
11+
import prettierConfig from 'eslint-config-prettier'
12+
import playwrightPlugin from 'eslint-plugin-playwright'
13+
import prettierPlugin from 'eslint-plugin-prettier'
14+
import reactPlugin from 'eslint-plugin-react'
15+
import reactHooksPlugin from 'eslint-plugin-react-hooks'
16+
import { defineConfig } from 'eslint/config'
17+
import globals from 'globals'
18+
import tseslint from 'typescript-eslint'
19+
20+
// FlatCompat needed for plugins that don't fully support flat config yet
21+
const compat = new FlatCompat({
22+
baseDirectory: import.meta.dirname,
23+
recommendedConfig: js.configs.recommended,
24+
})
25+
26+
export default defineConfig(
27+
{ ignores: ['**/dist/', '**/node_modules/', 'tools/deno/'] },
28+
js.configs.recommended,
29+
tseslint.configs.recommendedTypeChecked,
30+
tseslint.configs.strict,
31+
tseslint.configs.stylistic,
32+
reactPlugin.configs.flat.recommended,
33+
reactHooksPlugin.configs.flat.recommended,
34+
// Plugins without flat config support - use compat
35+
...fixupConfigRules(
36+
compat.extends(
37+
'plugin:jsx-a11y/recommended',
38+
'plugin:react-hook-form/recommended',
39+
'plugin:import/recommended'
40+
)
41+
),
42+
prettierConfig,
43+
// Main config
44+
{
45+
languageOptions: {
46+
parserOptions: {
47+
warnOnUnsupportedTypeScriptVersion: false,
48+
// this config is needed for type aware lint rules
49+
project: true,
50+
tsconfigRootDir: import.meta.dirname,
51+
},
52+
globals: { ...globals.node },
53+
},
54+
plugins: {
55+
prettier: prettierPlugin,
56+
},
57+
settings: {
58+
react: { version: 'detect' },
59+
},
60+
61+
rules: {
62+
'@typescript-eslint/array-type': 'off',
63+
'@typescript-eslint/consistent-type-definitions': 'off',
64+
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
65+
'@typescript-eslint/no-empty-function': 'off',
66+
'@typescript-eslint/ban-ts-comment': 'off',
67+
'@typescript-eslint/no-empty-object-type': [
68+
'error',
69+
{ allowInterfaces: 'with-single-extends' },
70+
],
71+
'@typescript-eslint/no-non-null-assertion': 'off',
72+
'@typescript-eslint/no-duplicate-type-constituents': 'off',
73+
'@typescript-eslint/no-unused-vars': [
74+
'error',
75+
{
76+
argsIgnorePattern: '^_',
77+
varsIgnorePattern: '^_',
78+
caughtErrorsIgnorePattern: '^_',
79+
},
80+
],
81+
82+
// disabling the type-aware rules we don't like
83+
// https://typescript-eslint.io/getting-started/typed-linting/
84+
'@typescript-eslint/no-floating-promises': 'off',
85+
'@typescript-eslint/no-misused-promises': 'off',
86+
'@typescript-eslint/no-unsafe-argument': 'off',
87+
'@typescript-eslint/no-unsafe-assignment': 'off',
88+
'@typescript-eslint/no-unsafe-call': 'off',
89+
'@typescript-eslint/no-unsafe-member-access': 'off',
90+
'@typescript-eslint/no-unsafe-return': 'off',
91+
'@typescript-eslint/only-throw-error': 'off',
92+
'@typescript-eslint/unbound-method': 'off',
93+
94+
eqeqeq: ['error', 'always', { null: 'ignore' }],
95+
'import/no-default-export': 'error',
96+
'import/no-unresolved': 'off', // plugin doesn't know anything
97+
'jsx-a11y/label-has-associated-control': [2, { controlComponents: ['button'] }],
98+
// only worry about console.log
99+
'no-console': ['error', { allow: ['warn', 'error', 'info', 'table'] }],
100+
'no-param-reassign': 'error',
101+
'no-restricted-imports': [
102+
'error',
103+
{
104+
paths: [
105+
'.', // preventing confusion due to auto-imports and barrel files
106+
],
107+
patterns: [
108+
// import all CSS except index.css at top level through CSS @import statements
109+
// to avoid bad ordering situations. See https://github.com/oxidecomputer/console/pull/2035
110+
'*.css',
111+
],
112+
},
113+
],
114+
'no-return-assign': 'error',
115+
'no-unused-vars': 'off',
116+
'prefer-arrow-callback': 'off',
117+
'prettier/prettier': 'error',
118+
radix: 'error',
119+
120+
// https://react.dev/reference/eslint-plugin-react-hooks#recommended
121+
'react-hooks/exhaustive-deps': 'error',
122+
// recommended rules that go nuts in our codebase. we should fix them eventually
123+
'react-hooks/incompatible-library': 'off',
124+
'react-hooks/purity': 'off',
125+
'react-hooks/refs': 'off',
126+
'react-hooks/set-state-in-effect': 'off',
127+
128+
'react/button-has-type': 'error',
129+
'react/jsx-boolean-value': 'error',
130+
'react/display-name': 'off',
131+
'react/react-in-jsx-scope': 'off',
132+
'react/prop-types': 'off',
133+
},
134+
},
135+
136+
// Default exports are needed in the route modules and the config files,
137+
// but we want to avoid them anywhere else
138+
{
139+
files: ['app/pages/**/*', 'app/layouts/**/*', 'app/forms/**/*', '*.config.ts'],
140+
rules: {
141+
'import/no-default-export': 'off',
142+
},
143+
},
144+
145+
// Playwright config
146+
{
147+
files: ['**/*.e2e.ts'],
148+
...playwrightPlugin.configs['flat/recommended'],
149+
rules: {
150+
...playwrightPlugin.configs['flat/recommended'].rules,
151+
'playwright/expect-expect': [
152+
'warn',
153+
{
154+
assertFunctionNames: [
155+
'expectVisible',
156+
'expectRowVisible',
157+
'expectOptions',
158+
'expectRowMenuStaysOpen',
159+
],
160+
},
161+
],
162+
'playwright/no-force-option': 'off',
163+
},
164+
}
165+
)

0 commit comments

Comments
 (0)