eslint-plugin-nextfriday 1.10.2 → 1.11.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,36 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#53](https://github.com/next-friday/eslint-plugin-nextfriday/pull/53) [`732db65`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/732db659671cb6363b40af16c9c40400a10225ab) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - feat(no-inline-default-export): extend rule to also flag inline named exports
8
+
9
+ The `no-inline-default-export` rule now also flags inline named exports like `export function xxx()` and `export class Xxx`. These should be declared first, then exported separately using `export { xxx };`.
10
+
11
+ ### New behavior
12
+
13
+ **Incorrect:**
14
+
15
+ ```typescript
16
+ export function fetchData() { ... }
17
+ export async function fetchHighlight() { ... }
18
+ export class UserService { ... }
19
+ ```
20
+
21
+ **Correct:**
22
+
23
+ ```typescript
24
+ function fetchData() { ... }
25
+ export { fetchData };
26
+
27
+ async function fetchHighlight() { ... }
28
+ export default fetchHighlight;
29
+
30
+ class UserService { ... }
31
+ export { UserService };
32
+ ```
33
+
3
34
  ## 1.10.2
4
35
 
5
36
  ### Patch Changes
@@ -34,16 +34,20 @@ The content of the file doesn't matter - only the filename is checked:
34
34
 
35
35
  ```typescript
36
36
  // INCORRECT: File: MyFile.ts (incorrect filename)
37
- export const myFunction = () => {
37
+ function myFunction() {
38
38
  return "Hello World";
39
- };
39
+ }
40
+
41
+ export { myFunction };
40
42
  ```
41
43
 
42
44
  ```typescript
43
45
  // CORRECT: File: my-file.ts (correct filename)
44
- export const myFunction = () => {
46
+ function myFunction() {
45
47
  return "Hello World";
46
- };
48
+ }
49
+
50
+ export { myFunction };
47
51
  ```
48
52
 
49
53
  ```javascript
@@ -53,6 +57,8 @@ class UserService {
53
57
  return {};
54
58
  }
55
59
  }
60
+
61
+ export { UserService };
56
62
  ```
57
63
 
58
64
  ```javascript
@@ -62,6 +68,8 @@ class UserService {
62
68
  return {};
63
69
  }
64
70
  }
71
+
72
+ export { UserService };
65
73
  ```
66
74
 
67
75
  ## When Not To Use It
@@ -55,9 +55,11 @@ const calculateTotal = (items: number[]) => {
55
55
  return items.reduce((sum, item) => sum + item, 0);
56
56
  };
57
57
 
58
- export const OrderSummary = () => {
58
+ const OrderSummary = () => {
59
59
  return <div>Total</div>;
60
60
  };
61
+
62
+ export { OrderSummary };
61
63
  ```
62
64
 
63
65
  ### ✅ Correct
@@ -89,19 +91,23 @@ const Component = () => {
89
91
  };
90
92
  ```
91
93
 
92
- ```tsx
94
+ ```typescript
93
95
  // Good: Functions in .ts or .js files are allowed
94
96
  // utils.ts
95
- export const helper = (name: string) => {
97
+ function helper(name: string) {
96
98
  return name.toUpperCase();
97
- };
99
+ }
100
+
101
+ export { helper };
98
102
  ```
99
103
 
100
104
  ```tsx
101
105
  // Good: Exported component functions are allowed
102
- export const Component = () => {
106
+ const Component = () => {
103
107
  return <div>Hello</div>;
104
108
  };
109
+
110
+ export { Component };
105
111
  ```
106
112
 
107
113
  ## When Not To Use It
@@ -34,30 +34,38 @@ The content of the file doesn't matter - only the filename is checked:
34
34
 
35
35
  ```jsx
36
36
  // INCORRECT: File: my-component.jsx (incorrect filename)
37
- export default function MyComponent() {
37
+ function MyComponent() {
38
38
  return <div>Hello</div>;
39
39
  }
40
+
41
+ export default MyComponent;
40
42
  ```
41
43
 
42
44
  ```jsx
43
45
  // CORRECT: File: MyComponent.jsx (correct filename)
44
- export default function MyComponent() {
46
+ function MyComponent() {
45
47
  return <div>Hello</div>;
46
48
  }
49
+
50
+ export default MyComponent;
47
51
  ```
48
52
 
49
53
  ```tsx
50
54
  // INCORRECT: File: user-profile.tsx (incorrect filename)
51
- export default function UserProfile() {
55
+ function UserProfile() {
52
56
  return <div>Profile</div>;
53
57
  }
58
+
59
+ export default UserProfile;
54
60
  ```
55
61
 
56
62
  ```tsx
57
63
  // CORRECT: File: UserProfile.tsx (correct filename)
58
- export default function UserProfile() {
64
+ function UserProfile() {
59
65
  return <div>Profile</div>;
60
66
  }
67
+
68
+ export default UserProfile;
61
69
  ```
62
70
 
63
71
  ## When Not To Use
@@ -1,78 +1,101 @@
1
1
  # no-inline-default-export
2
2
 
3
- Disallow inline default exports. Prefer declaring first, then exporting separately.
3
+ Disallow inline exports. Declare first, then export separately.
4
4
 
5
5
  ## Rule Details
6
6
 
7
- This rule enforces separating function/class declarations from their default exports. Instead of combining declaration and export in a single statement, declare the function or class first, then export it by reference.
7
+ This rule enforces separating declarations from exports. Instead of `export function`, declare the function first, then export it.
8
8
 
9
- This pattern improves code readability and makes it easier to identify what a module exports at a glance.
9
+ **Incorrect** code for this rule:
10
10
 
11
- ## Examples
11
+ ```typescript
12
+ // Inline named export
13
+ export function fetchData() {
14
+ return fetch("/api");
15
+ }
12
16
 
13
- ### Incorrect
17
+ // Inline async named export
18
+ export async function fetchHighlight(id: string) {
19
+ return await api.get(`/highlights/${id}`);
20
+ }
14
21
 
15
- ```typescript
16
- // Inline function default export
17
- export default function generator(plop: PlopTypes.NodePlopAPI): void {
22
+ // Inline class export
23
+ export class UserService {
24
+ // ...
25
+ }
26
+
27
+ // Inline default export
28
+ export default function generator() {
18
29
  // ...
19
30
  }
20
31
 
21
- // Inline class default export
32
+ // Inline default class export
22
33
  export default class MyService {
23
34
  // ...
24
35
  }
25
36
 
26
- // Anonymous function default export
37
+ // Anonymous exports
27
38
  export default function () {
28
39
  return "anonymous";
29
40
  }
30
41
 
31
- // Arrow function default export
32
42
  export default () => "arrow";
33
-
34
- // Anonymous class default export
35
- export default class {
36
- // ...
37
- }
38
43
  ```
39
44
 
40
- ### Correct
45
+ **Correct** code for this rule:
41
46
 
42
47
  ```typescript
43
- // Separate function declaration and export
44
- function generator(plop: PlopTypes.NodePlopAPI): void {
45
- // ...
48
+ // Declare function, then export
49
+ function fetchData() {
50
+ return fetch("/api");
46
51
  }
47
52
 
48
- export default generator;
53
+ export { fetchData };
49
54
 
50
- // Separate class declaration and export
51
- class MyService {
55
+ // Declare async function, then export
56
+ async function fetchHighlight(id: string) {
57
+ return await api.get(`/highlights/${id}`);
58
+ }
59
+
60
+ export { fetchHighlight };
61
+
62
+ // Or use default export
63
+ export default fetchHighlight;
64
+
65
+ // Declare class, then export
66
+ class UserService {
52
67
  // ...
53
68
  }
54
69
 
55
- export default MyService;
70
+ export { UserService };
56
71
 
57
- // Separate const arrow function and export
58
- const processData = (data: Data): Result => {
72
+ // Declare function, then default export
73
+ function generator() {
59
74
  // ...
60
- };
75
+ }
76
+
77
+ export default generator;
61
78
 
62
- export default processData;
79
+ // Re-exports are allowed
80
+ export { foo } from "./foo";
81
+ export { bar as default } from "./bar";
82
+ export type { Baz } from "./baz";
63
83
 
64
- // Exporting literals and objects is allowed
84
+ // Literals and objects are allowed
65
85
  export default "literal";
66
86
  export default { key: "value" };
67
-
68
- // Re-exports are allowed
69
- export { foo as default } from "./foo";
70
87
  ```
71
88
 
89
+ ## Benefits
90
+
91
+ - **Readability**: Easy to see what a module exports at a glance
92
+ - **Consistency**: All exports follow the same pattern
93
+ - **Refactoring**: Easier to rename or move declarations
94
+
72
95
  ## When Not To Use
73
96
 
74
- If your project prefers inline default exports for brevity, or if you're working with frameworks that expect specific export patterns, you may want to disable this rule.
97
+ If your project prefers inline exports for brevity, you may want to disable this rule.
75
98
 
76
99
  ## Related Rules
77
100
 
78
- - [prefer-function-declaration](./PREFER_FUNCTION_DECLARATION.md) - Prefer function declarations over expressions
101
+ - [prefer-function-declaration](./PREFER_FUNCTION_DECLARATION.md) - Prefer function declarations over arrow functions
@@ -1,29 +1,30 @@
1
1
  # prefer-function-declaration
2
2
 
3
- Enforce function declarations over arrow functions assigned to variables in `.ts` files for better readability and hoisting.
3
+ Enforce function declarations over arrow functions assigned to variables in `.ts` files.
4
4
 
5
5
  ## Rule Details
6
6
 
7
- This rule requires using function declarations instead of arrow functions or function expressions when defining named functions in TypeScript utility files. Arrow functions used as callbacks (in `.map()`, `.filter()`, etc.) are still allowed.
7
+ This rule requires using function declarations instead of arrow functions or function expressions when defining named functions. Arrow functions used as callbacks are still allowed.
8
8
 
9
9
  **Target:** `.ts` files only (not `.tsx`, `.js`, or `.d.ts`)
10
10
 
11
11
  **Incorrect** code for this rule:
12
12
 
13
13
  ```typescript
14
- // utils/date.ts
15
- const formatThaiDate = (date: Date) => {
14
+ // Arrow function assigned to variable
15
+ const formatDate = (date: Date) => {
16
16
  return date.toLocaleDateString("th-TH");
17
17
  };
18
18
 
19
- const formatDate = (date: Date) => date.toISOString();
20
-
21
- export const add = (a: number, b: number) => a + b;
19
+ // Arrow function with implicit return
20
+ const add = (a: number, b: number) => a + b;
22
21
 
22
+ // Function expression assigned to variable
23
23
  const greet = function (name: string) {
24
24
  return `Hello ${name}`;
25
25
  };
26
26
 
27
+ // Async arrow function
27
28
  const fetchUser = async (id: string) => {
28
29
  return await api.get(`/users/${id}`);
29
30
  };
@@ -32,23 +33,22 @@ const fetchUser = async (id: string) => {
32
33
  **Correct** code for this rule:
33
34
 
34
35
  ```typescript
35
- // utils/date.ts
36
- function formatThaiDate(date: Date) {
37
- return date.toLocaleDateString("th-TH");
38
- }
39
-
36
+ // Function declaration
40
37
  function formatDate(date: Date) {
41
- return date.toISOString();
38
+ return date.toLocaleDateString("th-TH");
42
39
  }
43
40
 
44
- export function add(a: number, b: number) {
41
+ // Function declaration
42
+ function add(a: number, b: number) {
45
43
  return a + b;
46
44
  }
47
45
 
46
+ // Function declaration
48
47
  function greet(name: string) {
49
48
  return `Hello ${name}`;
50
49
  }
51
50
 
51
+ // Async function declaration
52
52
  async function fetchUser(id: string) {
53
53
  return await api.get(`/users/${id}`);
54
54
  }
@@ -61,14 +61,11 @@ Arrow functions are still allowed in the following contexts:
61
61
  ### Callbacks
62
62
 
63
63
  ```typescript
64
- // All of these are allowed
65
64
  const years = dates.map((date) => date.getFullYear());
66
65
  const active = items.filter((item) => item.active);
67
66
  const sorted = items.sort((a, b) => a.name.localeCompare(b.name));
68
67
  items.forEach((item) => console.log(item));
69
- const total = items.reduce((sum, item) => sum + item.price, 0);
70
68
  setTimeout(() => console.log("done"), 1000);
71
- promise.then((result) => result.data);
72
69
  ```
73
70
 
74
71
  ### Object Properties
@@ -106,20 +103,18 @@ const handler = defaultFn || (() => fallback);
106
103
  ```typescript
107
104
  // components/Button.tsx - Arrow functions allowed
108
105
  const Button = () => <button>Click me</button>;
109
- const handleClick = () => console.log("clicked");
110
106
  ```
111
107
 
112
108
  ## Benefits
113
109
 
114
- - **Hoisting**: Function declarations are hoisted, allowing you to call functions before they're defined
115
- - **Better readability**: Function declarations are more explicit about intent
116
- - **Clearer stack traces**: Named function declarations provide better debugging information
117
- - **Consistent style**: Enforces uniform function definition patterns in utility files
110
+ - **Hoisting**: Function declarations are hoisted
111
+ - **Better readability**: Function declarations are more explicit
112
+ - **Clearer stack traces**: Named function declarations provide better debugging
118
113
  - **Self-documenting**: `function formatDate()` is clearer than `const formatDate = () =>`
119
114
 
120
115
  ## Why Only `.ts` Files?
121
116
 
122
- - **`.tsx` files**: Arrow functions are commonly used for React components and event handlers
117
+ - **`.tsx` files**: Arrow functions are commonly used for React components
123
118
  - **`.js` files**: JavaScript projects may have different conventions
124
119
  - **`.d.ts` files**: Declaration files don't contain implementations
125
120
 
@@ -127,13 +122,8 @@ const handleClick = () => console.log("clicked");
127
122
 
128
123
  - When you prefer arrow functions for all function definitions
129
124
  - In projects where arrow function style is established
130
- - When you need lexical `this` binding (arrow functions don't have their own `this`)
131
-
132
- ## Configuration
133
-
134
- This rule has no configuration options.
125
+ - When you need lexical `this` binding
135
126
 
136
127
  ## Related Rules
137
128
 
138
- - [func-style](https://eslint.org/docs/rules/func-style) - Built-in ESLint rule for function style
139
- - [arrow-body-style](https://eslint.org/docs/rules/arrow-body-style) - Enforce arrow function body style
129
+ - [no-inline-default-export](./NO_INLINE_DEFAULT_EXPORT.md) - Disallow inline exports
@@ -13,23 +13,23 @@ function getName() {
13
13
  return "John Doe";
14
14
  }
15
15
 
16
- const getAge = () => {
16
+ function getAge() {
17
17
  return 25;
18
- };
18
+ }
19
19
 
20
20
  function processUser() {
21
21
  console.log("Processing user");
22
22
  }
23
23
 
24
- const calculateTotal = (items: Item[]) => {
24
+ function calculateTotal(items: Item[]) {
25
25
  return items.reduce((sum, item) => sum + item.price, 0);
26
- };
26
+ }
27
27
 
28
28
  async function fetchData() {
29
29
  return await api.get("/data");
30
30
  }
31
31
 
32
- export function validateEmail(email: string) {
32
+ function validateEmail(email: string) {
33
33
  return email.includes("@");
34
34
  }
35
35
  ```
@@ -41,23 +41,23 @@ function getName(): string {
41
41
  return "John Doe";
42
42
  }
43
43
 
44
- const getAge = (): number => {
44
+ function getAge(): number {
45
45
  return 25;
46
- };
46
+ }
47
47
 
48
48
  function processUser(): void {
49
49
  console.log("Processing user");
50
50
  }
51
51
 
52
- const calculateTotal = (items: Item[]): number => {
52
+ function calculateTotal(items: Item[]): number {
53
53
  return items.reduce((sum, item) => sum + item.price, 0);
54
- };
54
+ }
55
55
 
56
56
  async function fetchData(): Promise<Data> {
57
57
  return await api.get("/data");
58
58
  }
59
59
 
60
- export function validateEmail(email: string): boolean {
60
+ function validateEmail(email: string): boolean {
61
61
  return email.includes("@");
62
62
  }
63
63
  ```
package/lib/index.cjs CHANGED
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(index_exports);
40
40
  // package.json
41
41
  var package_default = {
42
42
  name: "eslint-plugin-nextfriday",
43
- version: "1.10.2",
43
+ version: "1.11.0",
44
44
  description: "A comprehensive ESLint plugin providing custom rules and configurations for Next Friday development workflows.",
45
45
  keywords: [
46
46
  "eslint",
@@ -979,11 +979,12 @@ var noInlineDefaultExport = createRule13({
979
979
  meta: {
980
980
  type: "suggestion",
981
981
  docs: {
982
- description: "Disallow inline default exports. Prefer declaring first, then exporting separately."
982
+ description: "Disallow inline exports. Prefer declaring first, then exporting separately."
983
983
  },
984
984
  messages: {
985
985
  noInlineDefaultExport: "Avoid inline default export. Declare the {{type}} first, then export it separately: `export default {{name}};`",
986
- noAnonymousDefaultExport: "Avoid anonymous default export. Declare a named {{type}} first, then export it separately."
986
+ noAnonymousDefaultExport: "Avoid anonymous default export. Declare a named {{type}} first, then export it separately.",
987
+ noInlineNamedExport: "Avoid inline named export. Declare the {{type}} first, then export it separately: `export { {{name}} };`"
987
988
  },
988
989
  schema: []
989
990
  },
@@ -1029,6 +1030,26 @@ var noInlineDefaultExport = createRule13({
1029
1030
  data: { type: "function" }
1030
1031
  });
1031
1032
  }
1033
+ },
1034
+ ExportNamedDeclaration(node) {
1035
+ const { declaration } = node;
1036
+ if (!declaration) {
1037
+ return;
1038
+ }
1039
+ if (declaration.type === import_utils13.AST_NODE_TYPES.FunctionDeclaration && declaration.id) {
1040
+ context.report({
1041
+ node,
1042
+ messageId: "noInlineNamedExport",
1043
+ data: { type: "function", name: declaration.id.name }
1044
+ });
1045
+ }
1046
+ if (declaration.type === import_utils13.AST_NODE_TYPES.ClassDeclaration && declaration.id) {
1047
+ context.report({
1048
+ node,
1049
+ messageId: "noInlineNamedExport",
1050
+ data: { type: "class", name: declaration.id.name }
1051
+ });
1052
+ }
1032
1053
  }
1033
1054
  };
1034
1055
  }