@atlaskit/eslint-plugin-design-system
Version:
The essential plugin for use with the Atlassian Design System.
127 lines (122 loc) • 4.82 kB
JavaScript
import { isNodeOfType } from 'eslint-codemod-utils';
import { getSourceCode } from '@atlaskit/eslint-utils/context-compat';
import { createLintRule } from '../utils/create-lint-rule';
import { getConfig } from '../utils/get-deprecated-config';
import { isDeprecatedJSXAttributeConfig } from '../utils/is-deprecated-jsx-attribute-config';
export var noDeprecatedJSXAttributeMessageId = 'noDeprecatedJSXAttributes';
var isImportDeclaration = function isImportDeclaration(programStatement) {
return (programStatement === null || programStatement === void 0 ? void 0 : programStatement.type) === 'ImportDeclaration';
};
var findJSXElementName = function findJSXElementName(jsxAttributeNode) {
if (!jsxAttributeNode.parent || !isNodeOfType(jsxAttributeNode === null || jsxAttributeNode === void 0 ? void 0 : jsxAttributeNode.parent, 'JSXOpeningElement')) {
return;
}
var openingElement = jsxAttributeNode.parent;
if (!isNodeOfType(openingElement.name, 'JSXIdentifier')) {
return;
}
return openingElement.name.name;
};
export var name = 'no-deprecated-apis';
var rule = createLintRule({
meta: {
name: name,
type: 'suggestion',
docs: {
description: 'Disallow using deprecated APIs.',
recommended: true,
severity: 'error'
},
messages: {
noDeprecatedJSXAttributes: 'The JSX attribute {{propName}} has been deprecated.'
},
schema: [{
type: 'object',
properties: {
deprecatedConfig: {
type: 'object',
properties: {
'.+': {
type: 'array',
items: {
type: 'object',
properties: {
moduleSpecifier: {
type: 'string'
},
namedSpecifiers: {
type: 'array',
items: {
type: 'string'
}
},
actionableVersion: {
type: 'string'
}
},
required: ['moduleSpecifier'],
additionalProperties: false
}
}
}
}
}
}]
},
create: function create(context) {
var _context$options$;
// Get the rule configuration specified otherwise use default config.
// A bit confusing as it seems that the default options have precedence over the user specified options.
var deprecatedConfig =
// TODO: JFP-2823 - this type cast was added due to Jira's ESLint v9 migration
((_context$options$ = context.options[0]) === null || _context$options$ === void 0 ? void 0 : _context$options$.deprecatedConfig) || getConfig('jsxAttributes');
return {
// find JSX attribute - find name of attribute - get source and find relevant identifiers.
JSXAttribute: function JSXAttribute(node) {
if (!isNodeOfType(node, 'JSXAttribute') || !isNodeOfType(node.name, 'JSXIdentifier')) {
return;
}
var jsxAttributeName = node.name.name;
if (!isDeprecatedJSXAttributeConfig(deprecatedConfig) || !deprecatedConfig[jsxAttributeName]) {
return;
}
var jsxElementName = findJSXElementName(node);
if (!jsxElementName) {
return;
}
var source = getSourceCode(context);
// find an import for the path of the banned api
deprecatedConfig[jsxAttributeName].forEach(function (importItem) {
var _importItem$namedSpec;
var importNode = source.ast.body.filter(isImportDeclaration).find(function (node) {
return node && node.source.value && typeof node.source.value === 'string' && node.source.value.includes(importItem.moduleSpecifier);
});
if (!importNode) {
return;
}
// find an import that matches our JSX element
var targetNode = importNode.specifiers.find(function (node) {
return node.local.name === jsxElementName;
});
// check if the import exists
if (!targetNode) {
return;
}
// if the import has named specifiers, check if the JSX element is one of them
if (importItem !== null && importItem !== void 0 && (_importItem$namedSpec = importItem.namedSpecifiers) !== null && _importItem$namedSpec !== void 0 && _importItem$namedSpec.length && !importItem.namedSpecifiers.includes(targetNode.local.name)) {
return;
}
// if we're here, there is a valid lint error.
context.report({
node: node,
messageId: 'noDeprecatedJSXAttributes',
data: {
propName: jsxAttributeName
}
});
});
}
};
}
});
export default rule;