@wistia/oxlint-config 0.3.3 → 0.3.5

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
@@ -2,6 +2,13 @@
2
2
 
3
3
  Wistia's Oxlint configurations. This is a shared config package for [oxlint](https://oxc.rs/docs/guide/usage/linter), a fast TypeScript/Javascript linter.
4
4
 
5
+ ## Philosophy & Principles
6
+
7
+ - **Always Error, Never Warn:** Warnings become background noise that developers tune out. A rule should either flag a real problem or stay silent.
8
+ - **Strict, Consistent Code Style:** Where there's more than one way to do something, this configuration picks the strictest and most uniform option, favoring modern syntax and established best practices.
9
+ - **Fast:** Known performance-heavy rules are skipped.
10
+ - **Don't get in the way:** Rules that involve style preferences are intentionally disabled as this is best left to a formatter like `prettier`. Whenever possible, rules that can auto-fix are chosen to minimize friction and save developer time.
11
+
5
12
  ## How to install
6
13
 
7
14
  ```bash
@@ -10,79 +17,119 @@ yarn add -D @wistia/oxlint-config oxlint
10
17
 
11
18
  ## Quick start
12
19
 
13
- Create an `.oxlintrc.json` in your project root:
20
+ Create an `oxlint.config.ts` in your project root:
14
21
 
15
22
  **TypeScript project** (most common):
16
23
 
17
- ```json
18
- {
19
- "$schema": "./node_modules/oxlint/configuration_schema.json",
20
- "extends": ["./node_modules/@wistia/oxlint-config/configs/typescript.jsonc"]
21
- }
24
+ ```ts
25
+ import { defineConfig } from 'oxlint';
26
+ import { typescriptRules } from '@wistia/oxlint-config';
27
+
28
+ export default defineConfig({
29
+ plugins: typescriptRules.plugins,
30
+ rules: typescriptRules.rules,
31
+ });
22
32
  ```
23
33
 
24
34
  **JavaScript-only project:**
25
35
 
26
- ```json
27
- {
28
- "$schema": "./node_modules/oxlint/configuration_schema.json",
29
- "extends": ["./node_modules/@wistia/oxlint-config/configs/javascript.jsonc"]
30
- }
36
+ ```ts
37
+ import { defineConfig } from 'oxlint';
38
+ import { baseRules, importRules, promiseRules } from '@wistia/oxlint-config';
39
+
40
+ export default defineConfig({
41
+ plugins: [...baseRules.plugins, ...importRules.plugins, ...promiseRules.plugins],
42
+ rules: {
43
+ ...baseRules.rules,
44
+ ...importRules.rules,
45
+ ...promiseRules.rules,
46
+ },
47
+ });
31
48
  ```
32
49
 
33
- ## Available configs
34
-
35
- ### Base configs
36
-
37
- | Config | Description |
38
- | -------------------------- | ---------------------------------------------------------------------- |
39
- | `configs/javascript.jsonc` | Base config for any JavaScript project (base + import + promise rules) |
40
- | `configs/typescript.jsonc` | TypeScript projects (includes all JavaScript rules) |
41
-
42
- ### Feature configs
43
-
44
- | Config | Description |
45
- | --------------------------------- | --------------------------------------------------------------- |
46
- | `configs/react.jsonc` | React component and accessibility rules (react + jsx-a11y) |
47
- | `configs/node.jsonc` | Node.js-specific rules (native + eslint-plugin-n via jsPlugins) |
48
- | `configs/vitest.jsonc` | Vitest testing rules (see note below) |
49
- | `configs/playwright.jsonc` | Playwright E2E testing rules (via jsPlugins) |
50
- | `configs/storybook.jsonc` | Storybook story conventions (via jsPlugins) |
51
- | `configs/testing-library.jsonc` | Testing Library + jest-dom rules (via jsPlugins) |
52
- | `configs/styled-components.jsonc` | Styled Components accessibility rules (via jsPlugins) |
53
-
54
- **Note on jsPlugins configs:** Some configs use oxlint's [jsPlugins](https://oxc.rs/docs/guide/usage/linter/js-plugins) feature to load ESLint plugins for rules that don't have native oxlint equivalents. These configs require the corresponding ESLint plugin to be installed as a dev dependency in the consuming project. Check each config's rule file for the required `jsPlugins` specifiers.
55
-
56
- **Note on vitest config:** Oxlint splits vitest-related rules across two internal plugin namespaces -- `vitest/` for vitest-specific rules and `jest/` for rules that originated in eslint-plugin-jest but apply equally to vitest. The `jest/` prefix is an oxlint naming convention; it does **not** mean Jest is required or that these rules are Jest-specific.
57
-
58
- Configs are **additive** -- start with a base (`javascript` or `typescript`), then layer on feature configs as needed:
59
-
60
- ````json
61
- {
62
- "$schema": "./node_modules/oxlint/configuration_schema.json",
63
- "extends": [
64
- "./node_modules/@wistia/oxlint-config/configs/typescript.jsonc",
65
- "./node_modules/@wistia/oxlint-config/configs/react.jsonc",
66
- "./node_modules/@wistia/oxlint-config/configs/vitest.jsonc"
67
- ]
68
- }
50
+ ## Available rules
51
+
52
+ ### Base rules
53
+
54
+ | Export | Description |
55
+ | ----------------- | ------------------------------------------------------------------------ |
56
+ | `baseRules` | Core ESLint rules (correctness + suggestions) |
57
+ | `importRules` | Import/export validation (native + eslint-plugin-import-x via jsPlugins) |
58
+ | `promiseRules` | Promise handling rules |
59
+ | `typescriptRules` | TypeScript-specific rules (disables superseded base rules) |
60
+
61
+ ### Feature rules
62
+
63
+ | Export | Description |
64
+ | ----------------------- | ------------------------------------------------------------ |
65
+ | `reactRules` | React component rules (native + @eslint-react via jsPlugins) |
66
+ | `reactA11yRules` | JSX accessibility rules (jsx-a11y) |
67
+ | `nodeRules` | Node.js rules (native + eslint-plugin-n via jsPlugins) |
68
+ | `vitestRules` | Vitest testing rules (see note below) |
69
+ | `playwrightRules` | Playwright E2E testing rules (via jsPlugins) |
70
+ | `storybookRules` | Storybook story conventions (via jsPlugins) |
71
+ | `testingLibraryRules` | Testing Library + jest-dom rules (via jsPlugins) |
72
+ | `styledComponentsRules` | Styled Components accessibility rules (via jsPlugins) |
73
+ | `filenamesRules` | Filename convention rules (via jsPlugins) |
74
+ | `barrelFilesRules` | Barrel file rules (via jsPlugins) |
75
+
76
+ **Note on jsPlugins:** Some rule sets use oxlint's [jsPlugins](https://oxc.rs/docs/guide/usage/linter/js-plugins) feature to load ESLint plugins for rules that don't have native oxlint equivalents. These require the corresponding ESLint plugin to be installed. All jsPlugin dependencies are included in this package's `dependencies`.
77
+
78
+ **Note on vitest:** Oxlint splits vitest-related rules across two internal plugin namespaces -- `vitest/` for vitest-specific rules and `jest/` for rules that originated in eslint-plugin-jest but apply equally to vitest. The `jest/` prefix is an oxlint naming convention; it does **not** mean Jest is required.
79
+
80
+ ## Composing rules
81
+
82
+ Rules are **composable** -- import what you need and spread into your config. Rule sets that include `jsPlugins` need those spread too:
83
+
84
+ ```ts
85
+ import { defineConfig } from 'oxlint';
86
+ import {
87
+ baseRules,
88
+ importRules,
89
+ typescriptRules,
90
+ reactRules,
91
+ reactA11yRules,
92
+ vitestRules,
93
+ } from '@wistia/oxlint-config';
94
+
95
+ export default defineConfig({
96
+ plugins: [
97
+ ...baseRules.plugins,
98
+ ...importRules.plugins,
99
+ ...typescriptRules.plugins,
100
+ ...reactRules.plugins,
101
+ ...reactA11yRules.plugins,
102
+ ],
103
+ jsPlugins: [...(importRules.jsPlugins || []), ...(reactRules.jsPlugins || [])],
104
+ rules: {
105
+ ...baseRules.rules,
106
+ ...importRules.rules,
107
+ ...typescriptRules.rules,
108
+ ...reactRules.rules,
109
+ ...reactA11yRules.rules,
110
+ },
111
+ overrides: [
112
+ {
113
+ files: ['**/*.test.ts', '**/*.test.tsx'],
114
+ plugins: vitestRules.plugins,
115
+ jsPlugins: vitestRules.jsPlugins,
116
+ rules: vitestRules.rules,
117
+ },
118
+ ],
119
+ });
120
+ ```
69
121
 
70
122
  ## Overriding rules
71
123
 
72
- Add a `rules` section to your `.oxlintrc.json` -- your rules take precedence over the shared config:
124
+ Add overrides after the spread -- your rules take precedence:
73
125
 
74
- ```json
75
- {
76
- "$schema": "./node_modules/oxlint/configuration_schema.json",
77
- "extends": [
78
- "./node_modules/@wistia/oxlint-config/configs/typescript.jsonc"
79
- ],
80
- "rules": {
81
- "eslint/no-console": "off",
82
- "typescript/no-explicit-any": "off"
83
- }
84
- }
85
- ````
126
+ ```ts
127
+ rules: {
128
+ ...typescriptRules.rules,
129
+ // override
130
+ 'typescript/no-explicit-any': 'off',
131
+ },
132
+ ```
86
133
 
87
134
  ## Running oxlint
88
135
 
@@ -91,17 +138,19 @@ Add a script to your `package.json`:
91
138
  ```json
92
139
  {
93
140
  "scripts": {
94
- "lint": "oxlint ."
141
+ "lint:oxlint": "oxlint -c oxlint.config.ts ."
95
142
  }
96
143
  }
97
144
  ```
98
145
 
99
- Oxlint will automatically pick up `.oxlintrc.json` from your project root.
100
-
101
146
  ## Guidelines for adding new rules
102
147
 
103
148
  1. Preference given for autofixable rules
104
149
  2. Should not contradict existing rules
105
150
  3. Person/team adding new rules handles upgrading consumers and fixing violations
106
- 4. Rules should always be set to `error`, never `warn` (the latter are never fixed)
107
- 5. Add short description of rule & link to rule definition in code comments
151
+ 4. Rules should always be set to `error`, never `warn`
152
+ 5. Add short description of rule and link to rule documentation in code comments
153
+
154
+ ## ESLint parity
155
+
156
+ See [docs/eslint-parity.md](docs/eslint-parity.md) for a full list of differences between this package and `@wistia/eslint-config`.
@@ -2,13 +2,15 @@ import { defineConfig } from 'oxlint';
2
2
  import { baseRules } from '../rules/base.mjs';
3
3
  import { importRules } from '../rules/import.mjs';
4
4
  import { promiseRules } from '../rules/promise.mjs';
5
+ import { barrelFilesRules } from '../rules/barrel-files.mjs';
5
6
 
6
7
  export default defineConfig({
7
8
  plugins: [...baseRules.plugins, ...importRules.plugins, ...promiseRules.plugins],
8
- jsPlugins: [...(importRules.jsPlugins || [])],
9
+ jsPlugins: [...(importRules.jsPlugins || []), ...(barrelFilesRules.jsPlugins || [])],
9
10
  rules: {
10
11
  ...baseRules.rules,
11
12
  ...importRules.rules,
12
13
  ...promiseRules.rules,
14
+ ...barrelFilesRules.rules,
13
15
  },
14
16
  });
package/configs/node.mjs CHANGED
@@ -2,7 +2,12 @@ import { defineConfig } from 'oxlint';
2
2
  import { nodeRules } from '../rules/node.mjs';
3
3
 
4
4
  export default defineConfig({
5
- plugins: nodeRules.plugins,
6
- jsPlugins: nodeRules.jsPlugins,
7
- rules: nodeRules.rules,
5
+ overrides: [
6
+ {
7
+ files: ['**/*.mts', '**/*.mjs', '**/*.cjs'],
8
+ plugins: nodeRules.plugins,
9
+ jsPlugins: nodeRules.jsPlugins,
10
+ rules: nodeRules.rules,
11
+ },
12
+ ],
8
13
  });
@@ -2,6 +2,11 @@ import { defineConfig } from 'oxlint';
2
2
  import { playwrightRules } from '../rules/playwright.mjs';
3
3
 
4
4
  export default defineConfig({
5
- jsPlugins: playwrightRules.jsPlugins,
6
- rules: playwrightRules.rules,
5
+ overrides: [
6
+ {
7
+ files: ['**/*.spec.ts', '**/*.spec.tsx', '**/*.spec.js', '**/e2e/**/*.ts'],
8
+ jsPlugins: playwrightRules.jsPlugins,
9
+ rules: playwrightRules.rules,
10
+ },
11
+ ],
7
12
  });
@@ -2,6 +2,11 @@ import { defineConfig } from 'oxlint';
2
2
  import { storybookRules } from '../rules/storybook.mjs';
3
3
 
4
4
  export default defineConfig({
5
- jsPlugins: storybookRules.jsPlugins,
6
- rules: storybookRules.rules,
5
+ overrides: [
6
+ {
7
+ files: ['**/*.stories.ts', '**/*.stories.tsx', '**/*.stories.js', '**/*.stories.jsx'],
8
+ jsPlugins: storybookRules.jsPlugins,
9
+ rules: storybookRules.rules,
10
+ },
11
+ ],
7
12
  });
@@ -2,6 +2,20 @@ import { defineConfig } from 'oxlint';
2
2
  import { testingLibraryRules } from '../rules/testing-library.mjs';
3
3
 
4
4
  export default defineConfig({
5
- jsPlugins: testingLibraryRules.jsPlugins,
6
- rules: testingLibraryRules.rules,
5
+ overrides: [
6
+ {
7
+ files: [
8
+ '**/*.test.ts',
9
+ '**/*.test.tsx',
10
+ '**/*.test.js',
11
+ '**/*.test.jsx',
12
+ '**/*.vitest.ts',
13
+ '**/*.vitest.tsx',
14
+ '**/*.vitest.js',
15
+ '**/*.vitest.jsx',
16
+ ],
17
+ jsPlugins: testingLibraryRules.jsPlugins,
18
+ rules: testingLibraryRules.rules,
19
+ },
20
+ ],
7
21
  });
@@ -3,6 +3,7 @@ import { baseRules } from '../rules/base.mjs';
3
3
  import { importRules } from '../rules/import.mjs';
4
4
  import { promiseRules } from '../rules/promise.mjs';
5
5
  import { typescriptRules } from '../rules/typescript.mjs';
6
+ import { barrelFilesRules } from '../rules/barrel-files.mjs';
6
7
 
7
8
  export default defineConfig({
8
9
  plugins: [
@@ -11,11 +12,12 @@ export default defineConfig({
11
12
  ...promiseRules.plugins,
12
13
  ...typescriptRules.plugins,
13
14
  ],
14
- jsPlugins: [...(importRules.jsPlugins || [])],
15
+ jsPlugins: [...(importRules.jsPlugins || []), ...(barrelFilesRules.jsPlugins || [])],
15
16
  rules: {
16
17
  ...baseRules.rules,
17
18
  ...importRules.rules,
18
19
  ...promiseRules.rules,
19
20
  ...typescriptRules.rules,
21
+ ...barrelFilesRules.rules,
20
22
  },
21
23
  });
@@ -2,7 +2,21 @@ import { defineConfig } from 'oxlint';
2
2
  import { vitestRules } from '../rules/vitest.mjs';
3
3
 
4
4
  export default defineConfig({
5
- plugins: vitestRules.plugins,
6
- jsPlugins: vitestRules.jsPlugins,
7
- rules: vitestRules.rules,
5
+ overrides: [
6
+ {
7
+ files: [
8
+ '**/*.test.ts',
9
+ '**/*.test.tsx',
10
+ '**/*.test.js',
11
+ '**/*.test.jsx',
12
+ '**/*.vitest.ts',
13
+ '**/*.vitest.tsx',
14
+ '**/*.vitest.js',
15
+ '**/*.vitest.jsx',
16
+ ],
17
+ plugins: vitestRules.plugins,
18
+ jsPlugins: vitestRules.jsPlugins,
19
+ rules: vitestRules.rules,
20
+ },
21
+ ],
8
22
  });
package/index.d.mts CHANGED
@@ -19,6 +19,7 @@ export declare const playwrightRules: RuleFile;
19
19
  export declare const storybookRules: RuleFile;
20
20
  export declare const styledComponentsRules: RuleFile;
21
21
  export declare const testingLibraryRules: RuleFile;
22
+ export declare const barrelFilesRules: RuleFile;
22
23
 
23
24
  // Configs
24
25
  export declare const javascriptConfig: OxlintConfig;
package/index.mjs CHANGED
@@ -11,6 +11,7 @@ export { playwrightRules } from './rules/playwright.mjs';
11
11
  export { storybookRules } from './rules/storybook.mjs';
12
12
  export { styledComponentsRules } from './rules/styled-components.mjs';
13
13
  export { testingLibraryRules } from './rules/testing-library.mjs';
14
+ export { barrelFilesRules } from './rules/barrel-files.mjs';
14
15
 
15
16
  // Configs
16
17
  export { default as javascriptConfig } from './configs/javascript.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wistia/oxlint-config",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Wistia's Oxlint configurations",
5
5
  "packageManager": "yarn@4.13.0",
6
6
  "type": "module",
@@ -12,12 +12,12 @@
12
12
  ],
13
13
  "exports": {
14
14
  "./package.json": "./package.json",
15
- "./configs/*": "./configs/*",
16
- "./rules/*": "./rules/*",
17
15
  ".": {
18
16
  "types": "./index.d.mts",
19
17
  "default": "./index.mjs"
20
18
  },
19
+ "./configs/*": "./configs/*",
20
+ "./rules/*": "./rules/*",
21
21
  "./javascript": "./configs/javascript.mjs",
22
22
  "./typescript": "./configs/typescript.mjs",
23
23
  "./react": "./configs/react.mjs",
@@ -38,6 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@vitest/eslint-plugin": "^1.6.14",
41
+ "eslint-plugin-barrel-files": "^3.0.1",
41
42
  "eslint-plugin-import-x": "^4.16.2",
42
43
  "eslint-plugin-jest-dom": "^5.5.0",
43
44
  "eslint-plugin-n": "^17.24.0",
@@ -58,7 +59,7 @@
58
59
  "vitest": "^4.1.2"
59
60
  },
60
61
  "engines": {
61
- "node": "^20.19.0 || ^22.13.0 || >=24"
62
+ "node": "^20.19.0 || ^22.13.0 || >=24 || >=26"
62
63
  },
63
64
  "keywords": [
64
65
  "oxlint",
@@ -0,0 +1,22 @@
1
+ // All barrel-files rules loaded via jsPlugins (no native oxlint support).
2
+ // see: https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7/
3
+ export const barrelFilesRules = {
4
+ jsPlugins: ['eslint-plugin-barrel-files'],
5
+ rules: {
6
+ // Avoid barrel files
7
+ // https://github.com/thepassle/eslint-plugin-barrel-files/blob/main/docs/rules/avoid-barrel-files.md
8
+ 'eslint-plugin-barrel-files/avoid-barrel-files': 'off',
9
+
10
+ // Avoid importing barrel files
11
+ // https://github.com/thepassle/eslint-plugin-barrel-files/blob/main/docs/rules/avoid-importing-barrel-files.md
12
+ 'eslint-plugin-barrel-files/avoid-importing-barrel-files': 'off',
13
+
14
+ // Avoid namespace imports from barrel files
15
+ // https://github.com/thepassle/eslint-plugin-barrel-files/blob/main/docs/rules/avoid-namespace-import.md
16
+ 'eslint-plugin-barrel-files/avoid-namespace-import': 'off',
17
+
18
+ // Avoid re-export all from barrel files
19
+ // https://github.com/thepassle/eslint-plugin-barrel-files/blob/main/docs/rules/avoid-re-export-all.md
20
+ 'eslint-plugin-barrel-files/avoid-re-export-all': 'error',
21
+ },
22
+ };
package/rules/import.mjs CHANGED
@@ -92,7 +92,10 @@ export const importRules = {
92
92
 
93
93
  // Ensure imports point to files/modules that can be resolved
94
94
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-unresolved.md
95
- 'import-x-js/no-unresolved': ['error', { caseSensitive: true }],
95
+ // NOTE: disabled — requires eslint-import-resolver-typescript to resolve TS paths.
96
+ // oxlint's jsPlugin runner does not pass ESLint settings to plugins, so the resolver
97
+ // config never reaches the plugin.
98
+ 'import-x-js/no-unresolved': 'off',
96
99
 
97
100
  // Disallow invalid exports, e.g. multiple defaults
98
101
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/export.md
@@ -126,21 +129,13 @@ export const importRules = {
126
129
 
127
130
  // Reports if a default export is renamed during import
128
131
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-rename-default.md
129
- 'import-x-js/no-rename-default': 'error',
132
+ // NOTE: disabled — parser errors on TS modules without eslint-import-resolver-typescript.
133
+ 'import-x-js/no-rename-default': 'off',
130
134
 
131
135
  // Ensure consistent use of file extension within the import path
132
136
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/extensions.md
133
- 'import-x-js/extensions': [
134
- 'error',
135
- 'ignorePackages',
136
- {
137
- js: 'never',
138
- mjs: 'never',
139
- jsx: 'never',
140
- ts: 'never',
141
- tsx: 'never',
142
- },
143
- ],
137
+ // NOTE: disabled — cannot determine file existence without eslint-import-resolver-typescript.
138
+ 'import-x-js/extensions': 'off',
144
139
 
145
140
  // Ensure absolute imports are above relative imports
146
141
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/order.md