eslint-config-axkit 1.4.0 → 1.6.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
@@ -1,6 +1,6 @@
1
1
  # eslint-config-axkit
2
2
 
3
- Reusable ESLint flat config for TypeScript + Node.js projects with strict type checking, Prettier, Unicorn, and Vitest.
3
+ Reusable ESLint flat config for TypeScript + Node.js projects with strict type checking, Prettier, and Unicorn.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -83,12 +83,14 @@ export default [
83
83
 
84
84
  ## Options
85
85
 
86
- | Option | Type | Description |
87
- | --------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
88
- | `gitignorePath` | `string` | Path to `.gitignore` file. Patterns will be added to ESLint's ignore list. |
89
- | `nextjs` | `boolean` | Enable Next.js rules (`eslint-config-next` core-web-vitals + typescript). Requires `eslint-config-next` to be installed. |
90
- | `storybook` | `boolean` | Enable Storybook rules (`eslint-plugin-storybook` flat/recommended). Requires `eslint-plugin-storybook` to be installed. |
91
- | `tailwindcss` | `string` | Path to the Tailwind CSS entry point (e.g. `"src/app/globals.css"`). Enables `eslint-plugin-better-tailwindcss` recommended rules enforcing stylistic and correctness rules. Requires `eslint-plugin-better-tailwindcss` to be installed. |
86
+ | Option | Type | Description |
87
+ | --------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
88
+ | `gitignorePath` | `string` | Path to `.gitignore` file. Patterns will be added to ESLint's ignore list. |
89
+ | `vitest` | `boolean` | Enable Vitest ESLint rules for test files. Requires `@vitest/eslint-plugin` to be installed. |
90
+ | `fastify` | `boolean` | Relax rules that conflict with idiomatic Fastify patterns. Configures `unicorn/prevent-abbreviations` with an allowList for common terms (`app`, `db`, `req`, etc.) and disables `@typescript-eslint/require-await` and `@typescript-eslint/strict-void-return`. |
91
+ | `nextjs` | `boolean` | Enable Next.js rules (`eslint-config-next` core-web-vitals + typescript). Requires `eslint-config-next` to be installed. |
92
+ | `storybook` | `boolean` | Enable Storybook rules (`eslint-plugin-storybook` flat/recommended). Requires `eslint-plugin-storybook` to be installed. |
93
+ | `tailwindcss` | `string` | Path to the Tailwind CSS entry point (e.g. `"src/app/globals.css"`). Enables `eslint-plugin-better-tailwindcss` recommended rules enforcing stylistic and correctness rules. Requires `eslint-plugin-better-tailwindcss` to be installed. |
92
94
 
93
95
  ## Requirements
94
96
 
package/dist/index.d.ts CHANGED
@@ -11,6 +11,18 @@ export type Options = {
11
11
  * Requires `eslint-config-next` to be installed.
12
12
  */
13
13
  nextjs?: boolean;
14
+ /**
15
+ * Enable Vitest ESLint rules for test files.
16
+ * Requires `@vitest/eslint-plugin` to be installed.
17
+ */
18
+ vitest?: boolean;
19
+ /**
20
+ * Relax rules that conflict with idiomatic Fastify patterns:
21
+ * - `unicorn/prevent-abbreviations` — configured with allowList for common Fastify terms (`app`, `db`, `req`, `res`, `opts`, `params`, etc.)
22
+ * - `@typescript-eslint/require-await` — disabled; `FastifyPluginAsync` requires `async` but plugin bodies often contain no `await`
23
+ * - `@typescript-eslint/strict-void-return` — disabled; route handlers use `return reply.notFound()` as control flow
24
+ */
25
+ fastify?: boolean;
14
26
  /**
15
27
  * Enable Storybook rules (eslint-plugin-storybook flat/recommended).
16
28
  * Requires `eslint-plugin-storybook` to be installed.
@@ -31,10 +43,11 @@ export type Options = {
31
43
  * - ESLint recommended rules
32
44
  * - TypeScript strict type checking
33
45
  * - Unicorn plugin (recommended)
34
- * - Vitest plugin for test files
46
+ * - `node:test` support (`allowForKnownSafeCalls` for promise-returning functions)
35
47
  * - Prettier compatibility (disables conflicting rules)
36
48
  *
37
49
  * Optional:
50
+ * - Vitest plugin for test files via `vitest: true`
38
51
  * - Next.js rules (core-web-vitals + typescript) via `nextjs: true`
39
52
  * - Storybook rules (flat/recommended) via `storybook: true`
40
53
  * - Tailwind CSS rules (better-tailwindcss/recommended) via `tailwindcss: "path/to/entry.css"`
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@ import eslintConfigPrettier from "eslint-config-prettier/flat";
5
5
  import eslintPluginUnicorn from "eslint-plugin-unicorn";
6
6
  import { importOptional } from "./import-optional.js";
7
7
  import { baseConfig } from "./base-config.js";
8
- import { vitestConfig } from "./vitest-config.js";
8
+ import { nodeTestConfig } from "./node-test-config.js";
9
+ import { createVitestConfig } from "./vitest-config.js";
9
10
  /**
10
11
  * Creates a complete ESLint flat config for TypeScript projects.
11
12
  *
@@ -13,17 +14,23 @@ import { vitestConfig } from "./vitest-config.js";
13
14
  * - ESLint recommended rules
14
15
  * - TypeScript strict type checking
15
16
  * - Unicorn plugin (recommended)
16
- * - Vitest plugin for test files
17
+ * - `node:test` support (`allowForKnownSafeCalls` for promise-returning functions)
17
18
  * - Prettier compatibility (disables conflicting rules)
18
19
  *
19
20
  * Optional:
21
+ * - Vitest plugin for test files via `vitest: true`
20
22
  * - Next.js rules (core-web-vitals + typescript) via `nextjs: true`
21
23
  * - Storybook rules (flat/recommended) via `storybook: true`
22
24
  * - Tailwind CSS rules (better-tailwindcss/recommended) via `tailwindcss: "path/to/entry.css"`
23
25
  */
24
26
  export async function axkit(options = {}) {
25
- const { gitignorePath, nextjs, storybook, tailwindcss } = options;
26
- const configs = [];
27
+ const { gitignorePath, vitest, fastify, nextjs, storybook, tailwindcss } = options;
28
+ const configs = [
29
+ {
30
+ name: "axkit/ignores",
31
+ ignores: [".agents/", ".claude/"],
32
+ },
33
+ ];
27
34
  // ── Gitignore ──────────────────────────────────────────────────────
28
35
  if (gitignorePath) {
29
36
  configs.push(includeIgnoreFile(gitignorePath, "Copy patterns from .gitignore"));
@@ -53,7 +60,41 @@ export async function axkit(options = {}) {
53
60
  name: "axkit/config-files",
54
61
  files: ["*.config.{js,ts,mjs,mts}"],
55
62
  ...tseslint.configs.disableTypeChecked,
56
- }, vitestConfig);
63
+ },
64
+ // node:test (always applied — harmless if not using node:test)
65
+ nodeTestConfig);
66
+ // ── Vitest (optional, requires @vitest/eslint-plugin) ──────────────
67
+ if (vitest) {
68
+ const vitestPlugin = await importOptional("@vitest/eslint-plugin");
69
+ configs.push(createVitestConfig(vitestPlugin));
70
+ }
71
+ // ── Fastify (disable conflicting rules) ────────────────────────────
72
+ if (fastify) {
73
+ configs.push({
74
+ name: "axkit/fastify",
75
+ rules: {
76
+ "unicorn/prevent-abbreviations": [
77
+ "error",
78
+ {
79
+ allowList: {
80
+ app: true,
81
+ args: true,
82
+ ctx: true,
83
+ db: true,
84
+ env: true,
85
+ err: true,
86
+ opts: true,
87
+ params: true,
88
+ req: true,
89
+ res: true,
90
+ },
91
+ },
92
+ ],
93
+ "@typescript-eslint/require-await": "off",
94
+ "@typescript-eslint/strict-void-return": "off",
95
+ },
96
+ });
97
+ }
57
98
  // ── Storybook (after base, before Prettier) ────────────────────────
58
99
  if (storybook) {
59
100
  const storybookPlugin = (await importOptional("eslint-plugin-storybook"));
@@ -0,0 +1,8 @@
1
+ import type { Linter } from "eslint";
2
+ /**
3
+ * Whitelists promise-returning `node:test` functions in the
4
+ * `no-floating-promises` rule via `allowForKnownSafeCalls`.
5
+ *
6
+ * Always applied — harmless if not using `node:test`.
7
+ */
8
+ export declare const nodeTestConfig: Linter.Config;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Whitelists promise-returning `node:test` functions in the
3
+ * `no-floating-promises` rule via `allowForKnownSafeCalls`.
4
+ *
5
+ * Always applied — harmless if not using `node:test`.
6
+ */
7
+ export const nodeTestConfig = {
8
+ name: "axkit/node-test",
9
+ files: [
10
+ "**/*.{test,spec}.{ts,tsx,js,mjs,cjs,mts,cts}",
11
+ "tests/**/*.{ts,tsx,js,mjs,cjs,mts,cts}",
12
+ ],
13
+ rules: {
14
+ "@typescript-eslint/no-floating-promises": [
15
+ "error",
16
+ {
17
+ allowForKnownSafeCalls: [
18
+ {
19
+ from: "package",
20
+ package: "node:test",
21
+ name: ["describe", "it", "test", "suite", "todo", "skip", "only"],
22
+ },
23
+ ],
24
+ },
25
+ ],
26
+ },
27
+ };
@@ -1,2 +1,15 @@
1
1
  import type { Linter } from "eslint";
2
- export declare const vitestConfig: Linter.Config;
2
+ type VitestPlugin = {
3
+ configs: {
4
+ recommended: {
5
+ rules: Linter.RulesRecord;
6
+ };
7
+ };
8
+ environments: {
9
+ env: {
10
+ globals: Record<string, boolean>;
11
+ };
12
+ };
13
+ };
14
+ export declare function createVitestConfig(vitest: VitestPlugin): Linter.Config;
15
+ export {};
@@ -1,62 +1,63 @@
1
- import vitest from "@vitest/eslint-plugin";
2
- export const vitestConfig = {
3
- name: "axkit/vitest",
4
- files: [
5
- "**/*.{test,spec}.{ts,tsx,js,mjs,cjs,mts,cts}",
6
- "tests/**/*.{ts,tsx,js,mjs,cjs,mts,cts}",
7
- ],
8
- plugins: { vitest },
9
- rules: {
10
- ...vitest.configs.recommended.rules,
11
- // Ensure expect.poll() and expect.element() are awaited
12
- "vitest/require-awaited-expect-poll": "error",
13
- // Keep vi.mock() and other hoisted APIs at the top of files
14
- "vitest/hoisted-apis-on-top": "warn",
15
- // Prefer toHaveBeenCalledTimes() matcher
16
- "vitest/prefer-to-have-been-called-times": "warn",
17
- // Prefer mockResolvedValue() over mockImplementation(() => Promise.resolve())
18
- "vitest/prefer-mock-promise-shorthand": "warn",
19
- // Prefer expectTypeOf() for type testing
20
- "vitest/prefer-expect-type-of": "warn",
21
- // Enforce consistent use of .each vs .for for parameterized tests
22
- "vitest/consistent-each-for": "warn",
23
- // Keep hooks (beforeEach, afterEach, etc.) at the top of describe blocks
24
- "vitest/prefer-hooks-on-top": "warn",
25
- // ===== Test Logic Errors =====
26
- // No conditionals (if/else) inside test bodies - tests should be deterministic
27
- "vitest/no-conditional-in-test": "error",
28
- // No conditionally defined tests - tests should always run
29
- "vitest/no-conditional-tests": "error",
30
- // No return statements in tests - just execute assertions
31
- "vitest/no-test-return-statement": "warn",
32
- // No duplicate lifecycle hooks
33
- "vitest/no-duplicate-hooks": "warn",
34
- // ===== Better Matchers (auto-fixable) =====
35
- // Use toBe() for primitives (strict equality)
36
- "vitest/prefer-to-be": "warn",
37
- // Use toHaveLength() instead of expect(arr.length).toBe()
38
- "vitest/prefer-to-have-length": "warn",
39
- // Use toContain() instead of expect(arr.includes()).toBe(true)
40
- "vitest/prefer-to-contain": "warn",
41
- // Use toBeGreaterThan(), toBeLessThan(), etc.
42
- "vitest/prefer-comparison-matcher": "warn",
43
- // Use dedicated equality matchers
44
- "vitest/prefer-equality-matcher": "warn",
45
- // ===== Best Practices =====
46
- // Use vi.spyOn() instead of direct property assignment
47
- "vitest/prefer-spy-on": "warn",
48
- // Use test.todo() for empty/placeholder tests
49
- "vitest/prefer-todo": "warn",
50
- // Use expect().resolves instead of expect(await promise)
51
- "vitest/prefer-expect-resolves": "warn",
52
- // No deprecated alias methods (toBeCalled → toHaveBeenCalled)
53
- "vitest/no-alias-methods": "warn",
54
- // Use vi.mocked() instead of type casting
55
- "vitest/prefer-vi-mocked": "warn",
56
- // Use .only/.skip instead of f/x prefixes
57
- "vitest/no-test-prefixes": "warn",
58
- },
59
- languageOptions: {
60
- globals: { ...vitest.environments.env.globals },
61
- },
62
- };
1
+ export function createVitestConfig(vitest) {
2
+ return {
3
+ name: "axkit/vitest",
4
+ files: [
5
+ "**/*.{test,spec}.{ts,tsx,js,mjs,cjs,mts,cts}",
6
+ "tests/**/*.{ts,tsx,js,mjs,cjs,mts,cts}",
7
+ ],
8
+ plugins: { vitest },
9
+ rules: {
10
+ ...vitest.configs.recommended.rules,
11
+ // Ensure expect.poll() and expect.element() are awaited
12
+ "vitest/require-awaited-expect-poll": "error",
13
+ // Keep vi.mock() and other hoisted APIs at the top of files
14
+ "vitest/hoisted-apis-on-top": "warn",
15
+ // Prefer toHaveBeenCalledTimes() matcher
16
+ "vitest/prefer-to-have-been-called-times": "warn",
17
+ // Prefer mockResolvedValue() over mockImplementation(() => Promise.resolve())
18
+ "vitest/prefer-mock-promise-shorthand": "warn",
19
+ // Prefer expectTypeOf() for type testing
20
+ "vitest/prefer-expect-type-of": "warn",
21
+ // Enforce consistent use of .each vs .for for parameterized tests
22
+ "vitest/consistent-each-for": "warn",
23
+ // Keep hooks (beforeEach, afterEach, etc.) at the top of describe blocks
24
+ "vitest/prefer-hooks-on-top": "warn",
25
+ // ===== Test Logic Errors =====
26
+ // No conditionals (if/else) inside test bodies - tests should be deterministic
27
+ "vitest/no-conditional-in-test": "error",
28
+ // No conditionally defined tests - tests should always run
29
+ "vitest/no-conditional-tests": "error",
30
+ // No return statements in tests - just execute assertions
31
+ "vitest/no-test-return-statement": "warn",
32
+ // No duplicate lifecycle hooks
33
+ "vitest/no-duplicate-hooks": "warn",
34
+ // ===== Better Matchers (auto-fixable) =====
35
+ // Use toBe() for primitives (strict equality)
36
+ "vitest/prefer-to-be": "warn",
37
+ // Use toHaveLength() instead of expect(arr.length).toBe()
38
+ "vitest/prefer-to-have-length": "warn",
39
+ // Use toContain() instead of expect(arr.includes()).toBe(true)
40
+ "vitest/prefer-to-contain": "warn",
41
+ // Use toBeGreaterThan(), toBeLessThan(), etc.
42
+ "vitest/prefer-comparison-matcher": "warn",
43
+ // Use dedicated equality matchers
44
+ "vitest/prefer-equality-matcher": "warn",
45
+ // ===== Best Practices =====
46
+ // Use vi.spyOn() instead of direct property assignment
47
+ "vitest/prefer-spy-on": "warn",
48
+ // Use test.todo() for empty/placeholder tests
49
+ "vitest/prefer-todo": "warn",
50
+ // Use expect().resolves instead of expect(await promise)
51
+ "vitest/prefer-expect-resolves": "warn",
52
+ // No deprecated alias methods (toBeCalled → toHaveBeenCalled)
53
+ "vitest/no-alias-methods": "warn",
54
+ // Use vi.mocked() instead of type casting
55
+ "vitest/prefer-vi-mocked": "warn",
56
+ // Use .only/.skip instead of f/x prefixes
57
+ "vitest/no-test-prefixes": "warn",
58
+ },
59
+ languageOptions: {
60
+ globals: { ...vitest.environments.env.globals },
61
+ },
62
+ };
63
+ }
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "eslint-config-axkit",
3
3
  "author": "Łukasz Jerciński",
4
4
  "license": "MIT",
5
- "version": "1.4.0",
6
- "description": "Reusable ESLint flat config for TypeScript + Node.js projects with strict type checking, Prettier, Unicorn, and Vitest",
5
+ "version": "1.6.0",
6
+ "description": "Reusable ESLint flat config for TypeScript + Node.js projects with strict type checking, Prettier, and Unicorn",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/Jercik/eslint-config-axkit.git"
@@ -53,7 +53,7 @@
53
53
  "vitest",
54
54
  "axkit"
55
55
  ],
56
- "packageManager": "pnpm@10.30.1",
56
+ "packageManager": "pnpm@10.30.3",
57
57
  "engines": {
58
58
  "node": ">=22.14.0"
59
59
  },
@@ -61,7 +61,8 @@
61
61
  "eslint": ">=10",
62
62
  "eslint-config-next": ">=16",
63
63
  "eslint-plugin-better-tailwindcss": ">=4",
64
- "eslint-plugin-storybook": ">=10"
64
+ "eslint-plugin-storybook": ">=10",
65
+ "@vitest/eslint-plugin": ">=1"
65
66
  },
66
67
  "peerDependenciesMeta": {
67
68
  "eslint-config-next": {
@@ -72,25 +73,27 @@
72
73
  },
73
74
  "eslint-plugin-storybook": {
74
75
  "optional": true
76
+ },
77
+ "@vitest/eslint-plugin": {
78
+ "optional": true
75
79
  }
76
80
  },
77
81
  "dependencies": {
78
- "@eslint/compat": "^2.0.2",
82
+ "@eslint/compat": "^2.0.3",
79
83
  "@eslint/js": "^10.0.1",
80
- "@vitest/eslint-plugin": "^1.6.9",
81
84
  "eslint-config-prettier": "^10.1.8",
82
85
  "eslint-plugin-unicorn": "^63.0.0",
83
- "globals": "^17.3.0",
84
- "typescript-eslint": "^8.56.0"
86
+ "globals": "^17.4.0",
87
+ "typescript-eslint": "^8.56.1"
85
88
  },
86
89
  "devDependencies": {
87
90
  "@total-typescript/ts-reset": "^0.6.1",
88
- "@types/node": "^25.3.0",
91
+ "@types/node": "^25.3.5",
89
92
  "@vitest/coverage-v8": "^4.0.18",
90
- "eslint": "^10.0.0",
93
+ "eslint": "^10.0.3",
91
94
  "fta-check": "^1.5.1",
92
95
  "fta-cli": "^3.0.0",
93
- "knip": "^5.84.1",
96
+ "knip": "^5.85.0",
94
97
  "prettier": "3.8.1",
95
98
  "semantic-release": "^25.0.3",
96
99
  "typescript": "^5.9.3",