From 41162914070ebc4ec9b2e16c9703fb2e2af687e6 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 29 Oct 2024 14:56:58 +0100 Subject: [PATCH 1/4] Add rule check for arrow functions in object --- .../src/lint/nursery/use_explicit_type.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs b/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs index dd4bda33b777..54d467047515 100644 --- a/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs +++ b/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs @@ -246,6 +246,10 @@ impl Rule for UseExplicitType { return None; } + if is_arrow_func(func) && is_function_used_in_object(func) { + return None; + } + if is_higher_order_function(func) { return None; } @@ -362,6 +366,38 @@ fn is_function_used_in_argument_or_array(func: &AnyJsFunction) -> bool { ) } +/// Check if the function is used in some object +/// +/// # Examples +/// +/// JS_OBJECT: +/// +/// interface Behavior { +/// attribute: string; +/// func: () => string; +/// arrowFunc: () => string; +/// } +/// +/// function getObjectWithFunction(): Behavior { +/// return { +/// attribute: 'value', +/// func: function myFunc(): string { return "value" }, +/// arrowFunc: () => {}, +/// } +/// } +/// +fn is_function_used_in_object(func: &AnyJsFunction) -> bool { + matches!( + func.syntax().parent().kind(), + Some(JsSyntaxKind::JS_PROPERTY_OBJECT_MEMBER) + ) +} + +/// Check if a function is an arrow function +fn is_arrow_func(func: &AnyJsFunction) -> bool { + func.as_js_arrow_function_expression().is_some() +} + /// Checks if a function is an IIFE (Immediately Invoked Function Expressions) /// /// # Examples From ea270a5fcd829bb55b35bc182e67067ab521ef5a Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 29 Oct 2024 14:57:08 +0100 Subject: [PATCH 2/4] Update valid/invalid specs --- .../specs/nursery/useExplicitType/invalid.ts | 19 +++- .../nursery/useExplicitType/invalid.ts.snap | 93 +++++++++++++++++-- .../specs/nursery/useExplicitType/valid.ts | 15 ++- .../nursery/useExplicitType/valid.ts.snap | 15 +++ 4 files changed, 129 insertions(+), 13 deletions(-) diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts index 1cb6ba5f394e..6c8743eaaf0d 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts @@ -91,5 +91,20 @@ function fn() { }; } -const x = { prop: () => {} } -const x = { bar: { prop: () => {} } } \ No newline at end of file +const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } +const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + + +// Returning object from function +interface Behavior { + attribute: string; + namedFunc: () => string; + arrowFunc: () => string; +} + +function getObjectWithFunction(): Behavior { + return { + namedFunc: function myFunc() { return "value" }, + arrowFunc: () => {}, + } +} \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap index 6f34976d42c3..2ff50883afd9 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 86 expression: invalid.ts --- # Input @@ -97,8 +98,23 @@ function fn() { }; } -const x = { prop: () => {} } -const x = { bar: { prop: () => {} } } +const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } +const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + + +// Returning object from function +interface Behavior { + attribute: string; + namedFunc: () => string; + arrowFunc: () => string; +} + +function getObjectWithFunction(): Behavior { + return { + namedFunc: function myFunc() { return "value" }, + arrowFunc: () => {}, + } +} ``` # Diagnostics @@ -532,15 +548,69 @@ invalid.ts:85:2 lint/nursery/useExplicitType ━━━━━━━━━━━ ``` ``` -invalid.ts:94:19 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:94:29 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 92 │ } + 93 │ + > 94 │ const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } + │ ^^^^^^^^^^^^^^^ + 95 │ const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + 96 │ + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:94:81 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. 92 │ } 93 │ - > 94 │ const x = { prop: () => {} } - │ ^^^^^^^^^ - 95 │ const x = { bar: { prop: () => {} } } + > 94 │ const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } + │ ^^^^^^^^^ + 95 │ const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + 96 │ + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:95:36 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 94 │ const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } + > 95 │ const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + │ ^^^^^^^^^^^^^^^ + 96 │ + + i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. + + i Add a return type annotation. + + +``` + +``` +invalid.ts:95:79 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Missing return type on function. + + 94 │ const x = { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } + > 95 │ const x = { bar: { namedFunctions: function alpha () => {}, unNamedFunctions: function () => {} } } + │ ^^^^^^^^^^^^ + 96 │ i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. @@ -550,13 +620,16 @@ invalid.ts:94:19 lint/nursery/useExplicitType ━━━━━━━━━━━ ``` ``` -invalid.ts:95:26 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.ts:107:16 lint/nursery/useExplicitType ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Missing return type on function. - 94 │ const x = { prop: () => {} } - > 95 │ const x = { bar: { prop: () => {} } } - │ ^^^^^^^^^ + 105 │ function getObjectWithFunction(): Behavior { + 106 │ return { + > 107 │ namedFunc: function myFunc() { return "value" }, + │ ^^^^^^^^^^^^^^^ + 108 │ arrowFunc: () => {}, + 109 │ } i Declaring the return type makes the code self-documenting and can speed up TypeScript type checking. diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts index 41f4283c04c6..dc49ee64fbde 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts @@ -102,4 +102,17 @@ class Accumulator { this.count += fn(); } } -new Accumulator().accumulate(() => 1); \ No newline at end of file +new Accumulator().accumulate(() => 1); + +// Returning object from function +interface Behavior { + namedFunc: () => string; + arrowFunc: () => string; +} + +function getObjectWithFunction(): Behavior { + return { + namedFunc: function myFunc(): string { return "value" }, + arrowFunc: () => {}, + } +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts.snap index 45a4d83905d7..e145cc18edbc 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/valid.ts.snap @@ -1,5 +1,6 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs +assertion_line: 86 expression: valid.ts --- # Input @@ -109,4 +110,18 @@ class Accumulator { } } new Accumulator().accumulate(() => 1); + +// Returning object from function +interface Behavior { + namedFunc: () => string; + arrowFunc: () => string; +} + +function getObjectWithFunction(): Behavior { + return { + namedFunc: function myFunc(): string { return "value" }, + arrowFunc: () => {}, + } +} + ``` From dc0c38b2b2bb2fe3673585e35098956e99cd03e2 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 29 Oct 2024 14:58:57 +0100 Subject: [PATCH 3/4] Add empty line --- .../tests/specs/nursery/useExplicitType/invalid.ts | 2 +- .../tests/specs/nursery/useExplicitType/invalid.ts.snap | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts index 6c8743eaaf0d..42887f442195 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts @@ -107,4 +107,4 @@ function getObjectWithFunction(): Behavior { namedFunc: function myFunc() { return "value" }, arrowFunc: () => {}, } -} \ No newline at end of file +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap index 2ff50883afd9..c81b2709cd5a 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/useExplicitType/invalid.ts.snap @@ -115,6 +115,7 @@ function getObjectWithFunction(): Behavior { arrowFunc: () => {}, } } + ``` # Diagnostics From 4de55aae0731f42c8a88df5471a185d661e99872 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 29 Oct 2024 16:07:44 +0100 Subject: [PATCH 4/4] Fix formatting --- .../src/lint/nursery/use_explicit_type.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs b/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs index 54d467047515..94d29142c5b0 100644 --- a/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs +++ b/crates/biome_js_analyze/src/lint/nursery/use_explicit_type.rs @@ -367,25 +367,25 @@ fn is_function_used_in_argument_or_array(func: &AnyJsFunction) -> bool { } /// Check if the function is used in some object -/// +/// /// # Examples -/// -/// JS_OBJECT: -/// +/// +/// JS_OBJECT: +/// /// interface Behavior { -/// attribute: string; -/// func: () => string; +/// attribute: string; +/// func: () => string; /// arrowFunc: () => string; /// } -/// +/// /// function getObjectWithFunction(): Behavior { /// return { -/// attribute: 'value', +/// attribute: 'value', /// func: function myFunc(): string { return "value" }, /// arrowFunc: () => {}, /// } /// } -/// +/// fn is_function_used_in_object(func: &AnyJsFunction) -> bool { matches!( func.syntax().parent().kind(),