Skip to content

Commit eda0eab

Browse files
committed
Support Object.assign, et al, for bool-prop-naming
With `propObjectAssignFunctions` set in settings like so: ``` { ... propOjectAssignFunctions: ["Object.assign"] ... } ``` One can use `Object.assign` for setting the propTypes like this: ``` function Foo() {...} Foo.propTypes = Object.assign({}, morePropTypes, { isLoading: PropTypes.bool }); ``` And the boolean-prop-naming rule should be able to verify the prop `isLoading` against the defined options.
1 parent a120758 commit eda0eab

File tree

3 files changed

+90
-2
lines changed

3 files changed

+90
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ You can also specify some settings that will be shared across all the plugin rul
4343
"flowVersion": "0.53" // Flow version
4444
},
4545
"propWrapperFunctions": [ "forbidExtraProps" ] // The names of any functions used to wrap the propTypes object, such as `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
46+
"propObjectAssignFunctions": [ "Object.assign" ] // The names of functions used to merge props when declaring propTypes. If this isn't set, any propTypes set using any assign/merge function will be skipped.
4647
}
4748
}
4849
```

lib/rules/boolean-prop-naming.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ module.exports = {
4545
const config = context.options[0] || {};
4646
const rule = config.rule ? new RegExp(config.rule) : null;
4747
const propTypeNames = config.propTypeNames || ['bool'];
48+
const propObjectAssignFunctions = new Set(context.settings.propObjectAssignFunctions || []);
4849

4950
// Remembers all Flowtype object definitions
5051
const objectTypeAnnotations = new Map();
@@ -158,6 +159,22 @@ module.exports = {
158159
});
159160
}
160161

162+
/**
163+
* Checks if call expression node is one of the propObjectAssignFunctions in the settings
164+
* @param {ASTNode} node The node to process
165+
* @returns {Boolean} True if the function name is defined in the settings, false if not
166+
*/
167+
function isPropObjectAssignFunction(node) {
168+
if (!node) {
169+
return false;
170+
} else if (node.type === 'MemberExpression') {
171+
return propObjectAssignFunctions.has(`${node.object.name}.${node.property.name}`);
172+
} else if (node.type === 'Identifier') {
173+
return propObjectAssignFunctions.has(node.name);
174+
}
175+
return false;
176+
}
177+
161178
// --------------------------------------------------------------------------
162179
// Public
163180
// --------------------------------------------------------------------------
@@ -180,7 +197,12 @@ module.exports = {
180197
return;
181198
}
182199
const component = utils.getRelatedComponent(node);
183-
if (!component || !node.parent.right.properties) {
200+
if (!component || !node.parent.right) {
201+
return;
202+
}
203+
const right = node.parent.right;
204+
if (right.type === 'CallExpression' && isPropObjectAssignFunction(right.callee)) {
205+
right.arguments.filter(arg => arg.type === 'ObjectExpression').forEach(object => validatePropNaming(component.node, object.properties));
184206
return;
185207
}
186208
validatePropNaming(component.node, node.parent.right.properties);

tests/lib/rules/boolean-prop-naming.js

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ ruleTester.run('boolean-prop-naming', rule, {
102102
rule: '^is[A-Z]([A-Za-z0-9]?)+'
103103
}]
104104
}, {
105-
// ES6 components as React.Component with non-boolean PropTypes
106105
code: `
107106
class Hello extends React.Component {
108107
render () { return <div />; }
@@ -111,6 +110,9 @@ ruleTester.run('boolean-prop-naming', rule, {
111110
`,
112111
options: [{
113112
rule: '^is[A-Z]([A-Za-z0-9]?)+'
113+
}],
114+
errors: [{
115+
message: 'Prop name (a) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
114116
}]
115117
}, {
116118
code: `
@@ -269,6 +271,18 @@ ruleTester.run('boolean-prop-naming', rule, {
269271
rule: '^is[A-Z]([A-Za-z0-9]?)+'
270272
}],
271273
parser: 'babel-eslint'
274+
}, {
275+
// No propObjectAssignFunctions setting
276+
code: `
277+
function Card(props) {
278+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
279+
}
280+
Card.propTypes = merge({}, Card.propTypes, {
281+
showScore: PropTypes.bool
282+
});`,
283+
options: [{
284+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
285+
}]
272286
}],
273287

274288
invalid: [{
@@ -458,5 +472,56 @@ ruleTester.run('boolean-prop-naming', rule, {
458472
}, {
459473
message: 'Prop name (somethingElse) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
460474
}]
475+
}, {
476+
code: `
477+
function Card(props) {
478+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
479+
}
480+
Card.propTypes = merge({}, Card.propTypes, {
481+
showScore: PropTypes.bool
482+
});`,
483+
settings: {
484+
propObjectAssignFunctions: ['merge']
485+
},
486+
options: [{
487+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
488+
}],
489+
errors: [{
490+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
491+
}]
492+
}, {
493+
code: `
494+
function Card(props) {
495+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
496+
}
497+
Card.propTypes = Object.assign({}, Card.propTypes, {
498+
showScore: PropTypes.bool
499+
});`,
500+
settings: {
501+
propObjectAssignFunctions: ['Object.assign']
502+
},
503+
options: [{
504+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
505+
}],
506+
errors: [{
507+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
508+
}]
509+
}, {
510+
code: `
511+
function Card(props) {
512+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
513+
}
514+
Card.propTypes = _.assign({}, Card.propTypes, {
515+
showScore: PropTypes.bool
516+
});`,
517+
settings: {
518+
propObjectAssignFunctions: ['_.assign']
519+
},
520+
options: [{
521+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
522+
}],
523+
errors: [{
524+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
525+
}]
461526
}]
462527
});

0 commit comments

Comments
 (0)