@salesforce-ux/eslint-plugin-slds 1.0.8-internal → 1.0.10-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/build/config/rule-messages.d.ts +2 -0
- package/build/config/rule-messages.js +197 -0
- package/build/config/rule-messages.js.map +7 -0
- package/build/index.js +77 -2459
- package/build/index.js.map +4 -4
- package/build/rules/enforce-bem-usage.js +16 -232
- package/build/rules/enforce-bem-usage.js.map +4 -4
- package/build/rules/modal-close-button-issue.js +11 -183
- package/build/rules/modal-close-button-issue.js.map +4 -4
- package/build/rules/no-deprecated-classes-slds2.js +4 -176
- package/build/rules/no-deprecated-classes-slds2.js.map +4 -4
- package/build/rules/v9/enforce-bem-usage.js +1 -161
- package/build/rules/v9/enforce-bem-usage.js.map +4 -4
- package/build/rules/v9/enforce-component-hook-naming-convention.js +1 -161
- package/build/rules/v9/enforce-component-hook-naming-convention.js.map +4 -4
- package/build/rules/v9/enforce-sds-to-slds-hooks.js +1 -161
- package/build/rules/v9/enforce-sds-to-slds-hooks.js.map +4 -4
- package/build/rules/v9/lwc-token-to-slds-hook.js +4 -262
- package/build/rules/v9/lwc-token-to-slds-hook.js.map +4 -4
- package/build/rules/v9/no-deprecated-slds-classes.js +1 -161
- package/build/rules/v9/no-deprecated-slds-classes.js.map +4 -4
- package/build/rules/v9/no-deprecated-tokens-slds1.js +29 -168
- package/build/rules/v9/no-deprecated-tokens-slds1.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js +9 -289
- package/build/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js +13 -283
- package/build/rules/v9/no-hardcoded-values/handlers/colorHandler.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js +12 -328
- package/build/rules/v9/no-hardcoded-values/handlers/densityHandler.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js +13 -309
- package/build/rules/v9/no-hardcoded-values/handlers/fontHandler.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/handlers/index.js +8 -875
- package/build/rules/v9/no-hardcoded-values/handlers/index.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js +3 -1208
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds1.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js +3 -1208
- package/build/rules/v9/no-hardcoded-values/no-hardcoded-values-slds2.js.map +4 -4
- package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js +22 -993
- package/build/rules/v9/no-hardcoded-values/noHardcodedValueRule.js.map +4 -4
- package/build/rules/v9/no-slds-class-overrides.js +1 -161
- package/build/rules/v9/no-slds-class-overrides.js.map +4 -4
- package/build/rules/v9/no-slds-namespace-for-custom-hooks.js +3 -252
- package/build/rules/v9/no-slds-namespace-for-custom-hooks.js.map +4 -4
- package/build/rules/v9/no-slds-private-var.js +1 -161
- package/build/rules/v9/no-slds-private-var.js.map +4 -4
- package/build/rules/v9/no-slds-var-without-fallback.js +3 -255
- package/build/rules/v9/no-slds-var-without-fallback.js.map +4 -4
- package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js +1 -161
- package/build/rules/v9/no-sldshook-fallback-for-lwctoken.js.map +4 -4
- package/build/rules/v9/no-unsupported-hooks-slds2.js +1 -161
- package/build/rules/v9/no-unsupported-hooks-slds2.js.map +4 -4
- package/build/rules/v9/reduce-annotations.js +1 -161
- package/build/rules/v9/reduce-annotations.js.map +4 -4
- package/build/{src/utils → utils}/boxShadowValueParser.d.ts +1 -1
- package/build/utils/boxShadowValueParser.js +63 -93
- package/build/utils/boxShadowValueParser.js.map +4 -4
- package/build/utils/color-lib-utils.js +2 -29
- package/build/utils/color-lib-utils.js.map +3 -3
- package/build/{src/utils → utils}/css-utils.d.ts +7 -0
- package/build/utils/css-utils.js +10 -71
- package/build/utils/css-utils.js.map +4 -4
- package/build/utils/hardcoded-shared-utils.js +17 -82
- package/build/utils/hardcoded-shared-utils.js.map +4 -4
- package/build/utils/property-matcher.js +2 -2
- package/build/utils/property-matcher.js.map +2 -2
- package/build/utils/styling-hook-utils.js +16 -39
- package/build/utils/styling-hook-utils.js.map +3 -3
- package/build/{src/utils → utils}/value-utils.d.ts +2 -2
- package/build/utils/value-utils.js +8 -8
- package/build/utils/value-utils.js.map +2 -2
- package/package.json +5 -10
- package/src/config/rule-messages.yml +0 -143
- /package/build/{src/index.d.ts → index.d.ts} +0 -0
- /package/build/{src/rules → rules}/enforce-bem-usage.d.ts +0 -0
- /package/build/{src/rules → rules}/modal-close-button-issue.d.ts +0 -0
- /package/build/{src/rules → rules}/no-deprecated-classes-slds2.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/enforce-bem-usage.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/enforce-component-hook-naming-convention.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/enforce-sds-to-slds-hooks.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/lwc-token-to-slds-hook.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-deprecated-slds-classes.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-deprecated-tokens-slds1.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/handlers/boxShadowHandler.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/handlers/colorHandler.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/handlers/densityHandler.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/handlers/fontHandler.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/handlers/index.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/no-hardcoded-values-slds1.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/no-hardcoded-values-slds2.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/noHardcodedValueRule.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-hardcoded-values/ruleOptionsSchema.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-slds-class-overrides.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-slds-namespace-for-custom-hooks.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-slds-private-var.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-slds-var-without-fallback.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-sldshook-fallback-for-lwctoken.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/no-unsupported-hooks-slds2.d.ts +0 -0
- /package/build/{src/rules → rules}/v9/reduce-annotations.d.ts +0 -0
- /package/build/{src/types → types}/index.d.ts +0 -0
- /package/build/{src/utils → utils}/color-lib-utils.d.ts +0 -0
- /package/build/{src/utils → utils}/css-functions.d.ts +0 -0
- /package/build/{src/utils → utils}/custom-mapping-utils.d.ts +0 -0
- /package/build/{src/utils → utils}/hardcoded-shared-utils.d.ts +0 -0
- /package/build/{src/utils → utils}/node.d.ts +0 -0
- /package/build/{src/utils → utils}/property-matcher.d.ts +0 -0
- /package/build/{src/utils → utils}/rule-utils.d.ts +0 -0
- /package/build/{src/utils → utils}/styling-hook-utils.d.ts +0 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
5
|
var __export = (target, all) => {
|
|
8
6
|
for (var name in all)
|
|
@@ -16,14 +14,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
14
|
}
|
|
17
15
|
return to;
|
|
18
16
|
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
18
|
|
|
29
19
|
// src/rules/v9/no-hardcoded-values/noHardcodedValueRule.ts
|
|
@@ -32,971 +22,10 @@ __export(noHardcodedValueRule_exports, {
|
|
|
32
22
|
defineNoHardcodedValueRule: () => defineNoHardcodedValueRule
|
|
33
23
|
});
|
|
34
24
|
module.exports = __toCommonJS(noHardcodedValueRule_exports);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
// src/utils/css-functions.ts
|
|
41
|
-
var CSS_FUNCTIONS = [
|
|
42
|
-
"attr",
|
|
43
|
-
"calc",
|
|
44
|
-
"color-mix",
|
|
45
|
-
"conic-gradient",
|
|
46
|
-
"counter",
|
|
47
|
-
"cubic-bezier",
|
|
48
|
-
"linear-gradient",
|
|
49
|
-
"max",
|
|
50
|
-
"min",
|
|
51
|
-
"radial-gradient",
|
|
52
|
-
"repeating-conic-gradient",
|
|
53
|
-
"repeating-linear-gradient",
|
|
54
|
-
"repeating-radial-gradient",
|
|
55
|
-
"var"
|
|
56
|
-
];
|
|
57
|
-
var CSS_MATH_FUNCTIONS = ["calc", "min", "max"];
|
|
58
|
-
var RGB_COLOR_FUNCTIONS = ["rgb", "rgba", "hsl", "hsla"];
|
|
59
|
-
var cssFunctionsRegex = new RegExp(`(?:${CSS_FUNCTIONS.join("|")})`);
|
|
60
|
-
var cssFunctionsExactRegex = new RegExp(`^(?:${CSS_FUNCTIONS.join("|")})$`);
|
|
61
|
-
var cssMathFunctionsRegex = new RegExp(`^(?:${CSS_MATH_FUNCTIONS.join("|")})$`);
|
|
62
|
-
function isCssFunction(value) {
|
|
63
|
-
return cssFunctionsExactRegex.test(value);
|
|
64
|
-
}
|
|
65
|
-
function isCssColorFunction(value) {
|
|
66
|
-
return RGB_COLOR_FUNCTIONS.includes(value);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// src/utils/color-lib-utils.ts
|
|
70
|
-
var DELTAE_THRESHOLD = 10;
|
|
71
|
-
var convertToHex = (color) => {
|
|
72
|
-
try {
|
|
73
|
-
return (0, import_chroma_js.default)(color).hex();
|
|
74
|
-
} catch (e) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
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
|
-
}
|
|
91
|
-
var findClosestColorHook = (color, supportedColors, cssProperty) => {
|
|
92
|
-
const closestHooks = [];
|
|
93
|
-
Object.entries(supportedColors).forEach(([sldsValue, data]) => {
|
|
94
|
-
if (sldsValue && isValidColor(sldsValue)) {
|
|
95
|
-
const hooks = data;
|
|
96
|
-
hooks.forEach((hook) => {
|
|
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 });
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
const hooksByGroupMap = closestHooks.sort((a, b) => a.distance - b.distance).reduce((acc, hook) => {
|
|
105
|
-
if (!acc[hook.group]) {
|
|
106
|
-
acc[hook.group] = [];
|
|
107
|
-
}
|
|
108
|
-
acc[hook.group].push(hook.name);
|
|
109
|
-
return acc;
|
|
110
|
-
}, {});
|
|
111
|
-
return getOrderByCssProp(cssProperty).map((group) => hooksByGroupMap[group] || []).flat().slice(0, 5);
|
|
112
|
-
};
|
|
113
|
-
var isValidColor = (val) => import_chroma_js.default.valid(val);
|
|
114
|
-
var extractColorValue = (node) => {
|
|
115
|
-
let colorValue = null;
|
|
116
|
-
switch (node.type) {
|
|
117
|
-
case "Hash":
|
|
118
|
-
colorValue = `#${node.value}`;
|
|
119
|
-
break;
|
|
120
|
-
case "Identifier":
|
|
121
|
-
colorValue = node.name;
|
|
122
|
-
break;
|
|
123
|
-
case "Function":
|
|
124
|
-
if (isCssColorFunction(node.name)) {
|
|
125
|
-
colorValue = (0, import_css_tree.generate)(node);
|
|
126
|
-
}
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
return colorValue && isValidColor(colorValue) ? colorValue : null;
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// src/utils/property-matcher.ts
|
|
133
|
-
var DIRECTION_VALUES = "(?:top|right|bottom|left|inline|block|inline-start|inline-end|start|end|block-start|block-end)";
|
|
134
|
-
var CORNER_VALUES = "(?:top-left|top-right|bottom-right|bottom-left|start-start|start-end|end-start|end-end)";
|
|
135
|
-
var INSET_VALUES = "(?:inline|block|inline-start|inline-end|block-start|block-end)";
|
|
136
|
-
var BORDER_COLOR_REGEX = new RegExp(`^border(?:-${DIRECTION_VALUES})?-color$`);
|
|
137
|
-
var BORDER_WIDTH_REGEX = new RegExp(`^border(?:-${DIRECTION_VALUES})?-width$`);
|
|
138
|
-
var MARGIN_REGEX = new RegExp(`^margin(?:-${DIRECTION_VALUES})?$`);
|
|
139
|
-
var PADDING_REGEX = new RegExp(`^padding(?:-${DIRECTION_VALUES})?$`);
|
|
140
|
-
var BORDER_RADIUS_REGEX = new RegExp(`^border(?:-${CORNER_VALUES})?-radius$`);
|
|
141
|
-
var INSET_REGEX = new RegExp(`^inset(?:-${INSET_VALUES})?$`);
|
|
142
|
-
function isBorderColorProperty(cssProperty) {
|
|
143
|
-
return BORDER_COLOR_REGEX.test(cssProperty);
|
|
144
|
-
}
|
|
145
|
-
function isBorderWidthProperty(cssProperty) {
|
|
146
|
-
return BORDER_WIDTH_REGEX.test(cssProperty);
|
|
147
|
-
}
|
|
148
|
-
function isMarginProperty(cssProperty) {
|
|
149
|
-
return MARGIN_REGEX.test(cssProperty);
|
|
150
|
-
}
|
|
151
|
-
function isPaddingProperty(cssProperty) {
|
|
152
|
-
return PADDING_REGEX.test(cssProperty);
|
|
153
|
-
}
|
|
154
|
-
function isBorderRadius(cssProperty) {
|
|
155
|
-
return BORDER_RADIUS_REGEX.test(cssProperty);
|
|
156
|
-
}
|
|
157
|
-
function isDimensionProperty(cssProperty) {
|
|
158
|
-
return ["width", "height", "min-width", "max-width", "min-height", "max-height"].includes(cssProperty);
|
|
159
|
-
}
|
|
160
|
-
function isInsetProperty(cssProperty) {
|
|
161
|
-
return INSET_REGEX.test(cssProperty);
|
|
162
|
-
}
|
|
163
|
-
var fontProperties = [
|
|
164
|
-
"font",
|
|
165
|
-
"font-size",
|
|
166
|
-
"font-weight"
|
|
167
|
-
];
|
|
168
|
-
var colorProperties = [
|
|
169
|
-
"color",
|
|
170
|
-
"fill",
|
|
171
|
-
"background",
|
|
172
|
-
"background-color",
|
|
173
|
-
"stroke",
|
|
174
|
-
"border",
|
|
175
|
-
"border*",
|
|
176
|
-
"border*-color",
|
|
177
|
-
"outline",
|
|
178
|
-
"outline-color"
|
|
179
|
-
];
|
|
180
|
-
var densificationProperties = [
|
|
181
|
-
"border*",
|
|
182
|
-
"margin*",
|
|
183
|
-
"padding*",
|
|
184
|
-
"width",
|
|
185
|
-
"height",
|
|
186
|
-
"min-width",
|
|
187
|
-
"max-width",
|
|
188
|
-
"min-height",
|
|
189
|
-
"max-height",
|
|
190
|
-
"inset",
|
|
191
|
-
"top",
|
|
192
|
-
"right",
|
|
193
|
-
"left",
|
|
194
|
-
"bottom",
|
|
195
|
-
"outline",
|
|
196
|
-
"outline-width",
|
|
197
|
-
"line-height"
|
|
198
|
-
];
|
|
199
|
-
function toSelector(properties) {
|
|
200
|
-
const selectorParts = properties.map((prop) => {
|
|
201
|
-
if (prop.includes("*")) {
|
|
202
|
-
const regexPattern = prop.replace(/\*/g, ".*");
|
|
203
|
-
return `Declaration[property=/^${regexPattern}$/]`;
|
|
204
|
-
} else {
|
|
205
|
-
return `Declaration[property='${prop}']`;
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
return selectorParts.join(", ");
|
|
209
|
-
}
|
|
210
|
-
function resolveDensityPropertyToMatch(cssProperty) {
|
|
211
|
-
const propertyToMatch = cssProperty.toLowerCase();
|
|
212
|
-
if (isOutlineWidthProperty(propertyToMatch) || isBorderWidthProperty(propertyToMatch)) {
|
|
213
|
-
return "border-width";
|
|
214
|
-
} else if (isMarginProperty(propertyToMatch)) {
|
|
215
|
-
return "margin";
|
|
216
|
-
} else if (isPaddingProperty(propertyToMatch)) {
|
|
217
|
-
return "padding";
|
|
218
|
-
} else if (isBorderRadius(propertyToMatch)) {
|
|
219
|
-
return "border-radius";
|
|
220
|
-
} else if (isDimensionProperty(propertyToMatch)) {
|
|
221
|
-
return "width";
|
|
222
|
-
} else if (isInsetProperty(propertyToMatch)) {
|
|
223
|
-
return "top";
|
|
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") {
|
|
232
|
-
return "background-color";
|
|
233
|
-
} else if (isBorderColorProperty(propertyToMatch)) {
|
|
234
|
-
return "border-color";
|
|
235
|
-
}
|
|
236
|
-
return propertyToMatch;
|
|
237
|
-
}
|
|
238
|
-
function isOutlineWidthProperty(propertyToMatch) {
|
|
239
|
-
return propertyToMatch === "outline" || propertyToMatch === "outline-width";
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// src/utils/hardcoded-shared-utils.ts
|
|
243
|
-
var import_css_tree2 = require("@eslint/css-tree");
|
|
244
|
-
|
|
245
|
-
// src/utils/value-utils.ts
|
|
246
|
-
var ALLOWED_UNITS = ["px", "em", "rem", "%", "ch"];
|
|
247
|
-
function parseUnitValue(value) {
|
|
248
|
-
if (!value) return null;
|
|
249
|
-
const unitsPattern = ALLOWED_UNITS.join("|");
|
|
250
|
-
const regex = new RegExp(`^(-?\\d*\\.?\\d+)(${unitsPattern})?$`);
|
|
251
|
-
const match = value.match(regex);
|
|
252
|
-
if (!match) return null;
|
|
253
|
-
const number = parseFloat(match[1]);
|
|
254
|
-
const unit = match[2] ? match[2] : null;
|
|
255
|
-
if (isNaN(number)) return null;
|
|
256
|
-
return { number, unit };
|
|
257
|
-
}
|
|
258
|
-
function toAlternateUnitValue(numberVal, unitType) {
|
|
259
|
-
if (unitType === "px") {
|
|
260
|
-
let floatValue = parseFloat(`${numberVal / 16}`);
|
|
261
|
-
if (!isNaN(floatValue)) {
|
|
262
|
-
return {
|
|
263
|
-
unit: "rem",
|
|
264
|
-
number: parseFloat(floatValue.toFixed(4))
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
} else if (unitType === "rem") {
|
|
268
|
-
const intValue = parseInt(`${numberVal * 16}`);
|
|
269
|
-
if (!isNaN(intValue)) {
|
|
270
|
-
return {
|
|
271
|
-
unit: "px",
|
|
272
|
-
number: intValue
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return null;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// src/utils/hardcoded-shared-utils.ts
|
|
280
|
-
var FONT_WEIGHTS = [
|
|
281
|
-
"normal",
|
|
282
|
-
"bold",
|
|
283
|
-
"bolder",
|
|
284
|
-
"lighter",
|
|
285
|
-
"100",
|
|
286
|
-
"200",
|
|
287
|
-
"300",
|
|
288
|
-
"400",
|
|
289
|
-
"500",
|
|
290
|
-
"600",
|
|
291
|
-
"700",
|
|
292
|
-
"800",
|
|
293
|
-
"900"
|
|
294
|
-
];
|
|
295
|
-
function isKnownFontWeight(value) {
|
|
296
|
-
const stringValue = value.toString();
|
|
297
|
-
return FONT_WEIGHTS.includes(stringValue.toLowerCase());
|
|
298
|
-
}
|
|
299
|
-
function handleShorthandAutoFix(declarationNode, context, valueText, replacements) {
|
|
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 }) => {
|
|
315
|
-
const originalValue = valueText.substring(start, end);
|
|
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;
|
|
327
|
-
const { loc: { start: locStart, end: locEnd } } = declarationNode.value;
|
|
328
|
-
const reportNode = {
|
|
329
|
-
...declarationNode.value,
|
|
330
|
-
loc: {
|
|
331
|
-
...declarationNode.value.loc,
|
|
332
|
-
start: {
|
|
333
|
-
...locStart,
|
|
334
|
-
column: valueColumnStart
|
|
335
|
-
},
|
|
336
|
-
end: {
|
|
337
|
-
...locEnd,
|
|
338
|
-
column: valueColumnEnd
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
if (hasHook) {
|
|
343
|
-
const fix = canAutoFix ? fixCallback(start, originalValue, replacement) : void 0;
|
|
344
|
-
context.context.report({
|
|
345
|
-
node: reportNode,
|
|
346
|
-
messageId: "hardcodedValue",
|
|
347
|
-
data: {
|
|
348
|
-
oldValue: originalValue,
|
|
349
|
-
newValue: displayValue
|
|
350
|
-
},
|
|
351
|
-
fix
|
|
352
|
-
});
|
|
353
|
-
} else {
|
|
354
|
-
context.context.report({
|
|
355
|
-
node: reportNode,
|
|
356
|
-
messageId: "noReplacement",
|
|
357
|
-
data: {
|
|
358
|
-
oldValue: originalValue
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
function forEachValue(valueText, extractValue, shouldSkipNode, callback) {
|
|
365
|
-
if (!valueText || typeof valueText !== "string") {
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
const ast = (0, import_css_tree2.parse)(valueText, { context: "value", positions: true });
|
|
370
|
-
(0, import_css_tree2.walk)(ast, {
|
|
371
|
-
enter(node) {
|
|
372
|
-
if (shouldSkipNode(node)) {
|
|
373
|
-
return this.skip;
|
|
374
|
-
}
|
|
375
|
-
const value = extractValue(node);
|
|
376
|
-
if (value !== null) {
|
|
377
|
-
const positionInfo = {
|
|
378
|
-
start: node.loc?.start,
|
|
379
|
-
end: node.loc?.end
|
|
380
|
-
};
|
|
381
|
-
callback(value, positionInfo);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
} catch (error) {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
function shouldSkipColorNode(node) {
|
|
390
|
-
return node.type === "Function" && isCssFunction(node.name);
|
|
391
|
-
}
|
|
392
|
-
function shouldSkipDimensionNode(node) {
|
|
393
|
-
return node.type === "Function";
|
|
394
|
-
}
|
|
395
|
-
function extractDimensionValue(valueNode, cssProperty) {
|
|
396
|
-
if (!valueNode) return null;
|
|
397
|
-
switch (valueNode.type) {
|
|
398
|
-
case "Dimension":
|
|
399
|
-
const numValue = Number(valueNode.value);
|
|
400
|
-
if (numValue === 0) return null;
|
|
401
|
-
const unit = valueNode.unit.toLowerCase();
|
|
402
|
-
if (!ALLOWED_UNITS.includes(unit)) return null;
|
|
403
|
-
return {
|
|
404
|
-
number: numValue,
|
|
405
|
-
unit
|
|
406
|
-
};
|
|
407
|
-
case "Number":
|
|
408
|
-
const numberValue = Number(valueNode.value);
|
|
409
|
-
if (numberValue === 0) return null;
|
|
410
|
-
return {
|
|
411
|
-
number: numberValue,
|
|
412
|
-
unit: null
|
|
413
|
-
};
|
|
414
|
-
case "Percentage":
|
|
415
|
-
const percentValue = Number(valueNode.value);
|
|
416
|
-
if (percentValue === 0) return null;
|
|
417
|
-
return {
|
|
418
|
-
number: percentValue,
|
|
419
|
-
unit: "%"
|
|
420
|
-
};
|
|
421
|
-
case "Value":
|
|
422
|
-
return valueNode.children?.[0] ? extractDimensionValue(valueNode.children[0], cssProperty) : null;
|
|
423
|
-
}
|
|
424
|
-
return null;
|
|
425
|
-
}
|
|
426
|
-
function forEachColorValue(valueText, callback) {
|
|
427
|
-
forEachValue(valueText, extractColorValue, shouldSkipColorNode, callback);
|
|
428
|
-
}
|
|
429
|
-
function forEachDensityValue(valueText, cssProperty, callback) {
|
|
430
|
-
forEachValue(
|
|
431
|
-
valueText,
|
|
432
|
-
(node) => extractDimensionValue(node, cssProperty),
|
|
433
|
-
shouldSkipDimensionNode,
|
|
434
|
-
callback
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
function extractFontValue(node) {
|
|
438
|
-
if (!node) return null;
|
|
439
|
-
switch (node.type) {
|
|
440
|
-
case "Dimension":
|
|
441
|
-
const numValue = Number(node.value);
|
|
442
|
-
if (numValue <= 0) return null;
|
|
443
|
-
const unit = node.unit.toLowerCase();
|
|
444
|
-
if (!ALLOWED_UNITS.includes(unit)) return null;
|
|
445
|
-
return {
|
|
446
|
-
number: numValue,
|
|
447
|
-
unit
|
|
448
|
-
};
|
|
449
|
-
case "Number":
|
|
450
|
-
const numberValue = Number(node.value);
|
|
451
|
-
if (numberValue <= 0) {
|
|
452
|
-
return null;
|
|
453
|
-
}
|
|
454
|
-
if (!isKnownFontWeight(numberValue)) {
|
|
455
|
-
return null;
|
|
456
|
-
}
|
|
457
|
-
return {
|
|
458
|
-
number: numberValue,
|
|
459
|
-
unit: null
|
|
460
|
-
};
|
|
461
|
-
case "Identifier":
|
|
462
|
-
const namedValue = node.name.toLowerCase();
|
|
463
|
-
if (!isKnownFontWeight(namedValue)) {
|
|
464
|
-
return null;
|
|
465
|
-
}
|
|
466
|
-
if (namedValue === "normal") {
|
|
467
|
-
return { number: 400, unit: null };
|
|
468
|
-
}
|
|
469
|
-
return { number: namedValue, unit: null };
|
|
470
|
-
case "Percentage":
|
|
471
|
-
const percentValue = Number(node.value);
|
|
472
|
-
if (percentValue === 0) return null;
|
|
473
|
-
return {
|
|
474
|
-
number: percentValue,
|
|
475
|
-
unit: "%"
|
|
476
|
-
};
|
|
477
|
-
case "Value":
|
|
478
|
-
return node.children?.[0] ? extractFontValue(node.children[0]) : null;
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
function shouldSkipFontNode(node) {
|
|
483
|
-
return node.type === "Function";
|
|
484
|
-
}
|
|
485
|
-
function forEachFontValue(valueText, callback) {
|
|
486
|
-
forEachValue(valueText, extractFontValue, shouldSkipFontNode, callback);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// src/utils/css-utils.ts
|
|
490
|
-
function formatSuggestionHooks(hooks) {
|
|
491
|
-
if (hooks.length === 1) {
|
|
492
|
-
return `${hooks[0]}`;
|
|
493
|
-
}
|
|
494
|
-
return "\n" + hooks.map((hook, index) => `${index + 1}. ${hook}`).join("\n");
|
|
495
|
-
}
|
|
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
|
-
|
|
532
|
-
// src/rules/v9/no-hardcoded-values/handlers/colorHandler.ts
|
|
533
|
-
var handleColorDeclaration = (node, context) => {
|
|
534
|
-
const cssProperty = node.property.toLowerCase();
|
|
535
|
-
const valueText = context.sourceCode.getText(node.value);
|
|
536
|
-
const replacements = [];
|
|
537
|
-
forEachColorValue(valueText, (colorValue, positionInfo) => {
|
|
538
|
-
if (colorValue !== "transparent" && isValidColor(colorValue)) {
|
|
539
|
-
const replacement = createColorReplacement(colorValue, cssProperty, context, positionInfo, valueText);
|
|
540
|
-
if (replacement) {
|
|
541
|
-
replacements.push(replacement);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
handleShorthandAutoFix(node, context, valueText, replacements);
|
|
546
|
-
};
|
|
547
|
-
function createColorReplacement(colorValue, cssProperty, context, positionInfo, originalValueText) {
|
|
548
|
-
if (!positionInfo?.start) {
|
|
549
|
-
return null;
|
|
550
|
-
}
|
|
551
|
-
const hexValue = convertToHex(colorValue);
|
|
552
|
-
if (!hexValue) {
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
const start = positionInfo.start.offset;
|
|
556
|
-
const end = positionInfo.end.offset;
|
|
557
|
-
const originalValue = originalValueText ? originalValueText.substring(start, end) : colorValue;
|
|
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) {
|
|
577
|
-
return {
|
|
578
|
-
start,
|
|
579
|
-
end,
|
|
580
|
-
replacement,
|
|
581
|
-
// Use original value to preserve spacing
|
|
582
|
-
displayValue: formatSuggestionHooks(closestHooks),
|
|
583
|
-
hasHook: true
|
|
584
|
-
};
|
|
585
|
-
} else {
|
|
586
|
-
return {
|
|
587
|
-
start,
|
|
588
|
-
end,
|
|
589
|
-
replacement,
|
|
590
|
-
// Use original value to preserve spacing
|
|
591
|
-
displayValue: originalValue,
|
|
592
|
-
hasHook: false
|
|
593
|
-
};
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// src/utils/styling-hook-utils.ts
|
|
598
|
-
function isValueMatch(valueToMatch, sldsValue) {
|
|
599
|
-
if (!valueToMatch || !sldsValue) {
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
602
|
-
return valueToMatch.unit == sldsValue.unit && valueToMatch.number === sldsValue.number;
|
|
603
|
-
}
|
|
604
|
-
function getStylingHooksForDensityValue(parsedValue, supportedStylinghooks, cssProperty) {
|
|
605
|
-
if (!parsedValue) return [];
|
|
606
|
-
const alternateValue = toAlternateUnitValue(parsedValue.number, parsedValue.unit);
|
|
607
|
-
const matchedHooks = [];
|
|
608
|
-
for (const [sldsValue, hooks] of Object.entries(supportedStylinghooks)) {
|
|
609
|
-
const parsedSldsValue = parseUnitValue(sldsValue);
|
|
610
|
-
if (isValueMatch(parsedValue, parsedSldsValue) || alternateValue && isValueMatch(alternateValue, parsedSldsValue)) {
|
|
611
|
-
hooks.filter((hook) => hook.properties.includes(cssProperty)).forEach((hook) => matchedHooks.push(hook.name));
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
return matchedHooks;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// src/rules/v9/no-hardcoded-values/handlers/densityHandler.ts
|
|
618
|
-
var handleDensityDeclaration = (node, context) => {
|
|
619
|
-
const cssProperty = node.property.toLowerCase();
|
|
620
|
-
const valueText = context.sourceCode.getText(node.value);
|
|
621
|
-
const replacements = [];
|
|
622
|
-
forEachDensityValue(valueText, cssProperty, (parsedDimension, positionInfo) => {
|
|
623
|
-
if (parsedDimension) {
|
|
624
|
-
const replacement = createDimensionReplacement(parsedDimension, cssProperty, context, positionInfo);
|
|
625
|
-
if (replacement) {
|
|
626
|
-
replacements.push(replacement);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
|
-
handleShorthandAutoFix(node, context, valueText, replacements);
|
|
631
|
-
};
|
|
632
|
-
function createDimensionReplacement(parsedDimension, cssProperty, context, positionInfo) {
|
|
633
|
-
if (!parsedDimension || !positionInfo?.start) {
|
|
634
|
-
return null;
|
|
635
|
-
}
|
|
636
|
-
const rawValue = parsedDimension.unit ? `${parsedDimension.number}${parsedDimension.unit}` : parsedDimension.number.toString();
|
|
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
|
-
}
|
|
645
|
-
const start = positionInfo.start.offset;
|
|
646
|
-
const end = positionInfo.end.offset;
|
|
647
|
-
if (closestHooks.length === 1) {
|
|
648
|
-
return {
|
|
649
|
-
start,
|
|
650
|
-
end,
|
|
651
|
-
replacement: `var(${closestHooks[0]}, ${rawValue})`,
|
|
652
|
-
displayValue: closestHooks[0],
|
|
653
|
-
hasHook: true,
|
|
654
|
-
isNumeric: true
|
|
655
|
-
};
|
|
656
|
-
} else if (closestHooks.length > 1) {
|
|
657
|
-
return {
|
|
658
|
-
start,
|
|
659
|
-
end,
|
|
660
|
-
replacement: rawValue,
|
|
661
|
-
displayValue: formatSuggestionHooks(closestHooks),
|
|
662
|
-
hasHook: true,
|
|
663
|
-
isNumeric: true
|
|
664
|
-
};
|
|
665
|
-
} else {
|
|
666
|
-
return {
|
|
667
|
-
start,
|
|
668
|
-
end,
|
|
669
|
-
replacement: rawValue,
|
|
670
|
-
displayValue: rawValue,
|
|
671
|
-
hasHook: false,
|
|
672
|
-
isNumeric: true
|
|
673
|
-
};
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// src/rules/v9/no-hardcoded-values/handlers/fontHandler.ts
|
|
678
|
-
var handleFontDeclaration = (node, context) => {
|
|
679
|
-
const cssProperty = node.property.toLowerCase();
|
|
680
|
-
const valueText = context.sourceCode.getText(node.value);
|
|
681
|
-
const replacements = [];
|
|
682
|
-
forEachFontValue(valueText, (fontValue, positionInfo) => {
|
|
683
|
-
if (fontValue && isValidFontValue(fontValue, cssProperty)) {
|
|
684
|
-
const replacement = createFontReplacement(fontValue, cssProperty, context, positionInfo);
|
|
685
|
-
if (replacement) {
|
|
686
|
-
replacements.push(replacement);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
});
|
|
690
|
-
handleShorthandAutoFix(node, context, valueText, replacements);
|
|
691
|
-
};
|
|
692
|
-
function isValidFontValue(fontValue, cssProperty) {
|
|
693
|
-
if (cssProperty === "font-size") {
|
|
694
|
-
return !!fontValue.unit;
|
|
695
|
-
} else if (cssProperty === "font-weight") {
|
|
696
|
-
return !fontValue.unit && isKnownFontWeight(fontValue.number);
|
|
697
|
-
} else if (cssProperty === "font") {
|
|
698
|
-
if (!fontValue.unit && isKnownFontWeight(fontValue.number)) {
|
|
699
|
-
return true;
|
|
700
|
-
} else if (fontValue.unit) {
|
|
701
|
-
return true;
|
|
702
|
-
} else {
|
|
703
|
-
return false;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
return false;
|
|
707
|
-
}
|
|
708
|
-
function createFontReplacement(fontValue, cssProperty, context, positionInfo) {
|
|
709
|
-
if (!positionInfo?.start) {
|
|
710
|
-
return null;
|
|
711
|
-
}
|
|
712
|
-
const rawValue = fontValue.unit ? `${fontValue.number}${fontValue.unit}` : fontValue.number.toString();
|
|
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
|
-
}
|
|
721
|
-
const start = positionInfo.start.offset;
|
|
722
|
-
const end = positionInfo.end.offset;
|
|
723
|
-
if (closestHooks.length === 1) {
|
|
724
|
-
return {
|
|
725
|
-
start,
|
|
726
|
-
end,
|
|
727
|
-
replacement: `var(${closestHooks[0]}, ${rawValue})`,
|
|
728
|
-
displayValue: closestHooks[0],
|
|
729
|
-
hasHook: true,
|
|
730
|
-
isNumeric: true
|
|
731
|
-
};
|
|
732
|
-
} else if (closestHooks.length > 1) {
|
|
733
|
-
return {
|
|
734
|
-
start,
|
|
735
|
-
end,
|
|
736
|
-
replacement: rawValue,
|
|
737
|
-
displayValue: formatSuggestionHooks(closestHooks),
|
|
738
|
-
hasHook: true,
|
|
739
|
-
isNumeric: true
|
|
740
|
-
};
|
|
741
|
-
} else {
|
|
742
|
-
return {
|
|
743
|
-
start,
|
|
744
|
-
end,
|
|
745
|
-
replacement: rawValue,
|
|
746
|
-
displayValue: rawValue,
|
|
747
|
-
hasHook: false,
|
|
748
|
-
isNumeric: true
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
// src/utils/boxShadowValueParser.ts
|
|
754
|
-
var import_css_tree3 = require("@eslint/css-tree");
|
|
755
|
-
function isColorValue(node) {
|
|
756
|
-
if (!node) return false;
|
|
757
|
-
switch (node.type) {
|
|
758
|
-
case "Hash":
|
|
759
|
-
return true;
|
|
760
|
-
// #hex colors
|
|
761
|
-
case "Identifier":
|
|
762
|
-
return isValidColor(node.name);
|
|
763
|
-
case "Function":
|
|
764
|
-
return isCssColorFunction(node.name.toLowerCase());
|
|
765
|
-
default:
|
|
766
|
-
return false;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
function isLengthValue(node) {
|
|
770
|
-
if (!node) return false;
|
|
771
|
-
switch (node.type) {
|
|
772
|
-
case "Dimension":
|
|
773
|
-
const dimensionStr = `${node.value}${node.unit}`;
|
|
774
|
-
return parseUnitValue(dimensionStr) !== null;
|
|
775
|
-
case "Number":
|
|
776
|
-
return Number(node.value) === 0;
|
|
777
|
-
default:
|
|
778
|
-
return false;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
function isInsetKeyword(node) {
|
|
782
|
-
return node?.type === "Identifier" && node.name.toLowerCase() === "inset";
|
|
783
|
-
}
|
|
784
|
-
function extractShadowParts(valueText) {
|
|
785
|
-
const shadows = [];
|
|
786
|
-
let currentShadow = {
|
|
787
|
-
lengthParts: [],
|
|
788
|
-
colorParts: [],
|
|
789
|
-
inset: false
|
|
790
|
-
};
|
|
791
|
-
try {
|
|
792
|
-
const ast = (0, import_css_tree3.parse)(valueText, { context: "value" });
|
|
793
|
-
(0, import_css_tree3.walk)(ast, {
|
|
794
|
-
enter(node) {
|
|
795
|
-
if (node.type === "Function") {
|
|
796
|
-
return this.skip;
|
|
797
|
-
}
|
|
798
|
-
if (isInsetKeyword(node)) {
|
|
799
|
-
currentShadow.inset = true;
|
|
800
|
-
} else if (isLengthValue(node)) {
|
|
801
|
-
currentShadow.lengthParts.push((0, import_css_tree3.generate)(node));
|
|
802
|
-
} else if (isColorValue(node)) {
|
|
803
|
-
currentShadow.colorParts.push((0, import_css_tree3.generate)(node));
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
});
|
|
807
|
-
if (currentShadow.lengthParts.length > 0 || currentShadow.colorParts.length > 0 || currentShadow.inset) {
|
|
808
|
-
shadows.push(currentShadow);
|
|
809
|
-
}
|
|
810
|
-
} catch (error) {
|
|
811
|
-
return [];
|
|
812
|
-
}
|
|
813
|
-
return shadows;
|
|
814
|
-
}
|
|
815
|
-
function parseBoxShadowValue(value) {
|
|
816
|
-
const shadowStrings = value.split(",").map((s) => s.trim());
|
|
817
|
-
const allShadows = [];
|
|
818
|
-
for (const shadowString of shadowStrings) {
|
|
819
|
-
const shadows = extractShadowParts(shadowString);
|
|
820
|
-
const parsedShadows = shadows.map((shadow) => {
|
|
821
|
-
const shadowValue = {};
|
|
822
|
-
const lengthProps = ["offsetX", "offsetY", "blurRadius", "spreadRadius"];
|
|
823
|
-
lengthProps.forEach((prop, index) => {
|
|
824
|
-
if (shadow.lengthParts.length > index) {
|
|
825
|
-
shadowValue[prop] = shadow.lengthParts[index];
|
|
826
|
-
}
|
|
827
|
-
});
|
|
828
|
-
if (shadow.colorParts.length > 0) {
|
|
829
|
-
shadowValue.color = shadow.colorParts[0];
|
|
830
|
-
}
|
|
831
|
-
if (shadow.inset) {
|
|
832
|
-
shadowValue.inset = true;
|
|
833
|
-
}
|
|
834
|
-
return shadowValue;
|
|
835
|
-
});
|
|
836
|
-
allShadows.push(...parsedShadows);
|
|
837
|
-
}
|
|
838
|
-
return allShadows;
|
|
839
|
-
}
|
|
840
|
-
function normalizeLengthValue(value) {
|
|
841
|
-
if (!value) return "0px";
|
|
842
|
-
if (value === "0") return "0px";
|
|
843
|
-
return value;
|
|
844
|
-
}
|
|
845
|
-
function isBoxShadowMatch(parsedCssValue, parsedValueHook) {
|
|
846
|
-
if (parsedCssValue.length !== parsedValueHook.length) {
|
|
847
|
-
return false;
|
|
848
|
-
}
|
|
849
|
-
for (let i = 0; i < parsedCssValue.length; i++) {
|
|
850
|
-
const cssShadow = parsedCssValue[i];
|
|
851
|
-
const hookShadow = parsedValueHook[i];
|
|
852
|
-
if (cssShadow.color !== hookShadow.color || cssShadow.inset !== hookShadow.inset) {
|
|
853
|
-
return false;
|
|
854
|
-
}
|
|
855
|
-
const lengthProps = ["offsetX", "offsetY", "blurRadius", "spreadRadius"];
|
|
856
|
-
for (const prop of lengthProps) {
|
|
857
|
-
if (normalizeLengthValue(cssShadow[prop]) !== normalizeLengthValue(hookShadow[prop])) {
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
return true;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// src/rules/v9/no-hardcoded-values/handlers/boxShadowHandler.ts
|
|
866
|
-
function toBoxShadowValue(cssValue) {
|
|
867
|
-
const parsedCssValue = parseBoxShadowValue(cssValue).filter((shadow) => Object.keys(shadow).length > 0);
|
|
868
|
-
if (parsedCssValue.length === 0) {
|
|
869
|
-
return null;
|
|
870
|
-
}
|
|
871
|
-
return parsedCssValue;
|
|
872
|
-
}
|
|
873
|
-
function shadowValueToHookEntries(supportedStylinghooks) {
|
|
874
|
-
return Object.entries(supportedStylinghooks).filter(([key, value]) => {
|
|
875
|
-
return value.some((hook) => hook.properties.includes("box-shadow"));
|
|
876
|
-
}).map(([key, value]) => {
|
|
877
|
-
return [key, value.map((hook) => hook.name)];
|
|
878
|
-
});
|
|
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
|
-
}
|
|
896
|
-
var handleBoxShadowDeclaration = (node, context) => {
|
|
897
|
-
const cssProperty = node.property.toLowerCase();
|
|
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
|
-
}
|
|
904
|
-
const shadowHooks = shadowValueToHookEntries(context.valueToStylinghook);
|
|
905
|
-
const parsedCssValue = toBoxShadowValue(valueText);
|
|
906
|
-
if (!parsedCssValue) {
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
for (const [shadow, closestHooks] of shadowHooks) {
|
|
910
|
-
const parsedValueHook = toBoxShadowValue(shadow);
|
|
911
|
-
if (parsedValueHook && isBoxShadowMatch(parsedCssValue, parsedValueHook)) {
|
|
912
|
-
if (closestHooks.length > 0) {
|
|
913
|
-
reportBoxShadowViolation(node, context, valueText, closestHooks);
|
|
914
|
-
}
|
|
915
|
-
return;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
function createBoxShadowReplacement(originalValue, hooks, context, positionInfo) {
|
|
920
|
-
if (!positionInfo?.start) {
|
|
921
|
-
return null;
|
|
922
|
-
}
|
|
923
|
-
const start = positionInfo.start.offset;
|
|
924
|
-
const end = positionInfo.end.offset;
|
|
925
|
-
if (hooks.length === 1) {
|
|
926
|
-
return {
|
|
927
|
-
start,
|
|
928
|
-
end,
|
|
929
|
-
replacement: `var(${hooks[0]}, ${originalValue})`,
|
|
930
|
-
displayValue: hooks[0],
|
|
931
|
-
hasHook: true
|
|
932
|
-
};
|
|
933
|
-
} else {
|
|
934
|
-
return {
|
|
935
|
-
start,
|
|
936
|
-
end,
|
|
937
|
-
replacement: originalValue,
|
|
938
|
-
displayValue: formatSuggestionHooks(hooks),
|
|
939
|
-
hasHook: true
|
|
940
|
-
};
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// src/utils/rule-utils.ts
|
|
945
|
-
function isRuleEnabled(context, ruleName) {
|
|
946
|
-
try {
|
|
947
|
-
const rules = context.settings?.sldsRules || {};
|
|
948
|
-
if (ruleName in rules) {
|
|
949
|
-
const ruleConfig = rules[ruleName];
|
|
950
|
-
if (Array.isArray(ruleConfig)) {
|
|
951
|
-
return ruleConfig[0] === true;
|
|
952
|
-
} else if (ruleConfig !== void 0 && ruleConfig !== null) {
|
|
953
|
-
return true;
|
|
954
|
-
} else if (ruleConfig === false) {
|
|
955
|
-
return false;
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
} catch (error) {
|
|
959
|
-
return false;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
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
|
-
|
|
999
|
-
// src/rules/v9/no-hardcoded-values/noHardcodedValueRule.ts
|
|
25
|
+
var import_handlers = require("./handlers/index");
|
|
26
|
+
var import_property_matcher = require("../../../utils/property-matcher");
|
|
27
|
+
var import_rule_utils = require("../../../utils/rule-utils");
|
|
28
|
+
var import_ruleOptionsSchema = require("./ruleOptionsSchema");
|
|
1000
29
|
function defineNoHardcodedValueRule(config) {
|
|
1001
30
|
const { ruleConfig, ruleName } = config;
|
|
1002
31
|
const { type, description, url, messages } = ruleConfig;
|
|
@@ -1010,10 +39,10 @@ function defineNoHardcodedValueRule(config) {
|
|
|
1010
39
|
},
|
|
1011
40
|
fixable: "code",
|
|
1012
41
|
messages,
|
|
1013
|
-
schema: ruleOptionsSchema
|
|
42
|
+
schema: import_ruleOptionsSchema.ruleOptionsSchema
|
|
1014
43
|
},
|
|
1015
44
|
create(context) {
|
|
1016
|
-
if (ruleName === "no-hardcoded-values-slds1" && isRuleEnabled(context, "@salesforce-ux/slds/no-hardcoded-values-slds2")) {
|
|
45
|
+
if (ruleName === "no-hardcoded-values-slds1" && (0, import_rule_utils.isRuleEnabled)(context, "@salesforce-ux/slds/no-hardcoded-values-slds2")) {
|
|
1017
46
|
return {};
|
|
1018
47
|
}
|
|
1019
48
|
const options = context.options[0] || {};
|
|
@@ -1028,11 +57,11 @@ function defineNoHardcodedValueRule(config) {
|
|
|
1028
57
|
sourceCode: context.sourceCode,
|
|
1029
58
|
options: ruleOptions
|
|
1030
59
|
};
|
|
1031
|
-
const colorOnlySelector = toSelector(colorProperties);
|
|
1032
|
-
const densityOnlySelector = toSelector(densificationProperties);
|
|
1033
|
-
const fontDensitySelector = toSelector(fontProperties);
|
|
1034
|
-
const overlappingProperties = colorProperties.filter((colorProp) => {
|
|
1035
|
-
return densificationProperties.some((densityProp) => {
|
|
60
|
+
const colorOnlySelector = (0, import_property_matcher.toSelector)(import_property_matcher.colorProperties);
|
|
61
|
+
const densityOnlySelector = (0, import_property_matcher.toSelector)(import_property_matcher.densificationProperties);
|
|
62
|
+
const fontDensitySelector = (0, import_property_matcher.toSelector)(import_property_matcher.fontProperties);
|
|
63
|
+
const overlappingProperties = import_property_matcher.colorProperties.filter((colorProp) => {
|
|
64
|
+
return import_property_matcher.densificationProperties.some((densityProp) => {
|
|
1036
65
|
if (densityProp === colorProp) {
|
|
1037
66
|
return true;
|
|
1038
67
|
}
|
|
@@ -1044,32 +73,32 @@ function defineNoHardcodedValueRule(config) {
|
|
|
1044
73
|
});
|
|
1045
74
|
});
|
|
1046
75
|
const overlappingSet = new Set(overlappingProperties);
|
|
1047
|
-
const colorOnlyProps = colorProperties.filter((prop) => !overlappingSet.has(prop));
|
|
1048
|
-
const densityOnlyProps = densificationProperties.filter((prop) => !overlappingSet.has(prop));
|
|
76
|
+
const colorOnlyProps = import_property_matcher.colorProperties.filter((prop) => !overlappingSet.has(prop));
|
|
77
|
+
const densityOnlyProps = import_property_matcher.densificationProperties.filter((prop) => !overlappingSet.has(prop));
|
|
1049
78
|
const visitors = {};
|
|
1050
79
|
if (colorOnlyProps.length > 0) {
|
|
1051
|
-
const colorOnlySelector2 = toSelector(colorOnlyProps);
|
|
80
|
+
const colorOnlySelector2 = (0, import_property_matcher.toSelector)(colorOnlyProps);
|
|
1052
81
|
visitors[colorOnlySelector2] = (node) => {
|
|
1053
|
-
handleColorDeclaration(node, handlerContext);
|
|
82
|
+
(0, import_handlers.handleColorDeclaration)(node, handlerContext);
|
|
1054
83
|
};
|
|
1055
84
|
}
|
|
1056
85
|
if (densityOnlyProps.length > 0) {
|
|
1057
|
-
const densityOnlySelector2 = toSelector(densityOnlyProps);
|
|
86
|
+
const densityOnlySelector2 = (0, import_property_matcher.toSelector)(densityOnlyProps);
|
|
1058
87
|
visitors[densityOnlySelector2] = (node) => {
|
|
1059
|
-
handleDensityDeclaration(node, handlerContext);
|
|
88
|
+
(0, import_handlers.handleDensityDeclaration)(node, handlerContext);
|
|
1060
89
|
};
|
|
1061
90
|
}
|
|
1062
91
|
visitors[fontDensitySelector] = (node) => {
|
|
1063
|
-
handleFontDeclaration(node, handlerContext);
|
|
92
|
+
(0, import_handlers.handleFontDeclaration)(node, handlerContext);
|
|
1064
93
|
};
|
|
1065
94
|
visitors['Declaration[property="box-shadow"]'] = (node) => {
|
|
1066
|
-
handleBoxShadowDeclaration(node, handlerContext);
|
|
95
|
+
(0, import_handlers.handleBoxShadowDeclaration)(node, handlerContext);
|
|
1067
96
|
};
|
|
1068
97
|
if (overlappingProperties.length > 0) {
|
|
1069
|
-
const overlappingSelector = toSelector(overlappingProperties);
|
|
98
|
+
const overlappingSelector = (0, import_property_matcher.toSelector)(overlappingProperties);
|
|
1070
99
|
visitors[overlappingSelector] = (node) => {
|
|
1071
|
-
handleColorDeclaration(node, handlerContext);
|
|
1072
|
-
handleDensityDeclaration(node, handlerContext);
|
|
100
|
+
(0, import_handlers.handleColorDeclaration)(node, handlerContext);
|
|
101
|
+
(0, import_handlers.handleDensityDeclaration)(node, handlerContext);
|
|
1073
102
|
};
|
|
1074
103
|
}
|
|
1075
104
|
return visitors;
|