@salesforce-ux/eslint-plugin-slds 1.0.5 → 1.0.6-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 (67) 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/eslint.config.mjs +0 -4
  67. package/package.json +2 -2
@@ -70,11 +70,7 @@ function isCssColorFunction(value) {
70
70
  }
71
71
 
72
72
  // src/utils/color-lib-utils.ts
73
- var LAB_THRESHOLD = 25;
74
- var isHexCode = (color) => {
75
- const hexPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
76
- return hexPattern.test(color);
77
- };
73
+ var DELTAE_THRESHOLD = 10;
78
74
  var convertToHex = (color) => {
79
75
  try {
80
76
  return (0, import_chroma_js.default)(color).hex();
@@ -82,52 +78,40 @@ var convertToHex = (color) => {
82
78
  return null;
83
79
  }
84
80
  };
81
+ var isHookPropertyMatch = (hook, cssProperty) => {
82
+ return hook.properties.includes(cssProperty) || hook.properties.includes("*");
83
+ };
84
+ function getOrderByCssProp(cssProperty) {
85
+ if (cssProperty === "color" || cssProperty === "fill") {
86
+ return ["surface", "theme", "feedback", "reference"];
87
+ } else if (cssProperty.match(/background/)) {
88
+ return ["surface", "surface-inverse", "theme", "feedback", "reference"];
89
+ } else if (cssProperty.match(/border/) || cssProperty.match(/outline/) || cssProperty.match(/stroke/)) {
90
+ return ["borders", "borders-inverse", "feedback", "theme", "reference"];
91
+ }
92
+ return ["surface", "surface-inverse", "borders", "borders-inverse", "theme", "feedback", "reference"];
93
+ }
85
94
  var findClosestColorHook = (color, supportedColors, cssProperty) => {
86
- const returnStylingHooks = [];
87
- const closestHooksWithSameProperty = [];
88
- const closestHooksWithoutSameProperty = [];
89
- const closestHooksWithAllProperty = [];
90
- const labColor = (0, import_chroma_js.default)(color).lab();
95
+ const closestHooks = [];
91
96
  Object.entries(supportedColors).forEach(([sldsValue, data]) => {
92
- if (sldsValue && isHexCode(sldsValue)) {
97
+ if (sldsValue && isValidColor(sldsValue)) {
93
98
  const hooks = data;
94
99
  hooks.forEach((hook) => {
95
- const labSupportedColor = (0, import_chroma_js.default)(sldsValue).lab();
96
- 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");
97
- if (hook.properties.includes(cssProperty)) {
98
- if (distance <= LAB_THRESHOLD) {
99
- closestHooksWithSameProperty.push({ name: hook.name, distance });
100
- }
101
- } else if (hook.properties.includes("*")) {
102
- if (distance <= LAB_THRESHOLD) {
103
- closestHooksWithAllProperty.push({ name: hook.name, distance });
104
- }
105
- } else {
106
- if (distance <= LAB_THRESHOLD) {
107
- closestHooksWithoutSameProperty.push({ name: hook.name, distance });
108
- }
100
+ const distance = sldsValue.toLowerCase() === color.toLowerCase() ? 0 : import_chroma_js.default.deltaE(sldsValue, color);
101
+ if (isHookPropertyMatch(hook, cssProperty) && distance <= DELTAE_THRESHOLD) {
102
+ closestHooks.push({ distance, group: hook.group, name: hook.name });
109
103
  }
110
104
  });
111
105
  }
112
106
  });
113
- const closesthookGroups = [
114
- { hooks: closestHooksWithSameProperty, distance: 0 },
115
- { hooks: closestHooksWithAllProperty, distance: 0 },
116
- { hooks: closestHooksWithSameProperty, distance: Infinity },
117
- // For hooks with distance > 0
118
- { hooks: closestHooksWithAllProperty, distance: Infinity },
119
- { hooks: closestHooksWithoutSameProperty, distance: Infinity }
120
- ];
121
- for (const group of closesthookGroups) {
122
- const filteredHooks = group.hooks.filter(
123
- (h) => group.distance === 0 ? h.distance === 0 : h.distance > 0
124
- );
125
- if (returnStylingHooks.length < 1 && filteredHooks.length > 0) {
126
- filteredHooks.sort((a, b) => a.distance - b.distance);
127
- returnStylingHooks.push(...filteredHooks.slice(0, 5).map((h) => h.name));
107
+ const hooksByGroupMap = closestHooks.sort((a, b) => a.distance - b.distance).reduce((acc, hook) => {
108
+ if (!acc[hook.group]) {
109
+ acc[hook.group] = [];
128
110
  }
129
- }
130
- return Array.from(new Set(returnStylingHooks));
111
+ acc[hook.group].push(hook.name);
112
+ return acc;
113
+ }, {});
114
+ return getOrderByCssProp(cssProperty).map((group) => hooksByGroupMap[group] || []).flat().slice(0, 5);
131
115
  };
132
116
  var isValidColor = (val) => import_chroma_js.default.valid(val);
133
117
  var extractColorValue = (node) => {
@@ -179,9 +163,9 @@ function isDimensionProperty(cssProperty) {
179
163
  function isInsetProperty(cssProperty) {
180
164
  return INSET_REGEX.test(cssProperty);
181
165
  }
182
- function resolvePropertyToMatch(cssProperty) {
166
+ function resolveDensityPropertyToMatch(cssProperty) {
183
167
  const propertyToMatch = cssProperty.toLowerCase();
184
- if (propertyToMatch === "outline" || propertyToMatch === "outline-width" || isBorderWidthProperty(propertyToMatch)) {
168
+ if (isOutlineWidthProperty(propertyToMatch) || isBorderWidthProperty(propertyToMatch)) {
185
169
  return "border-width";
186
170
  } else if (isMarginProperty(propertyToMatch)) {
187
171
  return "margin";
@@ -193,13 +177,23 @@ function resolvePropertyToMatch(cssProperty) {
193
177
  return "width";
194
178
  } else if (isInsetProperty(propertyToMatch)) {
195
179
  return "top";
196
- } else if (cssProperty === "background" || cssProperty === "background-color") {
180
+ }
181
+ return propertyToMatch;
182
+ }
183
+ function resolveColorPropertyToMatch(cssProperty) {
184
+ const propertyToMatch = cssProperty.toLowerCase();
185
+ if (propertyToMatch === "outline" || propertyToMatch === "outline-color") {
186
+ return "border-color";
187
+ } else if (propertyToMatch === "background" || propertyToMatch === "background-color") {
197
188
  return "background-color";
198
- } else if (cssProperty === "outline" || cssProperty === "outline-color" || isBorderColorProperty(cssProperty)) {
189
+ } else if (isBorderColorProperty(propertyToMatch)) {
199
190
  return "border-color";
200
191
  }
201
192
  return propertyToMatch;
202
193
  }
194
+ function isOutlineWidthProperty(propertyToMatch) {
195
+ return propertyToMatch === "outline" || propertyToMatch === "outline-width";
196
+ }
203
197
 
204
198
  // src/utils/hardcoded-shared-utils.ts
205
199
  var import_css_tree2 = require("@eslint/css-tree");
@@ -259,13 +253,33 @@ function isKnownFontWeight(value) {
259
253
  return FONT_WEIGHTS.includes(stringValue.toLowerCase());
260
254
  }
261
255
  function handleShorthandAutoFix(declarationNode, context, valueText, replacements) {
262
- const sortedReplacements = replacements.sort((a, b) => a.start - b.start);
263
- const hasAnyHooks = sortedReplacements.some((r) => r.hasHook);
264
- const canAutoFix = hasAnyHooks;
265
- sortedReplacements.forEach(({ start, end, replacement, displayValue, hasHook }) => {
256
+ if (!replacements || replacements.length === 0) {
257
+ return;
258
+ }
259
+ const sortedReplacements = replacements.sort((a, b) => b.start - a.start);
260
+ const reportNumericValue = context.options?.reportNumericValue || "always";
261
+ const fixCallback = (start, originalValue, replacement) => {
262
+ let newValue = valueText;
263
+ newValue = newValue.substring(0, start) + replacement + newValue.substring(start + originalValue.length);
264
+ if (newValue !== valueText) {
265
+ return (fixer) => {
266
+ return fixer.replaceText(declarationNode.value, newValue);
267
+ };
268
+ }
269
+ };
270
+ sortedReplacements.forEach(({ start, end, replacement, displayValue, hasHook, isNumeric }) => {
266
271
  const originalValue = valueText.substring(start, end);
267
- const valueStartColumn = declarationNode.value.loc.start.column;
268
- const valueColumn = valueStartColumn + start;
272
+ if (isNumeric) {
273
+ if (reportNumericValue === "never") {
274
+ return;
275
+ }
276
+ if (reportNumericValue === "hasReplacement" && !hasHook) {
277
+ return;
278
+ }
279
+ }
280
+ const valueColumnStart = declarationNode.value.loc.start.column + start;
281
+ const valueColumnEnd = valueColumnStart + originalValue.length;
282
+ const canAutoFix = originalValue !== replacement;
269
283
  const { loc: { start: locStart, end: locEnd } } = declarationNode.value;
270
284
  const reportNode = {
271
285
  ...declarationNode.value,
@@ -273,23 +287,16 @@ function handleShorthandAutoFix(declarationNode, context, valueText, replacement
273
287
  ...declarationNode.value.loc,
274
288
  start: {
275
289
  ...locStart,
276
- column: valueColumn
290
+ column: valueColumnStart
277
291
  },
278
292
  end: {
279
293
  ...locEnd,
280
- column: valueColumn + originalValue.length
294
+ column: valueColumnEnd
281
295
  }
282
296
  }
283
297
  };
284
298
  if (hasHook) {
285
- const fix = canAutoFix ? (fixer) => {
286
- let newValue = valueText;
287
- for (let i = sortedReplacements.length - 1; i >= 0; i--) {
288
- const { start: rStart, end: rEnd, replacement: rReplacement } = sortedReplacements[i];
289
- newValue = newValue.substring(0, rStart) + rReplacement + newValue.substring(rEnd);
290
- }
291
- return fixer.replaceText(declarationNode.value, newValue);
292
- } : void 0;
299
+ const fix = canAutoFix ? fixCallback(start, originalValue, replacement) : void 0;
293
300
  context.context.report({
294
301
  node: reportNode,
295
302
  messageId: "hardcodedValue",
@@ -443,6 +450,41 @@ function formatSuggestionHooks(hooks) {
443
450
  return "\n" + hooks.map((hook, index) => `${index + 1}. ${hook}`).join("\n");
444
451
  }
445
452
 
453
+ // src/utils/custom-mapping-utils.ts
454
+ function matchesPropertyPattern(cssProperty, pattern) {
455
+ const normalizedProperty = cssProperty.toLowerCase();
456
+ const normalizedPattern = pattern.toLowerCase();
457
+ if (normalizedProperty === normalizedPattern) {
458
+ return true;
459
+ }
460
+ if (normalizedPattern.endsWith("*")) {
461
+ const prefix = normalizedPattern.slice(0, -1);
462
+ return normalizedProperty.startsWith(prefix);
463
+ }
464
+ return false;
465
+ }
466
+ function getCustomMapping(cssProperty, value, customMapping) {
467
+ if (!customMapping) {
468
+ return null;
469
+ }
470
+ const normalizedValue = value.toLowerCase().trim();
471
+ for (const [hookName, config] of Object.entries(customMapping)) {
472
+ const propertyMatches = config.properties.some(
473
+ (pattern) => matchesPropertyPattern(cssProperty, pattern)
474
+ );
475
+ if (!propertyMatches) {
476
+ continue;
477
+ }
478
+ const valueMatches = config.values.some(
479
+ (configValue) => configValue.toLowerCase().trim() === normalizedValue
480
+ );
481
+ if (valueMatches) {
482
+ return hookName;
483
+ }
484
+ }
485
+ return null;
486
+ }
487
+
446
488
  // src/rules/v9/no-hardcoded-values/handlers/colorHandler.ts
447
489
  var handleColorDeclaration = (node, context) => {
448
490
  const cssProperty = node.property.toLowerCase();
@@ -466,24 +508,32 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
466
508
  if (!hexValue) {
467
509
  return null;
468
510
  }
469
- const propToMatch = resolvePropertyToMatch(cssProperty);
470
- const closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
471
511
  const start = positionInfo.start.offset;
472
512
  const end = positionInfo.end.offset;
473
513
  const originalValue = originalValueText ? originalValueText.substring(start, end) : colorValue;
474
- if (closestHooks.length === 1) {
475
- return {
476
- start,
477
- end,
478
- replacement: `var(${closestHooks[0]}, ${colorValue})`,
479
- displayValue: closestHooks[0],
480
- hasHook: true
481
- };
482
- } else if (closestHooks.length > 1) {
514
+ const customHook = getCustomMapping(cssProperty, colorValue, context.options?.customMapping);
515
+ let closestHooks = [];
516
+ if (customHook) {
517
+ closestHooks = [customHook];
518
+ } else {
519
+ const propToMatch = resolveColorPropertyToMatch(cssProperty);
520
+ closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
521
+ }
522
+ let replacement = originalValue;
523
+ let paletteHook = null;
524
+ if (context.options?.preferPaletteHook && closestHooks.length > 1) {
525
+ paletteHook = closestHooks.filter((hook) => hook.includes("-palette-"))[0];
526
+ }
527
+ if (paletteHook) {
528
+ replacement = `var(${paletteHook}, ${colorValue})`;
529
+ } else if (closestHooks.length === 1) {
530
+ replacement = `var(${closestHooks[0]}, ${colorValue})`;
531
+ }
532
+ if (closestHooks.length > 0) {
483
533
  return {
484
534
  start,
485
535
  end,
486
- replacement: originalValue,
536
+ replacement,
487
537
  // Use original value to preserve spacing
488
538
  displayValue: formatSuggestionHooks(closestHooks),
489
539
  hasHook: true
@@ -492,7 +542,7 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
492
542
  return {
493
543
  start,
494
544
  end,
495
- replacement: originalValue,
545
+ replacement,
496
546
  // Use original value to preserve spacing
497
547
  displayValue: originalValue,
498
548
  hasHook: false
@@ -540,8 +590,14 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
540
590
  return null;
541
591
  }
542
592
  const rawValue = parsedDimension.unit ? `${parsedDimension.number}${parsedDimension.unit}` : parsedDimension.number.toString();
543
- const propToMatch = resolvePropertyToMatch(cssProperty);
544
- const closestHooks = getStylingHooksForDensityValue(parsedDimension, context.valueToStylinghook, propToMatch);
593
+ const customHook = getCustomMapping(cssProperty, rawValue, context.options?.customMapping);
594
+ let closestHooks = [];
595
+ if (customHook) {
596
+ closestHooks = [customHook];
597
+ } else {
598
+ const propToMatch = resolveDensityPropertyToMatch(cssProperty);
599
+ closestHooks = getStylingHooksForDensityValue(parsedDimension, context.valueToStylinghook, propToMatch);
600
+ }
545
601
  const start = positionInfo.start.offset;
546
602
  const end = positionInfo.end.offset;
547
603
  if (closestHooks.length === 1) {
@@ -550,7 +606,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
550
606
  end,
551
607
  replacement: `var(${closestHooks[0]}, ${rawValue})`,
552
608
  displayValue: closestHooks[0],
553
- hasHook: true
609
+ hasHook: true,
610
+ isNumeric: true
554
611
  };
555
612
  } else if (closestHooks.length > 1) {
556
613
  return {
@@ -558,7 +615,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
558
615
  end,
559
616
  replacement: rawValue,
560
617
  displayValue: formatSuggestionHooks(closestHooks),
561
- hasHook: true
618
+ hasHook: true,
619
+ isNumeric: true
562
620
  };
563
621
  } else {
564
622
  return {
@@ -566,7 +624,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
566
624
  end,
567
625
  replacement: rawValue,
568
626
  displayValue: rawValue,
569
- hasHook: false
627
+ hasHook: false,
628
+ isNumeric: true
570
629
  };
571
630
  }
572
631
  }
@@ -607,8 +666,14 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
607
666
  return null;
608
667
  }
609
668
  const rawValue = fontValue.unit ? `${fontValue.number}${fontValue.unit}` : fontValue.number.toString();
610
- const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ? resolvePropertyToMatch("font-weight") : resolvePropertyToMatch("font-size");
611
- const closestHooks = getStylingHooksForDensityValue(fontValue, context.valueToStylinghook, propToMatch);
669
+ const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ? "font-weight" : "font-size";
670
+ const customHook = getCustomMapping(propToMatch, rawValue, context.options?.customMapping);
671
+ let closestHooks = [];
672
+ if (customHook) {
673
+ closestHooks = [customHook];
674
+ } else {
675
+ closestHooks = getStylingHooksForDensityValue(fontValue, context.valueToStylinghook, propToMatch);
676
+ }
612
677
  const start = positionInfo.start.offset;
613
678
  const end = positionInfo.end.offset;
614
679
  if (closestHooks.length === 1) {
@@ -617,7 +682,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
617
682
  end,
618
683
  replacement: `var(${closestHooks[0]}, ${rawValue})`,
619
684
  displayValue: closestHooks[0],
620
- hasHook: true
685
+ hasHook: true,
686
+ isNumeric: true
621
687
  };
622
688
  } else if (closestHooks.length > 1) {
623
689
  return {
@@ -625,7 +691,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
625
691
  end,
626
692
  replacement: rawValue,
627
693
  displayValue: formatSuggestionHooks(closestHooks),
628
- hasHook: true
694
+ hasHook: true,
695
+ isNumeric: true
629
696
  };
630
697
  } else {
631
698
  return {
@@ -633,7 +700,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
633
700
  end,
634
701
  replacement: rawValue,
635
702
  displayValue: rawValue,
636
- hasHook: false
703
+ hasHook: false,
704
+ isNumeric: true
637
705
  };
638
706
  }
639
707
  }
@@ -765,9 +833,30 @@ function shadowValueToHookEntries(supportedStylinghooks) {
765
833
  return [key, value.map((hook) => hook.name)];
766
834
  });
767
835
  }
836
+ function reportBoxShadowViolation(node, context, valueText, hooks) {
837
+ const positionInfo = {
838
+ start: { offset: 0, line: 1, column: 1 },
839
+ end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
840
+ };
841
+ const replacement = createBoxShadowReplacement(
842
+ valueText,
843
+ hooks,
844
+ context,
845
+ positionInfo
846
+ );
847
+ if (replacement) {
848
+ const replacements = [replacement];
849
+ handleShorthandAutoFix(node, context, valueText, replacements);
850
+ }
851
+ }
768
852
  var handleBoxShadowDeclaration = (node, context) => {
769
853
  const cssProperty = node.property.toLowerCase();
770
854
  const valueText = context.sourceCode.getText(node.value);
855
+ const customHook = getCustomMapping(cssProperty, valueText, context.options?.customMapping);
856
+ if (customHook) {
857
+ reportBoxShadowViolation(node, context, valueText, [customHook]);
858
+ return;
859
+ }
771
860
  const shadowHooks = shadowValueToHookEntries(context.valueToStylinghook);
772
861
  const parsedCssValue = toBoxShadowValue(valueText);
773
862
  if (!parsedCssValue) {
@@ -777,20 +866,7 @@ var handleBoxShadowDeclaration = (node, context) => {
777
866
  const parsedValueHook = toBoxShadowValue(shadow);
778
867
  if (parsedValueHook && isBoxShadowMatch(parsedCssValue, parsedValueHook)) {
779
868
  if (closestHooks.length > 0) {
780
- const positionInfo = {
781
- start: { offset: 0, line: 1, column: 1 },
782
- end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
783
- };
784
- const replacement = createBoxShadowReplacement(
785
- valueText,
786
- closestHooks,
787
- context,
788
- positionInfo
789
- );
790
- if (replacement) {
791
- const replacements = [replacement];
792
- handleShorthandAutoFix(node, context, valueText, replacements);
793
- }
869
+ reportBoxShadowViolation(node, context, valueText, closestHooks);
794
870
  }
795
871
  return;
796
872
  }