eslint-plugin-nextfriday 4.2.0 → 4.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 4.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#128](https://github.com/next-friday/eslint-plugin-nextfriday/pull/128) [`b165ec5`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/b165ec51eb3ec870a546ab808821426186543356) Thanks [@joetakara](https://github.com/joetakara)! - add enforce-hook-filename, enforce-test-filename, no-helper-function-in-hook, no-helper-function-in-test rules
8
+
3
9
  ## 4.2.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -413,6 +413,8 @@ In practice: turn the high tier on as `"error"` first, leave the medium tier as
413
413
  | [require-explicit-return-type](docs/rules/REQUIRE_EXPLICIT_RETURN_TYPE.md) | Require explicit return types on functions for better documentation | ❌ |
414
414
  | [no-complex-inline-return](docs/rules/NO_COMPLEX_INLINE_RETURN.md) | Disallow complex inline expressions in return - extract to const first | ❌ |
415
415
  | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic/conditions in function parameters - extract to const | ❌ |
416
+ | [enforce-hook-filename](docs/rules/ENFORCE_HOOK_FILENAME.md) | Enforce that files exporting custom hooks are named \*.hook.ts | ❌ |
417
+ | [enforce-test-filename](docs/rules/ENFORCE_TEST_FILENAME.md) | Enforce that files containing test code are named \*.test.ts | ❌ |
416
418
  | [enforce-hook-naming](docs/rules/ENFORCE_HOOK_NAMING.md) | Enforce 'use' prefix for functions in \*.hook.ts files | ❌ |
417
419
  | [enforce-service-naming](docs/rules/ENFORCE_SERVICE_NAMING.md) | Enforce 'fetch' prefix for async functions in \*.service.ts files | ❌ |
418
420
  | [enforce-sorted-destructuring](docs/rules/ENFORCE_SORTED_DESTRUCTURING.md) | Enforce alphabetical sorting of destructured properties | ✅ |
@@ -427,6 +429,8 @@ In practice: turn the high tier on as `"error"` first, leave the medium tier as
427
429
  | [prefer-async-await](docs/rules/PREFER_ASYNC_AWAIT.md) | Enforce async/await over .then() promise chains | ❌ |
428
430
  | [no-nested-ternary](docs/rules/NO_NESTED_TERNARY.md) | Disallow nested ternary expressions | ❌ |
429
431
  | [prefer-guard-clause](docs/rules/PREFER_GUARD_CLAUSE.md) | Enforce guard clause pattern instead of nested if statements | ❌ |
432
+ | [no-helper-function-in-hook](docs/rules/NO_HELPER_FUNCTION_IN_HOOK.md) | Disallow non-hook helper function definitions in hook files | ❌ |
433
+ | [no-helper-function-in-test](docs/rules/NO_HELPER_FUNCTION_IN_TEST.md) | Disallow helper function definitions in test files | ❌ |
430
434
 
431
435
  ### Import Optimization Rules
432
436
 
@@ -485,23 +489,25 @@ In practice: turn the high tier on as `"error"` first, leave the medium tier as
485
489
 
486
490
  | Preset | Severity | Base Rules | JSX Rules | Total Rules |
487
491
  | -------------------- | -------- | ---------- | --------- | ----------- |
488
- | `base` | warn | 40 | 0 | 40 |
489
- | `base/recommended` | error | 40 | 0 | 40 |
490
- | `react` | warn | 40 | 23 | 63 |
491
- | `react/recommended` | error | 40 | 23 | 63 |
492
- | `nextjs` | warn | 40 | 23 | 63 |
493
- | `nextjs/recommended` | error | 40 | 23 | 63 |
492
+ | `base` | warn | 42 | 0 | 42 |
493
+ | `base/recommended` | error | 42 | 0 | 42 |
494
+ | `react` | warn | 42 | 23 | 65 |
495
+ | `react/recommended` | error | 42 | 23 | 65 |
496
+ | `nextjs` | warn | 42 | 23 | 65 |
497
+ | `nextjs/recommended` | error | 42 | 23 | 65 |
494
498
 
495
499
  The `nextjs` and `nextjs/recommended` presets currently share the same rule set as `react` and `react/recommended`; they are kept as named aliases for ergonomics.
496
500
 
497
- ### Base Configuration Rules (40 rules)
501
+ ### Base Configuration Rules (42 rules)
498
502
 
499
503
  Included in `base`, `base/recommended`, and all other presets:
500
504
 
501
505
  - `nextfriday/boolean-naming-prefix`
502
506
  - `nextfriday/enforce-camel-case`
503
507
  - `nextfriday/enforce-constant-case`
508
+ - `nextfriday/enforce-hook-filename`
504
509
  - `nextfriday/enforce-hook-naming`
510
+ - `nextfriday/enforce-test-filename`
505
511
  - `nextfriday/enforce-property-case`
506
512
  - `nextfriday/enforce-service-naming`
507
513
  - `nextfriday/enforce-sorted-destructuring`
@@ -0,0 +1,77 @@
1
+ # enforce-hook-filename
2
+
3
+ Enforce that files exporting custom hooks are named `*.hook.ts` or `*.hooks.ts`.
4
+
5
+ ## Rule Details
6
+
7
+ Any file that exports a custom hook (a function whose name starts with `use` followed by an uppercase letter) must have a `.hook.ts` or `.hooks.ts` suffix. This ensures hook files are consistently discoverable and that `no-helper-function-in-hook` can be reliably scoped to them.
8
+
9
+ ### Why?
10
+
11
+ Without enforced naming, hooks can silently live inside service files, utility files, or component files — breaking the `files` glob that powers `no-helper-function-in-hook` and making codebases harder to navigate.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ // use-user-data.ts ❌
19
+ export function useUserData() {
20
+ return null;
21
+ }
22
+ ```
23
+
24
+ ```ts
25
+ // user.service.ts ❌
26
+ export const useCurrentUser = () => null;
27
+ ```
28
+
29
+ ```ts
30
+ // UserCard.tsx ❌
31
+ export function useUserCard() {
32
+ return null;
33
+ }
34
+ ```
35
+
36
+ ### Correct
37
+
38
+ ```ts
39
+ // use-user-data.hook.ts ✅
40
+ export function useUserData() {
41
+ return null;
42
+ }
43
+ ```
44
+
45
+ ```ts
46
+ // user.hooks.ts ✅
47
+ export const useCurrentUser = () => null;
48
+ ```
49
+
50
+ Re-exporting from an index file is fine — only the file that defines the hook must follow the naming convention:
51
+
52
+ ```ts
53
+ // index.ts ✅
54
+ export { useUserData } from "./use-user-data.hook";
55
+ ```
56
+
57
+ ## What This Rule Checks
58
+
59
+ - `export function useFoo()` — named function declaration export
60
+ - `export const useFoo = () =>` — arrow function export
61
+ - `export const useFoo = function()` — function expression export
62
+ - `export default function useFoo()` — default function declaration export
63
+
64
+ A name is treated as a hook only when it starts with `use` followed by an uppercase letter (e.g. `useData`, not `user` or `use`).
65
+
66
+ ## Exceptions
67
+
68
+ Files already named `*.hook.ts` or `*.hooks.ts` are skipped entirely. Re-exports (`export { useFoo } from "..."`) are not flagged.
69
+
70
+ ## When Not To Use It
71
+
72
+ Disable per-file if you intentionally co-locate a small hook with its only consumer and do not plan to reuse it.
73
+
74
+ ## Related Rules
75
+
76
+ - [enforce-hook-naming](./ENFORCE_HOOK_NAMING.md) — enforces the `use` prefix on functions inside hook files
77
+ - [no-helper-function-in-hook](./NO_HELPER_FUNCTION_IN_HOOK.md) — disallows non-hook helpers inside hook files
@@ -0,0 +1,61 @@
1
+ # enforce-test-filename
2
+
3
+ Enforce that files containing test code are named `*.test.ts` or `*.test.tsx`.
4
+
5
+ ## Rule Details
6
+
7
+ Any file that calls test runner globals (`describe`, `it`, `test`, `beforeEach`, `beforeAll`, `afterEach`, `afterAll`) must have a `.test.ts` or `.test.tsx` suffix. Files named `*.spec.ts` or any other pattern are not allowed.
8
+
9
+ ### Why?
10
+
11
+ Consistent naming makes test files predictable to find and reliable to target with `files` globs in ESLint configs (e.g. `no-helper-function-in-test`). Mixing `.spec.ts` and `.test.ts` breaks glob-based scoping.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ // user.spec.ts ❌
19
+ describe("user", () => {
20
+ it("works", () => {});
21
+ });
22
+ ```
23
+
24
+ ```ts
25
+ // user-tests.ts ❌
26
+ it("works", () => {});
27
+ ```
28
+
29
+ ### Correct
30
+
31
+ ```ts
32
+ // user.test.ts ✅
33
+ describe("user", () => {
34
+ it("works", () => {});
35
+ });
36
+ ```
37
+
38
+ ```ts
39
+ // UserCard.test.tsx ✅
40
+ test("renders", () => {});
41
+ ```
42
+
43
+ ## What This Rule Checks
44
+
45
+ Files that contain calls to any of the following globals trigger the requirement:
46
+
47
+ `describe`, `it`, `test`, `beforeEach`, `beforeAll`, `afterEach`, `afterAll`
48
+
49
+ Only one error is reported per file regardless of how many test calls are present.
50
+
51
+ ## Exceptions
52
+
53
+ Files already named `*.test.ts` or `*.test.tsx` are skipped entirely.
54
+
55
+ ## When Not To Use It
56
+
57
+ Disable if your project intentionally uses `.spec.ts` as the test file convention.
58
+
59
+ ## Related Rules
60
+
61
+ - [no-helper-function-in-test](./NO_HELPER_FUNCTION_IN_TEST.md) — disallows helper functions inside test files
@@ -0,0 +1,86 @@
1
+ # no-helper-function-in-hook
2
+
3
+ Disallow non-hook helper function definitions in hook files.
4
+
5
+ ## Rule Details
6
+
7
+ Custom hook files should contain only the hook function itself (prefixed with `use`) and its supporting constants. Utility functions that are not hooks must be extracted to a separate file and imported.
8
+
9
+ ### Why?
10
+
11
+ Helper functions defined inside a hook file are invisible to the rest of the codebase, cannot be tested independently, and are harder to reuse. Keeping hook files focused on a single hook makes them easier to read and maintain.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ function buildQueryKey(id: string): string {
19
+ return `item-${id}`;
20
+ }
21
+
22
+ export function useItemData(id: string) {
23
+ const key = buildQueryKey(id);
24
+ // ...
25
+ }
26
+ ```
27
+
28
+ ```ts
29
+ const formatResponse = (data: unknown) => data;
30
+
31
+ export const useItemData = (id: string) => {
32
+ // ...
33
+ };
34
+ ```
35
+
36
+ ### Correct
37
+
38
+ ```ts
39
+ import { buildQueryKey } from "./item.utils";
40
+
41
+ export function useItemData(id: string) {
42
+ const key = buildQueryKey(id);
43
+ // ...
44
+ }
45
+ ```
46
+
47
+ Functions defined inside the hook body are fine:
48
+
49
+ ```ts
50
+ export function useItemData(id: string) {
51
+ function buildQueryKey() {
52
+ return `item-${id}`;
53
+ }
54
+ // ...
55
+ }
56
+ ```
57
+
58
+ ## What This Rule Checks
59
+
60
+ - Top-level `function` declarations whose name does not start with `use`
61
+ - Top-level `const`/`let`/`var` declarations assigned an arrow function or function expression whose name does not start with `use`
62
+
63
+ Both plain and `export`-prefixed declarations are checked.
64
+
65
+ ## Exceptions
66
+
67
+ - Hook functions starting with `use` are allowed at the top level
68
+ - Functions defined inside a hook body are not flagged
69
+ - Non-function constants (strings, numbers, arrays, objects) are not flagged
70
+
71
+ ## When Not To Use It
72
+
73
+ This rule should be scoped to hook files using the ESLint `files` glob:
74
+
75
+ ```js
76
+ {
77
+ files: ["**/*.hook.ts", "**/*.hooks.ts"],
78
+ rules: {
79
+ "nextfriday/no-helper-function-in-hook": "error",
80
+ },
81
+ }
82
+ ```
83
+
84
+ ## Related Rules
85
+
86
+ - [enforce-hook-naming](./ENFORCE_HOOK_NAMING.md) — enforces the `use` prefix on all functions in hook files
@@ -0,0 +1,69 @@
1
+ # no-helper-function-in-test
2
+
3
+ Disallow helper function definitions in test files.
4
+
5
+ ## Rule Details
6
+
7
+ Test files should contain only pure test code — `describe`, `it`, `test`, `beforeEach`, and similar test runner constructs. Helper functions defined at the top level of a test file are utility code that belongs in a separate file and should be imported.
8
+
9
+ ### Why?
10
+
11
+ When helper functions are defined inside test files, they become invisible to other tests and are harder to maintain, test independently, and reuse. Keeping test files free of utility logic makes them easier to read and reason about.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ function findTemplateFiles(directory: string): string[] {
19
+ // ...
20
+ }
21
+
22
+ const extractImports = (source: string): string[] => {
23
+ // ...
24
+ };
25
+
26
+ describe("template imports", () => {
27
+ it("must only import from allowed paths", () => {
28
+ // ...
29
+ });
30
+ });
31
+ ```
32
+
33
+ ### Correct
34
+
35
+ ```ts
36
+ import { findTemplateFiles, extractImports } from "./test-utils";
37
+
38
+ describe("template imports", () => {
39
+ it("must only import from allowed paths", () => {
40
+ // ...
41
+ });
42
+ });
43
+ ```
44
+
45
+ ## What This Rule Checks
46
+
47
+ - Top-level `function` declarations
48
+ - Top-level `const`/`let`/`var` declarations assigned an arrow function or function expression
49
+
50
+ Constants that are not functions (regex patterns, arrays, objects) are allowed.
51
+
52
+ ## Exceptions
53
+
54
+ Functions declared inside `describe`, `it`, `test`, `beforeEach`, or other callback bodies are not flagged.
55
+
56
+ ## When Not To Use It
57
+
58
+ Disable this rule for files that are intentionally test utility modules (e.g., `test-utils.ts`, `helpers.ts`) rather than test suite files.
59
+
60
+ This rule should be scoped to test files using the ESLint `files` glob:
61
+
62
+ ```js
63
+ {
64
+ files: ["**/*.test.ts", "**/*.spec.ts", "**/*.test.tsx", "**/*.spec.tsx"],
65
+ rules: {
66
+ "nextfriday/no-helper-function-in-test": "error",
67
+ },
68
+ }
69
+ ```