Skip to content

Eslint/version 2 fixes #1261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions eslint-rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ module.exports = {
'no-hard-coded-color': require('./lib/rules/no-hard-coded-color'),
'no-direct-import': require('./lib/rules/no-direct-import'),
'component-deprecation': require('./lib/rules/component-deprecation'),
'component-prop-deprecation': require('./lib/rules/component-prop-deprecation'),
'assets-deprecation': require('./lib/rules/assets-deprecation'),
'typography-deprecation': require('./lib/rules/typography-deprecation'),
'function-deprecation': require('./lib/rules/function-deprecation'),
'prop-value-shape-deprecation': require('./lib/rules/prop-value-shape-deprecation'),
// for duplicate rules usage
'component-deprecation_warn': require('./lib/rules/component-deprecation'),
'component-prop-deprecation_warn': require('./lib/rules/component-prop-deprecation'),
'assets-deprecation_warn': require('./lib/rules/assets-deprecation'),
'typography-deprecation_warn': require('./lib/rules/typography-deprecation'),
'function-deprecation_warn': require('./lib/rules/function-deprecation'),
'prop-value-shape-deprecation_warn': require('./lib/rules/prop-value-shape-deprecation'),
'component-deprecation_error': require('./lib/rules/component-deprecation'),
'component-prop-deprecation_error': require('./lib/rules/component-prop-deprecation'),
'assets-deprecation_error': require('./lib/rules/assets-deprecation'),
'typography-deprecation_error': require('./lib/rules/typography-deprecation'),
'function-deprecation_error': require('./lib/rules/function-deprecation'),
Expand Down
45 changes: 38 additions & 7 deletions eslint-rules/lib/rules/component-deprecation.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const _ = require('lodash');
const {addToImports, organizeDeprecations, getComponentLocalName, getComponentName} = require('../utils');
const {addToImports, organizeDeprecations, getComponentLocalName, getPossibleDeprecations} = require('../utils');

const MAP_SCHEMA = {
type: 'object',
Expand Down Expand Up @@ -43,10 +43,27 @@ module.exports = {
const organizedDeprecations = organizeDeprecations(deprecations);

const imports = [];
const parents = [];

function getParent(localName) {
const foundParents = parents.filter(parent => Object.keys(parent)[0] === localName);
return !_.isEmpty(foundParents) ? foundParents[0][localName] : undefined;
}

function isParent(foundDeprecation, localName) {
if (foundDeprecation.parent) {
const parent = getParent(localName);
if (foundDeprecation.parent === parent) {
return true;
}
}

return false;
}

function importDeprecationCheck(node) {
const previousImports = _.cloneDeep(imports);
addToImports(node, imports);
addToImports(node, imports, parents);
const addedImports = _.differenceWith(imports, previousImports, _.isEqual);
addedImports.forEach(currentImport => {
const source = Object.keys(currentImport)[0];
Expand All @@ -60,11 +77,20 @@ module.exports = {

if (foundDeprecations.length > 0) {
foundDeprecations.forEach(foundDeprecation => {
const localName = Object.keys(components).find(key => components[key] === foundDeprecation.component);
if (isParent(foundDeprecation, localName)) {
return;
}

let fixNode;
if (node.type === 'ImportDeclaration') {
fixNode = node.specifiers.filter(
const foundSpecifiers = node.specifiers.filter(
specifier => _.get(specifier, 'imported.name') === foundDeprecation.component
)[0].imported;
);

if (foundSpecifiers.length > 0) {
fixNode = foundSpecifiers[0].imported;
}
} else if (node.type === 'VariableDeclarator') {
const properties = _.get(node, 'id.properties');
if (properties) {
Expand All @@ -88,13 +114,18 @@ module.exports = {
const deprecationSource = organizedDeprecations[source];
if (deprecationSource) {
// There are deprecations from this source
const componentName = getComponentName(componentLocalName, imports);
const foundDeprecations = deprecationSource.filter(
currentDeprecationSource => currentDeprecationSource.component === componentName
const foundDeprecations = getPossibleDeprecations(
componentLocalName,
imports,
currentImport,
deprecationSource
);

if (foundDeprecations.length > 0) {
const foundDeprecation = foundDeprecations[0];
if (isParent(foundDeprecation, componentLocalName)) {
return;
}

// This is a little hacky, is there a better way?
if (componentLocalName.includes(foundDeprecation.component)) {
Expand Down
9 changes: 7 additions & 2 deletions eslint-rules/lib/rules/component-prop-deprecation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
addToImports,
getComponentLocalName,
getComponentName,
getPossibleDeprecations,
findValueNodeOfIdentifier
} = require('../utils');

Expand Down Expand Up @@ -116,9 +117,13 @@ module.exports = {
if (deprecationSource) {
// There are deprecations from this source
const componentName = getComponentName(componentLocalName, imports);
const foundPossibleDeprecations = deprecationSource.filter(
currentDeprecationSource => currentDeprecationSource.component === componentName
const foundPossibleDeprecations = getPossibleDeprecations(
componentLocalName,
imports,
currentImport,
deprecationSource
);

foundPossibleDeprecations.forEach(foundPossibleDeprecation => {
const deprecatedPropList = foundPossibleDeprecation.props;
const attributes = node.attributes;
Expand Down
25 changes: 22 additions & 3 deletions eslint-rules/lib/utils/componentUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,32 @@ function getComponentLocalName(node) {
return `${start}.${end}`; // <List.Part/> OR <module.List.Part/> etc.
}

function getPrefix(componentLocalName) {
const indexOfDot = componentLocalName.indexOf('.');
return componentLocalName.slice(0, indexOfDot);
}

function isNamespace(currentImport, componentLocalName) {
const components = Object.values(currentImport)[0];
const prefix = getPrefix(componentLocalName);
if (prefix && components[prefix]) {
return components[prefix].isNamespace;
}

return false;
}

function getComponentName(componentLocalName, imports) {
for (let index = 0; index < imports.length; ++index) {
const currentImport = imports[index];
const components = Object.values(currentImport)[0];
if (components[componentLocalName]) {
return components[componentLocalName];
} else if (componentLocalName.indexOf('.') > 0) {
const indexOfDot = componentLocalName.indexOf('.');
const prefix = componentLocalName.slice(0, indexOfDot);
const prefix = getPrefix(componentLocalName);
if (components[prefix]) {
if (components[prefix].isNamespace) {
const indexOfDot = componentLocalName.indexOf('.');
return componentLocalName.slice(indexOfDot + 1);
} else {
return componentLocalName.replace(prefix, components[prefix]);
Expand All @@ -34,5 +49,9 @@ module.exports = {
// The local name of the component (List as L --> L)
getComponentLocalName,
// Get the real name of the component
getComponentName
getComponentName,
// Get the prefix of the component name (List for List.Part for example)
getPrefix,
// Is the localName comes from a namespace (module.Component)
isNamespace
};
24 changes: 23 additions & 1 deletion eslint-rules/lib/utils/deprecationsUtils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const {getComponentName, getPrefix, isNamespace} = require('./componentUtils');

function _organizeDeprecationsBySource(deprecations, defaultSource) {
const obj = {};
deprecations.forEach(deprecation => {
Expand All @@ -21,6 +23,10 @@ function organizeDeprecations(deprecations, defaultSource) {
}

function getLocalizedFix(fix, currentImport) {
if (!fix) {
return;
}

let localizedFix = fix;
const indexOfDot = fix.indexOf('.');
if (indexOfDot > 0) {
Expand All @@ -38,7 +44,23 @@ function getLocalizedFix(fix, currentImport) {
return localizedFix;
}

function getPossibleDeprecations(componentLocalName, imports, currentImport, deprecationSource) {
const source = Object.keys(currentImport)[0];
const components = currentImport[source];
const componentName = getComponentName(componentLocalName, imports);
const prefix = getPrefix(componentLocalName);
return deprecationSource.filter(currentDeprecationSource => {
return (
(isNamespace(currentImport, componentLocalName) ||
components[componentLocalName] ||
(prefix && components[prefix])) &&
currentDeprecationSource.component === componentName
);
});
}

module.exports = {
organizeDeprecations,
getLocalizedFix
getLocalizedFix,
getPossibleDeprecations
};
21 changes: 15 additions & 6 deletions eslint-rules/lib/utils/importUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,34 @@ function _getSourceForComponent(component, imports) {
}
}

function _addToImports_fromSpreading(midSource, newImports, imports) {
function _addToImports_fromSpreading(midSource, newImports, imports, parents) {
if (midSource) {
const source = _getSourceForComponent(midSource, imports);
if (source) {
_addToImports_aggregate(imports, source, newImports);
if (parents) {
_.forEach(Object.keys(newImports), currentImport => {
if (!parents.includes(currentImport)) {
parents.push({[currentImport]: midSource});
}
});
}
}
}
}

function _getImportsFromProperties(node) {
const newImports = {};
_.map(node.id.properties, property => {
newImports[property.value.name] = property.key.name;
if (property.type === 'Property') {
newImports[property.value.name] = property.key.name;
}
});

return newImports;
}

function _addToImports_fromDeclaration(node, imports) {
function _addToImports_fromDeclaration(node, imports, parents) {
let newImports, source, midSource;
if (_.get(node, 'init.type') === 'CallExpression' && _.get(node, 'init.callee.name') === 'require') {
source = node.init.arguments[0].value;
Expand All @@ -81,19 +90,19 @@ function _addToImports_fromDeclaration(node, imports) {
}

_addToImports_aggregate(imports, source, newImports);
_addToImports_fromSpreading(midSource, newImports, imports);
_addToImports_fromSpreading(midSource, newImports, imports, parents);
}

/**
* Aggregate all components, from 'import', 'require' or 'spreading' of other components\imports
* to a single object.
*/
function addToImports(node, imports) {
function addToImports(node, imports, parents) {
if (!node) return;
if (node.type === 'ImportDeclaration') {
_addToImports_fromImport(node, imports); // import
} else if (node.type === 'VariableDeclarator') {
_addToImports_fromDeclaration(node, imports); // require + spreading of sub-components etc
_addToImports_fromDeclaration(node, imports, parents); // require + spreading of sub-components etc
} else {
console.log('Debug', 'addToImports', 'unknown type:', node.type);
}
Expand Down
3 changes: 2 additions & 1 deletion eslint-rules/lib/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const {findValueNodeOfIdentifier} = require('./generalUtils');
const {organizeDeprecations, getLocalizedFix} = require('./deprecationsUtils');
const {organizeDeprecations, getLocalizedFix, getPossibleDeprecations} = require('./deprecationsUtils');
const {addToImports} = require('./importUtils');
const {getComponentLocalName, getComponentName} = require('./componentUtils');
const {findAndReportHardCodedValues} = require('./noHardCodedUtils');
Expand All @@ -11,6 +11,7 @@ module.exports = {
// Deprecations
organizeDeprecations,
getLocalizedFix,
getPossibleDeprecations,
// Imports
addToImports,
// Components
Expand Down
2 changes: 1 addition & 1 deletion eslint-rules/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-uilib",
"version": "2.0.0",
"version": "2.0.1",
"description": "uilib set of eslint rules",
"keywords": [
"eslint",
Expand Down
6 changes: 6 additions & 0 deletions eslint-rules/tests/component_deprecation.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@
"source": "another-module-with-deprecations",
"message": "Please use the 'ListList' component instead.",
"fix": {"componentName": "ListList"}
},
{
"component": "ScrollView",
"parent": "MyComponent",
"source": "module-with-deprecations",
"message": "Please use the 'MyComponent.ScrollView' component instead."
}
]
71 changes: 71 additions & 0 deletions eslint-rules/tests/lib/rules/component-deprecation.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,60 @@ ruleTester.run('component-deprecation', rule, {
code: `
import {List} from 'module-with-deprecations';
<List/>`
},
{
options: ruleOptions,
code: `
import {MyComponent} from 'module-with-deprecations';
const {ScrollView} = MyComponent;
<ScrollView/>;
`
},
{
options: ruleOptions,
code: `
import {MyComponent} from 'module-with-deprecations';
const {ScrollView: S, FlatList: F} = MyComponent;
<S/>;
`
},
{
options: ruleOptions,
code: `
import {MyComponent} from 'module-with-deprecations';
<MyComponent.ScrollView/>;
`
},
{
options: ruleOptions,
code: `
import {ScrollView} from 'another-module';
<ScrollView/>;
`
},
{
options: ruleOptions,
code: `
import {ScrollView} from 'another-module';
import {View} from 'module-with-deprecations';
<ScrollView/>;
`
},
{
options: ruleOptions,
code: `
import {ScrollView as S} from 'another-module';
import {View} from 'module-with-deprecations';
<S/>;
`
},
{
options: ruleOptions,
code: `
import {ScrollView} from 'another-module';
import {View as V} from 'module-with-deprecations';
<ScrollView/>;
`
}
],
invalid: [
Expand Down Expand Up @@ -284,6 +338,23 @@ ruleTester.run('component-deprecation', rule, {
{message: "The 'Button' component is deprecated. Please use the 'Touch' component instead."},
{message: "The 'List' component is deprecated. Please use the 'ListList' component instead."}
]
},
{
options: ruleOptions,
code: `import {ScrollView} from 'module-with-deprecations'; <ScrollView/>;`,
output: `import {ScrollView} from 'module-with-deprecations'; <ScrollView/>;`,
errors: [
{message: "The 'ScrollView' component is deprecated. Please use the 'MyComponent.ScrollView' component instead."},
{message: "The 'ScrollView' component is deprecated. Please use the 'MyComponent.ScrollView' component instead."}
]
},
{
options: ruleOptions,
code: `import {ScrollView as S} from 'module-with-deprecations'; <S/>;`,
code: `import {ScrollView as S} from 'module-with-deprecations'; <S/>;`,
errors: [
{message: "The 'ScrollView' component is deprecated. Please use the 'MyComponent.ScrollView' component instead."},
]
}
]
});
Loading