@@ -270,25 +270,25 @@ export default defineConfig(
270270 //#endregion
271271
272272 {
273- name : ' custom' ,
273+ name : " custom" ,
274274 plugins : {
275275 custom : {
276276 rules : {
277- ' no-arrow-parameter-types' : {
277+ " no-arrow-parameter-types" : {
278278 meta : {
279- fixable : ' code' ,
279+ fixable : " code" ,
280280 hasSuggestions : true ,
281- type : ' suggestion' ,
282- dialects : [ ' typescript' ] ,
281+ type : " suggestion" ,
282+ dialects : [ " typescript" ] ,
283283 schema : [
284284 {
285- type : ' object' ,
285+ type : " object" ,
286286 properties : {
287287 allowOptional : {
288- type : ' boolean' ,
288+ type : " boolean" ,
289289 default : false ,
290290 description :
291- ' Allow type annotations when the parameter is optional. Sometimes useful for overloaded functions.' ,
291+ " Allow type annotations when the parameter is optional. Sometimes useful for overloaded functions." ,
292292 } ,
293293 } ,
294294 } ,
@@ -307,12 +307,12 @@ export default defineConfig(
307307 const paramsWithTypeAnnotation = node . params . filter (
308308 (
309309 // @ts -expect-error: will be inferred when moved into an official plugin
310- param
311- ) => param . typeAnnotation !== undefined
310+ param ,
311+ ) => param . typeAnnotation !== undefined ,
312312 ) ;
313313
314314 const isCatchClause =
315- node . parent . callee ?. property ?. name === ' catch' ;
315+ node . parent . callee ?. property ?. name === " catch" ;
316316
317317 if ( paramsWithTypeAnnotation . length > 0 && ! isCatchClause ) {
318318 for ( const param of paramsWithTypeAnnotation ) {
@@ -323,51 +323,116 @@ export default defineConfig(
323323 context . report ( {
324324 node : param ,
325325 message :
326- ' Arrow function parameters should not have type annotations. Instead the Object where the operation is used should be typed correctly.' ,
326+ " Arrow function parameters should not have type annotations. Instead the Object where the operation is used should be typed correctly." ,
327327 fix ( fixer ) {
328328 if ( param . optional ) {
329329 return null ;
330330 }
331331
332- // TODO @Shinigami 92 2025-06-16: Handle async arrow functions
333- if ( node . parent . type === 'VariableDeclarator' ) {
334- const variableDeclaratorNode = node . parent ;
332+ if (
333+ node . parent . type === "VariableDeclarator" &&
334+ ! node . parent . id . typeAnnotation
335+ ) {
336+ const variableDeclarationNode = node . parent ;
335337
336- return [
337- // Remove ` =>`
338+ const isAsyncFunction : boolean = node . async ;
339+
340+ const isBodyBlockStatement =
341+ node . body . type === "BlockStatement" ;
342+
343+ const isBodyJSXElement =
344+ node . body . type === "JSXElement" ;
345+
346+ const hasReturnType = node . returnType !== undefined ;
347+
348+ const lastParam = node . params . at ( - 1 ) ;
349+
350+ const paramIdDifferentLine =
351+ lastParam . loc . start . line !==
352+ variableDeclarationNode . id . loc . end . line ;
353+
354+ const paramBlockDifferentLine =
355+ lastParam . loc . end . line !==
356+ node . body . loc . start . line ;
357+
358+ const behindClosingParenthesis = hasReturnType
359+ ? ( node . returnType . range [ 1 ] as number )
360+ : ( lastParam . range [ 1 ] as number ) + ")" . length ;
361+
362+ const fixes = [
363+ // Removes `=> `
338364 fixer . replaceTextRange (
339- [ node . body . range [ 0 ] - 3 , node . body . range [ 0 ] ] ,
340- ''
365+ [
366+ behindClosingParenthesis ,
367+ node . body . range [ 0 ] as number ,
368+ ] ,
369+ ! hasReturnType &&
370+ paramBlockDifferentLine &&
371+ paramIdDifferentLine
372+ ? ")"
373+ : "" ,
341374 ) ,
342- // Remove ` = `
375+ // Removes ` = ` or ` = async `
343376 fixer . replaceTextRange (
344377 [
345- variableDeclaratorNode . id . range [ 1 ] ,
346- variableDeclaratorNode . init . range [ 0 ] ,
378+ variableDeclarationNode . id . range [ 1 ] as number ,
379+ ( variableDeclarationNode . init
380+ . range [ 0 ] as number ) +
381+ ( isAsyncFunction ? "async " . length : 0 ) ,
347382 ] ,
348- ''
383+ "" ,
349384 ) ,
350- // Replace `const ` with `function `
385+ // Replaces `const ` with `function ` or `async function `
351386 fixer . replaceTextRange (
352387 [
353- variableDeclaratorNode . parent . range [ 0 ] ,
354- variableDeclaratorNode . range [ 0 ] ,
388+ variableDeclarationNode . parent
389+ . range [ 0 ] as number ,
390+ variableDeclarationNode . range [ 0 ] as number ,
355391 ] ,
356- 'function '
392+ isAsyncFunction
393+ ? "async function "
394+ : "function " ,
357395 ) ,
358396 ] ;
397+
398+ // If the body is not a BlockStatement, we need to wrap it in curly braces
399+ if ( ! isBodyBlockStatement ) {
400+ fixes . push (
401+ fixer . insertTextBefore (
402+ node . body ,
403+ `{return ${ isBodyJSXElement ? "(" : "" } ` ,
404+ ) ,
405+ fixer . insertTextAfter (
406+ node . body ,
407+ `${ isBodyJSXElement ? ")" : "" } }` ,
408+ ) ,
409+ ) ;
410+
411+ if ( isBodyJSXElement ) {
412+ fixes . push (
413+ fixer . removeRange ( [
414+ node . body . range [ 1 ] as number ,
415+ node . range [ 1 ] as number ,
416+ ] ) ,
417+ ) ;
418+ }
419+ }
420+
421+ return fixes ;
359422 }
360423
361- return fixer . removeRange ( param . typeAnnotation . range ) ;
424+ return fixer . removeRange (
425+ param . typeAnnotation . range as [ number , number ] ,
426+ ) ;
362427 } ,
363428 suggest : [
364429 {
365- desc : ' Remove type annotation' ,
430+ desc : " Remove type annotation" ,
366431 fix ( fixer ) {
367432 if ( param . optional ) {
368433 return fixer . removeRange ( [
369- param . typeAnnotation . range [ 0 ] - 1 , // Remove the `?` before the type annotation
370- param . typeAnnotation . range [ 1 ] ,
434+ ( param . typeAnnotation . range [ 0 ] as number ) - 1 , // Remove the `?` before the type annotation
435+ param . typeAnnotation . range [ 1 ] as number ,
371436 ] ) ;
372437 }
373438
@@ -386,7 +451,7 @@ export default defineConfig(
386451 } ,
387452 } ,
388453 rules : {
389- ' custom/no-arrow-parameter-types' : [ ' error' , { allowOptional : true } ] ,
454+ " custom/no-arrow-parameter-types" : [ " error" , { allowOptional : true } ] ,
390455 } ,
391- }
456+ } ,
392457) ;
0 commit comments