-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New boolean-prop-naming rule for enforcing the naming of booleans
#1264
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
Conversation
ljharb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about custom propTypes that enforce booleans but aren't PropTypes.bool? For example, mutuallyExclusiveTrueProps from https://www.npmjs.com/package/airbnb-prop-types.
Can there be a way to customize the name of custom propTypes that are booleans?
docs/rules/boolean-prop-naming.md
Outdated
| ```jsx | ||
| var Hello = createReactClass({ | ||
| propTypes: { | ||
| enabled: PropTypes.boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PropTypes.bool - .boolean isn't a thing (same throughout)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Good catch.
docs/rules/boolean-prop-naming.md
Outdated
|
|
||
| ### `rule` | ||
|
|
||
| The Regex pattern to use when validating the name of the prop. Some common examples are: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regex or RegExp
docs/rules/boolean-prop-naming.md
Outdated
|
|
||
| ## About component detection | ||
|
|
||
| For this rule to work we need to detect React components, this could be very hard since components could be declared in a lot of ways. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be using Components.detect in all our rules; is there a reason this paragraph needs to exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was copy/pasted from another rule's document. Should I remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this seems more like a project-level thing, not a rule-level thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WIll remove.
lib/rules/boolean-prop-naming.js
Outdated
| */ | ||
| 'use strict'; | ||
|
|
||
| var has = require('has'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Not all rules were using ES6, wasn't sure which version of Node we're supporting. Will update accordingly.
| // createReactClass components with PropTypes | ||
| code: [ | ||
| 'var Hello = createReactClass({', | ||
| ' propTypes: {isSomething: PropTypes.boolean},', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think all the PropType test cases are invalid - s/boolean/bool/g.
ae2b074 to
82e35b8
Compare
Good idea. I've added a new |
82e35b8 to
b16fd19
Compare
docs/rules/boolean-prop-naming.md
Outdated
|
|
||
| ### `rule` | ||
|
|
||
| The RegExp pattern to use when validating the name of the prop. Some common examples are: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the default for this option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null is the default at the moment (ie. the naming checks are disabled). It didn't seem right to enforce my own preferences on all users. Do you think is makes sense to set "(is|has)*" as the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since if not, the rule does nothing by default, yes.
The ideal scenario is that nobody ever needs to write a regex, except for the minority edge cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Will set a default.
| create: Components.detect(function(context, components, utils) { | ||
| const sourceCode = context.getSourceCode(); | ||
| const config = context.options[0] || {}; | ||
| const rule = config.rule ? new RegExp(config.rule) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm really really not a fan of user-supplied regexes, and passing unsanitized input into new RegExp can definitely cause catastrophic backtracking and other malicious regexes to be invoked.
Can we simplify this somehow, perhaps requiring a list of prefixes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not opposed to replacing the RegExp entry to just prefixes, however, that makes the rule much less powerful and less customizable. Having user-supplied regexes in ESLint rules isn't uncommon (eg. http://eslint.org/docs/rules/id-match) when specifying naming conventions for things.
| return false; | ||
| } | ||
|
|
||
| return Boolean( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usually we just do ‼x instead of Boolean(x), nbd tho
| require('babel-eslint'); | ||
|
|
||
| var parserOptions = { | ||
| ecmaVersion: 8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can probably be 6/2015, yes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix.
| ecmaVersion: 8, | ||
| sourceType: 'module', | ||
| ecmaFeatures: { | ||
| experimentalObjectRestSpread: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think we're using this feature in these tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix.
c9d8647 to
d76c2fb
Compare
lib/rules/boolean-prop-naming.js
Outdated
| type: 'array' | ||
| }, | ||
| rule: { | ||
| default: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put the default here, in the schema, and use minLength: 1 to avoid the empty string?
lib/rules/boolean-prop-naming.js
Outdated
| const sourceCode = context.getSourceCode(); | ||
| const config = context.options[0] || {}; | ||
| const rule = new RegExp(config.rule || DEFAULT_RULE); | ||
| const propTypeNames = config.propTypeNames ? config.propTypeNames : ['bool']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, can this default go in the schema instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, default schema definition doesn't work for this option. Maybe because it's an array type? Specifying a default at the schema level here never returns anything from config object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess you can't have a default array in jsonschema.
in that case, a ? a : b should always be a || b :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. Thanks!
lib/rules/boolean-prop-naming.js
Outdated
| items: { | ||
| type: 'string' | ||
| }, | ||
| type: 'array' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add uniqueItems: true and minItems: 1
fe71deb to
38e479a
Compare
lib/rules/boolean-prop-naming.js
Outdated
| } | ||
|
|
||
| const list = components.list(); | ||
| for (let component in list) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid for..in; can we use Object.keys().forEach here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
38e479a to
519dc2b
Compare
ljharb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Let's wait til we get at least one other collab review before merging.
lencioni
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution!
lib/rules/boolean-prop-naming.js
Outdated
| ( | ||
| prop.type === 'ObjectTypeProperty' && | ||
| prop.value.type === 'BooleanTypeAnnotation' && | ||
| getPropName(prop).search(rule) < 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think rule.test(getPropName(prop)) might be more appropriate here (and below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change to use .exec() actually, since (after some research) that appears to be the most performant way to execute Regex rules. Hope that's ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exec mutates; test doesn't - test might be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
lib/rules/boolean-prop-naming.js
Outdated
| const propName = getPropName(propNode); | ||
| context.report({ | ||
| node: propNode, | ||
| message: `Prop name (${propName}) doesn't match specified rule (${config.rule})`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"specified" seems redundant in this message. I think you can remove it without losing any meaning. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Will remove.
lib/rules/boolean-prop-naming.js
Outdated
| const propTypeNames = config.propTypeNames || ['bool']; | ||
|
|
||
| // Remembers all Flowtype object definitions | ||
| var ObjectTypeAnnonations = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo? ObjectTypeAnnotations?
Also, since this isn't instantiated, it should probably start with a lowercase letter.
And it might be a bit nicer to use a Map instead of a plain object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on all 3 points, nice catch
d27f42e to
f9c5fae
Compare
f9c5fae to
da0affa
Compare
At my workplace, we prefer to name our boolean props as "isSomething" or "hasWhatever". This is an ESLint rule which allows devs to specify a Regex pattern for how they want their boolean props named.
Tested with createReactClass, ES6 components, stateless components and Flowtype.
I support, in the future, this rule can be expanded to support naming rules for ANY props, but that felt like overkill for the time being. Hopefully this rule will be useful as is.