uilint-eslint 0.2.57 → 0.2.58

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/dist/index.d.ts CHANGED
@@ -790,11 +790,13 @@ declare const rules: {
790
790
  }], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
791
791
  name: string;
792
792
  };
793
- "prefer-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"preferTailwind", [({
793
+ "prefer-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"preferTailwind" | "preferSemanticColors", [({
794
794
  styleRatioThreshold?: number;
795
795
  minElementsForAnalysis?: number;
796
796
  allowedStyleProperties?: string[];
797
797
  ignoreComponents?: string[];
798
+ preferSemanticColors?: boolean;
799
+ allowedHardCodedColors?: string[];
798
800
  } | undefined)?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
799
801
  name: string;
800
802
  };
@@ -933,11 +935,13 @@ declare const plugin: {
933
935
  }], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
934
936
  name: string;
935
937
  };
936
- "prefer-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"preferTailwind", [({
938
+ "prefer-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"preferTailwind" | "preferSemanticColors", [({
937
939
  styleRatioThreshold?: number;
938
940
  minElementsForAnalysis?: number;
939
941
  allowedStyleProperties?: string[];
940
942
  ignoreComponents?: string[];
943
+ preferSemanticColors?: boolean;
944
+ allowedHardCodedColors?: string[];
941
945
  } | undefined)?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
942
946
  name: string;
943
947
  };
package/dist/index.js CHANGED
@@ -6501,7 +6501,9 @@ var meta16 = defineRuleMeta({
6501
6501
  styleRatioThreshold: 0.3,
6502
6502
  minElementsForAnalysis: 3,
6503
6503
  allowedStyleProperties: [],
6504
- ignoreComponents: []
6504
+ ignoreComponents: [],
6505
+ preferSemanticColors: true,
6506
+ allowedHardCodedColors: []
6505
6507
  }
6506
6508
  ],
6507
6509
  optionSchema: {
@@ -6533,6 +6535,20 @@ var meta16 = defineRuleMeta({
6533
6535
  type: "text",
6534
6536
  defaultValue: "",
6535
6537
  description: "Comma-separated component names to skip (e.g., motion.div,animated.View)"
6538
+ },
6539
+ {
6540
+ key: "preferSemanticColors",
6541
+ label: "Prefer semantic colors",
6542
+ type: "boolean",
6543
+ defaultValue: true,
6544
+ description: "Warn against hard-coded colors (bg-red-500) in favor of semantic theme colors (bg-destructive)"
6545
+ },
6546
+ {
6547
+ key: "allowedHardCodedColors",
6548
+ label: "Allowed hard-coded colors",
6549
+ type: "text",
6550
+ defaultValue: "",
6551
+ description: "Comma-separated color names to allow when preferSemanticColors is enabled (e.g., gray,slate)"
6536
6552
  }
6537
6553
  ]
6538
6554
  },
@@ -6581,10 +6597,36 @@ but only when the file exceeds a configurable threshold ratio.
6581
6597
  styleRatioThreshold: 0.3, // Warn when >30% of elements are style-only
6582
6598
  minElementsForAnalysis: 3, // Need at least 3 styled elements to analyze
6583
6599
  allowedStyleProperties: ["transform", "animation"], // Skip these properties
6584
- ignoreComponents: ["motion.div", "animated.View"] // Skip animation libraries
6600
+ ignoreComponents: ["motion.div", "animated.View"], // Skip animation libraries
6601
+ preferSemanticColors: true, // Warn on hard-coded colors like bg-red-500
6602
+ allowedHardCodedColors: ["gray", "slate"] // Allow specific color palettes
6585
6603
  }]
6586
6604
  \`\`\`
6587
6605
 
6606
+ ## Semantic Colors
6607
+
6608
+ When \`preferSemanticColors\` is enabled, the rule warns against hard-coded Tailwind color classes
6609
+ in favor of semantic theme colors:
6610
+
6611
+ ### \u274C Hard-coded colors (when enabled)
6612
+
6613
+ \`\`\`tsx
6614
+ <div className="bg-red-500 text-white">Error</div>
6615
+ <button className="hover:bg-blue-600">Click</button>
6616
+ \`\`\`
6617
+
6618
+ ### \u2705 Semantic colors (preferred)
6619
+
6620
+ \`\`\`tsx
6621
+ <div className="bg-destructive text-destructive-foreground">Error</div>
6622
+ <button className="hover:bg-primary">Click</button>
6623
+ \`\`\`
6624
+
6625
+ Semantic colors like \`bg-background\`, \`text-foreground\`, \`bg-primary\`, \`bg-destructive\`,
6626
+ \`bg-muted\`, etc. work better with theming and dark mode.
6627
+
6628
+ Colors that are always allowed: \`white\`, \`black\`, \`transparent\`, \`inherit\`, \`current\`.
6629
+
6588
6630
  ## Notes
6589
6631
 
6590
6632
  - Elements with BOTH \`style\` and \`className\` are considered acceptable
@@ -6636,6 +6678,63 @@ function hasOnlyAllowedProperties(styleProperties, allowedProperties) {
6636
6678
  }
6637
6679
  return styleProperties.every((prop) => allowedProperties.includes(prop));
6638
6680
  }
6681
+ var HARD_CODED_COLOR_NAMES = [
6682
+ "red",
6683
+ "orange",
6684
+ "amber",
6685
+ "yellow",
6686
+ "lime",
6687
+ "green",
6688
+ "emerald",
6689
+ "teal",
6690
+ "cyan",
6691
+ "sky",
6692
+ "blue",
6693
+ "indigo",
6694
+ "violet",
6695
+ "purple",
6696
+ "fuchsia",
6697
+ "pink",
6698
+ "rose",
6699
+ "slate",
6700
+ "gray",
6701
+ "zinc",
6702
+ "neutral",
6703
+ "stone"
6704
+ ];
6705
+ function createHardCodedColorRegex(colorNames) {
6706
+ const colorPattern = colorNames.join("|");
6707
+ return new RegExp(
6708
+ `(?:^|\\s)(?:[a-z-]+:)*(?:bg|text|border|ring|outline|decoration|accent|fill|stroke|from|via|to|divide|placeholder|caret|shadow)-(${colorPattern})-\\d{1,3}(?:/\\d{1,3})?(?=\\s|$)`,
6709
+ "g"
6710
+ );
6711
+ }
6712
+ function getClassNameValue(attr) {
6713
+ if (!attr.value) return null;
6714
+ if (attr.value.type === "Literal" && typeof attr.value.value === "string") {
6715
+ return attr.value.value;
6716
+ }
6717
+ if (attr.value.type === "JSXExpressionContainer" && attr.value.expression.type === "Literal" && typeof attr.value.expression.value === "string") {
6718
+ return attr.value.expression.value;
6719
+ }
6720
+ if (attr.value.type === "JSXExpressionContainer" && attr.value.expression.type === "TemplateLiteral") {
6721
+ return attr.value.expression.quasis.map((q) => q.value.raw).join(" ");
6722
+ }
6723
+ return null;
6724
+ }
6725
+ function findHardCodedColors(className, allowedColors) {
6726
+ const disallowedColorNames = HARD_CODED_COLOR_NAMES.filter(
6727
+ (c) => !allowedColors.includes(c)
6728
+ );
6729
+ if (disallowedColorNames.length === 0) return [];
6730
+ const regex = createHardCodedColorRegex(disallowedColorNames);
6731
+ const matches = [];
6732
+ let match;
6733
+ while ((match = regex.exec(className)) !== null) {
6734
+ matches.push(match[0].trim());
6735
+ }
6736
+ return matches;
6737
+ }
6639
6738
  var prefer_tailwind_default = createRule({
6640
6739
  name: "prefer-tailwind",
6641
6740
  meta: {
@@ -6644,7 +6743,8 @@ var prefer_tailwind_default = createRule({
6644
6743
  description: "Encourage Tailwind className over inline style attributes"
6645
6744
  },
6646
6745
  messages: {
6647
- preferTailwind: "Prefer Tailwind className over inline style. This element uses style attribute without className."
6746
+ preferTailwind: "Prefer Tailwind className over inline style. This element uses style attribute without className.",
6747
+ preferSemanticColors: "Prefer semantic color classes (e.g., bg-destructive, text-primary) over hard-coded colors (e.g., bg-red-500)."
6648
6748
  },
6649
6749
  schema: [
6650
6750
  {
@@ -6670,6 +6770,15 @@ var prefer_tailwind_default = createRule({
6670
6770
  type: "array",
6671
6771
  items: { type: "string" },
6672
6772
  description: "Component names to skip"
6773
+ },
6774
+ preferSemanticColors: {
6775
+ type: "boolean",
6776
+ description: "Warn against hard-coded colors in favor of semantic theme colors"
6777
+ },
6778
+ allowedHardCodedColors: {
6779
+ type: "array",
6780
+ items: { type: "string" },
6781
+ description: "Hard-coded color names to allow when preferSemanticColors is enabled"
6673
6782
  }
6674
6783
  },
6675
6784
  additionalProperties: false
@@ -6681,7 +6790,9 @@ var prefer_tailwind_default = createRule({
6681
6790
  styleRatioThreshold: 0.3,
6682
6791
  minElementsForAnalysis: 3,
6683
6792
  allowedStyleProperties: [],
6684
- ignoreComponents: []
6793
+ ignoreComponents: [],
6794
+ preferSemanticColors: false,
6795
+ allowedHardCodedColors: []
6685
6796
  }
6686
6797
  ],
6687
6798
  create(context) {
@@ -6690,6 +6801,8 @@ var prefer_tailwind_default = createRule({
6690
6801
  const minElementsForAnalysis = options.minElementsForAnalysis ?? 3;
6691
6802
  const allowedStyleProperties = options.allowedStyleProperties ?? [];
6692
6803
  const ignoreComponents = options.ignoreComponents ?? [];
6804
+ const preferSemanticColors = options.preferSemanticColors ?? false;
6805
+ const allowedHardCodedColors = options.allowedHardCodedColors ?? [];
6693
6806
  const styledElements = [];
6694
6807
  function isStyleAttribute(attr) {
6695
6808
  return attr.name.type === "JSXIdentifier" && attr.name.name === "style" && attr.value?.type === "JSXExpressionContainer";
@@ -6716,11 +6829,31 @@ var prefer_tailwind_default = createRule({
6716
6829
  }
6717
6830
  if (isClassNameAttribute(attr)) {
6718
6831
  hasClassName = true;
6832
+ if (preferSemanticColors) {
6833
+ const classNameValue = getClassNameValue(attr);
6834
+ if (classNameValue) {
6835
+ const hardCodedColors = findHardCodedColors(
6836
+ classNameValue,
6837
+ allowedHardCodedColors
6838
+ );
6839
+ if (hardCodedColors.length > 0) {
6840
+ context.report({
6841
+ node,
6842
+ messageId: "preferSemanticColors"
6843
+ });
6844
+ }
6845
+ }
6846
+ }
6719
6847
  }
6720
6848
  }
6721
6849
  }
6722
6850
  if (hasStyle || hasClassName) {
6723
- styledElements.push({ node, hasStyle, hasClassName, styleProperties });
6851
+ styledElements.push({
6852
+ node,
6853
+ hasStyle,
6854
+ hasClassName,
6855
+ styleProperties
6856
+ });
6724
6857
  }
6725
6858
  },
6726
6859
  "Program:exit"() {
@@ -6968,7 +7101,9 @@ var recommendedConfig = {
6968
7101
  "styleRatioThreshold": 0.3,
6969
7102
  "minElementsForAnalysis": 3,
6970
7103
  "allowedStyleProperties": [],
6971
- "ignoreComponents": []
7104
+ "ignoreComponents": [],
7105
+ "preferSemanticColors": true,
7106
+ "allowedHardCodedColors": []
6972
7107
  }
6973
7108
  ]]
6974
7109
  }
@@ -7114,7 +7249,9 @@ var strictConfig = {
7114
7249
  "styleRatioThreshold": 0.3,
7115
7250
  "minElementsForAnalysis": 3,
7116
7251
  "allowedStyleProperties": [],
7117
- "ignoreComponents": []
7252
+ "ignoreComponents": [],
7253
+ "preferSemanticColors": true,
7254
+ "allowedHardCodedColors": []
7118
7255
  }
7119
7256
  ]]
7120
7257
  }