Skip to content

Commit c25bfe5

Browse files
committed
Support for breakpoint spans in object binding pattern
1 parent 00e253a commit c25bfe5

6 files changed

Lines changed: 308 additions & 223 deletions

src/services/breakpoints.ts

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ namespace ts.BreakpointResolver {
212212
case SyntaxKind.EnumMember:
213213
case SyntaxKind.CallExpression:
214214
case SyntaxKind.NewExpression:
215+
case SyntaxKind.BindingElement:
215216
// span on complete node
216217
return textSpan(node);
217218

@@ -222,6 +223,10 @@ namespace ts.BreakpointResolver {
222223
case SyntaxKind.Decorator:
223224
return spanInNodeArray(node.parent.decorators);
224225

226+
case SyntaxKind.ObjectBindingPattern:
227+
case SyntaxKind.ArrayBindingPattern:
228+
return spanInBindingPattern(<BindingPattern>node);
229+
225230
// No breakpoint in interface, type alias
226231
case SyntaxKind.InterfaceDeclaration:
227232
case SyntaxKind.TypeAliasDeclaration:
@@ -279,48 +284,54 @@ namespace ts.BreakpointResolver {
279284
return spanInPreviousNode(node);
280285
}
281286

287+
// initializer of variable declaration go to previous node
288+
if (node.parent.kind === SyntaxKind.VariableDeclaration &&
289+
((<VariableDeclaration>node.parent).initializer === node ||
290+
isAssignmentOperator(node.kind))) {
291+
return spanInPreviousNode(node);
292+
}
293+
282294
// Default go to parent to set the breakpoint
283295
return spanInNode(node.parent);
284296
}
285297
}
286298

299+
function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
300+
let declarations = variableDeclaration.parent.declarations;
301+
if (declarations && declarations[0] === variableDeclaration) {
302+
// First declaration - include let keyword
303+
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
304+
}
305+
else {
306+
// Span only on this declaration
307+
return textSpan(variableDeclaration);
308+
}
309+
}
310+
287311
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
288312
// If declaration of for in statement, just set the span in parent
289313
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement ||
290314
variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
291315
return spanInNode(variableDeclaration.parent.parent);
292316
}
293317

294-
let isParentVariableStatement = variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement;
295-
let isDeclarationOfForStatement = variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement && contains((<VariableDeclarationList>(<ForStatement>variableDeclaration.parent.parent).initializer).declarations, variableDeclaration);
296-
let declarations = isParentVariableStatement
297-
? (<VariableStatement>variableDeclaration.parent.parent).declarationList.declarations
298-
: isDeclarationOfForStatement
299-
? (<VariableDeclarationList>(<ForStatement>variableDeclaration.parent.parent).initializer).declarations
300-
: undefined;
318+
// If this is a destructuring pattern set breakpoint in binding pattern
319+
if (isBindingPattern(variableDeclaration.name)) {
320+
return spanInBindingPattern(<BindingPattern>variableDeclaration.name);
321+
}
301322

302323
// Breakpoint is possible in variableDeclaration only if there is initialization
303324
if (variableDeclaration.initializer || (variableDeclaration.flags & NodeFlags.Export)) {
304-
if (declarations && declarations[0] === variableDeclaration) {
305-
if (isParentVariableStatement) {
306-
// First declaration - include let keyword
307-
return textSpan(variableDeclaration.parent, variableDeclaration);
308-
}
309-
else {
310-
Debug.assert(isDeclarationOfForStatement);
311-
// Include let keyword from for statement declarations in the span
312-
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
313-
}
314-
}
315-
else {
316-
// Span only on this declaration
317-
return textSpan(variableDeclaration);
318-
}
325+
return textSpanFromVariableDeclaration(variableDeclaration);
319326
}
320-
else if (declarations && declarations[0] !== variableDeclaration) {
327+
328+
let declarations = variableDeclaration.parent.declarations;
329+
if (declarations && declarations[0] !== variableDeclaration) {
321330
// If we cant set breakpoint on this declaration, set it on previous one
322-
let indexOfCurrentDeclaration = indexOf(declarations, variableDeclaration);
323-
return spanInVariableDeclaration(declarations[indexOfCurrentDeclaration - 1]);
331+
// Because the variable declaration may be binding pattern and
332+
// we would like to set breakpoint in last binding element if thats the case,
333+
// use preceding token instead
334+
return spanInNode(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent));
324335
}
325336
}
326337

@@ -421,6 +432,24 @@ namespace ts.BreakpointResolver {
421432
}
422433
}
423434

435+
function spanInBindingPattern(bindingPattern: BindingPattern): TextSpan {
436+
// Set breakpoint in first binding element
437+
let firstBindingElement = forEach(bindingPattern.elements,
438+
element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined);
439+
440+
if (firstBindingElement) {
441+
return spanInNode(firstBindingElement);
442+
}
443+
444+
// Empty binding pattern of binding element, set breakpoint on binding element
445+
if (bindingPattern.parent.kind === SyntaxKind.BindingElement) {
446+
return spanInNode(bindingPattern.parent);
447+
}
448+
449+
// Variable declaration is used as the span
450+
return textSpanFromVariableDeclaration(<VariableDeclaration>bindingPattern.parent);
451+
}
452+
424453
// Tokens:
425454
function spanInOpenBraceToken(node: Node): TextSpan {
426455
switch (node.parent.kind) {
@@ -472,6 +501,11 @@ namespace ts.BreakpointResolver {
472501
}
473502
return undefined;
474503

504+
case SyntaxKind.ObjectBindingPattern:
505+
// Breakpoint in last binding element or binding pattern if it contains no elements
506+
let bindingPattern = <BindingPattern>node.parent;
507+
return spanInNode(lastOrUndefined(bindingPattern.elements) || bindingPattern);
508+
475509
// Default to parent node
476510
default:
477511
return spanInNode(node.parent);

tests/baselines/reference/bpSpanDestructuringVariableStatement.baseline

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,31 @@
4747
--------------------------------
4848
11 >var { name: nameA } = robotA;
4949

50-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (247 to 276) SpanInfo: {"start":247,"length":28}
51-
>var { name: nameA } = robotA
52-
>:=> (line 11, col 0) to (line 11, col 28)
50+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (247 to 276) SpanInfo: {"start":253,"length":11}
51+
>name: nameA
52+
>:=> (line 11, col 6) to (line 11, col 17)
5353
--------------------------------
5454
12 >var { name: nameB, skill: skillB } = robotB;
5555

56-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (277 to 321) SpanInfo: {"start":277,"length":43}
57-
>var { name: nameB, skill: skillB } = robotB
58-
>:=> (line 12, col 0) to (line 12, col 43)
56+
~~~~~~~~~~~~~~~~~~ => Pos: (277 to 294) SpanInfo: {"start":283,"length":11}
57+
>name: nameB
58+
>:=> (line 12, col 6) to (line 12, col 17)
59+
12 >var { name: nameB, skill: skillB } = robotB;
60+
61+
~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (295 to 321) SpanInfo: {"start":296,"length":13}
62+
>skill: skillB
63+
>:=> (line 12, col 19) to (line 12, col 32)
5964
--------------------------------
6065
13 >var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" };
6166

62-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (322 to 401) SpanInfo: {"start":322,"length":78}
63-
>var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }
64-
>:=> (line 13, col 0) to (line 13, col 78)
67+
~~~~~~~~~~~~~~~~~~ => Pos: (322 to 339) SpanInfo: {"start":328,"length":11}
68+
>name: nameC
69+
>:=> (line 13, col 6) to (line 13, col 17)
70+
13 >var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" };
71+
72+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (340 to 401) SpanInfo: {"start":341,"length":13}
73+
>skill: skillC
74+
>:=> (line 13, col 19) to (line 13, col 32)
6575
--------------------------------
6676
14 >if (nameA == nameB) {
6777

tests/baselines/reference/bpSpanDestructuringVariableStatement1.baseline

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,37 +50,47 @@
5050
~~~~~~~~~~~~~~ => Pos: (247 to 260) SpanInfo: undefined
5151
11 >var a: string, { name: nameA } = robotA;
5252

53-
~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (261 to 287) SpanInfo: {"start":262,"length":24}
54-
>{ name: nameA } = robotA
55-
>:=> (line 11, col 15) to (line 11, col 39)
53+
~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (261 to 287) SpanInfo: {"start":264,"length":11}
54+
>name: nameA
55+
>:=> (line 11, col 17) to (line 11, col 28)
5656
--------------------------------
5757
12 >var b: string, { name: nameB, skill: skillB } = robotB;
5858

5959
~~~~~~~~~~~~~~ => Pos: (288 to 301) SpanInfo: undefined
6060
12 >var b: string, { name: nameB, skill: skillB } = robotB;
6161

62-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (302 to 343) SpanInfo: {"start":303,"length":39}
63-
>{ name: nameB, skill: skillB } = robotB
64-
>:=> (line 12, col 15) to (line 12, col 54)
62+
~~~~~~~~~~~~~~~ => Pos: (302 to 316) SpanInfo: {"start":305,"length":11}
63+
>name: nameB
64+
>:=> (line 12, col 17) to (line 12, col 28)
65+
12 >var b: string, { name: nameB, skill: skillB } = robotB;
66+
67+
~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (317 to 343) SpanInfo: {"start":318,"length":13}
68+
>skill: skillB
69+
>:=> (line 12, col 30) to (line 12, col 43)
6570
--------------------------------
6671
13 >var c: string, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" };
6772

6873
~~~~~~~~~~~~~~ => Pos: (344 to 357) SpanInfo: undefined
6974
13 >var c: string, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" };
7075

71-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (358 to 434) SpanInfo: {"start":359,"length":74}
72-
>{ name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }
73-
>:=> (line 13, col 15) to (line 13, col 89)
76+
~~~~~~~~~~~~~~~ => Pos: (358 to 372) SpanInfo: {"start":361,"length":11}
77+
>name: nameC
78+
>:=> (line 13, col 17) to (line 13, col 28)
79+
13 >var c: string, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" };
80+
81+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (373 to 434) SpanInfo: {"start":374,"length":13}
82+
>skill: skillC
83+
>:=> (line 13, col 30) to (line 13, col 43)
7484
--------------------------------
7585
14 >
7686

7787
~ => Pos: (435 to 435) SpanInfo: undefined
7888
--------------------------------
7989
15 >var { name: nameA } = robotA, a = hello;
8090

81-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (436 to 464) SpanInfo: {"start":436,"length":28}
82-
>var { name: nameA } = robotA
83-
>:=> (line 15, col 0) to (line 15, col 28)
91+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (436 to 464) SpanInfo: {"start":442,"length":11}
92+
>name: nameA
93+
>:=> (line 15, col 6) to (line 15, col 17)
8494
15 >var { name: nameA } = robotA, a = hello;
8595

8696
~~~~~~~~~~~~ => Pos: (465 to 476) SpanInfo: {"start":466,"length":9}
@@ -89,9 +99,14 @@
8999
--------------------------------
90100
16 >var { name: nameB, skill: skillB } = robotB, b = " hello";
91101

92-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (477 to 520) SpanInfo: {"start":477,"length":43}
93-
>var { name: nameB, skill: skillB } = robotB
94-
>:=> (line 16, col 0) to (line 16, col 43)
102+
~~~~~~~~~~~~~~~~~~ => Pos: (477 to 494) SpanInfo: {"start":483,"length":11}
103+
>name: nameB
104+
>:=> (line 16, col 6) to (line 16, col 17)
105+
16 >var { name: nameB, skill: skillB } = robotB, b = " hello";
106+
107+
~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (495 to 520) SpanInfo: {"start":496,"length":13}
108+
>skill: skillB
109+
>:=> (line 16, col 19) to (line 16, col 32)
95110
16 >var { name: nameB, skill: skillB } = robotB, b = " hello";
96111

97112
~~~~~~~~~~~~~~~=> Pos: (521 to 535) SpanInfo: {"start":522,"length":12}
@@ -100,9 +115,14 @@
100115
--------------------------------
101116
17 >var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c = hello;
102117

103-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (536 to 614) SpanInfo: {"start":536,"length":78}
104-
>var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }
105-
>:=> (line 17, col 0) to (line 17, col 78)
118+
~~~~~~~~~~~~~~~~~~ => Pos: (536 to 553) SpanInfo: {"start":542,"length":11}
119+
>name: nameC
120+
>:=> (line 17, col 6) to (line 17, col 17)
121+
17 >var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c = hello;
122+
123+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (554 to 614) SpanInfo: {"start":555,"length":13}
124+
>skill: skillC
125+
>:=> (line 17, col 19) to (line 17, col 32)
106126
17 >var { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c = hello;
107127

108128
~~~~~~~~~~~~=> Pos: (615 to 626) SpanInfo: {"start":616,"length":9}
@@ -120,9 +140,9 @@
120140
>:=> (line 19, col 0) to (line 19, col 13)
121141
19 >var a = hello, { name: nameA } = robotA, a1= "hello";
122142

123-
~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (642 to 667) SpanInfo: {"start":643,"length":24}
124-
>{ name: nameA } = robotA
125-
>:=> (line 19, col 15) to (line 19, col 39)
143+
~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (642 to 667) SpanInfo: {"start":645,"length":11}
144+
>name: nameA
145+
>:=> (line 19, col 17) to (line 19, col 28)
126146
19 >var a = hello, { name: nameA } = robotA, a1= "hello";
127147

128148
~~~~~~~~~~~~~~=> Pos: (668 to 681) SpanInfo: {"start":669,"length":11}
@@ -136,9 +156,14 @@
136156
>:=> (line 20, col 0) to (line 20, col 13)
137157
20 >var b = hello, { name: nameB, skill: skillB } = robotB, b1 = "hello";
138158

139-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (696 to 736) SpanInfo: {"start":697,"length":39}
140-
>{ name: nameB, skill: skillB } = robotB
141-
>:=> (line 20, col 15) to (line 20, col 54)
159+
~~~~~~~~~~~~~~~ => Pos: (696 to 710) SpanInfo: {"start":699,"length":11}
160+
>name: nameB
161+
>:=> (line 20, col 17) to (line 20, col 28)
162+
20 >var b = hello, { name: nameB, skill: skillB } = robotB, b1 = "hello";
163+
164+
~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (711 to 736) SpanInfo: {"start":712,"length":13}
165+
>skill: skillB
166+
>:=> (line 20, col 30) to (line 20, col 43)
142167
20 >var b = hello, { name: nameB, skill: skillB } = robotB, b1 = "hello";
143168

144169
~~~~~~~~~~~~~~~=> Pos: (737 to 751) SpanInfo: {"start":738,"length":12}
@@ -152,9 +177,14 @@
152177
>:=> (line 21, col 0) to (line 21, col 13)
153178
21 >var c = hello, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c1 = hello;
154179

155-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (766 to 841) SpanInfo: {"start":767,"length":74}
156-
>{ name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }
157-
>:=> (line 21, col 15) to (line 21, col 89)
180+
~~~~~~~~~~~~~~~ => Pos: (766 to 780) SpanInfo: {"start":769,"length":11}
181+
>name: nameC
182+
>:=> (line 21, col 17) to (line 21, col 28)
183+
21 >var c = hello, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c1 = hello;
184+
185+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=> Pos: (781 to 841) SpanInfo: {"start":782,"length":13}
186+
>skill: skillC
187+
>:=> (line 21, col 30) to (line 21, col 43)
158188
21 >var c = hello, { name: nameC, skill: skillC } = { name: "Edger", skill: "cutting edges" }, c1 = hello;
159189

160190
~~~~~~~~~~~~~=> Pos: (842 to 854) SpanInfo: {"start":843,"length":10}

0 commit comments

Comments
 (0)