@@ -45,6 +45,10 @@ namespace ts.BreakpointResolver {
4545 return createTextSpanFromBounds ( start , ( endNode || startNode ) . getEnd ( ) ) ;
4646 }
4747
48+ function textSpanEndingAtNextToken ( startNode : Node , previousTokenToFindNextEndToken : Node ) : TextSpan {
49+ return textSpan ( startNode , findNextToken ( previousTokenToFindNextEndToken , previousTokenToFindNextEndToken . parent ) ) ;
50+ }
51+
4852 function spanInNodeIfStartsOnSameLine ( node : Node , otherwiseOnNode ?: Node ) : TextSpan {
4953 if ( node && lineOfPosition === sourceFile . getLineAndCharacterOfPosition ( node . getStart ( sourceFile ) ) . line ) {
5054 return spanInNode ( node ) ;
@@ -67,29 +71,33 @@ namespace ts.BreakpointResolver {
6771 function spanInNode ( node : Node ) : TextSpan {
6872 if ( node ) {
6973 if ( isExpression ( node ) ) {
70- if ( node . parent . kind === SyntaxKind . DoStatement ) {
71- // Set span as if on while keyword
72- return spanInPreviousNode ( node ) ;
73- }
74+ switch ( node . parent . kind ) {
75+ case SyntaxKind . DoStatement :
76+ // Set span as if on while keyword
77+ return spanInPreviousNode ( node ) ;
7478
75- if ( node . parent . kind === SyntaxKind . Decorator ) {
76- // Set breakpoint on the decorator emit
77- return spanInNode ( node . parent ) ;
78- }
79+ case SyntaxKind . Decorator :
80+ // Set breakpoint on the decorator emit
81+ return spanInNode ( node . parent ) ;
7982
80- if ( node . parent . kind === SyntaxKind . ForStatement ) {
81- // For now lets set the span on this expression, fix it later
82- return textSpan ( node ) ;
83- }
83+ case SyntaxKind . ForStatement :
84+ case SyntaxKind . ForOfStatement :
85+ // For now lets set the span on this expression, fix it later
86+ return textSpan ( node ) ;
8487
85- if ( node . parent . kind === SyntaxKind . BinaryExpression && ( < BinaryExpression > node . parent ) . operatorToken . kind === SyntaxKind . CommaToken ) {
86- // if this is comma expression, the breakpoint is possible in this expression
87- return textSpan ( node ) ;
88- }
88+ case SyntaxKind . BinaryExpression :
89+ if ( ( < BinaryExpression > node . parent ) . operatorToken . kind === SyntaxKind . CommaToken ) {
90+ // if this is comma expression, the breakpoint is possible in this expression
91+ return textSpan ( node ) ;
92+ }
93+ break ;
8994
90- if ( node . parent . kind === SyntaxKind . ArrowFunction && ( < FunctionLikeDeclaration > node . parent ) . body === node ) {
91- // If this is body of arrow function, it is allowed to have the breakpoint
92- return textSpan ( node ) ;
95+ case SyntaxKind . ArrowFunction :
96+ if ( ( < FunctionLikeDeclaration > node . parent ) . body === node ) {
97+ // If this is body of arrow function, it is allowed to have the breakpoint
98+ return textSpan ( node ) ;
99+ }
100+ break ;
93101 }
94102 }
95103
@@ -137,7 +145,7 @@ namespace ts.BreakpointResolver {
137145
138146 case SyntaxKind . WhileStatement :
139147 // Span on while(...)
140- return textSpan ( node , findNextToken ( ( < WhileStatement > node ) . expression , node ) ) ;
148+ return textSpanEndingAtNextToken ( node , ( < WhileStatement > node ) . expression ) ;
141149
142150 case SyntaxKind . DoStatement :
143151 // span in statement of the do statement
@@ -149,7 +157,7 @@ namespace ts.BreakpointResolver {
149157
150158 case SyntaxKind . IfStatement :
151159 // set on if(..) span
152- return textSpan ( node , findNextToken ( ( < IfStatement > node ) . expression , node ) ) ;
160+ return textSpanEndingAtNextToken ( node , ( < IfStatement > node ) . expression ) ;
153161
154162 case SyntaxKind . LabeledStatement :
155163 // span in statement
@@ -164,13 +172,16 @@ namespace ts.BreakpointResolver {
164172 return spanInForStatement ( < ForStatement > node ) ;
165173
166174 case SyntaxKind . ForInStatement :
175+ // span of for (a in ...)
176+ return textSpanEndingAtNextToken ( node , ( < ForInStatement > node ) . expression ) ;
177+
167178 case SyntaxKind . ForOfStatement :
168- // span on for (a in ...)
169- return textSpan ( node , findNextToken ( ( < ForInStatement | ForOfStatement > node ) . expression , node ) ) ;
179+ // span in initializer
180+ return spanInInitializerOfForLike ( < ForOfStatement | ForInStatement > node ) ;
170181
171182 case SyntaxKind . SwitchStatement :
172183 // span on switch(...)
173- return textSpan ( node , findNextToken ( ( < SwitchStatement > node ) . expression , node ) ) ;
184+ return textSpanEndingAtNextToken ( node , ( < SwitchStatement > node ) . expression ) ;
174185
175186 case SyntaxKind . CaseClause :
176187 case SyntaxKind . DefaultClause :
@@ -271,6 +282,9 @@ namespace ts.BreakpointResolver {
271282 case SyntaxKind . FinallyKeyword :
272283 return spanInNextNode ( node ) ;
273284
285+ case SyntaxKind . OfKeyword :
286+ return spanInOfKeyword ( node ) ;
287+
274288 default :
275289 // If this is name of property assignment, set breakpoint in the initializer
276290 if ( node . parent . kind === SyntaxKind . PropertyAssignment && ( < PropertyDeclaration > node . parent ) . name === node ) {
@@ -317,18 +331,20 @@ namespace ts.BreakpointResolver {
317331
318332 function spanInVariableDeclaration ( variableDeclaration : VariableDeclaration ) : TextSpan {
319333 // If declaration of for in statement, just set the span in parent
320- if ( variableDeclaration . parent . parent . kind === SyntaxKind . ForInStatement ||
321- variableDeclaration . parent . parent . kind === SyntaxKind . ForOfStatement ) {
334+ if ( variableDeclaration . parent . parent . kind === SyntaxKind . ForInStatement ) {
322335 return spanInNode ( variableDeclaration . parent . parent ) ;
323336 }
324-
337+
325338 // If this is a destructuring pattern set breakpoint in binding pattern
326339 if ( isBindingPattern ( variableDeclaration . name ) ) {
327340 return spanInBindingPattern ( < BindingPattern > variableDeclaration . name ) ;
328341 }
329342
330343 // Breakpoint is possible in variableDeclaration only if there is initialization
331- if ( variableDeclaration . initializer || ( variableDeclaration . flags & NodeFlags . Export ) ) {
344+ // or its declaration from 'for of'
345+ if ( variableDeclaration . initializer ||
346+ ( variableDeclaration . flags & NodeFlags . Export ) ||
347+ variableDeclaration . parent . parent . kind === SyntaxKind . ForOfStatement ) {
332348 return textSpanFromVariableDeclaration ( variableDeclaration ) ;
333349 }
334350
@@ -410,29 +426,35 @@ namespace ts.BreakpointResolver {
410426 case SyntaxKind . WhileStatement :
411427 case SyntaxKind . IfStatement :
412428 case SyntaxKind . ForInStatement :
413- case SyntaxKind . ForOfStatement :
414429 return spanInNodeIfStartsOnSameLine ( block . parent , block . statements [ 0 ] ) ;
415430
416431 // Set span on previous token if it starts on same line otherwise on the first statement of the block
417432 case SyntaxKind . ForStatement :
433+ case SyntaxKind . ForOfStatement :
418434 return spanInNodeIfStartsOnSameLine ( findPrecedingToken ( block . pos , sourceFile , block . parent ) , block . statements [ 0 ] ) ;
419435 }
420436
421437 // Default action is to set on first statement
422438 return spanInNode ( block . statements [ 0 ] ) ;
423439 }
424440
441+ function spanInInitializerOfForLike ( forLikeStaement : ForStatement | ForOfStatement | ForInStatement ) : TextSpan {
442+ if ( forLikeStaement . initializer . kind === SyntaxKind . VariableDeclarationList ) {
443+ // declaration list, set breakpoint in first declaration
444+ let variableDeclarationList = < VariableDeclarationList > forLikeStaement . initializer ;
445+ if ( variableDeclarationList . declarations . length > 0 ) {
446+ return spanInNode ( variableDeclarationList . declarations [ 0 ] ) ;
447+ }
448+ }
449+ else {
450+ // Expression - set breakpoint in it
451+ return spanInNode ( forLikeStaement . initializer ) ;
452+ }
453+ }
454+
425455 function spanInForStatement ( forStatement : ForStatement ) : TextSpan {
426456 if ( forStatement . initializer ) {
427- if ( forStatement . initializer . kind === SyntaxKind . VariableDeclarationList ) {
428- let variableDeclarationList = < VariableDeclarationList > forStatement . initializer ;
429- if ( variableDeclarationList . declarations . length > 0 ) {
430- return spanInNode ( variableDeclarationList . declarations [ 0 ] ) ;
431- }
432- }
433- else {
434- return spanInNode ( forStatement . initializer ) ;
435- }
457+ return spanInInitializerOfForLike ( forStatement ) ;
436458 }
437459
438460 if ( forStatement . condition ) {
@@ -560,6 +582,7 @@ namespace ts.BreakpointResolver {
560582 case SyntaxKind . WhileStatement :
561583 case SyntaxKind . DoStatement :
562584 case SyntaxKind . ForStatement :
585+ case SyntaxKind . ForOfStatement :
563586 return spanInPreviousNode ( node ) ;
564587
565588 // Default to parent node
@@ -590,7 +613,17 @@ namespace ts.BreakpointResolver {
590613 function spanInWhileKeyword ( node : Node ) : TextSpan {
591614 if ( node . parent . kind === SyntaxKind . DoStatement ) {
592615 // Set span on while expression
593- return textSpan ( node , findNextToken ( ( < DoStatement > node . parent ) . expression , node . parent ) ) ;
616+ return textSpanEndingAtNextToken ( node , ( < DoStatement > node . parent ) . expression ) ;
617+ }
618+
619+ // Default to parent node
620+ return spanInNode ( node . parent ) ;
621+ }
622+
623+ function spanInOfKeyword ( node : Node ) : TextSpan {
624+ if ( node . parent . kind === SyntaxKind . ForOfStatement ) {
625+ // set using next token
626+ return spanInNextNode ( node ) ;
594627 }
595628
596629 // Default to parent node
0 commit comments