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

feat(lint): support assigned functions in noFloatingPromises #4958

Merged

Conversation

kaykdm
Copy link
Contributor

@kaykdm kaykdm commented Jan 24, 2025

Summary

related: #3187 and #4956
This pull request introduces the support for assigned functions in noFloatingPromises

Example of invalid code:

const returnsPromise = async (): Promise<string> => {
  return 'value';
};

returnsPromise();

const returnsPromiseAssignedFunction = async function (): Promise<string> {
  return 'value'
}

returnsPromiseAssignedFunction();

Example of valid code:

const returnsPromise = async (): Promise<string> => {
  return 'value';
};

await returnsPromise();
void returnsPromise();

// Calling .then() with two arguments
returnsPromise().then(
  () => {},
  () => {}
);

@github-actions github-actions bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Jan 24, 2025
Copy link

codspeed-hq bot commented Jan 24, 2025

CodSpeed Performance Report

Merging #4958 will improve performances by 6.88%

Comparing kaykdm:support-arrow-function-and-assigned-function (70e298c) with next (0bf4eaa)

Summary

⚡ 1 improvements
✅ 94 untouched benchmarks

Benchmarks breakdown

Benchmark BASE HEAD Change
react.production.min_3378072959512366797.js[cached] 2 ms 1.9 ms +6.88%

@kaykdm kaykdm marked this pull request as ready for review January 24, 2025 09:58
Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

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

Love it!

Comment on lines 207 to 216
match any_js_binding_decl {
AnyJsBindingDeclaration::JsFunctionDeclaration(func_decl) => {
return is_function_a_promise(&func_decl);
}
AnyJsBindingDeclaration::JsVariableDeclarator(js_var_decl) => {
return is_variable_initializer_a_promise(&js_var_decl)
|| is_variable_annotation_a_promise(&js_var_decl);
}
_ => {}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: if you remove the false at the end, you can just use this entire match as an expression that defines the return value, so you don't need the repeated return statements. This is generally considered a bit more idiomatic in Rust:

Suggested change
match any_js_binding_decl {
AnyJsBindingDeclaration::JsFunctionDeclaration(func_decl) => {
return is_function_a_promise(&func_decl);
}
AnyJsBindingDeclaration::JsVariableDeclarator(js_var_decl) => {
return is_variable_initializer_a_promise(&js_var_decl)
|| is_variable_annotation_a_promise(&js_var_decl);
}
_ => {}
}
match any_js_binding_decl {
AnyJsBindingDeclaration::JsFunctionDeclaration(func_decl) => {
is_function_a_promise(&func_decl)
}
AnyJsBindingDeclaration::JsVariableDeclarator(js_var_decl) => {
is_variable_initializer_a_promise(&js_var_decl)
|| is_variable_annotation_a_promise(&js_var_decl)
}
_ => false
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out!
I've updated the code to remove the repeated return statements. It looks cleaner and more idiomatic now.

Comment on lines 435 to 451
match expr {
AnyJsExpression::JsArrowFunctionExpression(arrow_func) => {
if arrow_func.async_token().is_some() {
return true;
}

return is_return_type_a_promise(arrow_func.return_type_annotation());
}
AnyJsExpression::JsFunctionExpression(func_expr) => {
if func_expr.async_token().is_some() {
return true;
}
return is_return_type_a_promise(func_expr.return_type_annotation());
}
_ => {}
}
false
Copy link
Contributor

@arendjr arendjr Jan 24, 2025

Choose a reason for hiding this comment

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

Similar to feedback above:

Suggested change
match expr {
AnyJsExpression::JsArrowFunctionExpression(arrow_func) => {
if arrow_func.async_token().is_some() {
return true;
}
return is_return_type_a_promise(arrow_func.return_type_annotation());
}
AnyJsExpression::JsFunctionExpression(func_expr) => {
if func_expr.async_token().is_some() {
return true;
}
return is_return_type_a_promise(func_expr.return_type_annotation());
}
_ => {}
}
false
match expr {
AnyJsExpression::JsArrowFunctionExpression(arrow_func) => {
arrow_func.async_token().is_some()
|| is_return_type_a_promise(arrow_func.return_type_annotation())
}
AnyJsExpression::JsFunctionExpression(func_expr) => {
func_expr.async_token().is_some()
|| is_return_type_a_promise(func_expr.return_type_annotation())
}
_ => false
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! updated!

@kaykdm kaykdm force-pushed the support-arrow-function-and-assigned-function branch from a4ee1e3 to 70e298c Compare January 24, 2025 11:02
/// return 'value'
/// }
/// ```
fn is_variable_initializer_a_promise(js_variable_declarator: &JsVariableDeclarator) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

It's been a while that you're contributing to the code base, so you might have noticed that you have to deal with many Result coming from the syntax.

I strongly suggest changing all these functions to return a Option instead, and start doing .ok()? for all those syntax APIs that return SyntaxResult.

This is an accepted approach inside Biome, especially inside the lint rules. Doing so, you low down the cognitive complexity of the code, and the code style it's in line with the existing rules.

In this case:

fn is_variable_initializer_a_promise(js_variable_declarator: &JsVariableDeclarator) -> Option<bool> {}

is_variable_initializer_a_promise(node)?

You're free to apply this suggestion to the whole file in the next PR, or in this PR, but we should do it eventually.

Copy link
Contributor Author

@kaykdm kaykdm Jan 24, 2025

Choose a reason for hiding this comment

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

Thanks for the review!
That makes sense. I'll apply that suggestion to the whole file in the next PR.

/// return Promise.resolve("value")
/// }
/// ```
fn is_variable_annotation_a_promise(js_variable_declarator: &JsVariableDeclarator) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

Same here. Change it to Option<bool>, use .ok()? every time you extract a type from a node, and the caller will use ?

@arendjr arendjr merged commit f15bd91 into biomejs:next Jan 24, 2025
11 checks passed
unvalley pushed a commit to unvalley/biome that referenced this pull request Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Linter Area: linter L-JavaScript Language: JavaScript and super languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants