Skip to content
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

Add no-fn-reference-in-iterator rule - fixes #91 #97

Merged
merged 7 commits into from
Jul 10, 2017

Conversation

SamVerschueren
Copy link
Contributor

Trying to fix #91 which prevents passing a function directly to an iterator method.

I think that we should also support reduce and reduceRight. Not sure about sort. These are somewhat different though because they accept multiple arguments so should be handled separately.

Just let me know if they should be supported as well.

@kevva
Copy link

kevva commented Jul 5, 2017

I definitely think sort should be allowed. I often pass in other modules directly in the callback. Not sure about reduce though.

Otherwise I think the PR looks good 👍

@SamVerschueren
Copy link
Contributor Author

Don't think sort should be in the list either. It always has 2 arguments.

@kevva
Copy link

kevva commented Jul 5, 2017

Also, should we handle closures? Might be overdoing it...

// invalid
[1, 2, 3].map(fn({unicorn: true}));

// valid
[1, 2, 3].map(x => fn({unicorn: true})(x));

@SamVerschueren
Copy link
Contributor Author

Good idea. Think we should yeah!

@sindresorhus sindresorhus changed the title add no-function-iterator rule - fixes #91 Add no-function-iterator rule - fixes #91 Jul 6, 2017
@SamVerschueren
Copy link
Contributor Author

@sindresorhus any feedback on reduce and reduceRight?

# Prevents passing a function directly to iterator methods

Prevents passing a function directly to an iterator method to make it more clear with the function accepts.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intro should include why it's a useful rule. See: #91 (comment) I don't think most realize the issue with doing this.

@@ -0,0 +1,34 @@
'use strict';
const iteratorMethods = [
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a Set.

@@ -0,0 +1,105 @@
# Prevents passing a function directly to iterator methods

Prevents passing a function directly to an iterator method to make it more clear with the function accepts.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't repeat the title in the text here.


const create = context => ({
CallExpression: node => {
const sourcecode = context.getSourceCode();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the source code is expensive. We should only do it when we actually need it.

@sindresorhus
Copy link
Owner

Wonder if we could use AST selectors for this: http://eslint.org/docs/developer-guide/selectors

@sindresorhus
Copy link
Owner

any feedback on reduce and reduceRight?

reduce() and reduceRight() doesn't make sense, as you always use all their arguments.

@sindresorhus
Copy link
Owner

I think the rule name could be clearer. Not exactly sure what though. Something like no-function-directly-in-iterator, but that's too long.

@SamVerschueren
Copy link
Contributor Author

I was able to do it like this

const iteratorMethods = [
	'filter',
	'map',
	'forEach',
	'every',
	'filter',
	'find',
	'findIndex',
	'some'
];

const selector = 'CallExpression[callee.property.name=/^' + iteratorMethods.join('|') + '$/]';

That way I can drop the isIteratorMethod function. Don't really have a strong preference for one of them.

I think the rule name could be clearer

Wasn't sure about it either. Can't really come up with something that really fits it.

  • no-function-ref-iterator
  • no-function-ref-in-iterator
  • no-fn-ref-in-iterator
  • no-fn-directly-in-iterator

@@ -0,0 +1,133 @@
# Prevents passing a function directly to iterator methods

Suppose you have a `unicorn` module:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote the example a bit. Feel free to provide feedback on wording/style/...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

return arg.name;
}

const sourcecode = context.getSourceCode();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable feels moot, just use it directly below.

@sindresorhus
Copy link
Owner

That way I can drop the isIteratorMethod function. Don't really have a strong preference for one of them.

Nah, I prefer what you already have.

@sindresorhus
Copy link
Owner

Maybe we just go verbose no-function-reference-in-iterator, unless @kevva can come up with something better.

@sindresorhus
Copy link
Owner

Actually, let's go with no-fn-reference-in-iterator. fn is a common function abbreviation.

@SamVerschueren SamVerschueren changed the title Add no-function-iterator rule - fixes #91 Add no-fn-reference-in-iterator rule - fixes #91 Jul 6, 2017
@SamVerschueren
Copy link
Contributor Author

I think I processed all the feedback

@kevva
Copy link

kevva commented Jul 6, 2017

reduce() and reduceRight() doesn't make sense, as you always use all their arguments.

Not necessarily true since they have index and array too, although it might be an edge case.

Maybe we just go verbose no-function-reference-in-iterator, unless @kevva can come up with something better.

I think no-fn-reference-in-iterator is good too. Had a look at what ESLint uses themselves to see if we could stay consistent with their naming, but they're using both function and func in their rule names.

@SamVerschueren
Copy link
Contributor Author

I prefer fn above func to be honest.

@sindresorhus
Copy link
Owner

Not necessarily true since they have index and array too, although it might be an edge case.

Oh, this is embarrassing. I didn't know that. Never used those arguments. I guess they make sense to include after all then.

I prefer fn above func to be honest.

Me too.

@sindresorhus
Copy link
Owner

Just a thought. Should we allow this if the function used is defined in the same scope?

Should be make an exception for built-in types? This is a very common pattern [true, 1, 2].filter(Boolean).

@SamVerschueren
Copy link
Contributor Author

Should we allow this if the function used is defined in the same scope?

I think we shouldn't. It's easy to overlook something and someone can also add a second argument to the function without really noticing this caveat.

Should we make an exception for built-in types?

We could, but I'd suggest using a whitelist. parseInt is also built-in but you don't want someone to write ['1', '2', '3'].map(parseInt).

@sindresorhus
Copy link
Owner

I think we shouldn't. It's easy to overlook something and someone can also add a second argument to the function without really noticing this caveat.

Yeah, you're probably right.

We could, but I'd suggest using a whitelist. parseInt is also built-in but you don't want someone to write ['1', '2', '3'].map(parseInt).

Actually, I can only think of Boolean as an actual use-case. Maybe we just add that first and add others later as needed.

@sindresorhus sindresorhus merged commit c11cc5d into sindresorhus:master Jul 10, 2017
@sindresorhus
Copy link
Owner

Good stuff Sam. This one will be very useful :)

@SamVerschueren
Copy link
Contributor Author

Woop woop, thanks for the feedback :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prevent passing a function directly to iterator methods
3 participants