UNPKG

@salesforce-ux/eslint-plugin-slds

Version:

ESLint plugin provides custom linting rules specifically built for Salesforce Lightning Design System 2 (SLDS 2 beta)

343 lines (334 loc) 17.6 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // yaml-file:rule-messages.yml var require_rule_messages = __commonJS({ "yaml-file:rule-messages.yml"(exports2, module2) { module2.exports = { "no-slds-class-overrides": { "description": "Create new custom CSS classes instead of overriding SLDS selectors", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-slds-class-overrides", "type": "problem", "messages": { "sldsClassOverride": "Overriding .{{className}} isn't supported. To differentiate SLDS and custom classes, create a CSS class in your namespace. Examples: myapp-input, myapp-button." } }, "no-deprecated-slds-classes": { "description": "Please replace the deprecated classes with a modern equivalent", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-slds-classes", "type": "problem", "messages": { "deprecatedClass": "The class {{className}} is deprecated and not available in SLDS2. Please update to a supported class." } }, "no-deprecated-tokens-slds1": { "description": "Update outdated design tokens to SLDS 2 styling hooks with similar values. For more information, see Styling Hooks on lightningdesignsystem.com.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-tokens-slds1", "type": "problem", "messages": { "deprecatedToken": "Consider removing {{oldValue}} or replacing it with {{newValue}}. Set the fallback to {{oldValue}}. For more info, see Styling Hooks on lightningdesignsystem.com.", "noReplacement": "Update outdated design tokens to SLDS 2 styling hooks with similar values. For more information, see Styling Hooks on lightningdesignsystem.com." } }, "enforce-sds-to-slds-hooks": { "description": "Convert your existing --sds styling hooks to --slds styling hooks. See lightningdesignsystem.com for more info.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-sds-to-slds-hooks", "type": "problem", "messages": { "replaceSdsWithSlds": "Replace {{oldValue}} with {{suggestedMatch}} styling hook." } }, "enforce-bem-usage": { "description": "Replace BEM double-dash syntax in class names with single underscore syntax", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-bem-usage", "type": "problem", "messages": { "bemDoubleDash": "{{actual}} has been retired. Update it to the new name {{newValue}}.", "fixBemNaming": "Update to correct BEM naming convention" } }, "modal-close-button-issue": { "description": "Update component attributes or CSS classes for the modal close button to comply with the modal component blueprint", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#modal-close-button-issue", "type": "problem", "messages": { "modalCloseButtonIssue": "Update component attributes or CSS classes for the modal close button to comply with the modal component blueprint.", "removeClass": "Remove the slds-button_icon-inverse class from the modal close button in components that use the SLDS modal blueprint.", "changeVariant": "Change the variant attribute value from bare-inverse to bare in <lightning-button-icon> or <lightning-icon>.", "removeVariant": "Remove the variant attribute from the <lightning-icon> component inside the <button> element.", "ensureButtonClasses": "Add or move slds-button and slds-button_icon to the class attribute of the <button> element or <lightning-button-icon> component.", "ensureSizeAttribute": "To size icons properly, set the size attribute \u200Cto large in the <lightning-icon> and <lightning-button-icon> components." } }, "no-deprecated-classes-slds2": { "description": "Replace classes that aren't available with SLDS 2 classes", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-classes-slds2", "type": "problem", "messages": { "deprecatedClass": "The class {{className}} isn't available in SLDS 2. Update it to a class supported in SLDS 2. See lightningdesignsystem.com for more information.", "updateToModernClass": "Replace deprecated class with modern equivalent", "checkDocumentation": "See lightningdesignsystem.com for SLDS 2 class alternatives" } }, "lwc-token-to-slds-hook": { "description": "Replace the deprecated --lwc tokens with the latest --slds tokens. See lightningdesignsystem.com for more info.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#lwc-token-to-slds-hook", "type": "problem", "messages": { "errorWithReplacement": "The '{{oldValue}}' design token is deprecated. Replace it with '{{newValue}}'. For more info, see Global Styling Hooks on lightningdesignsystem.com.", "errorWithStyleHooks": "The '{{oldValue}}' design token is deprecated. Replace it with the SLDS 2 '{{newValue}}' styling hook and set the fallback to '{{oldValue}}'. For more info, see Global Styling Hooks on lightningdesignsystem.com.", "errorWithNoRecommendation": "The '{{oldValue}}' design token is deprecated. For more info, see the New Global Styling Hook Guidance on lightningdesignsystem.com." } }, "no-sldshook-fallback-for-lwctoken": { "description": "Avoid using --slds styling hooks as fallback values for --lwc tokens.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-sldshook-fallback-for-lwctoken", "type": "problem", "messages": { "unsupportedFallback": "Remove the {{sldsToken}} styling hook that is used as a fallback value for {{lwcToken}}." } }, "no-unsupported-hooks-slds2": { "description": "Identifies styling hooks that aren't present in SLDS 2. They must be replaced with styling hooks that have a similar effect, or they must be removed.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-unsupported-hooks-slds2", "type": "problem", "messages": { "deprecated": "The {{token}} styling hook isn't present in SLDS 2 and there's no equivalent replacement. Remove it or replace it with a styling hook with a similar effect." } }, "no-slds-var-without-fallback": { "description": "Add fallback values to SLDS styling hooks. The fallback values are used in Salesforce environments where styling hooks are unavailable.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-slds-var-without-fallback", "type": "problem", "messages": { "varWithoutFallback": "Your code uses the {{cssVar}} styling hook without a fallback value. Styling hooks are unavailable in some Salesforce environments. To render your component correctly in all environments, add this fallback value: var({{cssVar}}, {{recommendation}}). To make this fallback value brand-aware, use a branded design token instead of a static value. See Design Tokens on v1.lightningdesignsystem.com." } }, "no-slds-namespace-for-custom-hooks": { "description": "To differentiate custom styling hooks from SLDS styling hooks, create custom styling hooks in your namespace.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-slds-namespace-for-custom-hooks", "type": "problem", "messages": { "customHookNamespace": "Using the --slds namespace for {{token}} isn't supported. Create the custom styling hook in your namespace. Example: --myapp-{{tokenWithoutNamespace}}" } }, "no-slds-private-var": { "description": "Some SLDS styling hooks are private and reserved only for internal Salesforce use. Private SLDS styling hooks have prefixes --_slds- and --slds-s-. For more information, look up private CSS in lightningdesignsystem.com.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-slds-private-var", "type": "problem", "messages": { "privateVar": "This styling hook is reserved for internal Salesforce use. Remove the --_slds- or \u2013slds-s private variable within selector {{prop}}. For more information, look up private CSS in lightningdesignsystem.com." } }, "enforce-component-hook-naming-convention": { "description": "Replace component styling hooks that use a deprecated naming convention.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-component-hook-naming-convention", "type": "problem", "messages": { "replace": "Replace the deprecated {{oldValue}} component styling hook with {{suggestedMatch}}." } }, "no-hardcoded-values-slds1": { "description": "Replace static values with SLDS 1 design tokens. For more information, look up design tokens on lightningdesignsystem.com.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-hardcoded-value", "type": "suggestion", "messages": { "hardcodedValue": "Replace the {{oldValue}} static value with an SLDS 1 styling hook: {{newValue}}.", "noReplacement": "There's no replacement styling hook for the {{oldValue}} static value. Remove the static value." } }, "no-hardcoded-values-slds2": { "description": "Replace static values with SLDS 2 styling hooks. For more information, look up design tokens on lightningdesignsystem.com.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-hardcoded-values-slds2", "type": "suggestion", "messages": { "hardcodedValue": "Consider replacing the {{oldValue}} static value with an SLDS 2 styling hook that has a similar value: {{newValue}}.", "noReplacement": "There's no replacement styling hook for the {{oldValue}} static value. Remove the static value." } }, "reduce-annotations": { "description": "Remove your annotations and update your code.", "url": "https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#reduce-annotations", "type": "problem", "messages": { "removeAnnotation": "Remove this annotation and update the code to SLDS best practices. For help, file an issue at https://github.com/salesforce-ux/slds-linter/" } } }; } }); // src/rules/v9/no-slds-var-without-fallback.ts var no_slds_var_without_fallback_exports = {}; __export(no_slds_var_without_fallback_exports, { default: () => no_slds_var_without_fallback_default }); module.exports = __toCommonJS(no_slds_var_without_fallback_exports); var import_sds_metadata = __toESM(require("@salesforce-ux/sds-metadata")); var import_rule_messages = __toESM(require_rule_messages()); // src/utils/hardcoded-shared-utils.ts var import_css_tree2 = require("@eslint/css-tree"); // src/utils/color-lib-utils.ts var import_chroma_js = __toESM(require("chroma-js")); var import_css_tree = require("@eslint/css-tree"); // src/utils/css-functions.ts var CSS_FUNCTIONS = [ "attr", "calc", "color-mix", "conic-gradient", "counter", "cubic-bezier", "linear-gradient", "max", "min", "radial-gradient", "repeating-conic-gradient", "repeating-linear-gradient", "repeating-radial-gradient", "var" ]; var CSS_MATH_FUNCTIONS = ["calc", "min", "max"]; var cssFunctionsRegex = new RegExp(`(?:${CSS_FUNCTIONS.join("|")})`); var cssFunctionsExactRegex = new RegExp(`^(?:${CSS_FUNCTIONS.join("|")})$`); var cssMathFunctionsRegex = new RegExp(`^(?:${CSS_MATH_FUNCTIONS.join("|")})$`); // src/utils/hardcoded-shared-utils.ts function forEachValue(valueText, extractValue, shouldSkipNode, callback) { if (!valueText || typeof valueText !== "string") { return; } try { const ast = (0, import_css_tree2.parse)(valueText, { context: "value", positions: true }); (0, import_css_tree2.walk)(ast, { enter(node) { if (shouldSkipNode(node)) { return this.skip; } const value = extractValue(node); if (value !== null) { const positionInfo = { start: node.loc?.start, end: node.loc?.end }; callback(value, positionInfo); } } }); } catch (error) { return; } } // src/utils/css-utils.ts function extractCssVariable(node, filter) { if (!node || node.type !== "Function" || node.name !== "var") { return null; } if (!node.children) { return null; } const childrenArray = Array.from(node.children); if (childrenArray.length === 0) { return null; } const firstChild = childrenArray[0]; if (!firstChild || firstChild.type !== "Identifier") { return null; } const variableName = firstChild.name; if (!variableName) { return null; } return filter(variableName, childrenArray); } function forEachSldsVariable(valueText, callback) { const extractor = (node) => extractCssVariable(node, (variableName, childrenArray) => { if (!variableName.startsWith("--slds-")) { return null; } const hasFallback = childrenArray.some( (child) => child.type === "Operator" && child.value === "," ); return { name: variableName, hasFallback }; }); forEachValue(valueText, extractor, () => false, callback); } // src/rules/v9/no-slds-var-without-fallback.ts var ruleConfig = import_rule_messages.default["no-slds-var-without-fallback"]; var { type, description, url, messages } = ruleConfig; var sldsVariables = import_sds_metadata.default.slds1ExcludedVars || {}; var no_slds_var_without_fallback_default = { meta: { type, docs: { description, recommended: true, url }, fixable: "code", messages }, create(context) { return { "Declaration"(node) { const valueText = context.sourceCode.getText(node.value); if (!valueText) return; const variablesNeedingFallback = []; forEachSldsVariable(valueText, (variableInfo, positionInfo) => { const { name: cssVar, hasFallback } = variableInfo; if (hasFallback) return; const fallbackValue = sldsVariables[cssVar]; if (!fallbackValue) return; variablesNeedingFallback.push({ cssVar, fallbackValue, start: positionInfo.start?.offset || 0, end: positionInfo.end?.offset || 0 }); }); if (variablesNeedingFallback.length > 0) { let newValue = valueText; const sortedVariables = variablesNeedingFallback.sort((a, b) => b.start - a.start); sortedVariables.forEach(({ cssVar, fallbackValue, start, end }) => { const replacement = `var(${cssVar}, ${fallbackValue})`; newValue = newValue.substring(0, start) + replacement + newValue.substring(end); }); variablesNeedingFallback.forEach(({ cssVar, fallbackValue }) => { context.report({ node, messageId: "varWithoutFallback", data: { cssVar, recommendation: fallbackValue }, fix: (fixer) => fixer.replaceText(node.value, newValue) }); }); } } }; } }; //# sourceMappingURL=no-slds-var-without-fallback.js.map