@will-stone/eslint-config 10.0.2 → 11.0.1

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/dist/index.d.ts CHANGED
@@ -1,16 +1,23 @@
1
- import { Linter } from 'eslint';
1
+ import { Linter } from '@typescript-eslint/utils/ts-eslint';
2
2
 
3
3
  type Options = {
4
- /**
5
- * When this option is provided, type-aware rules will be enabled.
6
- * @see https://typescript-eslint.io/linting/typed-linting/
7
- */
8
- readonly tsconfigPath?: string | readonly string[];
4
+ readonly astro?: boolean;
5
+ readonly jest?: boolean;
6
+ readonly react?: boolean;
7
+ readonly tailwind?: boolean;
8
+ readonly typescript?: boolean | {
9
+ /**
10
+ * When this option is provided, type-aware rules will be enabled.
11
+ * @see https://typescript-eslint.io/linting/typed-linting/
12
+ */
13
+ tsconfigPath?: string | readonly string[];
14
+ };
15
+ readonly vitest?: boolean;
9
16
  };
10
17
 
11
18
  /**
12
19
  * Construct an array of ESLint flat config items.
13
20
  */
14
- declare function factory(options?: Options): Linter.FlatConfig[];
21
+ declare function factory(options?: Options): Linter.ConfigType[];
15
22
 
16
23
  export { factory as default };
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- // src/factory.ts
2
- import gitignore from "eslint-config-flat-gitignore";
3
-
4
1
  // src/configs/astro.ts
5
2
  import parserTypescript from "@typescript-eslint/parser";
6
3
  import parserAstro from "astro-eslint-parser";
@@ -344,6 +341,9 @@ function base() {
344
341
  ];
345
342
  }
346
343
 
344
+ // src/configs/ignores.ts
345
+ import gitignore from "eslint-config-flat-gitignore";
346
+
347
347
  // src/globs.ts
348
348
  var GLOB_EXCLUDE = [
349
349
  "**/node_modules",
@@ -378,6 +378,13 @@ function ignores() {
378
378
  {
379
379
  ignores: GLOB_EXCLUDE,
380
380
  name: "will-stone/ignores"
381
+ },
382
+ {
383
+ name: "will-stone/git-ignores",
384
+ ...gitignore({
385
+ // Prevent throw if gitignore not found.
386
+ strict: false
387
+ })
381
388
  }
382
389
  ];
383
390
  }
@@ -539,13 +546,9 @@ import globals3 from "globals";
539
546
  function node() {
540
547
  return [
541
548
  {
542
- languageOptions: {
543
- globals: globals3.node
544
- },
549
+ languageOptions: { globals: globals3.node },
545
550
  name: "will-stone/node",
546
- plugins: {
547
- n: pluginNode
548
- },
551
+ plugins: { n: pluginNode },
549
552
  rules: {
550
553
  "n/callback-return": "error",
551
554
  "n/global-require": "error",
@@ -596,6 +599,7 @@ function node() {
596
599
  }
597
600
 
598
601
  // src/configs/react.ts
602
+ import { fixupPluginRules } from "@eslint/compat";
599
603
  import pluginJsxA11y from "eslint-plugin-jsx-a11y";
600
604
  import pluginReact from "eslint-plugin-react";
601
605
  import pluginReactHooks from "eslint-plugin-react-hooks";
@@ -616,7 +620,7 @@ function react() {
616
620
  plugins: {
617
621
  "jsx-a11y": pluginJsxA11y,
618
622
  react: pluginReact,
619
- "react-hooks": pluginReactHooks
623
+ "react-hooks": fixupPluginRules(pluginReactHooks)
620
624
  },
621
625
  rules: {
622
626
  "jsx-a11y/alt-text": "error",
@@ -920,23 +924,26 @@ function tailwind() {
920
924
  // src/configs/typescript.ts
921
925
  import pluginTypescript from "@typescript-eslint/eslint-plugin";
922
926
  import * as parserTypescript2 from "@typescript-eslint/parser";
923
- function typescript(options) {
924
- const tsconfigPath = options?.tsconfigPath ? Array.isArray(options.tsconfigPath) ? options.tsconfigPath : [options.tsconfigPath] : void 0;
927
+ function typescript(rawOptions) {
928
+ const options = !rawOptions || typeof rawOptions === "boolean" ? {} : rawOptions;
925
929
  return [
926
930
  {
927
931
  files: ["**/*.{ts,tsx,astro}"],
928
932
  languageOptions: {
929
933
  parser: parserTypescript2,
930
934
  parserOptions: {
931
- ...tsconfigPath ? {
932
- project: tsconfigPath,
935
+ ...options.tsconfigPath ? {
936
+ projectService: {
937
+ allowDefaultProject: ["./*.js"],
938
+ defaultProject: options.tsconfigPath
939
+ },
933
940
  tsconfigRootDir: process.cwd()
934
941
  } : {}
935
942
  }
936
943
  },
937
944
  name: "will-stone/typescript",
938
945
  plugins: {
939
- // @ts-expect-error -- does not confirm to type
946
+ // @ts-expect-error -- is using classic config type instead of flat config.
940
947
  "@typescript-eslint": pluginTypescript
941
948
  },
942
949
  rules: {
@@ -1009,7 +1016,7 @@ function typescript(options) {
1009
1016
  /**
1010
1017
  * These require type checking
1011
1018
  */
1012
- ...tsconfigPath ? {
1019
+ ...options?.tsconfigPath ? {
1013
1020
  "@typescript-eslint/await-thenable": "off",
1014
1021
  "@typescript-eslint/consistent-return": "off",
1015
1022
  "@typescript-eslint/consistent-type-exports": "warn",
@@ -1158,9 +1165,7 @@ function unicorn() {
1158
1165
  return [
1159
1166
  {
1160
1167
  name: "will-stone/unicorn",
1161
- plugins: {
1162
- unicorn: pluginUnicorn
1163
- },
1168
+ plugins: { unicorn: pluginUnicorn },
1164
1169
  rules: {
1165
1170
  // This rule is superseded by the unicorn version below
1166
1171
  "no-nested-ternary": "off",
@@ -1313,69 +1318,120 @@ function unicorn() {
1313
1318
  ];
1314
1319
  }
1315
1320
 
1321
+ // src/configs/vitest.ts
1322
+ import { fixupPluginRules as fixupPluginRules2 } from "@eslint/compat";
1323
+ import pluginVitest from "eslint-plugin-vitest";
1324
+ function vitest() {
1325
+ return [
1326
+ {
1327
+ files: ["**/*.{spec,test}.{js,cjs,mjs,jsx,ts,tsx}"],
1328
+ name: "will-stone/vitest",
1329
+ plugins: { vitest: fixupPluginRules2(pluginVitest) },
1330
+ rules: {
1331
+ // For now, I will turn on all rules and tweak them below.
1332
+ ...pluginVitest.configs.all.rules,
1333
+ // Expect as much as you like. Is there any benefit to limiting this?
1334
+ "vitest/max-expects": "off",
1335
+ // The lifecycle hooks, like `beforeEach`, can be useful. I could move
1336
+ // to setup and teardown functions, but not sure yet.
1337
+ "vitest/no-hooks": "off",
1338
+ // Every test must have an expect, this is covered by expect-expect rule.
1339
+ "vitest/prefer-expect-assertions": "off",
1340
+ // These two could be dangerous as you may actually want to ensure that
1341
+ // something is exactly `false` or `true`, and not something that
1342
+ // equates to that if run through Boolean().
1343
+ "vitest/prefer-to-be-falsy": "off",
1344
+ "vitest/prefer-to-be-truthy": "off",
1345
+ // No need to nest everything in useless describe blocks:
1346
+ "vitest/require-top-level-describe": "off"
1347
+ }
1348
+ }
1349
+ ];
1350
+ }
1351
+
1316
1352
  // src/utils.ts
1317
- import { existsSync, readFileSync } from "fs";
1318
- import { globSync } from "glob";
1319
- function checkEnvironment() {
1320
- const isGitIgnore = existsSync(".gitignore");
1321
- let isNodeEngine = false;
1322
- let isTailwind = false;
1323
- let testingFramework = null;
1324
- const allPackageJsonPaths = globSync("**/package.json", {
1325
- ignore: "**/node_modules/**"
1326
- });
1353
+ import { readFileSync } from "fs";
1354
+ import { globbySync } from "globby";
1355
+ function checkDepsExist(depNames) {
1356
+ const depCount = depNames.length;
1357
+ const allPackageJsonPaths = globbySync([
1358
+ "**/package.json",
1359
+ "!**/node_modules/**"
1360
+ ]);
1361
+ const hasPackageMap = {};
1362
+ let foundCount = 0;
1327
1363
  for (const packageJsonPath of allPackageJsonPaths) {
1328
1364
  const buffer = readFileSync(packageJsonPath);
1329
1365
  const data = new TextDecoder().decode(buffer);
1330
- const packageJson = JSON.parse(data);
1331
- if (!testingFramework && Boolean(
1332
- packageJson.dependencies?.jest || packageJson.devDependencies?.jest
1333
- )) {
1334
- testingFramework = "jest";
1335
- }
1336
- if (!isNodeEngine && Boolean(packageJson.engines?.node)) {
1337
- isNodeEngine = true;
1366
+ const package_ = JSON.parse(data);
1367
+ for (const depName of depNames) {
1368
+ if (package_ && (package_.dependencies?.[depName] || package_.devDependencies?.[depName])) {
1369
+ hasPackageMap[depName] = true;
1370
+ foundCount = foundCount + 1;
1371
+ if (foundCount === depCount) {
1372
+ break;
1373
+ }
1374
+ }
1338
1375
  }
1339
- if (!isTailwind && Boolean(
1340
- packageJson.dependencies?.tailwindcss || packageJson.devDependencies?.tailwindcss
1341
- )) {
1342
- isTailwind = true;
1376
+ if (foundCount === depCount) {
1377
+ break;
1343
1378
  }
1344
1379
  }
1345
- const isNode = isNodeEngine || existsSync(".nvmrc") || existsSync(".node-version");
1346
- return {
1347
- isGitIgnore,
1348
- isNode,
1349
- isTailwind,
1350
- testingFramework
1351
- };
1380
+ return hasPackageMap;
1352
1381
  }
1353
1382
 
1354
1383
  // src/factory.ts
1355
1384
  function factory(options) {
1356
- const { isGitIgnore, isNode, isTailwind, testingFramework } = checkEnvironment();
1357
1385
  const configs = [];
1358
- if (isGitIgnore) {
1359
- configs.push([gitignore()]);
1386
+ configs.push(ignores(), base(), imports(), unicorn(), node());
1387
+ const packageExists = checkDepsExist([
1388
+ "typescript",
1389
+ "astro",
1390
+ "react",
1391
+ "tailwind",
1392
+ "jest",
1393
+ "vitest"
1394
+ ]);
1395
+ const isAtLeastOnePackageExists = Object.values(packageExists).some(Boolean);
1396
+ if (isAtLeastOnePackageExists) {
1397
+ console.log("Auto configured plugins:");
1398
+ }
1399
+ if (packageExists.typescript) {
1400
+ console.log(" - TypeScript");
1360
1401
  }
1361
- configs.push(
1362
- ignores(),
1363
- base(),
1364
- imports(),
1365
- unicorn(),
1366
- typescript(options),
1367
- astro(),
1368
- react()
1369
- );
1370
- if (isNode) {
1371
- configs.push(node());
1402
+ if (packageExists.typescript || options?.typescript || process.env.INSPECTOR) {
1403
+ configs.push(typescript(options?.typescript));
1372
1404
  }
1373
- if (isTailwind) {
1405
+ if (packageExists.astro) {
1406
+ console.log(" - Astro");
1407
+ }
1408
+ if (packageExists.astro || options?.astro || process.env.INSPECTOR) {
1409
+ configs.push(astro());
1410
+ }
1411
+ if (packageExists.react) {
1412
+ console.log(" - React");
1413
+ }
1414
+ if (packageExists.react || options?.react || process.env.INSPECTOR) {
1415
+ configs.push(react());
1416
+ }
1417
+ if (packageExists.tailwind) {
1418
+ console.log(" - Tailwind");
1419
+ }
1420
+ if (packageExists.tailwind || options?.tailwind || process.env.INSPECTOR) {
1374
1421
  configs.push(tailwind());
1375
1422
  }
1376
- if (testingFramework === "jest") {
1423
+ if (packageExists.jest) {
1424
+ console.log(" - Tailwind");
1425
+ }
1426
+ if (packageExists.jest || options?.jest || process.env.INSPECTOR) {
1377
1427
  configs.push(jest());
1378
1428
  }
1429
+ if (packageExists.vitest) {
1430
+ console.log(" - Vitest");
1431
+ }
1432
+ if (packageExists.vitest || options?.vitest || process.env.INSPECTOR) {
1433
+ configs.push(vitest());
1434
+ }
1379
1435
  const merged = configs.flat();
1380
1436
  return merged;
1381
1437
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@will-stone/eslint-config",
3
- "version": "10.0.2",
3
+ "version": "11.0.1",
4
4
  "description": "Will Stone's ESLint config",
5
5
  "keywords": [
6
6
  "eslint-config"
@@ -25,8 +25,8 @@
25
25
  "dist"
26
26
  ],
27
27
  "scripts": {
28
- "build": "tsup src/index.ts --format esm,cjs --clean --dts --cjsInterop --splitting",
29
- "dev": "tsup src/index.ts --format esm,cjs --watch & config-inspector",
28
+ "build": "tsup src/index.ts --format esm --clean --dts",
29
+ "dev": "tsup src/index.ts --format esm --watch & INSPECTOR=true config-inspector",
30
30
  "lint": "npm run stub && eslint .",
31
31
  "prepare": "husky",
32
32
  "prepublishOnly": "npm run build",
@@ -44,23 +44,26 @@
44
44
  },
45
45
  "prettier": "@will-stone/prettier-config",
46
46
  "dependencies": {
47
- "@typescript-eslint/eslint-plugin": "^8.0.0",
48
- "@typescript-eslint/parser": "^8.0.0",
47
+ "@eslint/compat": "^1.1.1",
48
+ "@typescript-eslint/eslint-plugin": "^8.0.1",
49
+ "@typescript-eslint/parser": "^8.0.1",
49
50
  "astro-eslint-parser": "^1.0.2",
50
51
  "confusing-browser-globals": "^1.0.11",
51
52
  "eslint-config-flat-gitignore": "^0.1.8",
52
53
  "eslint-plugin-astro": "^1.2.3",
53
54
  "eslint-plugin-import-x": "^3.1.0",
54
- "eslint-plugin-jest": "^28.7.0",
55
+ "eslint-plugin-jest": "^28.8.0",
55
56
  "eslint-plugin-jsx-a11y": "^6.9.0",
56
- "eslint-plugin-n": "^17.10.1",
57
+ "eslint-plugin-n": "^17.10.2",
57
58
  "eslint-plugin-react": "^7.35.0",
58
59
  "eslint-plugin-react-hooks": "^4.6.2",
59
60
  "eslint-plugin-simple-import-sort": "^12.1.1",
60
61
  "eslint-plugin-tailwindcss": "^3.17.4",
61
62
  "eslint-plugin-unicorn": "^55.0.0",
62
- "glob": "^11.0.0",
63
- "globals": "^15.9.0"
63
+ "eslint-plugin-vitest": "^0.5.4",
64
+ "globals": "^15.9.0",
65
+ "globby": "^14.0.2",
66
+ "type-fest": "^4.24.0"
64
67
  },
65
68
  "devDependencies": {
66
69
  "@commits-with-character/conventional-changelog-preset": "^0.2.2",
@@ -68,20 +71,20 @@
68
71
  "@release-it/conventional-changelog": "^8.0.1",
69
72
  "@types/confusing-browser-globals": "^1.0.3",
70
73
  "@types/eslint": "^9.6.0",
71
- "@types/node": "^22.1.0",
74
+ "@types/node": "^22.2.0",
75
+ "@typescript-eslint/utils": "^8.0.1",
72
76
  "@will-stone/prettier-config": "^8.0.1",
73
77
  "husky": "^9.1.4",
74
78
  "lint-staged": "^15.2.8",
75
79
  "prettier": "^3.3.3",
76
80
  "release-it": "^17.6.0",
77
81
  "tsup": "^8.2.4",
78
- "type-fest": "^4.23.0",
79
82
  "typescript": "^5.5.4"
80
83
  },
81
84
  "peerDependencies": {
82
- "eslint": ">=9.8.0"
85
+ "eslint": ">=9.9.0"
83
86
  },
84
87
  "overrides": {
85
- "eslint": ">=9.8.0"
88
+ "eslint": ">=9.9.0"
86
89
  }
87
90
  }