Skip to content

Commit 540e7a1

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 aeed629 commit 540e7a1

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-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();
@@ -163,6 +164,22 @@ module.exports = {
163164
});
164165
}
165166

167+
/**
168+
* Checks if call expression node is one of the propObjectAssignFunctions in the settings
169+
* @param {ASTNode} node The node to process
170+
* @returns {Boolean} True if the function name is defined in the settings, false if not
171+
*/
172+
function isPropObjectAssignFunction(node) {
173+
if (!node) {
174+
return false;
175+
} else if (node.type === 'MemberExpression') {
176+
return propObjectAssignFunctions.has(`${node.object.name}.${node.property.name}`);
177+
} else if (node.type === 'Identifier') {
178+
return propObjectAssignFunctions.has(node.name);
179+
}
180+
return false;
181+
}
182+
166183
// --------------------------------------------------------------------------
167184
// Public
168185
// --------------------------------------------------------------------------
@@ -185,7 +202,12 @@ module.exports = {
185202
return;
186203
}
187204
const component = utils.getRelatedComponent(node);
188-
if (!component || !node.parent.right.properties) {
205+
if (!component || !node.parent.right) {
206+
return;
207+
}
208+
const right = node.parent.right;
209+
if (right.type === 'CallExpression' && isPropObjectAssignFunction(right.callee)) {
210+
right.arguments.filter(arg => arg.type === 'ObjectExpression').forEach(object => validatePropNaming(component.node, object.properties));
189211
return;
190212
}
191213
validatePropNaming(component.node, node.parent.right.properties);

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ ruleTester.run('boolean-prop-naming', rule, {
103103
rule: '^is[A-Z]([A-Za-z0-9]?)+'
104104
}]
105105
}, {
106-
// ES6 components as React.Component with non-boolean PropTypes
107106
code: `
108107
class Hello extends React.Component {
109108
render () { return <div />; }
@@ -295,6 +294,18 @@ ruleTester.run('boolean-prop-naming', rule, {
295294
rule: '^is[A-Z]([A-Za-z0-9]?)+'
296295
}],
297296
parser: 'babel-eslint'
297+
}, {
298+
// No propObjectAssignFunctions setting
299+
code: `
300+
function Card(props) {
301+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
302+
}
303+
Card.propTypes = merge({}, Card.propTypes, {
304+
showScore: PropTypes.bool
305+
});`,
306+
options: [{
307+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
308+
}]
298309
}],
299310

300311
invalid: [{
@@ -515,5 +526,56 @@ ruleTester.run('boolean-prop-naming', rule, {
515526
}, {
516527
message: 'Prop name (somethingElse) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
517528
}]
529+
}, {
530+
code: `
531+
function Card(props) {
532+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
533+
}
534+
Card.propTypes = merge({}, Card.propTypes, {
535+
showScore: PropTypes.bool
536+
});`,
537+
settings: {
538+
propObjectAssignFunctions: ['merge']
539+
},
540+
options: [{
541+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
542+
}],
543+
errors: [{
544+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
545+
}]
546+
}, {
547+
code: `
548+
function Card(props) {
549+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
550+
}
551+
Card.propTypes = Object.assign({}, Card.propTypes, {
552+
showScore: PropTypes.bool
553+
});`,
554+
settings: {
555+
propObjectAssignFunctions: ['Object.assign']
556+
},
557+
options: [{
558+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
559+
}],
560+
errors: [{
561+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
562+
}]
563+
}, {
564+
code: `
565+
function Card(props) {
566+
return <div>{props.showScore ? 'yeh' : 'no'}</div>;
567+
}
568+
Card.propTypes = _.assign({}, Card.propTypes, {
569+
showScore: PropTypes.bool
570+
});`,
571+
settings: {
572+
propObjectAssignFunctions: ['_.assign']
573+
},
574+
options: [{
575+
rule: '^(is|has)[A-Z]([A-Za-z0-9]?)+'
576+
}],
577+
errors: [{
578+
message: 'Prop name (showScore) doesn\'t match rule (^(is|has)[A-Z]([A-Za-z0-9]?)+)'
579+
}]
518580
}]
519581
});

0 commit comments

Comments
 (0)