@@ -576,13 +576,117 @@ public static bool HasParent(this Ast ast, Ast parent)
576576 /// </summary>
577577 internal static ScriptExtentAdapter GetFunctionNameExtent ( this FunctionDefinitionAst ast )
578578 {
579+ ScriptExtentAdapter funcExtent = new ( ast . Extent ) ;
580+ string ? extentText = ast . Extent . Text ;
581+
582+ if ( TryGetFunctionNameOffsets ( extentText , out int nameStartOffset , out int nameEndOffset ) )
583+ {
584+ funcExtent . Start = GetPositionAtOffset ( funcExtent . Start , extentText ! , nameStartOffset ) ;
585+ funcExtent . End = GetPositionAtOffset ( funcExtent . Start , extentText ! , nameEndOffset ) ;
586+ return funcExtent ;
587+ }
588+
589+ // Fallback for unexpected input: preserve the previous behavior as closely as possible.
579590 string name = ast . Name ;
580- // FIXME: Gather dynamically from the AST and include backticks and whatnot that might be present
581591 int funcLength = "function " . Length ;
582- ScriptExtentAdapter funcExtent = new ( ast . Extent ) ;
583592 funcExtent . Start = funcExtent . Start . Delta ( 0 , funcLength ) ;
584593 funcExtent . End = funcExtent . Start . Delta ( 0 , name . Length ) ;
585594
586595 return funcExtent ;
587596 }
597+
598+ private static ScriptPosition GetPositionAtOffset (
599+ ScriptPosition basePosition ,
600+ string text ,
601+ int offset )
602+ {
603+ int lineDelta = 0 ;
604+ int columnDelta = 0 ;
605+
606+ for ( int i = 0 ; i < offset ; i ++ )
607+ {
608+ char c = text [ i ] ;
609+ if ( c == '\r ' )
610+ {
611+ if ( i + 1 < offset && text [ i + 1 ] == '\n ' )
612+ {
613+ i ++ ;
614+ }
615+
616+ lineDelta ++ ;
617+ columnDelta = 0 ;
618+ }
619+ else if ( c == '\n ' )
620+ {
621+ lineDelta ++ ;
622+ columnDelta = 0 ;
623+ }
624+ else
625+ {
626+ columnDelta ++ ;
627+ }
628+ }
629+
630+ return basePosition . Delta ( lineDelta , columnDelta ) ;
631+ }
632+
633+ private static bool TryGetFunctionNameOffsets (
634+ string ? text ,
635+ out int nameStartOffset ,
636+ out int nameEndOffset )
637+ {
638+ nameStartOffset = 0 ;
639+ nameEndOffset = 0 ;
640+
641+ if ( string . IsNullOrEmpty ( text ) )
642+ {
643+ return false ;
644+ }
645+
646+ const string functionKeyword = "function" ;
647+ int functionIndex = text . IndexOf ( functionKeyword , StringComparison . OrdinalIgnoreCase ) ;
648+ if ( functionIndex < 0 )
649+ {
650+ return false ;
651+ }
652+
653+ int index = functionIndex + functionKeyword . Length ;
654+ while ( index < text . Length && char . IsWhiteSpace ( text [ index ] ) )
655+ {
656+ index ++ ;
657+ }
658+
659+ if ( index >= text . Length )
660+ {
661+ return false ;
662+ }
663+
664+ nameStartOffset = index ;
665+
666+ while ( index < text . Length )
667+ {
668+ char current = text [ index ] ;
669+
670+ if ( current == '`' )
671+ {
672+ index ++ ;
673+ if ( index < text . Length )
674+ {
675+ index ++ ;
676+ }
677+
678+ continue ;
679+ }
680+
681+ if ( char . IsWhiteSpace ( current ) || current == '{' || current == '(' )
682+ {
683+ break ;
684+ }
685+
686+ index ++ ;
687+ }
688+
689+ nameEndOffset = index ;
690+ return nameEndOffset > nameStartOffset ;
691+ }
588692}
0 commit comments