Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 19 additions & 7 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -1640,7 +1643,9 @@ namespace ts {
jsxOpenTagName = 19,
jsxCloseTagName = 20,
jsxSelfClosingTagName = 21,
jsxAttribute = 22
jsxAttribute = 22,
jsxText = 23,
jsxAttributeStringLiteralValue = 24,
}

/// Language Service
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down
30 changes: 30 additions & 0 deletions tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions tests/cases/fourslash/syntacticClassificationsJsx1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/// <reference path="fourslash.ts"/>

// @Filename: file1.tsx
////let x = <div a = "some-value" b = {1}>
//// some jsx text
////</div>;
////
////let y = <element attr="123"/>

const c = classification;
verify.syntacticClassificationsAre(
c.keyword("let"), c.identifier("x"), c.operator("="),
c.punctuation("<"),
c.jsxOpenTagName("div"),
c.jsxAttribute("a"), c.operator("="), c.jsxAttributeStringLiteralValue(`"some-value"`),
c.jsxAttribute("b"), c.operator("="), c.punctuation("{"), c.numericLiteral("1"), c.punctuation("}"),
c.punctuation(">"),
c.jsxText(`
some jsx text
`),
c.punctuation("<"), c.punctuation("/"), c.jsxCloseTagName("div"), c.punctuation(">"), c.punctuation(";"),
c.keyword("let"), c.identifier("y"), c.operator("="),
c.punctuation("<"),
c.jsxSelfClosingTagName("element"),
c.jsxAttribute("attr"), c.operator("="), c.jsxAttributeStringLiteralValue(`"123"`),
c.punctuation("/"), c.punctuation(">")
)