UNPKG

react-native-ui-lib

Version:

[![Build Status](https://travis-ci.org/wix/react-native-ui-lib.svg?branch=master)](https://travis-ci.org/wix/react-native-ui-lib) [![npm](https://img.shields.io/npm/v/react-native-ui-lib.svg)](https://www.npmjs.com/package/react-native-ui-lib) [![NPM Down

183 lines (165 loc) • 5.81 kB
const _ = require('lodash'); const utils = require('../utils'); const MAP_SCHEMA = { type: 'object', additionalProperties: true, }; const FIX_TYPES = { PROP_NAME: 'propName', }; module.exports = { meta: { docs: { description: "component or some of the component's props are deprecated", category: 'Best Practices', recommended: true, }, messages: { uiLib: 'This component is deprecated or containes deprecated props.', }, fixable: 'code', schema: [MAP_SCHEMA], }, create(context) { function reportDeprecatedComponentOrProps(node, options) { try { const {dueDate} = context.options[0]; const dueDateNotice = dueDate ? ` Please fix this issue by ${dueDate}!` : ''; const msg = options.prop === undefined ? `The '${options.name}' component is deprecated. ${options.message}${dueDateNotice}` : `The '${options.name}' component's prop '${options.prop}' is deprecated. ${options.message}${dueDateNotice}`; context.report({ node, message: `${msg}`, fix(fixer) { if (options.fix) { const type = Object.keys(options.fix)[0]; const fix = Object.values(options.fix)[0]; switch (type) { case FIX_TYPES.PROP_NAME: // Fix for prop name change only (when prop's value and type does not change) return fixer.replaceText(node.name, fix); default: break; } } }, }); } catch (err) { console.log('Found error in: ', context.getFilename()); } } function checkPropDeprecation(node, propName, deprecatedPropList, componentName) { const deprecatedProp = _.find(deprecatedPropList, {prop: propName}); if (deprecatedProp) { const {prop, message, fix} = deprecatedProp; reportDeprecatedComponentOrProps(node, {name: componentName, prop, message, fix}); } } function deprecationCheck(node, componentName) { let component = componentName; if (!componentName && node.name) { if (node.name.object) { component = `${node.name.object.name}.${node.name.property.name}`; } else { component = node.name.name; } } if (component) { if (isComponentDeprecated(component)) { const deprecatedComponent = getDeprecatedObject(component); if (isComponentImportMatch(deprecatedComponent)) { const name = deprecatedComponent.component; const message = deprecatedComponent.message; const fix = deprecatedComponent.fix; const props = deprecatedComponent.props; if (!props) { reportDeprecatedComponentOrProps(node, {name, message, fix}); } else { const nodeAttributes = node.attributes; nodeAttributes.forEach((att) => { if (att.type === 'JSXAttribute') { checkPropDeprecation(att, att.name.name, props, name); } else if (att.type === 'JSXSpreadAttribute') { const spreadSource = utils.findValueNodeOfIdentifier(att.argument.name, context.getScope()); if (spreadSource) { _.forEach(spreadSource.properties, (property) => { checkPropDeprecation(property.key, property.key.name, props, name); }); } } }); } } } } } const importSpecifiers = {}; function createImportsObject(node) { const source = node.source.value; if (Object.keys(deprecationSources).indexOf(source) !== -1) { if (!(source in importSpecifiers)) { importSpecifiers[source] = []; } const specifiers = node.specifiers; if (specifiers) { specifiers.forEach((s) => { importSpecifiers[source].push(s.local.name); checkSpecifier(s.local.name, node); }); } } } function checkSpecifier(name, node) { const deprecatedComponent = getDeprecatedObject(name); if (deprecatedComponent && !deprecatedComponent.props) { deprecationCheck(node, name); } } const {deprecations} = context.options[0]; const deprecationSources = createDeprecationSourcesObject(); function createDeprecationSourcesObject() { const obj = {}; if (!deprecations) { return obj; } deprecations.forEach((element) => { if (!(element.source in obj)) { obj[element.source] = [element.component]; } else { obj[element.source].push(element.component); } }); return obj; } function isComponentDeprecated(component) { const values = _.chain(deprecationSources) .values() .flatten() .value(); return _.includes(values, component); } function isComponentImportMatch(component) { // in case it's a sub component like List.Item const componentName = _.split(component.component, '.')[0]; if (component.source in importSpecifiers) { return _.includes(importSpecifiers[component.source], componentName); } return false; } function getDeprecatedObject(component) { let jsonElement; deprecations.forEach((element) => { if (element.component === component) { jsonElement = element; } }); return jsonElement; } return { ImportDeclaration: node => createImportsObject(node), JSXOpeningElement: node => deprecationCheck(node), }; }, };