eslint-plugin-nextfriday 1.20.0 → 1.21.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,18 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.21.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#87](https://github.com/next-friday/eslint-plugin-nextfriday/pull/87) [`ed401e3`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/ed401e39db04857995ddcc29d7444298181ee60b) Thanks [@joetakara](https://github.com/joetakara)! - Add `no-inline-return-properties` rule that enforces shorthand-only properties in return objects
8
+
9
+ - [#90](https://github.com/next-friday/eslint-plugin-nextfriday/pull/90) [`d5e9db5`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/d5e9db562cb9e38beadd59da39f8618b6f5825ed) Thanks [@joetakara](https://github.com/joetakara)! - Add comprehensive naming convention rules and fix prefer-import-type JSX prop bug
10
+ - Add `enforce-camel-case` rule: ban snake_case variables/functions, restrict PascalCase to React components
11
+ - Add `enforce-property-case` rule: enforce camelCase for unquoted object property keys
12
+ - Refactor `enforce-constant-case` to only check global scope, support RegExp/objects/arrays/as const
13
+ - Refactor `no-misleading-constant-case` to flag SCREAMING_SNAKE_CASE in local scope
14
+ - Fix `prefer-import-type` incorrectly converting imports used as JSX prop values to type imports
15
+
3
16
  ## 1.20.0
4
17
 
5
18
  ### Minor Changes
package/README.md CHANGED
@@ -155,8 +155,10 @@ export default [
155
155
  | [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md) | Disallow single character variable names (e.g., `d`, `u`, `l`) | ❌ |
156
156
  | [no-lazy-identifiers](docs/rules/NO_LAZY_IDENTIFIERS.md) | Disallow lazy identifiers like `xxx`, `asdf`, `qwerty` | ❌ |
157
157
  | [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md) | Enforce boolean variables to have prefix (is, has, should, can, etc.) | ❌ |
158
- | [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md) | Enforce SCREAMING_SNAKE_CASE for static constant primitive values | ❌ |
159
- | [no-misleading-constant-case](docs/rules/NO_MISLEADING_CONSTANT_CASE.md) | Disallow SCREAMING_SNAKE_CASE for non-constant or non-static values | ❌ |
158
+ | [enforce-camel-case](docs/rules/ENFORCE_CAMEL_CASE.md) | Ban snake_case and restrict PascalCase to React components | ❌ |
159
+ | [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md) | Enforce SCREAMING_SNAKE_CASE for global static constant values | ❌ |
160
+ | [enforce-property-case](docs/rules/ENFORCE_PROPERTY_CASE.md) | Enforce camelCase for unquoted object property keys | ❌ |
161
+ | [no-misleading-constant-case](docs/rules/NO_MISLEADING_CONSTANT_CASE.md) | Disallow SCREAMING_SNAKE_CASE in local scope and for dynamic values | ❌ |
160
162
 
161
163
  ### File Naming Rules
162
164
 
@@ -185,6 +187,7 @@ export default [
185
187
  | [newline-after-multiline-block](docs/rules/NEWLINE_AFTER_MULTILINE_BLOCK.md) | Require a blank line after multi-line statements | ✅ |
186
188
  | [newline-before-return](docs/rules/NEWLINE_BEFORE_RETURN.md) | Require a blank line before return statements | ✅ |
187
189
  | [no-inline-nested-object](docs/rules/NO_INLINE_NESTED_OBJECT.md) | Require nested objects and arrays to span multiple lines | ✅ |
190
+ | [no-inline-return-properties](docs/rules/NO_INLINE_RETURN_PROPERTIES.md) | Require return object properties to use shorthand notation | ❌ |
188
191
  | [prefer-async-await](docs/rules/PREFER_ASYNC_AWAIT.md) | Enforce async/await over .then() promise chains | ❌ |
189
192
  | [enforce-curly-newline](docs/rules/ENFORCE_CURLY_NEWLINE.md) | Enforce curly braces for multi-line if, forbid for single-line | ✅ |
190
193
  | [no-nested-ternary](docs/rules/NO_NESTED_TERNARY.md) | Disallow nested ternary expressions | ❌ |
@@ -0,0 +1,68 @@
1
+ # enforce-camel-case
2
+
3
+ Enforce camelCase for variables and functions, ban snake_case, and restrict PascalCase to React components.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces consistent naming conventions across your codebase:
8
+
9
+ - Variables and functions must use camelCase
10
+ - snake_case is banned for all variable and function declarations
11
+ - PascalCase is reserved exclusively for React components (functions that return JSX)
12
+
13
+ Global static constants are not checked by this rule. Use `enforce-constant-case` for those.
14
+
15
+ ### Why?
16
+
17
+ Consistent naming conventions reduce cognitive load. When PascalCase is reserved for components and camelCase is used for everything else, the name alone tells you what something is.
18
+
19
+ ## Examples
20
+
21
+ ### Incorrect
22
+
23
+ ```ts
24
+ // snake_case variables
25
+ let current_index = 0;
26
+ const first_name = "John";
27
+
28
+ // snake_case functions
29
+ function calculate_total() {
30
+ return 0;
31
+ }
32
+
33
+ // PascalCase for non-component functions
34
+ const CalculateTotal = () => 0;
35
+ const FormatDate = (date: string) => date;
36
+ ```
37
+
38
+ ### Correct
39
+
40
+ ```ts
41
+ // camelCase variables
42
+ let currentIndex = 0;
43
+ const firstName = "John";
44
+
45
+ // camelCase functions
46
+ function calculateTotal() { return 0; }
47
+ const formatDate = (date: string) => date;
48
+
49
+ // PascalCase for React components
50
+ const ArticleCard = () => <div />;
51
+ const WrappedComponent = memo(() => <div />);
52
+ const LazyPage = lazy(() => import("./Page"));
53
+ ```
54
+
55
+ ## Exceptions
56
+
57
+ - Global static constants (handled by `enforce-constant-case`)
58
+ - SCREAMING_SNAKE_CASE variables (handled by `no-misleading-constant-case`)
59
+ - React components wrapped with `memo`, `forwardRef`, or `lazy`
60
+
61
+ ## When Not To Use It
62
+
63
+ If your project does not follow the convention that PascalCase is reserved for React components.
64
+
65
+ ## Related Rules
66
+
67
+ - [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - Enforces SCREAMING_SNAKE_CASE for global static constants
68
+ - [no-misleading-constant-case](NO_MISLEADING_CONSTANT_CASE.md) - Disallows SCREAMING_SNAKE_CASE in local scope
@@ -1,10 +1,12 @@
1
1
  # enforce-constant-case
2
2
 
3
- Enforce SCREAMING_SNAKE_CASE for constant primitive values.
3
+ Enforce SCREAMING_SNAKE_CASE for global constant static values.
4
4
 
5
5
  ## Rule Details
6
6
 
7
- This rule ensures that `const` declarations with static primitive values (strings, numbers, booleans, static template literals) use SCREAMING_SNAKE_CASE naming convention. Template literals with expressions (e.g., `` `${variable}` ``) are considered dynamic and are not checked. Objects, arrays, and functions are not checked. Only `const` declarations are checked; `let` and `var` are ignored.
7
+ This rule ensures that global-scope `const` declarations with static values use SCREAMING_SNAKE_CASE naming convention. Static values include: string/number/boolean literals, RegExp, static template literals, `as const` assertions, and objects/arrays containing only literal values.
8
+
9
+ Only global scope (top-level of a file) is checked. Local scope constants inside functions are not checked by this rule.
8
10
 
9
11
  ## Examples
10
12
 
@@ -15,6 +17,9 @@ const defaultCover = "/images/default.jpg";
15
17
  const pageLimit = 10;
16
18
  const apiBaseUrl = "https://api.example.com";
17
19
  const template = `hello world`;
20
+ const phoneRegex = /^[0-9]{10}$/;
21
+ const default_theme = "dark";
22
+ export const categories = [{ id: "1" }] as const;
18
23
  ```
19
24
 
20
25
  ### Correct
@@ -24,27 +29,37 @@ const DEFAULT_COVER = "/images/default.jpg";
24
29
  const PAGE_LIMIT = 10;
25
30
  const API_BASE_URL = "https://api.example.com";
26
31
  const TEMPLATE = `hello world`;
32
+ const PHONE_REGEX = /^[0-9]{10}$/;
33
+ const DEFAULT_THEME = "dark";
34
+ export const CATEGORIES = [{ id: "1" }] as const;
35
+
36
+ const SKELETON_ITEMS = [1, 2, 3, 4, 5];
37
+ const MAP_STYLE = { height: "320px", width: "100%" };
38
+ const STATUS_MAP = { ACTIVE: "active" } as const;
27
39
 
28
- // Booleans with standard prefixes (is, has, should, can, etc.) are exempt
29
- const isEnabled = true;
40
+ // Booleans with standard prefixes (is, has, should, etc.) are exempt
41
+ const isProduction = true;
30
42
  const hasAccess = false;
31
- const shouldRender = true;
32
43
 
33
44
  // Template literals with expressions are dynamic, camelCase is fine
34
45
  const pendingHref = `/branch/${branch.branchNumber}`;
35
- const greeting = `Hello, ${user.name}!`;
36
46
 
37
- // Objects, arrays, and functions can use camelCase
38
- const config = { key: "value" };
39
- const items = [1, 2, 3];
47
+ // Functions and components are not checked
40
48
  const handleClick = () => {};
49
+ const MyComponent = () => {};
41
50
 
42
- // Let and var declarations are not checked
43
- let defaultCover = "/images/default.jpg";
44
- var pageLimit = 10;
51
+ // Local scope is not checked
52
+ function foo() {
53
+ const maxRetry = 3;
54
+ }
45
55
  ```
46
56
 
47
57
  ## When Not To Use It
48
58
 
49
59
  - If your project uses different naming conventions for constants
50
60
  - If you prefer camelCase for all variable declarations
61
+
62
+ ## Related Rules
63
+
64
+ - [no-misleading-constant-case](NO_MISLEADING_CONSTANT_CASE.md) - Disallows SCREAMING_SNAKE_CASE in local scope and for dynamic values
65
+ - [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions
@@ -0,0 +1,63 @@
1
+ # enforce-property-case
2
+
3
+ Enforce camelCase for unquoted object property keys.
4
+
5
+ ## Rule Details
6
+
7
+ This rule bans snake_case and SCREAMING_SNAKE_CASE for unquoted object property keys. Quoted keys (string literals) are allowed for API boundaries where external systems require different conventions.
8
+
9
+ ### Why?
10
+
11
+ Object properties should follow the same camelCase convention as variables. When an external API requires snake_case keys, wrapping them in quotes makes it explicit that the naming is intentional and driven by an external contract.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ const userPayload = {
19
+ first_name: "John",
20
+ last_name: "Doe",
21
+ };
22
+
23
+ const item = {
24
+ ITEM_ID: 1,
25
+ };
26
+ ```
27
+
28
+ ### Correct
29
+
30
+ ```ts
31
+ // camelCase properties
32
+ const userPayload = {
33
+ firstName: "John",
34
+ lastName: "Doe",
35
+ };
36
+
37
+ // Quoted keys for API boundaries
38
+ const apiPayload = {
39
+ first_name: "John",
40
+ last_name: "Doe",
41
+ };
42
+
43
+ // as const objects are exempt (enum-like pattern)
44
+ const STATUS_MAP = {
45
+ ACTIVE: "active",
46
+ INACTIVE: "inactive",
47
+ } as const;
48
+ ```
49
+
50
+ ## Exceptions
51
+
52
+ - Quoted property keys (`"first_name"`) are always allowed
53
+ - Computed property keys (`[key]`) are not checked
54
+ - Properties inside `as const` objects and arrays are exempt
55
+
56
+ ## When Not To Use It
57
+
58
+ If your project frequently uses snake_case or SCREAMING_SNAKE_CASE for object properties without quoting.
59
+
60
+ ## Related Rules
61
+
62
+ - [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions
63
+ - [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - Enforces SCREAMING_SNAKE_CASE for global constants
@@ -0,0 +1,83 @@
1
+ # no-inline-return-properties
2
+
3
+ Require return object properties to use shorthand notation by extracting non-shorthand values to const variables.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces that all properties in a returned object literal use shorthand notation. When a return statement contains an object with renamed or computed properties, the values should be extracted into const variables before the return statement.
8
+
9
+ ### Why?
10
+
11
+ Return objects with a mix of shorthand and non-shorthand properties are harder to scan. Extracting values into named constants before returning keeps the return statement clean and makes the data flow easier to follow.
12
+
13
+ ## Examples
14
+
15
+ ### Incorrect
16
+
17
+ ```ts
18
+ function useBranch() {
19
+ return {
20
+ admins,
21
+ branch,
22
+ coursesCurrentPage: coursePage,
23
+ coursesTotalPages: Math.ceil(sortedLearning.length / COURSES_PER_PAGE) || 1,
24
+ members,
25
+ membersHref: `/branch/${branchNumber}/members`,
26
+ news,
27
+ newsCurrentPage: newsData?.currentPage ?? 1,
28
+ newsTotalPages: newsData?.pages ?? 1,
29
+ stats,
30
+ };
31
+ }
32
+ ```
33
+
34
+ ```ts
35
+ function useJoin() {
36
+ return {
37
+ error,
38
+ isSubmitting,
39
+ onJoin: handleJoin,
40
+ };
41
+ }
42
+ ```
43
+
44
+ ### Correct
45
+
46
+ ```ts
47
+ function useBranch() {
48
+ const coursesCurrentPage = coursePage;
49
+ const coursesTotalPages = Math.ceil(sortedLearning.length / COURSES_PER_PAGE) || 1;
50
+ const membersHref = `/branch/${branchNumber}/members`;
51
+ const newsCurrentPage = newsData?.currentPage ?? 1;
52
+ const newsTotalPages = newsData?.pages ?? 1;
53
+
54
+ return {
55
+ admins,
56
+ branch,
57
+ coursesCurrentPage,
58
+ coursesTotalPages,
59
+ members,
60
+ membersHref,
61
+ news,
62
+ newsCurrentPage,
63
+ newsTotalPages,
64
+ stats,
65
+ };
66
+ }
67
+ ```
68
+
69
+ ```ts
70
+ function useJoin() {
71
+ const onJoin = handleJoin;
72
+
73
+ return {
74
+ error,
75
+ isSubmitting,
76
+ onJoin,
77
+ };
78
+ }
79
+ ```
80
+
81
+ ## When Not To Use It
82
+
83
+ If your project prefers inline property values in return statements for brevity.
@@ -4,47 +4,62 @@ Disallow SCREAMING_SNAKE_CASE for non-constant or non-static values.
4
4
 
5
5
  ## Rule Details
6
6
 
7
- SCREAMING_SNAKE_CASE conventionally signals a compile-time constant with a static, immutable value. Using it for mutable bindings (`let`/`var`) or dynamic values (function calls, objects, arrays, computed expressions) is misleading because the name implies immutability that the value does not have.
7
+ SCREAMING_SNAKE_CASE is reserved for global static constants. This rule flags it when used incorrectly:
8
+
9
+ - **Mutable bindings**: `let` or `var` with SCREAMING_SNAKE_CASE
10
+ - **Dynamic values**: `const` with function calls, await, dynamic templates, objects with dynamic values
11
+ - **Local scope**: SCREAMING_SNAKE_CASE inside functions, even for static values
8
12
 
9
13
  ### Why?
10
14
 
11
- When reading `const API_URL = getUrl()`, the SCREAMING_SNAKE_CASE name suggests a hardcoded value, but it is actually computed at runtime. This mismatch makes code harder to reason about. Reserving SCREAMING_SNAKE_CASE for true static primitives keeps the convention meaningful.
15
+ SCREAMING_SNAKE_CASE signals a compile-time constant at the module level. Using it for local variables or dynamic values is misleading. Local constants should use camelCase regardless of whether the value is static.
12
16
 
13
17
  ## Examples
14
18
 
15
19
  ### Incorrect
16
20
 
17
21
  ```ts
18
- // Mutable bindings should not use SCREAMING_SNAKE_CASE
22
+ // Mutable bindings
19
23
  let API_URL = "https://api.example.com";
20
24
  var MAX_COUNT = 10;
21
25
 
22
- // Dynamic or computed values should use camelCase
26
+ // Dynamic values at global scope
23
27
  const API_URL = getUrl();
24
28
  const USER_ID = await fetchId();
25
29
  const PATHNAME = `/news/${slug}`;
26
- const CONFIG = { key: "value" };
27
- const ITEMS = [1, 2, 3];
28
- const RESULT = a + b;
29
- const ACTIVE_USERS = users.filter((u) => u.active);
30
+ const CONFIG = { key: getValue() };
31
+
32
+ // SCREAMING_SNAKE_CASE in local scope (even static values)
33
+ function foo() {
34
+ const MAX_RETRY = 3;
35
+ const TOTAL_COUNT = items.length;
36
+ }
37
+
38
+ const MyComponent = () => {
39
+ const ACTIVE_ITEMS = ITEMS.filter((i) => i.active);
40
+ };
30
41
  ```
31
42
 
32
43
  ### Correct
33
44
 
34
45
  ```ts
35
- // Static primitive constants use SCREAMING_SNAKE_CASE
46
+ // Global static constants use SCREAMING_SNAKE_CASE
36
47
  const API_URL = "https://api.example.com";
37
48
  const MAX_COUNT = 10;
38
- const IS_PRODUCTION = true;
39
- const TEMPLATE = `hello world`;
49
+ const ITEMS = [1, 2, 3];
50
+ const CONFIG = { key: "value" };
51
+ const VARIANTS = ["a", "b"] as const;
40
52
 
41
- // Dynamic or computed values use camelCase
53
+ // Dynamic values use camelCase
42
54
  const apiUrl = getUrl();
43
55
  const userId = await fetchId();
44
56
  const pathname = `/news/${slug}`;
45
- const config = { key: "value" };
46
- const items = [1, 2, 3];
47
- const result = a + b;
57
+
58
+ // Local scope uses camelCase
59
+ function foo() {
60
+ const maxRetry = 3;
61
+ const totalCount = items.length;
62
+ }
48
63
 
49
64
  // Mutable bindings use camelCase
50
65
  let count = 10;
@@ -53,8 +68,9 @@ var name = "foo";
53
68
 
54
69
  ## When Not To Use It
55
70
 
56
- If your project does not follow the convention that SCREAMING_SNAKE_CASE is reserved for static primitive constants.
71
+ If your project does not follow the convention that SCREAMING_SNAKE_CASE is reserved for global static constants.
57
72
 
58
73
  ## Related Rules
59
74
 
60
- - [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - The complementary rule that enforces SCREAMING_SNAKE_CASE for static primitive constants
75
+ - [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - The complementary rule that enforces SCREAMING_SNAKE_CASE for global static constants
76
+ - [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions