From 76f11dda4b6c7844f4eff501b823d3907936366b Mon Sep 17 00:00:00 2001 From: Tapan Prakash Date: Fri, 17 Jan 2025 16:38:03 +0530 Subject: [PATCH 1/2] feat(linter): enhance `default_param_last` rule to handle optional parameters - Enhanced default_param_last to handle optional parameters based on the corresponding typescript-eslint rule. - Added additional test cases from the typescript-eslint rule. --- .../src/rules/eslint/default_param_last.rs | 159 ++++++++- .../snapshots/eslint_default_param_last.snap | 309 ++++++++++++++++++ 2 files changed, 466 insertions(+), 2 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/default_param_last.rs b/crates/oxc_linter/src/rules/eslint/default_param_last.rs index cdc32fc9dbab3..8673e2f9b8ac4 100644 --- a/crates/oxc_linter/src/rules/eslint/default_param_last.rs +++ b/crates/oxc_linter/src/rules/eslint/default_param_last.rs @@ -54,11 +54,13 @@ impl Rule for DefaultParamLast { 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() { + if !param.pattern.kind.is_assignment_pattern() && !param.pattern.optional { has_seen_plain_param = true; continue; } - if has_seen_plain_param && param.pattern.kind.is_assignment_pattern() { + if has_seen_plain_param + && (param.pattern.kind.is_assignment_pattern() || param.pattern.optional) + { ctx.diagnostic(default_param_last_diagnostic(param.span)); } } @@ -82,6 +84,108 @@ fn test() { "const f = function f() {}", "const f = function f(a) {}", "const f = function f(a = 5) {}", + "function fn(a: string = 'a', b?: string) {}", + "function foo() {}", + "function foo(a: number) {}", + "function foo(a = 1) {}", + "function foo(a?: number) {}", + "function foo(a: number, b: number) {}", + "function foo(a: number, b: number, c?: number) {}", + "function foo(a: number, b = 1) {}", + "function foo(a: number, b = 1, c = 1) {}", + "function foo(a: number, b = 1, c?: number) {}", + "function foo(a: number, b?: number, c = 1) {}", + "function foo(a: number, b = 1, ...c) {}", + "const foo = function () {};", + "const foo = function (a: number) {};", + "const foo = function (a = 1) {};", + "const foo = function (a?: number) {};", + "const foo = function (a: number, b: number) {};", + "const foo = function (a: number, b: number, c?: number) {};", + "const foo = function (a: number, b = 1) {};", + "const foo = function (a: number, b = 1, c = 1) {};", + "const foo = function (a: number, b = 1, c?: number) {};", + "const foo = function (a: number, b?: number, c = 1) {};", + "const foo = function (a: number, b = 1, ...c) {};", + "const foo = () => {};", + "const foo = (a: number) => {};", + "const foo = (a = 1) => {};", + "const foo = (a?: number) => {};", + "const foo = (a: number, b: number) => {};", + "const foo = (a: number, b: number, c?: number) => {};", + "const foo = (a: number, b = 1) => {};", + "const foo = (a: number, b = 1, c = 1) => {};", + "const foo = (a: number, b = 1, c?: number) => {};", + "const foo = (a: number, b?: number, c = 1) => {};", + "const foo = (a: number, b = 1, ...c) => {};", + " + class Foo { + constructor(a: number, b: number, c: number) {} + }", + " + class Foo { + constructor(a: number, b?: number, c = 1) {} + } + ", + " + class Foo { + constructor(a: number, b = 1, c?: number) {} + } + ", + " + class Foo { + constructor( + public a: number, + protected b: number, + private c: number, + ) {} + } + ", + " + class Foo { + constructor( + public a: number, + protected b?: number, + private c = 10, + ) {} + } + ", + " + class Foo { + constructor( + public a: number, + protected b = 10, + private c?: number, + ) {} + } + ", + " + class Foo { + constructor( + a: number, + protected b?: number, + private c = 0, + ) {} + } + ", + " + class Foo { + constructor( + a: number, + b?: number, + private c = 0, + ) {} + } + ", + " + class Foo { + constructor( + a: number, + private b?: number, + c = 0, + ) {} + } + ", ]; let fail = vec![ @@ -96,6 +200,57 @@ fn test() { "const f = ({ a, b } = { a: 1, b: 2 }, c) => {}", "const f = ([a] = [], b) => {}", "const f = ([a, b] = [1, 2], c) => {}", + "function foo(a = 1, b: number) {}", + "function foo(a = 1, b = 2, c: number) {}", + "function foo(a = 1, b: number, c = 2, d: number) {}", + "function foo(a = 1, b: number, c = 2) {}", + "function foo(a = 1, b: number, ...c) {}", + "function foo(a?: number, b: number) {}", + "function foo(a: number, b?: number, c: number) {}", + "function foo(a = 1, b?: number, c: number) {}", + "function foo(a = 1, { b }) {}", + "function foo({ a } = {}, b) {}", + "function foo({ a, b } = { a: 1, b: 2 }, c) {}", + "const foo = function (a = 1, b: number) {};", + "const foo = function (a = 1, b = 2, c: number) {};", + "const foo = function (a = 1, b: number, c = 2, d: number) {};", + "const foo = function (a = 1, b: number, c = 2) {};", + "const foo = function (a = 1, b: number, ...c) {};", + "const foo = function (a?: number, b: number) {};", + "const foo = function (a: number, b?: number, c: number) {};", + "const foo = function (a = 1, b?: number, c: number) {};", + "const foo = function (a = 1, { b }) {};", + "const foo = function ({ a } = {}, b) {};", + "const foo = function ({ a, b } = { a: 1, b: 2 }, c) {};", + "const foo = (a = 1, b: number) => {};", + "const foo = (a = 1, b = 2, c: number) => {};", + "const foo = (a = 1, b: number, c = 2, d: number) => {};", + "const foo = (a = 1, b: number, c = 2) => {};", + "const foo = (a = 1, b: number, ...c) => {};", + "const foo = (a?: number, b: number) => {};", + "const foo = (a: number, b?: number, c: number) => {};", + "const foo = (a = 1, b?: number, c: number) => {};", + " + class Foo { + constructor( + public a?: number, + private b: number, + ) {} + } + ", + "class Foo { + constructor(a = 0, b: number) {} + }", + "class Foo { + constructor(a?: number, b: number) {} + } + ", + "class Foo { + constructor( + public a = 0, + private b: number, + ) {} + }", ]; Tester::new(DefaultParamLast::NAME, DefaultParamLast::PLUGIN, pass, fail).test_and_snapshot(); diff --git a/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap b/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap index c0cd80f8183dd..4b1530be33c51 100644 --- a/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap +++ b/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap @@ -92,3 +92,312 @@ snapshot_kind: text · ─────────────── ╰──── help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:21] + 1 │ function foo(a = 1, b = 2, c: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b = 2, c: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:32] + 1 │ function foo(a = 1, b: number, c = 2, d: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b: number, c = 2, d: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b: number, c = 2) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b: number, ...c) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a?: number, b: number) {} + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:25] + 1 │ function foo(a: number, b?: number, c: number) {} + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:21] + 1 │ function foo(a = 1, b?: number, c: number) {} + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, b?: number, c: number) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo(a = 1, { b }) {} + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo({ a } = {}, b) {} + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ function foo({ 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:23] + 1 │ const foo = function (a = 1, b: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:30] + 1 │ const foo = function (a = 1, b = 2, c: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, b = 2, c: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:41] + 1 │ const foo = function (a = 1, b: number, c = 2, d: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, b: number, c = 2, d: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, b: number, c = 2) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, b: number, ...c) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a?: number, b: number) {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:34] + 1 │ const foo = function (a: number, b?: number, c: number) {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:30] + 1 │ const foo = function (a = 1, b?: number, c: number) {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, b?: number, c: number) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function (a = 1, { b }) {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function ({ a } = {}, b) {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:23] + 1 │ const foo = function ({ 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:14] + 1 │ const foo = (a = 1, b: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:21] + 1 │ const foo = (a = 1, b = 2, c: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a = 1, b = 2, c: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:32] + 1 │ const foo = (a = 1, b: number, c = 2, d: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a = 1, b: number, c = 2, d: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a = 1, b: number, c = 2) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a = 1, b: number, ...c) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a?: number, b: number) => {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:25] + 1 │ const foo = (a: number, b?: number, c: number) => {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:21] + 1 │ const foo = (a = 1, b?: number, c: number) => {}; + · ────────── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:1:14] + 1 │ const foo = (a = 1, b?: number, c: number) => {}; + · ───── + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:4:5] + 3 │ constructor( + 4 │ public a?: number, + · ───────────────── + 5 │ private b: number, + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:2:21] + 1 │ class Foo { + 2 │ constructor(a = 0, b: number) {} + · ───── + 3 │ } + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:2:21] + 1 │ class Foo { + 2 │ constructor(a?: number, b: number) {} + · ────────── + 3 │ } + ╰──── + help: Enforce default parameters to be last. + + ⚠ eslint(default-param-last): Default parameters should be last + ╭─[default_param_last.tsx:3:5] + 2 │ constructor( + 3 │ public a = 0, + · ──────────── + 4 │ private b: number, + ╰──── + help: Enforce default parameters to be last. From 29dc5ffe2174b6f891f11c98403a2f1092c3052d Mon Sep 17 00:00:00 2001 From: Tapan Prakash Date: Fri, 17 Jan 2025 16:48:16 +0530 Subject: [PATCH 2/2] Fix formatting issues --- .../src/rules/eslint/default_param_last.rs | 111 ++++++++---------- .../snapshots/eslint_default_param_last.snap | 38 +++--- 2 files changed, 70 insertions(+), 79 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/default_param_last.rs b/crates/oxc_linter/src/rules/eslint/default_param_last.rs index 8673e2f9b8ac4..0262276652088 100644 --- a/crates/oxc_linter/src/rules/eslint/default_param_last.rs +++ b/crates/oxc_linter/src/rules/eslint/default_param_last.rs @@ -123,69 +123,61 @@ fn test() { constructor(a: number, b: number, c: number) {} }", " - class Foo { + class Foo { constructor(a: number, b?: number, c = 1) {} - } - ", + }", " class Foo { - constructor(a: number, b = 1, c?: number) {} - } - ", + constructor(a: number, b = 1, c?: number) {} + }", " class Foo { - constructor( - public a: number, - protected b: number, - private c: number, - ) {} - } - ", + constructor( + public a: number, + protected b: number, + private c: number, + ) {} + }", " class Foo { - constructor( - public a: number, - protected b?: number, - private c = 10, - ) {} - } - ", + constructor( + public a: number, + protected b?: number, + private c = 10, + ) {} + }", " class Foo { - constructor( - public a: number, - protected b = 10, - private c?: number, - ) {} - } - ", + constructor( + public a: number, + protected b = 10, + private c?: number, + ) {} + }", " class Foo { - constructor( - a: number, - protected b?: number, - private c = 0, - ) {} - } - ", + constructor( + a: number, + protected b?: number, + private c = 0, + ) {} + }", " class Foo { - constructor( - a: number, - b?: number, - private c = 0, - ) {} - } - ", + constructor( + a: number, + b?: number, + private c = 0, + ) {} + }", " class Foo { - constructor( - a: number, - private b?: number, - c = 0, - ) {} - } - ", + constructor( + a: number, + private b?: number, + c = 0, + ) {} + }", ]; let fail = vec![ @@ -235,21 +227,20 @@ fn test() { constructor( public a?: number, private b: number, - ) {} - } - ", - "class Foo { - constructor(a = 0, b: number) {} + ) {} + }", + " + class Foo { + constructor(a = 0, b: number) {} }", "class Foo { - constructor(a?: number, b: number) {} - } - ", + constructor(a?: number, b: number) {} + }", "class Foo { - constructor( - public a = 0, - private b: number, - ) {} + constructor( + public a = 0, + private b: number, + ) {} }", ]; diff --git a/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap b/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap index 4b1530be33c51..49f25282c6aa1 100644 --- a/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap +++ b/crates/oxc_linter/src/snapshots/eslint_default_param_last.snap @@ -1,6 +1,6 @@ --- source: crates/oxc_linter/src/tester.rs -snapshot_kind: text +assertion_line: 357 --- ⚠ eslint(default-param-last): Default parameters should be last ╭─[default_param_last.tsx:1:12] @@ -367,37 +367,37 @@ snapshot_kind: text help: Enforce default parameters to be last. ⚠ eslint(default-param-last): Default parameters should be last - ╭─[default_param_last.tsx:4:5] - 3 │ constructor( - 4 │ public a?: number, - · ───────────────── - 5 │ private b: number, + ╭─[default_param_last.tsx:4:17] + 3 │ constructor( + 4 │ public a?: number, + · ───────────────── + 5 │ private b: number, ╰──── help: Enforce default parameters to be last. ⚠ eslint(default-param-last): Default parameters should be last - ╭─[default_param_last.tsx:2:21] - 1 │ class Foo { - 2 │ constructor(a = 0, b: number) {} - · ───── - 3 │ } + ╭─[default_param_last.tsx:3:25] + 2 │ class Foo { + 3 │ constructor(a = 0, b: number) {} + · ───── + 4 │ } ╰──── help: Enforce default parameters to be last. ⚠ eslint(default-param-last): Default parameters should be last - ╭─[default_param_last.tsx:2:21] + ╭─[default_param_last.tsx:2:25] 1 │ class Foo { - 2 │ constructor(a?: number, b: number) {} - · ────────── + 2 │ constructor(a?: number, b: number) {} + · ────────── 3 │ } ╰──── help: Enforce default parameters to be last. ⚠ eslint(default-param-last): Default parameters should be last - ╭─[default_param_last.tsx:3:5] - 2 │ constructor( - 3 │ public a = 0, - · ──────────── - 4 │ private b: number, + ╭─[default_param_last.tsx:3:17] + 2 │ constructor( + 3 │ public a = 0, + · ──────────── + 4 │ private b: number, ╰──── help: Enforce default parameters to be last.