@@ -683,6 +683,11 @@ namespace ts {
683683 return ;
684684 }
685685 }
686+ else if ( kind === SyntaxKind . SingleLineCommentTrivia ) {
687+ if ( tryClassifyTripleSlashComment ( start , width ) ) {
688+ return ;
689+ }
690+ }
686691
687692 // Simple comment. Just add as is.
688693 pushCommentRange ( start , width ) ;
@@ -755,6 +760,84 @@ namespace ts {
755760 }
756761 }
757762
763+ function tryClassifyTripleSlashComment ( start : number , width : number ) : boolean {
764+ const tripleSlashXMLCommentRegEx = / ^ ( \/ \/ \/ \s * ) ( < ) (?: ( \S + ) ( (?: [ ^ / ] | \/ [ ^ > ] ) * ) ( \/ > ) ? ) ? / im;
765+ const attributeRegex = / ( \S + ) ( \s * ) ( = ) ( \s * ) ( ' [ ^ ' ] + ' | " [ ^ " ] + " ) / img;
766+
767+ const text = sourceFile . text . substr ( start , width ) ;
768+ const match = tripleSlashXMLCommentRegEx . exec ( text ) ;
769+ if ( ! match ) {
770+ return false ;
771+ }
772+
773+ let pos = start ;
774+
775+ pushCommentRange ( pos , match [ 1 ] . length ) ; // ///
776+ pos += match [ 1 ] . length ;
777+
778+ pushClassification ( pos , match [ 2 ] . length , ClassificationType . punctuation ) ; // <
779+ pos += match [ 2 ] . length ;
780+
781+ if ( ! match [ 3 ] ) {
782+ return true ;
783+ }
784+
785+ pushClassification ( pos , match [ 3 ] . length , ClassificationType . jsxSelfClosingTagName ) ; // element name
786+ pos += match [ 3 ] . length ;
787+
788+ const attrText = match [ 4 ] ;
789+ let attrPos = pos ;
790+ while ( true ) {
791+ const attrMatch = attributeRegex . exec ( attrText ) ;
792+ if ( ! attrMatch ) {
793+ break ;
794+ }
795+
796+ const newAttrPos = pos + attrMatch . index ;
797+ if ( newAttrPos > attrPos ) {
798+ pushCommentRange ( attrPos , newAttrPos - attrPos ) ;
799+ attrPos = newAttrPos ;
800+ }
801+
802+ pushClassification ( attrPos , attrMatch [ 1 ] . length , ClassificationType . jsxAttribute ) ; // attribute name
803+ attrPos += attrMatch [ 1 ] . length ;
804+
805+ if ( attrMatch [ 2 ] . length ) {
806+ pushCommentRange ( attrPos , attrMatch [ 2 ] . length ) ; // whitespace
807+ attrPos += attrMatch [ 2 ] . length ;
808+ }
809+
810+ pushClassification ( attrPos , attrMatch [ 3 ] . length , ClassificationType . operator ) ; // =
811+ attrPos += attrMatch [ 3 ] . length ;
812+
813+ if ( attrMatch [ 4 ] . length ) {
814+ pushCommentRange ( attrPos , attrMatch [ 4 ] . length ) ; // whitespace
815+ attrPos += attrMatch [ 4 ] . length ;
816+ }
817+
818+ pushClassification ( attrPos , attrMatch [ 5 ] . length , ClassificationType . jsxAttributeStringLiteralValue ) ; // attribute value
819+ attrPos += attrMatch [ 5 ] . length ;
820+ }
821+
822+ pos += match [ 4 ] . length ;
823+
824+ if ( pos > attrPos ) {
825+ pushCommentRange ( attrPos , pos - attrPos ) ;
826+ }
827+
828+ if ( match [ 5 ] ) {
829+ pushClassification ( pos , match [ 5 ] . length , ClassificationType . punctuation ) ; // />
830+ pos += match [ 5 ] . length ;
831+ }
832+
833+ const end = start + width ;
834+ if ( pos < end ) {
835+ pushCommentRange ( pos , end - pos ) ;
836+ }
837+
838+ return true ;
839+ }
840+
758841 function processJSDocTemplateTag ( tag : JSDocTemplateTag ) {
759842 for ( const child of tag . getChildren ( ) ) {
760843 processElement ( child ) ;
0 commit comments