@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
101 lines (96 loc) • 4.35 kB
JavaScript
import { isNodeOfType } from 'eslint-codemod-utils';
import { createLintRule } from '../utils/create-lint-rule';
import { getFormImportLocalNames } from '../utils/get-form-import-local-names';
export const convertField = 'Convert field to simple field';
const rule = createLintRule({
meta: {
name: 'use-simple-field',
type: 'suggestion',
hasSuggestions: true,
docs: {
description: 'Encourage use of simple field for better developer experience and accessibility.',
recommended: true,
severity: 'warn'
},
messages: {
useSimpleField: 'The simplified field implementation can be used here.'
}
},
create(context) {
let fieldImport;
let messageImports = [];
return {
ImportDeclaration(node) {
var _formImports$Field$, _formImports$Field, _formImports$ErrorMes, _formImports$HelperMe, _formImports$ValidMes;
const formImports = getFormImportLocalNames(node);
fieldImport = (_formImports$Field$ = (_formImports$Field = formImports.Field) === null || _formImports$Field === void 0 ? void 0 : _formImports$Field[0]) !== null && _formImports$Field$ !== void 0 ? _formImports$Field$ : fieldImport;
messageImports.push(...((_formImports$ErrorMes = formImports.ErrorMessage) !== null && _formImports$ErrorMes !== void 0 ? _formImports$ErrorMes : []), ...((_formImports$HelperMe = formImports.HelperMessage) !== null && _formImports$HelperMe !== void 0 ? _formImports$HelperMe : []), ...((_formImports$ValidMes = formImports.ValidMessage) !== null && _formImports$ValidMes !== void 0 ? _formImports$ValidMes : []));
},
JSXElement(node) {
if (!isNodeOfType(node, 'JSXElement')) {
return;
}
if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
return;
}
// if no field import exists, skip
if (!fieldImport) {
return;
}
// if component is not field, skip
if (node.openingElement.name.name !== fieldImport) {
return;
}
// if message imports exist, skip because we can't really dig around
// inside the field to see if they exist because of memory constraints
if (messageImports.length > 0) {
return;
}
// if component exists as a prop, skip because it's already simple
const attributes = node.openingElement.attributes;
const componentAttr = attributes.find(attr => isNodeOfType(attr, 'JSXAttribute') && isNodeOfType(attr.name, 'JSXIdentifier') && attr.name.name === 'component');
if (componentAttr) {
return;
}
// if children is not a render prop, skip
const renderProps = node.children.find(child => isNodeOfType(child, 'JSXExpressionContainer'));
if (!renderProps) {
return;
}
const renderPropExpression = renderProps.expression;
// If not an arrow func, ignore
if (!isNodeOfType(renderPropExpression, 'ArrowFunctionExpression')) {
return;
}
const renderPropParams = renderPropExpression.params;
// if it is not an object pattern, skip
if (!isNodeOfType(renderPropParams[0], 'ObjectPattern')) {
return;
}
// if component uses more than just fieldProps in render props, skip
const renderPropArgProperties = renderPropParams[0].properties;
const fieldPropsProp = renderPropArgProperties.find(property => isNodeOfType(property, 'Property') && isNodeOfType(property.key, 'Identifier') && property.key.name === 'fieldProps');
if (renderPropArgProperties.length > 1 || !fieldPropsProp) {
return;
}
const lastProp = attributes.slice(-1)[0] || node.openingElement.name;
const sourceCode = context.sourceCode;
const renderPropsText = sourceCode.getText(renderProps);
context.report({
node: node,
messageId: 'useSimpleField',
suggest: [{
desc: convertField,
fix: fixer => {
const fixes = [];
fixes.push(fixer.insertTextAfter(lastProp, ` component=${renderPropsText} `));
fixes.push(fixer.remove(renderProps));
return fixes;
}
}]
});
}
};
}
});
export default rule;