react-native-ui-lib
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a
247 lines (226 loc) • 8.51 kB
JavaScript
const _ = require("lodash");
const {handleError} = require('../utils');
const RULE_ID = 'function-deprecation';
const MAP_SCHEMA = {
type: "object",
additionalProperties: true,
};
const FIX_TYPES = {
PROP_NAME: "propName",
FUNCTION_NAME: "functionName",
};
module.exports = {
meta: {
docs: {
description: "function or some of the props sent to it are deprecated",
category: "Best Practices",
recommended: true,
},
messages: {
uiLib: "This function is deprecated or contains deprecated props.",
},
fixable: "code",
schema: [MAP_SCHEMA],
},
create(context) {
function getSpecifierIndex(node, name) {
let matchIndex;
if (node && node.specifiers) {
_.forEach(node.specifiers, (s, index) => {
const x = _.get(s, 'imported.name');
if (x === name) {
matchIndex = index;
}
});
}
return matchIndex;
}
function reportDeprecatedFunction(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}' function is deprecated. ${options.message}${dueDateNotice}`
: `The '${options.name}' function'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];
let fixed;
// console.warn('fix');
switch (type) {
case FIX_TYPES.PROP_NAME:
// Fix for prop name change only (when prop's value and type does not change)
// console.warn('fix prop');
// console.warn('from', node.arguments[options.argumentIndex]);
const prop = _.find(node.arguments[options.argumentIndex].properties, prop => prop.key.name === options.prop);
const propIndex = node.arguments[options.argumentIndex].properties.indexOf(prop);
fixed = fixer.replaceText(node.arguments[options.argumentIndex].properties[propIndex], fix)
// console.warn('to', fixed);
return fixed;
case FIX_TYPES.FUNCTION_NAME:
if (node.type === "ImportDeclaration") {
// console.warn('fix function import');
const index = getSpecifierIndex(node, options.name);
// console.warn('from', node.specifiers[index]);
fixed = fixer.replaceText(node.specifiers[index], fix);
// console.warn('to', fixed);
return fixed;
}
// console.warn('fix function not import');
// console.warn('from', node.callee.name);
fixed = fixer.replaceText(node.callee, fix)
// console.warn('to', fixed);
return fixed;
default:
break;
}
}
},
});
} catch (err) {
handleError(RULE_ID, err, context.getFilename());
}
}
const { deprecations, source } = context.options[0];
const relevantDeprecationsData = [];
let everythingIsImported = false;
function getDeprecation(value) {
if (value && value.name) {
const name = value.name;
return _.find(
deprecations,
(deprecation) => deprecation.function === name
);
}
}
function searchForPossibleDeprecation(node) {
const importSource = node.source.value;
if (source === importSource) {
const specifiers = node.specifiers;
if (specifiers) {
_.map(specifiers, (specifier) => {
const deprecation = getDeprecation(specifier.imported);
if (deprecation) {
let type = FIX_TYPES.PROP_NAME;
if (!deprecation.arguments) {
type = FIX_TYPES.FUNCTION_NAME;
reportDeprecatedFunction(node, {
name: deprecation.function,
message: deprecation.message,
fix: deprecation.fix,
});
}
relevantDeprecationsData.push({
localFunctionName: specifier.local.name,
type,
deprecation,
});
}
});
}
if (relevantDeprecationsData.length === 0) { // someone is importing everything (*)
everythingIsImported = true;
_.map(deprecations, deprecation => {
relevantDeprecationsData.push({
localFunctionName: deprecation.function,
type: deprecation.arguments ? FIX_TYPES.PROP_NAME : FIX_TYPES.FUNCTION_NAME,
deprecation,
});
});
}
}
}
function findRelevantDeprecation(functionName) {
return _.find(
relevantDeprecationsData,
(relevantDeprecationData) =>
relevantDeprecationData.localFunctionName === functionName
);
}
function getArgumentsSent(node) {
const argumentsSent = [];
_.map(node.arguments, argument => {
const propsSentToArgument = [];
if (argument.properties) {
_.map(argument.properties, prop => {
if (prop.key && prop.key.name) {
propsSentToArgument.push(prop.key.name);
}
});
}
argumentsSent.push(propsSentToArgument);
});
return argumentsSent;
}
function getFunctionName(node) {
const propName = everythingIsImported ? 'callee.property.name' : 'callee.name';
return _.get(node, propName);
}
function testCallExpression(node) {
const functionName = getFunctionName(node);
if (functionName) {
const relevantDeprecation = findRelevantDeprecation(functionName);
if (relevantDeprecation) {
if (relevantDeprecation.type === FIX_TYPES.PROP_NAME) {
const argumentsSent = getArgumentsSent(node);
_.map(relevantDeprecation.deprecation.arguments, (argument, index) => {
if (argument.props && argument.props.length > 0 && argumentsSent.length >= index) {
const deprecationProps = argument.props;
const sentProps = argumentsSent[index];
_.map(sentProps, sentProp => {
const deprecationProp = _.find(deprecationProps, deprecationProp => deprecationProp.prop === sentProp);
if (deprecationProp) {
reportDeprecatedFunction(node, {
name: functionName,
message: deprecationProp.message,
argumentIndex: index,
prop: deprecationProp.prop,
fix: deprecationProp.fix,
});
}
});
}
});
} else {
reportDeprecatedFunction(node, {
name: relevantDeprecation.deprecation.function,
message: relevantDeprecation.deprecation.message,
fix: relevantDeprecation.deprecation.fix,
});
}
}
}
}
// Test for forbidden inherited functions (no source)
function testClassBody(node) {
if (node && node.body) {
_.forEach(node.body, item => {
const type = _.get(item, 'type');
if (type === 'ClassProperty' || type === 'MethodDefinition') {
const deprecation = _.find(deprecations,
(deprecation) => !deprecation.source && deprecation.function === _.get(item, 'key.name')
)
if (deprecation) {
reportDeprecatedFunction(node, {
name: deprecation.function,
message: deprecation.message
});
}
}
});
}
}
return {
ImportDeclaration: (node) => searchForPossibleDeprecation(node),
CallExpression: (node) => relevantDeprecationsData.length > 0 && testCallExpression(node),
ClassBody: (node) => testClassBody(node),
};
},
};