Skip to content
This repository was archived by the owner on Nov 21, 2025. It is now read-only.

Commit 9ff2572

Browse files
committed
feat(syntaxes): support template literals
Adds support for tagged and untagged template literals in our syntax definition. Fixes #2150.
1 parent 71c08a3 commit 9ff2572

File tree

4 files changed

+286
-0
lines changed

4 files changed

+286
-0
lines changed

syntaxes/expression.json

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,120 @@
558558
}
559559
]
560560
},
561+
"templateLiteral": {
562+
"patterns": [
563+
{
564+
"include": "#templateLiteralCall"
565+
},
566+
{
567+
"contentName": "string.template.ts",
568+
"begin": "([_$[:alpha:]][_$[:alnum:]]*)?(`)",
569+
"beginCaptures": {
570+
"1": {
571+
"name": "entity.name.function.tagged-template.ts"
572+
},
573+
"2": {
574+
"name": "string.template.ts punctuation.definition.string.template.begin.ts"
575+
}
576+
},
577+
"end": "`",
578+
"endCaptures": {
579+
"0": {
580+
"name": "string.template.ts punctuation.definition.string.template.end.ts"
581+
}
582+
},
583+
"patterns": [
584+
{
585+
"include": "#templateLiteralSubstitutionElement"
586+
},
587+
{
588+
"include": "#stringCharacterEscape"
589+
}
590+
]
591+
}
592+
]
593+
},
594+
"templateLiteralCall": {
595+
"patterns": [
596+
{
597+
"begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?<!=)\\>))*(?<!=)\\>)*(?<!=)>\\s*)?`)",
598+
"end": "(?=`)",
599+
"patterns": [
600+
{
601+
"begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))",
602+
"end": "(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?<!=)\\>))*(?<!=)\\>)*(?<!=)>\\s*)?`)",
603+
"patterns": [
604+
{
605+
"include": "#support-function-call-identifiers"
606+
},
607+
{
608+
"name": "entity.name.function.tagged-template.ts",
609+
"match": "([_$[:alpha:]][_$[:alnum:]]*)"
610+
}
611+
]
612+
},
613+
{
614+
"include": "#typeArguments"
615+
}
616+
]
617+
},
618+
{
619+
"begin": "([_$[:alpha:]][_$[:alnum:]]*)?\\s*(?=(<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))(([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>|\\<\\s*(((keyof|infer|typeof|readonly)\\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\\{([^\\{\\}]|(\\{([^\\{\\}]|\\{[^\\{\\}]*\\})*\\}))*\\})|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(\\[([^\\[\\]]|(\\[([^\\[\\]]|\\[[^\\[\\]]*\\])*\\]))*\\])|(\\'([^\\'\\\\]|\\\\.)*\\')|(\\\"([^\\\"\\\\]|\\\\.)*\\\")|(\\`([^\\`\\\\]|\\\\.)*\\`))(?=\\s*([\\<\\>\\,\\.\\[]|=>|&(?!&)|\\|(?!\\|)))))([^<>\\(]|(\\(([^\\(\\)]|(\\(([^\\(\\)]|\\([^\\(\\)]*\\))*\\)))*\\))|(?<==)\\>)*(?<!=)\\>))*(?<!=)\\>)*(?<!=)>\\s*)`)",
620+
"beginCaptures": {
621+
"1": {
622+
"name": "entity.name.function.tagged-template.ts"
623+
}
624+
},
625+
"end": "(?=`)",
626+
"patterns": [
627+
{
628+
"include": "#typeArguments"
629+
}
630+
]
631+
}
632+
]
633+
},
634+
"templateLiteralSubstitutionElement": {
635+
"name": "meta.template.expression.ts",
636+
"begin": "\\${",
637+
"beginCaptures": {
638+
"0": {
639+
"name": "punctuation.definition.template-expression.begin.ts"
640+
}
641+
},
642+
"end": "}",
643+
"endCaptures": {
644+
"0": {
645+
"name": "punctuation.definition.template-expression.end.ts"
646+
}
647+
},
648+
"patterns": [
649+
{
650+
"include": "#ngExpression"
651+
}
652+
],
653+
"contentName": "meta.embedded.line.ts"
654+
},
655+
"typeArguments": {
656+
"name": "meta.type.parameters.ts",
657+
"begin": "<",
658+
"beginCaptures": {
659+
"0": {
660+
"name": "punctuation.definition.typeparameters.begin.ts"
661+
}
662+
},
663+
"end": ">",
664+
"endCaptures": {
665+
"0": {
666+
"name": "punctuation.definition.typeparameters.end.ts"
667+
}
668+
},
669+
"patterns": [
670+
{
671+
"include": "#typeArgumentsBody"
672+
}
673+
]
674+
},
561675
"stringCharacterEscape": {
562676
"name": "constant.character.escape.ts",
563677
"match": "\\\\(x\\h{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)"
@@ -592,6 +706,9 @@
592706
},
593707
{
594708
"include": "#qstringDouble"
709+
},
710+
{
711+
"include": "#templateLiteral"
595712
}
596713
]
597714
},
@@ -776,6 +893,24 @@
776893
}
777894
]
778895
},
896+
"typeArgumentsBody": {
897+
"patterns": [
898+
{
899+
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(_)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))",
900+
"captures": {
901+
"0": {
902+
"name": "keyword.operator.type.ts"
903+
}
904+
}
905+
},
906+
{
907+
"include": "#type"
908+
},
909+
{
910+
"include": "#punctuationComma"
911+
}
912+
]
913+
},
779914
"type": {
780915
"name": "meta.type.ts",
781916
"patterns": [

syntaxes/src/expression.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,80 @@ export const Expression: GrammarDefinition = {
588588
],
589589
},
590590

591+
// Via https://github.com/microsoft/vscode-typescript-next/blob/bb6c015fdfe8c80e2f24bd83bb70d4d6581b0708/syntaxes/TypeScript.tmLanguage.json
592+
templateLiteral: {
593+
patterns: [
594+
{include: '#templateLiteralCall'},
595+
{
596+
contentName: 'string.template.ts',
597+
begin: /([_$[:alpha:]][_$[:alnum:]]*)?(`)/,
598+
beginCaptures: {
599+
1: {name: 'entity.name.function.tagged-template.ts'},
600+
2: {name: 'string.template.ts punctuation.definition.string.template.begin.ts'},
601+
},
602+
end: /`/,
603+
endCaptures: {
604+
0: {name: 'string.template.ts punctuation.definition.string.template.end.ts'},
605+
},
606+
patterns: [
607+
{include: '#templateLiteralSubstitutionElement'},
608+
{include: '#stringCharacterEscape'},
609+
],
610+
},
611+
],
612+
},
613+
614+
templateLiteralCall: {
615+
patterns: [
616+
{
617+
begin:
618+
/(?=(([_$[:alpha:]][_$[:alnum:]]*\s*\??\.\s*)*|(\??\.\s*)?)([_$[:alpha:]][_$[:alnum:]]*)(<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))(([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>)*(?<!=)\>))*(?<!=)\>)*(?<!=)>\s*)?`)/,
619+
end: /(?=`)/,
620+
patterns: [
621+
{
622+
begin:
623+
/(?=(([_$[:alpha:]][_$[:alnum:]]*\s*\??\.\s*)*|(\??\.\s*)?)([_$[:alpha:]][_$[:alnum:]]*))/,
624+
end: /(?=(<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))(([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>)*(?<!=)\>))*(?<!=)\>)*(?<!=)>\s*)?`)/,
625+
patterns: [
626+
{include: '#support-function-call-identifiers'},
627+
{
628+
name: 'entity.name.function.tagged-template.ts',
629+
match: /([_$[:alpha:]][_$[:alnum:]]*)/,
630+
},
631+
],
632+
},
633+
{include: '#typeArguments'},
634+
],
635+
},
636+
{
637+
begin:
638+
/([_$[:alpha:]][_$[:alnum:]]*)?\s*(?=(<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))(([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>|\<\s*(((keyof|infer|typeof|readonly)\s+)|(([_$[:alpha:]][_$[:alnum:]]*|(\{([^\{\}]|(\{([^\{\}]|\{[^\{\}]*\})*\}))*\})|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(\[([^\[\]]|(\[([^\[\]]|\[[^\[\]]*\])*\]))*\])|(\'([^\'\\]|\\.)*\')|(\"([^\"\\]|\\.)*\")|(\`([^\`\\]|\\.)*\`))(?=\s*([\<\>\,\.\[]|=>|&(?!&)|\|(?!\|)))))([^<>\(]|(\(([^\(\)]|(\(([^\(\)]|\([^\(\)]*\))*\)))*\))|(?<==)\>)*(?<!=)\>))*(?<!=)\>)*(?<!=)>\s*)`)/,
639+
beginCaptures: {1: {name: 'entity.name.function.tagged-template.ts'}},
640+
end: /(?=`)/,
641+
patterns: [{include: '#typeArguments'}],
642+
},
643+
],
644+
},
645+
646+
templateLiteralSubstitutionElement: {
647+
name: 'meta.template.expression.ts',
648+
begin: /\${/,
649+
beginCaptures: {0: {name: 'punctuation.definition.template-expression.begin.ts'}},
650+
end: /}/,
651+
endCaptures: {0: {name: 'punctuation.definition.template-expression.end.ts'}},
652+
patterns: [{include: '#ngExpression'}],
653+
contentName: 'meta.embedded.line.ts',
654+
},
655+
656+
typeArguments: {
657+
name: 'meta.type.parameters.ts',
658+
begin: /</,
659+
beginCaptures: {0: {name: 'punctuation.definition.typeparameters.begin.ts'}},
660+
end: />/,
661+
endCaptures: {0: {name: 'punctuation.definition.typeparameters.end.ts'}},
662+
patterns: [{include: '#typeArgumentsBody'}],
663+
},
664+
591665
stringCharacterEscape: {
592666
name: 'constant.character.escape.ts',
593667
match: /\\(x\h{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)/,
@@ -631,6 +705,9 @@ export const Expression: GrammarDefinition = {
631705
{
632706
include: '#qstringDouble',
633707
},
708+
{
709+
include: '#templateLiteral',
710+
}
634711
],
635712
},
636713

@@ -824,6 +901,17 @@ export const Expression: GrammarDefinition = {
824901
],
825902
},
826903

904+
typeArgumentsBody: {
905+
patterns: [
906+
{
907+
match: /(?<![_$[:alnum:]])(?:(?<=\.\.\.)|(?<!\.))(_)(?![_$[:alnum:]])(?:(?=\.\.\.)|(?!\.))/,
908+
captures: {0: {name: 'keyword.operator.type.ts'}},
909+
},
910+
{include: '#type'},
911+
{include: '#punctuationComma'},
912+
],
913+
},
914+
827915
type: {
828916
name: 'meta.type.ts',
829917
patterns: [

syntaxes/test/data/expression.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
{{ (let param of params) | customPipe: 'param' | search: ['term1', 'term2'] }}
8686
{{ ((let param of params) | async) | translate }}
8787

88+
<!-- Template literals -->
89+
{{ `hello world` }}
90+
{{ tag`hello world` }}
91+
{{ `before ${123} - ${fn()} after` }}
92+
{{ tag`before ${123} - ${fn()} after` }}
93+
8894
<!-- Mixed -->
8995
{{ (let param of params?.get('value')!.property | async).anotherProperty | translate: ['language1', 'language2']; index
9096
as i }}

0 commit comments

Comments
 (0)