@tommy-mitchell/eslint-config-xo 2.0.0-beta.6 → 2.0.0-beta.8

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,60 +1,59 @@
1
1
  {
2
2
  "name": "@tommy-mitchell/eslint-config-xo",
3
- "version": "2.0.0-beta.6",
3
+ "version": "2.0.0-beta.8",
4
4
  "description": "Personal config for XO.",
5
- "keywords": [
6
- "nodejs",
7
- "config",
8
- "xo"
9
- ],
10
- "repository": "tommy-mitchell/eslint-config-xo",
11
5
  "license": "MIT",
12
- "author": {
13
- "name": "Tommy Mitchell",
14
- "url": "https://tommymitchell.io"
15
- },
16
- "sideEffects": false,
6
+ "repository": "tommy-mitchell/eslint-config-xo",
7
+ "author": "Tommy Mitchell (https://tommymitchell.io)",
17
8
  "type": "module",
18
- "files": [
19
- "src"
20
- ],
21
9
  "exports": {
22
10
  "types": "./src/index.d.ts",
23
11
  "default": "./src/index.js"
24
12
  },
13
+ "sideEffects": false,
14
+ "engines": {
15
+ "node": "^22.22 || ^24.15 || >=26"
16
+ },
25
17
  "scripts": {
26
- "format": "dprint fmt && xo --fix",
27
18
  "lint": "xo",
19
+ "format": "dprint fmt && xo --fix",
28
20
  "test": "ava"
29
21
  },
22
+ "files": [
23
+ "src"
24
+ ],
25
+ "keywords": [
26
+ "nodejs",
27
+ "config",
28
+ "xo"
29
+ ],
30
30
  "dependencies": {
31
- "@eslint-react/eslint-plugin": "^3.0.0",
32
- "@next/eslint-plugin-next": "^16.0.5",
33
- "@tanstack/eslint-plugin-router": "^1.161.6",
34
- "eslint-plugin-better-tailwindcss": "^4.3.2",
35
- "eslint-plugin-jsx-a11y": "^6.10.2",
36
- "eslint-plugin-perfectionist": "^5.7.0",
37
- "eslint-plugin-react-refresh": "^0.5.2",
38
- "eslint-plugin-simple-import-sort": "^12.1.1",
39
- "eslint-plugin-sort-react-dependency-arrays": "^1.0.0"
31
+ "@next/eslint-plugin-next": "^16.3.7",
32
+ "@tanstack/eslint-plugin-router": "^1.162.0",
33
+ "eslint-plugin-better-tailwindcss": "^4.7.0",
34
+ "eslint-plugin-perfectionist": "^5.12.1",
35
+ "eslint-plugin-react-refresh": "^0.5.7",
36
+ "eslint-plugin-simple-import-sort": "^14.0.0"
40
37
  },
41
38
  "devDependencies": {
42
- "@stylistic/eslint-plugin": "^5.6.1",
43
- "@tommy-mitchell/dprint-config": "0.6.0",
44
- "ava": "^7.0.0",
39
+ "@stylistic/eslint-plugin": "^5.10.0",
40
+ "@tommy-mitchell/dprint-config": "^0.8.0",
41
+ "@tommy-mitchell/tsconfig": "^4.0.0",
42
+ "@types/node": "^22.20.4",
43
+ "@types/react": "^19.3.0",
44
+ "ava": "^8.0.1",
45
45
  "dprint": "0.x",
46
- "execa": "^9.6.0",
47
- "react": "^19.2.0",
48
- "tailwindcss": "^4.1.17",
49
- "tempy": "^3.1.0",
50
- "typescript": "6.0.2",
51
- "xo": "~2.0.2"
46
+ "eslint-config-xo-react": "^0.32.0",
47
+ "react": "^19.3.0",
48
+ "tailwindcss": "^4.3.3",
49
+ "typescript": "~6.0.3",
50
+ "xo": "~5.0.1"
52
51
  },
53
52
  "peerDependencies": {
54
53
  "dprint": "0.x",
55
54
  "react": "19.x",
56
55
  "tailwindcss": "4.x",
57
- "xo": "2.x"
56
+ "xo": "5.x"
58
57
  },
59
58
  "peerDependenciesMeta": {
60
59
  "dprint": {
@@ -67,10 +66,10 @@
67
66
  "optional": true
68
67
  }
69
68
  },
70
- "engines": {
71
- "node": ">=22"
72
- },
73
69
  "ava": {
70
+ "extensions": [
71
+ "ts"
72
+ ],
74
73
  "timeout": "30s"
75
74
  }
76
75
  }
package/readme.md CHANGED
@@ -45,9 +45,9 @@ pnpm add --save-dev @tommy-mitchell/eslint-config-xo xo @tommy-mitchell/dprint-c
45
45
  ### Peer Dependencies
46
46
 
47
47
  - [xo](https://github.com/xojs/xo) - JavaScript/TypeScript linter (ESLint wrapper) with great defaults.
48
- - [dprint](https://github.com/dprint/dprint) (*Optional*) - Pluggable and configurable code formatting platform written in Rust.
49
- - [react](https://react.dev) (*Optional*) - The library for web and native user interfaces.
50
- - [tailwindcss](https://tailwindcss.com) (*Optional*) - A utility-first CSS framework for rapid UI development.
48
+ - [dprint](https://github.com/dprint/dprint) (_Optional_) - Pluggable and configurable code formatting platform written in Rust.
49
+ - [react](https://react.dev) (_Optional_) - The library for web and native user interfaces.
50
+ - [tailwindcss](https://tailwindcss.com) (_Optional_) - A utility-first CSS framework for rapid UI development.
51
51
 
52
52
  ## Usage (Flat Config)
53
53
 
@@ -58,13 +58,27 @@ import * as configs from "@tommy-mitchell/eslint-config-xo";
58
58
  /** @type {import('xo').FlatXoConfig} */
59
59
  export default [
60
60
  ...configs.xo,
61
- ...configs.react({ version: "19" }), // If using React
61
+ ...configs.react, // If using React
62
62
  ...configs.next, // If using Next.js
63
63
  ...configs.tanstack, // If using TanStack Start
64
64
  ...configs.tailwind({ config: "src/tailwind.css" }), // If using TailwindCSS
65
65
  ...configs.dprint, // If using dprint (must be last to override stylistic rules)
66
66
  // Plus any overrides
67
- ]
67
+ ];
68
+ ```
69
+
70
+ ### TailwindCSS
71
+
72
+ Add the following to your `settings.json` to prevent duplicate lints:
73
+
74
+ ```jsonc
75
+ "tailwindCSS.lint.suggestCanonicalClasses": "ignore",
76
+ ```
77
+
78
+ If using TailwindCSS v3:
79
+
80
+ ```js
81
+ configs.tailwind({ config: "tailwind.config.ts", version: "3" }),
68
82
  ```
69
83
 
70
84
  ### VS Code
@@ -81,7 +95,7 @@ Add the following to your `settings.json`:
81
95
  If formatting with `dprint`:
82
96
 
83
97
  ```jsonc
84
- "[javascript][javascriptreact][typescript][typescriptreact]": {
98
+ "[javascript][javascriptreact][typescript][typescriptreact][json][jsonc][yaml][markdown]": {
85
99
  "editor.formatOnSave": true,
86
100
  "editor.defaultFormatter": "dprint.dprint",
87
101
  "editor.codeActionsOnSave": {
package/src/index.d.ts CHANGED
@@ -3,6 +3,6 @@ import type { FlatXoConfig } from "xo";
3
3
  export declare const dprint: FlatXoConfig;
4
4
  export declare const next: FlatXoConfig;
5
5
  export declare const react: FlatXoConfig;
6
- export declare const tailwind: ({ config }: { config: string; }) => FlatXoConfig;
6
+ export declare const tailwind: (options: { config: string; version?: "3" | "4"; }) => FlatXoConfig;
7
7
  export declare const tanstack: FlatXoConfig;
8
8
  export declare const xo: FlatXoConfig;
package/src/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  export { default as dprint } from "./dprint.js";
2
2
  export { default as next } from "./next.js";
3
3
  export { default as react } from "./react.js";
4
- // TODO: only load if tailwind is installed
5
4
  export { default as tailwind } from "./tailwind.js";
6
5
  export { default as tanstack } from "./tanstack.js";
7
6
  export { default as xo } from "./xo.js";
package/src/react.js CHANGED
@@ -1,28 +1,48 @@
1
- import eslintReact from "@eslint-react/eslint-plugin";
2
- import jsxA11y from "eslint-plugin-jsx-a11y";
1
+ import eslintConfigXoReact from "eslint-config-xo-react";
3
2
  import { reactRefresh } from "eslint-plugin-react-refresh";
4
- import sortReactDependencyArrays from "eslint-plugin-sort-react-dependency-arrays";
3
+
4
+ const customGroups = [
5
+ { elementNamePattern: "^on[A-Z].*", groupName: "callback" },
6
+ { elementNamePattern: "^(children|dangerouslySetInnerHTML|key|ref)$", groupName: "reserved" },
7
+ ];
8
+
9
+ const reactDependencyHooks = [
10
+ "useCallback",
11
+ "useEffect",
12
+ "useImperativeHandle",
13
+ "useInsertionEffect",
14
+ "useLayoutEffect",
15
+ "useMemo",
16
+ ];
17
+
18
+ // useX()
19
+ const reactHookCallees = reactDependencyHooks.map(hook => ([
20
+ "[callee.type=\"Identifier\"]",
21
+ `[callee.name="${hook}"]`,
22
+ ].join(""))).join(", ");
23
+
24
+ // React.useX()
25
+ const reactHookMemberCallees = reactDependencyHooks.map(hook => ([
26
+ "[callee.type=\"MemberExpression\"]",
27
+ "[callee.object.type=\"Identifier\"]",
28
+ "[callee.object.name=\"React\"]",
29
+ "[callee.property.type=\"Identifier\"]",
30
+ `[callee.property.name="${hook}"]`,
31
+ ].join(""))).join(", ");
5
32
 
6
33
  /** @type {import('xo').FlatXoConfig} */
7
- export default [jsxA11y.flatConfigs.recommended, {
8
- ...eslintReact.configs.strict,
9
- files: "**/*.{jsx}",
10
- }, {
11
- ...eslintReact.configs["strict-type-checked"],
12
- files: "**/*.{tsx}",
13
- }, {
34
+ export default [...eslintConfigXoReact(), {
14
35
  plugins: {
15
36
  "react-refresh": reactRefresh.plugin,
16
- "sort-react-dependency-arrays": sortReactDependencyArrays,
17
37
  },
18
- // TODO: boolean-prop-naming
19
38
  rules: {
39
+ "perfectionist/sort-arrays": ["error", {
40
+ useConfigurationIf: {
41
+ matchesAstSelector: `CallExpression:is(${reactHookCallees}, ${reactHookMemberCallees}) > ArrayExpression`,
42
+ },
43
+ }],
20
44
  "perfectionist/sort-jsx-props": ["error", {
21
- customGroups: [
22
- // TODO: move groups to a constant for reuse
23
- { elementNamePattern: "^on[A-Z].*", groupName: "callback" },
24
- { elementNamePattern: "^(children|dangerouslySetInnerHTML|key|ref)$", groupName: "reserved" },
25
- ],
45
+ customGroups,
26
46
  groups: ["reserved", "shorthand-prop", "unknown", "callback"],
27
47
  }],
28
48
  "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
@@ -38,7 +58,6 @@ export default [jsxA11y.flatConfigs.recommended, {
38
58
  String.raw`^.+\.s?css$`,
39
59
  ]],
40
60
  }],
41
- "sort-react-dependency-arrays/sort": "error",
42
61
  "unicorn/filename-case": ["error", {
43
62
  cases: {
44
63
  camelCase: true,
@@ -47,20 +66,15 @@ export default [jsxA11y.flatConfigs.recommended, {
47
66
  },
48
67
  }],
49
68
  },
50
- }, {
51
- files: ["src/constants/**/*.{ts,cts,mts,tsx}", "**/constants.{ts,cts,mts,tsx}"],
52
- rules: {
53
- "@typescript-eslint/naming-convention": "off",
54
- },
55
69
  }, {
56
70
  files: "**/*.{ts,cts,mts,tsx}",
57
71
  rules: {
58
72
  "perfectionist/sort-interfaces": ["error", {
59
- customGroups: [{ elementNamePattern: "^on[A-Z].*", groupName: "callback" }],
73
+ customGroups,
60
74
  groups: ["unknown", "callback"],
61
75
  }],
62
76
  "perfectionist/sort-object-types": ["error", {
63
- customGroups: [{ elementNamePattern: "^on[A-Z].*", groupName: "callback" }],
77
+ customGroups,
64
78
  groups: ["unknown", "callback"],
65
79
  }],
66
80
  },
package/src/tailwind.js CHANGED
@@ -1,23 +1,23 @@
1
1
  import eslintPluginBetterTailwindcss from "eslint-plugin-better-tailwindcss";
2
2
 
3
- /** @type {({config}: {config: string}) => import('xo').FlatXoConfig} */
4
- export default ({ config }) => [{
5
- plugins: {
6
- "better-tailwindcss": eslintPluginBetterTailwindcss,
7
- },
3
+ // eslint-disable-next-line jsdoc/require-description
4
+ /** @type {(options: {config: string; version?: "3" | "4"}) => import('xo').FlatXoConfig} */
5
+ export default ({ config, version = "4" }) => [{
6
+ ...eslintPluginBetterTailwindcss.configs.recommended,
8
7
  rules: {
9
- ...eslintPluginBetterTailwindcss.configs.recommended.rules,
10
8
  "better-tailwindcss/enforce-consistent-line-wrapping": ["warn", {
11
9
  indent: "tab",
12
10
  preferSingleLine: true,
13
11
  printWidth: 120,
12
+ tabWidth: 2,
14
13
  }],
14
+ "better-tailwindcss/enforce-logical-properties": ["warn"],
15
15
  },
16
16
  settings: {
17
17
  "better-tailwindcss": {
18
18
  callees: ["clsx", "cn", "cnx", "cva", "cx", "tv", "twJoin", "twMerge"],
19
19
  detectComponentClasses: true,
20
- entryPoint: config, // v4 config path
20
+ ...(version === "3" ? { tailwindConfig: config } : { entryPoint: config }),
21
21
  },
22
22
  },
23
23
  }];
package/src/tanstack.js CHANGED
@@ -17,6 +17,7 @@ export default [
17
17
  ],
18
18
  }),
19
19
  {
20
+ files: "**/**.{ts,cts,mts,tsx}",
20
21
  rules: {
21
22
  "@typescript-eslint/only-throw-error": ["error", {
22
23
  allow: [{
package/src/xo.js CHANGED
@@ -28,6 +28,7 @@ export default [{
28
28
  }],
29
29
  "unicorn/prefer-regexp-test": "off",
30
30
  "unicorn/prevent-abbreviations": "off",
31
+ "unicorn/single-line-block-comment-style": ["error", "single-line"],
31
32
  },
32
33
  settings: {
33
34
  perfectionist: {