eslint-plugin-code-style 1.9.2 → 1.9.4

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/index.js +72 -18
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.9.4] - 2026-02-03
11
+
12
+ ### Enhanced
13
+
14
+ - **`no-hardcoded-strings`** - Skip UI component patterns only in JSX attributes:
15
+ - In JSX attributes: `<Button variant="ghost" />` is now ignored
16
+ - In logic: `const status = "success"` or `setValue("primary")` is still detected
17
+ - UI patterns: `primary`, `secondary`, `ghost`, `outline`, `link`, `muted`, `danger`, `warning`, `success`, `error`, `sm`, `md`, `lg`, `xl`, `left`, `right`, `center`, `top`, `bottom`, `hover`, `focus`, `click`, etc.
18
+
19
+ ---
20
+
21
+ ## [1.9.3] - 2026-02-03
22
+
23
+ ### Enhanced
24
+
25
+ - **`no-hardcoded-strings`** - Remove single-word string length limitations and add more special cases:
26
+ - Removed length restrictions (now detects all single-word hardcoded strings)
27
+ - Added validation strings: `empty`, `invalid`, `missing`, `optional`, `required`, `valid`
28
+ - Added auth state strings: `anonymous`, `authenticated`, `authed`, `authorized`, `denied`, `forbidden`, `granted`, `locked`, `loggedin`, `loggedout`, `revoked`, `unauthenticated`, `unauthorized`, `unlocked`, `unverified`, `verified`
29
+ - Added more status strings: `done`, `finished`, `inprogress`, `queued`, `ready`, `running`, `started`, `stopped`, `successful`, `waiting`
30
+ - Made technical patterns stricter to avoid false negatives (camelCase requires uppercase in middle, snake_case requires underscore, kebab-case requires hyphen)
31
+
32
+ ---
33
+
10
34
  ## [1.9.2] - 2026-02-03
11
35
 
12
36
  ### Enhanced
@@ -1275,6 +1299,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1275
1299
 
1276
1300
  ---
1277
1301
 
1302
+ [1.9.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.3...v1.9.4
1303
+ [1.9.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.2...v1.9.3
1278
1304
  [1.9.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.1...v1.9.2
1279
1305
  [1.9.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.0...v1.9.1
1280
1306
  [1.9.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.4...v1.9.0
package/index.js CHANGED
@@ -14055,20 +14055,21 @@ const noHardcodedStrings = {
14055
14055
  /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?/,
14056
14056
  // Time formats
14057
14057
  /^\d{1,2}:\d{2}(:\d{2})?(\s?(AM|PM|am|pm))?$/,
14058
- // JSON keys (camelCase, snake_case, SCREAMING_SNAKE_CASE)
14059
- /^[a-z][a-zA-Z0-9]*$/,
14060
- /^[a-z][a-z0-9_]*$/,
14061
- /^[A-Z][A-Z0-9_]*$/,
14058
+ // JSON keys - require actual naming convention markers (underscore/uppercase in middle)
14059
+ // camelCase: must have uppercase letter in middle (e.g., userId, firstName)
14060
+ /^[a-z]+[A-Z][a-zA-Z0-9]*$/,
14061
+ // snake_case: must have underscore (e.g., user_id, first_name)
14062
+ /^[a-z][a-z0-9]*_[a-z0-9_]*$/,
14063
+ // SCREAMING_SNAKE_CASE: must have underscore (e.g., MAX_VALUE, API_URL)
14064
+ /^[A-Z][A-Z0-9]*_[A-Z0-9_]+$/,
14062
14065
  // Common technical strings
14063
14066
  /^(true|false|null|undefined|NaN|Infinity)$/,
14064
14067
  // Content types
14065
14068
  /^application\//,
14066
- // Environment variables pattern
14067
- /^[A-Z][A-Z0-9_]*$/,
14068
14069
  // Query parameters
14069
14070
  /^[a-z][a-zA-Z0-9_]*=/,
14070
- // CSS property-like
14071
- /^[a-z]+(-[a-z]+)*$/,
14071
+ // CSS property-like (kebab-case): must have hyphen (e.g., font-size, background-color)
14072
+ /^[a-z]+-[a-z]+(-[a-z]+)*$/,
14072
14073
  // Numbers with separators
14073
14074
  /^[\d,._]+$/,
14074
14075
  // Semantic version
@@ -14089,6 +14090,9 @@ const noHardcodedStrings = {
14089
14090
 
14090
14091
  const allIgnorePatterns = [...technicalPatterns, ...extraIgnorePatterns];
14091
14092
 
14093
+ // UI component patterns - only ignored in JSX attributes, not in logic
14094
+ const uiComponentPattern = /^(primary|secondary|tertiary|ghost|outline|link|muted|danger|warning|info|success|error|default|subtle|solid|soft|plain|flat|elevated|filled|tonal|text|contained|standard|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|xxs|xxl|small|medium|large|tiny|huge|compact|comfortable|spacious|left|right|center|top|bottom|start|end|middle|baseline|stretch|between|around|evenly|horizontal|vertical|row|column|inline|block|flex|grid|auto|none|hidden|visible|static|relative|absolute|fixed|sticky|on|off|hover|focus|click|blur|always|never)$/;
14095
+
14092
14096
  // HTTP status codes that should NOT be hardcoded (2xx, 4xx, and 5xx)
14093
14097
  const httpStatusCodePattern = /^[245]\d{2}$/;
14094
14098
 
@@ -14164,23 +14168,64 @@ const noHardcodedStrings = {
14164
14168
  "declined",
14165
14169
  "deleted",
14166
14170
  "disabled",
14171
+ "done",
14167
14172
  "draft",
14168
14173
  "enabled",
14169
14174
  "expired",
14170
14175
  "failed",
14176
+ "finished",
14171
14177
  "inactive",
14178
+ "inprogress",
14172
14179
  "open",
14173
14180
  "paused",
14174
14181
  "pending",
14175
14182
  "processing",
14176
14183
  "published",
14184
+ "queued",
14185
+ "ready",
14177
14186
  "rejected",
14178
14187
  "resolved",
14188
+ "running",
14179
14189
  "scheduled",
14190
+ "started",
14191
+ "stopped",
14180
14192
  "submitted",
14181
14193
  "success",
14194
+ "successful",
14182
14195
  "suspended",
14183
14196
  "verified",
14197
+ "waiting",
14198
+ ]);
14199
+
14200
+ // Validation/form strings that should be imported from enums/data
14201
+ const validationStrings = new Set([
14202
+ "empty",
14203
+ "invalid",
14204
+ "missing",
14205
+ "optional",
14206
+ "required",
14207
+ "valid",
14208
+ ]);
14209
+
14210
+ // Auth/permission state strings that should be imported from enums/data
14211
+ const authStrings = new Set([
14212
+ "anonymous",
14213
+ "authenticated",
14214
+ "authed",
14215
+ "authorized",
14216
+ "denied",
14217
+ "expired",
14218
+ "forbidden",
14219
+ "granted",
14220
+ "locked",
14221
+ "loggedin",
14222
+ "loggedout",
14223
+ "revoked",
14224
+ "unauthenticated",
14225
+ "unauthorized",
14226
+ "unlocked",
14227
+ "unverified",
14228
+ "verified",
14184
14229
  ]);
14185
14230
 
14186
14231
  // Priority levels that should be imported from enums/data
@@ -14203,6 +14248,8 @@ const noHardcodedStrings = {
14203
14248
  const isLogLevelHandler = (str) => logLevels.has(str.toLowerCase());
14204
14249
  const isStatusStringHandler = (str) => statusStrings.has(str.toLowerCase());
14205
14250
  const isPriorityLevelHandler = (str) => priorityLevels.has(str.toLowerCase());
14251
+ const isValidationStringHandler = (str) => validationStrings.has(str.toLowerCase());
14252
+ const isAuthStringHandler = (str) => authStrings.has(str.toLowerCase());
14206
14253
 
14207
14254
  // Check if string should be flagged even if it matches technical patterns
14208
14255
  const isFlaggedSpecialStringHandler = (str) => isHttpStatusCodeHandler(str)
@@ -14211,7 +14258,9 @@ const noHardcodedStrings = {
14211
14258
  || isEnvironmentNameHandler(str)
14212
14259
  || isLogLevelHandler(str)
14213
14260
  || isStatusStringHandler(str)
14214
- || isPriorityLevelHandler(str);
14261
+ || isPriorityLevelHandler(str)
14262
+ || isValidationStringHandler(str)
14263
+ || isAuthStringHandler(str);
14215
14264
 
14216
14265
  // Get descriptive error message based on string type
14217
14266
  const getErrorMessageHandler = (str, context = "") => {
@@ -14246,6 +14295,14 @@ const noHardcodedStrings = {
14246
14295
  return `Hardcoded priority level "${truncatedStr}"${contextPart} should be imported from @/enums or @/data`;
14247
14296
  }
14248
14297
 
14298
+ if (isValidationStringHandler(str)) {
14299
+ return `Hardcoded validation string "${truncatedStr}"${contextPart} should be imported from @/enums or @/data`;
14300
+ }
14301
+
14302
+ if (isAuthStringHandler(str)) {
14303
+ return `Hardcoded auth state "${truncatedStr}"${contextPart} should be imported from @/enums or @/data`;
14304
+ }
14305
+
14249
14306
  return `Hardcoded string "${truncatedStr}"${contextPart} should be imported from @/data or @/strings or @/constants or @/@constants or @/@strings`;
14250
14307
  };
14251
14308
 
@@ -14491,6 +14548,9 @@ const noHardcodedStrings = {
14491
14548
  if (node.value.type === "Literal" && typeof node.value.value === "string") {
14492
14549
  const str = node.value.value;
14493
14550
 
14551
+ // Skip UI component patterns in JSX attributes (variant, size, position props)
14552
+ if (uiComponentPattern.test(str)) return;
14553
+
14494
14554
  // Check if it's a flagged special string (status code, role name)
14495
14555
  const isSpecialString = isFlaggedSpecialStringHandler(str);
14496
14556
 
@@ -14499,9 +14559,6 @@ const noHardcodedStrings = {
14499
14559
  // Check if it looks like user-facing text - skip for special strings
14500
14560
  if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14501
14561
 
14502
- // Require multiple words or reasonable length for non-special strings
14503
- if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 10) return;
14504
-
14505
14562
  context.report({
14506
14563
  message: getErrorMessageHandler(str, `attribute "${attrName}"`),
14507
14564
  node: node.value,
@@ -14518,6 +14575,9 @@ const noHardcodedStrings = {
14518
14575
  if (expression.type === "Literal" && typeof expression.value === "string") {
14519
14576
  const str = expression.value;
14520
14577
 
14578
+ // Skip UI component patterns in JSX attributes (variant, size, position props)
14579
+ if (uiComponentPattern.test(str)) return;
14580
+
14521
14581
  // Check if it's a flagged special string (status code, role name)
14522
14582
  const isSpecialString = isFlaggedSpecialStringHandler(str);
14523
14583
 
@@ -14525,9 +14585,6 @@ const noHardcodedStrings = {
14525
14585
 
14526
14586
  if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14527
14587
 
14528
- // Require multiple words or reasonable length for non-special strings
14529
- if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 10) return;
14530
-
14531
14588
  context.report({
14532
14589
  message: getErrorMessageHandler(str, `attribute "${attrName}"`),
14533
14590
  node: expression,
@@ -14567,9 +14624,6 @@ const noHardcodedStrings = {
14567
14624
  // Skip if it doesn't look like user-facing text - but not for special strings
14568
14625
  if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14569
14626
 
14570
- // Require at least 2 words or be reasonably long - but not for special strings
14571
- if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 15) return;
14572
-
14573
14627
  context.report({
14574
14628
  message: getErrorMessageHandler(str),
14575
14629
  node,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-code-style",
3
- "version": "1.9.2",
3
+ "version": "1.9.4",
4
4
  "description": "A custom ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",