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 prefer-default-parameters rule #632

Merged
merged 17 commits into from Dec 20, 2020
Merged

Add prefer-default-parameters rule #632

merged 17 commits into from Dec 20, 2020

Conversation

medusalix
Copy link
Contributor

@medusalix medusalix commented Mar 26, 2020

Some notes: I've tried to keep the rule simple by only reporting literal assignments (see this comment). Combining parameters with e.g. a return value of another function or variable might be desired in some cases and should in my opinion not be reported. I've had to work around arrow functions with only one parameter and no parentheses (foo => {}) to make sure the default parameter gets inserted correctly by including the missing parentheses.

Fixes #29


IssueHunt Summary

Referenced issues

This pull request has been submitted to:


IssueHunt has been backed by the following sponsors. Become a sponsor

Copy link
Collaborator

@fisker fisker left a comment

Choose a reason for hiding this comment

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

Sorry for the delay.

Very good format and clear logic. ❤️

Can you update code with code in function body to multiple lines? Should easier to read.

rules/prefer-default-parameters.js Outdated Show resolved Hide resolved
rules/prefer-default-parameters.js Show resolved Hide resolved
rules/prefer-default-parameters.js Outdated Show resolved Hide resolved
test/prefer-default-parameters.js Outdated Show resolved Hide resolved
test/prefer-default-parameters.js Outdated Show resolved Hide resolved
@fisker
Copy link
Collaborator

fisker commented Apr 11, 2020

One more thing, since the fix is not safe , we should use suggestion api, but don't worry, we can easily convert it. example

@medusalix

This comment has been minimized.

@fisker

This comment has been minimized.

@medusalix
Copy link
Contributor Author

medusalix commented Apr 16, 2020

I think we only need check the last parameter.

We still need to check all of them to see if it's actually one of the parameters, but I chose to skip the fixing if it's not the last parameter.

Can you update code with code in function body to multiple lines?

Done. I kept the formatting of some of the tests to make sure that the fixer correctly formats one-line functions.

One more thing, since the fix is not safe , we should use suggestion api.

I've noticed that there are more cases where a fix would actually break the code, so I chose to use the suggestions API exclusively:

function abc(foo) {
	foo += 'bar';
	foo = foo || 'bar';
}

@fisker
Copy link
Collaborator

fisker commented Apr 16, 2020

We still need to check all of them to see if it's actually one of the parameters, but I chose to skip the fixing if it's not the last parameter.

I think we can simple this logic, only report one problem each time on one function. but we need consider following cases

function foo(a, b, c=1){} check b not c,
function foo(a, b, ...c){} also check b. Update: sorry, should ignore both c and b

@fisker
Copy link
Collaborator

fisker commented Apr 16, 2020

Another edge case, since the assignment can be used as value.

function foo(a){
 doSomething(
   a = a || 1
)

doAnotherThing(a)
}

or

function foo(a){
 const b = a = a || 1
}

So, we should choose leave a there or ignore those case.

My suggestion, alway leave a there unless parent is ExpressionStatement.

@fisker
Copy link
Collaborator

fisker commented May 3, 2020

@medusalix What do you think the suggestion above?

@medusalix
Copy link
Contributor Author

medusalix commented May 8, 2020

@fisker Sorry for the late reply, I'm pretty busy right now, I'll take a look at your suggestions when I get the time.

@medusalix
Copy link
Contributor Author

medusalix commented Jun 6, 2020

Another edge case, since the assignment can be used as value.

Yeah, that's already checked by the selector: ExpressionStatement[expression.type="AssignmentExpression"]. I've tested both of your examples.

@sindresorhus sindresorhus requested a review from fisker June 20, 2020 07:10
@fisker
Copy link
Collaborator

fisker commented Jun 23, 2020

  1. Please fix tests I added.
  2. ?? operator is supported by eslint now, please check it too.

@medusalix
Copy link
Contributor Author

medusalix commented Jun 23, 2020

I moved one of your test cases because it can actually be fixed. References are now checked using findVariable.

@fisker
Copy link
Collaborator

fisker commented Jun 23, 2020

I moved one of your test cases because it can actually be fixed. References are now checked using findVariable.

Good, you checked the foo

@fisker
Copy link
Collaborator

fisker commented Jun 30, 2020

I think the problem we can't resolve here is

function abc(foo) {
	foo = foo || 'bar';
	console.log(foo);
}

VS

function abc(foo) {
	console.log(foo);
	foo = foo || 'bar';
}
function abc(foo) {
	useFoo();
	foo = foo || 'bar';

	function useFoo() {
		console.log(foo);
	}
}

VS

function abc(foo) {
	notUseFoo();
	foo = foo || 'bar';

	function notUseFoo() {
	}
}

@sindresorhus
Copy link
Owner

Bump

@medusalix
Copy link
Contributor Author

I think I've found a pretty good solution for the first point @fisker outlined above:

  1. If the parameter is being reassigned, make sure that there are no references to the parameter before the default-assignment:
foo = foo || 123; // Reference 1 and 2
console.log(foo); // Reference 3
// First reference is the default-assignment; invalid, can be fixed.
console.log(foo); // Reference 1
foo = foo || 123; // Reference 2 and 3
// First reference is the console.log statement; valid.
  1. If the parameter is default-assigned to a new variable, make sure that there are no additional references to the old parameter at all:
const bar = foo || 'bar'; // Reference 1
console.log(foo, bar);    // Reference 2
// More than one reference; valid.
const bar = foo || 'bar'; // Reference 1
console.log(bar);
// Only one reference; invalid, can be fixed.

@medusalix
Copy link
Contributor Author

medusalix commented Oct 8, 2020

I've done some tests with the hasSideEffect function. I believe implementing side-effect checking defeats the purpose of this rule. Consider the following example:

function abc(foo) {
	let bar = true;
	bar = false;

	foo = foo || 123;
	console.log(foo);
}

This example would be ignored by the rule because hasSideEffect returns true for the bar = false statement, even though it doesn't have any effects on the foo parameter at all.

@fisker I think ignoring cases where there is any CallExpression before the default-assignment would be a better solution. Other side-effect causing statements would be detected by the reference checking. What do you think?

@medusalix medusalix requested a review from fisker October 8, 2020 15:27
@fisker
Copy link
Collaborator

fisker commented Oct 13, 2020

I'm running out of ideas. 😄

rules/prefer-default-parameters.js Show resolved Hide resolved
test/prefer-default-parameters.js Show resolved Hide resolved
@medusalix medusalix requested a review from fisker October 24, 2020 14:13
@medusalix
Copy link
Contributor Author

@fisker I've implemented the CallExpression check I described in my last comment and added lots of tests for it.

@sindresorhus
Copy link
Owner

// @fisker

Copy link
Collaborator

@fisker fisker left a comment

Choose a reason for hiding this comment

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

I forgot the review progress, I read all comments from beginning again, seems good enough, we can still improve it if any issue found.

@sindresorhus sindresorhus merged commit 8015768 into sindresorhus:master Dec 20, 2020
@medusalix medusalix deleted the prefer-default-parameters branch December 20, 2020 20:37
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.

Prefer default parameters
3 participants