Skip to content

Commit 675e212

Browse files
author
Andy
authored
Improve template literal tests (microsoft#24359)
* Improve template literal tests * Inline isTemplateLiteralToken where possible
1 parent 22cdff5 commit 675e212

File tree

6 files changed

+33
-34
lines changed

6 files changed

+33
-34
lines changed

src/compiler/utilities.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5594,13 +5594,18 @@ namespace ts {
55945594
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
55955595
}
55965596

5597+
export type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail;
5598+
export function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken {
5599+
return isTemplateLiteralKind(node.kind);
5600+
}
5601+
55975602
export function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail {
55985603
const kind = node.kind;
55995604
return kind === SyntaxKind.TemplateMiddle
56005605
|| kind === SyntaxKind.TemplateTail;
56015606
}
56025607

5603-
export function isStringTextContainingNode(node: Node) {
5608+
export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken {
56045609
return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind);
56055610
}
56065611

src/services/completions.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,27 +1486,13 @@ namespace ts.Completions {
14861486
}
14871487

14881488
function isInStringOrRegularExpressionOrTemplateLiteral(contextToken: Node): boolean {
1489-
if (contextToken.kind === SyntaxKind.StringLiteral
1490-
|| contextToken.kind === SyntaxKind.RegularExpressionLiteral
1491-
|| isTemplateLiteralKind(contextToken.kind)) {
1492-
const start = contextToken.getStart();
1493-
const end = contextToken.getEnd();
1494-
1495-
// To be "in" one of these literals, the position has to be:
1496-
// 1. entirely within the token text.
1497-
// 2. at the end position of an unterminated token.
1498-
// 3. at the end of a regular expression (due to trailing flags like '/foo/g').
1499-
if (start < position && position < end) {
1500-
return true;
1501-
}
1502-
1503-
if (position === end) {
1504-
return !!(<LiteralExpression>contextToken).isUnterminated
1505-
|| contextToken.kind === SyntaxKind.RegularExpressionLiteral;
1506-
}
1507-
}
1508-
1509-
return false;
1489+
// To be "in" one of these literals, the position has to be:
1490+
// 1. entirely within the token text.
1491+
// 2. at the end position of an unterminated token.
1492+
// 3. at the end of a regular expression (due to trailing flags like '/foo/g').
1493+
return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && (
1494+
rangeContainsPositionExclusive(createTextRangeFromSpan(createTextSpanFromNode(contextToken)), position) ||
1495+
position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)));
15101496
}
15111497

15121498
/**

src/services/signatureHelp.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ namespace ts.SignatureHelp {
161161
else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) {
162162
// Check if we're actually inside the template;
163163
// otherwise we'll fall out and return undefined.
164-
if (isInsideTemplateLiteral(node, position)) {
164+
if (isInsideTemplateLiteral(node, position, sourceFile)) {
165165
return getArgumentListInfoForTemplate(parent, /*argumentIndex*/ 0, sourceFile);
166166
}
167167
}
@@ -170,7 +170,7 @@ namespace ts.SignatureHelp {
170170
const tagExpression = <TaggedTemplateExpression>templateExpression.parent;
171171
Debug.assert(templateExpression.kind === SyntaxKind.TemplateExpression);
172172

173-
const argumentIndex = isInsideTemplateLiteral(node, position) ? 0 : 1;
173+
const argumentIndex = isInsideTemplateLiteral(node, position, sourceFile) ? 0 : 1;
174174

175175
return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile);
176176
}
@@ -179,12 +179,12 @@ namespace ts.SignatureHelp {
179179
const tagExpression = parent.parent.parent;
180180

181181
// If we're just after a template tail, don't show signature help.
182-
if (node.kind === SyntaxKind.TemplateTail && !isInsideTemplateLiteral(<LiteralExpression>node, position)) {
182+
if (isTemplateTail(node) && !isInsideTemplateLiteral(node, position, sourceFile)) {
183183
return undefined;
184184
}
185185

186186
const spanIndex = templateSpan.parent.templateSpans.indexOf(templateSpan);
187-
const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position);
187+
const argumentIndex = getArgumentIndexForTemplatePiece(spanIndex, node, position, sourceFile);
188188

189189
return getArgumentListInfoForTemplate(tagExpression, argumentIndex, sourceFile);
190190
}
@@ -266,7 +266,7 @@ namespace ts.SignatureHelp {
266266

267267
// spanIndex is either the index for a given template span.
268268
// This does not give appropriate results for a NoSubstitutionTemplateLiteral
269-
function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number): number {
269+
function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number, sourceFile: SourceFile): number {
270270
// Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1.
271271
// There are three cases we can encounter:
272272
// 1. We are precisely in the template literal (argIndex = 0).
@@ -281,8 +281,8 @@ namespace ts.SignatureHelp {
281281
// Case: 1 1 3 2 1 3 2 2 1
282282
// tslint:enable no-double-space
283283
Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node.");
284-
if (isTemplateLiteralKind(node.kind)) {
285-
if (isInsideTemplateLiteral(<LiteralExpression>node, position)) {
284+
if (isTemplateLiteralToken(node)) {
285+
if (isInsideTemplateLiteral(node, position, sourceFile)) {
286286
return 0;
287287
}
288288
return spanIndex + 2;

src/services/utilities.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ namespace ts {
423423
return r.pos <= pos && pos <= r.end;
424424
}
425425

426+
export function rangeContainsPositionExclusive(r: TextRange, pos: number) {
427+
return r.pos < pos && pos < r.end;
428+
}
429+
426430
export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
427431
return start <= range.pos && end >= range.end;
428432
}
@@ -830,7 +834,7 @@ namespace ts {
830834

831835
export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean {
832836
if (previousToken && isStringTextContainingNode(previousToken)) {
833-
const start = previousToken.getStart();
837+
const start = previousToken.getStart(sourceFile);
834838
const end = previousToken.getEnd();
835839

836840
// To be "in" one of these literals, the position has to be:
@@ -1093,9 +1097,9 @@ namespace ts {
10931097
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
10941098
}
10951099

1096-
export function isInsideTemplateLiteral(node: LiteralExpression | TemplateHead, position: number) {
1100+
export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean {
10971101
return isTemplateLiteralKind(node.kind)
1098-
&& (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd());
1102+
&& (node.getStart(sourceFile) < position && position < node.end) || (!!node.isUnterminated && position === node.end);
10991103
}
11001104

11011105
export function isAccessibilityModifier(kind: SyntaxKind) {

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3399,8 +3399,10 @@ declare namespace ts {
33993399
*/
34003400
function isToken(n: Node): boolean;
34013401
function isLiteralExpression(node: Node): node is LiteralExpression;
3402+
type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail;
3403+
function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
34023404
function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
3403-
function isStringTextContainingNode(node: Node): boolean;
3405+
function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
34043406
function isModifier(node: Node): node is Modifier;
34053407
function isEntityName(node: Node): node is EntityName;
34063408
function isPropertyName(node: Node): node is PropertyName;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3399,8 +3399,10 @@ declare namespace ts {
33993399
*/
34003400
function isToken(n: Node): boolean;
34013401
function isLiteralExpression(node: Node): node is LiteralExpression;
3402+
type TemplateLiteralToken = NoSubstitutionTemplateLiteral | TemplateHead | TemplateMiddle | TemplateTail;
3403+
function isTemplateLiteralToken(node: Node): node is TemplateLiteralToken;
34023404
function isTemplateMiddleOrTemplateTail(node: Node): node is TemplateMiddle | TemplateTail;
3403-
function isStringTextContainingNode(node: Node): boolean;
3405+
function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken;
34043406
function isModifier(node: Node): node is Modifier;
34053407
function isEntityName(node: Node): node is EntityName;
34063408
function isPropertyName(node: Node): node is PropertyName;

0 commit comments

Comments
 (0)