@salesforce-ux/eslint-plugin-slds 0.5.1-internal → 0.5.2
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/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/rules/utils/node.ts", "../src/rules/enforce-bem-usage.ts", "../src/rules/no-deprecated-classes-slds2.ts", "../src/rules/utils/rule.ts", "../src/rules/modal-close-button-issue.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata/next';\nconst bemMapping = metadata.bemNaming;\nconst deprecatedClasses = metadata.deprecatedClasses;\n\n/**\n * Checks if a given className or its BEM mapped equivalent is deprecated.\n * \n * This function checks whether the provided className is included in the\n * `deprecatedClasses` list or if the BEM mapped class is deprecated.\n * \n * @param className - The class name to check for deprecation.\n * @returns A boolean indicating whether the className or its mapped version is deprecated.\n */\nconst isDeprecatedClass = (className : string) => {\n return (deprecatedClasses.includes(className) || deprecatedClasses.includes(bemMapping[className]))\n}\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Stylistic Issues\",\n recommended: true,\n description: \"Replace BEM double-dash syntax in class names with single underscore syntax.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-bem-usage\"\n },\n fixable: \"code\", // This rule can be fixed automatically\n schema: [\n {\n type: \"object\",\n properties: {\n pattern: { type: \"string\" }, // Regex pattern for BEM\n flags: { type: \"string\" }, // Regex flags\n },\n additionalProperties: false,\n },\n ],\n },\n\n create(context) { \n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && className in bemMapping && !isDeprecatedClass(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) + 7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n\n // Check whether a fixed class is available\n const newValue = bemMapping[className];\n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n actual: className,\n newValue\n },\n message: \"{{actual}} has been retired. Update it to the new name {{newValue}}.\",\n fix(fixer) {\n if (newValue) {\n const newClassValue = classAttr.value.value.replace(\n className,\n newValue\n );\n return fixer.replaceTextRange(\n [classAttr.value.range[0], classAttr.value.range[1]],\n `${newClassValue}`\n );\n }\n return null; // Ensure a return value even if no fix is applied\n },\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata/next';\nconst deprecatedClasses = metadata.deprecatedClasses;\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Best Practices\",\n recommended: true,\n description: \"Replace classes that aren\u2019t available with SLDS 2 classes. See lightningdesignsystem.com for more info.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-classes-slds2\"\n },\n schema: [], // No additional options needed\n },\n\n create(context) {\n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && deprecatedClasses.includes(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) +7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n \n \n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n className,\n },\n message: \"The class {{className}} isn't available in SLDS 2. Update it to a class supported in SLDS 2. See lightningdesignsystem.com for more information.\",\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};", "export const messages= {\n removeClass:\n \"Remove the slds-button_icon-inverse class from the modal close button in components that use the SLDS modal blueprint.\",\n changeVariant:\n \"Change the variant attribute value from bare-inverse to bare in <lightning-button-icon> or <lightning-icon>.\",\n removeVariant:\n \"Remove the variant attribute from the <lightning-icon> component inside the <button> element.\",\n ensureButtonClasses:\n \"Add or move slds-button and slds-button_icon to the class attribute of the <button> element or <lightning-button-icon> component.\",\n ensureSizeAttribute:\n \"To size icons properly, set the size attribute \u200Cto large in the <lightning-icon> and <lightning-button-icon> components.\",\n }", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport { messages } from \"./utils/rule\";\n\n// This rule specific to CVS, find more details here https://issues.salesforce.com/issue/a028c00000zh1iqAAA/modal-close-button-is-not-visible-with-the-new-white-background-after-winter-25-release\nexport = {\n meta: {\n type: \"problem\",\n docs: {\n category: \"Best Practices\",\n recommended: true,\n description: \"Update component attributes or CSS classes for the modal close button to comply with the modal component blueprint.\",\n url: \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#modal-close-button-issue\"\n },\n fixable: \"code\",\n schema: [],\n },\n\n create(context) {\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n\n const tagName = node.name;\n\n // \u2705 Scenario 1: Remove 'slds-button_icon-inverse' from <button> \n // (optional) when the parent of the button has class name `slds-modal`\n // and also button should have class `slds-modal__close`\n if (tagName === \"button\") {\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classList = classAttr.value.value.split(/\\s+/);\n\n // \u2705 Ensure button has \"slds-modal__close\" before proceeding\n if (!classList.includes(\"slds-modal__close\")) {\n return; // Stop execution if the class is missing\n }\n\n if (classList.includes(\"slds-button_icon-inverse\") || classList.includes(\"slds-button--icon-inverse\")) {\n const newClassList = classList\n .filter((cls) => (cls !== \"slds-button_icon-inverse\" && cls !== \"slds-button--icon-inverse\"))\n .join(\" \");\n context.report({\n node,\n loc: classAttr.loc,\n message: messages[\"removeClass\"],\n fix(fixer) { \n return fixer.replaceText(classAttr, // Replace the full attribute\n `class=\"${newClassList}\"` // Updated class list\n );\n },\n });\n }\n }\n }\n\n // \u2705 Scenario 2: Fix <lightning-button-icon> and this should have class `slds-modal__close`\n if (tagName === \"lightning-button-icon\" || tagName === \"lightning:buttonIcon\") {\n const variantAttr = findAttr(node, \"variant\");\n const sizeAttr = findAttr(node, \"size\");\n const classAttr = findAttr(node, \"class\");\n const iconClassAttr = findAttr(node, \"icon-class\"); // \uD83D\uDD0D Check for icon-class attribute\n \n function validateClassAttr(attribute, attrName) {\n if (attribute && attribute.value) {\n const classList = attribute.value.value.split(/\\s+/);\n\n // Irrespective of whether we are checking for class or icon-class we need to check whether the attribute is present or not.\n // \u2705 Ensure \"slds-modal__close\" exists before proceeding\n if(!classAttr?.value?.value?.includes(\"slds-modal__close\"))\n {\n return;\n }\n \n // \u2705 Ensure \"slds-modal__close\" exists before proceeding\n // if (!classList.includes(\"slds-modal__close\")) {\n // return; // Stop execution if the class is missing\n // }\n \n // Remove inverse classes\n if (classList.includes(\"slds-button_icon-inverse\") || classList.includes(\"slds-button--icon-inverse\")) {\n const newClassList = classList\n .filter((cls) => cls !== \"slds-button_icon-inverse\" && cls !== \"slds-button--icon-inverse\")\n .join(\" \");\n context.report({\n node,\n loc: attribute.loc,\n message: messages[\"removeClass\"],\n fix(fixer) {\n return fixer.replaceText(attribute, // Replace the full attribute\n `${attrName}=\"${newClassList}\"` // Correctly modifies the respective attribute\n );\n },\n });\n }\n \n // Ensure 'slds-button' and 'slds-button_icon' exist\n if (!classList.includes(\"slds-button\") || !classList.includes(\"slds-button_icon\")) {\n let newClassList;\n if(attrName === 'icon-class'){\n newClassList = [\n ...classList.filter((cls) => cls !== \"slds-button_icon-inverse\"),\n ].join(\" \");\n }else{\n newClassList = [\n \"slds-button\",\n \"slds-button_icon\",\n ...classList.filter((cls) => cls !== \"slds-button_icon-inverse\"),\n ].join(\" \");\n }\n context.report({\n node: attribute,\n loc: attribute.value.loc,\n message: messages[\"ensureButtonClasses\"],\n fix(fixer) {\n return fixer.replaceText(attribute.value, `${newClassList}`);\n },\n });}\n \n // Fix variant=\"bare-inverse\" to \"bare\"\n if (variantAttr && variantAttr.value && variantAttr.value.value === \"bare-inverse\") {\n context.report({\n node: variantAttr,\n message: messages[\"changeVariant\"],\n loc: variantAttr.value.loc,\n fix(fixer) {\n return fixer.replaceText(variantAttr.value, `bare`);\n },\n });\n }\n \n // Ensure size=\"large\" exists\n // if (!sizeAttr) {\n // context.report({\n // node,\n // message: messages[\"ensureSizeAttribute\"],\n // fix(fixer) {\n // if (variantAttr) {\n // return fixer.insertTextAfterRange([variantAttr.range[1], variantAttr.range[1]], ' size=\"large\"');\n // }\n // },\n // });\n // }\n }\n }\n \n // \u2705 Validate `class` and `icon-class` separately, maintaining their own attribute names\n validateClassAttr(classAttr, \"class\");\n validateClassAttr(iconClassAttr, \"icon-class\");\n }\n\n // \u2705 Scenario 3: Fix <lightning-icon> inside <button> & the class name of the parent name as button and it should have `slds-modal__close`\n if ((tagName === \"lightning-icon\" || tagName === \"lightning:icon\") && node.parent?.name === \"button\") {\n const parentClassAttr = findAttr(node.parent, \"class\");\n if (parentClassAttr && parentClassAttr.value) {\n const parentClassList = parentClassAttr.value.value.split(/\\s+/);\n\n // \u2705 Ensure the parent <button> has \"slds-modal__close\" before proceeding\n if (!parentClassList.includes(\"slds-modal__close\")) {\n return; // Stop execution if the class is missing\n }\n const variantAttr = findAttr(node, \"variant\");\n const sizeAttr = findAttr(node, \"size\");\n\n // Fix variant=\"bare-inverse\" to \"bare\"\n if (variantAttr && variantAttr.value && variantAttr.value.value === \"bare-inverse\") {\n context.report({\n node: variantAttr,\n message: messages[\"changeVariant\"],\n loc: variantAttr.value.loc,\n fix(fixer) {\n return fixer.replaceText(variantAttr.value, `bare`);\n },\n });\n }\n\n // // Remove variant attribute completely\n // if (variantAttr) {\n // context.report({\n // node: variantAttr,\n // messageId: \"removeVariant\",\n // fix(fixer) {\n // return fixer.remove(variantAttr);\n // },\n // });\n // }\n\n //Ensure size=\"large\" is set\n // if (!sizeAttr) {\n // context.report({\n // node,\n // message: messages[\"ensureSizeAttribute\"],\n // fix(fixer) {\n // //return fixer.insertTextAfter(node, ' size=\"large\"');\n // if(variantAttr)\n // {\n // return fixer.insertTextAfterRange([variantAttr.range[1], variantAttr.range[1]], ' size=\"large\"')\n // }\n // },\n // });\n // }\n }\n }\n }\n return {\n Tag: check,\n };\n },\n};", "// Unified ESLint plugin config for both v8 (legacy) and v9+ (flat)\n\nimport enforceBemUsage from './rules/enforce-bem-usage';\nimport noDeprecatedClassesSlds2 from './rules/no-deprecated-classes-slds2';\nimport modalCloseButtonIssue from './rules/modal-close-button-issue';\nimport htmlParser from \"@html-eslint/parser\";\n\nconst plugin = {\n meta: {\n name: \"@salesforce-ux/eslint-plugin-slds\",\n version: process.env.PLUGIN_VERSION\n },\n configs: {},\n rules: {\n \"enforce-bem-usage\": enforceBemUsage,\n \"no-deprecated-classes-slds2\": noDeprecatedClassesSlds2,\n \"modal-close-button-issue\": modalCloseButtonIssue\n }\n};\n\nObject.assign(plugin.configs, {\n // flat config format for ESLint v9+\n \"flat/recommended\": [\n {\n plugins: {\n \"@salesforce-ux/slds\": plugin,\n },\n rules: {\n \"@salesforce-ux/slds/enforce-bem-usage\": \"error\",\n \"@salesforce-ux/slds/no-deprecated-classes-slds2\": \"error\",\n \"@salesforce-ux/slds/modal-close-button-issue\": \"error\"\n },\n languageOptions: {\n parser: htmlParser,\n ecmaVersion: 2021,\n sourceType: \"module\"\n },\n files: [\"**/*.html\", \"**/*.cmp\"]\n }\n ],\n // legacy config for ESLint v8-\n recommended: {\n plugins: [\"@salesforce-ux/slds\"],\n rules: {\n \"@salesforce-ux/slds/enforce-bem-usage\": \"error\",\n \"@salesforce-ux/slds/no-deprecated-classes-slds2\": \"error\",\n \"@salesforce-ux/slds/modal-close-button-issue\": \"error\"\n },\n parser: htmlParser,\n parserOptions: {\n ecmaVersion: 2021,\n sourceType: \"module\"\n }\n }\n});\n\nmodule.exports = plugin;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,SAAS,SAAS,MAAM,KAAK;AAC3B,SAAO,KAAK,WAAW;AAAA,IACrB,CAAC,SAAS,KAAK,OAAO,KAAK,IAAI,MAAM,YAAY,MAAM,IAAI,YAAY;AAAA,EACzE;AACF;AAOA,SAAS,kBAAkB,MAAM;AAC/B,SAAO,CAAC,KAAK,cAAc,KAAK,WAAW,UAAU;AACvD;AAvBA,IAEA,eAsLM,kBACA;AAzLN;AAAA;AAEA,oBAA2B;AAsL3B,IAAM,mBAAmB;AACzB,IAAM,oBAAoB,IAAI,OAAO,iBAAiB,QAAQ,IAAI;AAAA;AAAA;;;ACzLlE;AAAA,mCAAAA,UAAAC,SAAA;AAAA;AACA,
|
|
4
|
+
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata';\nconst bemMapping = metadata.bemNaming;\nconst deprecatedClasses = metadata.deprecatedClasses;\n\n/**\n * Checks if a given className or its BEM mapped equivalent is deprecated.\n * \n * This function checks whether the provided className is included in the\n * `deprecatedClasses` list or if the BEM mapped class is deprecated.\n * \n * @param className - The class name to check for deprecation.\n * @returns A boolean indicating whether the className or its mapped version is deprecated.\n */\nconst isDeprecatedClass = (className : string) => {\n return (deprecatedClasses.includes(className) || deprecatedClasses.includes(bemMapping[className]))\n}\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Stylistic Issues\",\n recommended: true,\n description: \"Replace BEM double-dash syntax in class names with single underscore syntax.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-bem-usage\"\n },\n fixable: \"code\", // This rule can be fixed automatically\n schema: [\n {\n type: \"object\",\n properties: {\n pattern: { type: \"string\" }, // Regex pattern for BEM\n flags: { type: \"string\" }, // Regex flags\n },\n additionalProperties: false,\n },\n ],\n },\n\n create(context) { \n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && className in bemMapping && !isDeprecatedClass(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) + 7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n\n // Check whether a fixed class is available\n const newValue = bemMapping[className];\n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n actual: className,\n newValue\n },\n message: \"{{actual}} has been retired. Update it to the new name {{newValue}}.\",\n fix(fixer) {\n if (newValue) {\n const newClassValue = classAttr.value.value.replace(\n className,\n newValue\n );\n return fixer.replaceTextRange(\n [classAttr.value.range[0], classAttr.value.range[1]],\n `${newClassValue}`\n );\n }\n return null; // Ensure a return value even if no fix is applied\n },\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata';\nconst deprecatedClasses = metadata.deprecatedClasses;\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Best Practices\",\n recommended: true,\n description: \"Replace classes that aren\u2019t available with SLDS 2 classes. See lightningdesignsystem.com for more info.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-classes-slds2\"\n },\n schema: [], // No additional options needed\n },\n\n create(context) {\n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && deprecatedClasses.includes(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) +7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n \n \n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n className,\n },\n message: \"The class {{className}} isn't available in SLDS 2. Update it to a class supported in SLDS 2. See lightningdesignsystem.com for more information.\",\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};", "export const messages= {\n removeClass:\n \"Remove the slds-button_icon-inverse class from the modal close button in components that use the SLDS modal blueprint.\",\n changeVariant:\n \"Change the variant attribute value from bare-inverse to bare in <lightning-button-icon> or <lightning-icon>.\",\n removeVariant:\n \"Remove the variant attribute from the <lightning-icon> component inside the <button> element.\",\n ensureButtonClasses:\n \"Add or move slds-button and slds-button_icon to the class attribute of the <button> element or <lightning-button-icon> component.\",\n ensureSizeAttribute:\n \"To size icons properly, set the size attribute \u200Cto large in the <lightning-icon> and <lightning-button-icon> components.\",\n }", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport { messages } from \"./utils/rule\";\n\n// This rule specific to CVS, find more details here https://issues.salesforce.com/issue/a028c00000zh1iqAAA/modal-close-button-is-not-visible-with-the-new-white-background-after-winter-25-release\nexport = {\n meta: {\n type: \"problem\",\n docs: {\n category: \"Best Practices\",\n recommended: true,\n description: \"Update component attributes or CSS classes for the modal close button to comply with the modal component blueprint.\",\n url: \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#modal-close-button-issue\"\n },\n fixable: \"code\",\n schema: [],\n },\n\n create(context) {\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n\n const tagName = node.name;\n\n // \u2705 Scenario 1: Remove 'slds-button_icon-inverse' from <button> \n // (optional) when the parent of the button has class name `slds-modal`\n // and also button should have class `slds-modal__close`\n if (tagName === \"button\") {\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classList = classAttr.value.value.split(/\\s+/);\n\n // \u2705 Ensure button has \"slds-modal__close\" before proceeding\n if (!classList.includes(\"slds-modal__close\")) {\n return; // Stop execution if the class is missing\n }\n\n if (classList.includes(\"slds-button_icon-inverse\") || classList.includes(\"slds-button--icon-inverse\")) {\n const newClassList = classList\n .filter((cls) => (cls !== \"slds-button_icon-inverse\" && cls !== \"slds-button--icon-inverse\"))\n .join(\" \");\n context.report({\n node,\n loc: classAttr.loc,\n message: messages[\"removeClass\"],\n fix(fixer) { \n return fixer.replaceText(classAttr, // Replace the full attribute\n `class=\"${newClassList}\"` // Updated class list\n );\n },\n });\n }\n }\n }\n\n // \u2705 Scenario 2: Fix <lightning-button-icon> and this should have class `slds-modal__close`\n if (tagName === \"lightning-button-icon\" || tagName === \"lightning:buttonIcon\") {\n const variantAttr = findAttr(node, \"variant\");\n const sizeAttr = findAttr(node, \"size\");\n const classAttr = findAttr(node, \"class\");\n const iconClassAttr = findAttr(node, \"icon-class\"); // \uD83D\uDD0D Check for icon-class attribute\n \n function validateClassAttr(attribute, attrName) {\n if (attribute && attribute.value) {\n const classList = attribute.value.value.split(/\\s+/);\n\n // Irrespective of whether we are checking for class or icon-class we need to check whether the attribute is present or not.\n // \u2705 Ensure \"slds-modal__close\" exists before proceeding\n if(!classAttr?.value?.value?.includes(\"slds-modal__close\"))\n {\n return;\n }\n \n // \u2705 Ensure \"slds-modal__close\" exists before proceeding\n // if (!classList.includes(\"slds-modal__close\")) {\n // return; // Stop execution if the class is missing\n // }\n \n // Remove inverse classes\n if (classList.includes(\"slds-button_icon-inverse\") || classList.includes(\"slds-button--icon-inverse\")) {\n const newClassList = classList\n .filter((cls) => cls !== \"slds-button_icon-inverse\" && cls !== \"slds-button--icon-inverse\")\n .join(\" \");\n context.report({\n node,\n loc: attribute.loc,\n message: messages[\"removeClass\"],\n fix(fixer) {\n return fixer.replaceText(attribute, // Replace the full attribute\n `${attrName}=\"${newClassList}\"` // Correctly modifies the respective attribute\n );\n },\n });\n }\n \n // Ensure 'slds-button' and 'slds-button_icon' exist\n if (!classList.includes(\"slds-button\") || !classList.includes(\"slds-button_icon\")) {\n let newClassList;\n if(attrName === 'icon-class'){\n newClassList = [\n ...classList.filter((cls) => cls !== \"slds-button_icon-inverse\"),\n ].join(\" \");\n }else{\n newClassList = [\n \"slds-button\",\n \"slds-button_icon\",\n ...classList.filter((cls) => cls !== \"slds-button_icon-inverse\"),\n ].join(\" \");\n }\n context.report({\n node: attribute,\n loc: attribute.value.loc,\n message: messages[\"ensureButtonClasses\"],\n fix(fixer) {\n return fixer.replaceText(attribute.value, `${newClassList}`);\n },\n });}\n \n // Fix variant=\"bare-inverse\" to \"bare\"\n if (variantAttr && variantAttr.value && variantAttr.value.value === \"bare-inverse\") {\n context.report({\n node: variantAttr,\n message: messages[\"changeVariant\"],\n loc: variantAttr.value.loc,\n fix(fixer) {\n return fixer.replaceText(variantAttr.value, `bare`);\n },\n });\n }\n \n // Ensure size=\"large\" exists\n // if (!sizeAttr) {\n // context.report({\n // node,\n // message: messages[\"ensureSizeAttribute\"],\n // fix(fixer) {\n // if (variantAttr) {\n // return fixer.insertTextAfterRange([variantAttr.range[1], variantAttr.range[1]], ' size=\"large\"');\n // }\n // },\n // });\n // }\n }\n }\n \n // \u2705 Validate `class` and `icon-class` separately, maintaining their own attribute names\n validateClassAttr(classAttr, \"class\");\n validateClassAttr(iconClassAttr, \"icon-class\");\n }\n\n // \u2705 Scenario 3: Fix <lightning-icon> inside <button> & the class name of the parent name as button and it should have `slds-modal__close`\n if ((tagName === \"lightning-icon\" || tagName === \"lightning:icon\") && node.parent?.name === \"button\") {\n const parentClassAttr = findAttr(node.parent, \"class\");\n if (parentClassAttr && parentClassAttr.value) {\n const parentClassList = parentClassAttr.value.value.split(/\\s+/);\n\n // \u2705 Ensure the parent <button> has \"slds-modal__close\" before proceeding\n if (!parentClassList.includes(\"slds-modal__close\")) {\n return; // Stop execution if the class is missing\n }\n const variantAttr = findAttr(node, \"variant\");\n const sizeAttr = findAttr(node, \"size\");\n\n // Fix variant=\"bare-inverse\" to \"bare\"\n if (variantAttr && variantAttr.value && variantAttr.value.value === \"bare-inverse\") {\n context.report({\n node: variantAttr,\n message: messages[\"changeVariant\"],\n loc: variantAttr.value.loc,\n fix(fixer) {\n return fixer.replaceText(variantAttr.value, `bare`);\n },\n });\n }\n\n // // Remove variant attribute completely\n // if (variantAttr) {\n // context.report({\n // node: variantAttr,\n // messageId: \"removeVariant\",\n // fix(fixer) {\n // return fixer.remove(variantAttr);\n // },\n // });\n // }\n\n //Ensure size=\"large\" is set\n // if (!sizeAttr) {\n // context.report({\n // node,\n // message: messages[\"ensureSizeAttribute\"],\n // fix(fixer) {\n // //return fixer.insertTextAfter(node, ' size=\"large\"');\n // if(variantAttr)\n // {\n // return fixer.insertTextAfterRange([variantAttr.range[1], variantAttr.range[1]], ' size=\"large\"')\n // }\n // },\n // });\n // }\n }\n }\n }\n return {\n Tag: check,\n };\n },\n};", "// Unified ESLint plugin config for both v8 (legacy) and v9+ (flat)\n\nimport enforceBemUsage from './rules/enforce-bem-usage';\nimport noDeprecatedClassesSlds2 from './rules/no-deprecated-classes-slds2';\nimport modalCloseButtonIssue from './rules/modal-close-button-issue';\nimport htmlParser from \"@html-eslint/parser\";\n\nconst plugin = {\n meta: {\n name: \"@salesforce-ux/eslint-plugin-slds\",\n version: process.env.PLUGIN_VERSION\n },\n configs: {},\n rules: {\n \"enforce-bem-usage\": enforceBemUsage,\n \"no-deprecated-classes-slds2\": noDeprecatedClassesSlds2,\n \"modal-close-button-issue\": modalCloseButtonIssue\n }\n};\n\nObject.assign(plugin.configs, {\n // flat config format for ESLint v9+\n \"flat/recommended\": [\n {\n plugins: {\n \"@salesforce-ux/slds\": plugin,\n },\n rules: {\n \"@salesforce-ux/slds/enforce-bem-usage\": \"error\",\n \"@salesforce-ux/slds/no-deprecated-classes-slds2\": \"error\",\n \"@salesforce-ux/slds/modal-close-button-issue\": \"error\"\n },\n languageOptions: {\n parser: htmlParser,\n ecmaVersion: 2021,\n sourceType: \"module\"\n },\n files: [\"**/*.html\", \"**/*.cmp\"]\n }\n ],\n // legacy config for ESLint v8-\n recommended: {\n plugins: [\"@salesforce-ux/slds\"],\n rules: {\n \"@salesforce-ux/slds/enforce-bem-usage\": \"error\",\n \"@salesforce-ux/slds/no-deprecated-classes-slds2\": \"error\",\n \"@salesforce-ux/slds/modal-close-button-issue\": \"error\"\n },\n parser: htmlParser,\n parserOptions: {\n ecmaVersion: 2021,\n sourceType: \"module\"\n }\n }\n});\n\nmodule.exports = plugin;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["exports", "module", "metadata", "exports", "module", "metadata", "exports", "module", "import_parser", "enforceBemUsage", "noDeprecatedClassesSlds2", "modalCloseButtonIssue", "htmlParser"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rules/utils/node.ts", "../../src/rules/enforce-bem-usage.ts"],
|
|
4
|
-
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAEA,oBAA2B;AAQ3B,SAAS,SAAS,MAAM,KAAK;AAC3B,SAAO,KAAK,WAAW;AAAA,IACrB,CAAC,SAAS,KAAK,OAAO,KAAK,IAAI,MAAM,YAAY,MAAM,IAAI,YAAY;AAAA,EACzE;AACF;AAOA,SAAS,kBAAkB,MAAM;AAC/B,SAAO,CAAC,KAAK,cAAc,KAAK,WAAW,UAAU;AACvD;AAiKA,IAAM,mBAAmB;AACzB,IAAM,oBAAoB,IAAI,OAAO,iBAAiB,QAAQ,IAAI;;;ACxLlE,
|
|
4
|
+
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata';\nconst bemMapping = metadata.bemNaming;\nconst deprecatedClasses = metadata.deprecatedClasses;\n\n/**\n * Checks if a given className or its BEM mapped equivalent is deprecated.\n * \n * This function checks whether the provided className is included in the\n * `deprecatedClasses` list or if the BEM mapped class is deprecated.\n * \n * @param className - The class name to check for deprecation.\n * @returns A boolean indicating whether the className or its mapped version is deprecated.\n */\nconst isDeprecatedClass = (className : string) => {\n return (deprecatedClasses.includes(className) || deprecatedClasses.includes(bemMapping[className]))\n}\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Stylistic Issues\",\n recommended: true,\n description: \"Replace BEM double-dash syntax in class names with single underscore syntax.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#enforce-bem-usage\"\n },\n fixable: \"code\", // This rule can be fixed automatically\n schema: [\n {\n type: \"object\",\n properties: {\n pattern: { type: \"string\" }, // Regex pattern for BEM\n flags: { type: \"string\" }, // Regex flags\n },\n additionalProperties: false,\n },\n ],\n },\n\n create(context) { \n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && className in bemMapping && !isDeprecatedClass(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) + 7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n\n // Check whether a fixed class is available\n const newValue = bemMapping[className];\n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n actual: className,\n newValue\n },\n message: \"{{actual}} has been retired. Update it to the new name {{newValue}}.\",\n fix(fixer) {\n if (newValue) {\n const newClassValue = classAttr.value.value.replace(\n className,\n newValue\n );\n return fixer.replaceTextRange(\n [classAttr.value.range[0], classAttr.value.range[1]],\n `${newClassValue}`\n );\n }\n return null; // Ensure a return value even if no fix is applied\n },\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAEA,oBAA2B;AAQ3B,SAAS,SAAS,MAAM,KAAK;AAC3B,SAAO,KAAK,WAAW;AAAA,IACrB,CAAC,SAAS,KAAK,OAAO,KAAK,IAAI,MAAM,YAAY,MAAM,IAAI,YAAY;AAAA,EACzE;AACF;AAOA,SAAS,kBAAkB,MAAM;AAC/B,SAAO,CAAC,KAAK,cAAc,KAAK,WAAW,UAAU;AACvD;AAiKA,IAAM,mBAAmB;AACzB,IAAM,oBAAoB,IAAI,OAAO,iBAAiB,QAAQ,IAAI;;;ACxLlE,0BAAqB;AACrB,IAAM,aAAa,oBAAAA,QAAS;AAC5B,IAAM,oBAAoB,oBAAAA,QAAS;AAWnC,IAAM,oBAAoB,CAAC,cAAuB;AAChD,SAAQ,kBAAkB,SAAS,SAAS,KAAK,kBAAkB,SAAS,WAAW,SAAS,CAAC;AACnG;AAEA,iBAAS;AAAA,EACP,MAAM;AAAA,IACJ,MAAM;AAAA;AAAA,IACN,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,KAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA;AAAA,IACT,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,SAAS,EAAE,MAAM,SAAS;AAAA;AAAA,UAC1B,OAAO,EAAE,MAAM,SAAS;AAAA;AAAA,QAC1B;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,SAAS;AAEd,aAAS,MAAM,MAAM;AACnB,UAAI,kBAAkB,IAAI,GAAG;AAC3B;AAAA,MACF;AACA,YAAM,YAAY,SAAS,MAAM,OAAO;AACxC,UAAI,aAAa,UAAU,OAAO;AAChC,cAAM,aAAa,UAAU,MAAM,MAAM,MAAM,KAAK;AACpD,mBAAW,QAAQ,CAAC,cAAc;AAChC,cAAI,aAAa,aAAa,cAAc,CAAC,kBAAkB,SAAS,GAAG;AAEzE,kBAAM,iBAAiB,UAAU,MAAM,MAAM,QAAQ,SAAS,IAAI;AAClE,kBAAM,eAAe,iBAAiB,UAAU;AAGhD,kBAAM,WAAW;AAAA,cACf,MAAM,UAAU,IAAI,MAAM;AAAA,cAC1B,QAAQ,UAAU,IAAI,MAAM,SAAS;AAAA,YACvC;AACA,kBAAM,SAAS;AAAA,cACb,MAAM,UAAU,IAAI,MAAM;AAAA,cAC1B,QAAQ,UAAU,IAAI,MAAM,SAAS;AAAA,YACvC;AAGA,kBAAM,WAAW,WAAW,SAAS;AACrC,oBAAQ,OAAO;AAAA,cACb;AAAA,cACA,KAAK,EAAE,OAAO,UAAU,KAAK,OAAO;AAAA,cACpC,MAAM;AAAA,gBACJ,QAAQ;AAAA,gBACR;AAAA,cACF;AAAA,cACA,SAAS;AAAA,cACT,IAAI,OAAO;AACT,oBAAI,UAAU;AACZ,wBAAM,gBAAgB,UAAU,MAAM,MAAM;AAAA,oBAC1C;AAAA,oBACA;AAAA,kBACF;AACA,yBAAO,MAAM;AAAA,oBACX,CAAC,UAAU,MAAM,MAAM,CAAC,GAAG,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,oBACnD,GAAG,aAAa;AAAA,kBAClB;AAAA,gBACF;AACA,uBAAO;AAAA,cACT;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["metadata"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/rules/utils/node.ts", "../../src/rules/no-deprecated-classes-slds2.ts"],
|
|
4
|
-
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAEA,oBAA2B;AAQ3B,SAAS,SAAS,MAAM,KAAK;AAC3B,SAAO,KAAK,WAAW;AAAA,IACrB,CAAC,SAAS,KAAK,OAAO,KAAK,IAAI,MAAM,YAAY,MAAM,IAAI,YAAY;AAAA,EACzE;AACF;AAOA,SAAS,kBAAkB,MAAM;AAC/B,SAAO,CAAC,KAAK,cAAc,KAAK,WAAW,UAAU;AACvD;AAiKA,IAAM,mBAAmB;AACzB,IAAM,oBAAoB,IAAI,OAAO,iBAAiB,QAAQ,IAAI;;;ACxLlE,
|
|
4
|
+
"sourcesContent": ["// THIS IS TAKEN FROM html-eslint\n\nimport { NODE_TYPES } from \"@html-eslint/parser\";\n\n\n/**\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @param {string} key\n * @returns {AttributeNode | undefined}\n */\nfunction findAttr(node, key) {\n return node.attributes.find(\n (attr) => attr.key && attr.key.value.toLowerCase() === key.toLowerCase()\n );\n}\n\n/**\n * Checks whether a node's attributes is empty or not.\n * @param {TagNode | ScriptTagNode | StyleTagNode} node\n * @returns {boolean}\n */\nfunction isAttributesEmpty(node) {\n return !node.attributes || node.attributes.length <= 0;\n}\n\n/**\n * Checks whether a node's all tokens are on the same line or not.\n * @param {AnyNode} node A node to check\n * @returns {boolean} `true` if a node's tokens are on the same line, otherwise `false`.\n */\nfunction isNodeTokensOnSameLine(node) {\n return node.loc.start.line === node.loc.end.line;\n}\n\n/**\n *\n * @param {Range} rangeA\n * @param {Range} rangeB\n * @returns {boolean}\n */\nfunction isRangesOverlap(rangeA, rangeB) {\n return rangeA[0] < rangeB[1] && rangeB[0] < rangeA[1];\n}\n\n/**\n * @param {(TextNode | CommentContentNode)['templates']} templates\n * @param {Range} range\n * @returns {boolean}\n */\nfunction isOverlapWithTemplates(templates, range) {\n return templates\n .filter((template) => template.isTemplate)\n .some((template) => isRangesOverlap(template.range, range));\n}\n\n/**\n *\n * @param {TextNode | CommentContentNode} node\n * @returns {LineNode[]}\n */\nfunction splitToLineNodes(node) {\n let start = node.range[0];\n let line = node.loc.start.line;\n const startCol = node.loc.start.column;\n /**\n * @type {LineNode[]}\n */\n const lineNodes = [];\n const templates = node.templates || [];\n /**\n *\n * @param {import(\"../../types\").Range} range\n */\n function shouldSkipIndentCheck(range) {\n const overlappedTemplates = templates.filter(\n (template) =>\n template.isTemplate && isRangesOverlap(template.range, range)\n );\n\n const isLineInTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] >= range[1];\n });\n if (isLineInTemplate) {\n return true;\n }\n const isLineBeforeTemplate = overlappedTemplates.some((template) => {\n return template.range[0] <= range[0] && template.range[1] <= range[1];\n });\n if (isLineBeforeTemplate) {\n return true;\n }\n const isLineAfterTemplate = overlappedTemplates.some((template) => {\n return template.range[1] <= range[0];\n });\n if (isLineAfterTemplate) {\n return true;\n }\n return false;\n }\n\n node.value.split(\"\\n\").forEach((value, index) => {\n const columnStart = index === 0 ? startCol : 0;\n /**\n * @type {import(\"../../types\").Range}\n */\n const range = [start, start + value.length];\n const loc = {\n start: {\n line,\n column: columnStart,\n },\n end: {\n line,\n column: columnStart + value.length,\n },\n };\n /**\n * @type {LineNode}\n */\n const lineNode = {\n type: \"Line\",\n value,\n range,\n loc,\n skipIndentCheck: shouldSkipIndentCheck(range),\n };\n\n start += value.length + 1;\n line += 1;\n\n lineNodes.push(lineNode);\n });\n\n return lineNodes;\n}\n\n/**\n * Get location between two nodes.\n * @param {BaseNode} before A node placed in before\n * @param {BaseNode} after A node placed in after\n * @returns {Location} location between two nodes.\n */\nfunction getLocBetween(before, after) {\n return {\n start: before.loc.end,\n end: after.loc.start,\n };\n}\n\n/**\n * @param {AttributeValueNode} node\n * @return {boolean}\n */\nfunction isExpressionInTemplate(node) {\n if (node.type === NODE_TYPES.AttributeValue) {\n return node.value.indexOf(\"${\") === 0;\n }\n return false;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TagNode}\n */\nfunction isTag(node) {\n return node.type === NODE_TYPES.Tag;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is CommentNode}\n */\nfunction isComment(node) {\n return node.type === NODE_TYPES.Comment;\n}\n\n/**\n * @param {AnyNode} node\n * @returns {node is TextNode}\n */\nfunction isText(node) {\n return node.type === NODE_TYPES.Text;\n}\n\nconst lineBreakPattern = /\\r\\n|[\\r\\n\\u2028\\u2029]/u;\nconst lineEndingPattern = new RegExp(lineBreakPattern.source, \"gu\");\n/**\n * @param {string} source\n * @returns {string[]}\n */\nfunction codeToLines(source) {\n return source.split(lineEndingPattern);\n}\n\n/**\n *\n * @param {AnyToken[]} tokens\n * @returns {((CommentContentNode | TextNode)['templates'][number])[]}\n */\nfunction getTemplateTokens(tokens) {\n return (\n []\n .concat(\n ...tokens\n // @ts-ignore\n .map((token) => token[\"templates\"] || [])\n )\n // @ts-ignore\n .filter((token) => token.isTemplate)\n );\n}\n\nexport {\n findAttr,\n isAttributesEmpty,\n isNodeTokensOnSameLine,\n splitToLineNodes,\n getLocBetween,\n isExpressionInTemplate,\n isTag,\n isComment,\n isText,\n isOverlapWithTemplates,\n codeToLines,\n isRangesOverlap,\n getTemplateTokens,\n};\n", "import { findAttr, isAttributesEmpty } from \"./utils/node\";\nimport metadata from '@salesforce-ux/sds-metadata';\nconst deprecatedClasses = metadata.deprecatedClasses;\n\nexport = {\n meta: {\n type: \"problem\", // The rule type\n docs: {\n category: \"Best Practices\",\n recommended: true,\n description: \"Replace classes that aren\u2019t available with SLDS 2 classes. See lightningdesignsystem.com for more info.\",\n url : \"https://developer.salesforce.com/docs/platform/slds-linter/guide/reference-rules.html#no-deprecated-classes-slds2\"\n },\n schema: [], // No additional options needed\n },\n\n create(context) {\n\n function check(node) {\n if (isAttributesEmpty(node)) {\n return;\n }\n\n const classAttr = findAttr(node, \"class\");\n if (classAttr && classAttr.value) {\n const classNames = classAttr.value.value.split(/\\s+/);\n classNames.forEach((className) => {\n if (className && deprecatedClasses.includes(className)) {\n // Find the exact location of the problematic class name\n const classNameStart = classAttr.value.value.indexOf(className) +7; // 7 here is for `class= \"`\n const classNameEnd = classNameStart + className.length;\n\n // Use the loc property to get line and column from the class attribute\n const startLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameStart,\n };\n const endLoc = {\n line: classAttr.loc.start.line,\n column: classAttr.loc.start.column + classNameEnd,\n };\n \n \n context.report({\n node,\n loc: { start: startLoc, end: endLoc },\n data: {\n className,\n },\n message: \"The class {{className}} isn't available in SLDS 2. Update it to a class supported in SLDS 2. See lightningdesignsystem.com for more information.\",\n });\n }\n });\n }\n }\n\n return {\n Tag: check,\n };\n },\n};"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAEA,oBAA2B;AAQ3B,SAAS,SAAS,MAAM,KAAK;AAC3B,SAAO,KAAK,WAAW;AAAA,IACrB,CAAC,SAAS,KAAK,OAAO,KAAK,IAAI,MAAM,YAAY,MAAM,IAAI,YAAY;AAAA,EACzE;AACF;AAOA,SAAS,kBAAkB,MAAM;AAC/B,SAAO,CAAC,KAAK,cAAc,KAAK,WAAW,UAAU;AACvD;AAiKA,IAAM,mBAAmB;AACzB,IAAM,oBAAoB,IAAI,OAAO,iBAAiB,QAAQ,IAAI;;;ACxLlE,0BAAqB;AACrB,IAAM,oBAAoB,oBAAAA,QAAS;AAEnC,iBAAS;AAAA,EACP,MAAM;AAAA,IACJ,MAAM;AAAA;AAAA,IACN,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,KAAM;AAAA,IACR;AAAA,IACA,QAAQ,CAAC;AAAA;AAAA,EACX;AAAA,EAEA,OAAO,SAAS;AAEd,aAAS,MAAM,MAAM;AACnB,UAAI,kBAAkB,IAAI,GAAG;AAC3B;AAAA,MACF;AAEA,YAAM,YAAY,SAAS,MAAM,OAAO;AACxC,UAAI,aAAa,UAAU,OAAO;AAChC,cAAM,aAAa,UAAU,MAAM,MAAM,MAAM,KAAK;AACpD,mBAAW,QAAQ,CAAC,cAAc;AAChC,cAAI,aAAa,kBAAkB,SAAS,SAAS,GAAG;AAEtD,kBAAM,iBAAiB,UAAU,MAAM,MAAM,QAAQ,SAAS,IAAG;AACjE,kBAAM,eAAe,iBAAiB,UAAU;AAGhD,kBAAM,WAAW;AAAA,cACb,MAAM,UAAU,IAAI,MAAM;AAAA,cAC1B,QAAQ,UAAU,IAAI,MAAM,SAAS;AAAA,YACzC;AACA,kBAAM,SAAS;AAAA,cACX,MAAM,UAAU,IAAI,MAAM;AAAA,cAC1B,QAAQ,UAAU,IAAI,MAAM,SAAS;AAAA,YACzC;AAGA,oBAAQ,OAAO;AAAA,cACb;AAAA,cACA,KAAK,EAAE,OAAO,UAAU,KAAK,OAAO;AAAA,cACpC,MAAM;AAAA,gBACJ;AAAA,cACF;AAAA,cACA,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["metadata"]
|
|
7
7
|
}
|