@antfu/eslint-config 2.0.0 → 2.1.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
@@ -32,7 +32,7 @@ With [`"type": "module"`](https://nodejs.org/api/packages.html#type) in `package
32
32
  // eslint.config.js
33
33
  import antfu from '@antfu/eslint-config'
34
34
 
35
- export default antfu()
35
+ export default await antfu()
36
36
  ```
37
37
 
38
38
  With CJS:
@@ -155,7 +155,7 @@ Normally you only need to import the `antfu` preset:
155
155
  // eslint.config.js
156
156
  import antfu from '@antfu/eslint-config'
157
157
 
158
- export default antfu()
158
+ export default await antfu()
159
159
  ```
160
160
 
161
161
  And that's it! Or you can configure each integration individually, for example:
@@ -164,7 +164,7 @@ And that's it! Or you can configure each integration individually, for example:
164
164
  // eslint.config.js
165
165
  import antfu from '@antfu/eslint-config'
166
166
 
167
- export default antfu({
167
+ export default await antfu({
168
168
  // Enable stylistic formatting rules
169
169
  // stylistic: true,
170
170
 
@@ -196,7 +196,7 @@ The `antfu` factory function also accepts any number of arbitrary custom config
196
196
  // eslint.config.js
197
197
  import antfu from '@antfu/eslint-config'
198
198
 
199
- export default antfu(
199
+ export default await antfu(
200
200
  {
201
201
  // Configures for antfu's config
202
202
  },
@@ -241,7 +241,7 @@ import {
241
241
  yaml,
242
242
  } from '@antfu/eslint-config'
243
243
 
244
- export default combine(
244
+ export default await combine(
245
245
  ignores(),
246
246
  javascript(/* Options */),
247
247
  comments(),
@@ -294,7 +294,7 @@ Certain rules would only be enabled in specific files, for example, `ts/*` rules
294
294
  // eslint.config.js
295
295
  import antfu from '@antfu/eslint-config'
296
296
 
297
- export default antfu(
297
+ export default await antfu(
298
298
  { vue: true, typescript: true },
299
299
  {
300
300
  // Remember to specify the file glob here, otherwise it might cause the vue plugin to handle non-vue files
@@ -312,7 +312,7 @@ export default antfu(
312
312
  )
313
313
  ```
314
314
 
315
- We also provided an `overrides` options to make it easier:
315
+ We also provided a `overrides` options to make it easier:
316
316
 
317
317
  ```js
318
318
  // eslint.config.js
@@ -332,6 +332,29 @@ export default antfu({
332
332
  })
333
333
  ```
334
334
 
335
+ ### Optional Configs
336
+
337
+ #### React
338
+
339
+ We do include configs for React. But due to the install size of React plugins we didn't include the dependencies by default.
340
+
341
+ To enable React support, need to explicitly turn it on:
342
+
343
+ ```js
344
+ // eslint.config.js
345
+ import antfu from '@antfu/eslint-config'
346
+
347
+ export default antfu({
348
+ react: true,
349
+ })
350
+ ```
351
+
352
+ Running `npx eslint` should prompt you to install the required dependencies, otherwise you can install them manually:
353
+
354
+ ```bash
355
+ npm i -D eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh
356
+ ```
357
+
335
358
  ### Optional Rules
336
359
 
337
360
  This config also provides some optional plugins/rules for extended usages.
package/dist/cli.cjs CHANGED
@@ -46,13 +46,40 @@ var import_parse_gitignore = __toESM(require("parse-gitignore"), 1);
46
46
  var import_picocolors = __toESM(require("picocolors"), 1);
47
47
 
48
48
  // package.json
49
- var version = "2.0.0";
49
+ var version = "2.1.0";
50
+ var devDependencies = {
51
+ "@antfu/eslint-config": "workspace:*",
52
+ "@antfu/ni": "^0.21.10",
53
+ "@stylistic/eslint-plugin-migrate": "^1.4.0",
54
+ "@types/eslint": "^8.44.7",
55
+ "@types/fs-extra": "^11.0.4",
56
+ "@types/node": "^20.9.4",
57
+ "@types/prompts": "^2.4.9",
58
+ "@types/yargs": "^17.0.32",
59
+ bumpp: "^9.2.0",
60
+ eslint: "^8.54.0",
61
+ "eslint-flat-config-viewer": "^0.1.3",
62
+ "eslint-plugin-react": "^7.33.2",
63
+ "eslint-plugin-react-hooks": "^4.6.0",
64
+ "eslint-plugin-react-refresh": "^0.4.4",
65
+ esno: "^4.0.0",
66
+ execa: "^8.0.1",
67
+ "fast-glob": "^3.3.2",
68
+ "fs-extra": "^11.1.1",
69
+ "lint-staged": "^15.1.0",
70
+ rimraf: "^5.0.5",
71
+ "simple-git-hooks": "^2.9.0",
72
+ tsup: "^8.0.1",
73
+ typescript: "^5.3.2",
74
+ vitest: "^0.34.6"
75
+ };
50
76
 
51
77
  // src/cli/constants.ts
52
78
  var ARROW = import_picocolors.default.cyan("\u2192");
53
79
  var CHECK = import_picocolors.default.green("\u2714");
54
80
  var CROSS = import_picocolors.default.red("\u2718");
55
81
  var WARN = import_picocolors.default.yellow("\u2139");
82
+ var eslintVersion = devDependencies.eslint;
56
83
  var vscodeSettingsString = `
57
84
  // Enable the ESlint flat config support
58
85
  "eslint.experimental.useFlatConfig": true,
@@ -126,7 +153,7 @@ async function run(options = {}) {
126
153
  pkg.devDependencies ?? (pkg.devDependencies = {});
127
154
  pkg.devDependencies["@antfu/eslint-config"] = `^${version}`;
128
155
  if (!pkg.devDependencies.eslint)
129
- pkg.devDependencies.eslint = "^8";
156
+ pkg.devDependencies.eslint = eslintVersion;
130
157
  await import_promises.default.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2));
131
158
  console.log(import_picocolors2.default.green(`${CHECK} changes wrote to package.json`));
132
159
  const eslintIgnores = [];
package/dist/cli.js CHANGED
@@ -17,13 +17,40 @@ import parse from "parse-gitignore";
17
17
  import c from "picocolors";
18
18
 
19
19
  // package.json
20
- var version = "2.0.0";
20
+ var version = "2.1.0";
21
+ var devDependencies = {
22
+ "@antfu/eslint-config": "workspace:*",
23
+ "@antfu/ni": "^0.21.10",
24
+ "@stylistic/eslint-plugin-migrate": "^1.4.0",
25
+ "@types/eslint": "^8.44.7",
26
+ "@types/fs-extra": "^11.0.4",
27
+ "@types/node": "^20.9.4",
28
+ "@types/prompts": "^2.4.9",
29
+ "@types/yargs": "^17.0.32",
30
+ bumpp: "^9.2.0",
31
+ eslint: "^8.54.0",
32
+ "eslint-flat-config-viewer": "^0.1.3",
33
+ "eslint-plugin-react": "^7.33.2",
34
+ "eslint-plugin-react-hooks": "^4.6.0",
35
+ "eslint-plugin-react-refresh": "^0.4.4",
36
+ esno: "^4.0.0",
37
+ execa: "^8.0.1",
38
+ "fast-glob": "^3.3.2",
39
+ "fs-extra": "^11.1.1",
40
+ "lint-staged": "^15.1.0",
41
+ rimraf: "^5.0.5",
42
+ "simple-git-hooks": "^2.9.0",
43
+ tsup: "^8.0.1",
44
+ typescript: "^5.3.2",
45
+ vitest: "^0.34.6"
46
+ };
21
47
 
22
48
  // src/cli/constants.ts
23
49
  var ARROW = c.cyan("\u2192");
24
50
  var CHECK = c.green("\u2714");
25
51
  var CROSS = c.red("\u2718");
26
52
  var WARN = c.yellow("\u2139");
53
+ var eslintVersion = devDependencies.eslint;
27
54
  var vscodeSettingsString = `
28
55
  // Enable the ESlint flat config support
29
56
  "eslint.experimental.useFlatConfig": true,
@@ -97,7 +124,7 @@ async function run(options = {}) {
97
124
  pkg.devDependencies ?? (pkg.devDependencies = {});
98
125
  pkg.devDependencies["@antfu/eslint-config"] = `^${version}`;
99
126
  if (!pkg.devDependencies.eslint)
100
- pkg.devDependencies.eslint = "^8";
127
+ pkg.devDependencies.eslint = eslintVersion;
101
128
  await fsp.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2));
102
129
  console.log(c2.green(`${CHECK} changes wrote to package.json`));
103
130
  const eslintIgnores = [];
package/dist/index.cjs CHANGED
@@ -55,6 +55,7 @@ __export(src_exports, {
55
55
  combine: () => combine,
56
56
  comments: () => comments,
57
57
  default: () => src_default,
58
+ ensurePackages: () => ensurePackages,
58
59
  ignores: () => ignores,
59
60
  imports: () => imports,
60
61
  interopDefault: () => interopDefault,
@@ -64,6 +65,7 @@ __export(src_exports, {
64
65
  markdown: () => markdown,
65
66
  node: () => node,
66
67
  perfectionist: () => perfectionist,
68
+ react: () => react,
67
69
  renameRules: () => renameRules,
68
70
  sortPackageJson: () => sortPackageJson,
69
71
  sortTsconfig: () => sortTsconfig,
@@ -78,9 +80,9 @@ __export(src_exports, {
78
80
  module.exports = __toCommonJS(src_exports);
79
81
 
80
82
  // src/factory.ts
81
- var import_node_process2 = __toESM(require("process"), 1);
83
+ var import_node_process3 = __toESM(require("process"), 1);
82
84
  var import_node_fs = __toESM(require("fs"), 1);
83
- var import_local_pkg = require("local-pkg");
85
+ var import_local_pkg3 = require("local-pkg");
84
86
 
85
87
  // src/plugins.ts
86
88
  var import_eslint_plugin_antfu = __toESM(require("eslint-plugin-antfu"), 1);
@@ -433,6 +435,47 @@ async function javascript(options = {}) {
433
435
  ];
434
436
  }
435
437
 
438
+ // src/utils.ts
439
+ var import_node_process = __toESM(require("process"), 1);
440
+ var import_local_pkg = require("local-pkg");
441
+ async function combine(...configs) {
442
+ const resolved = await Promise.all(configs);
443
+ return resolved.flat();
444
+ }
445
+ function renameRules(rules, from, to) {
446
+ return Object.fromEntries(
447
+ Object.entries(rules).map(([key, value]) => {
448
+ if (key.startsWith(from))
449
+ return [to + key.slice(from.length), value];
450
+ return [key, value];
451
+ })
452
+ );
453
+ }
454
+ function toArray(value) {
455
+ return Array.isArray(value) ? value : [value];
456
+ }
457
+ async function interopDefault(m) {
458
+ const resolved = await m;
459
+ return resolved.default || resolved;
460
+ }
461
+ async function ensurePackages(packages) {
462
+ if (import_node_process.default.env.CI || import_node_process.default.stdout.isTTY === false)
463
+ return;
464
+ const nonExistingPackages = packages.filter((i) => !(0, import_local_pkg.isPackageExists)(i));
465
+ if (nonExistingPackages.length === 0)
466
+ return;
467
+ const { default: prompts } = await import("prompts");
468
+ const { result } = await prompts([
469
+ {
470
+ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`,
471
+ name: "result",
472
+ type: "confirm"
473
+ }
474
+ ]);
475
+ if (result)
476
+ await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
477
+ }
478
+
436
479
  // src/configs/jsdoc.ts
437
480
  async function jsdoc(options = {}) {
438
481
  const {
@@ -470,31 +513,10 @@ async function jsdoc(options = {}) {
470
513
  ];
471
514
  }
472
515
 
473
- // src/utils.ts
474
- async function combine(...configs) {
475
- const resolved = await Promise.all(configs);
476
- return resolved.flat();
477
- }
478
- function renameRules(rules, from, to) {
479
- return Object.fromEntries(
480
- Object.entries(rules).map(([key, value]) => {
481
- if (key.startsWith(from))
482
- return [to + key.slice(from.length), value];
483
- return [key, value];
484
- })
485
- );
486
- }
487
- function toArray(value) {
488
- return Array.isArray(value) ? value : [value];
489
- }
490
- async function interopDefault(m) {
491
- const resolved = await m;
492
- return resolved.default || resolved;
493
- }
494
-
495
516
  // src/configs/jsonc.ts
496
517
  async function jsonc(options = {}) {
497
518
  const {
519
+ files = [GLOB_JSON, GLOB_JSON5, GLOB_JSONC],
498
520
  overrides = {},
499
521
  stylistic: stylistic2 = true
500
522
  } = options;
@@ -516,7 +538,7 @@ async function jsonc(options = {}) {
516
538
  }
517
539
  },
518
540
  {
519
- files: [GLOB_JSON, GLOB_JSON5, GLOB_JSONC],
541
+ files,
520
542
  languageOptions: {
521
543
  parser: parserJsonc
522
544
  },
@@ -570,6 +592,7 @@ async function jsonc(options = {}) {
570
592
  async function markdown(options = {}) {
571
593
  const {
572
594
  componentExts = [],
595
+ files = [GLOB_MARKDOWN],
573
596
  overrides = {}
574
597
  } = options;
575
598
  return [
@@ -581,7 +604,7 @@ async function markdown(options = {}) {
581
604
  }
582
605
  },
583
606
  {
584
- files: [GLOB_MARKDOWN],
607
+ files,
585
608
  name: "antfu:markdown:processor",
586
609
  processor: "markdown/markdown"
587
610
  },
@@ -923,13 +946,17 @@ async function stylistic(options = {}) {
923
946
  }
924
947
 
925
948
  // src/configs/typescript.ts
926
- var import_node_process = __toESM(require("process"), 1);
927
- async function typescript(options) {
949
+ var import_node_process2 = __toESM(require("process"), 1);
950
+ async function typescript(options = {}) {
928
951
  const {
929
952
  componentExts = [],
930
953
  overrides = {},
931
954
  parserOptions = {}
932
- } = options ?? {};
955
+ } = options;
956
+ const files = options.files ?? [
957
+ GLOB_SRC,
958
+ ...componentExts.map((ext) => `**/*.${ext}`)
959
+ ];
933
960
  const typeAwareRules = {
934
961
  "dot-notation": "off",
935
962
  "no-implied-eval": "off",
@@ -969,10 +996,7 @@ async function typescript(options) {
969
996
  }
970
997
  },
971
998
  {
972
- files: [
973
- GLOB_SRC,
974
- ...componentExts.map((ext) => `**/*.${ext}`)
975
- ],
999
+ files,
976
1000
  languageOptions: {
977
1001
  parser: parserTs,
978
1002
  parserOptions: {
@@ -980,7 +1004,7 @@ async function typescript(options) {
980
1004
  sourceType: "module",
981
1005
  ...tsconfigPath ? {
982
1006
  project: tsconfigPath,
983
- tsconfigRootDir: import_node_process.default.cwd()
1007
+ tsconfigRootDir: import_node_process2.default.cwd()
984
1008
  } : {},
985
1009
  ...parserOptions
986
1010
  }
@@ -1101,6 +1125,7 @@ async function unicorn() {
1101
1125
  // src/configs/vue.ts
1102
1126
  async function vue(options = {}) {
1103
1127
  const {
1128
+ files = [GLOB_VUE],
1104
1129
  overrides = {},
1105
1130
  stylistic: stylistic2 = true
1106
1131
  } = options;
@@ -1123,7 +1148,7 @@ async function vue(options = {}) {
1123
1148
  }
1124
1149
  },
1125
1150
  {
1126
- files: [GLOB_VUE],
1151
+ files,
1127
1152
  languageOptions: {
1128
1153
  parser: parserVue,
1129
1154
  parserOptions: {
@@ -1226,6 +1251,7 @@ async function vue(options = {}) {
1226
1251
  // src/configs/yaml.ts
1227
1252
  async function yaml(options = {}) {
1228
1253
  const {
1254
+ files = [GLOB_YAML],
1229
1255
  overrides = {},
1230
1256
  stylistic: stylistic2 = true
1231
1257
  } = options;
@@ -1248,7 +1274,7 @@ async function yaml(options = {}) {
1248
1274
  }
1249
1275
  },
1250
1276
  {
1251
- files: [GLOB_YAML],
1277
+ files,
1252
1278
  languageOptions: {
1253
1279
  parser: parserYaml
1254
1280
  },
@@ -1284,6 +1310,7 @@ async function yaml(options = {}) {
1284
1310
  // src/configs/test.ts
1285
1311
  async function test(options = {}) {
1286
1312
  const {
1313
+ files = GLOB_TESTS,
1287
1314
  isInEditor = false,
1288
1315
  overrides = {}
1289
1316
  } = options;
@@ -1310,7 +1337,7 @@ async function test(options = {}) {
1310
1337
  }
1311
1338
  },
1312
1339
  {
1313
- files: GLOB_TESTS,
1340
+ files,
1314
1341
  name: "antfu:test:rules",
1315
1342
  rules: {
1316
1343
  "node/prefer-global/process": "off",
@@ -1337,6 +1364,96 @@ async function perfectionist() {
1337
1364
  ];
1338
1365
  }
1339
1366
 
1367
+ // src/configs/react.ts
1368
+ var import_local_pkg2 = require("local-pkg");
1369
+ var ReactRefreshAllowConstantExportPackages = [
1370
+ "vite"
1371
+ ];
1372
+ async function react(options = {}) {
1373
+ const {
1374
+ files = [GLOB_JSX, GLOB_TSX],
1375
+ overrides = {},
1376
+ typescript: typescript2 = true
1377
+ } = options;
1378
+ await ensurePackages([
1379
+ "eslint-plugin-react",
1380
+ "eslint-plugin-react-hooks",
1381
+ "eslint-plugin-react-refresh"
1382
+ ]);
1383
+ const [
1384
+ pluginReact,
1385
+ pluginReactHooks,
1386
+ pluginReactRefresh
1387
+ ] = await Promise.all([
1388
+ interopDefault(import("eslint-plugin-react")),
1389
+ interopDefault(import("eslint-plugin-react-hooks")),
1390
+ interopDefault(import("eslint-plugin-react-refresh"))
1391
+ ]);
1392
+ const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some(
1393
+ (i) => (0, import_local_pkg2.isPackageExists)(i)
1394
+ );
1395
+ return [
1396
+ {
1397
+ name: "antfu:react:setup",
1398
+ plugins: {
1399
+ "react": pluginReact,
1400
+ "react-hooks": pluginReactHooks,
1401
+ "react-refresh": pluginReactRefresh
1402
+ }
1403
+ },
1404
+ {
1405
+ files,
1406
+ languageOptions: {
1407
+ parserOptions: {
1408
+ ecmaFeatures: {
1409
+ jsx: true
1410
+ }
1411
+ }
1412
+ },
1413
+ name: "antfu:react:rules",
1414
+ rules: {
1415
+ // recommended rules react-hooks
1416
+ "react-hooks/exhaustive-deps": "warn",
1417
+ "react-hooks/rules-of-hooks": "error",
1418
+ // react refresh
1419
+ "react-refresh/only-export-components": [
1420
+ "warn",
1421
+ { allowConstantExport: isAllowConstantExport }
1422
+ ],
1423
+ // recommended rules react
1424
+ "react/display-name": "error",
1425
+ "react/jsx-key": "error",
1426
+ "react/jsx-no-comment-textnodes": "error",
1427
+ "react/jsx-no-duplicate-props": "error",
1428
+ "react/jsx-no-target-blank": "error",
1429
+ "react/jsx-no-undef": "error",
1430
+ "react/jsx-uses-react": "error",
1431
+ "react/jsx-uses-vars": "error",
1432
+ "react/no-children-prop": "error",
1433
+ "react/no-danger-with-children": "error",
1434
+ "react/no-deprecated": "error",
1435
+ "react/no-direct-mutation-state": "error",
1436
+ "react/no-find-dom-node": "error",
1437
+ "react/no-is-mounted": "error",
1438
+ "react/no-render-return-value": "error",
1439
+ "react/no-string-refs": "error",
1440
+ "react/no-unescaped-entities": "error",
1441
+ "react/no-unknown-property": "error",
1442
+ "react/no-unsafe": "off",
1443
+ "react/prop-types": "error",
1444
+ "react/react-in-jsx-scope": "off",
1445
+ "react/require-render-return": "error",
1446
+ ...typescript2 ? {
1447
+ "react/jsx-no-undef": "off",
1448
+ "react/prop-type": "off"
1449
+ } : {},
1450
+ // overrides
1451
+ ...overrides
1452
+ }
1453
+ }
1454
+ ];
1455
+ }
1456
+
1340
1457
  // src/factory.ts
1341
1458
  var flatConfigProps = [
1342
1459
  "files",
@@ -1358,10 +1475,11 @@ async function antfu(options = {}, ...userConfigs) {
1358
1475
  const {
1359
1476
  componentExts = [],
1360
1477
  gitignore: enableGitignore = true,
1361
- isInEditor = !!((import_node_process2.default.env.VSCODE_PID || import_node_process2.default.env.JETBRAINS_IDE) && !import_node_process2.default.env.CI),
1478
+ isInEditor = !!((import_node_process3.default.env.VSCODE_PID || import_node_process3.default.env.JETBRAINS_IDE) && !import_node_process3.default.env.CI),
1362
1479
  overrides = {},
1363
- typescript: enableTypeScript = (0, import_local_pkg.isPackageExists)("typescript"),
1364
- vue: enableVue = VuePackages.some((i) => (0, import_local_pkg.isPackageExists)(i))
1480
+ react: enableReact = false,
1481
+ typescript: enableTypeScript = (0, import_local_pkg3.isPackageExists)("typescript"),
1482
+ vue: enableVue = VuePackages.some((i) => (0, import_local_pkg3.isPackageExists)(i))
1365
1483
  } = options;
1366
1484
  const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
1367
1485
  if (stylisticOptions && !("jsx" in stylisticOptions))
@@ -1417,6 +1535,12 @@ async function antfu(options = {}, ...userConfigs) {
1417
1535
  typescript: !!enableTypeScript
1418
1536
  }));
1419
1537
  }
1538
+ if (enableReact) {
1539
+ configs.push(react({
1540
+ overrides: overrides.react,
1541
+ typescript: !!enableTypeScript
1542
+ }));
1543
+ }
1420
1544
  if (options.jsonc ?? true) {
1421
1545
  configs.push(
1422
1546
  jsonc({
@@ -1481,6 +1605,7 @@ var src_default = antfu;
1481
1605
  antfu,
1482
1606
  combine,
1483
1607
  comments,
1608
+ ensurePackages,
1484
1609
  ignores,
1485
1610
  imports,
1486
1611
  interopDefault,
@@ -1490,6 +1615,7 @@ var src_default = antfu;
1490
1615
  markdown,
1491
1616
  node,
1492
1617
  perfectionist,
1618
+ react,
1493
1619
  renameRules,
1494
1620
  sortPackageJson,
1495
1621
  sortTsconfig,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FlatGitignoreOptions } from 'eslint-config-flat-gitignore';
2
2
  import { ParserOptions } from '@typescript-eslint/parser';
3
3
  import { Linter } from 'eslint';
4
- import { RuleConfig, MergeIntersection, RenamePrefix, VitestRules, YmlRules, NRules, Prefix, ImportRules, EslintRules, JsoncRules, VueRules, EslintCommentsRules, FlatESLintConfigItem } from '@antfu/eslint-define-config';
4
+ import { RuleConfig, MergeIntersection, RenamePrefix, VitestRules, YmlRules, NRules, Prefix, ReactHooksRules, ReactRules, ImportRules, EslintRules, JsoncRules, VueRules, EslintCommentsRules, FlatESLintConfigItem } from '@antfu/eslint-define-config';
5
5
  import { RuleOptions as RuleOptions$1 } from '@eslint-types/jsdoc/types';
6
6
  import { RuleOptions } from '@eslint-types/typescript-eslint/types';
7
7
  import { RuleOptions as RuleOptions$2 } from '@eslint-types/unicorn/types';
@@ -14,7 +14,7 @@ type WrapRuleConfig<T extends {
14
14
  [K in keyof T]: T[K] extends RuleConfig ? T[K] : RuleConfig<T[K]>;
15
15
  };
16
16
  type Awaitable<T> = T | Promise<T>;
17
- type Rules = WrapRuleConfig<MergeIntersection<RenamePrefix<RuleOptions, '@typescript-eslint/', 'ts/'> & RenamePrefix<VitestRules, 'vitest/', 'test/'> & RenamePrefix<YmlRules, 'yml/', 'yaml/'> & RenamePrefix<NRules, 'n/', 'node/'> & Prefix<UnprefixedRuleOptions, 'style/'> & Prefix<Rules$1, 'antfu/'> & RuleOptions$1 & ImportRules & EslintRules & JsoncRules & VueRules & RuleOptions$2 & EslintCommentsRules & {
17
+ type Rules = WrapRuleConfig<MergeIntersection<RenamePrefix<RuleOptions, '@typescript-eslint/', 'ts/'> & RenamePrefix<VitestRules, 'vitest/', 'test/'> & RenamePrefix<YmlRules, 'yml/', 'yaml/'> & RenamePrefix<NRules, 'n/', 'node/'> & Prefix<UnprefixedRuleOptions, 'style/'> & Prefix<Rules$1, 'antfu/'> & ReactHooksRules & ReactRules & RuleOptions$1 & ImportRules & EslintRules & JsoncRules & VueRules & RuleOptions$2 & EslintCommentsRules & {
18
18
  'test/no-only-tests': RuleConfig<[]>;
19
19
  }>>;
20
20
  type FlatConfigItem = Omit<FlatESLintConfigItem<Rules, false>, 'plugins'> & {
@@ -30,6 +30,12 @@ type FlatConfigItem = Omit<FlatESLintConfigItem<Rules, false>, 'plugins'> & {
30
30
  plugins?: Record<string, any>;
31
31
  };
32
32
  type UserConfigItem = FlatConfigItem | Linter.FlatConfig;
33
+ interface OptionsFiles {
34
+ /**
35
+ * Override the `files` option to provide custom globs.
36
+ */
37
+ files?: string[];
38
+ }
33
39
  interface OptionsComponentExts {
34
40
  /**
35
41
  * Additional extensions for components.
@@ -128,6 +134,12 @@ interface OptionsConfig extends OptionsComponentExts {
128
134
  * @default true
129
135
  */
130
136
  stylistic?: boolean | StylisticConfig;
137
+ /**
138
+ * Enable react rules.
139
+ *
140
+ * @default true
141
+ */
142
+ react?: boolean;
131
143
  /**
132
144
  * Control to disable some rules in editors.
133
145
  * @default auto-detect based on the process.env
@@ -144,6 +156,7 @@ interface OptionsConfig extends OptionsComponentExts {
144
156
  jsonc?: FlatConfigItem['rules'];
145
157
  markdown?: FlatConfigItem['rules'];
146
158
  yaml?: FlatConfigItem['rules'];
159
+ react?: FlatConfigItem['rules'];
147
160
  };
148
161
  }
149
162
 
@@ -162,9 +175,9 @@ declare function javascript(options?: OptionsIsInEditor & OptionsOverrides): Pro
162
175
 
163
176
  declare function jsdoc(options?: OptionsStylistic): Promise<FlatConfigItem[]>;
164
177
 
165
- declare function jsonc(options?: OptionsStylistic & OptionsOverrides): Promise<FlatConfigItem[]>;
178
+ declare function jsonc(options?: OptionsFiles & OptionsStylistic & OptionsOverrides): Promise<FlatConfigItem[]>;
166
179
 
167
- declare function markdown(options?: OptionsComponentExts & OptionsOverrides): Promise<FlatConfigItem[]>;
180
+ declare function markdown(options?: OptionsFiles & OptionsComponentExts & OptionsOverrides): Promise<FlatConfigItem[]>;
168
181
 
169
182
  declare function node(): Promise<FlatConfigItem[]>;
170
183
 
@@ -183,15 +196,15 @@ declare function sortTsconfig(): FlatConfigItem[];
183
196
 
184
197
  declare function stylistic(options?: StylisticConfig): Promise<FlatConfigItem[]>;
185
198
 
186
- declare function typescript(options?: OptionsComponentExts & OptionsOverrides & OptionsTypeScriptWithTypes & OptionsTypeScriptParserOptions): Promise<FlatConfigItem[]>;
199
+ declare function typescript(options?: OptionsFiles & OptionsComponentExts & OptionsOverrides & OptionsTypeScriptWithTypes & OptionsTypeScriptParserOptions): Promise<FlatConfigItem[]>;
187
200
 
188
201
  declare function unicorn(): Promise<FlatConfigItem[]>;
189
202
 
190
- declare function vue(options?: OptionsHasTypeScript & OptionsOverrides & OptionsStylistic): Promise<FlatConfigItem[]>;
203
+ declare function vue(options?: OptionsHasTypeScript & OptionsOverrides & OptionsStylistic & OptionsFiles): Promise<FlatConfigItem[]>;
191
204
 
192
- declare function yaml(options?: OptionsOverrides & OptionsStylistic): Promise<FlatConfigItem[]>;
205
+ declare function yaml(options?: OptionsOverrides & OptionsStylistic & OptionsFiles): Promise<FlatConfigItem[]>;
193
206
 
194
- declare function test(options?: OptionsIsInEditor & OptionsOverrides): Promise<FlatConfigItem[]>;
207
+ declare function test(options?: OptionsFiles & OptionsIsInEditor & OptionsOverrides): Promise<FlatConfigItem[]>;
195
208
 
196
209
  /**
197
210
  * Optional perfectionist plugin for props and items sorting.
@@ -200,6 +213,8 @@ declare function test(options?: OptionsIsInEditor & OptionsOverrides): Promise<F
200
213
  */
201
214
  declare function perfectionist(): Promise<FlatConfigItem[]>;
202
215
 
216
+ declare function react(options?: OptionsHasTypeScript & OptionsOverrides & OptionsFiles): Promise<FlatConfigItem[]>;
217
+
203
218
  declare const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
204
219
  declare const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
205
220
  declare const GLOB_JS = "**/*.?([cm])js";
@@ -233,5 +248,6 @@ declare function toArray<T>(value: T | T[]): T[];
233
248
  declare function interopDefault<T>(m: Awaitable<T>): Promise<T extends {
234
249
  default: infer U;
235
250
  } ? U : T>;
251
+ declare function ensurePackages(packages: string[]): Promise<void>;
236
252
 
237
- export { type Awaitable, type FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TESTS, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML, type OptionsComponentExts, type OptionsConfig, type OptionsHasTypeScript, type OptionsIsInEditor, type OptionsOverrides, type OptionsStylistic, type OptionsTypeScriptParserOptions, type OptionsTypeScriptWithTypes, type Rules, type StylisticConfig, type UserConfigItem, type WrapRuleConfig, antfu, combine, comments, antfu as default, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, node, perfectionist, renameRules, sortPackageJson, sortTsconfig, stylistic, test, toArray, typescript, unicorn, vue, yaml };
253
+ export { type Awaitable, type FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TESTS, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML, type OptionsComponentExts, type OptionsConfig, type OptionsFiles, type OptionsHasTypeScript, type OptionsIsInEditor, type OptionsOverrides, type OptionsStylistic, type OptionsTypeScriptParserOptions, type OptionsTypeScriptWithTypes, type Rules, type StylisticConfig, type UserConfigItem, type WrapRuleConfig, antfu, combine, comments, antfu as default, ensurePackages, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, node, perfectionist, react, renameRules, sortPackageJson, sortTsconfig, stylistic, test, toArray, typescript, unicorn, vue, yaml };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FlatGitignoreOptions } from 'eslint-config-flat-gitignore';
2
2
  import { ParserOptions } from '@typescript-eslint/parser';
3
3
  import { Linter } from 'eslint';
4
- import { RuleConfig, MergeIntersection, RenamePrefix, VitestRules, YmlRules, NRules, Prefix, ImportRules, EslintRules, JsoncRules, VueRules, EslintCommentsRules, FlatESLintConfigItem } from '@antfu/eslint-define-config';
4
+ import { RuleConfig, MergeIntersection, RenamePrefix, VitestRules, YmlRules, NRules, Prefix, ReactHooksRules, ReactRules, ImportRules, EslintRules, JsoncRules, VueRules, EslintCommentsRules, FlatESLintConfigItem } from '@antfu/eslint-define-config';
5
5
  import { RuleOptions as RuleOptions$1 } from '@eslint-types/jsdoc/types';
6
6
  import { RuleOptions } from '@eslint-types/typescript-eslint/types';
7
7
  import { RuleOptions as RuleOptions$2 } from '@eslint-types/unicorn/types';
@@ -14,7 +14,7 @@ type WrapRuleConfig<T extends {
14
14
  [K in keyof T]: T[K] extends RuleConfig ? T[K] : RuleConfig<T[K]>;
15
15
  };
16
16
  type Awaitable<T> = T | Promise<T>;
17
- type Rules = WrapRuleConfig<MergeIntersection<RenamePrefix<RuleOptions, '@typescript-eslint/', 'ts/'> & RenamePrefix<VitestRules, 'vitest/', 'test/'> & RenamePrefix<YmlRules, 'yml/', 'yaml/'> & RenamePrefix<NRules, 'n/', 'node/'> & Prefix<UnprefixedRuleOptions, 'style/'> & Prefix<Rules$1, 'antfu/'> & RuleOptions$1 & ImportRules & EslintRules & JsoncRules & VueRules & RuleOptions$2 & EslintCommentsRules & {
17
+ type Rules = WrapRuleConfig<MergeIntersection<RenamePrefix<RuleOptions, '@typescript-eslint/', 'ts/'> & RenamePrefix<VitestRules, 'vitest/', 'test/'> & RenamePrefix<YmlRules, 'yml/', 'yaml/'> & RenamePrefix<NRules, 'n/', 'node/'> & Prefix<UnprefixedRuleOptions, 'style/'> & Prefix<Rules$1, 'antfu/'> & ReactHooksRules & ReactRules & RuleOptions$1 & ImportRules & EslintRules & JsoncRules & VueRules & RuleOptions$2 & EslintCommentsRules & {
18
18
  'test/no-only-tests': RuleConfig<[]>;
19
19
  }>>;
20
20
  type FlatConfigItem = Omit<FlatESLintConfigItem<Rules, false>, 'plugins'> & {
@@ -30,6 +30,12 @@ type FlatConfigItem = Omit<FlatESLintConfigItem<Rules, false>, 'plugins'> & {
30
30
  plugins?: Record<string, any>;
31
31
  };
32
32
  type UserConfigItem = FlatConfigItem | Linter.FlatConfig;
33
+ interface OptionsFiles {
34
+ /**
35
+ * Override the `files` option to provide custom globs.
36
+ */
37
+ files?: string[];
38
+ }
33
39
  interface OptionsComponentExts {
34
40
  /**
35
41
  * Additional extensions for components.
@@ -128,6 +134,12 @@ interface OptionsConfig extends OptionsComponentExts {
128
134
  * @default true
129
135
  */
130
136
  stylistic?: boolean | StylisticConfig;
137
+ /**
138
+ * Enable react rules.
139
+ *
140
+ * @default true
141
+ */
142
+ react?: boolean;
131
143
  /**
132
144
  * Control to disable some rules in editors.
133
145
  * @default auto-detect based on the process.env
@@ -144,6 +156,7 @@ interface OptionsConfig extends OptionsComponentExts {
144
156
  jsonc?: FlatConfigItem['rules'];
145
157
  markdown?: FlatConfigItem['rules'];
146
158
  yaml?: FlatConfigItem['rules'];
159
+ react?: FlatConfigItem['rules'];
147
160
  };
148
161
  }
149
162
 
@@ -162,9 +175,9 @@ declare function javascript(options?: OptionsIsInEditor & OptionsOverrides): Pro
162
175
 
163
176
  declare function jsdoc(options?: OptionsStylistic): Promise<FlatConfigItem[]>;
164
177
 
165
- declare function jsonc(options?: OptionsStylistic & OptionsOverrides): Promise<FlatConfigItem[]>;
178
+ declare function jsonc(options?: OptionsFiles & OptionsStylistic & OptionsOverrides): Promise<FlatConfigItem[]>;
166
179
 
167
- declare function markdown(options?: OptionsComponentExts & OptionsOverrides): Promise<FlatConfigItem[]>;
180
+ declare function markdown(options?: OptionsFiles & OptionsComponentExts & OptionsOverrides): Promise<FlatConfigItem[]>;
168
181
 
169
182
  declare function node(): Promise<FlatConfigItem[]>;
170
183
 
@@ -183,15 +196,15 @@ declare function sortTsconfig(): FlatConfigItem[];
183
196
 
184
197
  declare function stylistic(options?: StylisticConfig): Promise<FlatConfigItem[]>;
185
198
 
186
- declare function typescript(options?: OptionsComponentExts & OptionsOverrides & OptionsTypeScriptWithTypes & OptionsTypeScriptParserOptions): Promise<FlatConfigItem[]>;
199
+ declare function typescript(options?: OptionsFiles & OptionsComponentExts & OptionsOverrides & OptionsTypeScriptWithTypes & OptionsTypeScriptParserOptions): Promise<FlatConfigItem[]>;
187
200
 
188
201
  declare function unicorn(): Promise<FlatConfigItem[]>;
189
202
 
190
- declare function vue(options?: OptionsHasTypeScript & OptionsOverrides & OptionsStylistic): Promise<FlatConfigItem[]>;
203
+ declare function vue(options?: OptionsHasTypeScript & OptionsOverrides & OptionsStylistic & OptionsFiles): Promise<FlatConfigItem[]>;
191
204
 
192
- declare function yaml(options?: OptionsOverrides & OptionsStylistic): Promise<FlatConfigItem[]>;
205
+ declare function yaml(options?: OptionsOverrides & OptionsStylistic & OptionsFiles): Promise<FlatConfigItem[]>;
193
206
 
194
- declare function test(options?: OptionsIsInEditor & OptionsOverrides): Promise<FlatConfigItem[]>;
207
+ declare function test(options?: OptionsFiles & OptionsIsInEditor & OptionsOverrides): Promise<FlatConfigItem[]>;
195
208
 
196
209
  /**
197
210
  * Optional perfectionist plugin for props and items sorting.
@@ -200,6 +213,8 @@ declare function test(options?: OptionsIsInEditor & OptionsOverrides): Promise<F
200
213
  */
201
214
  declare function perfectionist(): Promise<FlatConfigItem[]>;
202
215
 
216
+ declare function react(options?: OptionsHasTypeScript & OptionsOverrides & OptionsFiles): Promise<FlatConfigItem[]>;
217
+
203
218
  declare const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
204
219
  declare const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
205
220
  declare const GLOB_JS = "**/*.?([cm])js";
@@ -233,5 +248,6 @@ declare function toArray<T>(value: T | T[]): T[];
233
248
  declare function interopDefault<T>(m: Awaitable<T>): Promise<T extends {
234
249
  default: infer U;
235
250
  } ? U : T>;
251
+ declare function ensurePackages(packages: string[]): Promise<void>;
236
252
 
237
- export { type Awaitable, type FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TESTS, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML, type OptionsComponentExts, type OptionsConfig, type OptionsHasTypeScript, type OptionsIsInEditor, type OptionsOverrides, type OptionsStylistic, type OptionsTypeScriptParserOptions, type OptionsTypeScriptWithTypes, type Rules, type StylisticConfig, type UserConfigItem, type WrapRuleConfig, antfu, combine, comments, antfu as default, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, node, perfectionist, renameRules, sortPackageJson, sortTsconfig, stylistic, test, toArray, typescript, unicorn, vue, yaml };
253
+ export { type Awaitable, type FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TESTS, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML, type OptionsComponentExts, type OptionsConfig, type OptionsFiles, type OptionsHasTypeScript, type OptionsIsInEditor, type OptionsOverrides, type OptionsStylistic, type OptionsTypeScriptParserOptions, type OptionsTypeScriptWithTypes, type Rules, type StylisticConfig, type UserConfigItem, type WrapRuleConfig, antfu, combine, comments, antfu as default, ensurePackages, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, node, perfectionist, react, renameRules, sortPackageJson, sortTsconfig, stylistic, test, toArray, typescript, unicorn, vue, yaml };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/factory.ts
2
- import process2 from "process";
2
+ import process3 from "process";
3
3
  import fs from "fs";
4
- import { isPackageExists } from "local-pkg";
4
+ import { isPackageExists as isPackageExists3 } from "local-pkg";
5
5
 
6
6
  // src/plugins.ts
7
7
  import { default as default2 } from "eslint-plugin-antfu";
@@ -354,6 +354,47 @@ async function javascript(options = {}) {
354
354
  ];
355
355
  }
356
356
 
357
+ // src/utils.ts
358
+ import process from "process";
359
+ import { isPackageExists } from "local-pkg";
360
+ async function combine(...configs) {
361
+ const resolved = await Promise.all(configs);
362
+ return resolved.flat();
363
+ }
364
+ function renameRules(rules, from, to) {
365
+ return Object.fromEntries(
366
+ Object.entries(rules).map(([key, value]) => {
367
+ if (key.startsWith(from))
368
+ return [to + key.slice(from.length), value];
369
+ return [key, value];
370
+ })
371
+ );
372
+ }
373
+ function toArray(value) {
374
+ return Array.isArray(value) ? value : [value];
375
+ }
376
+ async function interopDefault(m) {
377
+ const resolved = await m;
378
+ return resolved.default || resolved;
379
+ }
380
+ async function ensurePackages(packages) {
381
+ if (process.env.CI || process.stdout.isTTY === false)
382
+ return;
383
+ const nonExistingPackages = packages.filter((i) => !isPackageExists(i));
384
+ if (nonExistingPackages.length === 0)
385
+ return;
386
+ const { default: prompts } = await import("prompts");
387
+ const { result } = await prompts([
388
+ {
389
+ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`,
390
+ name: "result",
391
+ type: "confirm"
392
+ }
393
+ ]);
394
+ if (result)
395
+ await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
396
+ }
397
+
357
398
  // src/configs/jsdoc.ts
358
399
  async function jsdoc(options = {}) {
359
400
  const {
@@ -391,31 +432,10 @@ async function jsdoc(options = {}) {
391
432
  ];
392
433
  }
393
434
 
394
- // src/utils.ts
395
- async function combine(...configs) {
396
- const resolved = await Promise.all(configs);
397
- return resolved.flat();
398
- }
399
- function renameRules(rules, from, to) {
400
- return Object.fromEntries(
401
- Object.entries(rules).map(([key, value]) => {
402
- if (key.startsWith(from))
403
- return [to + key.slice(from.length), value];
404
- return [key, value];
405
- })
406
- );
407
- }
408
- function toArray(value) {
409
- return Array.isArray(value) ? value : [value];
410
- }
411
- async function interopDefault(m) {
412
- const resolved = await m;
413
- return resolved.default || resolved;
414
- }
415
-
416
435
  // src/configs/jsonc.ts
417
436
  async function jsonc(options = {}) {
418
437
  const {
438
+ files = [GLOB_JSON, GLOB_JSON5, GLOB_JSONC],
419
439
  overrides = {},
420
440
  stylistic: stylistic2 = true
421
441
  } = options;
@@ -437,7 +457,7 @@ async function jsonc(options = {}) {
437
457
  }
438
458
  },
439
459
  {
440
- files: [GLOB_JSON, GLOB_JSON5, GLOB_JSONC],
460
+ files,
441
461
  languageOptions: {
442
462
  parser: parserJsonc
443
463
  },
@@ -491,6 +511,7 @@ async function jsonc(options = {}) {
491
511
  async function markdown(options = {}) {
492
512
  const {
493
513
  componentExts = [],
514
+ files = [GLOB_MARKDOWN],
494
515
  overrides = {}
495
516
  } = options;
496
517
  return [
@@ -502,7 +523,7 @@ async function markdown(options = {}) {
502
523
  }
503
524
  },
504
525
  {
505
- files: [GLOB_MARKDOWN],
526
+ files,
506
527
  name: "antfu:markdown:processor",
507
528
  processor: "markdown/markdown"
508
529
  },
@@ -844,13 +865,17 @@ async function stylistic(options = {}) {
844
865
  }
845
866
 
846
867
  // src/configs/typescript.ts
847
- import process from "process";
848
- async function typescript(options) {
868
+ import process2 from "process";
869
+ async function typescript(options = {}) {
849
870
  const {
850
871
  componentExts = [],
851
872
  overrides = {},
852
873
  parserOptions = {}
853
- } = options ?? {};
874
+ } = options;
875
+ const files = options.files ?? [
876
+ GLOB_SRC,
877
+ ...componentExts.map((ext) => `**/*.${ext}`)
878
+ ];
854
879
  const typeAwareRules = {
855
880
  "dot-notation": "off",
856
881
  "no-implied-eval": "off",
@@ -890,10 +915,7 @@ async function typescript(options) {
890
915
  }
891
916
  },
892
917
  {
893
- files: [
894
- GLOB_SRC,
895
- ...componentExts.map((ext) => `**/*.${ext}`)
896
- ],
918
+ files,
897
919
  languageOptions: {
898
920
  parser: parserTs,
899
921
  parserOptions: {
@@ -901,7 +923,7 @@ async function typescript(options) {
901
923
  sourceType: "module",
902
924
  ...tsconfigPath ? {
903
925
  project: tsconfigPath,
904
- tsconfigRootDir: process.cwd()
926
+ tsconfigRootDir: process2.cwd()
905
927
  } : {},
906
928
  ...parserOptions
907
929
  }
@@ -1022,6 +1044,7 @@ async function unicorn() {
1022
1044
  // src/configs/vue.ts
1023
1045
  async function vue(options = {}) {
1024
1046
  const {
1047
+ files = [GLOB_VUE],
1025
1048
  overrides = {},
1026
1049
  stylistic: stylistic2 = true
1027
1050
  } = options;
@@ -1044,7 +1067,7 @@ async function vue(options = {}) {
1044
1067
  }
1045
1068
  },
1046
1069
  {
1047
- files: [GLOB_VUE],
1070
+ files,
1048
1071
  languageOptions: {
1049
1072
  parser: parserVue,
1050
1073
  parserOptions: {
@@ -1147,6 +1170,7 @@ async function vue(options = {}) {
1147
1170
  // src/configs/yaml.ts
1148
1171
  async function yaml(options = {}) {
1149
1172
  const {
1173
+ files = [GLOB_YAML],
1150
1174
  overrides = {},
1151
1175
  stylistic: stylistic2 = true
1152
1176
  } = options;
@@ -1169,7 +1193,7 @@ async function yaml(options = {}) {
1169
1193
  }
1170
1194
  },
1171
1195
  {
1172
- files: [GLOB_YAML],
1196
+ files,
1173
1197
  languageOptions: {
1174
1198
  parser: parserYaml
1175
1199
  },
@@ -1205,6 +1229,7 @@ async function yaml(options = {}) {
1205
1229
  // src/configs/test.ts
1206
1230
  async function test(options = {}) {
1207
1231
  const {
1232
+ files = GLOB_TESTS,
1208
1233
  isInEditor = false,
1209
1234
  overrides = {}
1210
1235
  } = options;
@@ -1231,7 +1256,7 @@ async function test(options = {}) {
1231
1256
  }
1232
1257
  },
1233
1258
  {
1234
- files: GLOB_TESTS,
1259
+ files,
1235
1260
  name: "antfu:test:rules",
1236
1261
  rules: {
1237
1262
  "node/prefer-global/process": "off",
@@ -1258,6 +1283,96 @@ async function perfectionist() {
1258
1283
  ];
1259
1284
  }
1260
1285
 
1286
+ // src/configs/react.ts
1287
+ import { isPackageExists as isPackageExists2 } from "local-pkg";
1288
+ var ReactRefreshAllowConstantExportPackages = [
1289
+ "vite"
1290
+ ];
1291
+ async function react(options = {}) {
1292
+ const {
1293
+ files = [GLOB_JSX, GLOB_TSX],
1294
+ overrides = {},
1295
+ typescript: typescript2 = true
1296
+ } = options;
1297
+ await ensurePackages([
1298
+ "eslint-plugin-react",
1299
+ "eslint-plugin-react-hooks",
1300
+ "eslint-plugin-react-refresh"
1301
+ ]);
1302
+ const [
1303
+ pluginReact,
1304
+ pluginReactHooks,
1305
+ pluginReactRefresh
1306
+ ] = await Promise.all([
1307
+ interopDefault(import("eslint-plugin-react")),
1308
+ interopDefault(import("eslint-plugin-react-hooks")),
1309
+ interopDefault(import("eslint-plugin-react-refresh"))
1310
+ ]);
1311
+ const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some(
1312
+ (i) => isPackageExists2(i)
1313
+ );
1314
+ return [
1315
+ {
1316
+ name: "antfu:react:setup",
1317
+ plugins: {
1318
+ "react": pluginReact,
1319
+ "react-hooks": pluginReactHooks,
1320
+ "react-refresh": pluginReactRefresh
1321
+ }
1322
+ },
1323
+ {
1324
+ files,
1325
+ languageOptions: {
1326
+ parserOptions: {
1327
+ ecmaFeatures: {
1328
+ jsx: true
1329
+ }
1330
+ }
1331
+ },
1332
+ name: "antfu:react:rules",
1333
+ rules: {
1334
+ // recommended rules react-hooks
1335
+ "react-hooks/exhaustive-deps": "warn",
1336
+ "react-hooks/rules-of-hooks": "error",
1337
+ // react refresh
1338
+ "react-refresh/only-export-components": [
1339
+ "warn",
1340
+ { allowConstantExport: isAllowConstantExport }
1341
+ ],
1342
+ // recommended rules react
1343
+ "react/display-name": "error",
1344
+ "react/jsx-key": "error",
1345
+ "react/jsx-no-comment-textnodes": "error",
1346
+ "react/jsx-no-duplicate-props": "error",
1347
+ "react/jsx-no-target-blank": "error",
1348
+ "react/jsx-no-undef": "error",
1349
+ "react/jsx-uses-react": "error",
1350
+ "react/jsx-uses-vars": "error",
1351
+ "react/no-children-prop": "error",
1352
+ "react/no-danger-with-children": "error",
1353
+ "react/no-deprecated": "error",
1354
+ "react/no-direct-mutation-state": "error",
1355
+ "react/no-find-dom-node": "error",
1356
+ "react/no-is-mounted": "error",
1357
+ "react/no-render-return-value": "error",
1358
+ "react/no-string-refs": "error",
1359
+ "react/no-unescaped-entities": "error",
1360
+ "react/no-unknown-property": "error",
1361
+ "react/no-unsafe": "off",
1362
+ "react/prop-types": "error",
1363
+ "react/react-in-jsx-scope": "off",
1364
+ "react/require-render-return": "error",
1365
+ ...typescript2 ? {
1366
+ "react/jsx-no-undef": "off",
1367
+ "react/prop-type": "off"
1368
+ } : {},
1369
+ // overrides
1370
+ ...overrides
1371
+ }
1372
+ }
1373
+ ];
1374
+ }
1375
+
1261
1376
  // src/factory.ts
1262
1377
  var flatConfigProps = [
1263
1378
  "files",
@@ -1279,10 +1394,11 @@ async function antfu(options = {}, ...userConfigs) {
1279
1394
  const {
1280
1395
  componentExts = [],
1281
1396
  gitignore: enableGitignore = true,
1282
- isInEditor = !!((process2.env.VSCODE_PID || process2.env.JETBRAINS_IDE) && !process2.env.CI),
1397
+ isInEditor = !!((process3.env.VSCODE_PID || process3.env.JETBRAINS_IDE) && !process3.env.CI),
1283
1398
  overrides = {},
1284
- typescript: enableTypeScript = isPackageExists("typescript"),
1285
- vue: enableVue = VuePackages.some((i) => isPackageExists(i))
1399
+ react: enableReact = false,
1400
+ typescript: enableTypeScript = isPackageExists3("typescript"),
1401
+ vue: enableVue = VuePackages.some((i) => isPackageExists3(i))
1286
1402
  } = options;
1287
1403
  const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
1288
1404
  if (stylisticOptions && !("jsx" in stylisticOptions))
@@ -1338,6 +1454,12 @@ async function antfu(options = {}, ...userConfigs) {
1338
1454
  typescript: !!enableTypeScript
1339
1455
  }));
1340
1456
  }
1457
+ if (enableReact) {
1458
+ configs.push(react({
1459
+ overrides: overrides.react,
1460
+ typescript: !!enableTypeScript
1461
+ }));
1462
+ }
1341
1463
  if (options.jsonc ?? true) {
1342
1464
  configs.push(
1343
1465
  jsonc({
@@ -1402,6 +1524,7 @@ export {
1402
1524
  combine,
1403
1525
  comments,
1404
1526
  src_default as default,
1527
+ ensurePackages,
1405
1528
  ignores,
1406
1529
  imports,
1407
1530
  interopDefault,
@@ -1411,6 +1534,7 @@ export {
1411
1534
  markdown,
1412
1535
  node,
1413
1536
  perfectionist,
1537
+ react,
1414
1538
  renameRules,
1415
1539
  sortPackageJson,
1416
1540
  sortTsconfig,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@antfu/eslint-config",
3
3
  "type": "module",
4
- "version": "2.0.0",
4
+ "version": "2.1.0",
5
5
  "packageManager": "pnpm@8.10.5",
6
6
  "description": "Anthony's ESLint config",
7
7
  "author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
@@ -25,18 +25,33 @@
25
25
  "dist"
26
26
  ],
27
27
  "peerDependencies": {
28
- "eslint": ">=8.0.0"
28
+ "eslint": ">=8.40.0",
29
+ "eslint-plugin-react": "^7.33.2",
30
+ "eslint-plugin-react-hooks": "^4.6.0",
31
+ "eslint-plugin-react-refresh": "^0.4.4"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "eslint-plugin-react": {
35
+ "optional": true
36
+ },
37
+ "eslint-plugin-react-hooks": {
38
+ "optional": true
39
+ },
40
+ "eslint-plugin-react-refresh": {
41
+ "optional": true
42
+ }
29
43
  },
30
44
  "dependencies": {
31
45
  "@antfu/eslint-define-config": "^1.23.0-2",
46
+ "@antfu/install-pkg": "^0.2.0",
32
47
  "@eslint-types/jsdoc": "46.8.2-1",
33
- "@eslint-types/typescript-eslint": "^6.11.0",
48
+ "@eslint-types/typescript-eslint": "^6.12.0",
34
49
  "@eslint-types/unicorn": "^49.0.0",
35
50
  "@stylistic/eslint-plugin": "^1.4.0",
36
- "@typescript-eslint/eslint-plugin": "^6.11.0",
37
- "@typescript-eslint/parser": "^6.11.0",
51
+ "@typescript-eslint/eslint-plugin": "^6.12.0",
52
+ "@typescript-eslint/parser": "^6.12.0",
38
53
  "eslint-config-flat-gitignore": "^0.1.1",
39
- "eslint-plugin-antfu": "^1.0.9",
54
+ "eslint-plugin-antfu": "^1.0.10",
40
55
  "eslint-plugin-eslint-comments": "^3.2.0",
41
56
  "eslint-plugin-i": "^2.29.0",
42
57
  "eslint-plugin-jsdoc": "^46.9.0",
@@ -47,10 +62,9 @@
47
62
  "eslint-plugin-perfectionist": "^2.4.0",
48
63
  "eslint-plugin-unicorn": "^49.0.0",
49
64
  "eslint-plugin-unused-imports": "^3.0.0",
50
- "eslint-plugin-vitest": "^0.3.9",
65
+ "eslint-plugin-vitest": "^0.3.10",
51
66
  "eslint-plugin-vue": "^9.18.1",
52
67
  "eslint-plugin-yml": "^1.10.0",
53
- "execa": "^8.0.1",
54
68
  "globals": "^13.23.0",
55
69
  "jsonc-eslint-parser": "^2.4.0",
56
70
  "local-pkg": "^0.5.0",
@@ -62,25 +76,30 @@
62
76
  "yargs": "^17.7.2"
63
77
  },
64
78
  "devDependencies": {
65
- "@antfu/ni": "^0.21.9",
79
+ "@antfu/ni": "^0.21.10",
80
+ "@stylistic/eslint-plugin-migrate": "^1.4.0",
66
81
  "@types/eslint": "^8.44.7",
67
82
  "@types/fs-extra": "^11.0.4",
68
- "@types/node": "^20.9.1",
69
- "@types/prompts": "^2.4.8",
70
- "@types/yargs": "^17.0.31",
83
+ "@types/node": "^20.9.4",
84
+ "@types/prompts": "^2.4.9",
85
+ "@types/yargs": "^17.0.32",
71
86
  "bumpp": "^9.2.0",
72
87
  "eslint": "^8.54.0",
73
- "eslint-flat-config-viewer": "^0.1.2",
88
+ "eslint-flat-config-viewer": "^0.1.3",
89
+ "eslint-plugin-react": "^7.33.2",
90
+ "eslint-plugin-react-hooks": "^4.6.0",
91
+ "eslint-plugin-react-refresh": "^0.4.4",
74
92
  "esno": "^4.0.0",
93
+ "execa": "^8.0.1",
75
94
  "fast-glob": "^3.3.2",
76
95
  "fs-extra": "^11.1.1",
77
96
  "lint-staged": "^15.1.0",
78
97
  "rimraf": "^5.0.5",
79
98
  "simple-git-hooks": "^2.9.0",
80
- "tsup": "^7.3.0",
81
- "typescript": "^5.2.2",
99
+ "tsup": "^8.0.1",
100
+ "typescript": "^5.3.2",
82
101
  "vitest": "^0.34.6",
83
- "@antfu/eslint-config": "2.0.0"
102
+ "@antfu/eslint-config": "2.1.0"
84
103
  },
85
104
  "simple-git-hooks": {
86
105
  "pre-commit": "pnpm lint-staged"