@wistia/oxlint-config 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,9 +12,23 @@ Wistia's Oxlint configurations. This is a shared config package for [oxlint](htt
12
12
  ## How to install
13
13
 
14
14
  ```bash
15
- yarn add -D @wistia/oxlint-config oxlint
15
+ yarn add -D @wistia/oxlint-config oxlint eslint
16
16
  ```
17
17
 
18
+ > **Why `eslint`?** This package uses oxlint's [jsPlugins](https://oxc.rs/docs/guide/usage/linter/js-plugins) feature to run ESLint plugins (e.g. `eslint-plugin-import-x`, `@eslint-react/eslint-plugin`, `eslint-plugin-testing-library`, etc.) natively inside oxlint. These plugins import utilities from the `eslint` package at runtime, so it must be installed even though you won't run `eslint` directly.
19
+ >
20
+ > **Note:** jsPlugins do not support rules that rely on TypeScript type information. Any type-aware rules in this config use native oxlint rules instead.
21
+
22
+ ### Type-aware linting
23
+
24
+ The `typescriptConfig` enables [type-aware linting](https://oxc.rs/docs/guide/usage/linter/type-aware), which requires the `oxlint-tsgolint` package:
25
+
26
+ ```bash
27
+ yarn add -D oxlint-tsgolint
28
+ ```
29
+
30
+ `oxlint-tsgolint` is a separate Go-based tool that builds your TypeScript program using `typescript-go` and runs type-aware rules (e.g. detecting unhandled promises, unsafe assignments). Without it installed, type-aware rules will not run.
31
+
18
32
  ## Quick start
19
33
 
20
34
  Create an `oxlint.config.ts` in your project root:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wistia/oxlint-config",
3
- "version": "0.7.5",
3
+ "version": "0.8.0",
4
4
  "description": "Wistia's Oxlint configurations",
5
5
  "packageManager": "yarn@4.14.1",
6
6
  "type": "module",
@@ -55,16 +55,16 @@
55
55
  "oxlint-tsgolint": ">= 1.0.0"
56
56
  },
57
57
  "dependencies": {
58
- "@eslint-react/eslint-plugin": "^5.7.6",
59
- "@vitest/eslint-plugin": "^1.6.16",
58
+ "@eslint-react/eslint-plugin": "^5.8.3",
59
+ "@vitest/eslint-plugin": "^1.6.17",
60
60
  "confusing-browser-globals": "^1.0.11",
61
61
  "eslint-plugin-barrel-files": "^3.0.1",
62
62
  "eslint-plugin-import-x": "^4.16.2",
63
63
  "eslint-plugin-jest-dom": "^5.5.0",
64
64
  "eslint-plugin-n": "^18.0.1",
65
65
  "eslint-plugin-no-only-tests": "^3.4.0",
66
- "eslint-plugin-playwright": "^2.10.2",
67
- "eslint-plugin-storybook": "^10.3.6",
66
+ "eslint-plugin-playwright": "^2.10.4",
67
+ "eslint-plugin-storybook": "^10.4.0",
68
68
  "eslint-plugin-styled-components": "^0.0.0",
69
69
  "eslint-plugin-styled-components-a11y": "^2.2.1",
70
70
  "eslint-plugin-testing-library": "^7.16.2",
@@ -73,12 +73,12 @@
73
73
  "devDependencies": {
74
74
  "@changesets/changelog-github": "^0.7.0",
75
75
  "@changesets/cli": "^2.31.0",
76
- "eslint": "^10.3.0",
77
- "oxfmt": "^0.48.0",
78
- "oxlint": "^1.64.0",
79
- "oxlint-tsgolint": "^0.22.1",
80
- "storybook": "^10.3.6",
81
- "vitest": "^4.1.5"
76
+ "eslint": "^10.4.0",
77
+ "oxfmt": "^0.51.0",
78
+ "oxlint": "^1.66.0",
79
+ "oxlint-tsgolint": "^0.23.0",
80
+ "storybook": "^10.4.0",
81
+ "vitest": "^4.1.7"
82
82
  },
83
83
  "engines": {
84
84
  "node": "^20.19.0 || ^22.13.0 || >=24 || >=26"
package/rules/base.mjs CHANGED
@@ -272,6 +272,11 @@ export const baseRules = {
272
272
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/grouped-accessor-pairs.html
273
273
  'eslint/grouped-accessor-pairs': 'error',
274
274
 
275
+ // Require identifiers to match a specified regular expression
276
+ // https://oxc.rs/docs/guide/usage/linter/rules/eslint/id-match.html
277
+ // Decision: too opinionated for general use
278
+ 'eslint/id-match': 'off',
279
+
275
280
  // Enforce minimum and maximum identifier lengths
276
281
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/id-length.html
277
282
  'eslint/id-length': [
@@ -374,6 +379,14 @@ export const baseRules = {
374
379
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-implicit-coercion.html
375
380
  'eslint/no-implicit-coercion': 'error',
376
381
 
382
+ // Disallow declarations in the global scope
383
+ // https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-implicit-globals.html
384
+ 'eslint/no-implicit-globals': 'error',
385
+
386
+ // Disallow the use of eval()-like methods
387
+ // https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-implied-eval.html
388
+ 'eslint/no-implied-eval': 'error',
389
+
377
390
  // Disallow the use of the __iterator__ property
378
391
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-iterator.html
379
392
  'eslint/no-iterator': 'error',
@@ -577,6 +590,13 @@ export const baseRules = {
577
590
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/operator-assignment.html
578
591
  'eslint/operator-assignment': ['error', 'always'],
579
592
 
593
+ // Require using arrow functions for callbacks
594
+ // https://oxc.rs/docs/guide/usage/linter/rules/eslint/prefer-arrow-callback.html
595
+ 'eslint/prefer-arrow-callback': [
596
+ 'error',
597
+ { allowNamedFunctions: false, allowUnboundThis: true },
598
+ ],
599
+
580
600
  // Require const declarations for variables that are never reassigned after declared
581
601
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/prefer-const.html
582
602
  'eslint/prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: true }],
@@ -608,6 +628,10 @@ export const baseRules = {
608
628
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/prefer-object-spread.html
609
629
  'eslint/prefer-object-spread': 'error',
610
630
 
631
+ // Disallow use of the RegExp constructor in favor of regular expression literals
632
+ // https://oxc.rs/docs/guide/usage/linter/rules/eslint/prefer-regex-literals.html
633
+ 'eslint/prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
634
+
611
635
  // Require using Error objects as Promise rejection reasons
612
636
  // https://oxc.rs/docs/guide/usage/linter/rules/eslint/prefer-promise-reject-errors.html
613
637
  'eslint/prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
package/rules/import.mjs CHANGED
@@ -115,6 +115,10 @@ export const importRules = {
115
115
  // Decision: too opinionated for general use
116
116
  'import/max-dependencies': 'off',
117
117
 
118
+ // Require a newline after the last import/require in a group
119
+ // https://oxc.rs/docs/guide/usage/linter/rules/import/newline-after-import.html
120
+ 'import/newline-after-import': 'error',
121
+
118
122
  // Ensure named imports coupled with named exports
119
123
  // https://oxc.rs/docs/guide/usage/linter/rules/import/named.html
120
124
  // Decision: handled by TypeScript
@@ -175,19 +179,17 @@ export const importRules = {
175
179
  'error',
176
180
  {
177
181
  devDependencies: [
178
- '**/*{.,_}{test,vitest,spec}.{js,jsx,ts,tsx}',
182
+ '**/*{.,_}{test,vitest,spec,stories}.{js,jsx,ts,tsx}',
183
+ '**/oxfmt.config.*',
184
+ '**/.oxfmtrc.json*',
179
185
  '**/vite.config.{ts,js,cjs,mjs,mts}',
180
186
  '**/vitest.config.{ts,js,cjs,mjs,mts}',
181
- '**/jest.config.{js,cjs,mjs,mts}',
182
- '**/jest.setup.{js,cjs,mjs,mts}',
183
187
  '**/eslint.config.{js,cjs,mjs,mts}',
184
188
  '**/.eslintrc.{js,cjs}',
185
189
  '**/.stylelintrc.{cjs,js,json,yaml,yml}',
186
190
  '**/stylelint.config.{cjs,mjs,mts,js}',
187
191
  '**/esbuild.config.{js,cjs,mjs,mts}',
188
192
  '**/tsup.config.{js,cjs,mjs,mts}',
189
- '**/webpack.config.{js,cjs,mjs,mts}',
190
- '**/webpack.config.*.{js,cjs,mjs,mts}',
191
193
  '**/rollup.config.{js,cjs,mjs,mts}',
192
194
  '**/rollup.config.*.{js,cjs,mjs,mts}',
193
195
  ],
@@ -219,7 +221,8 @@ export const importRules = {
219
221
 
220
222
  // Require a newline after the last import/require in a group
221
223
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/newline-after-import.md
222
- 'import-x-js/newline-after-import': 'error',
224
+ // Decision: handled by native import/newline-after-import
225
+ 'import-x-js/newline-after-import': 'off',
223
226
 
224
227
  // Ensures that there are no useless path segments
225
228
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-useless-path-segments.md
@@ -53,6 +53,30 @@ export const reactA11yRules = {
53
53
  // Decision: too opinionated for general use
54
54
  'jsx_a11y/autocomplete-valid': 'off',
55
55
 
56
+ // Enforce that a control (an interactive element) has a text label
57
+ // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/control-has-associated-label.html
58
+ 'jsx_a11y/control-has-associated-label': [
59
+ 'error',
60
+ {
61
+ labelAttributes: ['label'],
62
+ controlComponents: [],
63
+ ignoreElements: ['audio', 'canvas', 'embed', 'input', 'textarea', 'tr', 'video'],
64
+ ignoreRoles: [
65
+ 'grid',
66
+ 'listbox',
67
+ 'menu',
68
+ 'menubar',
69
+ 'radiogroup',
70
+ 'row',
71
+ 'tablist',
72
+ 'toolbar',
73
+ 'tree',
74
+ 'treegrid',
75
+ ],
76
+ depth: 5,
77
+ },
78
+ ],
79
+
56
80
  // Enforce a clickable non-interactive element has at least one keyboard event listener
57
81
  // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/click-events-have-key-events.html
58
82
  'jsx_a11y/click-events-have-key-events': 'error',
@@ -128,6 +152,33 @@ export const reactA11yRules = {
128
152
  },
129
153
  ],
130
154
 
155
+ // Ensure interactive elements are not assigned non-interactive roles
156
+ // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/no-interactive-element-to-noninteractive-role.html
157
+ 'jsx_a11y/no-interactive-element-to-noninteractive-role': [
158
+ 'error',
159
+ { tr: ['none', 'presentation'] },
160
+ ],
161
+
162
+ // Enforce that non-interactive elements do not have interaction handlers
163
+ // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/no-noninteractive-element-interactions.html
164
+ 'jsx_a11y/no-noninteractive-element-interactions': [
165
+ 'error',
166
+ { handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'] },
167
+ ],
168
+
169
+ // Enforce that non-interactive elements are not assigned interactive roles
170
+ // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/no-noninteractive-element-to-interactive-role.html
171
+ 'jsx_a11y/no-noninteractive-element-to-interactive-role': [
172
+ 'error',
173
+ {
174
+ ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
175
+ ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
176
+ li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
177
+ table: ['grid'],
178
+ td: ['gridcell'],
179
+ },
180
+ ],
181
+
131
182
  // Enforce explicit role is not redundant with implicit role of the element
132
183
  // https://oxc.rs/docs/guide/usage/linter/rules/jsx-a11y/no-redundant-roles.html
133
184
  'jsx_a11y/no-redundant-roles': 'error',
package/rules/react.mjs CHANGED
@@ -105,6 +105,14 @@ export const reactRules = {
105
105
  // Decision: this is a decision best left to the implementer
106
106
  'react/no-multi-comp': 'off',
107
107
 
108
+ // Disallow object types as default props
109
+ // https://oxc.rs/docs/guide/usage/linter/rules/react/no-object-type-as-default-prop.html
110
+ 'react/no-object-type-as-default-prop': 'error',
111
+
112
+ // Disallow creating unstable components inside components
113
+ // https://oxc.rs/docs/guide/usage/linter/rules/react/no-unstable-nested-components.html
114
+ 'react/no-unstable-nested-components': 'error',
115
+
108
116
  // Disallow usage of the return value of ReactDOM.render
109
117
  // https://oxc.rs/docs/guide/usage/linter/rules/react/no-render-return-value.html
110
118
  'react/no-render-return-value': 'error',
@@ -430,7 +438,8 @@ export const reactRules = {
430
438
 
431
439
  // Prevent creating unstable components inside components
432
440
  // https://eslint-react.xyz/docs/rules/no-nested-component-definitions
433
- '@eslint-react/no-nested-component-definitions': 'error',
441
+ // Decision: handled by native react/no-unstable-nested-components
442
+ '@eslint-react/no-nested-component-definitions': 'off',
434
443
 
435
444
  // Prevent creating lazy components inside components
436
445
  // https://eslint-react.xyz/docs/rules/no-nested-lazy-component-declarations
@@ -473,7 +482,8 @@ export const reactRules = {
473
482
 
474
483
  // Disallow referential-type variables as default props
475
484
  // https://eslint-react.xyz/docs/rules/no-unstable-default-props
476
- '@eslint-react/no-unstable-default-props': 'error',
485
+ // Decision: handled by native react/no-object-type-as-default-prop
486
+ '@eslint-react/no-unstable-default-props': 'off',
477
487
 
478
488
  // Prevent declaring unused methods of component class
479
489
  // https://eslint-react.xyz/docs/rules/no-unused-class-component-members
package/rules/vitest.mjs CHANGED
@@ -30,6 +30,11 @@ export const vitestRules = {
30
30
  // https://oxc.rs/docs/guide/usage/linter/rules/vitest/no-import-node-test.html
31
31
  'vitest/no-import-node-test': 'error',
32
32
 
33
+ // Enforce padding around afterAll blocks
34
+ // https://oxc.rs/docs/guide/usage/linter/rules/vitest/padding-around-after-all-blocks.html
35
+ // Decision: stylistic formatting rule, left to formatter
36
+ 'vitest/padding-around-after-all-blocks': 'off',
37
+
33
38
  // Disallow conditional tests
34
39
  // https://oxc.rs/docs/guide/usage/linter/rules/vitest/no-conditional-in-test.html
35
40
  'vitest/no-conditional-in-test': 'error',