diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 30626a83d620d..435acf548b2fc 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -3285,6 +3285,30 @@ namespace FourSlashInterface {
return getClassification("typeAliasName", text, position);
}
+ export function jsxOpenTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxOpenTagName", text, position);
+ }
+
+ export function jsxCloseTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxCloseTagName", text, position);
+ }
+
+ export function jsxSelfClosingTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxSelfClosingTagName", text, position);
+ }
+
+ export function jsxAttribute(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxAttribute", text, position);
+ }
+
+ export function jsxText(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxText", text, position);
+ }
+
+ export function jsxAttributeStringLiteralValue(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
+ return getClassification("jsxAttributeStringLiteralValue", text, position);
+ }
+
function getClassification(type: string, text: string, position?: number) {
return {
classificationType: type,
diff --git a/src/services/services.ts b/src/services/services.ts
index 2c8982f10ea94..61b504a25c0b7 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1616,6 +1616,9 @@ namespace ts {
public static jsxOpenTagName = "jsx open tag name";
public static jsxCloseTagName = "jsx close tag name";
public static jsxSelfClosingTagName = "jsx self closing tag name";
+ public static jsxAttribute = "jsx attribute";
+ public static jsxText = "jsx text";
+ public static jsxAttributeStringLiteralValue = "jsx attribute string literal value";
}
export const enum ClassificationType {
@@ -1640,7 +1643,9 @@ namespace ts {
jsxOpenTagName = 19,
jsxCloseTagName = 20,
jsxSelfClosingTagName = 21,
- jsxAttribute = 22
+ jsxAttribute = 22,
+ jsxText = 23,
+ jsxAttributeStringLiteralValue = 24,
}
/// Language Service
@@ -6575,6 +6580,9 @@ namespace ts {
case ClassificationType.jsxOpenTagName: return ClassificationTypeNames.jsxOpenTagName;
case ClassificationType.jsxCloseTagName: return ClassificationTypeNames.jsxCloseTagName;
case ClassificationType.jsxSelfClosingTagName: return ClassificationTypeNames.jsxSelfClosingTagName;
+ case ClassificationType.jsxAttribute: return ClassificationTypeNames.jsxAttribute;
+ case ClassificationType.jsxText: return ClassificationTypeNames.jsxText;
+ case ClassificationType.jsxAttributeStringLiteralValue: return ClassificationTypeNames.jsxAttributeStringLiteralValue;
}
}
@@ -6783,12 +6791,12 @@ namespace ts {
}
}
- function classifyToken(token: Node): void {
+ function classifyTokenOrJsxText(token: Node): void {
if (nodeIsMissing(token)) {
return;
}
- const tokenStart = classifyLeadingTriviaAndGetTokenStart(token);
+ const tokenStart = token.kind === SyntaxKind.JsxText ? token.pos : classifyLeadingTriviaAndGetTokenStart(token);
const tokenWidth = token.end - tokenStart;
Debug.assert(tokenWidth >= 0);
@@ -6824,7 +6832,8 @@ namespace ts {
// the '=' in a variable declaration is special cased here.
if (token.parent.kind === SyntaxKind.VariableDeclaration ||
token.parent.kind === SyntaxKind.PropertyDeclaration ||
- token.parent.kind === SyntaxKind.Parameter) {
+ token.parent.kind === SyntaxKind.Parameter ||
+ token.parent.kind === SyntaxKind.JsxAttribute) {
return ClassificationType.operator;
}
}
@@ -6843,7 +6852,7 @@ namespace ts {
return ClassificationType.numericLiteral;
}
else if (tokenKind === SyntaxKind.StringLiteral || tokenKind === SyntaxKind.StringLiteralType) {
- return ClassificationType.stringLiteral;
+ return token.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral;
}
else if (tokenKind === SyntaxKind.RegularExpressionLiteral) {
// TODO: we should get another classification type for these literals.
@@ -6853,6 +6862,9 @@ namespace ts {
// TODO (drosen): we should *also* get another classification type for these literals.
return ClassificationType.stringLiteral;
}
+ else if (tokenKind === SyntaxKind.JsxText) {
+ return ClassificationType.jsxText;
+ }
else if (tokenKind === SyntaxKind.Identifier) {
if (token) {
switch (token.parent.kind) {
@@ -6926,8 +6938,8 @@ namespace ts {
const children = element.getChildren(sourceFile);
for (let i = 0, n = children.length; i < n; i++) {
const child = children[i];
- if (isToken(child)) {
- classifyToken(child);
+ if (isToken(child) || child.kind === SyntaxKind.JsxText) {
+ classifyTokenOrJsxText(child);
}
else {
// Recurse into our child nodes.
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 0e83189dd8e62..b69a757f01e1b 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -338,6 +338,36 @@ declare namespace FourSlashInterface {
text: string;
textSpan?: TextSpan;
};
+ function jsxOpenTagName(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
+ function jsxCloseTagName(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
+ function jsxSelfClosingTagName(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
+ function jsxAttribute(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
+ function jsxText(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
+ function jsxAttributeStringLiteralValue(text: string, position?: number): {
+ classificationType: string;
+ text: string;
+ textSpan?: TextSpan;
+ };
}
}
declare function verifyOperationIsCancelled(f: any): void;
diff --git a/tests/cases/fourslash/syntacticClassificationsJsx1.ts b/tests/cases/fourslash/syntacticClassificationsJsx1.ts
new file mode 100644
index 0000000000000..e9de07c759b7b
--- /dev/null
+++ b/tests/cases/fourslash/syntacticClassificationsJsx1.ts
@@ -0,0 +1,27 @@
+///