@jimmy.codes/eslint-config 6.21.0 → 6.22.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
@@ -42,7 +42,7 @@ import { defineConfig } from "@jimmy.codes/eslint-config";
42
42
  export default defineConfig();
43
43
  ```
44
44
 
45
- Itll auto-configure based on your installed dependencies.
45
+ It'll auto-configure based on your installed dependencies.
46
46
 
47
47
  ---
48
48
 
@@ -75,6 +75,30 @@ export default defineConfig({
75
75
  });
76
76
  ```
77
77
 
78
+ ### Vitest Configuration
79
+
80
+ Vitest also supports some configuration options. If options are provided then Vitest support is enabled.
81
+
82
+ #### Configure Vitest Globals
83
+
84
+ Control how [Vitest globals configuration](https://vitest.dev/config/globals.html) (`describe`, `it`, `expect`, etc.) are handled:
85
+
86
+ ```ts
87
+ import { defineConfig } from "@jimmy.codes/eslint-config";
88
+
89
+ export default defineConfig({
90
+ vitest: {
91
+ globals: "explicit", // Require explicit imports from 'vitest'
92
+ },
93
+ });
94
+ ```
95
+
96
+ Options:
97
+
98
+ - `'explicit'`: Require explicit imports from `'vitest'`
99
+ - `'implicit'`: Use implicit global APIs (vitest config `globals: true`)
100
+ - `'either'`: Allow both styles (default)
101
+
78
102
  ### Override Specific Rules
79
103
 
80
104
  ```ts
package/dist/index.d.mts CHANGED
@@ -15004,6 +15004,20 @@ interface LinterConfigOverrides {
15004
15004
  plugins?: Record<string, unknown>;
15005
15005
  }
15006
15006
  type TypedConfigItem = Prettify<Override<Base, LinterConfigOverrides>>;
15007
+ interface VitestOptions {
15008
+ /**
15009
+ * How to handle Vitest global APIs (describe, it, expect, etc.).
15010
+ *
15011
+ * - 'explicit': Require explicit imports from 'vitest'
15012
+ * - 'implicit': Use implicit global APIs (vitest config globals: true)
15013
+ * - 'either': Allow both styles (default)
15014
+ *
15015
+ * @see https://vitest.dev/config/globals.html
15016
+ *
15017
+ * @default 'either'
15018
+ */
15019
+ globals?: "either" | "explicit" | "implicit";
15020
+ }
15007
15021
  interface Options {
15008
15022
  /**
15009
15023
  * Are astro rules enabled?
@@ -15091,7 +15105,7 @@ interface Options {
15091
15105
  *
15092
15106
  * @default false
15093
15107
  */
15094
- vitest?: boolean;
15108
+ vitest?: boolean | VitestOptions;
15095
15109
  }
15096
15110
  //#endregion
15097
15111
  //#region src/factory.d.ts
@@ -15122,4 +15136,4 @@ declare const defineConfig: ({
15122
15136
  vitest
15123
15137
  }?: Options, ...moreOverrides: Linter.Config[] | TypedConfigItem[]) => Promise<any[]>;
15124
15138
  //#endregion
15125
- export { Options, Rules, TypedConfigItem, defineConfig };
15139
+ export { type Options, type TypedConfigItem, type VitestOptions, defineConfig };
package/dist/index.mjs CHANGED
@@ -424,6 +424,22 @@ const unicornConfig = () => {
424
424
  }];
425
425
  };
426
426
 
427
+ //#endregion
428
+ //#region src/utils/create-featured.ts
429
+ /**
430
+ * Creates a featured flag checker function.
431
+ *
432
+ * @param autoDetect - Whether to auto-detect features.
433
+ *
434
+ * @returns A function that determines if a feature is enabled.
435
+ */
436
+ const createFeatured = (autoDetect) => {
437
+ return (explicit, detector) => {
438
+ if (typeof explicit !== "boolean") return true;
439
+ return explicit || autoDetect && detector();
440
+ };
441
+ };
442
+
427
443
  //#endregion
428
444
  //#region src/utils/unwrap.ts
429
445
  /**
@@ -436,16 +452,19 @@ const unicornConfig = () => {
436
452
  *
437
453
  * @param module - A dynamically imported module.
438
454
  *
455
+ * @param args - Optional arguments forwarded to the module's default export if it's a function.
456
+ *
439
457
  * @returns
440
458
  * If the module has a `default` export that is a function, it returns the result of calling it.
441
459
  * Otherwise, it returns the module itself.
442
460
  *
443
461
  * @example
444
462
  * const config = await unwrap(import("./configs/react"));
463
+ * const configWithOptions = await unwrap(import("./configs/react"), { version: "12" });
445
464
  */
446
- const unwrap = async (module) => {
465
+ const unwrap = async (module, ...args) => {
447
466
  const resolved = await module;
448
- if (typeof resolved.default === "function") return resolved.default();
467
+ if (typeof resolved.default === "function") return resolved.default(...args);
449
468
  return resolved;
450
469
  };
451
470
 
@@ -462,19 +481,17 @@ const unwrap = async (module) => {
462
481
  * export default defineConfig();
463
482
  */
464
483
  const defineConfig = async ({ astro = false, autoDetect = true, gitignore = false, ignores = [], jest = false, nextjs = false, overrides = [], playwright = false, react = false, storybook = false, tanstackQuery = false, testingLibrary = false, typescript = false, vitest = false } = {}, ...moreOverrides) => {
465
- const getFlag = (explicit, detector) => {
466
- return explicit || autoDetect && detector();
467
- };
468
- const isTypescriptEnabled = getFlag(typescript, hasTypescript);
469
- const isReactEnabled = getFlag(react, hasReact);
470
- const isAstroEnabled = getFlag(astro, hasAstro);
471
- const isTanstackQueryEnabled = getFlag(tanstackQuery, hasReactQuery);
472
- const isTestingLibraryEnabled = getFlag(testingLibrary, hasTestingLibrary);
473
- const isPlaywrightEnabled = getFlag(playwright, hasPlaywright);
474
- const isStorybookEnabled = getFlag(storybook, hasStorybook);
475
- const isNextjsEnabled = getFlag(nextjs, hasNext);
476
- const isJestEnabled = getFlag(jest, hasJest);
477
- const isVitestEnabled = getFlag(vitest, hasVitest);
484
+ const featured = createFeatured(autoDetect);
485
+ const isTypescriptEnabled = featured(typescript, hasTypescript);
486
+ const isReactEnabled = featured(react, hasReact);
487
+ const isAstroEnabled = featured(astro, hasAstro);
488
+ const isTanstackQueryEnabled = featured(tanstackQuery, hasReactQuery);
489
+ const isTestingLibraryEnabled = featured(testingLibrary, hasTestingLibrary);
490
+ const isPlaywrightEnabled = featured(playwright, hasPlaywright);
491
+ const isStorybookEnabled = featured(storybook, hasStorybook);
492
+ const isNextjsEnabled = featured(nextjs, hasNext);
493
+ const isJestEnabled = featured(jest, hasJest);
494
+ const isVitestEnabled = featured(vitest, hasVitest);
478
495
  const baseConfigs = [
479
496
  javascriptConfig(),
480
497
  perfectionistConfig(),
@@ -492,7 +509,7 @@ const defineConfig = async ({ astro = false, autoDetect = true, gitignore = fals
492
509
  isTanstackQueryEnabled && unwrap(import("./tanstack-query-D1gpzKY3.mjs")),
493
510
  isAstroEnabled && unwrap(import("./astro-D3Zl135N.mjs")),
494
511
  isJestEnabled && unwrap(import("./jest-DZtYWPoX.mjs")),
495
- isVitestEnabled && unwrap(import("./vitest-57vZrKwy.mjs")),
512
+ isVitestEnabled && unwrap(import("./vitest-oIUtAksi.mjs"), vitest),
496
513
  isTestingLibraryEnabled && unwrap(import("./testing-library-BBWV3thw.mjs")),
497
514
  isPlaywrightEnabled && unwrap(import("./playwright-CrBcE3qD.mjs")),
498
515
  isStorybookEnabled && unwrap(import("./storybook-CyxpG33Q.mjs")),
@@ -2,7 +2,7 @@ import { l as GLOB_TESTS, r as GLOB_E2E } from "./globs-C_yfK842.mjs";
2
2
  import { t as interopDefault } from "./interop-default-Bn64p66u.mjs";
3
3
 
4
4
  //#region src/rules/vitest.ts
5
- const vitestRules = async () => {
5
+ const vitestRules = async (options) => {
6
6
  return {
7
7
  ...(await interopDefault(import("@vitest/eslint-plugin"))).configs.recommended.rules,
8
8
  "vitest/consistent-each-for": ["error", {
@@ -21,6 +21,7 @@ const vitestRules = async () => {
21
21
  "vitest/no-conditional-in-test": "error",
22
22
  "vitest/no-duplicate-hooks": "error",
23
23
  "vitest/no-hooks": "off",
24
+ "vitest/no-importing-vitest-globals": options?.globals === "implicit" ? "error" : "off",
24
25
  "vitest/no-large-snapshots": "off",
25
26
  "vitest/no-restricted-matchers": "off",
26
27
  "vitest/no-restricted-vi-methods": "off",
@@ -39,6 +40,7 @@ const vitestRules = async () => {
39
40
  "vitest/prefer-expect-type-of": "error",
40
41
  "vitest/prefer-hooks-in-order": "error",
41
42
  "vitest/prefer-hooks-on-top": "error",
43
+ "vitest/prefer-importing-vitest-globals": options?.globals === "explicit" ? "error" : "off",
42
44
  "vitest/prefer-lowercase-title": "off",
43
45
  "vitest/prefer-mock-promise-shorthand": "error",
44
46
  "vitest/prefer-snapshot-hint": "error",
@@ -59,15 +61,30 @@ const vitestRules = async () => {
59
61
  };
60
62
  };
61
63
 
64
+ //#endregion
65
+ //#region src/utils/extract-options.ts
66
+ /**
67
+ * A simple utility to derive options for configurations when one option is a boolean.
68
+ *
69
+ * @param options - The options to derive.
70
+ *
71
+ * @returns The extracted options or `undefined` if the input was a boolean.
72
+ */
73
+ const extractOptions = (options) => {
74
+ if (typeof options !== "boolean") return options;
75
+ };
76
+
62
77
  //#endregion
63
78
  //#region src/configs/vitest.ts
64
- async function vitestConfig() {
79
+ async function vitestConfig(options) {
80
+ const vitestPlugin = await interopDefault(import("@vitest/eslint-plugin"));
81
+ const extractedOptions = extractOptions(options);
65
82
  return [{
66
83
  files: GLOB_TESTS,
67
84
  ignores: GLOB_E2E,
68
- ...(await interopDefault(import("@vitest/eslint-plugin"))).configs.recommended,
85
+ ...vitestPlugin.configs.recommended,
69
86
  name: "jimmy.codes/vitest",
70
- rules: await vitestRules()
87
+ rules: await vitestRules(extractedOptions)
71
88
  }];
72
89
  }
73
90
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jimmy.codes/eslint-config",
3
- "version": "6.21.0",
3
+ "version": "6.22.0",
4
4
  "description": "A simple, modern ESLint config that covers most use cases.",
5
5
  "keywords": [
6
6
  "eslint",