Skip to content

Commit 35537b5

Browse files
committed
Implement breakpoint spans of array destructuring pattern of destructuring assignment
1 parent 7146b48 commit 35537b5

4 files changed

Lines changed: 426 additions & 147 deletions

File tree

src/services/breakpoints.ts

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ namespace ts.BreakpointResolver {
9797
if (isFunctionBlock(node)) {
9898
return spanInFunctionBlock(<Block>node);
9999
}
100-
// Fall through
100+
// Fall through
101101
case SyntaxKind.ModuleBlock:
102102
return spanInBlock(<Block>node);
103103

@@ -217,17 +217,17 @@ namespace ts.BreakpointResolver {
217217

218218
case SyntaxKind.CommaToken:
219219
return spanInPreviousNode(node)
220-
220+
221221
case SyntaxKind.OpenBraceToken:
222222
return spanInOpenBraceToken(node);
223223

224224
case SyntaxKind.CloseBraceToken:
225225
return spanInCloseBraceToken(node);
226-
226+
227227
case SyntaxKind.CloseBracketToken:
228228
return spanInCloseBracketToken(node);
229229

230-
case SyntaxKind.OpenParenToken:
230+
case SyntaxKind.OpenParenToken:
231231
return spanInOpenParenToken(node);
232232

233233
case SyntaxKind.CloseParenToken:
@@ -253,6 +253,42 @@ namespace ts.BreakpointResolver {
253253
return spanInOfKeyword(node);
254254

255255
default:
256+
// Destructuring pattern in destructuring assignment
257+
// [a, b, c] of
258+
// [a, b, c] = expression
259+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node)) {
260+
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(<DestructuringPattern>node);
261+
}
262+
263+
// Set breakpoint on identifier element of destructuring pattern
264+
// a or ...c from
265+
// [a, b, ...c] or { a, b } from destructuring pattern
266+
if ((node.kind === SyntaxKind.Identifier || node.kind == SyntaxKind.SpreadElementExpression) &&
267+
isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
268+
return textSpan(node);
269+
}
270+
271+
if (node.kind === SyntaxKind.BinaryExpression) {
272+
const binaryExpression = <BinaryExpression>node;
273+
// Set breakpoint in destructuring pattern if its destructuring assignment
274+
// [a, b, c] or {a, b, c} of
275+
// [a, b, c] = expression or
276+
// {a, b, c} = expression
277+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left)) {
278+
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(
279+
<ArrayLiteralExpression | ObjectLiteralExpression>binaryExpression.left);
280+
}
281+
282+
if (binaryExpression.operatorToken.kind === SyntaxKind.EqualsToken &&
283+
isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.parent)) {
284+
// Set breakpoint on assignment expression element of destructuring pattern
285+
// a = expression of
286+
// [a = expression, b, c] = someExpression or
287+
// { a = expression, b, c } = someExpression
288+
return textSpan(node);
289+
}
290+
}
291+
256292
if (isExpression(node)) {
257293
switch (node.parent.kind) {
258294
case SyntaxKind.DoStatement:
@@ -310,6 +346,16 @@ namespace ts.BreakpointResolver {
310346
}
311347
}
312348

349+
if (node.parent.kind === SyntaxKind.BinaryExpression) {
350+
const binaryExpression = <BinaryExpression>node.parent;
351+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left) &&
352+
(binaryExpression.right === node ||
353+
binaryExpression.operatorToken === node)) {
354+
// If initializer of destructuring assignment move to previous token
355+
return spanInPreviousNode(node);
356+
}
357+
}
358+
313359
// Default go to parent to set the breakpoint
314360
return spanInNode(node.parent);
315361
}
@@ -474,13 +520,34 @@ namespace ts.BreakpointResolver {
474520

475521
// Empty binding pattern of binding element, set breakpoint on binding element
476522
if (bindingPattern.parent.kind === SyntaxKind.BindingElement) {
477-
return spanInNode(bindingPattern.parent);
523+
return textSpan(bindingPattern.parent);
478524
}
479525

480526
// Variable declaration is used as the span
481527
return textSpanFromVariableDeclaration(<VariableDeclaration>bindingPattern.parent);
482528
}
483529

530+
function spanInArrayLiteralOrObjectLiteralDestructuringPattern(node: DestructuringPattern): TextSpan {
531+
Debug.assert(node.kind !== SyntaxKind.ArrayBindingPattern && node.kind !== SyntaxKind.ObjectBindingPattern);
532+
const elements: NodeArray<Expression | ObjectLiteralElement> =
533+
node.kind === SyntaxKind.ArrayLiteralExpression ?
534+
(<ArrayLiteralExpression>node).elements :
535+
(<ObjectLiteralExpression>node).properties;
536+
537+
const firstBindingElement = forEach(elements,
538+
element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined);
539+
540+
if (firstBindingElement) {
541+
return spanInNode(firstBindingElement);
542+
}
543+
544+
// Could be ArrayLiteral from destructuring assignment or
545+
// just nested element in another destructuring assignment
546+
// set breakpoint on assignment when parent is destructuring assignment
547+
// Otherwise set breakpoint for this element
548+
return textSpan(node.parent.kind === SyntaxKind.BinaryExpression ? node.parent : node);
549+
}
550+
484551
// Tokens:
485552
function spanInOpenBraceToken(node: Node): TextSpan {
486553
switch (node.parent.kind) {
@@ -548,10 +615,16 @@ namespace ts.BreakpointResolver {
548615
case SyntaxKind.ArrayBindingPattern:
549616
// Breakpoint in last binding element or binding pattern if it contains no elements
550617
let bindingPattern = <BindingPattern>node.parent;
551-
return spanInNode(lastOrUndefined(bindingPattern.elements) || bindingPattern);
618+
return textSpan(lastOrUndefined(bindingPattern.elements) || bindingPattern);
552619

553-
// Default to parent node
554620
default:
621+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
622+
// Breakpoint in last binding element or binding pattern if it contains no elements
623+
let arrayLiteral = <ArrayLiteralExpression>node.parent;
624+
return textSpan(lastOrUndefined(arrayLiteral.elements) || arrayLiteral);
625+
}
626+
627+
// Default to parent node
555628
return spanInNode(node.parent);
556629
}
557630
}

src/services/utilities.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,34 @@ namespace ts {
608608
}
609609
return true;
610610
}
611+
612+
export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) {
613+
if (node.kind === SyntaxKind.ArrayLiteralExpression ||
614+
node.kind === SyntaxKind.ObjectLiteralExpression) {
615+
// [a,b,c] from:
616+
// [a, b, c] = someExpression;
617+
if (node.parent.kind === SyntaxKind.BinaryExpression &&
618+
(<BinaryExpression>node.parent).left === node &&
619+
(<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
620+
return true;
621+
}
622+
623+
// [a, b, c] from:
624+
// for([a, b, c] of expression)
625+
if (node.parent.kind === SyntaxKind.ForOfStatement &&
626+
(<ForOfStatement>node.parent).initializer === node) {
627+
return true;
628+
}
629+
630+
// [a, b, c] of
631+
// [x, [a, b, c] ] = someExpression
632+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
633+
return true;
634+
}
635+
}
636+
637+
return false;
638+
}
611639
}
612640

613641
// Display-part writer helpers

0 commit comments

Comments
 (0)