eslint-plugin-code-style 1.9.5 → 1.9.7

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 +30 -1
  2. package/index.js +79 -0
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,12 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.9.7] - 2026-02-03
11
+
12
+ ### Fixed
13
+
14
+ - **`no-hardcoded-strings`** - Fix Tailwind detection being too broad:
15
+ - Previously: `"john"`, `"not found"` were incorrectly skipped as Tailwind classes
16
+ - Now: Only strings with Tailwind syntax (hyphens, colons, slashes, brackets) are skipped
17
+ - Regular strings like `const name = "john"` are now properly detected
18
+ - Tailwind classes like `"px-5 py-3 w-full"` still correctly skipped
19
+
20
+ ---
21
+
22
+ ## [1.9.6] - 2026-02-03
23
+
24
+ ### Enhanced
25
+
26
+ - **`no-hardcoded-strings`** - Skip Tailwind CSS class strings:
27
+ - Multi-class strings like `"px-5 py-3 w-full bg-white"` are now ignored
28
+ - Individual classes: `w-5`, `p-4`, `pr-12`, `text-2xl`, `gap-4`, etc.
29
+ - State modifiers: `hover:bg-primary`, `focus:ring-2`, `disabled:opacity-50`
30
+ - Responsive prefixes: `sm:flex`, `md:hidden`, `lg:grid`
31
+ - Opacity values: `bg-white/50`, `text-black/80`, `placeholder-error/50`
32
+ - Arbitrary values: `w-[100px]`, `bg-[#ff0000]`
33
+ - Negative values: `-translate-y-1/2`, `-rotate-45`
34
+
35
+ ---
36
+
10
37
  ## [1.9.5] - 2026-02-03
11
38
 
12
39
  ### Fixed
13
40
 
14
41
  - **`no-hardcoded-strings`** - Fix bug where strings inside exported components were incorrectly skipped:
15
- - Previously: `export const Component = () => { const name = "ahmed" }` was not detected
42
+ - Previously: `export const Component = () => { const name = "john" }` was not detected
16
43
  - Now: Strings inside functions are properly detected regardless of export status
17
44
  - Only direct constant exports are skipped: `export const MESSAGE = "value"` or `export const DATA = { key: "value" }`
18
45
 
@@ -1310,6 +1337,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1310
1337
 
1311
1338
  ---
1312
1339
 
1340
+ [1.9.7]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.6...v1.9.7
1341
+ [1.9.6]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.5...v1.9.6
1313
1342
  [1.9.5]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.4...v1.9.5
1314
1343
  [1.9.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.3...v1.9.4
1315
1344
  [1.9.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.2...v1.9.3
package/index.js CHANGED
@@ -14070,6 +14070,22 @@ const noHardcodedStrings = {
14070
14070
  /^[a-z][a-zA-Z0-9_]*=/,
14071
14071
  // CSS property-like (kebab-case): must have hyphen (e.g., font-size, background-color)
14072
14072
  /^[a-z]+-[a-z]+(-[a-z]+)*$/,
14073
+ // Tailwind CSS utility classes
14074
+ // With numbers: w-5, p-4, pr-12, mt-1, text-2xl, gap-4, h-5, rounded-lg, etc.
14075
+ /^-?[a-z]+-\d+(\.\d+)?(\/\d+)?$/,
14076
+ /^-?[a-z]+-[a-z]+-\d+(\.\d+)?(\/\d+)?$/,
14077
+ // With modifiers: hover:bg-primary, focus:ring-2, sm:flex, disabled:opacity-50, etc.
14078
+ /^[a-z]+:[a-z][-a-z0-9/]*$/,
14079
+ // With opacity: bg-white/50, text-black/80, placeholder-error/50, etc.
14080
+ /^[a-z]+-[a-z]+(-[a-z]+)*\/\d+$/,
14081
+ // Arbitrary values: w-[100px], bg-[#ff0000], translate-x-[50%], etc.
14082
+ /^-?[a-z]+(-[a-z]+)*-\[.+\]$/,
14083
+ // Negative transforms: -translate-y-1/2, -rotate-45, -skew-x-12, etc.
14084
+ /^-[a-z]+-[a-z]+-\d+\/\d+$/,
14085
+ // Common Tailwind patterns with full/auto/screen/none/inherit etc.
14086
+ /^[a-z]+-(full|auto|screen|none|inherit|initial|px|fit|min|max)$/,
14087
+ // Responsive/state prefixes with values: sm:w-full, md:flex, lg:hidden, etc.
14088
+ /^(sm|md|lg|xl|2xl|hover|focus|active|disabled|first|last|odd|even|group-hover|dark|motion-safe|motion-reduce):[a-z][-a-z0-9/[\]]*$/,
14073
14089
  // Numbers with separators
14074
14090
  /^[\d,._]+$/,
14075
14091
  // Semantic version
@@ -14090,6 +14106,66 @@ const noHardcodedStrings = {
14090
14106
 
14091
14107
  const allIgnorePatterns = [...technicalPatterns, ...extraIgnorePatterns];
14092
14108
 
14109
+ // Tailwind/CSS class pattern - matches individual class names
14110
+ const tailwindClassPattern = /^-?[a-z]+(-[a-z0-9]+)*(\/\d+)?$|^-?[a-z]+(-[a-z0-9]+)*-\[.+\]$|^[a-z]+:[a-z][-a-z0-9/[\]]*$/;
14111
+
14112
+ // Known single-word Tailwind utilities (no hyphen required)
14113
+ const singleWordTailwindUtilities = new Set([
14114
+ // Display
14115
+ "block", "contents", "flex", "flow", "grid", "hidden", "inline", "table",
14116
+ // Position
14117
+ "absolute", "fixed", "relative", "static", "sticky",
14118
+ // Visibility
14119
+ "collapse", "invisible", "visible",
14120
+ // Typography
14121
+ "antialiased", "capitalize", "italic", "lowercase", "ordinal", "overline",
14122
+ "subpixel", "truncate", "underline", "uppercase",
14123
+ // Layout
14124
+ "container", "isolate",
14125
+ // Misc
14126
+ "resize", "snap", "touch", "select", "pointer", "transition", "animate",
14127
+ "filter", "backdrop", "transform", "appearance", "cursor", "outline",
14128
+ "ring", "shadow", "opacity", "blur", "invert", "sepia", "grayscale",
14129
+ "hue", "saturate", "brightness", "contrast",
14130
+ ]);
14131
+
14132
+ // Check if a string contains only CSS/Tailwind class names
14133
+ const isTailwindClassStringHandler = (str) => {
14134
+ // Split by whitespace and filter empty strings
14135
+ const tokens = str.trim().split(/\s+/).filter(Boolean);
14136
+
14137
+ // Must have at least one token
14138
+ if (tokens.length === 0) return false;
14139
+
14140
+ // Must have at least one token with Tailwind-like syntax (hyphen, colon, slash, or brackets)
14141
+ // to be considered a Tailwind class string
14142
+ const hasTailwindSyntax = tokens.some((token) =>
14143
+ token.includes("-") || token.includes(":") || token.includes("/") || token.includes("["));
14144
+
14145
+ if (!hasTailwindSyntax) return false;
14146
+
14147
+ // Check if all tokens look like CSS classes
14148
+ return tokens.every((token) => {
14149
+ // Skip template literal expressions placeholders if any
14150
+ if (token.includes("${")) return true;
14151
+
14152
+ // Known single-word Tailwind utilities
14153
+ if (singleWordTailwindUtilities.has(token)) return true;
14154
+
14155
+ // Common Tailwind patterns - MUST have hyphen, colon, slash, or brackets
14156
+ return (
14157
+ // Kebab-case: w-5, p-4, pr-12, text-2xl, gap-4, bg-white, text-error
14158
+ /^-?[a-z]+(-[a-z0-9]+)+$/.test(token)
14159
+ // With fractions: w-1/2, -translate-y-1/2, bg-black/50
14160
+ || /^-?[a-z]+(-[a-z0-9]+)*\/\d+$/.test(token)
14161
+ // With modifiers: hover:bg-primary, focus:ring-2, sm:flex
14162
+ || /^[a-z0-9]+:[a-z][-a-z0-9/[\]]*$/.test(token)
14163
+ // Arbitrary values: w-[100px], bg-[#ff0000]
14164
+ || /^-?[a-z]+(-[a-z]+)*-?\[.+\]$/.test(token)
14165
+ );
14166
+ });
14167
+ };
14168
+
14093
14169
  // UI component patterns - only ignored in JSX attributes, not in logic
14094
14170
  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
14171
 
@@ -14311,6 +14387,9 @@ const noHardcodedStrings = {
14311
14387
  // Always flag HTTP status codes and role names
14312
14388
  if (isFlaggedSpecialStringHandler(str)) return false;
14313
14389
 
14390
+ // Skip Tailwind/CSS class strings
14391
+ if (isTailwindClassStringHandler(str)) return true;
14392
+
14314
14393
  return allIgnorePatterns.some((pattern) => pattern.test(str));
14315
14394
  };
14316
14395
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-code-style",
3
- "version": "1.9.5",
3
+ "version": "1.9.7",
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",