@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
150 lines (140 loc) • 6.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.convertForm = void 0;
Object.defineProperty(exports, "topLevelAttributeNames", {
enumerable: true,
get: function get() {
return _topLevelAttributeNames.topLevelAttributeNames;
}
});
var _eslintCodemodUtils = require("eslint-codemod-utils");
var _createLintRule = require("../utils/create-lint-rule");
var _getFormImportLocalNames = require("../utils/get-form-import-local-names");
var _topLevelAttributeNames = require("./top-level-attribute-names");
var convertForm = exports.convertForm = 'Convert form to simple form';
var rule = (0, _createLintRule.createLintRule)({
meta: {
name: 'use-simple-form',
type: 'suggestion',
hasSuggestions: true,
docs: {
description: 'Encourage use of simple form for better developer experience and accessibility.',
recommended: true,
severity: 'warn'
},
messages: {
useSimpleForm: 'The simplified form implementation can be used here.'
}
},
create: function create(context) {
var formImport;
return {
ImportDeclaration: function ImportDeclaration(node) {
var _getFormImportLocalNa, _getFormImportLocalNa2;
formImport = (_getFormImportLocalNa = (_getFormImportLocalNa2 = (0, _getFormImportLocalNames.getFormImportLocalNames)(node).Form) === null || _getFormImportLocalNa2 === void 0 ? void 0 : _getFormImportLocalNa2[0]) !== null && _getFormImportLocalNa !== void 0 ? _getFormImportLocalNa : formImport;
},
JSXElement: function JSXElement(node) {
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'JSXElement')) {
return;
}
if (!(0, _eslintCodemodUtils.isNodeOfType)(node.openingElement.name, 'JSXIdentifier')) {
return;
}
// if no form import exists, skip
if (!formImport) {
return;
}
// if component is not field, skip
if (node.openingElement.name.name !== formImport) {
return;
}
// if children is not a render prop, skip
var renderProps = node.children.find(function (child) {
return (0, _eslintCodemodUtils.isNodeOfType)(child, 'JSXExpressionContainer');
});
if (!renderProps) {
return;
}
var renderPropExpression = renderProps.expression;
// If not an arrow func, ignore
if (!(0, _eslintCodemodUtils.isNodeOfType)(renderPropExpression, 'ArrowFunctionExpression')) {
return;
}
var renderPropParams = renderPropExpression.params;
// if it is not an object pattern, skip
if (!(0, _eslintCodemodUtils.isNodeOfType)(renderPropParams[0], 'ObjectPattern')) {
return;
}
// if component uses more than just formProps in render props, skip
var renderPropArgProperties = renderPropParams[0].properties;
var formPropsProp = renderPropArgProperties.find(function (property) {
return (0, _eslintCodemodUtils.isNodeOfType)(property, 'Property') && (0, _eslintCodemodUtils.isNodeOfType)(property.key, 'Identifier') && property.key.name === 'formProps';
});
if (renderPropArgProperties.length > 1 || !formPropsProp) {
return;
}
var attributes = node.openingElement.attributes;
var lastProp = attributes.slice(-1)[0] || node.openingElement.name;
var sourceCode = context.sourceCode;
// if html form is not first child, don't give a fix
var renderPropBody = renderPropExpression.body;
var firstChildIsHTMLForm = (0, _eslintCodemodUtils.isNodeOfType)(renderPropBody, 'JSXElement') && (0, _eslintCodemodUtils.isNodeOfType)(renderPropBody.openingElement.name, 'JSXIdentifier') && renderPropBody.openingElement.name.name === 'form';
// If this is not an HTML form. skip because we can't convert
if (!firstChildIsHTMLForm) {
return;
}
context.report({
node: node,
messageId: 'useSimpleForm',
suggest: [{
desc: convertForm,
fix: function fix(fixer) {
var fixes = [];
// add each attribute in the HTML form inside to the AK form
var attrs = {
topLevel: [],
formProps: []
};
var htmlFormAttributes = renderPropBody.openingElement.attributes;
htmlFormAttributes.forEach(function (attr) {
if ((0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute') && (0, _eslintCodemodUtils.isNodeOfType)(attr.name, 'JSXIdentifier')) {
if (_topLevelAttributeNames.topLevelAttributeNames.includes(attr.name.name)) {
attrs.topLevel.push(attr);
} else {
attrs.formProps.push(attr);
}
}
});
attrs.topLevel.forEach(function (attr) {
fixes.push(fixer.insertTextAfter(lastProp, " ".concat(sourceCode.getText(attr))));
});
if (attrs.formProps.length > 0) {
var formPropsText = attrs.formProps.map(function (attr) {
return sourceCode.getText(attr).replace(/^([^=]*)/, "'$1'").replace('=', ': ');
}).join(',\n');
fixes.push(fixer.insertTextAfter(lastProp, " formProps={{\n".concat(formPropsText, "\n}} ")));
}
// remove the body of the AK form
fixes.push(fixer.remove(renderProps));
// Get all children text of HTML form to be added to AK form
var childrenText = '<>';
renderPropBody.children.forEach(function (child) {
// Doing `as any` because it doesn't like spread props. I
// added a test that verifies that this does indeed work,
// though, so it's fine.
childrenText += sourceCode.getText(child);
});
childrenText += '</>';
// Add the children of the HTML form to the children of the AK form
node.closingElement && fixes.push(fixer.insertTextBefore(node.closingElement, childrenText));
return fixes;
}
}]
});
}
};
}
});
var _default = exports.default = rule;