Skip to content

Commit

Permalink
jsdoc import type completions
Browse files Browse the repository at this point in the history
  • Loading branch information
a-tarasyuk committed Jan 30, 2024
1 parent df23ce3 commit db6bd73
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47625,6 +47625,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (
(isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) ||
((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) ||
(isInJSFile(node) && isJSDocImportTypeTag(node.parent) && node.parent.moduleSpecifier === node) ||
((isInJSFile(node) && isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false)) || isImportCall(node.parent)) ||
(isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent)
) {
Expand Down
39 changes: 23 additions & 16 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3172,6 +3172,7 @@ function getCompletionData(
log("getCompletionData: Is inside comment: " + (timestamp() - start));

let insideJsDocTagTypeExpression = false;
let insideJsDocImportTypeTag = false;
let isInSnippetScope = false;
if (insideComment) {
if (hasDocComment(sourceFile, position)) {
Expand Down Expand Up @@ -3212,25 +3213,30 @@ function getCompletionData(
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
return { kind: CompletionDataKind.JsDocTagName };
}
const typeExpression = tryGetTypeExpressionFromTag(tag);
if (typeExpression) {
currentToken = getTokenAtPosition(sourceFile, position);
if (
!currentToken ||
(!isDeclarationName(currentToken) &&
(currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag ||
(currentToken.parent as JSDocPropertyTag).name !== currentToken))
) {
// Use as type location if inside tag's type expression
insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression);
}
if (isJSDocImportTypeTag(tag)) {
insideJsDocImportTypeTag = true;
}
if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
return { kind: CompletionDataKind.JsDocParameterName, tag };
else {
const typeExpression = tryGetTypeExpressionFromTag(tag);
if (typeExpression) {
currentToken = getTokenAtPosition(sourceFile, position);
if (
!currentToken ||
(!isDeclarationName(currentToken) &&
(currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag ||
(currentToken.parent as JSDocPropertyTag).name !== currentToken))
) {
// Use as type location if inside tag's type expression
insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression);
}
}
if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
return { kind: CompletionDataKind.JsDocParameterName, tag };
}
}
}

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

function isTypeOnlyCompletion(): boolean {
return insideJsDocTagTypeExpression
|| insideJsDocImportTypeTag
|| !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent)
|| !isContextTokenValueLocation(contextToken) &&
(isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker)
Expand Down
1 change: 1 addition & 0 deletions src/services/stringCompletions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
case SyntaxKind.ExternalModuleReference:
case SyntaxKind.JSDocImportTypeTag:
// Get all known external module names or complete a path to a module
// i.e. import * as ns from "/*completion position*/";
// var y = import("/*completion position*/");
Expand Down

0 comments on commit db6bd73

Please sign in to comment.