From 9647506d8c6dea0c2531f5f4867971e419799e1f Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 24 Jul 2019 15:57:46 -0700 Subject: [PATCH] Support classification of triple-slash references Note: not restricted to the element and attribute names that actually bind --- src/services/classifier.ts | 83 +++++++++++++++++++ .../syntacticClassificationsTripleSlash1.ts | 15 ++++ .../syntacticClassificationsTripleSlash10.ts | 13 +++ .../syntacticClassificationsTripleSlash11.ts | 15 ++++ .../syntacticClassificationsTripleSlash12.ts | 19 +++++ .../syntacticClassificationsTripleSlash13.ts | 16 ++++ .../syntacticClassificationsTripleSlash14.ts | 7 ++ .../syntacticClassificationsTripleSlash15.ts | 25 ++++++ .../syntacticClassificationsTripleSlash16.ts | 17 ++++ .../syntacticClassificationsTripleSlash2.ts | 16 ++++ .../syntacticClassificationsTripleSlash3.ts | 19 +++++ .../syntacticClassificationsTripleSlash4.ts | 8 ++ .../syntacticClassificationsTripleSlash5.ts | 9 ++ .../syntacticClassificationsTripleSlash6.ts | 10 +++ .../syntacticClassificationsTripleSlash7.ts | 10 +++ .../syntacticClassificationsTripleSlash8.ts | 10 +++ .../syntacticClassificationsTripleSlash9.ts | 10 +++ 17 files changed, 302 insertions(+) create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash11.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash12.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash6.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash7.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash8.ts create mode 100644 tests/cases/fourslash/syntacticClassificationsTripleSlash9.ts diff --git a/src/services/classifier.ts b/src/services/classifier.ts index f85a69681d..f1db477481 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -683,6 +683,11 @@ namespace ts { return; } } + else if (kind === SyntaxKind.SingleLineCommentTrivia) { + if (tryClassifyTripleSlashComment(start, width)) { + return; + } + } // Simple comment. Just add as is. pushCommentRange(start, width); @@ -755,6 +760,84 @@ namespace ts { } } + function tryClassifyTripleSlashComment(start: number, width: number): boolean { + const tripleSlashXMLCommentRegEx = /^(\/\/\/\s*)(<)(?:(\S+)((?:[^/]|\/[^>])*)(\/>)?)?/im; + const attributeRegex = /(\S+)(\s*)(=)(\s*)('[^']+'|"[^"]+")/img; + + const text = sourceFile.text.substr(start, width); + const match = tripleSlashXMLCommentRegEx.exec(text); + if (!match) { + return false; + } + + let pos = start; + + pushCommentRange(pos, match[1].length); // /// + pos += match[1].length; + + pushClassification(pos, match[2].length, ClassificationType.punctuation); // < + pos += match[2].length; + + if (!match[3]) { + return true; + } + + pushClassification(pos, match[3].length, ClassificationType.jsxSelfClosingTagName); // element name + pos += match[3].length; + + const attrText = match[4]; + let attrPos = pos; + while (true) { + const attrMatch = attributeRegex.exec(attrText); + if (!attrMatch) { + break; + } + + const newAttrPos = pos + attrMatch.index; + if (newAttrPos > attrPos) { + pushCommentRange(attrPos, newAttrPos - attrPos); + attrPos = newAttrPos; + } + + pushClassification(attrPos, attrMatch[1].length, ClassificationType.jsxAttribute); // attribute name + attrPos += attrMatch[1].length; + + if (attrMatch[2].length) { + pushCommentRange(attrPos, attrMatch[2].length); // whitespace + attrPos += attrMatch[2].length; + } + + pushClassification(attrPos, attrMatch[3].length, ClassificationType.operator); // = + attrPos += attrMatch[3].length; + + if (attrMatch[4].length) { + pushCommentRange(attrPos, attrMatch[4].length); // whitespace + attrPos += attrMatch[4].length; + } + + pushClassification(attrPos, attrMatch[5].length, ClassificationType.jsxAttributeStringLiteralValue); // attribute value + attrPos += attrMatch[5].length; + } + + pos += match[4].length; + + if (pos > attrPos) { + pushCommentRange(attrPos, pos - attrPos); + } + + if (match[5]) { + pushClassification(pos, match[5].length, ClassificationType.punctuation); // /> + pos += match[5].length; + } + + const end = start + width; + if (pos < end) { + pushCommentRange(pos, end - pos); + } + + return true; + } + function processJSDocTemplateTag(tag: JSDocTemplateTag) { for (const child of tag.getChildren()) { processElement(child); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts new file mode 100644 index 0000000000..13c27669ad --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts @@ -0,0 +1,15 @@ +/// + +//// /// + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.comment(" "), + c.punctuation("/>")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts new file mode 100644 index 0000000000..d1bb681b92 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts @@ -0,0 +1,13 @@ +/// + +//// /// + +//// /// + +//// /// + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.comment(" bad "), + c.jsxAttribute("types"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"node\""), + c.comment(" "), + c.punctuation("/>")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts new file mode 100644 index 0000000000..182b01f756 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts @@ -0,0 +1,16 @@ +/// + +//// /// trailing + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.comment(" "), + c.punctuation("/>"), + c.comment(" trailing")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts new file mode 100644 index 0000000000..a7d16fea02 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts @@ -0,0 +1,7 @@ +/// + +//// /// nonElement + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// nonElement")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts new file mode 100644 index 0000000000..8ec5ebbea5 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts @@ -0,0 +1,25 @@ +/// + +//// /// +//// /// + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module1.ts\""), + c.comment(" "), + c.punctuation("/>"), + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module2.ts\""), + c.comment(" "), + c.punctuation("/>")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts new file mode 100644 index 0000000000..1dbee22cb5 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts @@ -0,0 +1,17 @@ +/// + +//// /// +//// 1 + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.comment(" "), + c.punctuation("/>"), + c.numericLiteral("1")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts new file mode 100644 index 0000000000..278d66dcb4 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts @@ -0,0 +1,16 @@ +/// + +//// /// + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("///"), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.comment(" "), + c.operator("="), + c.comment(" "), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.punctuation("/>")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts new file mode 100644 index 0000000000..11d3b2462b --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts @@ -0,0 +1,19 @@ +/// + +//// /// + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<"), + c.jsxSelfClosingTagName("reference"), + c.comment(" "), + c.jsxAttribute("path"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"./module.ts\""), + c.comment(" "), + c.jsxAttribute("types"), + c.operator("="), + c.jsxAttributeStringLiteralValue("\"node\""), + c.comment(" "), + c.punctuation("/>")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts new file mode 100644 index 0000000000..e656c81137 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts @@ -0,0 +1,8 @@ +/// + +//// /// < + +var c = classification; +verify.syntacticClassificationsAre( + c.comment("/// "), + c.punctuation("<")); \ No newline at end of file diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts new file mode 100644 index 0000000000..c6f1de38f2 --- /dev/null +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts @@ -0,0 +1,9 @@ +/// + +//// /// + +//// /// + +//// /// + +//// /// + +//// ///