UNPKG

@atlaskit/eslint-plugin-design-system

Version:

The essential plugin for use with the Atlassian Design System.

70 lines 3.11 kB
import { isNodeOfType } from 'eslint-codemod-utils'; import { createLintRule } from '../utils/create-lint-rule'; const rule = createLintRule({ meta: { name: 'use-cx-function-in-xcss', fixable: 'code', hasSuggestions: true, type: 'problem', docs: { description: 'Enforces cx function use to combine styles in xcss.', recommended: true, severity: 'error' }, messages: { useCxFunc: `Use the cx function when combining styles in the xcss prop.` } }, create(context) { let importStatement = null; const primitiveNames = new Set(); return { "ImportDeclaration[source.value='@atlaskit/css']"(node) { importStatement = { node }; for (const specifier of node.specifiers) { if (specifier.type === 'ImportSpecifier' && 'name' in specifier.imported && specifier.imported.name === 'cx') { importStatement.cxFuncLocalName = specifier.local.name; } } }, 'ImportDeclaration[source.value="@atlaskit/primitives/compiled"]'(node) { for (const specifier of node.specifiers) { primitiveNames.add(specifier.local.name); } }, 'JSXAttribute > JSXIdentifier[name=/[xX]css$/]'(node) { const xcssValue = node.parent && isNodeOfType(node.parent, 'JSXAttribute') && node.parent.value && isNodeOfType(node.parent.value, 'JSXExpressionContainer') ? node.parent.value : undefined; if (!xcssValue) { return; } const jsxElementName = node.parent.parent && isNodeOfType(node.parent.parent, 'JSXOpeningElement') && node.parent.parent.name && isNodeOfType(node.parent.parent.name, 'JSXIdentifier') ? node.parent.parent.name.name : undefined; if (!jsxElementName) { return; } // check if this JSX element is from the primitives entry point and if prop value is an array if (primitiveNames.has(jsxElementName) && xcssValue.expression.type === 'ArrayExpression') { context.report({ node: xcssValue, messageId: 'useCxFunc', fix: fixer => { const fixes = []; const sourceCode = context.sourceCode; const styles = sourceCode.getText(xcssValue.expression); fixes.push(fixer.replaceText(xcssValue, (importStatement && importStatement.cxFuncLocalName ? `{${importStatement.cxFuncLocalName}` : `{cx`) + `(${styles.replace(/^\[/, '').replace(/\]$/, '')})}`)); if (!importStatement) { fixes.push(fixer.insertTextBeforeRange([0, 0], `import { cx } from '@atlaskit/css';\n`)); } else if (!importStatement.cxFuncLocalName) { const importText = sourceCode.getText(importStatement.node); fixes.push(fixer.replaceText(importStatement.node, importText.includes('{') ? importText.replace(/import(.*) {\s?/, `import$1 { cx, `) : importText.replace(/ from /, `, { cx } from `))); } return fixes; } }); } } }; } }); export default rule;