xo 2.0.2 → 3.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xo",
3
- "version": "2.0.2",
3
+ "version": "3.0.0",
4
4
  "description": "JavaScript/TypeScript linter (ESLint wrapper) with great defaults",
5
5
  "license": "MIT",
6
6
  "repository": "xojs/xo",
@@ -13,12 +13,18 @@
13
13
  "type": "module",
14
14
  "bin": "./dist/cli.js",
15
15
  "exports": {
16
- "types": "./dist/index.d.ts",
17
- "default": "./dist/index.js"
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./eslint-adapter": {
21
+ "types": "./dist/lib/eslint-adapter.d.ts",
22
+ "default": "./dist/lib/eslint-adapter.js"
23
+ }
18
24
  },
19
25
  "sideEffects": false,
20
26
  "engines": {
21
- "node": ">=20.19"
27
+ "node": ">=22"
22
28
  },
23
29
  "scripts": {
24
30
  "build": "npm run clean && tsc",
@@ -27,7 +33,7 @@
27
33
  "lint": "node dist/cli.js",
28
34
  "prepare": "npm run build && husky",
29
35
  "release": "np",
30
- "test": "npm run build && npm run lint && npm run test:setup && ava",
36
+ "test": "npm run build && npm run lint && npm run test:setup && node --enable-source-maps --test \"dist/test/**/*.test.js\"",
31
37
  "test:setup": "node scripts/setup-tests"
32
38
  },
33
39
  "files": [
@@ -67,86 +73,41 @@
67
73
  "typescript"
68
74
  ],
69
75
  "dependencies": {
70
- "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1",
71
- "@eslint/compat": "^2.0.2",
72
76
  "@sindresorhus/tsconfig": "^8.1.0",
73
77
  "arrify": "^3.0.0",
74
- "cosmiconfig": "^9.0.0",
78
+ "cosmiconfig": "^9.0.2",
75
79
  "define-lazy-prop": "^3.0.0",
76
- "eslint": "^10.0.2",
77
- "eslint-config-prettier": "^10.1.8",
78
- "eslint-config-xo-react": "^0.29.0",
79
- "eslint-config-xo-typescript": "^10.0.0",
80
- "eslint-formatter-pretty": "^7.0.0",
81
- "eslint-plugin-ava": "^16.0.0",
82
- "eslint-plugin-import-x": "^4.16.1",
83
- "eslint-plugin-n": "^17.24.0",
84
- "eslint-plugin-prettier": "^5.5.5",
85
- "eslint-plugin-unicorn": "^63.0.0",
80
+ "eslint": "^10.5.0",
81
+ "eslint-config-xo": "^0.53.1",
82
+ "eslint-formatter-pretty": "^7.1.0",
86
83
  "find-cache-directory": "^6.0.0",
87
84
  "get-stdin": "^10.0.0",
88
- "get-tsconfig": "^4.13.6",
89
- "globals": "^17.3.0",
90
- "globby": "^16.1.1",
85
+ "get-tsconfig": "^4.14.0",
86
+ "globby": "^16.2.0",
87
+ "jiti": "^2.7.0",
91
88
  "meow": "^14.1.0",
92
89
  "micromatch": "^4.0.8",
93
90
  "open-editor": "^6.0.0",
94
91
  "path-exists": "^5.0.0",
95
- "prettier": "^3.8.1",
96
- "type-fest": "^5.4.3",
97
- "typescript": "^5.9.3",
98
- "typescript-eslint": "^8.56.1"
92
+ "prettier": "^3.8.4",
93
+ "type-fest": "^5.7.0",
94
+ "typescript": "^6.0.3"
99
95
  },
100
96
  "devDependencies": {
101
- "@commitlint/cli": "^20.4.1",
102
- "@commitlint/config-conventional": "^20.4.1",
103
97
  "@types/micromatch": "^4.0.10",
104
- "@types/node": "^25.2.1",
105
- "@types/prettier": "^3.0.0",
106
- "ava": "^7.0.0",
107
- "dedent": "^1.7.1",
98
+ "@types/node": "^25.9.3",
99
+ "dedent": "^1.7.2",
100
+ "eslint-plugin-vue": "^10.9.2",
108
101
  "execa": "^9.6.1",
109
102
  "husky": "^9.1.7",
110
- "lint-staged": "^16.3.4",
111
- "np": "^11.0.2",
112
- "npm-package-json-lint": "^9.1.0",
113
- "npm-package-json-lint-config-default": "^8.0.1",
114
- "prettier-plugin-packagejson": "^3.0.0",
103
+ "np": "^11.2.1",
115
104
  "temp-dir": "^3.0.0",
116
105
  "xo": "file:."
117
106
  },
118
- "ava": {
119
- "files": [
120
- "dist/test/**/*.js",
121
- "!dist/test/fixtures/**",
122
- "!dist/test/helpers/**",
123
- "!dist/test/scripts/**"
124
- ],
125
- "nodeArguments": [
126
- "--enable-source-maps"
127
- ],
128
- "timeout": "1m",
129
- "verbose": true,
130
- "watchMode": {
131
- "ignoreChanges": [
132
- ".history",
133
- ".history/**/*",
134
- "node_modules",
135
- "package.json",
136
- "xo.config.*",
137
- "**/*.ts"
138
- ]
139
- }
140
- },
141
107
  "nyc": {
142
108
  "reporter": [
143
109
  "text",
144
110
  "lcov"
145
111
  ]
146
- },
147
- "xo": {
148
- "rules": {
149
- "ava/no-ignored-test-files": "off"
150
- }
151
112
  }
152
113
  }
package/readme.md CHANGED
@@ -34,7 +34,6 @@ It uses [ESLint](https://eslint.org) underneath, so issues regarding built-in ru
34
34
  - Open all files with errors at the correct line in your editor with `$ xo --open`.
35
35
  - Specify [indent](#space) and [semicolon](#semicolon) preferences easily without messing with the rule config.
36
36
  - Optionally use the [Prettier](https://github.com/prettier/prettier) code style or turn off all Prettier rules with the `compat` option.
37
- - Optionally use `eslint-config-xo-react` for easy JSX and React linting with zero config.
38
37
  - Optionally use with ESLint [directly](#usage-as-an-eslint-configuration)
39
38
  - Great [editor plugins](#editor-plugins).
40
39
 
@@ -46,33 +45,34 @@ npm install xo --save-dev
46
45
 
47
46
  *You must install XO locally. You can run it directly with `$ npx xo`.*
48
47
 
49
- *For framework-specific linting, see [Astro](#astro), [Svelte](#svelte), and [Vue](#vue).*
48
+ *For framework-specific linting, see [Astro](#astro), [React](#react), [Svelte](#svelte), and [Vue](#vue).*
50
49
 
51
50
  ## Usage
52
51
 
53
- ```
52
+ ```console
54
53
  $ xo --help
55
54
 
56
55
  Usage
57
56
  $ xo [<file|glob> ...]
58
57
 
59
58
  Options
60
- --fix Automagically fix issues
61
- --fix-dry-run Automagically fix issues without saving the changes to the file system
62
- --reporter Reporter to use
63
- --space Use space indent instead of tabs [Default: 2]
64
- --config Path to a XO configuration file
65
- --semicolon Use semicolons [Default: true]
66
- --react Include React specific parsing and xo-react linting rules [Default: false]
67
- --prettier Format with prettier or turn off prettier-conflicted rules when set to 'compat' [Default: false]
68
- --print-config Print the effective ESLint config for the given file
69
- --version Print XO version
70
- --open Open files with issues in your editor
71
- --quiet Show only errors and no warnings
72
- --stdin Validate/fix code from stdin
73
- --stdin-filename Specify a filename for the --stdin option
74
- --ignore Ignore pattern globs, can be set multiple times
75
- --cwd=<dir> Working directory for files [Default: process.cwd()]
59
+ --fix Automagically fix issues
60
+ --fix-dry-run Automagically fix issues without saving the changes to the file system
61
+ --reporter Reporter to use
62
+ --space Use space indent instead of tabs [Default: 2]
63
+ --config Path to a XO configuration file
64
+ --semicolon Use semicolons [Default: true]
65
+ --prettier Format with prettier or turn off Prettier-conflicted rules when set to 'compat' [Default: false]
66
+ --print-config Print the effective ESLint config for the given file
67
+ --version Print XO version
68
+ --open Open files with issues in your editor
69
+ --quiet Show only errors and no warnings
70
+ --max-warnings Number of warnings to trigger nonzero exit code [Default: -1]
71
+ --stdin Validate/fix code from stdin
72
+ --stdin-filename Specify a filename for the --stdin option
73
+ --ignore Ignore pattern globs, can be set multiple times
74
+ --suppressions-location Path to a custom ESLint suppressions file
75
+ --cwd=<dir> Working directory for files [Default: process.cwd()]
76
76
 
77
77
  Examples
78
78
  $ xo
@@ -89,7 +89,7 @@ $ xo --help
89
89
 
90
90
  ## Default code style
91
91
 
92
- *Any of these can be [overridden](#rules) if necessary.*
92
+ *Any of these can be [overridden](#shareable-configs) if necessary.*
93
93
 
94
94
  - Tab indentation *[(or space)](#space)*
95
95
  - Semicolons *[(or not)](#semicolon)*
@@ -152,6 +152,16 @@ Some [paths](lib/constants.ts) are ignored by default, including paths in `.giti
152
152
 
153
153
  > Tip: For *global* ignores, keep `ignores` as the only key in the config item. You can optionally set a `name` property. Adding more properties will cause ignores to be scoped down to your files selection, which may have unexpected effects.
154
154
 
155
+ Global negated ignores are supported in both config files and the CLI for reopening XO's built-in ignored paths. This includes directory globs like `!dist/**`, file globs like `!**/*.min.js`, and literal file paths like `!dist/src/index.js`.
156
+
157
+ When global ignores are involved, XO uses them in this order:
158
+
159
+ 1. Built-in default ignores
160
+ 2. Global config `ignores`
161
+ 3. CLI `ignores`
162
+
163
+ XO keeps positive ignores for fast file discovery and only rechecks XO's own default-ignored paths. ESLint makes the final ignore decision.
164
+
155
165
  ### space
156
166
 
157
167
  Type: `boolean | number`\
@@ -175,36 +185,22 @@ Default: `false`
175
185
 
176
186
  Format code with [Prettier](https://github.com/prettier/prettier).
177
187
 
178
- [Prettier options](https://prettier.io/docs/en/options.html) will be based on your [Prettier config](https://prettier.io/docs/en/configuration.html). XO will then **merge** your options with its own defaults:
188
+ XO applies its own [Prettier options](https://prettier.io/docs/en/options.html):
179
189
 
180
190
  - [semi](https://prettier.io/docs/en/options.html#semicolons): based on [semicolon](#semicolon) option
181
191
  - [useTabs](https://prettier.io/docs/en/options.html#tabs): based on [space](#space) option
182
192
  - [tabWidth](https://prettier.io/docs/en/options.html#tab-width): based on [space](#space) option
183
193
  - [singleQuote](https://prettier.io/docs/en/options.html#quotes): `true`
184
194
  - [bracketSpacing](https://prettier.io/docs/en/options.html#bracket-spacing): `false`
195
+ - [bracketSameLine](https://prettier.io/docs/en/options.html#bracket-line): `false`
196
+ - [trailingComma](https://prettier.io/docs/en/options.html#trailing-commas): `all`
185
197
 
186
- To stick with Prettier's defaults, add this to your Prettier config:
187
-
188
- ```js
189
- export default {
190
- singleQuote: false,
191
- bracketSpacing: true,
192
- };
193
- ```
194
-
195
- If contradicting options are set for both Prettier and XO, an error will be thrown.
198
+ Any options you set in a [Prettier config](https://prettier.io/docs/en/configuration.html) still apply for anything XO does not configure (like `printWidth` or plugins), but XO's own style settings take precedence.
196
199
 
197
200
  #### Compat
198
201
 
199
202
  If the Prettier option is set to `compat`, instead of formatting your code automatically, XO will turn off all rules that conflict with Prettier code style and allow you to pass your formatting to the Prettier tool directly.
200
203
 
201
- ### react
202
-
203
- Type: `boolean`\
204
- Default: `false`
205
-
206
- Adds `eslint-plugin-react`, `eslint-plugin-react-hooks`, and `eslint-config-xo-react` to get all the React best practices applied automatically.
207
-
208
204
  ### Astro
209
205
 
210
206
  To lint [Astro](https://astro.build) files, install [`eslint-plugin-astro`](https://github.com/ota-meshi/eslint-plugin-astro):
@@ -225,6 +221,29 @@ const xoConfig = [
225
221
  export default xoConfig;
226
222
  ```
227
223
 
224
+ ### React
225
+
226
+ To lint [React](https://react.dev) files, install [`eslint-config-xo-react`](https://github.com/xojs/eslint-config-xo-react):
227
+
228
+ ```sh
229
+ npm install --save-dev eslint-config-xo-react
230
+ ```
231
+
232
+ Then spread it in your `xo.config.js`:
233
+
234
+ ```js
235
+ import xoReact from 'eslint-config-xo-react';
236
+
237
+ const xoConfig = [
238
+ ...xoReact(),
239
+ ];
240
+
241
+ export default xoConfig;
242
+ ```
243
+
244
+ > [!NOTE]
245
+ > Until `eslint-plugin-react` supports ESLint 10 natively, you may need to wrap the config with [`fixupConfigRules`](https://github.com/eslint/rewrite/tree/main/packages/compat) from `@eslint/compat`.
246
+
228
247
  ### Svelte
229
248
 
230
249
  To lint [Svelte](https://svelte.dev) files, install [`eslint-plugin-svelte`](https://github.com/sveltejs/eslint-plugin-svelte):
@@ -265,6 +284,31 @@ const xoConfig = [
265
284
  export default xoConfig;
266
285
  ```
267
286
 
287
+ ### Shareable configs
288
+
289
+ If you want to extend a [shareable ESLint config](https://eslint.org/docs/latest/extend/shareable-configs) or any other npm package, use `xo.config.js` instead of `package.json`, since `package.json` only supports serializable values and cannot `import`.
290
+
291
+ `xo.config.js`
292
+
293
+ ```js
294
+ export {default} from 'my-shareable-config';
295
+ ```
296
+
297
+ You can also extend and override:
298
+
299
+ ```js
300
+ import myConfig from 'my-shareable-config';
301
+
302
+ export default [
303
+ ...myConfig,
304
+ {
305
+ rules: {
306
+ // Your overrides
307
+ },
308
+ },
309
+ ];
310
+ ```
311
+
268
312
  ## TypeScript
269
313
 
270
314
  XO will automatically lint TypeScript files (`.ts`, `.mts`, `.cts`, and `.tsx`) with the rules defined in [eslint-config-xo-typescript#use-with-xo](https://github.com/xojs/eslint-config-xo-typescript#use-with-xo).
@@ -275,20 +319,33 @@ You can opt out of XO's automatic tsconfig handling by specifying your own `lang
275
319
 
276
320
  ## Usage as an ESLint Configuration
277
321
 
278
- With the introduction of the ESLint flat config, many of the original goals of `xo` were brought into the ESLint core, and shareable configs with plugins became possible. Although we highly recommend the use of the `xo` cli, we understand that some teams need to rely on ESLint directly.
279
-
280
- For these purposes, you can still get most of the features of `xo` by using our ESLint configuration helpers.
322
+ There are two different ways to use XO's rules with ESLint directly, depending on whether you use the `xo` CLI.
281
323
 
282
- ### xoToEslintConfig
324
+ ### Without the `xo` CLI
283
325
 
284
- The `xoToEslintConfig` function is designed for use in an `eslint.config.js` file. It is NOT for use in an `xo.config.js` file. This function takes a `FlatXoConfig` and outputs an ESLint config object. This function will neither be able to automatically handle TS integration for you nor automatic Prettier integration. You are responsible for configuring your other tools appropriately. The `xo` cli, will, however, handle all of these details for you.
326
+ If you don't use the `xo` CLI and just want XO's rules in ESLint, use [`eslint-config-xo`](https://github.com/xojs/eslint-config-xo). It accepts the same core style options as XO, including Prettier integration:
285
327
 
286
328
  `eslint.config.js`
287
329
 
288
330
  ```js
289
- import xo from 'xo';
331
+ import eslintConfigXo from 'eslint-config-xo';
290
332
 
291
- export default xo.xoToEslintConfig([{space: true, prettier: 'compat'}]);
333
+ export default [
334
+ ...eslintConfigXo({space: true, prettier: true}),
335
+ ];
336
+ ```
337
+
338
+ > [!NOTE]
339
+ > This replaces the old `xoToEslintConfig` helper. For example, `xoToEslintConfig([{space: true, prettier: true}])` becomes `eslintConfigXo({space: true, prettier: true})`. For per-file overrides, add normal ESLint config objects alongside it.
340
+
341
+ ### With the `xo` CLI (editor integration)
342
+
343
+ If you use the `xo` CLI but your editor only has the ESLint extension (not [XO's](#editor-plugins)), add an `eslint.config.js` that re-exports the adapter. It reads your `xo.config.js` and generates the matching ESLint config automatically, so your editor shows the same errors as running `xo` — without duplicating your config.
344
+
345
+ `eslint.config.js`
346
+
347
+ ```js
348
+ export {default} from 'xo/eslint-adapter';
292
349
  ```
293
350
 
294
351
  ## Tips
@@ -307,17 +364,47 @@ const xoConfig = [{ignores: ['!vendor/**']}];
307
364
  export default xoConfig;
308
365
  ```
309
366
 
367
+ This also works for narrower carve-outs:
368
+
369
+ ```js
370
+ const xoConfig = [{ignores: ['!dist/src/**', '!dist/src/index.js']}];
371
+
372
+ export default xoConfig;
373
+ ```
374
+
375
+ ### Warnings are hidden when there are errors
376
+
377
+ When XO finds errors, warnings are automatically hidden to reduce noise and let you focus on what matters. Warnings are shown normally when there are no errors. Use `--quiet` to always suppress warnings, or `--max-warnings` to treat warnings as errors.
378
+
379
+ ### Bulk suppression
380
+
381
+ XO automatically respects an [`eslint-suppressions.json`](https://eslint.org/docs/latest/use/suppressions) file if one exists in the working directory. This lets you suppress existing violations while still enforcing rules on new code — useful for incrementally adopting stricter rules in a large codebase.
382
+
383
+ To generate the suppressions file, create a temporary `eslint.config.js` using [`xo/eslint-adapter`](#with-the-xo-cli-editor-integration) and run ESLint with `--suppress-all`:
384
+
385
+ ```sh
386
+ npx eslint --suppress-all
387
+ ```
388
+
389
+ Commit the resulting `eslint-suppressions.json` to share suppressions across your team.
390
+
391
+ To use a custom suppressions file path, pass `--suppressions-location`:
392
+
393
+ ```sh
394
+ xo --suppressions-location config/suppressions.json
395
+ ```
396
+
310
397
  ## FAQ
311
398
 
312
- #### What does XO mean?
399
+ ### What does XO mean?
313
400
 
314
401
  It means [hugs and kisses](https://en.wiktionary.org/wiki/xoxo).
315
402
 
316
- #### Why not Standard?
403
+ ### Why not Standard?
317
404
 
318
405
  The [Standard style](https://standardjs.com) is a really cool idea. I too wish we could have one style to rule them all! But the reality is that the JS community is just too diverse and opinionated to create *one* code style. They also made the mistake of pushing their own style instead of the most popular one. In contrast, XO is more pragmatic and has no aspiration of being *the* style. My goal with XO is to make it simple to enforce consistent code style with close to no config. XO comes with my code style preference by default, as I mainly made it for myself, but everything is configurable.
319
406
 
320
- #### Why not ESLint?
407
+ ### Why not ESLint?
321
408
 
322
409
  XO is based on ESLint. This project started out as just a shareable ESLint config, but it quickly grew out of that. I wanted something even simpler. Just typing `xo` and be done. No decision-making. No config. I also have some exciting future plans for it. However, you can still get most of the XO benefits while using ESLint directly with the [ESLint shareable config](https://github.com/xojs/eslint-config-xo).
323
410
 
@@ -376,14 +463,3 @@ Large badge: [![XO code style](https://shields.io/badge/code_style-5ed9c7?style=
376
463
  Or [customize the badge](https://github.com/xojs/xo/issues/689#issuecomment-1253127616).
377
464
 
378
465
  You can also find some nice dynamic XO badges on [badgen.net](https://badgen.net/#xo).
379
-
380
- ## Team
381
-
382
- - [Sindre Sorhus](https://github.com/sindresorhus)
383
-
384
- ###### Former
385
-
386
- - [James Talmage](https://github.com/jamestalmage)
387
- - [Michael Mayer](https://github.com/schnittstabil)
388
- - [Mario Nebl](https://github.com/marionebl)
389
- - [Pierre Vanduynslager](https://github.com/pvdlg)
@@ -1,3 +0,0 @@
1
- import { type Rule } from 'eslint';
2
- declare const noUseExtendNativeRule: Rule.RuleModule;
3
- export default noUseExtendNativeRule;