@salesforce-ux/eslint-plugin-slds 1.0.7 → 1.0.8-internal

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 (66) hide show
  1. package/README.md +62 -0
  2. package/build/index.js +280 -141
  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 +2 -2
  15. package/build/rules/v9/lwc-token-to-slds-hook.js.map +2 -2
  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 +86 -30
  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 +116 -104
  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 +83 -30
  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 +78 -74
  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 +175 -99
  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 +223 -103
  31. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js.map +3 -3
  32. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js +223 -103
  33. package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js.map +3 -3
  34. package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js +221 -101
  35. package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js.map +3 -3
  36. package/build/rules/v9/no-hardcoded-values/ruleOptionsSchema.js +63 -0
  37. package/build/rules/v9/no-hardcoded-values/ruleOptionsSchema.js.map +7 -0
  38. package/build/rules/v9/no-slds-class-overrides.js +2 -2
  39. package/build/rules/v9/no-slds-class-overrides.js.map +2 -2
  40. package/build/rules/v9/no-slds-namespace-for-custom-hooks.js +2 -2
  41. package/build/rules/v9/no-slds-namespace-for-custom-hooks.js.map +2 -2
  42. package/build/rules/v9/no-slds-var-without-fallback.js +2 -2
  43. package/build/rules/v9/no-slds-var-without-fallback.js.map +2 -2
  44. package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js +2 -2
  45. package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js.map +2 -2
  46. package/build/rules/v9/no-unsupported-hooks-slds2.js +2 -2
  47. package/build/rules/v9/no-unsupported-hooks-slds2.js.map +2 -2
  48. package/build/src/rules/v9/no-hardcoded-values/ruleOptionsSchema.d.ts +40 -0
  49. package/build/src/types/index.d.ts +31 -0
  50. package/build/src/utils/color-lib-utils.d.ts +16 -9
  51. package/build/src/utils/custom-mapping-utils.d.ts +9 -0
  52. package/build/src/utils/hardcoded-shared-utils.d.ts +1 -0
  53. package/build/src/utils/property-matcher.d.ts +3 -1
  54. package/build/types/index.js.map +1 -1
  55. package/build/utils/boxShadowValueParser.js.map +2 -2
  56. package/build/utils/color-lib-utils.js +26 -50
  57. package/build/utils/color-lib-utils.js.map +2 -2
  58. package/build/utils/css-utils.js.map +2 -2
  59. package/build/utils/custom-mapping-utils.js +62 -0
  60. package/build/utils/custom-mapping-utils.js.map +7 -0
  61. package/build/utils/hardcoded-shared-utils.js +29 -16
  62. package/build/utils/hardcoded-shared-utils.js.map +2 -2
  63. package/build/utils/property-matcher.js +20 -6
  64. package/build/utils/property-matcher.js.map +2 -2
  65. package/build/utils/styling-hook-utils.js.map +1 -1
  66. package/package.json +2 -2
@@ -67,11 +67,7 @@ function isCssColorFunction(value) {
67
67
  }
68
68
 
69
69
  // src/utils/color-lib-utils.ts
70
- var LAB_THRESHOLD = 25;
71
- var isHexCode = (color) => {
72
- const hexPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
73
- return hexPattern.test(color);
74
- };
70
+ var DELTAE_THRESHOLD = 10;
75
71
  var convertToHex = (color) => {
76
72
  try {
77
73
  return (0, import_chroma_js.default)(color).hex();
@@ -79,52 +75,40 @@ var convertToHex = (color) => {
79
75
  return null;
80
76
  }
81
77
  };
78
+ var isHookPropertyMatch = (hook, cssProperty) => {
79
+ return hook.properties.includes(cssProperty) || hook.properties.includes("*");
80
+ };
81
+ function getOrderByCssProp(cssProperty) {
82
+ if (cssProperty === "color" || cssProperty === "fill") {
83
+ return ["surface", "theme", "feedback", "reference"];
84
+ } else if (cssProperty.match(/background/)) {
85
+ return ["surface", "surface-inverse", "theme", "feedback", "reference"];
86
+ } else if (cssProperty.match(/border/) || cssProperty.match(/outline/) || cssProperty.match(/stroke/)) {
87
+ return ["borders", "borders-inverse", "feedback", "theme", "reference"];
88
+ }
89
+ return ["surface", "surface-inverse", "borders", "borders-inverse", "theme", "feedback", "reference"];
90
+ }
82
91
  var findClosestColorHook = (color, supportedColors, cssProperty) => {
83
- const returnStylingHooks = [];
84
- const closestHooksWithSameProperty = [];
85
- const closestHooksWithoutSameProperty = [];
86
- const closestHooksWithAllProperty = [];
87
- const labColor = (0, import_chroma_js.default)(color).lab();
92
+ const closestHooks = [];
88
93
  Object.entries(supportedColors).forEach(([sldsValue, data]) => {
89
- if (sldsValue && isHexCode(sldsValue)) {
94
+ if (sldsValue && isValidColor(sldsValue)) {
90
95
  const hooks = data;
91
96
  hooks.forEach((hook) => {
92
- const labSupportedColor = (0, import_chroma_js.default)(sldsValue).lab();
93
- const distance = JSON.stringify(labColor) === JSON.stringify(labSupportedColor) ? 0 : import_chroma_js.default.distance(import_chroma_js.default.lab(...labColor), import_chroma_js.default.lab(...labSupportedColor), "lab");
94
- if (hook.properties.includes(cssProperty)) {
95
- if (distance <= LAB_THRESHOLD) {
96
- closestHooksWithSameProperty.push({ name: hook.name, distance });
97
- }
98
- } else if (hook.properties.includes("*")) {
99
- if (distance <= LAB_THRESHOLD) {
100
- closestHooksWithAllProperty.push({ name: hook.name, distance });
101
- }
102
- } else {
103
- if (distance <= LAB_THRESHOLD) {
104
- closestHooksWithoutSameProperty.push({ name: hook.name, distance });
105
- }
97
+ const distance = sldsValue.toLowerCase() === color.toLowerCase() ? 0 : import_chroma_js.default.deltaE(sldsValue, color);
98
+ if (isHookPropertyMatch(hook, cssProperty) && distance <= DELTAE_THRESHOLD) {
99
+ closestHooks.push({ distance, group: hook.group, name: hook.name });
106
100
  }
107
101
  });
108
102
  }
109
103
  });
110
- const closesthookGroups = [
111
- { hooks: closestHooksWithSameProperty, distance: 0 },
112
- { hooks: closestHooksWithAllProperty, distance: 0 },
113
- { hooks: closestHooksWithSameProperty, distance: Infinity },
114
- // For hooks with distance > 0
115
- { hooks: closestHooksWithAllProperty, distance: Infinity },
116
- { hooks: closestHooksWithoutSameProperty, distance: Infinity }
117
- ];
118
- for (const group of closesthookGroups) {
119
- const filteredHooks = group.hooks.filter(
120
- (h) => group.distance === 0 ? h.distance === 0 : h.distance > 0
121
- );
122
- if (returnStylingHooks.length < 1 && filteredHooks.length > 0) {
123
- filteredHooks.sort((a, b) => a.distance - b.distance);
124
- returnStylingHooks.push(...filteredHooks.slice(0, 5).map((h) => h.name));
104
+ const hooksByGroupMap = closestHooks.sort((a, b) => a.distance - b.distance).reduce((acc, hook) => {
105
+ if (!acc[hook.group]) {
106
+ acc[hook.group] = [];
125
107
  }
126
- }
127
- return Array.from(new Set(returnStylingHooks));
108
+ acc[hook.group].push(hook.name);
109
+ return acc;
110
+ }, {});
111
+ return getOrderByCssProp(cssProperty).map((group) => hooksByGroupMap[group] || []).flat().slice(0, 5);
128
112
  };
129
113
  var isValidColor = (val) => import_chroma_js.default.valid(val);
130
114
  var extractColorValue = (node) => {
@@ -223,9 +207,9 @@ function toSelector(properties) {
223
207
  });
224
208
  return selectorParts.join(", ");
225
209
  }
226
- function resolvePropertyToMatch(cssProperty) {
210
+ function resolveDensityPropertyToMatch(cssProperty) {
227
211
  const propertyToMatch = cssProperty.toLowerCase();
228
- if (propertyToMatch === "outline" || propertyToMatch === "outline-width" || isBorderWidthProperty(propertyToMatch)) {
212
+ if (isOutlineWidthProperty(propertyToMatch) || isBorderWidthProperty(propertyToMatch)) {
229
213
  return "border-width";
230
214
  } else if (isMarginProperty(propertyToMatch)) {
231
215
  return "margin";
@@ -237,13 +221,23 @@ function resolvePropertyToMatch(cssProperty) {
237
221
  return "width";
238
222
  } else if (isInsetProperty(propertyToMatch)) {
239
223
  return "top";
240
- } else if (cssProperty === "background" || cssProperty === "background-color") {
224
+ }
225
+ return propertyToMatch;
226
+ }
227
+ function resolveColorPropertyToMatch(cssProperty) {
228
+ const propertyToMatch = cssProperty.toLowerCase();
229
+ if (propertyToMatch === "outline" || propertyToMatch === "outline-color") {
230
+ return "border-color";
231
+ } else if (propertyToMatch === "background" || propertyToMatch === "background-color") {
241
232
  return "background-color";
242
- } else if (cssProperty === "outline" || cssProperty === "outline-color" || isBorderColorProperty(cssProperty)) {
233
+ } else if (isBorderColorProperty(propertyToMatch)) {
243
234
  return "border-color";
244
235
  }
245
236
  return propertyToMatch;
246
237
  }
238
+ function isOutlineWidthProperty(propertyToMatch) {
239
+ return propertyToMatch === "outline" || propertyToMatch === "outline-width";
240
+ }
247
241
 
248
242
  // src/utils/hardcoded-shared-utils.ts
249
243
  var import_css_tree2 = require("@eslint/css-tree");
@@ -303,13 +297,33 @@ function isKnownFontWeight(value) {
303
297
  return FONT_WEIGHTS.includes(stringValue.toLowerCase());
304
298
  }
305
299
  function handleShorthandAutoFix(declarationNode, context, valueText, replacements) {
306
- const sortedReplacements = replacements.sort((a, b) => a.start - b.start);
307
- const hasAnyHooks = sortedReplacements.some((r) => r.hasHook);
308
- const canAutoFix = hasAnyHooks;
309
- sortedReplacements.forEach(({ start, end, replacement, displayValue, hasHook }) => {
300
+ if (!replacements || replacements.length === 0) {
301
+ return;
302
+ }
303
+ const sortedReplacements = replacements.sort((a, b) => b.start - a.start);
304
+ const reportNumericValue = context.options?.reportNumericValue || "always";
305
+ const fixCallback = (start, originalValue, replacement) => {
306
+ let newValue = valueText;
307
+ newValue = newValue.substring(0, start) + replacement + newValue.substring(start + originalValue.length);
308
+ if (newValue !== valueText) {
309
+ return (fixer) => {
310
+ return fixer.replaceText(declarationNode.value, newValue);
311
+ };
312
+ }
313
+ };
314
+ sortedReplacements.forEach(({ start, end, replacement, displayValue, hasHook, isNumeric }) => {
310
315
  const originalValue = valueText.substring(start, end);
311
- const valueStartColumn = declarationNode.value.loc.start.column;
312
- const valueColumn = valueStartColumn + start;
316
+ if (isNumeric) {
317
+ if (reportNumericValue === "never") {
318
+ return;
319
+ }
320
+ if (reportNumericValue === "hasReplacement" && !hasHook) {
321
+ return;
322
+ }
323
+ }
324
+ const valueColumnStart = declarationNode.value.loc.start.column + start;
325
+ const valueColumnEnd = valueColumnStart + originalValue.length;
326
+ const canAutoFix = originalValue !== replacement;
313
327
  const { loc: { start: locStart, end: locEnd } } = declarationNode.value;
314
328
  const reportNode = {
315
329
  ...declarationNode.value,
@@ -317,23 +331,16 @@ function handleShorthandAutoFix(declarationNode, context, valueText, replacement
317
331
  ...declarationNode.value.loc,
318
332
  start: {
319
333
  ...locStart,
320
- column: valueColumn
334
+ column: valueColumnStart
321
335
  },
322
336
  end: {
323
337
  ...locEnd,
324
- column: valueColumn + originalValue.length
338
+ column: valueColumnEnd
325
339
  }
326
340
  }
327
341
  };
328
342
  if (hasHook) {
329
- const fix = canAutoFix ? (fixer) => {
330
- let newValue = valueText;
331
- for (let i = sortedReplacements.length - 1; i >= 0; i--) {
332
- const { start: rStart, end: rEnd, replacement: rReplacement } = sortedReplacements[i];
333
- newValue = newValue.substring(0, rStart) + rReplacement + newValue.substring(rEnd);
334
- }
335
- return fixer.replaceText(declarationNode.value, newValue);
336
- } : void 0;
343
+ const fix = canAutoFix ? fixCallback(start, originalValue, replacement) : void 0;
337
344
  context.context.report({
338
345
  node: reportNode,
339
346
  messageId: "hardcodedValue",
@@ -487,6 +494,41 @@ function formatSuggestionHooks(hooks) {
487
494
  return "\n" + hooks.map((hook, index) => `${index + 1}. ${hook}`).join("\n");
488
495
  }
489
496
 
497
+ // src/utils/custom-mapping-utils.ts
498
+ function matchesPropertyPattern(cssProperty, pattern) {
499
+ const normalizedProperty = cssProperty.toLowerCase();
500
+ const normalizedPattern = pattern.toLowerCase();
501
+ if (normalizedProperty === normalizedPattern) {
502
+ return true;
503
+ }
504
+ if (normalizedPattern.endsWith("*")) {
505
+ const prefix = normalizedPattern.slice(0, -1);
506
+ return normalizedProperty.startsWith(prefix);
507
+ }
508
+ return false;
509
+ }
510
+ function getCustomMapping(cssProperty, value, customMapping) {
511
+ if (!customMapping) {
512
+ return null;
513
+ }
514
+ const normalizedValue = value.toLowerCase().trim();
515
+ for (const [hookName, config] of Object.entries(customMapping)) {
516
+ const propertyMatches = config.properties.some(
517
+ (pattern) => matchesPropertyPattern(cssProperty, pattern)
518
+ );
519
+ if (!propertyMatches) {
520
+ continue;
521
+ }
522
+ const valueMatches = config.values.some(
523
+ (configValue) => configValue.toLowerCase().trim() === normalizedValue
524
+ );
525
+ if (valueMatches) {
526
+ return hookName;
527
+ }
528
+ }
529
+ return null;
530
+ }
531
+
490
532
  // src/rules/v9/no-hardcoded-values/handlers/colorHandler.ts
491
533
  var handleColorDeclaration = (node, context) => {
492
534
  const cssProperty = node.property.toLowerCase();
@@ -510,24 +552,32 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
510
552
  if (!hexValue) {
511
553
  return null;
512
554
  }
513
- const propToMatch = resolvePropertyToMatch(cssProperty);
514
- const closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
515
555
  const start = positionInfo.start.offset;
516
556
  const end = positionInfo.end.offset;
517
557
  const originalValue = originalValueText ? originalValueText.substring(start, end) : colorValue;
518
- if (closestHooks.length === 1) {
519
- return {
520
- start,
521
- end,
522
- replacement: `var(${closestHooks[0]}, ${colorValue})`,
523
- displayValue: closestHooks[0],
524
- hasHook: true
525
- };
526
- } else if (closestHooks.length > 1) {
558
+ const customHook = getCustomMapping(cssProperty, colorValue, context.options?.customMapping);
559
+ let closestHooks = [];
560
+ if (customHook) {
561
+ closestHooks = [customHook];
562
+ } else {
563
+ const propToMatch = resolveColorPropertyToMatch(cssProperty);
564
+ closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
565
+ }
566
+ let replacement = originalValue;
567
+ let paletteHook = null;
568
+ if (context.options?.preferPaletteHook && closestHooks.length > 1) {
569
+ paletteHook = closestHooks.filter((hook) => hook.includes("-palette-"))[0];
570
+ }
571
+ if (paletteHook) {
572
+ replacement = `var(${paletteHook}, ${colorValue})`;
573
+ } else if (closestHooks.length === 1) {
574
+ replacement = `var(${closestHooks[0]}, ${colorValue})`;
575
+ }
576
+ if (closestHooks.length > 0) {
527
577
  return {
528
578
  start,
529
579
  end,
530
- replacement: originalValue,
580
+ replacement,
531
581
  // Use original value to preserve spacing
532
582
  displayValue: formatSuggestionHooks(closestHooks),
533
583
  hasHook: true
@@ -536,7 +586,7 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
536
586
  return {
537
587
  start,
538
588
  end,
539
- replacement: originalValue,
589
+ replacement,
540
590
  // Use original value to preserve spacing
541
591
  displayValue: originalValue,
542
592
  hasHook: false
@@ -584,8 +634,14 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
584
634
  return null;
585
635
  }
586
636
  const rawValue = parsedDimension.unit ? `${parsedDimension.number}${parsedDimension.unit}` : parsedDimension.number.toString();
587
- const propToMatch = resolvePropertyToMatch(cssProperty);
588
- const closestHooks = getStylingHooksForDensityValue(parsedDimension, context.valueToStylinghook, propToMatch);
637
+ const customHook = getCustomMapping(cssProperty, rawValue, context.options?.customMapping);
638
+ let closestHooks = [];
639
+ if (customHook) {
640
+ closestHooks = [customHook];
641
+ } else {
642
+ const propToMatch = resolveDensityPropertyToMatch(cssProperty);
643
+ closestHooks = getStylingHooksForDensityValue(parsedDimension, context.valueToStylinghook, propToMatch);
644
+ }
589
645
  const start = positionInfo.start.offset;
590
646
  const end = positionInfo.end.offset;
591
647
  if (closestHooks.length === 1) {
@@ -594,7 +650,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
594
650
  end,
595
651
  replacement: `var(${closestHooks[0]}, ${rawValue})`,
596
652
  displayValue: closestHooks[0],
597
- hasHook: true
653
+ hasHook: true,
654
+ isNumeric: true
598
655
  };
599
656
  } else if (closestHooks.length > 1) {
600
657
  return {
@@ -602,7 +659,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
602
659
  end,
603
660
  replacement: rawValue,
604
661
  displayValue: formatSuggestionHooks(closestHooks),
605
- hasHook: true
662
+ hasHook: true,
663
+ isNumeric: true
606
664
  };
607
665
  } else {
608
666
  return {
@@ -610,7 +668,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
610
668
  end,
611
669
  replacement: rawValue,
612
670
  displayValue: rawValue,
613
- hasHook: false
671
+ hasHook: false,
672
+ isNumeric: true
614
673
  };
615
674
  }
616
675
  }
@@ -651,8 +710,14 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
651
710
  return null;
652
711
  }
653
712
  const rawValue = fontValue.unit ? `${fontValue.number}${fontValue.unit}` : fontValue.number.toString();
654
- const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ? resolvePropertyToMatch("font-weight") : resolvePropertyToMatch("font-size");
655
- const closestHooks = getStylingHooksForDensityValue(fontValue, context.valueToStylinghook, propToMatch);
713
+ const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ? "font-weight" : "font-size";
714
+ const customHook = getCustomMapping(propToMatch, rawValue, context.options?.customMapping);
715
+ let closestHooks = [];
716
+ if (customHook) {
717
+ closestHooks = [customHook];
718
+ } else {
719
+ closestHooks = getStylingHooksForDensityValue(fontValue, context.valueToStylinghook, propToMatch);
720
+ }
656
721
  const start = positionInfo.start.offset;
657
722
  const end = positionInfo.end.offset;
658
723
  if (closestHooks.length === 1) {
@@ -661,7 +726,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
661
726
  end,
662
727
  replacement: `var(${closestHooks[0]}, ${rawValue})`,
663
728
  displayValue: closestHooks[0],
664
- hasHook: true
729
+ hasHook: true,
730
+ isNumeric: true
665
731
  };
666
732
  } else if (closestHooks.length > 1) {
667
733
  return {
@@ -669,7 +735,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
669
735
  end,
670
736
  replacement: rawValue,
671
737
  displayValue: formatSuggestionHooks(closestHooks),
672
- hasHook: true
738
+ hasHook: true,
739
+ isNumeric: true
673
740
  };
674
741
  } else {
675
742
  return {
@@ -677,7 +744,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
677
744
  end,
678
745
  replacement: rawValue,
679
746
  displayValue: rawValue,
680
- hasHook: false
747
+ hasHook: false,
748
+ isNumeric: true
681
749
  };
682
750
  }
683
751
  }
@@ -809,9 +877,30 @@ function shadowValueToHookEntries(supportedStylinghooks) {
809
877
  return [key, value.map((hook) => hook.name)];
810
878
  });
811
879
  }
880
+ function reportBoxShadowViolation(node, context, valueText, hooks) {
881
+ const positionInfo = {
882
+ start: { offset: 0, line: 1, column: 1 },
883
+ end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
884
+ };
885
+ const replacement = createBoxShadowReplacement(
886
+ valueText,
887
+ hooks,
888
+ context,
889
+ positionInfo
890
+ );
891
+ if (replacement) {
892
+ const replacements = [replacement];
893
+ handleShorthandAutoFix(node, context, valueText, replacements);
894
+ }
895
+ }
812
896
  var handleBoxShadowDeclaration = (node, context) => {
813
897
  const cssProperty = node.property.toLowerCase();
814
898
  const valueText = context.sourceCode.getText(node.value);
899
+ const customHook = getCustomMapping(cssProperty, valueText, context.options?.customMapping);
900
+ if (customHook) {
901
+ reportBoxShadowViolation(node, context, valueText, [customHook]);
902
+ return;
903
+ }
815
904
  const shadowHooks = shadowValueToHookEntries(context.valueToStylinghook);
816
905
  const parsedCssValue = toBoxShadowValue(valueText);
817
906
  if (!parsedCssValue) {
@@ -821,20 +910,7 @@ var handleBoxShadowDeclaration = (node, context) => {
821
910
  const parsedValueHook = toBoxShadowValue(shadow);
822
911
  if (parsedValueHook && isBoxShadowMatch(parsedCssValue, parsedValueHook)) {
823
912
  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
- }
913
+ reportBoxShadowViolation(node, context, valueText, closestHooks);
838
914
  }
839
915
  return;
840
916
  }
@@ -884,6 +960,42 @@ function isRuleEnabled(context, ruleName) {
884
960
  }
885
961
  }
886
962
 
963
+ // src/rules/v9/no-hardcoded-values/ruleOptionsSchema.ts
964
+ var ruleOptionsSchema = [
965
+ {
966
+ type: "object",
967
+ properties: {
968
+ reportNumericValue: {
969
+ type: "string",
970
+ enum: ["never", "always", "hasReplacement"],
971
+ default: "always"
972
+ },
973
+ customMapping: {
974
+ type: "object",
975
+ additionalProperties: {
976
+ type: "object",
977
+ properties: {
978
+ properties: {
979
+ type: "array",
980
+ items: { type: "string" }
981
+ },
982
+ values: {
983
+ type: "array",
984
+ items: { type: "string" }
985
+ }
986
+ },
987
+ required: ["properties", "values"]
988
+ }
989
+ },
990
+ preferPaletteHook: {
991
+ type: "boolean",
992
+ default: false
993
+ }
994
+ },
995
+ additionalProperties: false
996
+ }
997
+ ];
998
+
887
999
  // src/rules/v9/no-hardcoded-values/noHardcodedValueRule.ts
888
1000
  function defineNoHardcodedValueRule(config) {
889
1001
  const { ruleConfig, ruleName } = config;
@@ -897,16 +1009,24 @@ function defineNoHardcodedValueRule(config) {
897
1009
  url
898
1010
  },
899
1011
  fixable: "code",
900
- messages
1012
+ messages,
1013
+ schema: ruleOptionsSchema
901
1014
  },
902
1015
  create(context) {
903
1016
  if (ruleName === "no-hardcoded-values-slds1" && isRuleEnabled(context, "@salesforce-ux/slds/no-hardcoded-values-slds2")) {
904
1017
  return {};
905
1018
  }
1019
+ const options = context.options[0] || {};
1020
+ const ruleOptions = {
1021
+ reportNumericValue: options.reportNumericValue || "always",
1022
+ customMapping: options.customMapping || {},
1023
+ preferPaletteHook: options.preferPaletteHook || false
1024
+ };
906
1025
  const handlerContext = {
907
1026
  valueToStylinghook: config.valueToStylinghook,
908
1027
  context,
909
- sourceCode: context.sourceCode
1028
+ sourceCode: context.sourceCode,
1029
+ options: ruleOptions
910
1030
  };
911
1031
  const colorOnlySelector = toSelector(colorProperties);
912
1032
  const densityOnlySelector = toSelector(densificationProperties);