Skip to content

Commit db6bd73

Browse files
committed
jsdoc import type completions
1 parent df23ce3 commit db6bd73

File tree

3 files changed

+25
-16
lines changed

3 files changed

+25
-16
lines changed

src/compiler/checker.ts

+1
Original file line numberDiff line numberDiff line change
@@ -47625,6 +47625,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4762547625
if (
4762647626
(isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) ||
4762747627
((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) ||
47628+
(isInJSFile(node) && isJSDocImportTypeTag(node.parent) && node.parent.moduleSpecifier === node) ||
4762847629
((isInJSFile(node) && isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false)) || isImportCall(node.parent)) ||
4762947630
(isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent)
4763047631
) {

src/services/completions.ts

+23-16
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,7 @@ function getCompletionData(
31723172
log("getCompletionData: Is inside comment: " + (timestamp() - start));
31733173

31743174
let insideJsDocTagTypeExpression = false;
3175+
let insideJsDocImportTypeTag = false;
31753176
let isInSnippetScope = false;
31763177
if (insideComment) {
31773178
if (hasDocComment(sourceFile, position)) {
@@ -3212,25 +3213,30 @@ function getCompletionData(
32123213
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
32133214
return { kind: CompletionDataKind.JsDocTagName };
32143215
}
3215-
const typeExpression = tryGetTypeExpressionFromTag(tag);
3216-
if (typeExpression) {
3217-
currentToken = getTokenAtPosition(sourceFile, position);
3218-
if (
3219-
!currentToken ||
3220-
(!isDeclarationName(currentToken) &&
3221-
(currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag ||
3222-
(currentToken.parent as JSDocPropertyTag).name !== currentToken))
3223-
) {
3224-
// Use as type location if inside tag's type expression
3225-
insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression);
3226-
}
3216+
if (isJSDocImportTypeTag(tag)) {
3217+
insideJsDocImportTypeTag = true;
32273218
}
3228-
if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
3229-
return { kind: CompletionDataKind.JsDocParameterName, tag };
3219+
else {
3220+
const typeExpression = tryGetTypeExpressionFromTag(tag);
3221+
if (typeExpression) {
3222+
currentToken = getTokenAtPosition(sourceFile, position);
3223+
if (
3224+
!currentToken ||
3225+
(!isDeclarationName(currentToken) &&
3226+
(currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag ||
3227+
(currentToken.parent as JSDocPropertyTag).name !== currentToken))
3228+
) {
3229+
// Use as type location if inside tag's type expression
3230+
insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression);
3231+
}
3232+
}
3233+
if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
3234+
return { kind: CompletionDataKind.JsDocParameterName, tag };
3235+
}
32303236
}
32313237
}
32323238

3233-
if (!insideJsDocTagTypeExpression) {
3239+
if (!insideJsDocTagTypeExpression && !insideJsDocImportTypeTag) {
32343240
// Proceed if the current position is in jsDoc tag expression; otherwise it is a normal
32353241
// comment or the plain text part of a jsDoc comment, so no completion should be available
32363242
log("Returning an empty list because completion was inside a regular comment or plain text part of a JsDoc comment.");
@@ -3241,7 +3247,7 @@ function getCompletionData(
32413247
start = timestamp();
32423248
// The decision to provide completion depends on the contextToken, which is determined through the previousToken.
32433249
// Note: 'previousToken' (and thus 'contextToken') can be undefined if we are the beginning of the file
3244-
const isJsOnlyLocation = !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile);
3250+
const isJsOnlyLocation = !insideJsDocTagTypeExpression && !insideJsDocImportTypeTag && isSourceFileJS(sourceFile);
32453251
const tokens = getRelevantTokens(position, sourceFile);
32463252
const previousToken = tokens.previousToken!;
32473253
let contextToken = tokens.contextToken!;
@@ -3922,6 +3928,7 @@ function getCompletionData(
39223928

39233929
function isTypeOnlyCompletion(): boolean {
39243930
return insideJsDocTagTypeExpression
3931+
|| insideJsDocImportTypeTag
39253932
|| !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent)
39263933
|| !isContextTokenValueLocation(contextToken) &&
39273934
(isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker)

src/services/stringCompletions.ts

+1
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
418418
case SyntaxKind.ImportDeclaration:
419419
case SyntaxKind.ExportDeclaration:
420420
case SyntaxKind.ExternalModuleReference:
421+
case SyntaxKind.JSDocImportTypeTag:
421422
// Get all known external module names or complete a path to a module
422423
// i.e. import * as ns from "/*completion position*/";
423424
// var y = import("/*completion position*/");

0 commit comments

Comments
 (0)