From e6c6d3090a85efeab90f8b755882d8c8010c9846 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 1 Feb 2016 13:35:57 -0800 Subject: [PATCH] properly classify dotted tag names in jsx --- src/services/services.ts | 76 +++++++++++-------- .../fourslash/syntacticClassificationsJsx2.ts | 27 +++++++ 2 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 tests/cases/fourslash/syntacticClassificationsJsx2.ts diff --git a/src/services/services.ts b/src/services/services.ts index 6d12f29d50858..fdc578b33fd1d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6860,21 +6860,58 @@ namespace ts { } } - function classifyTokenOrJsxText(token: Node): void { - if (nodeIsMissing(token)) { - return; + /** + * Returns true if node should be treated as classified and no further processing is required. + * False will mean that node is not classified and traverse routine should recurse into node contents. + */ + function tryClassifyNode(node: Node): boolean { + if (nodeIsMissing(node)) { + return true; } - const tokenStart = token.kind === SyntaxKind.JsxText ? token.pos : classifyLeadingTriviaAndGetTokenStart(token); + const classifiedElementName = tryClassifyJsxElementName(node); + if (!isToken(node) && node.kind !== SyntaxKind.JsxText && classifiedElementName === undefined) { + return false; + } + + const tokenStart = node.kind === SyntaxKind.JsxText ? node.pos : classifyLeadingTriviaAndGetTokenStart(node); - const tokenWidth = token.end - tokenStart; + const tokenWidth = node.end - tokenStart; Debug.assert(tokenWidth >= 0); if (tokenWidth > 0) { - const type = classifyTokenType(token.kind, token); + const type = classifiedElementName || classifyTokenType(node.kind, node); if (type) { pushClassification(tokenStart, tokenWidth, type); } } + + return true; + } + + function tryClassifyJsxElementName(token: Node): ClassificationType { + switch (token.parent && token.parent.kind) { + case SyntaxKind.JsxOpeningElement: + if ((token.parent).tagName === token) { + return ClassificationType.jsxOpenTagName; + } + break; + case SyntaxKind.JsxClosingElement: + if ((token.parent).tagName === token) { + return ClassificationType.jsxCloseTagName; + } + break; + case SyntaxKind.JsxSelfClosingElement: + if ((token.parent).tagName === token) { + return ClassificationType.jsxSelfClosingTagName; + } + break; + case SyntaxKind.JsxAttribute: + if ((token.parent).name === token) { + return ClassificationType.jsxAttribute; + } + break; + } + return undefined; } // for accurate classification, the actual token should be passed in. however, for @@ -6967,28 +7004,6 @@ namespace ts { return ClassificationType.parameterName; } return; - - case SyntaxKind.JsxOpeningElement: - if ((token.parent).tagName === token) { - return ClassificationType.jsxOpenTagName; - } - return; - - case SyntaxKind.JsxClosingElement: - if ((token.parent).tagName === token) { - return ClassificationType.jsxCloseTagName; - } - return; - - case SyntaxKind.JsxSelfClosingElement: - if ((token.parent).tagName === token) { - return ClassificationType.jsxSelfClosingTagName; - } - return; - case SyntaxKind.JsxAttribute: - if ((token.parent).name === token) { - return ClassificationType.jsxAttribute; - } } } return ClassificationType.identifier; @@ -7007,10 +7022,7 @@ namespace ts { const children = element.getChildren(sourceFile); for (let i = 0, n = children.length; i < n; i++) { const child = children[i]; - if (isToken(child) || child.kind === SyntaxKind.JsxText) { - classifyTokenOrJsxText(child); - } - else { + if (!tryClassifyNode(child)) { // Recurse into our child nodes. processElement(child); } diff --git a/tests/cases/fourslash/syntacticClassificationsJsx2.ts b/tests/cases/fourslash/syntacticClassificationsJsx2.ts new file mode 100644 index 0000000000000..9110c6ce4b934 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsJsx2.ts @@ -0,0 +1,27 @@ +/// + +// @Filename: file1.tsx +////let x = +//// some jsx text +////; +//// +////let y = + +const c = classification; +verify.syntacticClassificationsAre( + c.keyword("let"), c.identifier("x"), c.operator("="), + c.punctuation("<"), + c.jsxOpenTagName("div.name"), + c.jsxAttribute("b"), c.operator("="), c.jsxAttributeStringLiteralValue(`"some-value"`), + c.jsxAttribute("c"), c.operator("="), c.punctuation("{"), c.numericLiteral("1"), c.punctuation("}"), + c.punctuation(">"), + c.jsxText(` + some jsx text +`), + c.punctuation("<"), c.punctuation("/"), c.jsxCloseTagName("div.name"), c.punctuation(">"), c.punctuation(";"), + c.keyword("let"), c.identifier("y"), c.operator("="), + c.punctuation("<"), + c.jsxSelfClosingTagName("element.name"), + c.jsxAttribute("attr"), c.operator("="), c.jsxAttributeStringLiteralValue(`"123"`), + c.punctuation("/"), c.punctuation(">") +) \ No newline at end of file