@salesforce-ux/eslint-plugin-slds 1.0.0-internal-alpha.0 → 1.0.1

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 (67) hide show
  1. package/README.md +17 -1
  2. package/build/index.js +1072 -1016
  3. package/build/index.js.map +4 -4
  4. package/build/rules/enforce-bem-usage.js +5 -5
  5. package/build/rules/enforce-bem-usage.js.map +3 -3
  6. package/build/rules/no-deprecated-classes-slds2.js +2 -2
  7. package/build/rules/no-deprecated-classes-slds2.js.map +2 -2
  8. package/build/rules/v9/enforce-bem-usage.js +2 -2
  9. package/build/rules/v9/enforce-bem-usage.js.map +2 -2
  10. package/build/rules/v9/enforce-component-hook-naming-convention.js +2 -2
  11. package/build/rules/v9/enforce-component-hook-naming-convention.js.map +2 -2
  12. package/build/rules/v9/enforce-sds-to-slds-hooks.js +2 -2
  13. package/build/rules/v9/enforce-sds-to-slds-hooks.js.map +2 -2
  14. package/build/rules/v9/lwc-token-to-slds-hook.js +42 -3
  15. package/build/rules/v9/lwc-token-to-slds-hook.js.map +4 -4
  16. package/build/rules/v9/no-deprecated-slds-classes.js +2 -2
  17. package/build/rules/v9/no-deprecated-slds-classes.js.map +2 -2
  18. package/build/rules/v9/no-deprecated-tokens-slds1.js +2 -2
  19. package/build/rules/v9/no-deprecated-tokens-slds1.js.map +2 -2
  20. package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js +49 -54
  21. package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js.map +3 -3
  22. package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js +9 -2
  23. package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js.map +3 -3
  24. package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js +14 -3
  25. package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js.map +3 -3
  26. package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js +14 -3
  27. package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js.map +3 -3
  28. package/build/rules/v9/no-hardcoded-values/handlers/index.js +86 -90
  29. package/build/rules/v9/no-hardcoded-values/handlers/index.js.map +3 -3
  30. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js +116 -96
  31. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js.map +4 -4
  32. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js +116 -96
  33. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js.map +4 -4
  34. package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js +110 -92
  35. package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js.map +3 -3
  36. package/build/rules/v9/no-slds-class-overrides.js +2 -2
  37. package/build/rules/v9/no-slds-class-overrides.js.map +2 -2
  38. package/build/rules/v9/no-slds-namespace-for-custom-hooks.js +2 -2
  39. package/build/rules/v9/no-slds-namespace-for-custom-hooks.js.map +2 -2
  40. package/build/rules/v9/no-slds-var-without-fallback.js +121 -35
  41. package/build/rules/v9/no-slds-var-without-fallback.js.map +4 -4
  42. package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js +2 -2
  43. package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js.map +2 -2
  44. package/build/rules/v9/no-unsupported-hooks-slds2.js +2 -2
  45. package/build/rules/v9/no-unsupported-hooks-slds2.js.map +2 -2
  46. package/build/src/rules/v9/no-hardcoded-values/noHardcodedValueRule.d.ts +3 -1
  47. package/build/src/rules/v9/no-slds-var-without-fallback.d.ts +4 -0
  48. package/build/src/utils/css-utils.d.ts +19 -0
  49. package/build/src/utils/rule-utils.d.ts +8 -0
  50. package/build/src/utils/value-utils.d.ts +3 -2
  51. package/build/types/index.js.map +1 -1
  52. package/build/utils/boxShadowValueParser.js +4 -1
  53. package/build/utils/boxShadowValueParser.js.map +2 -2
  54. package/build/utils/color-lib-utils.js.map +1 -1
  55. package/build/utils/css-utils.js +108 -0
  56. package/build/utils/css-utils.js.map +4 -4
  57. package/build/utils/hardcoded-shared-utils.js +5 -2
  58. package/build/utils/hardcoded-shared-utils.js.map +3 -3
  59. package/build/utils/property-matcher.js +1 -1
  60. package/build/utils/property-matcher.js.map +2 -2
  61. package/build/utils/rule-utils.js +46 -0
  62. package/build/utils/rule-utils.js.map +7 -0
  63. package/build/utils/styling-hook-utils.js +4 -1
  64. package/build/utils/styling-hook-utils.js.map +2 -2
  65. package/build/utils/value-utils.js +6 -1
  66. package/build/utils/value-utils.js.map +2 -2
  67. package/package.json +1 -1
@@ -216,7 +216,7 @@ function toSelector(properties) {
216
216
  const selectorParts = properties.map((prop) => {
217
217
  if (prop.includes("*")) {
218
218
  const regexPattern = prop.replace(/\*/g, ".*");
219
- return `Declaration[property=/${regexPattern}$/]`;
219
+ return `Declaration[property=/^${regexPattern}$/]`;
220
220
  } else {
221
221
  return `Declaration[property='${prop}']`;
222
222
  }
@@ -247,6 +247,42 @@ function resolvePropertyToMatch(cssProperty) {
247
247
 
248
248
  // src/utils/hardcoded-shared-utils.ts
249
249
  var import_css_tree2 = require("@eslint/css-tree");
250
+
251
+ // src/utils/value-utils.ts
252
+ var ALLOWED_UNITS = ["px", "em", "rem", "%", "ch"];
253
+ function parseUnitValue(value) {
254
+ if (!value) return null;
255
+ const unitsPattern = ALLOWED_UNITS.join("|");
256
+ const regex = new RegExp(`^(-?\\d*\\.?\\d+)(${unitsPattern})?$`);
257
+ const match = value.match(regex);
258
+ if (!match) return null;
259
+ const number = parseFloat(match[1]);
260
+ const unit = match[2] ? match[2] : null;
261
+ if (isNaN(number)) return null;
262
+ return { number, unit };
263
+ }
264
+ function toAlternateUnitValue(numberVal, unitType) {
265
+ if (unitType === "px") {
266
+ let floatValue = parseFloat(`${numberVal / 16}`);
267
+ if (!isNaN(floatValue)) {
268
+ return {
269
+ unit: "rem",
270
+ number: parseFloat(floatValue.toFixed(4))
271
+ };
272
+ }
273
+ } else if (unitType === "rem") {
274
+ const intValue = parseInt(`${numberVal * 16}`);
275
+ if (!isNaN(intValue)) {
276
+ return {
277
+ unit: "px",
278
+ number: intValue
279
+ };
280
+ }
281
+ }
282
+ return null;
283
+ }
284
+
285
+ // src/utils/hardcoded-shared-utils.ts
250
286
  var FONT_WEIGHTS = [
251
287
  "normal",
252
288
  "bold",
@@ -356,7 +392,7 @@ function extractDimensionValue(valueNode, cssProperty) {
356
392
  const numValue = Number(valueNode.value);
357
393
  if (numValue === 0) return null;
358
394
  const unit = valueNode.unit.toLowerCase();
359
- if (unit !== "px" && unit !== "rem" && unit !== "%") return null;
395
+ if (!ALLOWED_UNITS.includes(unit)) return null;
360
396
  return {
361
397
  number: numValue,
362
398
  unit
@@ -398,7 +434,7 @@ function extractFontValue(node) {
398
434
  const numValue = Number(node.value);
399
435
  if (numValue <= 0) return null;
400
436
  const unit = node.unit.toLowerCase();
401
- if (unit !== "px" && unit !== "rem" && unit !== "%") return null;
437
+ if (!ALLOWED_UNITS.includes(unit)) return null;
402
438
  return {
403
439
  number: numValue,
404
440
  unit
@@ -443,6 +479,14 @@ function forEachFontValue(valueText, callback) {
443
479
  forEachValue(valueText, extractFontValue, shouldSkipFontNode, callback);
444
480
  }
445
481
 
482
+ // src/utils/css-utils.ts
483
+ function formatSuggestionHooks(hooks) {
484
+ if (hooks.length === 1) {
485
+ return `${hooks[0]}`;
486
+ }
487
+ return "\n" + hooks.map((hook, index) => `${index + 1}. ${hook}`).join("\n");
488
+ }
489
+
446
490
  // src/rules/v9/no-hardcoded-values/handlers/colorHandler.ts
447
491
  var handleColorDeclaration = (node, context) => {
448
492
  const cssProperty = node.property.toLowerCase();
@@ -485,9 +529,8 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
485
529
  end,
486
530
  replacement: originalValue,
487
531
  // Use original value to preserve spacing
488
- displayValue: closestHooks.join(", "),
532
+ displayValue: formatSuggestionHooks(closestHooks),
489
533
  hasHook: true
490
- // ← THE FIX: Multiple hooks still means "has hooks"
491
534
  };
492
535
  } else {
493
536
  return {
@@ -501,37 +544,6 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
501
544
  }
502
545
  }
503
546
 
504
- // src/utils/value-utils.ts
505
- function parseUnitValue(value) {
506
- if (!value) return null;
507
- const match = value.match(/^(-?\d*\.?\d+)(px|rem|%)?$/);
508
- if (!match) return null;
509
- const number = parseFloat(match[1]);
510
- const unit = match[2] ? match[2] : null;
511
- if (isNaN(number)) return null;
512
- return { number, unit };
513
- }
514
- function toAlternateUnitValue(numberVal, unitType) {
515
- if (unitType === "px") {
516
- let floatValue = parseFloat(`${numberVal / 16}`);
517
- if (!isNaN(floatValue)) {
518
- return {
519
- unit: "rem",
520
- number: parseFloat(floatValue.toFixed(4))
521
- };
522
- }
523
- } else if (unitType === "rem") {
524
- const intValue = parseInt(`${numberVal * 16}`);
525
- if (!isNaN(intValue)) {
526
- return {
527
- unit: "px",
528
- number: intValue
529
- };
530
- }
531
- }
532
- return null;
533
- }
534
-
535
547
  // src/utils/styling-hook-utils.ts
536
548
  function isValueMatch(valueToMatch, sldsValue) {
537
549
  if (!valueToMatch || !sldsValue) {
@@ -589,7 +601,7 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
589
601
  start,
590
602
  end,
591
603
  replacement: rawValue,
592
- displayValue: closestHooks.join(", "),
604
+ displayValue: formatSuggestionHooks(closestHooks),
593
605
  hasHook: true
594
606
  };
595
607
  } else {
@@ -656,7 +668,7 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
656
668
  start,
657
669
  end,
658
670
  replacement: rawValue,
659
- displayValue: closestHooks.join(", "),
671
+ displayValue: formatSuggestionHooks(closestHooks),
660
672
  hasHook: true
661
673
  };
662
674
  } else {
@@ -783,59 +795,51 @@ function isBoxShadowMatch(parsedCssValue, parsedValueHook) {
783
795
  }
784
796
 
785
797
  // src/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.ts
786
- function containsCssVariable(valueText) {
787
- return valueText.includes("var(");
788
- }
789
- var handleBoxShadowDeclaration = (node, context) => {
790
- const cssProperty = node.property.toLowerCase();
791
- const valueText = context.sourceCode.getText(node.value);
792
- if (containsCssVariable(valueText)) {
793
- return;
794
- }
795
- const replacements = [];
796
- const parsedCssValue = parseAndValidateBoxShadow(valueText);
797
- if (parsedCssValue) {
798
- const shadowHooks = getBoxShadowHooks(context.valueToStylinghook);
799
- const closestHooks = findMatchingBoxShadowHooks(parsedCssValue, shadowHooks);
800
- const positionInfo = {
801
- start: { offset: 0, line: 1, column: 1 },
802
- end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
803
- };
804
- const replacement = createBoxShadowReplacement(
805
- valueText,
806
- closestHooks,
807
- context,
808
- positionInfo
809
- );
810
- if (replacement) {
811
- replacements.push(replacement);
812
- }
798
+ function toBoxShadowValue(cssValue) {
799
+ const parsedCssValue = parseBoxShadowValue(cssValue).filter((shadow) => Object.keys(shadow).length > 0);
800
+ if (parsedCssValue.length === 0) {
801
+ return null;
813
802
  }
814
- handleShorthandAutoFix(node, context, valueText, replacements);
815
- };
816
- function getBoxShadowHooks(supportedStylinghooks) {
803
+ return parsedCssValue;
804
+ }
805
+ function shadowValueToHookEntries(supportedStylinghooks) {
817
806
  return Object.entries(supportedStylinghooks).filter(([key, value]) => {
818
807
  return value.some((hook) => hook.properties.includes("box-shadow"));
819
808
  }).map(([key, value]) => {
820
809
  return [key, value.map((hook) => hook.name)];
821
810
  });
822
811
  }
823
- function parseAndValidateBoxShadow(cssValue) {
824
- const parsedCssValue = parseBoxShadowValue(cssValue).filter((shadow) => Object.keys(shadow).length > 0);
825
- if (parsedCssValue.length === 0) {
826
- return null;
812
+ var handleBoxShadowDeclaration = (node, context) => {
813
+ const cssProperty = node.property.toLowerCase();
814
+ const valueText = context.sourceCode.getText(node.value);
815
+ const shadowHooks = shadowValueToHookEntries(context.valueToStylinghook);
816
+ const parsedCssValue = toBoxShadowValue(valueText);
817
+ if (!parsedCssValue) {
818
+ return;
827
819
  }
828
- return parsedCssValue;
829
- }
830
- function findMatchingBoxShadowHooks(parsedCssValue, shadowHooks) {
831
- for (const [shadowHookValue, closestHooks] of shadowHooks) {
832
- const parsedHookValue = parseAndValidateBoxShadow(shadowHookValue);
833
- if (parsedHookValue && isBoxShadowMatch(parsedCssValue, parsedHookValue)) {
834
- return closestHooks;
820
+ for (const [shadow, closestHooks] of shadowHooks) {
821
+ const parsedValueHook = toBoxShadowValue(shadow);
822
+ if (parsedValueHook && isBoxShadowMatch(parsedCssValue, parsedValueHook)) {
823
+ if (closestHooks.length > 0) {
824
+ const positionInfo = {
825
+ start: { offset: 0, line: 1, column: 1 },
826
+ end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
827
+ };
828
+ const replacement = createBoxShadowReplacement(
829
+ valueText,
830
+ closestHooks,
831
+ context,
832
+ positionInfo
833
+ );
834
+ if (replacement) {
835
+ const replacements = [replacement];
836
+ handleShorthandAutoFix(node, context, valueText, replacements);
837
+ }
838
+ }
839
+ return;
835
840
  }
836
841
  }
837
- return [];
838
- }
842
+ };
839
843
  function createBoxShadowReplacement(originalValue, hooks, context, positionInfo) {
840
844
  if (!positionInfo?.start) {
841
845
  return null;
@@ -850,28 +854,39 @@ function createBoxShadowReplacement(originalValue, hooks, context, positionInfo)
850
854
  displayValue: hooks[0],
851
855
  hasHook: true
852
856
  };
853
- } else if (hooks.length > 1) {
854
- return {
855
- start,
856
- end,
857
- replacement: originalValue,
858
- displayValue: hooks.join(", "),
859
- hasHook: true
860
- };
861
857
  } else {
862
858
  return {
863
859
  start,
864
860
  end,
865
861
  replacement: originalValue,
866
- displayValue: originalValue,
867
- hasHook: false
862
+ displayValue: formatSuggestionHooks(hooks),
863
+ hasHook: true
868
864
  };
869
865
  }
870
866
  }
871
867
 
868
+ // src/utils/rule-utils.ts
869
+ function isRuleEnabled(context, ruleName) {
870
+ try {
871
+ const rules = context.settings?.sldsRules || {};
872
+ if (ruleName in rules) {
873
+ const ruleConfig = rules[ruleName];
874
+ if (Array.isArray(ruleConfig)) {
875
+ return ruleConfig[0] === true;
876
+ } else if (ruleConfig !== void 0 && ruleConfig !== null) {
877
+ return true;
878
+ } else if (ruleConfig === false) {
879
+ return false;
880
+ }
881
+ }
882
+ } catch (error) {
883
+ return false;
884
+ }
885
+ }
886
+
872
887
  // src/rules/v9/no-hardcoded-values/noHardcodedValueRule.ts
873
888
  function defineNoHardcodedValueRule(config) {
874
- const { ruleConfig } = config;
889
+ const { ruleConfig, ruleName } = config;
875
890
  const { type, description, url, messages } = ruleConfig;
876
891
  return {
877
892
  meta: {
@@ -885,6 +900,9 @@ function defineNoHardcodedValueRule(config) {
885
900
  messages
886
901
  },
887
902
  create(context) {
903
+ if (ruleName === "no-hardcoded-values-slds1" && isRuleEnabled(context, "@salesforce-ux/slds/no-hardcoded-values-slds2")) {
904
+ return {};
905
+ }
888
906
  const handlerContext = {
889
907
  valueToStylinghook: config.valueToStylinghook,
890
908
  context,