Skip to content

Commit f465d99

Browse files
committed
Fix attribute completion following JSX exprs
1 parent b2a871d commit f465d99

File tree

4 files changed

+60
-25
lines changed

4 files changed

+60
-25
lines changed

src/services/services.ts

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,7 @@ namespace ts {
30093009

30103010
function tryGetGlobalSymbols(): boolean {
30113011
let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken);
3012+
let jsxContainer = tryGetContainingJsxElement(contextToken);
30123013
if (objectLikeContainer) {
30133014
// Object literal expression, look up possible property names from contextual type
30143015
isMemberCompletion = true;
@@ -3059,30 +3060,22 @@ namespace ts {
30593060
}
30603061
return true;
30613062
}
3062-
else if (getAncestor(contextToken, SyntaxKind.JsxElement) || getAncestor(contextToken, SyntaxKind.JsxSelfClosingElement)) {
3063-
// Go up until we hit either the element or expression
3064-
let jsxNode = contextToken;
3063+
else if(jsxContainer) {
3064+
let attrsType: Type;
3065+
if (jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) {
3066+
// Cursor is inside a JSX self-closing element
3067+
attrsType = typeChecker.getJsxElementAttributesType(<JsxSelfClosingElement>jsxContainer);
3068+
}
3069+
else if(jsxContainer.kind === SyntaxKind.JsxOpeningElement) {
3070+
// Cursor is inside a JSX element
3071+
attrsType = typeChecker.getJsxElementAttributesType(<JsxOpeningElement>jsxContainer);
3072+
}
30653073

3066-
while (jsxNode) {
3067-
if (jsxNode.kind === SyntaxKind.JsxExpression) {
3068-
// Defer to global completion if we're inside an {expression}
3069-
break;
3070-
} else if (jsxNode.kind === SyntaxKind.JsxSelfClosingElement || jsxNode.kind === SyntaxKind.JsxElement) {
3071-
let attrsType: Type;
3072-
if (jsxNode.kind === SyntaxKind.JsxSelfClosingElement) {
3073-
// Cursor is inside a JSX self-closing element
3074-
attrsType = typeChecker.getJsxElementAttributesType(<JsxSelfClosingElement>jsxNode);
3075-
}
3076-
else {
3077-
Debug.assert(jsxNode.kind === SyntaxKind.JsxElement);
3078-
// Cursor is inside a JSX element
3079-
attrsType = typeChecker.getJsxElementAttributesType((<JsxElement>jsxNode).openingElement);
3080-
}
3081-
symbols = typeChecker.getPropertiesOfType(attrsType);
3082-
isMemberCompletion = true;
3083-
return true;
3084-
}
3085-
jsxNode = jsxNode.parent;
3074+
if (attrsType) {
3075+
symbols = typeChecker.getPropertiesOfType(attrsType);
3076+
isMemberCompletion = true;
3077+
isNewIdentifierLocation = false;
3078+
return true;
30863079
}
30873080
}
30883081

@@ -3268,6 +3261,36 @@ namespace ts {
32683261
return undefined;
32693262
}
32703263

3264+
function tryGetContainingJsxElement(contextToken: Node): JsxOpeningLikeElement {
3265+
if (contextToken) {
3266+
let parent = contextToken.parent;
3267+
switch(contextToken.kind) {
3268+
case SyntaxKind.LessThanSlashToken:
3269+
case SyntaxKind.SlashToken:
3270+
case SyntaxKind.Identifier:
3271+
if(parent && (parent.kind === SyntaxKind.JsxSelfClosingElement || parent.kind === SyntaxKind.JsxOpeningElement)) {
3272+
return <JsxOpeningLikeElement>parent;
3273+
}
3274+
break;
3275+
3276+
case SyntaxKind.CloseBraceToken:
3277+
// The context token is the closing } of an attribute, which means
3278+
// its parent is a JsxExpression, whose parent is a JsxAttribute,
3279+
// whose parent is a JsxOpeningLikeElement
3280+
if(parent &&
3281+
parent.kind === SyntaxKind.JsxExpression &&
3282+
parent.parent &&
3283+
parent.parent.kind === SyntaxKind.JsxAttribute) {
3284+
3285+
return <JsxOpeningLikeElement>parent.parent.parent;
3286+
}
3287+
3288+
break;
3289+
}
3290+
}
3291+
return undefined;
3292+
}
3293+
32713294
function isFunction(kind: SyntaxKind): boolean {
32723295
switch (kind) {
32733296
case SyntaxKind.FunctionExpression:

tests/cases/fourslash/incrementalParsingInsertIntoMethod1.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@
88
//// public foo3() { }
99
////}
1010

11-
debugger;
1211
goTo.marker("1");
1312
edit.insert(" + 1");

tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//// v = 2;
88
////>>>>>>> Branch - a
99
////}
10-
debugger;
10+
1111
var c = classification;
1212
verify.syntacticClassificationsAre(
1313
c.keyword("class"), c.className("C"), c.punctuation("{"),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//@Filename: file.tsx
4+
//// declare module JSX {
5+
//// interface Element { }
6+
//// interface IntrinsicElements {
7+
//// div: { one; two; }
8+
//// }
9+
//// }
10+
//// <div one={1} /**//>;
11+
12+
goTo.marker();
13+
verify.completionListContains('two');

0 commit comments

Comments
 (0)