UNPKG

@atlaskit/eslint-plugin-design-system

Version:

The essential plugin for use with the Atlassian Design System.

123 lines (118 loc) 4.64 kB
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 const noDeprecatedJSXAttributeMessageId = 'noDeprecatedJSXAttributes'; const isImportDeclaration = programStatement => { return (programStatement === null || programStatement === void 0 ? void 0 : programStatement.type) === 'ImportDeclaration'; }; const findJSXElementName = jsxAttributeNode => { if (!jsxAttributeNode.parent || !isNodeOfType(jsxAttributeNode === null || jsxAttributeNode === void 0 ? void 0 : jsxAttributeNode.parent, 'JSXOpeningElement')) { return; } const openingElement = jsxAttributeNode.parent; if (!isNodeOfType(openingElement.name, 'JSXIdentifier')) { return; } return openingElement.name.name; }; export const name = 'no-deprecated-apis'; const rule = createLintRule({ meta: { 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(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. const 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(node) { if (!isNodeOfType(node, 'JSXAttribute') || !isNodeOfType(node.name, 'JSXIdentifier')) { return; } const jsxAttributeName = node.name.name; if (!isDeprecatedJSXAttributeConfig(deprecatedConfig) || !deprecatedConfig[jsxAttributeName]) { return; } const jsxElementName = findJSXElementName(node); if (!jsxElementName) { return; } const source = getSourceCode(context); // find an import for the path of the banned api deprecatedConfig[jsxAttributeName].forEach(importItem => { var _importItem$namedSpec; const importNode = source.ast.body.filter(isImportDeclaration).find(node => 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 const targetNode = importNode.specifiers.find(node => 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, messageId: 'noDeprecatedJSXAttributes', data: { propName: jsxAttributeName } }); }); } }; } }); export default rule;