@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
136 lines (135 loc) • 4.85 kB
JavaScript
import { isNodeOfType } from 'eslint-codemod-utils';
import { getScope } from '@atlaskit/eslint-utils/context-compat';
import { findIdentifierInParentScope } from '../utils/find-in-parent';
import { getValueFromShorthand } from './get-value-from-shorthand';
import { getValueFromTemplateLiteralRaw } from './get-value-from-template-literal-raw';
import { isBorderRadius } from './is-border-radius';
import { removePixelSuffix } from './remove-pixel-suffix';
const isGridSize = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'gridSize' || node.callee.name === 'getGridSize') &&
// If there are arguments we know it's a custom gridSize function and cannot be certain what it returns
node.arguments.length === 0;
const isToken = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'token';
const getRawExpressionForToken = (node, context) => {
const args = node.arguments;
const call = `\${token(${args.map(argNode => {
if (isNodeOfType(argNode, 'Literal')) {
return argNode.raw;
}
if (isNodeOfType(argNode, 'Identifier')) {
return argNode.name;
}
if (isNodeOfType(argNode, 'MemberExpression')) {
return getValue(argNode, context);
}
}).join(', ')})}`;
return call;
};
const isFontSize = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && (node.callee.name === 'fontSize' || node.callee.name === 'getFontSize');
const isFontSizeSmall = node => isNodeOfType(node, 'CallExpression') && isNodeOfType(node.callee, 'Identifier') && node.callee.name === 'fontSizeSmall';
const getValueFromCallExpression = (node, context) => {
if (!isNodeOfType(node, 'CallExpression')) {
return null;
}
if (isGridSize(node)) {
return 8;
}
if (isBorderRadius(node)) {
return 3;
}
if (isFontSize(node)) {
return 14;
}
if (isFontSizeSmall(node)) {
return 11;
}
if (isToken(node)) {
return getRawExpressionForToken(node, context);
}
return null;
};
const getValueFromUnaryExpression = (node, context) => {
if (!isNodeOfType(node, 'UnaryExpression')) {
return null;
}
const value = getValue(node.argument, context);
if (!value) {
return null;
}
// eslint-disable-next-line no-eval
return eval(`${node.operator}(${value})`);
};
const getValueFromBinaryExpression = (node, context) => {
if (!isNodeOfType(node, 'BinaryExpression')) {
return null;
}
const {
left,
right,
operator
} = node;
const leftValue = getValue(left, context);
const rightValue = getValue(right, context);
if (rightValue === null || rightValue === undefined || leftValue === null || leftValue === undefined) {
return null;
}
try {
// Token calls are represented as template fragments, which cannot always be
// evaluated as JavaScript when composed into a binary expression.
// eslint-disable-next-line no-eval
return eval(`${leftValue}${operator}${rightValue}`);
} catch {
return null;
}
};
const getValueFromIdentifier = (node, context) => {
if (!isNodeOfType(node, 'Identifier')) {
return null;
}
if (node.name === 'gridSize') {
return 8;
}
const scope = getScope(context, node);
const variable = findIdentifierInParentScope({
scope,
identifierName: node.name
});
if (!variable) {
return null;
}
const definition = variable.defs[0];
if (isNodeOfType(definition.node, 'ImportSpecifier') && isNodeOfType(definition.node.parent, 'ImportDeclaration') && definition.node.parent.source.value === '@atlassian/jira-common-styles/src/main.tsx') {
return definition.node.imported.type === 'Identifier' && definition.node.imported.name === 'gridSize' ? 8 : null;
}
if (!isNodeOfType(definition.node, 'VariableDeclarator')) {
return null;
}
if (!definition.node.init) {
return null;
}
return getValue(definition.node.init, context);
};
const getValueFromTemplateLiteral = (node, context) => {
const value = getValueFromTemplateLiteralRaw(node, context);
return Array.isArray(value) ? value.map(removePixelSuffix) : value;
};
export const getValue = (node, context) => {
if (isNodeOfType(node, 'Literal')) {
return getValueFromShorthand(node.value);
}
if (isNodeOfType(node, 'BinaryExpression')) {
return getValueFromBinaryExpression(node, context);
}
if (isNodeOfType(node, 'UnaryExpression')) {
return getValueFromUnaryExpression(node, context);
}
if (isNodeOfType(node, 'CallExpression')) {
return getValueFromCallExpression(node, context);
}
if (isNodeOfType(node, 'Identifier')) {
return getValueFromIdentifier(node, context);
}
if (isNodeOfType(node, 'TemplateLiteral')) {
return getValueFromTemplateLiteral(node, context);
}
return null;
};