Skip to content

Commit e4bbbce

Browse files
refactor(eslint/default-param-last): simplify implementation and enhance readability (#13516)
## Refactor and Standardize: `eslint/default-param-last` This PR refactors the implementation of the `default-param-last` rule to make the codebase more **idiomatic Rust**, improving readability, maintainability, and alignment with Rust best practices. In addition, the rule documentation has been **standardized and enhanced** following the documentation skeleton described in #13389. ### Changes included * Refactored rule logic with clearer naming, early returns, and idiomatic Rust patterns (`if let`, `Option`, `Iterator`, etc.). * Improved structure for better readability and maintainability. * Focused on optimization and performances. * Standardized rule documentation for consistency across the linter rules. > [!NOTE] > This PR is focused solely on refactoring and documentation; no test behavior is modified. --------- Co-authored-by: Cameron <cameron.clark@hey.com>
1 parent e87d7bd commit e4bbbce

File tree

1 file changed

+51
-20
lines changed

1 file changed

+51
-20
lines changed

crates/oxc_linter/src/rules/eslint/default_param_last.rs

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use oxc_ast::{AstKind, ast::FormalParameter};
1+
use oxc_ast::{AstKind, ast::FormalParameter, ast::Function};
22
use oxc_diagnostics::OxcDiagnostic;
33
use oxc_macros::declare_oxc_lint;
44
use oxc_span::Span;
@@ -17,26 +17,58 @@ pub struct DefaultParamLast;
1717
declare_oxc_lint!(
1818
/// ### What it does
1919
///
20-
/// Enforce default parameters to be last
20+
/// Requires default parameters in functions to be the last ones.
2121
///
2222
/// ### Why is this bad?
2323
///
24-
/// Putting default parameter at last allows function calls to omit optional tail arguments.
24+
/// Placing default parameters last allows function calls to omit optional trailing arguments,
25+
/// which improves readability and consistency. This rule applies equally to JavaScript and
26+
/// TypeScript functions.
27+
///
28+
/// ### Options
29+
///
30+
/// No options available for this rule
2531
///
2632
/// ### Examples
2733
///
2834
/// Examples of **incorrect** code for this rule:
29-
/// ```javascript
30-
/// // Incorrect: optional argument can **not** be omitted
35+
/// ```js
36+
/// /* default-param-last: "error" */
37+
///
38+
/// function f(a = 0, b) {}
39+
/// function f(a, b = 0, c) {}
3140
/// function createUser(isAdmin = false, id) {}
3241
/// createUser(undefined, "tabby")
3342
/// ```
3443
///
3544
/// Examples of **correct** code for this rule:
36-
/// ```javascript
45+
/// ```js
46+
/// /* default-param-last: "error" */
47+
///
48+
/// function f(a, b = 0) {}
49+
/// function f(a = 0, b = 0) {}
3750
/// function createUser(id, isAdmin = false) {}
3851
/// createUser("tabby")
3952
/// ```
53+
///
54+
/// Examples of **incorrect** TypeScript code for this rule:
55+
/// ```ts
56+
/// /* default-param-last: "error" */
57+
///
58+
/// function greet(message: string = "Hello", name: string) {}
59+
/// function combine(a: number = 1, b: number, c: number) {}
60+
/// function combine(a: number, b: number = 2, c: number) {}
61+
/// function combine(a: number = 1, b?: number, c: number) {}
62+
/// ```
63+
///
64+
/// Examples of **correct** TypeScript code for this rule:
65+
/// ```ts
66+
/// /* default-param-last: "error" */
67+
///
68+
/// function greet(name: string, message: string = "Hello") {}
69+
/// function combine(a: number, b: number = 2, c: number = 3) {}
70+
/// function combine(a: number, b?: number, c: number = 3) {}
71+
/// ```
4072
DefaultParamLast,
4173
eslint,
4274
style
@@ -45,10 +77,7 @@ declare_oxc_lint!(
4577
impl Rule for DefaultParamLast {
4678
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
4779
match node.kind() {
48-
AstKind::Function(function) => {
49-
if !function.is_declaration() && !function.is_expression() {
50-
return;
51-
}
80+
AstKind::Function(function) if is_function_decl_or_expr(function) => {
5281
check_params(&function.params.items, ctx);
5382
}
5483
AstKind::ArrowFunctionExpression(function) => check_params(&function.params.items, ctx),
@@ -57,16 +86,18 @@ impl Rule for DefaultParamLast {
5786
}
5887
}
5988

60-
fn check_params<'a>(items: &'a [FormalParameter<'a>], ctx: &LintContext<'a>) {
61-
let mut has_seen_plain_param = false;
62-
for param in items.iter().rev() {
63-
if !param.pattern.kind.is_assignment_pattern() && !param.pattern.optional {
64-
has_seen_plain_param = true;
65-
continue;
66-
}
67-
if has_seen_plain_param
68-
&& (param.pattern.kind.is_assignment_pattern() || param.pattern.optional)
69-
{
89+
fn is_function_decl_or_expr(function: &Function) -> bool {
90+
function.is_declaration() || function.is_expression()
91+
}
92+
93+
fn check_params<'a>(params: &'a [FormalParameter<'a>], ctx: &LintContext<'a>) {
94+
let mut seen_plain = false;
95+
for param in params.iter().rev() {
96+
let is_default = param.pattern.kind.is_assignment_pattern() || param.pattern.optional;
97+
98+
if !is_default {
99+
seen_plain = true;
100+
} else if seen_plain {
70101
ctx.diagnostic(default_param_last_diagnostic(param.span));
71102
}
72103
}

0 commit comments

Comments
 (0)