UNPKG

18.9 kBMarkdownView Raw
1<h1 align="center">
2 <br>
3 <img width="400" src="media/logo.svg" alt="XO">
4 <br>
5 <br>
6 <br>
7</h1>
8
9> JavaScript/TypeScript linter (ESLint wrapper) with great defaults
10
11[![Coverage Status](https://codecov.io/gh/xojs/xo/branch/main/graph/badge.svg)](https://codecov.io/gh/xojs/xo/branch/main)
12[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
13
14Opinionated but configurable ESLint wrapper with lots of goodies included. Enforces strict and readable code. Never discuss code style on a pull request again! No decision-making. No `.eslintrc` to manage. It just works!
15
16It uses [ESLint](https://eslint.org) underneath, so issues regarding built-in rules should be opened over [there](https://github.com/eslint/eslint/issues).
17
18**XO requires your project to be [ESM](https://blog.sindresorhus.com/hello-modules-d1010b4e777b).**
19
20![](https://raw.githubusercontent.com/sindresorhus/eslint-formatter-pretty/main/screenshot.png)
21
22## Highlights
23
24- Beautiful output.
25- Zero-config, but [configurable when needed](#config).
26- Enforces readable code, because you read more code than you write.
27- No need to specify file paths to lint as it lints all JS/TS files except for [commonly ignored paths](#ignores).
28- [Config overrides per files/globs.](#config-overrides)
29- [TypeScript supported by default](#typescript)
30- Includes many useful ESLint plugins, like [`unicorn`](https://github.com/sindresorhus/eslint-plugin-unicorn), [`import`](https://github.com/benmosher/eslint-plugin-import), [`ava`](https://github.com/avajs/eslint-plugin-ava), [`node`](https://github.com/mysticatea/eslint-plugin-node) and more.
31- Automatically enables rules based on the [`engines`](https://docs.npmjs.com/files/package.json#engines) field in your `package.json`.
32- Caches results between runs for much better performance.
33- Super simple to add XO to a project with [`$ npm init xo`](https://github.com/xojs/create-xo).
34- Fix many issues automagically with `$ xo --fix`.
35- Open all files with errors at the correct line in your editor with `$ xo --open`.
36- Specify [indent](#space) and [semicolon](#semicolon) preferences easily without messing with the rule config.
37- Optionally use the [Prettier](https://github.com/prettier/prettier) code style.
38- Great [editor plugins](#editor-plugins).
39
40## Install
41
42```
43$ npm install xo --save-dev
44```
45
46*You must install XO locally. You can run it directly with `$ npx xo`.*
47
48*JSX is supported by default, but you'll need [eslint-config-xo-react](https://github.com/xojs/eslint-config-xo-react#use-with-xo) for React specific linting. Vue components are not supported by default. You'll need [eslint-config-xo-vue](https://github.com/ChocPanda/eslint-config-xo-vue#use-with-xo) for specific linting in a Vue app.*
49
50## Usage
51
52```
53$ xo --help
54
55 Usage
56 $ xo [<file|glob> ...]
57
58 Options
59 --fix Automagically fix issues
60 --reporter Reporter to use
61 --env Environment preset [Can be set multiple times]
62 --global Global variable [Can be set multiple times]
63 --ignore Additional paths to ignore [Can be set multiple times]
64 --space Use space indent instead of tabs [Default: 2]
65 --no-semicolon Prevent use of semicolons
66 --prettier Conform to Prettier code style
67 --node-version Range of Node.js version to support
68 --plugin Include third-party plugins [Can be set multiple times]
69 --extend Extend defaults with a custom config [Can be set multiple times]
70 --open Open files with issues in your editor
71 --quiet Show only errors and no warnings
72 --extension Additional extension to lint [Can be set multiple times]
73 --cwd=<dir> Working directory for files
74 --stdin Validate/fix code from stdin
75 --stdin-filename Specify a filename for the --stdin option
76 --print-config Print the ESLint configuration for the given file
77
78 Examples
79 $ xo
80 $ xo index.js
81 $ xo *.js !foo.js
82 $ xo --space
83 $ xo --env=node --env=mocha
84 $ xo --plugin=react
85 $ xo --plugin=html --extension=html
86 $ echo 'const x=true' | xo --stdin --fix
87 $ xo --print-config=index.js
88
89 Tips
90 - Add XO to your project with `npm init xo`.
91 - Put options in package.json instead of using flags so other tools can read it.
92```
93
94## Default code style
95
96*Any of these can be [overridden](#rules) if necessary.*
97
98- Tab indentation *[(or space)](#space)*
99- Semicolons *[(or not)](#semicolon)*
100- Single-quotes
101- [Trailing comma](https://medium.com/@nikgraf/why-you-should-enforce-dangling-commas-for-multiline-statements-d034c98e36f8) for multiline statements
102- No unused variables
103- Space after keyword `if (condition) {}`
104- Always `===` instead of `==`
105
106Check out an [example](index.js) and the [ESLint rules](https://github.com/xojs/eslint-config-xo/blob/main/index.js).
107
108## Workflow
109
110The recommended workflow is to add XO locally to your project and run it with the tests.
111
112Simply run `$ npm init xo` (with any options) to add XO to your package.json or create one.
113
114### Before/after
115
116```diff
117 {
118 "name": "awesome-package",
119 "scripts": {
120- "test": "ava",
121+ "test": "xo && ava"
122 },
123 "devDependencies": {
124- "ava": "^3.0.0"
125+ "ava": "^3.0.0",
126+ "xo": "^0.41.0"
127 }
128 }
129```
130
131Then just run `$ npm test` and XO will be run before your tests.
132
133## Config
134
135You can configure XO options with one of the following files:
136
1371. As JSON in the `xo` property in `package.json`:
138
139```json
140{
141 "name": "awesome-package",
142 "xo": {
143 "space": true
144 }
145}
146```
147
1482. As JSON in `.xo-config` or `.xo-config.json`:
149
150```json
151{
152 "space": true
153}
154```
155
1563. As a JavaScript module in `.xo-config.js` or `xo.config.js`:
157
158```js
159module.exports = {
160 space: true
161};
162```
163
1644. For [ECMAScript module (ESM)](https://nodejs.org/api/esm.html) packages with [`"type": "module"`](https://nodejs.org/api/packages.html#packages_type), as a JavaScript module in `.xo-config.cjs` or `xo.config.cjs`:
165
166```js
167module.exports = {
168 space: true
169};
170```
171
172[Globals](https://eslint.org/docs/user-guide/configuring/language-options#specifying-globals) and [rules](https://eslint.org/docs/user-guide/configuring/rules#configuring-rules) can be configured inline in files.
173
174### envs
175
176Type: `string[]`\
177Default: `['es2021', 'node']`
178
179Which [environments](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments) your code is designed to run in. Each environment brings with it a certain set of predefined global variables.
180
181### globals
182
183Type: `string[]`
184
185Additional global variables your code accesses during execution.
186
187### ignores
188
189Type: `string[]`
190
191Some [paths](lib/options-manager.js) are ignored by default, including paths in `.gitignore` and [.eslintignore](https://eslint.org/docs/user-guide/configuring/ignoring-code#the-eslintignore-file). Additional ignores can be added here.
192
193### space
194
195Type: `boolean | number`\
196Default: `false` *(tab indentation)*
197
198Set it to `true` to get 2-space indentation or specify the number of spaces.
199
200This option exists for pragmatic reasons, but I would strongly recommend you read ["Why tabs are superior"](http://lea.verou.me/2012/01/why-tabs-are-clearly-superior/).
201
202### rules
203
204Type: `object`
205
206Override any of the [default rules](https://github.com/xojs/eslint-config-xo/blob/main/index.js). See the [ESLint docs](https://eslint.org/docs/rules/) for more info on each rule.
207
208Please take a moment to consider if you really need to use this option.
209
210### semicolon
211
212Type: `boolean`\
213Default: `true` *(Semicolons required)*
214
215Set it to `false` to enforce no-semicolon style.
216
217### prettier
218
219Type: `boolean`\
220Default: `false`
221
222Format code with [Prettier](https://github.com/prettier/prettier).
223
224[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:
225- [semi](https://prettier.io/docs/en/options.html#semicolons): based on [semicolon](#semicolon) option
226- [useTabs](https://prettier.io/docs/en/options.html#tabs): based on [space](#space) option
227- [tabWidth](https://prettier.io/docs/en/options.html#tab-width): based on [space](#space) option
228- [trailingComma](https://prettier.io/docs/en/options.html#trailing-commas): `all`
229- [singleQuote](https://prettier.io/docs/en/options.html#quotes): `true`
230- [bracketSpacing](https://prettier.io/docs/en/options.html#bracket-spacing): `false`
231
232To stick with Prettier's defaults, add this to your Prettier config:
233
234```js
235module.exports = {
236 trailingComma: 'es5',
237 singleQuote: false,
238 bracketSpacing: true,
239};
240```
241
242If contradicting options are set for both Prettier and XO an error will be thrown.
243
244### nodeVersion
245
246Type: `string | boolean`\
247Default: Value of the `engines.node` key in the project `package.json`
248
249Enable rules specific to the Node.js versions within the configured range.
250
251If set to `false`, no rules specific to a Node.js version will be enabled.
252
253### plugins
254
255Type: `string[]`
256
257Include third-party [plugins](https://eslint.org/docs/user-guide/configuring/plugins#configuring-plugins).
258
259### extends
260
261Type: `string | string[]`
262
263Use one or more [shareable configs](https://eslint.org/docs/developer-guide/shareable-configs) or [plugin configs](https://eslint.org/docs/user-guide/configuring/configuration-files#using-a-configuration-from-a-plugin) to override any of the default rules (like `rules` above).
264
265### extensions
266
267Type: `string[]`
268
269Allow more extensions to be linted besides `.js`, `.jsx`, `.mjs`, and `.cjs`. Make sure they're supported by ESLint or an ESLint plugin.
270
271### settings
272
273Type: `object`
274
275[Shared ESLint settings](https://eslint.org/docs/user-guide/configuring/configuration-files#adding-shared-settings) exposed to rules.
276
277### parser
278
279Type: `string`
280
281ESLint parser. For example, [`@babel/eslint-parser`](https://github.com/babel/babel/tree/main/eslint/babel-eslint-parser) if you're using language features that ESLint doesn't yet support.
282
283### processor
284
285Type: `string`
286
287[ESLint processor.](https://eslint.org/docs/user-guide/configuring/plugins#specifying-processor)
288
289### webpack
290
291Type: `boolean | object`
292Default: `false`
293
294Use [eslint-import-resolver-webpack](https://github.com/benmosher/eslint-plugin-import/tree/master/resolvers/webpack) to resolve import search paths. This is enabled automatically if a `webpack.config.js` file is found.
295
296Set this to a boolean to explicitly enable or disable the resolver.
297
298Setting this to an object enables the resolver and passes the object as configuration. See the [resolver readme](https://github.com/benmosher/eslint-plugin-import/blob/master/resolvers/webpack/README.md) along with the [webpack documentation](https://webpack.js.org/configuration/resolve/) for more information.
299
300## TypeScript
301
302XO will automatically lint TypeScript files (`.ts`, `.d.ts` 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).
303
304XO will handle the [@typescript-eslint/parser `project` option](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject) automatically even if you don't have a `tsconfig.json` in your project.
305
306## GitHub Actions
307
308XO uses a different formatter when running in a GitHub Actions workflow to be able to get [inline annotations](https://developer.github.com/changes/2019-09-06-more-check-annotations-shown-in-files-changed-tab/). XO also disables warnings here.
309
310**Note**: For this to work, the [setup-node](https://github.com/actions/setup-node) action must be run before XO.
311
312## Config Overrides
313
314XO makes it easy to override configs for specific files. The `overrides` property must be an array of override objects. Each override object must contain a `files` property which is a glob string, or an array of glob strings, relative to the config file. The remaining properties are identical to those described above, and will override the settings of the base config. If multiple override configs match the same file, each matching override is applied in the order it appears in the array. This means the last override in the array takes precedence over earlier ones. Consider the following example:
315
316```json
317{
318 "xo": {
319 "semicolon": false,
320 "space": 2,
321 "overrides": [
322 {
323 "files": "test/*.js",
324 "space": 3
325 },
326 {
327 "files": "test/foo.js",
328 "semicolon": true
329 }
330 ]
331 }
332}
333```
334
335- The base configuration is simply `space: 2`, `semicolon: false`. These settings are used for every file unless otherwise noted below.
336
337- For every file in `test/*.js`, the base config is used, but `space` is overridden with `3`. The resulting config is:
338
339```json
340{
341 "semicolon": false,
342 "space": 3
343}
344```
345
346- For `test/foo.js`, the base config is first applied, followed the first overrides config (its glob pattern also matches `test/foo.js`), finally the second override config is applied. The resulting config is:
347
348```json
349{
350 "semicolon": true,
351 "space": 3
352}
353```
354
355## Tips
356
357### Using a parent's config
358
359If you have a directory structure with nested `package.json` files and you want one of the child manifests to be skipped, you can do so by ommiting the `xo` property in the child's `package.json`. For example, when you have separate app and dev `package.json` files with `electron-builder`.
360
361### Monorepo
362
363Put a `package.json` with your config at the root and omit the `xo` property in the `package.json` of your bundled packages.
364
365### Transpilation
366
367If some files in your project are transpiled in order to support an older Node.js version, you can use the [config overrides](#config-overrides) option to set a specific [`nodeVersion`](#nodeversion) to target your sources files.
368
369For example, if your project targets Node.js 8 but you want to use the latest JavaScript syntax as supported in Node.js 12:
3701. Set the `engines.node` property of your `package.json` to `>=8`
3712. Configure [Babel](https://babeljs.io) to transpile your source files (in `src` directory in this example)
3723. Make sure to include the transpiled files in your published package with the [`files`](https://docs.npmjs.com/files/package.json#files) and [`main`](https://docs.npmjs.com/files/package.json#main) properties of your `package.json`
3734. Configure the XO `overrides` option to set `nodeVersion` to `>=12` for your source files directory
374
375```json
376{
377 "engines": {
378 "node": ">=12"
379 },
380 "scripts": {
381 "build": "babel src --out-dir dist"
382 },
383 "main": "dist/index.js",
384 "files": ["dist/**/*.js"],
385 "xo": {
386 "overrides": [
387 {
388 "files": "{src}/**/*.js",
389 "nodeVersion": ">=16"
390 }
391 ]
392 }
393}
394```
395
396This way your `package.json` will contain the actual minimum Node.js version supported by your published code, but XO will lint your source code as if it targets Node.js 16.
397
398### Including files ignored by default
399
400To include files that XO [ignores by default](lib/constants.js#L1), add them as negative globs in the `ignores` option:
401
402```json
403{
404 "xo": {
405 "ignores": [
406 "!vendor/**"
407 ]
408 }
409}
410```
411
412## FAQ
413
414#### What does XO mean?
415
416It means [hugs and kisses](https://en.wiktionary.org/wiki/xoxo).
417
418#### Why not Standard?
419
420The [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.
421
422#### Why not ESLint?
423
424XO 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).
425
426## Editor plugins
427
428- [Sublime Text](https://github.com/xojs/SublimeLinter-contrib-xo)
429- [Atom](https://github.com/xojs/atom-linter-xo)
430- [Vim](https://github.com/xojs/vim-xo)
431- [TextMate 2](https://github.com/claylo/XO.tmbundle)
432- [VSCode](https://github.com/SamVerschueren/vscode-linter-xo)
433- [Emacs](https://github.com/j-em/xo-emacs)
434- [WebStorm](https://github.com/jamestalmage/xo-with-webstorm)
435
436## Build-system plugins
437
438- [Gulp](https://github.com/xojs/gulp-xo)
439- [Grunt](https://github.com/xojs/grunt-xo)
440- [webpack loader](https://github.com/Semigradsky/xo-loader)
441- [webpack plugin](https://github.com/nstanard/xo-webpack-plugin)
442- [Metalsmith](https://github.com/blainsmith/metalsmith-xo)
443- [Fly](https://github.com/lukeed/fly-xo)
444
445## Configs
446
447- [eslint-config-xo](https://github.com/xojs/eslint-config-xo) - ESLint shareable config for XO with tab indent
448- [eslint-config-xo-space](https://github.com/xojs/eslint-config-xo-space) - ESLint shareable config for XO with 2-space indent
449- [eslint-config-xo-react](https://github.com/xojs/eslint-config-xo-react) - ESLint shareable config for React to be used with the above
450- [eslint-config-xo-vue](https://github.com/ChocPanda/eslint-config-xo-vue) - ESLint shareable config for Vue to be used with the above
451- [stylelint-config-xo](https://github.com/xojs/stylelint-config-xo) - Stylelint shareable config for XO with tab indent
452- [stylelint-config-xo-space](https://github.com/xojs/stylelint-config-xo-space) - Stylelint shareable config for XO with 2-space indent
453- [tslint-xo](https://github.com/xojs/tslint-xo) - TSLint shareable config for XO
454- [eslint-config-xo-typescript](https://github.com/xojs/eslint-config-xo-typescript) - ESLint shareable config for TypeScript
455
456## Support
457
458- [Twitter](https://twitter.com/sindresorhus)
459
460## Related
461
462- [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) - Various awesome ESLint rules *(Bundled in XO)*
463- [xo-summary](https://github.com/LitoMore/xo-summary) - Display output from `xo` as a list of style errors, ordered by count
464
465## Badge
466
467Show the world you're using XO → [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
468
469```md
470[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
471```
472
473You can also find some nice dynamic XO badges on [badgen.net](https://badgen.net/#xo).
474
475## Team
476
477- [Sindre Sorhus](https://github.com/sindresorhus)
478
479###### Former
480
481- [James Talmage](https://github.com/jamestalmage)
482- [Michael Mayer](https://github.com/schnittstabil)
483- [Mario Nebl](https://github.com/marionebl)
484- [Pierre Vanduynslager](https://github.com/pvdlg)