mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(linter): default_param_last (#2756)
Rule detail: https://eslint.org/docs/latest/rules/default-param-last --------- Co-authored-by: j.buendia <j.buendia> Co-authored-by: Dunqing <dengqing0821@gmail.com>
This commit is contained in:
parent
291dc0597c
commit
1c07a9908d
3 changed files with 200 additions and 0 deletions
|
|
@ -40,6 +40,7 @@ mod eslint {
|
|||
pub mod array_callback_return;
|
||||
pub mod constructor_super;
|
||||
pub mod default_case_last;
|
||||
pub mod default_param_last;
|
||||
pub mod eqeqeq;
|
||||
pub mod for_direction;
|
||||
pub mod getter_return;
|
||||
|
|
@ -363,6 +364,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
eslint::array_callback_return,
|
||||
eslint::constructor_super,
|
||||
eslint::default_case_last,
|
||||
eslint::default_param_last,
|
||||
eslint::eqeqeq,
|
||||
eslint::for_direction,
|
||||
eslint::getter_return,
|
||||
|
|
|
|||
104
crates/oxc_linter/src/rules/eslint/default_param_last.rs
Normal file
104
crates/oxc_linter/src/rules/eslint/default_param_last.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
use oxc_ast::ast::FormalParameter;
|
||||
use oxc_ast::AstKind;
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint(default-param-last): Default parameters should be last")]
|
||||
#[diagnostic(severity(warning), help("Enforce default parameters to be last."))]
|
||||
struct DefaultParamLastDiagnostic(#[label] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct DefaultParamLast;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
/// Enforce default parameters to be last
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Putting default parameter at last allows function calls to omit optional tail arguments.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// // Correct: optional argument can be omitted
|
||||
/// function createUser(id, isAdmin = false) {}
|
||||
/// createUser("tabby")
|
||||
///
|
||||
/// // Incorrect: optional argument can **not** be omitted
|
||||
/// function createUser(isAdmin = false, id) {}
|
||||
/// createUser(undefined, "tabby")
|
||||
/// ```
|
||||
DefaultParamLast,
|
||||
style
|
||||
);
|
||||
|
||||
impl Rule for DefaultParamLast {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match node.kind() {
|
||||
AstKind::Function(function) => {
|
||||
if !function.is_declaration() && !function.is_expression() {
|
||||
return;
|
||||
}
|
||||
check_params(&function.params.items, ctx);
|
||||
}
|
||||
AstKind::ArrowFunctionExpression(function) => check_params(&function.params.items, ctx),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_params<'a>(items: &'a [FormalParameter<'a>], ctx: &LintContext<'a>) {
|
||||
let mut has_seen_plain_param = false;
|
||||
for param in items.iter().rev() {
|
||||
if !param.pattern.kind.is_assignment_pattern() {
|
||||
has_seen_plain_param = true;
|
||||
continue;
|
||||
}
|
||||
if has_seen_plain_param && param.pattern.kind.is_assignment_pattern() {
|
||||
ctx.diagnostic(DefaultParamLastDiagnostic(param.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
"function f() {}",
|
||||
"function f(a) {}",
|
||||
"function f(a = 5) {}",
|
||||
"function f(a, b) {}",
|
||||
"function f(a, b = 5) {}",
|
||||
"function f(a, b = 5, c = 5) {}",
|
||||
"function f(a, b = 5, ...c) {}",
|
||||
"const f = () => {}",
|
||||
"const f = (a) => {}",
|
||||
"const f = (a = 5) => {}",
|
||||
"const f = function f() {}",
|
||||
"const f = function f(a) {}",
|
||||
"const f = function f(a = 5) {}",
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
"function f(a = 5, b) {}",
|
||||
"function f(a = 5, b = 6, c) {}",
|
||||
"function f (a = 5, b, c = 6, d) {}",
|
||||
"function f(a = 5, b, c = 5) {}",
|
||||
"const f = (a = 5, b, ...c) => {}",
|
||||
"const f = function f (a, b = 5, c) {}",
|
||||
"const f = (a = 5, { b }) => {}",
|
||||
"const f = ({ a } = {}, b) => {}",
|
||||
"const f = ({ a, b } = { a: 1, b: 2 }, c) => {}",
|
||||
"const f = ([a] = [], b) => {}",
|
||||
"const f = ([a, b] = [1, 2], c) => {}",
|
||||
];
|
||||
|
||||
Tester::new(DefaultParamLast::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
94
crates/oxc_linter/src/snapshots/default_param_last.snap
Normal file
94
crates/oxc_linter/src/snapshots/default_param_last.snap
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: default_param_last
|
||||
---
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ function f(a = 5, b) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:19]
|
||||
1 │ function f(a = 5, b = 6, c) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ function f(a = 5, b = 6, c) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:23]
|
||||
1 │ function f (a = 5, b, c = 6, d) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:13]
|
||||
1 │ function f (a = 5, b, c = 6, d) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ function f(a = 5, b, c = 5) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = (a = 5, b, ...c) => {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:26]
|
||||
1 │ const f = function f (a, b = 5, c) {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = (a = 5, { b }) => {}
|
||||
· ─────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = ({ a } = {}, b) => {}
|
||||
· ──────────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = ({ a, b } = { a: 1, b: 2 }, c) => {}
|
||||
· ─────────────────────────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = ([a] = [], b) => {}
|
||||
· ────────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
|
||||
⚠ eslint(default-param-last): Default parameters should be last
|
||||
╭─[default_param_last.tsx:1:12]
|
||||
1 │ const f = ([a, b] = [1, 2], c) => {}
|
||||
· ───────────────
|
||||
╰────
|
||||
help: Enforce default parameters to be last.
|
||||
Loading…
Reference in a new issue