@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
80 lines (79 loc) • 3.27 kB
JavaScript
import { isNodeOfType } from 'eslint-codemod-utils';
import { createLintRule } from '../utils/create-lint-rule';
var rule = createLintRule({
meta: {
name: 'no-margin',
type: 'problem',
docs: {
recommended: false,
severity: 'warn',
description: 'Disallow using the margin CSS property.'
},
messages: {
noMargin: 'The use of `margin` is considered dangerous as it breaks the component model. Prefer a primitive spacing component or the application of `gap` via CSS Flexbox or Grid to achieve the same result and control the layout from the parent.'
}
},
create: function create(context) {
return {
// CSSObjectExpression and StyledObjectExpression
// const cssObjectExpression = css({ margin: '4px' })
// const styledObjectExpression = styled.div({margin: '8px'})
'CallExpression[callee.name=css] > ObjectExpression, CallExpression[callee.object.name=styled] > ObjectExpression': function CallExpressionCalleeNameCss__ObjectExpression_CallExpressionCalleeObjectNameStyled__ObjectExpression(parentNode) {
if (!isNodeOfType(parentNode, 'ObjectExpression')) {
return;
}
var _findObjectStyles = function findObjectStyles(node) {
if (!isNodeOfType(node, 'Property')) {
return;
}
if (isNodeOfType(node.value, 'ObjectExpression')) {
return node.value.properties.forEach(_findObjectStyles);
}
if (!isNodeOfType(node.key, 'Identifier')) {
return;
}
if (node.key.name.includes('margin')) {
context.report({
node: node,
messageId: 'noMargin'
});
}
return;
};
parentNode.properties.forEach(_findObjectStyles);
},
// CSSTemplateLiteral and StyledTemplateLiteral
// const cssTemplateLiteral = css`color: red; margin: 12px`;
// const styledTemplateLiteral = styled.p`color: red; margin: 8px`;
'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"]': function TaggedTemplateExpressionTagNameCssTaggedTemplateExpressionTagObjectNameStyled(node) {
if (node.type !== 'TaggedTemplateExpression') {
return;
}
var combinedString = node.quasi.quasis.map(function (q) {
return q.value.raw;
}).join('');
/**
* Attempts to remove all non-essential words & characters from a style block.
* Including selectors and queries
* Adapted from ensure-design-token-usage
*/
var cssProperties = combinedString.split('\n').filter(function (line) {
return !line.trim().startsWith('@');
}).join('\n').replace(/\n/g, '').split(/;|(?<!\$){|(?<!\${.+?)}/) // don't split on template literal expressions i.e. `${...}`
.map(function (el) {
return el.trim() || '';
}).filter(Boolean);
cssProperties.forEach(function (style) {
var prop = style.split(':')[0];
if (prop.includes('margin')) {
context.report({
node: node,
messageId: 'noMargin'
});
}
});
}
};
}
});
export default rule;