Skip to content

Commit 145cd44

Browse files
committed
add cases to prop-value-shape lint rule
1 parent cb47fb6 commit 145cd44

File tree

3 files changed

+185
-63
lines changed

3 files changed

+185
-63
lines changed

eslint-rules/lib/rules/prop-value-shape-deprecation.js

Lines changed: 88 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
11
const _ = require('lodash');
2+
const utils = require('../utils');
23

34
const MAP_SCHEMA = {
45
type: 'object',
56
properties: {
6-
component: {
7-
type: 'string'
7+
components: {
8+
type: 'array',
9+
items: {
10+
type: 'string'
11+
}
812
},
9-
props: {
13+
propNames: {
14+
type: 'array',
15+
items: {
16+
type: 'string'
17+
}
18+
},
19+
shape: {
1020
type: 'array',
1121
items: {
1222
type: 'object',
13-
required: ['prop', 'value'],
23+
required: ['prop', 'message', 'fix'],
1424
properties: {
1525
prop: {
1626
type: 'string'
1727
},
18-
value: {
19-
type: 'array',
20-
items: {
21-
type: 'object',
22-
required: ['prop', 'message', 'fix'],
23-
properties: {
24-
prop: {
25-
type: 'string'
26-
},
27-
message: {
28-
type: 'string'
29-
},
30-
fix: {
31-
type: 'object',
32-
additionalProperties: true
33-
}
34-
}
35-
}
28+
message: {
29+
type: 'string'
30+
},
31+
fix: {
32+
type: 'object',
33+
additionalProperties: true
3634
}
3735
}
3836
}
@@ -59,39 +57,80 @@ module.exports = {
5957
try {
6058
const {deprecations} = _.get(context, 'options[0]');
6159
const nodeName = _.get(node, 'name.name');
62-
const deprecation = nodeName && deprecations && _.find(deprecations, ['component', nodeName]);
63-
if (deprecation.component && nodeName === deprecation.component) {
64-
_.forEach(node.attributes, attribute => {
65-
const attributeName = _.get(attribute, 'name.name');
66-
const deprecationProps = _.get(deprecation, 'props');
67-
const deprecationProp =
68-
attributeName && deprecationProps && _.find(deprecationProps, ['prop', attributeName]);
69-
const deprecationPropName = _.get(deprecationProp, 'prop');
70-
if (deprecationPropName && attributeName === deprecationPropName) {
71-
const attributeProperties = _.get(attribute, 'value.expression.properties');
72-
for (let i = 0; i <= attributeProperties.length; i++) {
73-
const propertyName = _.get(attributeProperties[i], 'key.name');
74-
const origin =
75-
deprecationProp.value && propertyName && _.find(deprecationProp.value, ['prop', propertyName]);
76-
if (origin.prop && propertyName === origin.prop) {
77-
const destination = _.get(origin, 'fix.propName');
78-
const message = `The shape of '${deprecationPropName}' prop of '${deprecation.component}' doesn't contain '${origin.prop}' anymore. Please use '${destination}' instead (fix is available).`;
79-
context.report({
80-
node,
81-
message,
82-
fix(fixer) {
83-
if (destination && attributeProperties[i].key) {
84-
return fixer.replaceText(attributeProperties[i].key, destination);
85-
}
60+
_.forEach(deprecations, deprecation => {
61+
if (_.includes(deprecation.components, nodeName)) {
62+
_.forEach(node.attributes, attribute => {
63+
const attributeName = _.get(attribute, 'name.name');
64+
if (attribute.type === 'JSXSpreadAttribute') {
65+
const spreadSource = utils.findValueNodeOfIdentifier(attribute.argument.name, context.getScope());
66+
const spreadSourceName = _.get(spreadSource, 'properties[0].key.name');
67+
checkAttributeProperties(
68+
spreadSource.properties[0].value.properties,
69+
spreadSourceName,
70+
deprecation,
71+
nodeName,
72+
node,
73+
context
74+
);
75+
} else if (_.includes(deprecation.propNames, attributeName)) {
76+
const attributeType = _.get(attribute, 'value.expression.type');
77+
if (attributeType === 'Identifier') {
78+
const passedProp = utils.findValueNodeOfIdentifier(
79+
attribute.value.expression.name,
80+
context.getScope()
81+
);
82+
if (passedProp && passedProp.properties) {
83+
checkAttributeProperties(
84+
passedProp.properties,
85+
attributeName,
86+
deprecation,
87+
nodeName,
88+
node,
89+
context
90+
);
91+
}
92+
}
93+
const attributeProps = _.get(attribute, 'value.expression.properties');
94+
for (let index = 0; index < attributeProps.length; index++) {
95+
const spreadElementType = _.get(attribute, `value.expression.properties[${index}].type`);
96+
if (attributeType === 'ObjectExpression' && spreadElementType === 'ExperimentalSpreadProperty') {
97+
const spreadSource = utils.findValueNodeOfIdentifier(
98+
attribute.value.expression.properties[index].argument.name,
99+
context.getScope()
100+
);
101+
if (spreadSource && spreadSource.properties) {
102+
checkAttributeProperties(spreadSource.properties, attributeName, deprecation, nodeName, node, context);
86103
}
87-
});
104+
}
88105
}
106+
const attributeProperties = _.get(attribute, 'value.expression.properties');
107+
checkAttributeProperties(attributeProperties, attributeName, deprecation, nodeName, node, context);
108+
}
109+
});
110+
}
111+
});
112+
} catch (err) {
113+
console.log('Found error in: ', context.getFilename());
114+
}
115+
}
116+
117+
function checkAttributeProperties(attributeProperties, attributeName, deprecation, nodeName, node, context) {
118+
for (let i = 0; i <= attributeProperties.length; i++) {
119+
const propertyName = _.get(attributeProperties[i], 'key.name');
120+
const origin = propertyName && _.find(deprecation.shape, ['prop', propertyName]);
121+
if (origin && origin.prop && propertyName === origin.prop) {
122+
const destination = _.get(origin, 'fix.propName');
123+
const message = `The shape of '${attributeName}' prop of '${nodeName}' doesn't contain '${origin.prop}' anymore. Please use '${destination}' instead (fix is available).`;
124+
context.report({
125+
node,
126+
message,
127+
fix(fixer) {
128+
if (destination && attributeProperties[i].key) {
129+
return fixer.replaceText(attributeProperties[i].key, destination);
89130
}
90131
}
91132
});
92133
}
93-
} catch (err) {
94-
console.log('Found error in: ', context.getFilename());
95134
}
96135
}
97136

eslint-rules/tests/lib/rules/prop-value-shape-deprecation.js

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,63 @@ RuleTester.setDefaultConfig({
1010
const ruleTester = new RuleTester();
1111

1212
const ruleOptions = [{deprecations: deprecationsJson}];
13+
const PassedPropExampleCode = `
14+
const myProps = {
15+
goodProp: goodValue,
16+
imageSource: {uri: some_uri}
17+
};
18+
19+
<Label avatar={myProps}/>
20+
`;
21+
const PassedPropExampleOutput = `
22+
const myProps = {
23+
goodProp: goodValue,
24+
source: {uri: some_uri}
25+
};
26+
27+
<Label avatar={myProps}/>
28+
`;
29+
30+
const firstLevelSpreadCode = `
31+
const myProps = {
32+
avatarProps: {
33+
goodProp: goodValue,
34+
imageSource: {uri: some_uri}
35+
}
36+
};
37+
38+
<Label goodProp={'goodValue'} {...myProps}/>
39+
`;
40+
41+
const firstLevelSpreadOutput = `
42+
const myProps = {
43+
avatarProps: {
44+
goodProp: goodValue,
45+
source: {uri: some_uri}
46+
}
47+
};
48+
49+
<Label goodProp={'goodValue'} {...myProps}/>
50+
`;
51+
52+
const secondLevelSpreadCode = `
53+
const myProps = {
54+
goodProp: goodValue,
55+
imageSource: {uri: some_uri}
56+
};
57+
58+
<Label avatar={{goodProp: goodValue, ...myProps}}/>
59+
`;
60+
61+
const secondLevelSpreadOutput = `
62+
const myProps = {
63+
goodProp: goodValue,
64+
source: {uri: some_uri}
65+
};
66+
67+
<Label avatar={{goodProp: goodValue, ...myProps}}/>
68+
`;
69+
1370

1471
ruleTester.run('prop-value-shape-deprecation', rule, {
1572
valid: [
@@ -21,9 +78,39 @@ ruleTester.run('prop-value-shape-deprecation', rule, {
2178
invalid: [
2279
{
2380
options: ruleOptions,
24-
code: '<ListItem avatar={{imageSource: {uri: some_uri}}}/>',
81+
code: '<ListItem avatar={{imageSource: {uri: some_uri}, someProp: someValue}}/>',
2582
errors: [{message: `The shape of 'avatar' prop of 'ListItem' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
26-
output: '<ListItem avatar={{source: {uri: some_uri}}}/>'
83+
output: '<ListItem avatar={{source: {uri: some_uri}, someProp: someValue}}/>'
84+
},
85+
{
86+
options: ruleOptions,
87+
code: '<ListItem avatar={{someProp: someValue, imageSource: {uri: some_uri}}}/>',
88+
errors: [{message: `The shape of 'avatar' prop of 'ListItem' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
89+
output: '<ListItem avatar={{someProp: someValue, source: {uri: some_uri}}}/>'
90+
},
91+
{
92+
options: ruleOptions,
93+
code: '<ListItem someProp={someValue} avatar={{imageSource: {uri: some_uri}}}/>',
94+
errors: [{message: `The shape of 'avatar' prop of 'ListItem' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
95+
output: '<ListItem someProp={someValue} avatar={{source: {uri: some_uri}}}/>'
96+
},
97+
{
98+
options: ruleOptions,
99+
code: PassedPropExampleCode,
100+
errors: [{message: `The shape of 'avatar' prop of 'Label' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
101+
output: PassedPropExampleOutput
102+
},
103+
{
104+
options: ruleOptions,
105+
code: firstLevelSpreadCode,
106+
errors: [{message: `The shape of 'avatarProps' prop of 'Label' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
107+
output: firstLevelSpreadOutput
108+
},
109+
{
110+
options: ruleOptions,
111+
code: secondLevelSpreadCode,
112+
errors: [{message: `The shape of 'avatar' prop of 'Label' doesn't contain 'imageSource' anymore. Please use 'source' instead (fix is available).`}],
113+
output: secondLevelSpreadOutput
27114
}
28115
]
29116
});

eslint-rules/tests/prop-value-shape-deprecation.json

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
[
22
{
3-
"component": "ListItem",
4-
"props": [
3+
"components": ["ListItem", "Label"],
4+
"propNames": ["avatar", "avatarProps"],
5+
"shape": [
56
{
6-
"prop": "avatar",
7-
"value": [
8-
{
9-
"prop": "imageSource",
10-
"message": "Please use the 'source' prop instead (fix is available).",
11-
"fix": {
12-
"propName": "source"
13-
}
14-
}
15-
]
7+
"prop": "imageSource",
8+
"message": "Please use the 'source' prop instead (fix is available).",
9+
"fix": {
10+
"propName": "source"
11+
}
1612
}
1713
]
1814
}

0 commit comments

Comments
 (0)