@@ -251,25 +251,25 @@ export default defineConfig(
251251 //#endregion
252252
253253 {
254- name : ' custom' ,
254+ name : " custom" ,
255255 plugins : {
256256 custom : {
257257 rules : {
258- ' no-arrow-parameter-types' : {
258+ " no-arrow-parameter-types" : {
259259 meta : {
260- fixable : ' code' ,
260+ fixable : " code" ,
261261 hasSuggestions : true ,
262- type : ' suggestion' ,
263- dialects : [ ' typescript' ] ,
262+ type : " suggestion" ,
263+ dialects : [ " typescript" ] ,
264264 schema : [
265265 {
266- type : ' object' ,
266+ type : " object" ,
267267 properties : {
268268 allowOptional : {
269- type : ' boolean' ,
269+ type : " boolean" ,
270270 default : false ,
271271 description :
272- ' Allow type annotations when the parameter is optional. Sometimes useful for overloaded functions.' ,
272+ " Allow type annotations when the parameter is optional. Sometimes useful for overloaded functions." ,
273273 } ,
274274 } ,
275275 } ,
@@ -288,12 +288,12 @@ export default defineConfig(
288288 const paramsWithTypeAnnotation = node . params . filter (
289289 (
290290 // @ts -expect-error: will be inferred when moved into an official plugin
291- param
292- ) => param . typeAnnotation !== undefined
291+ param ,
292+ ) => param . typeAnnotation !== undefined ,
293293 ) ;
294294
295295 const isCatchClause =
296- node . parent . callee ?. property ?. name === ' catch' ;
296+ node . parent . callee ?. property ?. name === " catch" ;
297297
298298 if ( paramsWithTypeAnnotation . length > 0 && ! isCatchClause ) {
299299 for ( const param of paramsWithTypeAnnotation ) {
@@ -304,51 +304,116 @@ export default defineConfig(
304304 context . report ( {
305305 node : param ,
306306 message :
307- ' Arrow function parameters should not have type annotations. Instead the Object where the operation is used should be typed correctly.' ,
307+ " Arrow function parameters should not have type annotations. Instead the Object where the operation is used should be typed correctly." ,
308308 fix ( fixer ) {
309309 if ( param . optional ) {
310310 return null ;
311311 }
312312
313- // TODO @Shinigami 92 2025-06-16: Handle async arrow functions
314- if ( node . parent . type === 'VariableDeclarator' ) {
315- const variableDeclaratorNode = node . parent ;
313+ if (
314+ node . parent . type === "VariableDeclarator" &&
315+ ! node . parent . id . typeAnnotation
316+ ) {
317+ const variableDeclarationNode = node . parent ;
316318
317- return [
318- // Remove ` =>`
319+ const isAsyncFunction : boolean = node . async ;
320+
321+ const isBodyBlockStatement =
322+ node . body . type === "BlockStatement" ;
323+
324+ const isBodyJSXElement =
325+ node . body . type === "JSXElement" ;
326+
327+ const hasReturnType = node . returnType !== undefined ;
328+
329+ const lastParam = node . params . at ( - 1 ) ;
330+
331+ const paramIdDifferentLine =
332+ lastParam . loc . start . line !==
333+ variableDeclarationNode . id . loc . end . line ;
334+
335+ const paramBlockDifferentLine =
336+ lastParam . loc . end . line !==
337+ node . body . loc . start . line ;
338+
339+ const behindClosingParenthesis = hasReturnType
340+ ? ( node . returnType . range [ 1 ] as number )
341+ : ( lastParam . range [ 1 ] as number ) + ")" . length ;
342+
343+ const fixes = [
344+ // Removes `=> `
319345 fixer . replaceTextRange (
320- [ node . body . range [ 0 ] - 3 , node . body . range [ 0 ] ] ,
321- ''
346+ [
347+ behindClosingParenthesis ,
348+ node . body . range [ 0 ] as number ,
349+ ] ,
350+ ! hasReturnType &&
351+ paramBlockDifferentLine &&
352+ paramIdDifferentLine
353+ ? ")"
354+ : "" ,
322355 ) ,
323- // Remove ` = `
356+ // Removes ` = ` or ` = async `
324357 fixer . replaceTextRange (
325358 [
326- variableDeclaratorNode . id . range [ 1 ] ,
327- variableDeclaratorNode . init . range [ 0 ] ,
359+ variableDeclarationNode . id . range [ 1 ] as number ,
360+ ( variableDeclarationNode . init
361+ . range [ 0 ] as number ) +
362+ ( isAsyncFunction ? "async " . length : 0 ) ,
328363 ] ,
329- ''
364+ "" ,
330365 ) ,
331- // Replace `const ` with `function `
366+ // Replaces `const ` with `function ` or `async function `
332367 fixer . replaceTextRange (
333368 [
334- variableDeclaratorNode . parent . range [ 0 ] ,
335- variableDeclaratorNode . range [ 0 ] ,
369+ variableDeclarationNode . parent
370+ . range [ 0 ] as number ,
371+ variableDeclarationNode . range [ 0 ] as number ,
336372 ] ,
337- 'function '
373+ isAsyncFunction
374+ ? "async function "
375+ : "function " ,
338376 ) ,
339377 ] ;
378+
379+ // If the body is not a BlockStatement, we need to wrap it in curly braces
380+ if ( ! isBodyBlockStatement ) {
381+ fixes . push (
382+ fixer . insertTextBefore (
383+ node . body ,
384+ `{return ${ isBodyJSXElement ? "(" : "" } ` ,
385+ ) ,
386+ fixer . insertTextAfter (
387+ node . body ,
388+ `${ isBodyJSXElement ? ")" : "" } }` ,
389+ ) ,
390+ ) ;
391+
392+ if ( isBodyJSXElement ) {
393+ fixes . push (
394+ fixer . removeRange ( [
395+ node . body . range [ 1 ] as number ,
396+ node . range [ 1 ] as number ,
397+ ] ) ,
398+ ) ;
399+ }
400+ }
401+
402+ return fixes ;
340403 }
341404
342- return fixer . removeRange ( param . typeAnnotation . range ) ;
405+ return fixer . removeRange (
406+ param . typeAnnotation . range as [ number , number ] ,
407+ ) ;
343408 } ,
344409 suggest : [
345410 {
346- desc : ' Remove type annotation' ,
411+ desc : " Remove type annotation" ,
347412 fix ( fixer ) {
348413 if ( param . optional ) {
349414 return fixer . removeRange ( [
350- param . typeAnnotation . range [ 0 ] - 1 , // Remove the `?` before the type annotation
351- param . typeAnnotation . range [ 1 ] ,
415+ ( param . typeAnnotation . range [ 0 ] as number ) - 1 , // Remove the `?` before the type annotation
416+ param . typeAnnotation . range [ 1 ] as number ,
352417 ] ) ;
353418 }
354419
@@ -367,7 +432,7 @@ export default defineConfig(
367432 } ,
368433 } ,
369434 rules : {
370- ' custom/no-arrow-parameter-types' : [ ' error' , { allowOptional : true } ] ,
435+ " custom/no-arrow-parameter-types" : [ " error" , { allowOptional : true } ] ,
371436 } ,
372- }
437+ } ,
373438) ;
0 commit comments