@salesforce-ux/eslint-plugin-slds 1.0.7-internal → 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.
- package/README.md +62 -0
- package/build/index.js +240 -104
- package/build/index.js.map +3 -3
- package/build/rules/v9/lwc-token-to-slds-hook.js.map +2 -2
- package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js +86 -30
- package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js +116 -104
- package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js +83 -30
- package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js +78 -74
- package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/handlers/index.js +175 -99
- package/build/rules/v9/no-hardcoded-values/handlers/index.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js +221 -101
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js +221 -101
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js +221 -101
- package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js.map +3 -3
- package/build/rules/v9/no-hardcoded-values/ruleOptionsSchema.js +63 -0
- package/build/rules/v9/no-hardcoded-values/ruleOptionsSchema.js.map +7 -0
- package/build/rules/v9/no-slds-namespace-for-custom-hooks.js.map +2 -2
- package/build/rules/v9/no-slds-var-without-fallback.js.map +2 -2
- package/build/src/rules/v9/no-hardcoded-values/ruleOptionsSchema.d.ts +40 -0
- package/build/src/types/index.d.ts +31 -0
- package/build/src/utils/color-lib-utils.d.ts +16 -9
- package/build/src/utils/custom-mapping-utils.d.ts +9 -0
- package/build/src/utils/hardcoded-shared-utils.d.ts +1 -0
- package/build/src/utils/property-matcher.d.ts +3 -1
- package/build/types/index.js.map +1 -1
- package/build/utils/boxShadowValueParser.js.map +2 -2
- package/build/utils/color-lib-utils.js +26 -50
- package/build/utils/color-lib-utils.js.map +2 -2
- package/build/utils/css-utils.js.map +2 -2
- package/build/utils/custom-mapping-utils.js +62 -0
- package/build/utils/custom-mapping-utils.js.map +7 -0
- package/build/utils/hardcoded-shared-utils.js +29 -16
- package/build/utils/hardcoded-shared-utils.js.map +2 -2
- package/build/utils/property-matcher.js +20 -6
- package/build/utils/property-matcher.js.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -96,6 +96,68 @@ By default, the latest version of the plugin supports legacy and flat config sys
|
|
|
96
96
|
- `reduce-annotations`: Identifies annotations that must be removed from the code.
|
|
97
97
|
- `lwc-token-to-slds-hook`: Identifies the deprecated --lwc tokens that must be replaced with the latest --slds tokens. For more information, see lightningdesignsystem.com.
|
|
98
98
|
|
|
99
|
+
## Closest Color Suggestion Logic
|
|
100
|
+
|
|
101
|
+
This plugin suggests SLDS styling hooks that are perceptually closest to a given hardcoded color. The logic lives in `src/utils/color-lib-utils.ts` and is used by `no-hardcoded-values-slds2`.
|
|
102
|
+
|
|
103
|
+
- **API surface**
|
|
104
|
+
- `findClosestColorHook(color, supportedColors, cssProperty): string[]`
|
|
105
|
+
Returns up to 5 hook names, ordered by category priority and perceptual distance.
|
|
106
|
+
- `isHardCodedColor(value): boolean`
|
|
107
|
+
Detects if a string likely represents a hardcoded color (excludes CSS `var(...)`).
|
|
108
|
+
|
|
109
|
+
- **Perceptual metric**
|
|
110
|
+
- Uses `chroma.deltaE` (CIEDE2000) to compare the input color against known SLDS color values.
|
|
111
|
+
- A threshold (`DELTAE_THRESHOLD = 25`) controls how strict the matching is.
|
|
112
|
+
- Exact hex matches short-circuit to distance `0` to avoid float rounding differences.
|
|
113
|
+
|
|
114
|
+
- **Category ordering**
|
|
115
|
+
- Hooks are ranked by category, then by distance (ascending):
|
|
116
|
+
1. Semantic hooks (e.g., surface, accent, error, success, etc.)
|
|
117
|
+
2. System hooks
|
|
118
|
+
3. Palette hooks
|
|
119
|
+
- Only the top 5 suggestions are returned.
|
|
120
|
+
|
|
121
|
+
- **Property awareness**
|
|
122
|
+
- Suggestions consider the CSS property from rule context.
|
|
123
|
+
- Hooks declared for the same property (or `*`) are prioritized if within the distance threshold.
|
|
124
|
+
|
|
125
|
+
- **CSS variables**
|
|
126
|
+
- Values using `var(...)` are not flagged as hardcoded colors and are excluded from matching.
|
|
127
|
+
|
|
128
|
+
- **Semantic hook ordering by CSS property**
|
|
129
|
+
The sorter always applies the same category priority (semantic → system → palette). Within the semantic category, ordering is purely by perceptual distance for the current CSS property; there is no hardcoded sub-priority among semantic families (surface, accent, error, etc.). Property awareness comes from the metadata (`properties` on each hook).
|
|
130
|
+
|
|
131
|
+
- `color`
|
|
132
|
+
- Prefers semantic hooks that declare `properties: ['color']` (e.g., text/foreground-oriented tokens).
|
|
133
|
+
- If multiple semantic hooks are eligible, they are ordered by Delta E (closest first).
|
|
134
|
+
- If none are within threshold, the sorter may fall back to system, then palette.
|
|
135
|
+
|
|
136
|
+
- `background-color`
|
|
137
|
+
- Prefers semantic surface/role tokens that declare `['background-color']`.
|
|
138
|
+
- Among eligible semantic hooks, order is by Delta E.
|
|
139
|
+
|
|
140
|
+
- `border-color` (and `outline-color`)
|
|
141
|
+
- Prefers semantic or system hooks that declare `['border-color']` (or `['outline-color']`).
|
|
142
|
+
- If semantic hooks exist for borders, they are ranked before system; otherwise system hooks lead.
|
|
143
|
+
- Order within the chosen category is by Delta E.
|
|
144
|
+
|
|
145
|
+
- `box-shadow`
|
|
146
|
+
- For color components inside shadows, prefers hooks declaring `['box-shadow']` or universal `['*']`.
|
|
147
|
+
- Ordering within semantic remains by Delta E.
|
|
148
|
+
|
|
149
|
+
- Other properties
|
|
150
|
+
- If hook metadata specifies the current property, those hooks are preferred.
|
|
151
|
+
- Hooks with `['*']` (universal) are considered next.
|
|
152
|
+
- If still none within threshold, different-property hooks may be considered (still subject to category priority and Delta E).
|
|
153
|
+
|
|
154
|
+
- **Example**
|
|
155
|
+
```js
|
|
156
|
+
// Given a hex color and a CSS property like 'color'
|
|
157
|
+
const suggestions = findClosestColorHook('#ff0000', supportedColors, 'color');
|
|
158
|
+
// => ['--slds-...semantic-...', '--slds-...system-...', ...]
|
|
159
|
+
```
|
|
160
|
+
|
|
99
161
|
## License
|
|
100
162
|
|
|
101
163
|
ISC
|
package/build/index.js
CHANGED
|
@@ -780,11 +780,7 @@ function isCssColorFunction(value) {
|
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
// src/utils/color-lib-utils.ts
|
|
783
|
-
var
|
|
784
|
-
var isHexCode = (color) => {
|
|
785
|
-
const hexPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
|
|
786
|
-
return hexPattern.test(color);
|
|
787
|
-
};
|
|
783
|
+
var DELTAE_THRESHOLD = 10;
|
|
788
784
|
var convertToHex = (color) => {
|
|
789
785
|
try {
|
|
790
786
|
return (0, import_chroma_js.default)(color).hex();
|
|
@@ -792,52 +788,40 @@ var convertToHex = (color) => {
|
|
|
792
788
|
return null;
|
|
793
789
|
}
|
|
794
790
|
};
|
|
791
|
+
var isHookPropertyMatch = (hook, cssProperty) => {
|
|
792
|
+
return hook.properties.includes(cssProperty) || hook.properties.includes("*");
|
|
793
|
+
};
|
|
794
|
+
function getOrderByCssProp(cssProperty) {
|
|
795
|
+
if (cssProperty === "color" || cssProperty === "fill") {
|
|
796
|
+
return ["surface", "theme", "feedback", "reference"];
|
|
797
|
+
} else if (cssProperty.match(/background/)) {
|
|
798
|
+
return ["surface", "surface-inverse", "theme", "feedback", "reference"];
|
|
799
|
+
} else if (cssProperty.match(/border/) || cssProperty.match(/outline/) || cssProperty.match(/stroke/)) {
|
|
800
|
+
return ["borders", "borders-inverse", "feedback", "theme", "reference"];
|
|
801
|
+
}
|
|
802
|
+
return ["surface", "surface-inverse", "borders", "borders-inverse", "theme", "feedback", "reference"];
|
|
803
|
+
}
|
|
795
804
|
var findClosestColorHook = (color, supportedColors, cssProperty) => {
|
|
796
|
-
const
|
|
797
|
-
const closestHooksWithSameProperty = [];
|
|
798
|
-
const closestHooksWithoutSameProperty = [];
|
|
799
|
-
const closestHooksWithAllProperty = [];
|
|
800
|
-
const labColor = (0, import_chroma_js.default)(color).lab();
|
|
805
|
+
const closestHooks = [];
|
|
801
806
|
Object.entries(supportedColors).forEach(([sldsValue, data]) => {
|
|
802
|
-
if (sldsValue &&
|
|
807
|
+
if (sldsValue && isValidColor(sldsValue)) {
|
|
803
808
|
const hooks = data;
|
|
804
809
|
hooks.forEach((hook) => {
|
|
805
|
-
const
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (distance <= LAB_THRESHOLD) {
|
|
809
|
-
closestHooksWithSameProperty.push({ name: hook.name, distance });
|
|
810
|
-
}
|
|
811
|
-
} else if (hook.properties.includes("*")) {
|
|
812
|
-
if (distance <= LAB_THRESHOLD) {
|
|
813
|
-
closestHooksWithAllProperty.push({ name: hook.name, distance });
|
|
814
|
-
}
|
|
815
|
-
} else {
|
|
816
|
-
if (distance <= LAB_THRESHOLD) {
|
|
817
|
-
closestHooksWithoutSameProperty.push({ name: hook.name, distance });
|
|
818
|
-
}
|
|
810
|
+
const distance = sldsValue.toLowerCase() === color.toLowerCase() ? 0 : import_chroma_js.default.deltaE(sldsValue, color);
|
|
811
|
+
if (isHookPropertyMatch(hook, cssProperty) && distance <= DELTAE_THRESHOLD) {
|
|
812
|
+
closestHooks.push({ distance, group: hook.group, name: hook.name });
|
|
819
813
|
}
|
|
820
814
|
});
|
|
821
815
|
}
|
|
822
816
|
});
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
{ hooks: closestHooksWithSameProperty, distance: Infinity },
|
|
827
|
-
// For hooks with distance > 0
|
|
828
|
-
{ hooks: closestHooksWithAllProperty, distance: Infinity },
|
|
829
|
-
{ hooks: closestHooksWithoutSameProperty, distance: Infinity }
|
|
830
|
-
];
|
|
831
|
-
for (const group of closesthookGroups) {
|
|
832
|
-
const filteredHooks = group.hooks.filter(
|
|
833
|
-
(h) => group.distance === 0 ? h.distance === 0 : h.distance > 0
|
|
834
|
-
);
|
|
835
|
-
if (returnStylingHooks.length < 1 && filteredHooks.length > 0) {
|
|
836
|
-
filteredHooks.sort((a, b) => a.distance - b.distance);
|
|
837
|
-
returnStylingHooks.push(...filteredHooks.slice(0, 5).map((h) => h.name));
|
|
817
|
+
const hooksByGroupMap = closestHooks.sort((a, b) => a.distance - b.distance).reduce((acc, hook) => {
|
|
818
|
+
if (!acc[hook.group]) {
|
|
819
|
+
acc[hook.group] = [];
|
|
838
820
|
}
|
|
839
|
-
|
|
840
|
-
|
|
821
|
+
acc[hook.group].push(hook.name);
|
|
822
|
+
return acc;
|
|
823
|
+
}, {});
|
|
824
|
+
return getOrderByCssProp(cssProperty).map((group) => hooksByGroupMap[group] || []).flat().slice(0, 5);
|
|
841
825
|
};
|
|
842
826
|
var isValidColor = (val) => import_chroma_js.default.valid(val);
|
|
843
827
|
var extractColorValue = (node) => {
|
|
@@ -879,13 +863,33 @@ function isKnownFontWeight(value) {
|
|
|
879
863
|
return FONT_WEIGHTS.includes(stringValue.toLowerCase());
|
|
880
864
|
}
|
|
881
865
|
function handleShorthandAutoFix(declarationNode, context, valueText, replacements) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
sortedReplacements.
|
|
866
|
+
if (!replacements || replacements.length === 0) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const sortedReplacements = replacements.sort((a, b) => b.start - a.start);
|
|
870
|
+
const reportNumericValue = context.options?.reportNumericValue || "always";
|
|
871
|
+
const fixCallback = (start, originalValue, replacement) => {
|
|
872
|
+
let newValue = valueText;
|
|
873
|
+
newValue = newValue.substring(0, start) + replacement + newValue.substring(start + originalValue.length);
|
|
874
|
+
if (newValue !== valueText) {
|
|
875
|
+
return (fixer) => {
|
|
876
|
+
return fixer.replaceText(declarationNode.value, newValue);
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
sortedReplacements.forEach(({ start, end, replacement, displayValue, hasHook, isNumeric }) => {
|
|
886
881
|
const originalValue = valueText.substring(start, end);
|
|
887
|
-
|
|
888
|
-
|
|
882
|
+
if (isNumeric) {
|
|
883
|
+
if (reportNumericValue === "never") {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
if (reportNumericValue === "hasReplacement" && !hasHook) {
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
const valueColumnStart = declarationNode.value.loc.start.column + start;
|
|
891
|
+
const valueColumnEnd = valueColumnStart + originalValue.length;
|
|
892
|
+
const canAutoFix = originalValue !== replacement;
|
|
889
893
|
const { loc: { start: locStart, end: locEnd } } = declarationNode.value;
|
|
890
894
|
const reportNode = {
|
|
891
895
|
...declarationNode.value,
|
|
@@ -893,23 +897,16 @@ function handleShorthandAutoFix(declarationNode, context, valueText, replacement
|
|
|
893
897
|
...declarationNode.value.loc,
|
|
894
898
|
start: {
|
|
895
899
|
...locStart,
|
|
896
|
-
column:
|
|
900
|
+
column: valueColumnStart
|
|
897
901
|
},
|
|
898
902
|
end: {
|
|
899
903
|
...locEnd,
|
|
900
|
-
column:
|
|
904
|
+
column: valueColumnEnd
|
|
901
905
|
}
|
|
902
906
|
}
|
|
903
907
|
};
|
|
904
908
|
if (hasHook) {
|
|
905
|
-
const fix = canAutoFix ? (
|
|
906
|
-
let newValue = valueText;
|
|
907
|
-
for (let i = sortedReplacements.length - 1; i >= 0; i--) {
|
|
908
|
-
const { start: rStart, end: rEnd, replacement: rReplacement } = sortedReplacements[i];
|
|
909
|
-
newValue = newValue.substring(0, rStart) + rReplacement + newValue.substring(rEnd);
|
|
910
|
-
}
|
|
911
|
-
return fixer.replaceText(declarationNode.value, newValue);
|
|
912
|
-
} : void 0;
|
|
909
|
+
const fix = canAutoFix ? fixCallback(start, originalValue, replacement) : void 0;
|
|
913
910
|
context.context.report({
|
|
914
911
|
node: reportNode,
|
|
915
912
|
messageId: "hardcodedValue",
|
|
@@ -1790,9 +1787,9 @@ function toSelector(properties) {
|
|
|
1790
1787
|
});
|
|
1791
1788
|
return selectorParts.join(", ");
|
|
1792
1789
|
}
|
|
1793
|
-
function
|
|
1790
|
+
function resolveDensityPropertyToMatch(cssProperty) {
|
|
1794
1791
|
const propertyToMatch = cssProperty.toLowerCase();
|
|
1795
|
-
if (propertyToMatch
|
|
1792
|
+
if (isOutlineWidthProperty(propertyToMatch) || isBorderWidthProperty(propertyToMatch)) {
|
|
1796
1793
|
return "border-width";
|
|
1797
1794
|
} else if (isMarginProperty(propertyToMatch)) {
|
|
1798
1795
|
return "margin";
|
|
@@ -1804,13 +1801,58 @@ function resolvePropertyToMatch(cssProperty) {
|
|
|
1804
1801
|
return "width";
|
|
1805
1802
|
} else if (isInsetProperty(propertyToMatch)) {
|
|
1806
1803
|
return "top";
|
|
1807
|
-
}
|
|
1804
|
+
}
|
|
1805
|
+
return propertyToMatch;
|
|
1806
|
+
}
|
|
1807
|
+
function resolveColorPropertyToMatch(cssProperty) {
|
|
1808
|
+
const propertyToMatch = cssProperty.toLowerCase();
|
|
1809
|
+
if (propertyToMatch === "outline" || propertyToMatch === "outline-color") {
|
|
1810
|
+
return "border-color";
|
|
1811
|
+
} else if (propertyToMatch === "background" || propertyToMatch === "background-color") {
|
|
1808
1812
|
return "background-color";
|
|
1809
|
-
} else if (
|
|
1813
|
+
} else if (isBorderColorProperty(propertyToMatch)) {
|
|
1810
1814
|
return "border-color";
|
|
1811
1815
|
}
|
|
1812
1816
|
return propertyToMatch;
|
|
1813
1817
|
}
|
|
1818
|
+
function isOutlineWidthProperty(propertyToMatch) {
|
|
1819
|
+
return propertyToMatch === "outline" || propertyToMatch === "outline-width";
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// src/utils/custom-mapping-utils.ts
|
|
1823
|
+
function matchesPropertyPattern(cssProperty, pattern) {
|
|
1824
|
+
const normalizedProperty = cssProperty.toLowerCase();
|
|
1825
|
+
const normalizedPattern = pattern.toLowerCase();
|
|
1826
|
+
if (normalizedProperty === normalizedPattern) {
|
|
1827
|
+
return true;
|
|
1828
|
+
}
|
|
1829
|
+
if (normalizedPattern.endsWith("*")) {
|
|
1830
|
+
const prefix = normalizedPattern.slice(0, -1);
|
|
1831
|
+
return normalizedProperty.startsWith(prefix);
|
|
1832
|
+
}
|
|
1833
|
+
return false;
|
|
1834
|
+
}
|
|
1835
|
+
function getCustomMapping(cssProperty, value, customMapping) {
|
|
1836
|
+
if (!customMapping) {
|
|
1837
|
+
return null;
|
|
1838
|
+
}
|
|
1839
|
+
const normalizedValue = value.toLowerCase().trim();
|
|
1840
|
+
for (const [hookName, config] of Object.entries(customMapping)) {
|
|
1841
|
+
const propertyMatches = config.properties.some(
|
|
1842
|
+
(pattern) => matchesPropertyPattern(cssProperty, pattern)
|
|
1843
|
+
);
|
|
1844
|
+
if (!propertyMatches) {
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
const valueMatches = config.values.some(
|
|
1848
|
+
(configValue) => configValue.toLowerCase().trim() === normalizedValue
|
|
1849
|
+
);
|
|
1850
|
+
if (valueMatches) {
|
|
1851
|
+
return hookName;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
return null;
|
|
1855
|
+
}
|
|
1814
1856
|
|
|
1815
1857
|
// src/rules/v9/no-hardcoded-values/handlers/colorHandler.ts
|
|
1816
1858
|
var handleColorDeclaration = (node, context) => {
|
|
@@ -1835,24 +1877,32 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
|
|
|
1835
1877
|
if (!hexValue) {
|
|
1836
1878
|
return null;
|
|
1837
1879
|
}
|
|
1838
|
-
const propToMatch = resolvePropertyToMatch(cssProperty);
|
|
1839
|
-
const closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
|
|
1840
1880
|
const start = positionInfo.start.offset;
|
|
1841
1881
|
const end = positionInfo.end.offset;
|
|
1842
1882
|
const originalValue = originalValueText ? originalValueText.substring(start, end) : colorValue;
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1883
|
+
const customHook = getCustomMapping(cssProperty, colorValue, context.options?.customMapping);
|
|
1884
|
+
let closestHooks = [];
|
|
1885
|
+
if (customHook) {
|
|
1886
|
+
closestHooks = [customHook];
|
|
1887
|
+
} else {
|
|
1888
|
+
const propToMatch = resolveColorPropertyToMatch(cssProperty);
|
|
1889
|
+
closestHooks = findClosestColorHook(hexValue, context.valueToStylinghook, propToMatch);
|
|
1890
|
+
}
|
|
1891
|
+
let replacement = originalValue;
|
|
1892
|
+
let paletteHook = null;
|
|
1893
|
+
if (context.options?.preferPaletteHook && closestHooks.length > 1) {
|
|
1894
|
+
paletteHook = closestHooks.filter((hook) => hook.includes("-palette-"))[0];
|
|
1895
|
+
}
|
|
1896
|
+
if (paletteHook) {
|
|
1897
|
+
replacement = `var(${paletteHook}, ${colorValue})`;
|
|
1898
|
+
} else if (closestHooks.length === 1) {
|
|
1899
|
+
replacement = `var(${closestHooks[0]}, ${colorValue})`;
|
|
1900
|
+
}
|
|
1901
|
+
if (closestHooks.length > 0) {
|
|
1852
1902
|
return {
|
|
1853
1903
|
start,
|
|
1854
1904
|
end,
|
|
1855
|
-
replacement
|
|
1905
|
+
replacement,
|
|
1856
1906
|
// Use original value to preserve spacing
|
|
1857
1907
|
displayValue: formatSuggestionHooks(closestHooks),
|
|
1858
1908
|
hasHook: true
|
|
@@ -1861,7 +1911,7 @@ function createColorReplacement(colorValue, cssProperty, context, positionInfo,
|
|
|
1861
1911
|
return {
|
|
1862
1912
|
start,
|
|
1863
1913
|
end,
|
|
1864
|
-
replacement
|
|
1914
|
+
replacement,
|
|
1865
1915
|
// Use original value to preserve spacing
|
|
1866
1916
|
displayValue: originalValue,
|
|
1867
1917
|
hasHook: false
|
|
@@ -1909,8 +1959,14 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
|
|
|
1909
1959
|
return null;
|
|
1910
1960
|
}
|
|
1911
1961
|
const rawValue = parsedDimension.unit ? `${parsedDimension.number}${parsedDimension.unit}` : parsedDimension.number.toString();
|
|
1912
|
-
const
|
|
1913
|
-
|
|
1962
|
+
const customHook = getCustomMapping(cssProperty, rawValue, context.options?.customMapping);
|
|
1963
|
+
let closestHooks = [];
|
|
1964
|
+
if (customHook) {
|
|
1965
|
+
closestHooks = [customHook];
|
|
1966
|
+
} else {
|
|
1967
|
+
const propToMatch = resolveDensityPropertyToMatch(cssProperty);
|
|
1968
|
+
closestHooks = getStylingHooksForDensityValue(parsedDimension, context.valueToStylinghook, propToMatch);
|
|
1969
|
+
}
|
|
1914
1970
|
const start = positionInfo.start.offset;
|
|
1915
1971
|
const end = positionInfo.end.offset;
|
|
1916
1972
|
if (closestHooks.length === 1) {
|
|
@@ -1919,7 +1975,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
|
|
|
1919
1975
|
end,
|
|
1920
1976
|
replacement: `var(${closestHooks[0]}, ${rawValue})`,
|
|
1921
1977
|
displayValue: closestHooks[0],
|
|
1922
|
-
hasHook: true
|
|
1978
|
+
hasHook: true,
|
|
1979
|
+
isNumeric: true
|
|
1923
1980
|
};
|
|
1924
1981
|
} else if (closestHooks.length > 1) {
|
|
1925
1982
|
return {
|
|
@@ -1927,7 +1984,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
|
|
|
1927
1984
|
end,
|
|
1928
1985
|
replacement: rawValue,
|
|
1929
1986
|
displayValue: formatSuggestionHooks(closestHooks),
|
|
1930
|
-
hasHook: true
|
|
1987
|
+
hasHook: true,
|
|
1988
|
+
isNumeric: true
|
|
1931
1989
|
};
|
|
1932
1990
|
} else {
|
|
1933
1991
|
return {
|
|
@@ -1935,7 +1993,8 @@ function createDimensionReplacement(parsedDimension, cssProperty, context, posit
|
|
|
1935
1993
|
end,
|
|
1936
1994
|
replacement: rawValue,
|
|
1937
1995
|
displayValue: rawValue,
|
|
1938
|
-
hasHook: false
|
|
1996
|
+
hasHook: false,
|
|
1997
|
+
isNumeric: true
|
|
1939
1998
|
};
|
|
1940
1999
|
}
|
|
1941
2000
|
}
|
|
@@ -1976,8 +2035,14 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
|
|
|
1976
2035
|
return null;
|
|
1977
2036
|
}
|
|
1978
2037
|
const rawValue = fontValue.unit ? `${fontValue.number}${fontValue.unit}` : fontValue.number.toString();
|
|
1979
|
-
const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ?
|
|
1980
|
-
const
|
|
2038
|
+
const propToMatch = !fontValue.unit && isKnownFontWeight(fontValue.number) ? "font-weight" : "font-size";
|
|
2039
|
+
const customHook = getCustomMapping(propToMatch, rawValue, context.options?.customMapping);
|
|
2040
|
+
let closestHooks = [];
|
|
2041
|
+
if (customHook) {
|
|
2042
|
+
closestHooks = [customHook];
|
|
2043
|
+
} else {
|
|
2044
|
+
closestHooks = getStylingHooksForDensityValue(fontValue, context.valueToStylinghook, propToMatch);
|
|
2045
|
+
}
|
|
1981
2046
|
const start = positionInfo.start.offset;
|
|
1982
2047
|
const end = positionInfo.end.offset;
|
|
1983
2048
|
if (closestHooks.length === 1) {
|
|
@@ -1986,7 +2051,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
|
|
|
1986
2051
|
end,
|
|
1987
2052
|
replacement: `var(${closestHooks[0]}, ${rawValue})`,
|
|
1988
2053
|
displayValue: closestHooks[0],
|
|
1989
|
-
hasHook: true
|
|
2054
|
+
hasHook: true,
|
|
2055
|
+
isNumeric: true
|
|
1990
2056
|
};
|
|
1991
2057
|
} else if (closestHooks.length > 1) {
|
|
1992
2058
|
return {
|
|
@@ -1994,7 +2060,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
|
|
|
1994
2060
|
end,
|
|
1995
2061
|
replacement: rawValue,
|
|
1996
2062
|
displayValue: formatSuggestionHooks(closestHooks),
|
|
1997
|
-
hasHook: true
|
|
2063
|
+
hasHook: true,
|
|
2064
|
+
isNumeric: true
|
|
1998
2065
|
};
|
|
1999
2066
|
} else {
|
|
2000
2067
|
return {
|
|
@@ -2002,7 +2069,8 @@ function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
|
|
|
2002
2069
|
end,
|
|
2003
2070
|
replacement: rawValue,
|
|
2004
2071
|
displayValue: rawValue,
|
|
2005
|
-
hasHook: false
|
|
2072
|
+
hasHook: false,
|
|
2073
|
+
isNumeric: true
|
|
2006
2074
|
};
|
|
2007
2075
|
}
|
|
2008
2076
|
}
|
|
@@ -2134,9 +2202,30 @@ function shadowValueToHookEntries(supportedStylinghooks) {
|
|
|
2134
2202
|
return [key, value.map((hook) => hook.name)];
|
|
2135
2203
|
});
|
|
2136
2204
|
}
|
|
2205
|
+
function reportBoxShadowViolation(node, context, valueText, hooks) {
|
|
2206
|
+
const positionInfo = {
|
|
2207
|
+
start: { offset: 0, line: 1, column: 1 },
|
|
2208
|
+
end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
|
|
2209
|
+
};
|
|
2210
|
+
const replacement = createBoxShadowReplacement(
|
|
2211
|
+
valueText,
|
|
2212
|
+
hooks,
|
|
2213
|
+
context,
|
|
2214
|
+
positionInfo
|
|
2215
|
+
);
|
|
2216
|
+
if (replacement) {
|
|
2217
|
+
const replacements = [replacement];
|
|
2218
|
+
handleShorthandAutoFix(node, context, valueText, replacements);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2137
2221
|
var handleBoxShadowDeclaration = (node, context) => {
|
|
2138
2222
|
const cssProperty = node.property.toLowerCase();
|
|
2139
2223
|
const valueText = context.sourceCode.getText(node.value);
|
|
2224
|
+
const customHook = getCustomMapping(cssProperty, valueText, context.options?.customMapping);
|
|
2225
|
+
if (customHook) {
|
|
2226
|
+
reportBoxShadowViolation(node, context, valueText, [customHook]);
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2140
2229
|
const shadowHooks = shadowValueToHookEntries(context.valueToStylinghook);
|
|
2141
2230
|
const parsedCssValue = toBoxShadowValue(valueText);
|
|
2142
2231
|
if (!parsedCssValue) {
|
|
@@ -2146,20 +2235,7 @@ var handleBoxShadowDeclaration = (node, context) => {
|
|
|
2146
2235
|
const parsedValueHook = toBoxShadowValue(shadow);
|
|
2147
2236
|
if (parsedValueHook && isBoxShadowMatch(parsedCssValue, parsedValueHook)) {
|
|
2148
2237
|
if (closestHooks.length > 0) {
|
|
2149
|
-
|
|
2150
|
-
start: { offset: 0, line: 1, column: 1 },
|
|
2151
|
-
end: { offset: valueText.length, line: 1, column: valueText.length + 1 }
|
|
2152
|
-
};
|
|
2153
|
-
const replacement = createBoxShadowReplacement(
|
|
2154
|
-
valueText,
|
|
2155
|
-
closestHooks,
|
|
2156
|
-
context,
|
|
2157
|
-
positionInfo
|
|
2158
|
-
);
|
|
2159
|
-
if (replacement) {
|
|
2160
|
-
const replacements = [replacement];
|
|
2161
|
-
handleShorthandAutoFix(node, context, valueText, replacements);
|
|
2162
|
-
}
|
|
2238
|
+
reportBoxShadowViolation(node, context, valueText, closestHooks);
|
|
2163
2239
|
}
|
|
2164
2240
|
return;
|
|
2165
2241
|
}
|
|
@@ -2209,6 +2285,42 @@ function isRuleEnabled(context, ruleName3) {
|
|
|
2209
2285
|
}
|
|
2210
2286
|
}
|
|
2211
2287
|
|
|
2288
|
+
// src/rules/v9/no-hardcoded-values/ruleOptionsSchema.ts
|
|
2289
|
+
var ruleOptionsSchema = [
|
|
2290
|
+
{
|
|
2291
|
+
type: "object",
|
|
2292
|
+
properties: {
|
|
2293
|
+
reportNumericValue: {
|
|
2294
|
+
type: "string",
|
|
2295
|
+
enum: ["never", "always", "hasReplacement"],
|
|
2296
|
+
default: "always"
|
|
2297
|
+
},
|
|
2298
|
+
customMapping: {
|
|
2299
|
+
type: "object",
|
|
2300
|
+
additionalProperties: {
|
|
2301
|
+
type: "object",
|
|
2302
|
+
properties: {
|
|
2303
|
+
properties: {
|
|
2304
|
+
type: "array",
|
|
2305
|
+
items: { type: "string" }
|
|
2306
|
+
},
|
|
2307
|
+
values: {
|
|
2308
|
+
type: "array",
|
|
2309
|
+
items: { type: "string" }
|
|
2310
|
+
}
|
|
2311
|
+
},
|
|
2312
|
+
required: ["properties", "values"]
|
|
2313
|
+
}
|
|
2314
|
+
},
|
|
2315
|
+
preferPaletteHook: {
|
|
2316
|
+
type: "boolean",
|
|
2317
|
+
default: false
|
|
2318
|
+
}
|
|
2319
|
+
},
|
|
2320
|
+
additionalProperties: false
|
|
2321
|
+
}
|
|
2322
|
+
];
|
|
2323
|
+
|
|
2212
2324
|
// src/rules/v9/no-hardcoded-values/noHardcodedValueRule.ts
|
|
2213
2325
|
function defineNoHardcodedValueRule(config) {
|
|
2214
2326
|
const { ruleConfig: ruleConfig14, ruleName: ruleName3 } = config;
|
|
@@ -2222,16 +2334,24 @@ function defineNoHardcodedValueRule(config) {
|
|
|
2222
2334
|
url: url15
|
|
2223
2335
|
},
|
|
2224
2336
|
fixable: "code",
|
|
2225
|
-
messages: messages15
|
|
2337
|
+
messages: messages15,
|
|
2338
|
+
schema: ruleOptionsSchema
|
|
2226
2339
|
},
|
|
2227
2340
|
create(context) {
|
|
2228
2341
|
if (ruleName3 === "no-hardcoded-values-slds1" && isRuleEnabled(context, "@salesforce-ux/slds/no-hardcoded-values-slds2")) {
|
|
2229
2342
|
return {};
|
|
2230
2343
|
}
|
|
2344
|
+
const options = context.options[0] || {};
|
|
2345
|
+
const ruleOptions = {
|
|
2346
|
+
reportNumericValue: options.reportNumericValue || "always",
|
|
2347
|
+
customMapping: options.customMapping || {},
|
|
2348
|
+
preferPaletteHook: options.preferPaletteHook || false
|
|
2349
|
+
};
|
|
2231
2350
|
const handlerContext = {
|
|
2232
2351
|
valueToStylinghook: config.valueToStylinghook,
|
|
2233
2352
|
context,
|
|
2234
|
-
sourceCode: context.sourceCode
|
|
2353
|
+
sourceCode: context.sourceCode,
|
|
2354
|
+
options: ruleOptions
|
|
2235
2355
|
};
|
|
2236
2356
|
const colorOnlySelector = toSelector(colorProperties);
|
|
2237
2357
|
const densityOnlySelector = toSelector(densificationProperties);
|
|
@@ -2325,8 +2445,24 @@ var eslint_rules_internal_default = {
|
|
|
2325
2445
|
"@salesforce-ux/slds/no-slds-namespace-for-custom-hooks": "warn",
|
|
2326
2446
|
"@salesforce-ux/slds/enforce-component-hook-naming-convention": "error",
|
|
2327
2447
|
"@salesforce-ux/slds/no-slds-private-var": "warn",
|
|
2328
|
-
"@salesforce-ux/slds/no-hardcoded-values-
|
|
2329
|
-
|
|
2448
|
+
"@salesforce-ux/slds/no-hardcoded-values-slds2": ["warn", {
|
|
2449
|
+
reportNumericValue: "hasReplacement",
|
|
2450
|
+
preferPaletteHook: true,
|
|
2451
|
+
customMapping: {
|
|
2452
|
+
"--slds-g-font-line-height-4": {
|
|
2453
|
+
properties: ["line-height"],
|
|
2454
|
+
values: ["1.5"]
|
|
2455
|
+
},
|
|
2456
|
+
"--slds-g-sizing-5": {
|
|
2457
|
+
properties: ["width", "height", "max-width", "max-height", "border*"],
|
|
2458
|
+
values: ["1rem", "16px"]
|
|
2459
|
+
},
|
|
2460
|
+
"--slds-g-sizing-content-1": {
|
|
2461
|
+
properties: ["width", "height", "max-width", "max-height", "border*"],
|
|
2462
|
+
values: ["20ch"]
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}],
|
|
2330
2466
|
"@salesforce-ux/slds/reduce-annotations": "warn"
|
|
2331
2467
|
},
|
|
2332
2468
|
html: {
|
|
@@ -2359,7 +2495,7 @@ var rules = {
|
|
|
2359
2495
|
var plugin = {
|
|
2360
2496
|
meta: {
|
|
2361
2497
|
name: "@salesforce-ux/eslint-plugin-slds",
|
|
2362
|
-
version: "1.0.
|
|
2498
|
+
version: "1.0.8-internal"
|
|
2363
2499
|
},
|
|
2364
2500
|
rules,
|
|
2365
2501
|
configs: {}
|