@@ -339,6 +339,22 @@ namespace ts.textChanges {
339339 this . insertText ( sourceFile , token . getStart ( sourceFile ) , text ) ;
340340 }
341341
342+ public insertJsdocCommentBefore ( sourceFile : SourceFile , fn : FunctionDeclaration | FunctionExpression , tag : JSDocTag ) : void {
343+ const existingJsdoc = fn . jsDoc && firstOrUndefined ( fn . jsDoc ) ;
344+ if ( existingJsdoc ) {
345+ // `/** foo */` --> `/**\n * @constructor\n * foo */`
346+ const jsdocStart = existingJsdoc . getStart ( sourceFile ) ;
347+ const indent = getIndent ( sourceFile , jsdocStart ) ;
348+ const indentAsterisk = `${ this . newLineCharacter } ${ indent } *` ;
349+ this . insertNodeAt ( sourceFile , jsdocStart + "/**" . length , tag , { prefix : `${ indentAsterisk } ` , suffix : indentAsterisk } ) ;
350+ }
351+ else {
352+ const fnStart = fn . getStart ( sourceFile ) ;
353+ const indent = getIndent ( sourceFile , fnStart ) ;
354+ this . insertNodeAt ( sourceFile , fnStart , tag , { prefix : "/** " , suffix : ` */${ this . newLineCharacter } ${ indent } ` } ) ;
355+ }
356+ }
357+
342358 public replaceRangeWithText ( sourceFile : SourceFile , range : TextRange , text : string ) {
343359 this . changes . push ( { kind : ChangeKind . Text , sourceFile, range, text } ) ;
344360 }
@@ -720,6 +736,11 @@ namespace ts.textChanges {
720736 }
721737 }
722738
739+ function getIndent ( sourceFile : SourceFile , position : number ) : string {
740+ const lineStart = getStartPositionOfLine ( getLineAndCharacterOfPosition ( sourceFile , position ) . line , sourceFile ) ;
741+ return sourceFile . text . slice ( lineStart , position ) ;
742+ }
743+
723744 // find first non-whitespace position in the leading trivia of the node
724745 function startPositionToDeleteNodeInList ( sourceFile : SourceFile , node : Node ) : number {
725746 return skipTrivia ( sourceFile . text , getAdjustedStartPosition ( sourceFile , node , { } , Position . FullStart ) , /*stopAfterLineBreak*/ false , /*stopAtComments*/ true ) ;
@@ -788,21 +809,35 @@ namespace ts.textChanges {
788809 }
789810
790811 /** Note: this may mutate `nodeIn`. */
791- function getFormattedTextOfNode ( nodeIn : Node , sourceFile : SourceFile , pos : number , { indentation, prefix, delta } : InsertNodeOptions , newLineCharacter : string , formatContext : formatting . FormatContext , validate : ValidateNonFormattedText | undefined ) : string {
792- const { node, text } = getNonformattedText ( nodeIn , sourceFile , newLineCharacter ) ;
793- if ( validate ) validate ( node , text ) ;
794- const { options : formatOptions } = formatContext ;
795- const initialIndentation =
796- indentation !== undefined
797- ? indentation
798- : formatting . SmartIndenter . getIndentation ( pos , sourceFile , formatOptions , prefix === newLineCharacter || getLineStartPositionForPosition ( pos , sourceFile ) === pos ) ;
799- if ( delta === undefined ) {
800- delta = formatting . SmartIndenter . shouldIndentChildNode ( formatContext . options , nodeIn ) ? ( formatOptions . indentSize || 0 ) : 0 ;
812+ export function getFormattedTextOfNode ( nodeIn : Node , sourceFile : SourceFile , pos : number , { indentation, prefix, delta } : InsertNodeOptions , newLineCharacter : string , formatContext : formatting . FormatContext , validate : ValidateNonFormattedText | undefined ) : string {
813+ // Emitter doesn't handle JSDoc, so generate that here.
814+ if ( isJSDocTag ( nodeIn ) ) {
815+ switch ( nodeIn . kind ) {
816+ case SyntaxKind . JSDocClassTag :
817+ return "@class" ;
818+ case SyntaxKind . JSDocThisTag :
819+ const { typeExpression } = nodeIn as JSDocThisTag ;
820+ return typeExpression ? `@this {${ getNonformattedText ( typeExpression . type , sourceFile , newLineCharacter ) . text } }` : "@this" ;
821+ default :
822+ return Debug . fail ( ) ; // TODO (if this is needed)
823+ }
801824 }
825+ else {
826+ const { node, text } = getNonformattedText ( nodeIn , sourceFile , newLineCharacter ) ;
827+ if ( validate ) validate ( node , text ) ;
828+ const { options : formatOptions } = formatContext ;
829+ const initialIndentation =
830+ indentation !== undefined
831+ ? indentation
832+ : formatting . SmartIndenter . getIndentation ( pos , sourceFile , formatOptions , prefix === newLineCharacter || getLineStartPositionForPosition ( pos , sourceFile ) === pos ) ;
833+ if ( delta === undefined ) {
834+ delta = formatting . SmartIndenter . shouldIndentChildNode ( formatContext . options , nodeIn ) ? ( formatOptions . indentSize || 0 ) : 0 ;
835+ }
802836
803- const file : SourceFileLike = { text, getLineAndCharacterOfPosition ( pos ) { return getLineAndCharacterOfPosition ( this , pos ) ; } } ;
804- const changes = formatting . formatNodeGivenIndentation ( node , file , sourceFile . languageVariant , initialIndentation , delta , formatContext ) ;
805- return applyChanges ( text , changes ) ;
837+ const file : SourceFileLike = { text, getLineAndCharacterOfPosition ( pos ) { return getLineAndCharacterOfPosition ( this , pos ) ; } } ;
838+ const changes = formatting . formatNodeGivenIndentation ( node , file , sourceFile . languageVariant , initialIndentation , delta , formatContext ) ;
839+ return applyChanges ( text , changes ) ;
840+ }
806841 }
807842
808843 /** Note: output node may be mutated input node. */
@@ -1103,15 +1138,20 @@ namespace ts.textChanges {
11031138 deleteImportBinding ( changes , sourceFile , node as NamespaceImport ) ;
11041139 break ;
11051140
1141+ case SyntaxKind . SemicolonToken :
1142+ case SyntaxKind . FunctionKeyword :
1143+ deleteNode ( changes , sourceFile , node , { useNonAdjustedStartPosition : true } ) ;
1144+ break ;
1145+
11061146 default :
11071147 if ( isImportClause ( node . parent ) && node . parent . name === node ) {
11081148 deleteDefaultImport ( changes , sourceFile , node . parent ) ;
11091149 }
1110- else if ( isCallLikeExpression ( node . parent ) ) {
1150+ else if ( isCallExpression ( node . parent ) && contains ( node . parent . arguments , node ) ) {
11111151 deleteNodeInList ( changes , deletedNodesInLists , sourceFile , node ) ;
11121152 }
11131153 else {
1114- deleteNode ( changes , sourceFile , node , node . kind === SyntaxKind . SemicolonToken ? { useNonAdjustedEndPosition : true } : undefined ) ;
1154+ deleteNode ( changes , sourceFile , node ) ;
11151155 }
11161156 }
11171157 }
0 commit comments