@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
142 lines (139 loc) • 6.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _eslintCodemodUtils = require("eslint-codemod-utils");
var _jsxElementHelper = require("../../ast-nodes/jsx-element-helper");
var _createLintRule = require("../utils/create-lint-rule");
var _getAffectedPackageConfig = require("../utils/get-affected-package-config");
var _affectedAtlaskitPackages = require("./affected-atlaskit-packages");
var _affectedHtmlElements = require("./affected-html-elements");
var _unwantedAtlaskitAttributes = require("./unwanted-atlaskit-attributes");
var _unwantedHtmlAttributes = require("./unwanted-html-attributes");
var isUnwantedHTMLAtrribute = function isUnwantedHTMLAtrribute(s) {
var attrs = _unwantedHtmlAttributes.UNWANTED_HTML_ATTRIBUTES;
return attrs.includes(s);
};
var isUnwantedAtlaskitAtrribute = function isUnwantedAtlaskitAtrribute(s) {
var attrs = _unwantedAtlaskitAttributes.UNWANTED_ATLASKIT_ATTRIBUTES;
return attrs.includes(s);
};
var isUnwantedAttribute = function isUnwantedAttribute(s) {
return isUnwantedHTMLAtrribute(s) || isUnwantedAtlaskitAtrribute(s);
};
var hasUnwantedAttributes = function hasUnwantedAttributes(node, type) {
var attrNames = (0, _toConsumableArray2.default)(type === 'html' ? _unwantedHtmlAttributes.UNWANTED_HTML_ATTRIBUTES : _unwantedAtlaskitAttributes.UNWANTED_ATLASKIT_ATTRIBUTES);
var unwantedAttrs = node.openingElement.attributes.filter(function (attr) {
return (0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute');
}).map(function (attr) {
return String(attr.name.name);
}).filter(isUnwantedAttribute).filter(function (unwantedAttribute) {
return attrNames.includes(unwantedAttribute);
});
return unwantedAttrs;
};
var rule = (0, _createLintRule.createLintRule)({
meta: {
name: 'no-readonly-or-disabled-inputs',
type: 'problem',
docs: {
description: 'Inputs should almost always be interactive. Disabled and read-only inputs can usually be replaced by a more user-friendly design pattern.',
recommended: true,
severity: 'warn'
},
messages: {
noDisabled: 'Inputs should almost always be interactive. Instead of disabling an input, consider removing it altogether, as it cannot be used anyway. Disabled inputs are much less accessible than a well labeled and described input with clear error, valid, and/or helper messages.',
noReadOnly: 'Inputs should almost always be interactive. Instead of making an input read-only, consider making it normal text. Read-only inputs do the same thing as normal text but appear as interactive elements and add themselves to the tab-order, which can be confusing for users.'
}
},
create: function create(context) {
var localComponentNames = [];
return {
ImportDeclaration: function ImportDeclaration(node) {
var source = node.source.value;
var affectedPackage = (0, _getAffectedPackageConfig.getAffectedPackageConfig)(source, _affectedAtlaskitPackages.AFFECTED_ATLASKIT_PACKAGES);
// Ignore non-atlaskit input packages
if (!affectedPackage) {
return;
}
if (!node.specifiers.length) {
return;
}
var defaultImport = node.specifiers.filter(function (spec) {
return spec.type === 'ImportDefaultSpecifier';
});
var namedImport = node.specifiers.filter(function (spec) {
return spec.type === 'ImportSpecifier';
});
var importNames = affectedPackage.importNames;
var usesDefaultImport = importNames.includes('default');
var possibleNamedImports = importNames.filter(function (importName) {
return importName !== 'default';
});
if (usesDefaultImport && defaultImport.length && defaultImport[0].local) {
localComponentNames.push(defaultImport[0].local.name);
} else if (possibleNamedImports.length >= 1 && namedImport.length) {
namedImport.forEach(function (imp) {
if (imp.type === 'ImportSpecifier' && 'name' in imp.imported && possibleNamedImports.includes(imp.imported.name)) {
localComponentNames.push(imp.local.name);
}
});
}
},
JSXElement: function JSXElement(node) {
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'JSXElement')) {
return false;
}
var elName = _jsxElementHelper.JSXElementHelper.getName(node);
if (!elName) {
return false;
}
var fixes = [];
// If it is one of the affected native HTML elements
if (_affectedHtmlElements.AFFECTED_HTML_ELEMENTS.includes(elName)) {
var unwantedAttributes = hasUnwantedAttributes(node, 'html');
if (unwantedAttributes.includes('disabled')) {
fixes.push(context.report({
node: node.openingElement,
messageId: 'noDisabled'
}));
}
if (unwantedAttributes.includes('readonly')) {
fixes.push(context.report({
node: node.openingElement,
messageId: 'noReadOnly'
}));
}
// Else, it is a React component
} else {
// if none of the affected packages is imported, return
if (localComponentNames.length === 0) {
return;
}
// if component name is not in the list, exit
if (!(0, _eslintCodemodUtils.isNodeOfType)(node.openingElement.name, 'JSXIdentifier') || !localComponentNames.includes(node.openingElement.name.name)) {
return;
}
var _unwantedAttributes = hasUnwantedAttributes(node, 'atlaskit');
if (_unwantedAttributes.includes('isDisabled')) {
fixes.push(context.report({
node: node.openingElement,
messageId: 'noDisabled'
}));
}
if (_unwantedAttributes.includes('isReadOnly')) {
fixes.push(context.report({
node: node.openingElement,
messageId: 'noReadOnly'
}));
}
}
return fixes;
}
};
}
});
var _default = exports.default = rule;