From 953e54b2ee1f1c106852afedde85af74158e736e Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Mon, 29 Jan 2024 00:24:39 +0200 Subject: [PATCH 01/23] feat(41825): add importType jsdoc tag --- src/compiler/checker.ts | 20 ++++++---- src/compiler/emitter.ts | 18 +++++++++ src/compiler/factory/nodeFactory.ts | 23 ++++++++++++ src/compiler/factory/nodeTests.ts | 5 +++ src/compiler/parser.ts | 37 +++++++++++++++++++ src/compiler/program.ts | 19 ++++++++++ src/compiler/transformers/declarations.ts | 3 ++ src/compiler/types.ts | 24 +++++++++--- src/compiler/utilities.ts | 7 +++- .../codefixes/convertToTypeOnlyImport.ts | 5 ++- src/services/codefixes/useDefaultImport.ts | 3 +- src/services/completions.ts | 8 ++-- src/services/refactors/convertImport.ts | 10 ++++- src/services/utilities.ts | 3 +- tests/baselines/reference/api/typescript.d.ts | 28 +++++++++----- .../reference/importTypeTag1.symbols | 22 +++++++++++ .../baselines/reference/importTypeTag1.types | 20 ++++++++++ .../reference/importTypeTag2.symbols | 22 +++++++++++ .../baselines/reference/importTypeTag2.types | 20 ++++++++++ .../reference/importTypeTag3.symbols | 22 +++++++++++ .../baselines/reference/importTypeTag3.types | 20 ++++++++++ .../reference/importTypeTag4.errors.txt | 27 ++++++++++++++ .../reference/importTypeTag4.symbols | 26 +++++++++++++ .../baselines/reference/importTypeTag4.types | 24 ++++++++++++ tests/baselines/reference/importTypeTag5.js | 32 ++++++++++++++++ .../reference/importTypeTag5.symbols | 22 +++++++++++ .../baselines/reference/importTypeTag5.types | 20 ++++++++++ .../cases/conformance/jsdoc/importTypeTag1.ts | 18 +++++++++ .../cases/conformance/jsdoc/importTypeTag2.ts | 18 +++++++++ .../cases/conformance/jsdoc/importTypeTag3.ts | 18 +++++++++ .../cases/conformance/jsdoc/importTypeTag4.ts | 22 +++++++++++ .../cases/conformance/jsdoc/importTypeTag5.ts | 19 ++++++++++ 32 files changed, 553 insertions(+), 32 deletions(-) create mode 100644 tests/baselines/reference/importTypeTag1.symbols create mode 100644 tests/baselines/reference/importTypeTag1.types create mode 100644 tests/baselines/reference/importTypeTag2.symbols create mode 100644 tests/baselines/reference/importTypeTag2.types create mode 100644 tests/baselines/reference/importTypeTag3.symbols create mode 100644 tests/baselines/reference/importTypeTag3.types create mode 100644 tests/baselines/reference/importTypeTag4.errors.txt create mode 100644 tests/baselines/reference/importTypeTag4.symbols create mode 100644 tests/baselines/reference/importTypeTag4.types create mode 100644 tests/baselines/reference/importTypeTag5.js create mode 100644 tests/baselines/reference/importTypeTag5.symbols create mode 100644 tests/baselines/reference/importTypeTag5.types create mode 100644 tests/cases/conformance/jsdoc/importTypeTag1.ts create mode 100644 tests/cases/conformance/jsdoc/importTypeTag2.ts create mode 100644 tests/cases/conformance/jsdoc/importTypeTag3.ts create mode 100644 tests/cases/conformance/jsdoc/importTypeTag4.ts create mode 100644 tests/cases/conformance/jsdoc/importTypeTag5.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3b3d4256fecfc..fb0565e4897be 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11,8 +11,8 @@ import { AmbientModuleDeclaration, and, AnonymousType, + AnyImportOrJsDocImportTypeImport, AnyImportOrReExport, - AnyImportSyntax, append, appendIfUnique, ArrayBindingPattern, @@ -583,6 +583,7 @@ import { isJSDocCallbackTag, isJSDocConstructSignature, isJSDocFunctionType, + isJSDocImportTypeTag, isJSDocIndexSignature, isJSDocLinkLike, isJSDocMemberName, @@ -770,6 +771,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, + JSDocImportTypeTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -3942,7 +3944,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || (n === stopAt || isFunctionLike(n) && (!getImmediatelyInvokedFunctionExpression(n) || (getFunctionFlags(n) & FunctionFlags.AsyncGenerator)) ? "quit" : false)); } - function getAnyImportSyntax(node: Node): AnyImportSyntax | undefined { + function getAnyImportSyntax(node: Node): AnyImportOrJsDocImportTypeImport | undefined { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: return node as ImportEqualsDeclaration; @@ -4280,8 +4282,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { - const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; + function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration | JSDocImportTypeTag, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { + const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration | JSDocImportTypeTag).moduleSpecifier!; const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; if (!isIdentifier(name)) { @@ -5006,6 +5008,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? location : (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal || + (isInJSFile(location) && isJSDocImportTypeTag(location) ? location.moduleSpecifier : undefined) || (isVariableDeclaration(location) && location.initializer && isRequireCall(location.initializer, /*requireStringLiteralLikeArgument*/ true) ? location.initializer.arguments[0] : undefined) || findAncestor(location, isImportCall)?.arguments[0] || findAncestor(location, isImportDeclaration)?.moduleSpecifier || @@ -9720,12 +9723,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportClause: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportClause).parent.moduleSpecifier; + const attributes = isImportDeclaration(node.parent) ? node.parent.attributes : undefined; addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, factory.createIdentifier(localName), /*namedBindings*/ undefined), specifier, - (node as ImportClause).parent.attributes, + attributes, ), ModifierFlags.None, ); @@ -9734,12 +9738,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as NamespaceImport).parent.parent.moduleSpecifier; + const attributes = isImportDeclaration(node.parent) ? node.parent.attributes : undefined; addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), specifier, - (node as ImportClause).parent.attributes, + attributes, ), ModifierFlags.None, ); @@ -9759,6 +9764,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportSpecifier: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; + const attributes = isImportDeclaration(node.parent.parent.parent) ? node.parent.parent.parent.attributes : undefined; addResult( factory.createImportDeclaration( /*modifiers*/ undefined, @@ -9774,7 +9780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ]), ), specifier, - (node as ImportSpecifier).parent.parent.parent.attributes, + attributes, ), ModifierFlags.None, ); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7b7f0fcfa8143..ef564f615b516 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -266,6 +266,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, + JSDocImportTypeTag, JSDocNameReference, JSDocNonNullableType, JSDocNullableType, @@ -2204,6 +2205,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return emitJSDocTypedefTag(node as JSDocTypedefTag); case SyntaxKind.JSDocSeeTag: return emitJSDocSeeTag(node as JSDocSeeTag); + case SyntaxKind.JSDocImportTypeTag: + return emitJSDocImportTypeTag(node as JSDocImportTypeTag); // SyntaxKind.JSDocPropertyTag (see JSDocParameterTag, above) // Transformation nodes @@ -4452,6 +4455,21 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitJSDocComment(tag.comment); } + function emitJSDocImportTypeTag(tag: JSDocImportTypeTag) { + emitJSDocTagName(tag.tagName); + + writeSpace(); + emit(tag.importClause); + + writeSpace(); + emitTokenWithComment(SyntaxKind.FromKeyword, tag.importClause.end, writeKeyword, tag); + + writeSpace(); + emitExpression(tag.moduleSpecifier); + + emitJSDocComment(tag.comment); + } + function emitJSDocNameReference(node: JSDocNameReference) { writeSpace(); writePunctuation("{"); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 907ab3833b672..51a4559ea17be 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -238,6 +238,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, + JSDocImportTypeTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -882,6 +883,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode updateJSDocImplementsTag, createJSDocSeeTag, updateJSDocSeeTag, + createJSDocImportTypeTag, + updateJSDocImportTypeTag, createJSDocNameReference, updateJSDocNameReference, createJSDocMemberName, @@ -5554,6 +5557,24 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : node; } + // @api + function createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag { + const node = createBaseJSDocTag(SyntaxKind.JSDocImportTypeTag, tagName ?? createIdentifier("importType"), comment); + node.importClause = importClause; + node.moduleSpecifier = moduleSpecifier; + node.comment = comment; + return node; + } + + function updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag { + return node.tagName !== tagName + || node.comment !== comment + || node.importClause !== importClause + || node.moduleSpecifier !== moduleSpecifier + ? update(createJSDocImportTypeTag(tagName, importClause, moduleSpecifier, comment), node) + : node; + } + // @api function createJSDocText(text: string): JSDocText { const node = createBaseNode(SyntaxKind.JSDocText); @@ -7265,6 +7286,8 @@ function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string { return "augments"; case SyntaxKind.JSDocImplementsTag: return "implements"; + case SyntaxKind.JSDocImportTypeTag: + return "importType"; default: return Debug.fail(`Unsupported kind: ${Debug.formatSyntaxKind(kind)}`); } diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index eca54d346d882..02cf0ec7ca6e7 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -91,6 +91,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, + JSDocImportTypeTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -1202,6 +1203,10 @@ export function isJSDocThrowsTag(node: Node): node is JSDocThrowsTag { return node.kind === SyntaxKind.JSDocThrowsTag; } +export function isJSDocImportTypeTag(node: Node): node is JSDocImportTypeTag { + return node.kind === SyntaxKind.JSDocImportTypeTag; +} + // Synthesized list /** @internal */ diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2f411c435492a..7b372d7d665b9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -175,6 +175,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, + JSDocImportTypeTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -1125,6 +1126,7 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, + [SyntaxKind.JSDocImportTypeTag]: forEachChildInJSDocImportTypeTag, [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, }; @@ -1214,6 +1216,13 @@ function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDoc || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } +function forEachChildInJSDocImportTypeTag(node: JSDocImportTypeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.importClause) + || visitNode(cbNode, node.moduleSpecifier) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); +} + function forEachChildInPartiallyEmittedExpression(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNode(cbNode, node.expression); } @@ -9073,6 +9082,9 @@ namespace Parser { case "throws": tag = parseThrowsTag(start, tagName, margin, indentText); break; + case "importType": + tag = parseImportTypeTag(start, tagName, margin, indentText); + break; default: tag = parseUnknownTag(start, tagName, margin, indentText); break; @@ -9445,6 +9457,31 @@ namespace Parser { return finishNode(factory.createJSDocSatisfiesTag(tagName, typeExpression, comments), start); } + function parseImportTypeTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTypeTag { + const afterImportTypeTagPos = scanner.getTokenEnd(); + + let identifier: Identifier | undefined; + if (isIdentifier()) { + identifier = parseIdentifier(); + } + + let importClause: ImportClause | undefined; + if ( + identifier // @importType id + || token() === SyntaxKind.AsteriskToken // @importType * + || token() === SyntaxKind.OpenBraceToken // @importType { + ) { + importClause = parseImportClause(identifier, afterImportTypeTagPos, /*isTypeOnly*/ true); + parseExpected(SyntaxKind.FromKeyword); + } + + Debug.assert(importClause); + + const moduleSpecifier = parseModuleSpecifier(); + const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; + return finishNode(factory.createJSDocImportTypeTag(tagName, importClause, moduleSpecifier, comments), start); + } + function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } { const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); const pos = getNodePos(); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index d34984bca506c..74bd222a91c4d 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -195,6 +195,7 @@ import { isImportTypeNode, isIncrementalCompilation, isInJSFile, + isJSDocImportTypeTag, isLiteralImportTypeNode, isModifier, isModuleDeclaration, @@ -3370,6 +3371,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg collectDynamicImportOrRequireCalls(file); } + if (isJavaScriptFile) { + collectJsDocImportTypeReferences(file); + } + file.imports = imports || emptyArray; file.moduleAugmentations = moduleAugmentations || emptyArray; file.ambientModuleNames = ambientModules || emptyArray; @@ -3444,6 +3449,20 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } + function collectJsDocImportTypeReferences(file: SourceFile) { + const r = /@importType/g; + while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null + const node = getNodeAtPosition(file, r.lastIndex); + if (isJSDocImportTypeTag(node)) { + const moduleNameExpr = getExternalModuleName(node); + if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) { + setParentRecursive(node, /*incremental*/ false); + imports = append(imports, moduleNameExpr); + } + } + } + } + /** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */ function getNodeAtPosition(sourceFile: SourceFile, position: number): Node { let current: Node = sourceFile; diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 0a9e58c6de3b8..3a30173316e46 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -118,6 +118,7 @@ import { isIndexSignatureDeclaration, isInterfaceDeclaration, isInternalDeclaration, + isJSDocImportTypeTag, isJsonSourceFile, isLateVisibilityPaintedStatement, isLiteralImportTypeNode, @@ -1458,6 +1459,8 @@ export function transformDeclarations(context: TransformationContext) { } if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return; + if (isJSDocImportTypeTag(input)) return; + // Elide implementation signatures from overload sets if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 48d8e2d01bb94..5512e0c7712c7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -447,6 +447,7 @@ export const enum SyntaxKind { JSDocPropertyTag, JSDocThrowsTag, JSDocSatisfiesTag, + JSDocImportTypeTag, // Synthesized list SyntaxList, @@ -489,9 +490,9 @@ export const enum SyntaxKind { LastStatement = DebuggerStatement, FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, - LastJSDocNode = JSDocSatisfiesTag, + LastJSDocNode = JSDocImportTypeTag, FirstJSDocTagNode = JSDocTag, - LastJSDocTagNode = JSDocSatisfiesTag, + LastJSDocTagNode = JSDocImportTypeTag, /** @internal */ FirstContextualKeyword = AbstractKeyword, /** @internal */ LastContextualKeyword = OfKeyword, } @@ -1044,7 +1045,8 @@ export type ForEachChildNodes = | JSDocThrowsTag | JSDocOverrideTag | JSDocSatisfiesTag - | JSDocOverloadTag; + | JSDocOverloadTag + | JSDocImportTypeTag; /** @internal */ export type HasChildren = @@ -3654,7 +3656,7 @@ export type NamedExportBindings = // import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} export interface ImportClause extends NamedDeclaration { readonly kind: SyntaxKind.ImportClause; - readonly parent: ImportDeclaration; + readonly parent: ImportDeclaration | JSDocImportTypeTag; readonly isTypeOnly: boolean; readonly name?: Identifier; // Default binding readonly namedBindings?: NamedImportBindings; @@ -4065,6 +4067,13 @@ export interface JSDocSatisfiesExpression extends ParenthesizedExpression { readonly _jsDocSatisfiesExpressionBrand: never; } +export interface JSDocImportTypeTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImportTypeTag; + readonly parent: JSDoc; + readonly importClause: ImportClause; + readonly moduleSpecifier: Expression; +} + // NOTE: Ensure this is up-to-date with src/debug/debug.ts // dprint-ignore export const enum FlowFlags { @@ -5544,6 +5553,9 @@ export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitialize /** @internal */ export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; +/** @internal */ +export type AnyImportOrJsDocImportTypeImport = AnyImportSyntax | JSDocImportTypeTag; + /** @internal */ export type AliasDeclarationNode = | ImportEqualsDeclaration @@ -5599,7 +5611,7 @@ export interface RequireVariableDeclarationList extends VariableDeclarationList /** @internal */ export type LateVisibilityPaintedStatement = - | AnyImportSyntax + | AnyImportOrJsDocImportTypeImport | VariableStatement | ClassDeclaration | FunctionDeclaration @@ -8806,6 +8818,8 @@ export interface NodeFactory { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; + createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag; + updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f9ec2c9b48639..ee94ea45d6346 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -356,6 +356,7 @@ import { JSDocArray, JSDocCallbackTag, JSDocEnumTag, + JSDocImportTypeTag, JSDocMemberName, JSDocOverloadTag, JSDocParameterTag, @@ -3985,13 +3986,14 @@ export function isFunctionSymbol(symbol: Symbol | undefined) { } /** @internal */ -export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode): StringLiteralLike | undefined { +export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode | JSDocImportTypeTag): StringLiteralLike | undefined { switch (node.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: + case SyntaxKind.JSDocImportTypeTag: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike); @@ -4034,10 +4036,11 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal } /** @internal */ -export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration): Expression | undefined { +export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration | JSDocImportTypeTag): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: + case SyntaxKind.JSDocImportTypeTag: return node.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined; diff --git a/src/services/codefixes/convertToTypeOnlyImport.ts b/src/services/codefixes/convertToTypeOnlyImport.ts index 43ebf3e7ac6bc..d9a0d23051d45 100644 --- a/src/services/codefixes/convertToTypeOnlyImport.ts +++ b/src/services/codefixes/convertToTypeOnlyImport.ts @@ -37,8 +37,8 @@ registerCodeFix({ const declaration = getDeclaration(context.sourceFile, context.span.start); if (declaration) { const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declaration)); - const importDeclarationChanges = declaration.kind === SyntaxKind.ImportSpecifier && canConvertImportDeclarationForSpecifier(declaration, context.sourceFile, context.program) - ? textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declaration.parent.parent.parent)) + const importDeclarationChanges = declaration.kind === SyntaxKind.ImportSpecifier && isImportDeclaration(declaration.parent.parent.parent) && canConvertImportDeclarationForSpecifier(declaration, context.sourceFile, context.program) + ? textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declaration.parent.parent.parent as ImportDeclaration)) : undefined; const mainAction = createCodeFixAction( fixId, @@ -71,6 +71,7 @@ registerCodeFix({ } else if ( errorDeclaration?.kind === SyntaxKind.ImportSpecifier + && isImportDeclaration(errorDeclaration.parent.parent.parent) && !fixedImportDeclarations.has(errorDeclaration.parent.parent.parent) && canConvertImportDeclarationForSpecifier(errorDeclaration, diag.file, context.program) ) { diff --git a/src/services/codefixes/useDefaultImport.ts b/src/services/codefixes/useDefaultImport.ts index 92ef84495a7bb..11d647517593a 100644 --- a/src/services/codefixes/useDefaultImport.ts +++ b/src/services/codefixes/useDefaultImport.ts @@ -7,6 +7,7 @@ import { Identifier, isExternalModuleReference, isIdentifier, + isImportDeclaration, isImportEqualsDeclaration, isNamespaceImport, makeImport, @@ -51,7 +52,7 @@ function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { if (isImportEqualsDeclaration(parent) && isExternalModuleReference(parent.moduleReference)) { return { importNode: parent, name, moduleSpecifier: parent.moduleReference.expression }; } - else if (isNamespaceImport(parent)) { + else if (isNamespaceImport(parent) && isImportDeclaration(parent.parent.parent)) { const importNode = parent.parent.parent; return { importNode, name, moduleSpecifier: importNode.moduleSpecifier }; } diff --git a/src/services/completions.ts b/src/services/completions.ts index 349d4066b8059..14c001ca36e0f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -188,6 +188,7 @@ import { isJSDoc, isJSDocAugmentsTag, isJSDocImplementsTag, + isJSDocImportTypeTag, isJSDocParameterTag, isJSDocTag, isJSDocTemplateTag, @@ -255,6 +256,7 @@ import { isVariableDeclaration, isVariableLike, JsDoc, + JSDocImportTypeTag, JSDocParameterTag, JSDocPropertyTag, JSDocReturnTag, @@ -5708,9 +5710,9 @@ function getImportStatementCompletionInfo(contextToken: Node, sourceFile: Source } } -function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | Token | undefined) { +function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | JSDocImportTypeTag | Token | undefined) { if (!node) return undefined; - const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)) ?? node; + const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration, isJSDocImportTypeTag)) ?? node; const sourceFile = top.getSourceFile(); if (rangeIsOnSingleLine(top, sourceFile)) { return createTextSpanFromNode(top, sourceFile); @@ -5719,7 +5721,7 @@ function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclara Debug.assert(top.kind !== SyntaxKind.ImportKeyword && top.kind !== SyntaxKind.ImportSpecifier); // Guess which point in the import might actually be a later statement parsed as part of the import // during parser recovery - either in the middle of named imports, or the module specifier. - const potentialSplitPoint = top.kind === SyntaxKind.ImportDeclaration + const potentialSplitPoint = top.kind === SyntaxKind.ImportDeclaration || top.kind === SyntaxKind.JSDocImportTypeTag ? getPotentiallyInvalidImportSpecifier(top.importClause?.namedBindings) ?? top.moduleSpecifier : top.moduleReference; const withoutModuleSpecifier: TextRange = { diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index 5e6ac06ec846d..55a19ef6f471e 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -42,6 +42,7 @@ import { SymbolFlags, SyntaxKind, textChanges, + tryCast, TypeChecker, } from "../_namespaces/ts"; import { @@ -188,7 +189,9 @@ function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, name === propertyName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name))); }); - const importDecl = toConvert.parent.parent; + const importDecl = tryCast(toConvert.parent.parent, isImportDeclaration); + Debug.assert(importDecl, "Unexpected declaration"); + if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) { // Need to leave the namespace import alone changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); @@ -209,7 +212,10 @@ function getLeftOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: P /** @internal */ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault = getShouldUseDefault(program, toConvert.parent)): void { const checker = program.getTypeChecker(); - const importDecl = toConvert.parent.parent; + const importDecl = tryCast(toConvert.parent.parent, isImportDeclaration); + if (importDecl === undefined) { + Debug.assert(importDecl, "Unexpected declaration"); + } const { moduleSpecifier } = importDecl; const toConvertSymbols = new Set(); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 0b2072f449008..59663726b11ef 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -257,6 +257,7 @@ import { isWhiteSpaceSingleLine, isYieldExpression, IterationStatement, + JSDocImportTypeTag, JSDocLink, JSDocLinkCode, JSDocLinkDisplayPart, @@ -1244,7 +1245,7 @@ function getAdjustedLocationForDeclaration(node: Node, forRename: boolean) { } } -function getAdjustedLocationForImportDeclaration(node: ImportDeclaration, forRename: boolean) { +function getAdjustedLocationForImportDeclaration(node: ImportDeclaration | JSDocImportTypeTag, forRename: boolean) { if (node.importClause) { if (node.importClause.name && node.importClause.namedBindings) { // do not adjust if we have both a name and named bindings diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 100081fb8cccf..78fdabc94c120 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4542,12 +4542,13 @@ declare namespace ts { JSDocPropertyTag = 355, JSDocThrowsTag = 356, JSDocSatisfiesTag = 357, - SyntaxList = 358, - NotEmittedStatement = 359, - PartiallyEmittedExpression = 360, - CommaListExpression = 361, - SyntheticReferenceExpression = 362, - Count = 363, + JSDocImportTypeTag = 358, + SyntaxList = 359, + NotEmittedStatement = 360, + PartiallyEmittedExpression = 361, + CommaListExpression = 362, + SyntheticReferenceExpression = 363, + Count = 364, FirstAssignment = 64, LastAssignment = 79, FirstCompoundAssignment = 65, @@ -4576,9 +4577,9 @@ declare namespace ts { LastStatement = 259, FirstNode = 166, FirstJSDocNode = 316, - LastJSDocNode = 357, + LastJSDocNode = 358, FirstJSDocTagNode = 334, - LastJSDocTagNode = 357, + LastJSDocTagNode = 358, } type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -6028,7 +6029,7 @@ declare namespace ts { type NamedExportBindings = NamespaceExport | NamedExports; interface ImportClause extends NamedDeclaration { readonly kind: SyntaxKind.ImportClause; - readonly parent: ImportDeclaration; + readonly parent: ImportDeclaration | JSDocImportTypeTag; readonly isTypeOnly: boolean; readonly name?: Identifier; readonly namedBindings?: NamedImportBindings; @@ -6384,6 +6385,12 @@ declare namespace ts { readonly kind: SyntaxKind.JSDocSatisfiesTag; readonly typeExpression: JSDocTypeExpression; } + interface JSDocImportTypeTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImportTypeTag; + readonly parent: JSDoc; + readonly importClause: ImportClause; + readonly moduleSpecifier: Expression; + } enum FlowFlags { Unreachable = 1, Start = 2, @@ -8348,6 +8355,8 @@ declare namespace ts { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; + createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag; + updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; @@ -9575,6 +9584,7 @@ declare namespace ts { function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag; function isJSDocSatisfiesTag(node: Node): node is JSDocSatisfiesTag; function isJSDocThrowsTag(node: Node): node is JSDocThrowsTag; + function isJSDocImportTypeTag(node: Node): node is JSDocImportTypeTag; function isQuestionOrExclamationToken(node: Node): node is QuestionToken | ExclamationToken; function isIdentifierOrThisTypeNode(node: Node): node is Identifier | ThisTypeNode; function isReadonlyKeywordOrPlusOrMinusToken(node: Node): node is ReadonlyKeyword | PlusToken | MinusToken; diff --git a/tests/baselines/reference/importTypeTag1.symbols b/tests/baselines/reference/importTypeTag1.symbols new file mode 100644 index 0000000000000..ededafd16bb9a --- /dev/null +++ b/tests/baselines/reference/importTypeTag1.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag1.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 11)) + diff --git a/tests/baselines/reference/importTypeTag1.types b/tests/baselines/reference/importTypeTag1.types new file mode 100644 index 0000000000000..f9b8235b61900 --- /dev/null +++ b/tests/baselines/reference/importTypeTag1.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag1.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTypeTag2.symbols b/tests/baselines/reference/importTypeTag2.symbols new file mode 100644 index 0000000000000..1839c87046897 --- /dev/null +++ b/tests/baselines/reference/importTypeTag2.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag2.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @importType * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 18)) + diff --git a/tests/baselines/reference/importTypeTag2.types b/tests/baselines/reference/importTypeTag2.types new file mode 100644 index 0000000000000..4bc8720e60755 --- /dev/null +++ b/tests/baselines/reference/importTypeTag2.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag2.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @importType * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} +>f : (foo: types.Foo) => void +>foo : types.Foo + diff --git a/tests/baselines/reference/importTypeTag3.symbols b/tests/baselines/reference/importTypeTag3.symbols new file mode 100644 index 0000000000000..fa49c3ada1727 --- /dev/null +++ b/tests/baselines/reference/importTypeTag3.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag3.ts] //// + +=== /types.ts === +export default interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 30)) +} + +=== /foo.js === +/** + * @importType Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 18)) + diff --git a/tests/baselines/reference/importTypeTag3.types b/tests/baselines/reference/importTypeTag3.types new file mode 100644 index 0000000000000..52c525116d7cd --- /dev/null +++ b/tests/baselines/reference/importTypeTag3.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag3.ts] //// + +=== /types.ts === +export default interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @importType Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTypeTag4.errors.txt b/tests/baselines/reference/importTypeTag4.errors.txt new file mode 100644 index 0000000000000..afabc669d2632 --- /dev/null +++ b/tests/baselines/reference/importTypeTag4.errors.txt @@ -0,0 +1,27 @@ +/foo.js(2,18): error TS2300: Duplicate identifier 'Foo'. +/foo.js(6,18): error TS2300: Duplicate identifier 'Foo'. + + +==== /types.ts (0 errors) ==== + export interface Foo { + a: number; + } + +==== /foo.js (2 errors) ==== + /** + * @importType { Foo } from "./types" + ~~~ +!!! error TS2300: Duplicate identifier 'Foo'. + */ + + /** + * @importType { Foo } from "./types" + ~~~ +!!! error TS2300: Duplicate identifier 'Foo'. + */ + + /** + * @param { Foo } foo + */ + function f(foo) {} + \ No newline at end of file diff --git a/tests/baselines/reference/importTypeTag4.symbols b/tests/baselines/reference/importTypeTag4.symbols new file mode 100644 index 0000000000000..6da33eedc913c --- /dev/null +++ b/tests/baselines/reference/importTypeTag4.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag4.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 11, 11)) + diff --git a/tests/baselines/reference/importTypeTag4.types b/tests/baselines/reference/importTypeTag4.types new file mode 100644 index 0000000000000..d7cb442b86362 --- /dev/null +++ b/tests/baselines/reference/importTypeTag4.types @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag4.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTypeTag5.js b/tests/baselines/reference/importTypeTag5.js new file mode 100644 index 0000000000000..6c001af0780c7 --- /dev/null +++ b/tests/baselines/reference/importTypeTag5.js @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// + +//// [types.ts] +export interface Foo { + a: number; +} + +//// [foo.js] +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} + + + + +//// [types.d.ts] +export interface Foo { + a: number; +} +//// [foo.d.ts] +/** + * @importType { Foo } from "./types" + */ +/** + * @param { Foo } foo + */ +declare function f(foo: import("./types").Foo): void; diff --git a/tests/baselines/reference/importTypeTag5.symbols b/tests/baselines/reference/importTypeTag5.symbols new file mode 100644 index 0000000000000..faac6b1a6c300 --- /dev/null +++ b/tests/baselines/reference/importTypeTag5.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 11)) + diff --git a/tests/baselines/reference/importTypeTag5.types b/tests/baselines/reference/importTypeTag5.types new file mode 100644 index 0000000000000..9595271509c2b --- /dev/null +++ b/tests/baselines/reference/importTypeTag5.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/cases/conformance/jsdoc/importTypeTag1.ts b/tests/cases/conformance/jsdoc/importTypeTag1.ts new file mode 100644 index 0000000000000..c4ea7011276f8 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTypeTag1.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag2.ts b/tests/cases/conformance/jsdoc/importTypeTag2.ts new file mode 100644 index 0000000000000..0d095b79d5e9b --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTypeTag2.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @importType * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag3.ts b/tests/cases/conformance/jsdoc/importTypeTag3.ts new file mode 100644 index 0000000000000..f081e451772d9 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTypeTag3.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export default interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @importType Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag4.ts b/tests/cases/conformance/jsdoc/importTypeTag4.ts new file mode 100644 index 0000000000000..d0d76cc1d4c03 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTypeTag4.ts @@ -0,0 +1,22 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @importType { Foo } from "./types" + */ + +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag5.ts b/tests/cases/conformance/jsdoc/importTypeTag5.ts new file mode 100644 index 0000000000000..48ffe0a77a822 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTypeTag5.ts @@ -0,0 +1,19 @@ +// @checkJs: true +// @allowJs: true +// @declaration: true +// @emitDeclarationOnly: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @importType { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} From b67cba6864699fbdad69b5e8fb2dc15b342d0c6a Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Mon, 29 Jan 2024 18:49:06 +0200 Subject: [PATCH 02/23] add jsdocImportTypeTag parsing tests --- src/compiler/parser.ts | 2 +- src/testRunner/unittests/jsDocParsing.ts | 28 +++++++ ...mments.parsesCorrectly.importTypeTag1.json | 54 +++++++++++++ ...mments.parsesCorrectly.importTypeTag2.json | 76 +++++++++++++++++++ ...mments.parsesCorrectly.importTypeTag3.json | 62 +++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7b372d7d665b9..15c88977fa675 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9458,7 +9458,7 @@ namespace Parser { } function parseImportTypeTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTypeTag { - const afterImportTypeTagPos = scanner.getTokenEnd(); + const afterImportTypeTagPos = scanner.getTokenFullStart(); let identifier: Identifier | undefined; if (isIdentifier()) { diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index 56ba3a9cc05eb..62bfb8eebe9f4 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -204,6 +204,34 @@ describe("unittests:: JSDocParsing", () => { */`, ); + parsesCorrectly( + "importTypeTag1", + `/** + * @importType foo from 'foo' + */`, + ); + + parsesCorrectly( + "importTypeTag2", + `/** + * @importType { foo } from 'foo' + */`, + ); + + parsesCorrectly( + "importTypeTag3", + `/** + * @importType * as types from 'foo' + */`, + ); + + parsesCorrectly( + "importTypeTag3", + `/** + * @importType * as types from 'foo' comment part + */`, + ); + parsesCorrectly( "returnTag1", `/** diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json new file mode 100644 index 0000000000000..f2f67264e6d0c --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json @@ -0,0 +1,54 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 39, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTypeTag", + "pos": 8, + "end": 34, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "importType" + }, + "importClause": { + "kind": "ImportClause", + "pos": 20, + "end": 23, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "name": { + "kind": "Identifier", + "pos": 20, + "end": 23, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "foo" + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 28, + "end": 34, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 34, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json new file mode 100644 index 0000000000000..fc388e6f3f4a7 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json @@ -0,0 +1,76 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 43, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTypeTag", + "pos": 8, + "end": 38, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "importType" + }, + "importClause": { + "kind": "ImportClause", + "pos": 20, + "end": 27, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamedImports", + "pos": 20, + "end": 27, + "modifierFlagsCache": 0, + "transformFlags": 0, + "elements": { + "0": { + "kind": "ImportSpecifier", + "pos": 21, + "end": 25, + "modifierFlagsCache": 0, + "transformFlags": 0, + "isTypeOnly": false, + "name": { + "kind": "Identifier", + "pos": 21, + "end": 25, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "foo" + } + }, + "length": 1, + "pos": 21, + "end": 25, + "hasTrailingComma": false, + "transformFlags": 0 + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 32, + "end": 38, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 38, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json new file mode 100644 index 0000000000000..51beb502ee7e4 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json @@ -0,0 +1,62 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 59, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTypeTag", + "pos": 8, + "end": 57, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "importType" + }, + "comment": "comment part", + "importClause": { + "kind": "ImportClause", + "pos": 20, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamespaceImport", + "pos": 20, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "name": { + "kind": "Identifier", + "pos": 24, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "types" + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 35, + "end": 41, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 57, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file From fc4ac15a3ce791bb0342d76ec3f23762dc40de73 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Mon, 29 Jan 2024 19:57:12 +0200 Subject: [PATCH 03/23] update baseline --- src/testRunner/unittests/jsDocParsing.ts | 2 +- ...mments.parsesCorrectly.importTypeTag3.json | 7 +-- ...mments.parsesCorrectly.importTypeTag4.json | 62 +++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index 62bfb8eebe9f4..a6beadc076e3d 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -226,7 +226,7 @@ describe("unittests:: JSDocParsing", () => { ); parsesCorrectly( - "importTypeTag3", + "importTypeTag4", `/** * @importType * as types from 'foo' comment part */`, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json index 51beb502ee7e4..b398a4d3d5a89 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json @@ -1,7 +1,7 @@ { "kind": "JSDoc", "pos": 0, - "end": 59, + "end": 46, "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, @@ -9,7 +9,7 @@ "0": { "kind": "JSDocImportTypeTag", "pos": 8, - "end": 57, + "end": 41, "modifierFlagsCache": 0, "transformFlags": 0, "tagName": { @@ -20,7 +20,6 @@ "transformFlags": 0, "escapedText": "importType" }, - "comment": "comment part", "importClause": { "kind": "ImportClause", "pos": 20, @@ -55,7 +54,7 @@ }, "length": 1, "pos": 8, - "end": 57, + "end": 41, "hasTrailingComma": false, "transformFlags": 0 } diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json new file mode 100644 index 0000000000000..51beb502ee7e4 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json @@ -0,0 +1,62 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 59, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTypeTag", + "pos": 8, + "end": 57, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "importType" + }, + "comment": "comment part", + "importClause": { + "kind": "ImportClause", + "pos": 20, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamespaceImport", + "pos": 20, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "name": { + "kind": "Identifier", + "pos": 24, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "types" + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 35, + "end": 41, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 57, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file From df23ce36d36c15f01ffa75827057926841284c0e Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Tue, 30 Jan 2024 01:33:15 +0200 Subject: [PATCH 04/23] add jsdoc import type tag go to definition tests --- src/services/jsDoc.ts | 1 + src/services/utilities.ts | 2 + ...finitionJsDocImportTypeTag1.baseline.jsonc | 17 ++ ...finitionJsDocImportTypeTag2.baseline.jsonc | 5 + ...finitionJsDocImportTypeTag3.baseline.jsonc | 5 + ...finitionJsDocImportTypeTag4.baseline.jsonc | 20 ++ ...finitionJsDocImportTypeTag5.baseline.jsonc | 25 ++ ...docParameterTagSnippetCompletion1.baseline | 238 ++++++++++++++++++ ...docParameterTagSnippetCompletion2.baseline | 70 ++++++ ...docParameterTagSnippetCompletion3.baseline | 84 +++++++ .../goToDefinitionJsDocImportTypeTag1.ts | 14 ++ .../goToDefinitionJsDocImportTypeTag2.ts | 14 ++ .../goToDefinitionJsDocImportTypeTag3.ts | 14 ++ .../goToDefinitionJsDocImportTypeTag4.ts | 14 ++ .../goToDefinitionJsDocImportTypeTag5.ts | 19 ++ .../jsdocImportTypeTagCompletion1.ts | 13 + 16 files changed, 555 insertions(+) create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts create mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 6f387271048dc..a30641e8cc06c 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -131,6 +131,7 @@ const jsDocTagNames = [ "host", "ignore", "implements", + "importType", "inheritdoc", "inner", "instance", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 59663726b11ef..04ef6e85ca400 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -187,6 +187,7 @@ import { isInternalModuleImportEqualsDeclaration, isJSDoc, isJSDocCommentContainingNode, + isJSDocImportTypeTag, isJSDocLink, isJSDocLinkCode, isJSDocLinkLike, @@ -2574,6 +2575,7 @@ export function isModuleSpecifierLike(node: Node): node is StringLiteralLike { return isStringLiteralLike(node) && ( isExternalModuleReference(node.parent) || isImportDeclaration(node.parent) || + isJSDocImportTypeTag(node.parent) || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node || isImportCall(node.parent) && node.parent.arguments[0] === node ); diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc new file mode 100644 index 0000000000000..dcdf4ade81eed --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToDefinition === +// === /b.ts === +// [||]export interface A { } + +// === /a.js === +// /** +// * @importType { A } from [|"./b/*GOTO DEF*/"|] +// */ + + // === Details === + [ + { + "kind": "script", + "name": "./b", + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc new file mode 100644 index 0000000000000..450a58c2c9e0d --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc @@ -0,0 +1,5 @@ +// === goToDefinition === +// === /a.js === +// /** +// * @importType { A } from/*GOTO DEF*/ "./b" +// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc new file mode 100644 index 0000000000000..4c2ef9da7fb74 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc @@ -0,0 +1,5 @@ +// === goToDefinition === +// === /a.js === +// /** +// * @importType { A } from /*GOTO DEF*/ "./b"; +// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc new file mode 100644 index 0000000000000..b5dc8296bbe76 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc @@ -0,0 +1,20 @@ +// === goToDefinition === +// === /b.ts === +// <|export interface [|A|] { }|> + +// === /a.js === +// /** +// * @importType { [|A|]/*GOTO DEF*/ } from "./b"; +// */ + + // === Details === + [ + { + "kind": "interface", + "name": "A", + "containerName": "\"/b\"", + "isLocal": false, + "isAmbient": false, + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc new file mode 100644 index 0000000000000..1cf7ba59f4b27 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc @@ -0,0 +1,25 @@ +// === goToDefinition === +// === /b.ts === +// <|export interface [|A|] { }|> + +// === /a.js === +// /** +// * @importType { A } from "./b"; +// */ +// +// /** +// * @param { [|A|]/*GOTO DEF*/ } a +// */ +// function f(a) {} + + // === Details === + [ + { + "kind": "interface", + "name": "A", + "containerName": "\"/b\"", + "isLocal": false, + "isAmbient": false, + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline index 970b5ae25841e..52be28e24ed64 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline @@ -40,6 +40,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -136,6 +137,7 @@ // | @host // | @ignore // | @implements +// | @importType // | @inheritdoc // | @inner // | @instance @@ -229,6 +231,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -327,6 +330,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -427,6 +431,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -522,6 +527,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -618,6 +624,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -714,6 +721,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -809,6 +817,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -905,6 +914,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -998,6 +1008,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1092,6 +1103,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1186,6 +1198,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1279,6 +1292,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1374,6 +1388,7 @@ // | @host // | @ignore // | @implements +// | @importType // | @inheritdoc // | @inner // | @instance @@ -1467,6 +1482,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1562,6 +1578,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -2096,6 +2113,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -3215,6 +3245,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -4334,6 +4377,19 @@ ], "documentation": [] }, + { + "name": "@importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@inheritdoc", "kind": "", @@ -5440,6 +5496,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -6546,6 +6615,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -7652,6 +7734,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -8771,6 +8866,19 @@ ], "documentation": [] }, + { + "name": "@importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@inheritdoc", "kind": "", @@ -9877,6 +9985,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -10983,6 +11104,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -12089,6 +12223,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -13195,6 +13342,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -14301,6 +14461,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -15407,6 +15580,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -16513,6 +16699,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -17632,6 +17831,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -18738,6 +18950,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -19844,6 +20069,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline index 0e8cc9b8ceed1..d58ae8143f038 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline @@ -40,6 +40,7 @@ // | @host // | @ignore // | @implements +// | @importType // | @inheritdoc // | @inner // | @instance @@ -133,6 +134,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -231,6 +233,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -323,6 +326,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -416,6 +420,7 @@ // | @host // | @ignore // | @implements +// | @importType // | @inheritdoc // | @inner // | @instance @@ -948,6 +953,19 @@ ], "documentation": [] }, + { + "name": "@importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@inheritdoc", "kind": "", @@ -2056,6 +2074,19 @@ ], "documentation": [] }, + { + "name": "@importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@inheritdoc", "kind": "", @@ -3164,6 +3195,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -4272,6 +4316,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -5380,6 +5437,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline index 31809167ab0f8..28d7cdbd961d3 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline @@ -40,6 +40,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -131,6 +132,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -223,6 +225,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -318,6 +321,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -413,6 +417,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -506,6 +511,7 @@ // | host // | ignore // | implements +// | importType // | inheritdoc // | inner // | instance @@ -1039,6 +1045,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -2145,6 +2164,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -3251,6 +3283,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -4357,6 +4402,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -5463,6 +5521,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", @@ -6569,6 +6640,19 @@ ], "documentation": [] }, + { + "name": "importType", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "importType", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "inheritdoc", "kind": "", diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts new file mode 100644 index 0000000000000..393e3f13223df --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @importType { A } from [|"./b/*1*/"|] +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts new file mode 100644 index 0000000000000..18ef0717769bd --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @importType { A } [|from/*1*/|] "./b" +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts new file mode 100644 index 0000000000000..6ef9cc078a055 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @importType { A } [|from /*1*/|] "./b"; +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts new file mode 100644 index 0000000000000..b2ead0b378e82 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface /*2*/A { } + +// @Filename: /a.js +/////** +//// * @importType { [|A/*1*/|] } from "./b"; +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts new file mode 100644 index 0000000000000..3c374a79b52bb --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface /*2*/A { } + +// @Filename: /a.js +/////** +//// * @importType { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/*1*/|] } a +//// */ +////function f(a) {} + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts new file mode 100644 index 0000000000000..0ef03d9f18263 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts @@ -0,0 +1,13 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @filename: /a.js +/////** +//// * @/**/ +//// */ + +verify.completions( + { marker: "", includes: ["importType"] }, +); From 0b0029dc934f5b5e5d75ed9290abdf4a47967ee0 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Tue, 30 Jan 2024 17:35:13 +0200 Subject: [PATCH 05/23] jsdoc import type completions --- src/compiler/checker.ts | 1 + src/services/completions.ts | 39 ++++++++------ src/services/stringCompletions.ts | 1 + .../jsdocImportTypeTagCompletion2.baseline | 48 +++++++++++++++++ .../jsdocImportTypeTagCompletion3.baseline | 51 +++++++++++++++++++ .../jsdocImportTypeTagCompletion2.ts | 14 +++++ .../jsdocImportTypeTagCompletion3.ts | 18 +++++++ 7 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline create mode 100644 tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline create mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts create mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fb0565e4897be..9cef39709e62e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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) ) { diff --git a/src/services/completions.ts b/src/services/completions.ts index 14c001ca36e0f..1bc9adb2e414b 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -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)) { @@ -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."); @@ -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!; @@ -3922,6 +3928,7 @@ function getCompletionData( function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression + || insideJsDocImportTypeTag || !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent) || !isContextTokenValueLocation(contextToken) && (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 1c0339f7c1488..72b8a0b3832ed 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -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*/"); diff --git a/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline b/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline new file mode 100644 index 0000000000000..6905eacdea1b1 --- /dev/null +++ b/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline @@ -0,0 +1,48 @@ +// === Completions === +=== /b.js === +// /** +// * @importType { } from "./a" +// ^ +// | ---------------------------------------------------------------------- +// | interface A +// | ---------------------------------------------------------------------- +// */ + +[ + { + "marker": { + "fileName": "/b.js", + "position": 21, + "name": "" + }, + "item": { + "flags": 0, + "isGlobalCompletion": false, + "isMemberCompletion": true, + "isNewIdentifierLocation": false, + "entries": [ + { + "name": "A", + "kind": "interface", + "kindModifiers": "export", + "sortText": "11", + "displayParts": [ + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "interfaceName" + } + ], + "documentation": [] + } + ] + } + } +] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline b/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline new file mode 100644 index 0000000000000..665cbf11fbdcc --- /dev/null +++ b/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline @@ -0,0 +1,51 @@ +// === Completions === +=== /tests/cases/fourslash/./c.js === +// /** +// * @importType * as types from "./" +// ^ +// | ---------------------------------------------------------------------- +// | a +// | b +// | ---------------------------------------------------------------------- +// */ + +[ + { + "marker": { + "fileName": "/tests/cases/fourslash/./c.js", + "position": 38, + "name": "" + }, + "item": { + "isGlobalCompletion": false, + "isMemberCompletion": false, + "isNewIdentifierLocation": true, + "entries": [ + { + "name": "a", + "kind": "script", + "kindModifiers": ".ts", + "sortText": "11", + "displayParts": [ + { + "text": "a", + "kind": "text" + } + ] + }, + { + "name": "b", + "kind": "script", + "kindModifiers": ".ts", + "sortText": "11", + "displayParts": [ + { + "text": "b", + "kind": "text" + } + ] + } + ] + } + } +] \ No newline at end of file diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts new file mode 100644 index 0000000000000..14d9701627026 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @filename: /a.ts +////export interface A {} + +// @filename: /b.js +/////** +//// * @importType { /**/ } from "./a" +//// */ + +verify.baselineCompletions(); diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts new file mode 100644 index 0000000000000..7c0e7ad0998e2 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts @@ -0,0 +1,18 @@ +/// + +// @allowJS: true +// @checkJs: true +// @module: esnext + +// @filename: ./a.ts +////export interface A {} + +// @filename: ./b.ts +////export interface B {} + +// @filename: ./c.js +/////** +//// * @importType * as types from ".//**/" +//// */ + +verify.baselineCompletions(); From 0a20ad3154f4d1a7a3da37f9a9c51d2a4cabb5db Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 31 Jan 2024 00:56:58 +0200 Subject: [PATCH 06/23] jsdoc import type find-all-refs/rename --- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 3 +- src/services/importTracker.ts | 6 +- ...ndAllRefsJsDocImportTypeTag.baseline.jsonc | 105 ++++++++++++++++++ .../renameJsDocImportTypeTag.baseline.jsonc | 10 ++ .../findAllRefsJsDocImportTypeTag.ts | 19 ++++ .../fourslash/renameJsDocImportTypeTag.ts | 19 ++++ 7 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc create mode 100644 tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc create mode 100644 tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts create mode 100644 tests/cases/fourslash/renameJsDocImportTypeTag.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5512e0c7712c7..3f542b5b4d1d9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5586,7 +5586,7 @@ export interface ValidImportTypeNode extends ImportTypeNode { /** @internal */ export type AnyValidImportOrReExport = - | (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral; } + | (ImportDeclaration | ExportDeclaration | JSDocImportTypeTag) & { moduleSpecifier: StringLiteral; } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral; }; } | RequireOrImportCall | ValidImportTypeNode; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ee94ea45d6346..71f88d89f54e7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4022,6 +4022,7 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal switch (node.parent.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: + case SyntaxKind.JSDocImportTypeTag: return node.parent as AnyValidImportOrReExport; case SyntaxKind.ExternalModuleReference: return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport; @@ -4070,7 +4071,7 @@ export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqua } /** @internal */ -export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { +export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration | JSDocImportTypeTag): boolean { return node.kind === SyntaxKind.ImportDeclaration && !!node.importClause && !!node.importClause.name; } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index b0e7215625e12..b8dc5758def9f 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -57,6 +57,7 @@ import { isVariableDeclaration, isVariableDeclarationInitializedToBareOrAccessedRequire, isVariableStatement, + JSDocImportTypeTag, ModifierFlags, ModuleBlock, ModuleDeclaration, @@ -138,7 +139,7 @@ interface AmbientModuleDeclaration extends ModuleDeclaration { } type SourceFileLike = SourceFile | AmbientModuleDeclaration; // Identifier for the case of `const x = require("y")`. -type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier; +type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier | JSDocImportTypeTag; type ImporterOrCallExpression = Importer | CallExpression; /** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */ @@ -215,6 +216,7 @@ function getImportersForExport( break; case SyntaxKind.ImportDeclaration: + case SyntaxKind.JSDocImportTypeTag: directImports.push(direct); const namedBindings = direct.importClause && direct.importClause.namedBindings; if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { @@ -267,7 +269,7 @@ function getImportersForExport( }); } - function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { + function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration | JSDocImportTypeTag, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { if (exportKind === ExportKind.ExportEquals) { // This is a direct import, not import-as-namespace. if (!alreadyAddedDirect) directImports.push(importDeclaration); diff --git a/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc b/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc new file mode 100644 index 0000000000000..7310f74b390b5 --- /dev/null +++ b/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc @@ -0,0 +1,105 @@ +// === findAllReferences === +// === /a.js === +// /** +// * <|@importType { [|{| defId: 0, isWriteAccess: true |}A|] } from "./b"; +// |>*/ +// +// /** +// * @param { [|{| defId: 0 |}A|]/*FIND ALL REFS*/ } a +// */ +// function f(a) {} + +// === /b.ts === +// <|export interface [|{| defId: 1, isWriteAccess: true |}A|] { }|> + + // === Definitions === + // === /a.js === + // /** + // * <|@importType { [|{| defId: 0 |}A|] } from "./b"; + // |>*/ + // + // /** + // * @param { A/*FIND ALL REFS*/ } a + // */ + // function f(a) {} + + // === /b.ts === + // <|export interface [|{| defId: 1 |}A|] { }|> + + // === Details === + [ + { + "defId": 0, + "containerKind": "", + "containerName": "", + "kind": "alias", + "name": "(alias) interface A\nimport A", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "alias", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "aliasName" + }, + { + "text": "\n", + "kind": "lineBreak" + }, + { + "text": "import", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "aliasName" + } + ] + }, + { + "defId": 1, + "containerKind": "", + "containerName": "", + "kind": "interface", + "name": "interface A", + "displayParts": [ + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "interfaceName" + } + ] + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc b/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc new file mode 100644 index 0000000000000..89d16ef43ae38 --- /dev/null +++ b/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc @@ -0,0 +1,10 @@ +// === findRenameLocations === +// === /a.js === +// /** +// * <|@importType { /*START PREFIX*/A as [|ARENAME|] } from "./b"; +// |>*/ +// +// /** +// * @param { [|ARENAME|]/*RENAME*/ } a +// */ +// function f(a) {} \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts b/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts new file mode 100644 index 0000000000000..2918fd59c1caf --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface A { } + +// @Filename: /a.js +/////** +//// * @importType { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/**/|] } a +//// */ +////function f(a) {} + +verify.baselineFindAllReferences(""); diff --git a/tests/cases/fourslash/renameJsDocImportTypeTag.ts b/tests/cases/fourslash/renameJsDocImportTypeTag.ts new file mode 100644 index 0000000000000..dbd09f2ae7ff5 --- /dev/null +++ b/tests/cases/fourslash/renameJsDocImportTypeTag.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface A { } + +// @Filename: /a.js +/////** +//// * @importType { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/**/|] } a +//// */ +////function f(a) {} + +verify.baselineRename(""); From 386120f00f5505bbe0b72798614efda813d71e64 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 1 Feb 2024 01:58:12 +0200 Subject: [PATCH 07/23] rename importType to import --- src/compiler/checker.ts | 16 +-- src/compiler/emitter.ts | 8 +- src/compiler/factory/nodeFactory.ts | 18 +-- src/compiler/factory/nodeTests.ts | 6 +- src/compiler/parser.ts | 20 ++-- src/compiler/program.ts | 6 +- src/compiler/transformers/declarations.ts | 4 +- src/compiler/types.ts | 24 ++-- src/compiler/utilities.ts | 14 +-- src/services/completions.ts | 22 ++-- src/services/importTracker.ts | 8 +- src/services/jsDoc.ts | 2 +- src/services/stringCompletions.ts | 2 +- src/services/utilities.ts | 8 +- src/testRunner/unittests/jsDocParsing.ts | 16 +-- ...mments.parsesCorrectly.importTypeTag1.json | 54 --------- ...mments.parsesCorrectly.importTypeTag2.json | 76 ------------- ...mments.parsesCorrectly.importTypeTag3.json | 61 ---------- ...mments.parsesCorrectly.importTypeTag4.json | 62 ----------- tests/baselines/reference/api/typescript.d.ts | 14 +-- ...ndAllRefsJsDocImportTypeTag.baseline.jsonc | 105 ------------------ ...finitionJsDocImportTypeTag1.baseline.jsonc | 17 --- ...finitionJsDocImportTypeTag2.baseline.jsonc | 5 - ...finitionJsDocImportTypeTag3.baseline.jsonc | 5 - ...finitionJsDocImportTypeTag4.baseline.jsonc | 20 ---- ...finitionJsDocImportTypeTag5.baseline.jsonc | 25 ----- .../reference/importTypeTag1.symbols | 22 ---- .../baselines/reference/importTypeTag1.types | 20 ---- .../reference/importTypeTag2.symbols | 22 ---- .../baselines/reference/importTypeTag2.types | 20 ---- .../reference/importTypeTag3.symbols | 22 ---- .../baselines/reference/importTypeTag3.types | 20 ---- .../reference/importTypeTag4.errors.txt | 27 ----- .../reference/importTypeTag4.symbols | 26 ----- .../baselines/reference/importTypeTag4.types | 24 ---- tests/baselines/reference/importTypeTag5.js | 32 ------ .../reference/importTypeTag5.symbols | 22 ---- .../baselines/reference/importTypeTag5.types | 20 ---- .../jsdocImportTypeTagCompletion2.baseline | 48 -------- .../jsdocImportTypeTagCompletion3.baseline | 51 --------- ...docParameterTagSnippetCompletion1.baseline | 102 ++++++++--------- ...docParameterTagSnippetCompletion2.baseline | 30 ++--- ...docParameterTagSnippetCompletion3.baseline | 36 +++--- .../renameJsDocImportTypeTag.baseline.jsonc | 10 -- .../cases/conformance/jsdoc/importTypeTag1.ts | 18 --- .../cases/conformance/jsdoc/importTypeTag2.ts | 18 --- .../cases/conformance/jsdoc/importTypeTag3.ts | 18 --- .../cases/conformance/jsdoc/importTypeTag4.ts | 22 ---- .../cases/conformance/jsdoc/importTypeTag5.ts | 19 ---- .../findAllRefsJsDocImportTypeTag.ts | 19 ---- .../goToDefinitionJsDocImportTypeTag1.ts | 14 --- .../goToDefinitionJsDocImportTypeTag2.ts | 14 --- .../goToDefinitionJsDocImportTypeTag3.ts | 14 --- .../goToDefinitionJsDocImportTypeTag4.ts | 14 --- .../goToDefinitionJsDocImportTypeTag5.ts | 19 ---- .../jsdocImportTypeTagCompletion1.ts | 13 --- .../jsdocImportTypeTagCompletion2.ts | 14 --- .../jsdocImportTypeTagCompletion3.ts | 18 --- .../fourslash/renameJsDocImportTypeTag.ts | 19 ---- 59 files changed, 178 insertions(+), 1247 deletions(-) delete mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json delete mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json delete mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json delete mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json delete mode 100644 tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc delete mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc delete mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc delete mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc delete mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc delete mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc delete mode 100644 tests/baselines/reference/importTypeTag1.symbols delete mode 100644 tests/baselines/reference/importTypeTag1.types delete mode 100644 tests/baselines/reference/importTypeTag2.symbols delete mode 100644 tests/baselines/reference/importTypeTag2.types delete mode 100644 tests/baselines/reference/importTypeTag3.symbols delete mode 100644 tests/baselines/reference/importTypeTag3.types delete mode 100644 tests/baselines/reference/importTypeTag4.errors.txt delete mode 100644 tests/baselines/reference/importTypeTag4.symbols delete mode 100644 tests/baselines/reference/importTypeTag4.types delete mode 100644 tests/baselines/reference/importTypeTag5.js delete mode 100644 tests/baselines/reference/importTypeTag5.symbols delete mode 100644 tests/baselines/reference/importTypeTag5.types delete mode 100644 tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline delete mode 100644 tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline delete mode 100644 tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc delete mode 100644 tests/cases/conformance/jsdoc/importTypeTag1.ts delete mode 100644 tests/cases/conformance/jsdoc/importTypeTag2.ts delete mode 100644 tests/cases/conformance/jsdoc/importTypeTag3.ts delete mode 100644 tests/cases/conformance/jsdoc/importTypeTag4.ts delete mode 100644 tests/cases/conformance/jsdoc/importTypeTag5.ts delete mode 100644 tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts delete mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts delete mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts delete mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts delete mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts delete mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts delete mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts delete mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts delete mode 100644 tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts delete mode 100644 tests/cases/fourslash/renameJsDocImportTypeTag.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9cef39709e62e..c0ccd62ad51a9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11,7 +11,7 @@ import { AmbientModuleDeclaration, and, AnonymousType, - AnyImportOrJsDocImportTypeImport, + AnyImportOrJsDocImport, AnyImportOrReExport, append, appendIfUnique, @@ -583,7 +583,7 @@ import { isJSDocCallbackTag, isJSDocConstructSignature, isJSDocFunctionType, - isJSDocImportTypeTag, + isJSDocImportTag, isJSDocIndexSignature, isJSDocLinkLike, isJSDocMemberName, @@ -771,7 +771,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -3944,7 +3944,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || (n === stopAt || isFunctionLike(n) && (!getImmediatelyInvokedFunctionExpression(n) || (getFunctionFlags(n) & FunctionFlags.AsyncGenerator)) ? "quit" : false)); } - function getAnyImportSyntax(node: Node): AnyImportOrJsDocImportTypeImport | undefined { + function getAnyImportSyntax(node: Node): AnyImportOrJsDocImport | undefined { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: return node as ImportEqualsDeclaration; @@ -4282,8 +4282,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration | JSDocImportTypeTag, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { - const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration | JSDocImportTypeTag).moduleSpecifier!; + function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration | JSDocImportTag, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { + const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration | JSDocImportTag).moduleSpecifier!; const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; if (!isIdentifier(name)) { @@ -5008,7 +5008,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? location : (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal || - (isInJSFile(location) && isJSDocImportTypeTag(location) ? location.moduleSpecifier : undefined) || + (isInJSFile(location) && isJSDocImportTag(location) ? location.moduleSpecifier : undefined) || (isVariableDeclaration(location) && location.initializer && isRequireCall(location.initializer, /*requireStringLiteralLikeArgument*/ true) ? location.initializer.arguments[0] : undefined) || findAncestor(location, isImportCall)?.arguments[0] || findAncestor(location, isImportDeclaration)?.moduleSpecifier || @@ -47625,7 +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) && isJSDocImportTag(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) ) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index ef564f615b516..2accbf8f872eb 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -266,7 +266,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocNameReference, JSDocNonNullableType, JSDocNullableType, @@ -2205,8 +2205,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return emitJSDocTypedefTag(node as JSDocTypedefTag); case SyntaxKind.JSDocSeeTag: return emitJSDocSeeTag(node as JSDocSeeTag); - case SyntaxKind.JSDocImportTypeTag: - return emitJSDocImportTypeTag(node as JSDocImportTypeTag); + case SyntaxKind.JSDocImportTag: + return emitJSDocImportTag(node as JSDocImportTag); // SyntaxKind.JSDocPropertyTag (see JSDocParameterTag, above) // Transformation nodes @@ -4455,7 +4455,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitJSDocComment(tag.comment); } - function emitJSDocImportTypeTag(tag: JSDocImportTypeTag) { + function emitJSDocImportTag(tag: JSDocImportTag) { emitJSDocTagName(tag.tagName); writeSpace(); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 51a4559ea17be..a3cbe509e97de 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -238,7 +238,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -883,8 +883,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode updateJSDocImplementsTag, createJSDocSeeTag, updateJSDocSeeTag, - createJSDocImportTypeTag, - updateJSDocImportTypeTag, + createJSDocImportTag, + updateJSDocImportTag, createJSDocNameReference, updateJSDocNameReference, createJSDocMemberName, @@ -5558,20 +5558,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocImportTypeTag, tagName ?? createIdentifier("importType"), comment); + function createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag { + const node = createBaseJSDocTag(SyntaxKind.JSDocImportTag, tagName ?? createIdentifier("import"), comment); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; node.comment = comment; return node; } - function updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag { + function updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag { return node.tagName !== tagName || node.comment !== comment || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier - ? update(createJSDocImportTypeTag(tagName, importClause, moduleSpecifier, comment), node) + ? update(createJSDocImportTag(tagName, importClause, moduleSpecifier, comment), node) : node; } @@ -7286,8 +7286,8 @@ function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string { return "augments"; case SyntaxKind.JSDocImplementsTag: return "implements"; - case SyntaxKind.JSDocImportTypeTag: - return "importType"; + case SyntaxKind.JSDocImportTag: + return "import"; default: return Debug.fail(`Unsupported kind: ${Debug.formatSyntaxKind(kind)}`); } diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 02cf0ec7ca6e7..ead0f4230ada9 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -91,7 +91,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -1203,8 +1203,8 @@ export function isJSDocThrowsTag(node: Node): node is JSDocThrowsTag { return node.kind === SyntaxKind.JSDocThrowsTag; } -export function isJSDocImportTypeTag(node: Node): node is JSDocImportTypeTag { - return node.kind === SyntaxKind.JSDocImportTypeTag; +export function isJSDocImportTag(node: Node): node is JSDocImportTag { + return node.kind === SyntaxKind.JSDocImportTag; } // Synthesized list diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 15c88977fa675..3aed7f7b9ea1a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -175,7 +175,7 @@ import { JSDocEnumTag, JSDocFunctionType, JSDocImplementsTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocLink, JSDocLinkCode, JSDocLinkPlain, @@ -1126,7 +1126,7 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, - [SyntaxKind.JSDocImportTypeTag]: forEachChildInJSDocImportTypeTag, + [SyntaxKind.JSDocImportTag]: forEachChildInJSDocImportTag, [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, }; @@ -1216,7 +1216,7 @@ function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDoc || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } -function forEachChildInJSDocImportTypeTag(node: JSDocImportTypeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInJSDocImportTag(node: JSDocImportTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNode(cbNode, node.tagName) || visitNode(cbNode, node.importClause) || visitNode(cbNode, node.moduleSpecifier) @@ -9082,8 +9082,8 @@ namespace Parser { case "throws": tag = parseThrowsTag(start, tagName, margin, indentText); break; - case "importType": - tag = parseImportTypeTag(start, tagName, margin, indentText); + case "import": + tag = parseImportTag(start, tagName, margin, indentText); break; default: tag = parseUnknownTag(start, tagName, margin, indentText); @@ -9457,7 +9457,7 @@ namespace Parser { return finishNode(factory.createJSDocSatisfiesTag(tagName, typeExpression, comments), start); } - function parseImportTypeTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTypeTag { + function parseImportTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTag { const afterImportTypeTagPos = scanner.getTokenFullStart(); let identifier: Identifier | undefined; @@ -9467,9 +9467,9 @@ namespace Parser { let importClause: ImportClause | undefined; if ( - identifier // @importType id - || token() === SyntaxKind.AsteriskToken // @importType * - || token() === SyntaxKind.OpenBraceToken // @importType { + identifier // @import id + || token() === SyntaxKind.AsteriskToken // @import * + || token() === SyntaxKind.OpenBraceToken // @import { ) { importClause = parseImportClause(identifier, afterImportTypeTagPos, /*isTypeOnly*/ true); parseExpected(SyntaxKind.FromKeyword); @@ -9479,7 +9479,7 @@ namespace Parser { const moduleSpecifier = parseModuleSpecifier(); const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; - return finishNode(factory.createJSDocImportTypeTag(tagName, importClause, moduleSpecifier, comments), start); + return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, comments), start); } function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 74bd222a91c4d..23135d4b5ca93 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -195,7 +195,7 @@ import { isImportTypeNode, isIncrementalCompilation, isInJSFile, - isJSDocImportTypeTag, + isJSDocImportTag, isLiteralImportTypeNode, isModifier, isModuleDeclaration, @@ -3450,10 +3450,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function collectJsDocImportTypeReferences(file: SourceFile) { - const r = /@importType/g; + const r = /@import/g; while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null const node = getNodeAtPosition(file, r.lastIndex); - if (isJSDocImportTypeTag(node)) { + if (isJSDocImportTag(node)) { const moduleNameExpr = getExternalModuleName(node); if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) { setParentRecursive(node, /*incremental*/ false); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 3a30173316e46..589cf3420b2cf 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -118,7 +118,7 @@ import { isIndexSignatureDeclaration, isInterfaceDeclaration, isInternalDeclaration, - isJSDocImportTypeTag, + isJSDocImportTag, isJsonSourceFile, isLateVisibilityPaintedStatement, isLiteralImportTypeNode, @@ -1459,7 +1459,7 @@ export function transformDeclarations(context: TransformationContext) { } if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return; - if (isJSDocImportTypeTag(input)) return; + if (isJSDocImportTag(input)) return; // Elide implementation signatures from overload sets if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3f542b5b4d1d9..8a1946e512e68 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -447,7 +447,7 @@ export const enum SyntaxKind { JSDocPropertyTag, JSDocThrowsTag, JSDocSatisfiesTag, - JSDocImportTypeTag, + JSDocImportTag, // Synthesized list SyntaxList, @@ -490,9 +490,9 @@ export const enum SyntaxKind { LastStatement = DebuggerStatement, FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, - LastJSDocNode = JSDocImportTypeTag, + LastJSDocNode = JSDocImportTag, FirstJSDocTagNode = JSDocTag, - LastJSDocTagNode = JSDocImportTypeTag, + LastJSDocTagNode = JSDocImportTag, /** @internal */ FirstContextualKeyword = AbstractKeyword, /** @internal */ LastContextualKeyword = OfKeyword, } @@ -1046,7 +1046,7 @@ export type ForEachChildNodes = | JSDocOverrideTag | JSDocSatisfiesTag | JSDocOverloadTag - | JSDocImportTypeTag; + | JSDocImportTag; /** @internal */ export type HasChildren = @@ -3656,7 +3656,7 @@ export type NamedExportBindings = // import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} export interface ImportClause extends NamedDeclaration { readonly kind: SyntaxKind.ImportClause; - readonly parent: ImportDeclaration | JSDocImportTypeTag; + readonly parent: ImportDeclaration | JSDocImportTag; readonly isTypeOnly: boolean; readonly name?: Identifier; // Default binding readonly namedBindings?: NamedImportBindings; @@ -4067,8 +4067,8 @@ export interface JSDocSatisfiesExpression extends ParenthesizedExpression { readonly _jsDocSatisfiesExpressionBrand: never; } -export interface JSDocImportTypeTag extends JSDocTag { - readonly kind: SyntaxKind.JSDocImportTypeTag; +export interface JSDocImportTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImportTag; readonly parent: JSDoc; readonly importClause: ImportClause; readonly moduleSpecifier: Expression; @@ -5554,7 +5554,7 @@ export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitialize export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; /** @internal */ -export type AnyImportOrJsDocImportTypeImport = AnyImportSyntax | JSDocImportTypeTag; +export type AnyImportOrJsDocImport = AnyImportSyntax | JSDocImportTag; /** @internal */ export type AliasDeclarationNode = @@ -5586,7 +5586,7 @@ export interface ValidImportTypeNode extends ImportTypeNode { /** @internal */ export type AnyValidImportOrReExport = - | (ImportDeclaration | ExportDeclaration | JSDocImportTypeTag) & { moduleSpecifier: StringLiteral; } + | (ImportDeclaration | ExportDeclaration | JSDocImportTag) & { moduleSpecifier: StringLiteral; } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral; }; } | RequireOrImportCall | ValidImportTypeNode; @@ -5611,7 +5611,7 @@ export interface RequireVariableDeclarationList extends VariableDeclarationList /** @internal */ export type LateVisibilityPaintedStatement = - | AnyImportOrJsDocImportTypeImport + | AnyImportOrJsDocImport | VariableStatement | ClassDeclaration | FunctionDeclaration @@ -8818,8 +8818,8 @@ export interface NodeFactory { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag; - updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 71f88d89f54e7..f4e92ea062cd4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -356,7 +356,7 @@ import { JSDocArray, JSDocCallbackTag, JSDocEnumTag, - JSDocImportTypeTag, + JSDocImportTag, JSDocMemberName, JSDocOverloadTag, JSDocParameterTag, @@ -3986,14 +3986,14 @@ export function isFunctionSymbol(symbol: Symbol | undefined) { } /** @internal */ -export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode | JSDocImportTypeTag): StringLiteralLike | undefined { +export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode | JSDocImportTag): StringLiteralLike | undefined { switch (node.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: - case SyntaxKind.JSDocImportTypeTag: + case SyntaxKind.JSDocImportTag: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike); @@ -4022,7 +4022,7 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal switch (node.parent.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: - case SyntaxKind.JSDocImportTypeTag: + case SyntaxKind.JSDocImportTag: return node.parent as AnyValidImportOrReExport; case SyntaxKind.ExternalModuleReference: return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport; @@ -4037,11 +4037,11 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal } /** @internal */ -export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration | JSDocImportTypeTag): Expression | undefined { +export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration | JSDocImportTag): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: - case SyntaxKind.JSDocImportTypeTag: + case SyntaxKind.JSDocImportTag: return node.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined; @@ -4071,7 +4071,7 @@ export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqua } /** @internal */ -export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration | JSDocImportTypeTag): boolean { +export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration | JSDocImportTag): boolean { return node.kind === SyntaxKind.ImportDeclaration && !!node.importClause && !!node.importClause.name; } diff --git a/src/services/completions.ts b/src/services/completions.ts index 1bc9adb2e414b..268dbd7da866f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -188,7 +188,7 @@ import { isJSDoc, isJSDocAugmentsTag, isJSDocImplementsTag, - isJSDocImportTypeTag, + isJSDocImportTag, isJSDocParameterTag, isJSDocTag, isJSDocTemplateTag, @@ -256,7 +256,7 @@ import { isVariableDeclaration, isVariableLike, JsDoc, - JSDocImportTypeTag, + JSDocImportTag, JSDocParameterTag, JSDocPropertyTag, JSDocReturnTag, @@ -3172,7 +3172,7 @@ function getCompletionData( log("getCompletionData: Is inside comment: " + (timestamp() - start)); let insideJsDocTagTypeExpression = false; - let insideJsDocImportTypeTag = false; + let insideJsDocImportTag = false; let isInSnippetScope = false; if (insideComment) { if (hasDocComment(sourceFile, position)) { @@ -3213,8 +3213,8 @@ function getCompletionData( if (tag.tagName.pos <= position && position <= tag.tagName.end) { return { kind: CompletionDataKind.JsDocTagName }; } - if (isJSDocImportTypeTag(tag)) { - insideJsDocImportTypeTag = true; + if (isJSDocImportTag(tag)) { + insideJsDocImportTag = true; } else { const typeExpression = tryGetTypeExpressionFromTag(tag); @@ -3236,7 +3236,7 @@ function getCompletionData( } } - if (!insideJsDocTagTypeExpression && !insideJsDocImportTypeTag) { + if (!insideJsDocTagTypeExpression && !insideJsDocImportTag) { // 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."); @@ -3247,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 && !insideJsDocImportTypeTag && isSourceFileJS(sourceFile); + const isJsOnlyLocation = !insideJsDocTagTypeExpression && !insideJsDocImportTag && isSourceFileJS(sourceFile); const tokens = getRelevantTokens(position, sourceFile); const previousToken = tokens.previousToken!; let contextToken = tokens.contextToken!; @@ -3928,7 +3928,7 @@ function getCompletionData( function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression - || insideJsDocImportTypeTag + || insideJsDocImportTag || !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent) || !isContextTokenValueLocation(contextToken) && (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) @@ -5717,9 +5717,9 @@ function getImportStatementCompletionInfo(contextToken: Node, sourceFile: Source } } -function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | JSDocImportTypeTag | Token | undefined) { +function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | JSDocImportTag | Token | undefined) { if (!node) return undefined; - const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration, isJSDocImportTypeTag)) ?? node; + const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration, isJSDocImportTag)) ?? node; const sourceFile = top.getSourceFile(); if (rangeIsOnSingleLine(top, sourceFile)) { return createTextSpanFromNode(top, sourceFile); @@ -5728,7 +5728,7 @@ function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclara Debug.assert(top.kind !== SyntaxKind.ImportKeyword && top.kind !== SyntaxKind.ImportSpecifier); // Guess which point in the import might actually be a later statement parsed as part of the import // during parser recovery - either in the middle of named imports, or the module specifier. - const potentialSplitPoint = top.kind === SyntaxKind.ImportDeclaration || top.kind === SyntaxKind.JSDocImportTypeTag + const potentialSplitPoint = top.kind === SyntaxKind.ImportDeclaration || top.kind === SyntaxKind.JSDocImportTag ? getPotentiallyInvalidImportSpecifier(top.importClause?.namedBindings) ?? top.moduleSpecifier : top.moduleReference; const withoutModuleSpecifier: TextRange = { diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index b8dc5758def9f..a3c4e9a495ef1 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -57,7 +57,7 @@ import { isVariableDeclaration, isVariableDeclarationInitializedToBareOrAccessedRequire, isVariableStatement, - JSDocImportTypeTag, + JSDocImportTag, ModifierFlags, ModuleBlock, ModuleDeclaration, @@ -139,7 +139,7 @@ interface AmbientModuleDeclaration extends ModuleDeclaration { } type SourceFileLike = SourceFile | AmbientModuleDeclaration; // Identifier for the case of `const x = require("y")`. -type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier | JSDocImportTypeTag; +type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier | JSDocImportTag; type ImporterOrCallExpression = Importer | CallExpression; /** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */ @@ -216,7 +216,7 @@ function getImportersForExport( break; case SyntaxKind.ImportDeclaration: - case SyntaxKind.JSDocImportTypeTag: + case SyntaxKind.JSDocImportTag: directImports.push(direct); const namedBindings = direct.importClause && direct.importClause.namedBindings; if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { @@ -269,7 +269,7 @@ function getImportersForExport( }); } - function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration | JSDocImportTypeTag, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { + function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration | JSDocImportTag, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { if (exportKind === ExportKind.ExportEquals) { // This is a direct import, not import-as-namespace. if (!alreadyAddedDirect) directImports.push(importDeclaration); diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index a30641e8cc06c..a08937cfd7e99 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -131,7 +131,7 @@ const jsDocTagNames = [ "host", "ignore", "implements", - "importType", + "import", "inheritdoc", "inner", "instance", diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 72b8a0b3832ed..6d1fb87d15d08 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -418,7 +418,7 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: case SyntaxKind.ExternalModuleReference: - case SyntaxKind.JSDocImportTypeTag: + case SyntaxKind.JSDocImportTag: // 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*/"); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 04ef6e85ca400..6837e46407b6a 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -187,7 +187,7 @@ import { isInternalModuleImportEqualsDeclaration, isJSDoc, isJSDocCommentContainingNode, - isJSDocImportTypeTag, + isJSDocImportTag, isJSDocLink, isJSDocLinkCode, isJSDocLinkLike, @@ -258,7 +258,7 @@ import { isWhiteSpaceSingleLine, isYieldExpression, IterationStatement, - JSDocImportTypeTag, + JSDocImportTag, JSDocLink, JSDocLinkCode, JSDocLinkDisplayPart, @@ -1246,7 +1246,7 @@ function getAdjustedLocationForDeclaration(node: Node, forRename: boolean) { } } -function getAdjustedLocationForImportDeclaration(node: ImportDeclaration | JSDocImportTypeTag, forRename: boolean) { +function getAdjustedLocationForImportDeclaration(node: ImportDeclaration | JSDocImportTag, forRename: boolean) { if (node.importClause) { if (node.importClause.name && node.importClause.namedBindings) { // do not adjust if we have both a name and named bindings @@ -2575,7 +2575,7 @@ export function isModuleSpecifierLike(node: Node): node is StringLiteralLike { return isStringLiteralLike(node) && ( isExternalModuleReference(node.parent) || isImportDeclaration(node.parent) || - isJSDocImportTypeTag(node.parent) || + isJSDocImportTag(node.parent) || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node || isImportCall(node.parent) && node.parent.arguments[0] === node ); diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index a6beadc076e3d..0635aff6cdd1d 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -205,30 +205,30 @@ describe("unittests:: JSDocParsing", () => { ); parsesCorrectly( - "importTypeTag1", + "importTag1", `/** - * @importType foo from 'foo' + * @import foo from 'foo' */`, ); parsesCorrectly( - "importTypeTag2", + "importTag2", `/** - * @importType { foo } from 'foo' + * @import { foo } from 'foo' */`, ); parsesCorrectly( - "importTypeTag3", + "importTag3", `/** - * @importType * as types from 'foo' + * @import * as types from 'foo' */`, ); parsesCorrectly( - "importTypeTag4", + "importTag4", `/** - * @importType * as types from 'foo' comment part + * @import * as types from 'foo' comment part */`, ); diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json deleted file mode 100644 index f2f67264e6d0c..0000000000000 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag1.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "kind": "JSDoc", - "pos": 0, - "end": 39, - "flags": "JSDoc", - "modifierFlagsCache": 0, - "transformFlags": 0, - "tags": { - "0": { - "kind": "JSDocImportTypeTag", - "pos": 8, - "end": 34, - "modifierFlagsCache": 0, - "transformFlags": 0, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 19, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "importType" - }, - "importClause": { - "kind": "ImportClause", - "pos": 20, - "end": 23, - "modifierFlagsCache": 0, - "transformFlags": 1, - "isTypeOnly": true, - "name": { - "kind": "Identifier", - "pos": 20, - "end": 23, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "foo" - } - }, - "moduleSpecifier": { - "kind": "StringLiteral", - "pos": 28, - "end": 34, - "modifierFlagsCache": 0, - "transformFlags": 0, - "text": "foo" - } - }, - "length": 1, - "pos": 8, - "end": 34, - "hasTrailingComma": false, - "transformFlags": 0 - } -} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json deleted file mode 100644 index fc388e6f3f4a7..0000000000000 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag2.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "kind": "JSDoc", - "pos": 0, - "end": 43, - "flags": "JSDoc", - "modifierFlagsCache": 0, - "transformFlags": 0, - "tags": { - "0": { - "kind": "JSDocImportTypeTag", - "pos": 8, - "end": 38, - "modifierFlagsCache": 0, - "transformFlags": 0, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 19, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "importType" - }, - "importClause": { - "kind": "ImportClause", - "pos": 20, - "end": 27, - "modifierFlagsCache": 0, - "transformFlags": 1, - "isTypeOnly": true, - "namedBindings": { - "kind": "NamedImports", - "pos": 20, - "end": 27, - "modifierFlagsCache": 0, - "transformFlags": 0, - "elements": { - "0": { - "kind": "ImportSpecifier", - "pos": 21, - "end": 25, - "modifierFlagsCache": 0, - "transformFlags": 0, - "isTypeOnly": false, - "name": { - "kind": "Identifier", - "pos": 21, - "end": 25, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "foo" - } - }, - "length": 1, - "pos": 21, - "end": 25, - "hasTrailingComma": false, - "transformFlags": 0 - } - } - }, - "moduleSpecifier": { - "kind": "StringLiteral", - "pos": 32, - "end": 38, - "modifierFlagsCache": 0, - "transformFlags": 0, - "text": "foo" - } - }, - "length": 1, - "pos": 8, - "end": 38, - "hasTrailingComma": false, - "transformFlags": 0 - } -} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json deleted file mode 100644 index b398a4d3d5a89..0000000000000 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag3.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "kind": "JSDoc", - "pos": 0, - "end": 46, - "flags": "JSDoc", - "modifierFlagsCache": 0, - "transformFlags": 0, - "tags": { - "0": { - "kind": "JSDocImportTypeTag", - "pos": 8, - "end": 41, - "modifierFlagsCache": 0, - "transformFlags": 0, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 19, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "importType" - }, - "importClause": { - "kind": "ImportClause", - "pos": 20, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 1, - "isTypeOnly": true, - "namedBindings": { - "kind": "NamespaceImport", - "pos": 20, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 0, - "name": { - "kind": "Identifier", - "pos": 24, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "types" - } - } - }, - "moduleSpecifier": { - "kind": "StringLiteral", - "pos": 35, - "end": 41, - "modifierFlagsCache": 0, - "transformFlags": 0, - "text": "foo" - } - }, - "length": 1, - "pos": 8, - "end": 41, - "hasTrailingComma": false, - "transformFlags": 0 - } -} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json deleted file mode 100644 index 51beb502ee7e4..0000000000000 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTypeTag4.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "kind": "JSDoc", - "pos": 0, - "end": 59, - "flags": "JSDoc", - "modifierFlagsCache": 0, - "transformFlags": 0, - "tags": { - "0": { - "kind": "JSDocImportTypeTag", - "pos": 8, - "end": 57, - "modifierFlagsCache": 0, - "transformFlags": 0, - "tagName": { - "kind": "Identifier", - "pos": 9, - "end": 19, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "importType" - }, - "comment": "comment part", - "importClause": { - "kind": "ImportClause", - "pos": 20, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 1, - "isTypeOnly": true, - "namedBindings": { - "kind": "NamespaceImport", - "pos": 20, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 0, - "name": { - "kind": "Identifier", - "pos": 24, - "end": 30, - "modifierFlagsCache": 0, - "transformFlags": 0, - "escapedText": "types" - } - } - }, - "moduleSpecifier": { - "kind": "StringLiteral", - "pos": 35, - "end": 41, - "modifierFlagsCache": 0, - "transformFlags": 0, - "text": "foo" - } - }, - "length": 1, - "pos": 8, - "end": 57, - "hasTrailingComma": false, - "transformFlags": 0 - } -} \ No newline at end of file diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 78fdabc94c120..9b2665a045bc4 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4542,7 +4542,7 @@ declare namespace ts { JSDocPropertyTag = 355, JSDocThrowsTag = 356, JSDocSatisfiesTag = 357, - JSDocImportTypeTag = 358, + JSDocImportTag = 358, SyntaxList = 359, NotEmittedStatement = 360, PartiallyEmittedExpression = 361, @@ -6029,7 +6029,7 @@ declare namespace ts { type NamedExportBindings = NamespaceExport | NamedExports; interface ImportClause extends NamedDeclaration { readonly kind: SyntaxKind.ImportClause; - readonly parent: ImportDeclaration | JSDocImportTypeTag; + readonly parent: ImportDeclaration | JSDocImportTag; readonly isTypeOnly: boolean; readonly name?: Identifier; readonly namedBindings?: NamedImportBindings; @@ -6385,8 +6385,8 @@ declare namespace ts { readonly kind: SyntaxKind.JSDocSatisfiesTag; readonly typeExpression: JSDocTypeExpression; } - interface JSDocImportTypeTag extends JSDocTag { - readonly kind: SyntaxKind.JSDocImportTypeTag; + interface JSDocImportTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImportTag; readonly parent: JSDoc; readonly importClause: ImportClause; readonly moduleSpecifier: Expression; @@ -8355,8 +8355,8 @@ declare namespace ts { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTypeTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTypeTag; - updateJSDocImportTypeTag(node: JSDocImportTypeTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTypeTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; @@ -9584,7 +9584,7 @@ declare namespace ts { function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag; function isJSDocSatisfiesTag(node: Node): node is JSDocSatisfiesTag; function isJSDocThrowsTag(node: Node): node is JSDocThrowsTag; - function isJSDocImportTypeTag(node: Node): node is JSDocImportTypeTag; + function isJSDocImportTag(node: Node): node is JSDocImportTag; function isQuestionOrExclamationToken(node: Node): node is QuestionToken | ExclamationToken; function isIdentifierOrThisTypeNode(node: Node): node is Identifier | ThisTypeNode; function isReadonlyKeywordOrPlusOrMinusToken(node: Node): node is ReadonlyKeyword | PlusToken | MinusToken; diff --git a/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc b/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc deleted file mode 100644 index 7310f74b390b5..0000000000000 --- a/tests/baselines/reference/findAllRefsJsDocImportTypeTag.baseline.jsonc +++ /dev/null @@ -1,105 +0,0 @@ -// === findAllReferences === -// === /a.js === -// /** -// * <|@importType { [|{| defId: 0, isWriteAccess: true |}A|] } from "./b"; -// |>*/ -// -// /** -// * @param { [|{| defId: 0 |}A|]/*FIND ALL REFS*/ } a -// */ -// function f(a) {} - -// === /b.ts === -// <|export interface [|{| defId: 1, isWriteAccess: true |}A|] { }|> - - // === Definitions === - // === /a.js === - // /** - // * <|@importType { [|{| defId: 0 |}A|] } from "./b"; - // |>*/ - // - // /** - // * @param { A/*FIND ALL REFS*/ } a - // */ - // function f(a) {} - - // === /b.ts === - // <|export interface [|{| defId: 1 |}A|] { }|> - - // === Details === - [ - { - "defId": 0, - "containerKind": "", - "containerName": "", - "kind": "alias", - "name": "(alias) interface A\nimport A", - "displayParts": [ - { - "text": "(", - "kind": "punctuation" - }, - { - "text": "alias", - "kind": "text" - }, - { - "text": ")", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "interface", - "kind": "keyword" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "A", - "kind": "aliasName" - }, - { - "text": "\n", - "kind": "lineBreak" - }, - { - "text": "import", - "kind": "keyword" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "A", - "kind": "aliasName" - } - ] - }, - { - "defId": 1, - "containerKind": "", - "containerName": "", - "kind": "interface", - "name": "interface A", - "displayParts": [ - { - "text": "interface", - "kind": "keyword" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "A", - "kind": "interfaceName" - } - ] - } - ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc deleted file mode 100644 index dcdf4ade81eed..0000000000000 --- a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag1.baseline.jsonc +++ /dev/null @@ -1,17 +0,0 @@ -// === goToDefinition === -// === /b.ts === -// [||]export interface A { } - -// === /a.js === -// /** -// * @importType { A } from [|"./b/*GOTO DEF*/"|] -// */ - - // === Details === - [ - { - "kind": "script", - "name": "./b", - "unverified": false - } - ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc deleted file mode 100644 index 450a58c2c9e0d..0000000000000 --- a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag2.baseline.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -// === goToDefinition === -// === /a.js === -// /** -// * @importType { A } from/*GOTO DEF*/ "./b" -// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc deleted file mode 100644 index 4c2ef9da7fb74..0000000000000 --- a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag3.baseline.jsonc +++ /dev/null @@ -1,5 +0,0 @@ -// === goToDefinition === -// === /a.js === -// /** -// * @importType { A } from /*GOTO DEF*/ "./b"; -// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc deleted file mode 100644 index b5dc8296bbe76..0000000000000 --- a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag4.baseline.jsonc +++ /dev/null @@ -1,20 +0,0 @@ -// === goToDefinition === -// === /b.ts === -// <|export interface [|A|] { }|> - -// === /a.js === -// /** -// * @importType { [|A|]/*GOTO DEF*/ } from "./b"; -// */ - - // === Details === - [ - { - "kind": "interface", - "name": "A", - "containerName": "\"/b\"", - "isLocal": false, - "isAmbient": false, - "unverified": false - } - ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc deleted file mode 100644 index 1cf7ba59f4b27..0000000000000 --- a/tests/baselines/reference/goToDefinitionJsDocImportTypeTag5.baseline.jsonc +++ /dev/null @@ -1,25 +0,0 @@ -// === goToDefinition === -// === /b.ts === -// <|export interface [|A|] { }|> - -// === /a.js === -// /** -// * @importType { A } from "./b"; -// */ -// -// /** -// * @param { [|A|]/*GOTO DEF*/ } a -// */ -// function f(a) {} - - // === Details === - [ - { - "kind": "interface", - "name": "A", - "containerName": "\"/b\"", - "isLocal": false, - "isAmbient": false, - "unverified": false - } - ] \ No newline at end of file diff --git a/tests/baselines/reference/importTypeTag1.symbols b/tests/baselines/reference/importTypeTag1.symbols deleted file mode 100644 index ededafd16bb9a..0000000000000 --- a/tests/baselines/reference/importTypeTag1.symbols +++ /dev/null @@ -1,22 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag1.ts] //// - -=== /types.ts === -export interface Foo { ->Foo : Symbol(Foo, Decl(types.ts, 0, 0)) - - a: number; ->a : Symbol(Foo.a, Decl(types.ts, 0, 22)) -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : Symbol(f, Decl(foo.js, 0, 0)) ->foo : Symbol(foo, Decl(foo.js, 7, 11)) - diff --git a/tests/baselines/reference/importTypeTag1.types b/tests/baselines/reference/importTypeTag1.types deleted file mode 100644 index f9b8235b61900..0000000000000 --- a/tests/baselines/reference/importTypeTag1.types +++ /dev/null @@ -1,20 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag1.ts] //// - -=== /types.ts === -export interface Foo { - a: number; ->a : number -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : (foo: Foo) => void ->foo : Foo - diff --git a/tests/baselines/reference/importTypeTag2.symbols b/tests/baselines/reference/importTypeTag2.symbols deleted file mode 100644 index 1839c87046897..0000000000000 --- a/tests/baselines/reference/importTypeTag2.symbols +++ /dev/null @@ -1,22 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag2.ts] //// - -=== /types.ts === -export interface Foo { ->Foo : Symbol(Foo, Decl(types.ts, 0, 0)) - - a: number; ->a : Symbol(Foo.a, Decl(types.ts, 0, 22)) -} - -=== /foo.js === -/** - * @importType * as types from "./types" - */ - -/** - * @param { types.Foo } foo - */ -export function f(foo) {} ->f : Symbol(f, Decl(foo.js, 0, 0)) ->foo : Symbol(foo, Decl(foo.js, 7, 18)) - diff --git a/tests/baselines/reference/importTypeTag2.types b/tests/baselines/reference/importTypeTag2.types deleted file mode 100644 index 4bc8720e60755..0000000000000 --- a/tests/baselines/reference/importTypeTag2.types +++ /dev/null @@ -1,20 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag2.ts] //// - -=== /types.ts === -export interface Foo { - a: number; ->a : number -} - -=== /foo.js === -/** - * @importType * as types from "./types" - */ - -/** - * @param { types.Foo } foo - */ -export function f(foo) {} ->f : (foo: types.Foo) => void ->foo : types.Foo - diff --git a/tests/baselines/reference/importTypeTag3.symbols b/tests/baselines/reference/importTypeTag3.symbols deleted file mode 100644 index fa49c3ada1727..0000000000000 --- a/tests/baselines/reference/importTypeTag3.symbols +++ /dev/null @@ -1,22 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag3.ts] //// - -=== /types.ts === -export default interface Foo { ->Foo : Symbol(Foo, Decl(types.ts, 0, 0)) - - a: number; ->a : Symbol(Foo.a, Decl(types.ts, 0, 30)) -} - -=== /foo.js === -/** - * @importType Foo from "./types" - */ - -/** - * @param { Foo } foo - */ -export function f(foo) {} ->f : Symbol(f, Decl(foo.js, 0, 0)) ->foo : Symbol(foo, Decl(foo.js, 7, 18)) - diff --git a/tests/baselines/reference/importTypeTag3.types b/tests/baselines/reference/importTypeTag3.types deleted file mode 100644 index 52c525116d7cd..0000000000000 --- a/tests/baselines/reference/importTypeTag3.types +++ /dev/null @@ -1,20 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag3.ts] //// - -=== /types.ts === -export default interface Foo { - a: number; ->a : number -} - -=== /foo.js === -/** - * @importType Foo from "./types" - */ - -/** - * @param { Foo } foo - */ -export function f(foo) {} ->f : (foo: Foo) => void ->foo : Foo - diff --git a/tests/baselines/reference/importTypeTag4.errors.txt b/tests/baselines/reference/importTypeTag4.errors.txt deleted file mode 100644 index afabc669d2632..0000000000000 --- a/tests/baselines/reference/importTypeTag4.errors.txt +++ /dev/null @@ -1,27 +0,0 @@ -/foo.js(2,18): error TS2300: Duplicate identifier 'Foo'. -/foo.js(6,18): error TS2300: Duplicate identifier 'Foo'. - - -==== /types.ts (0 errors) ==== - export interface Foo { - a: number; - } - -==== /foo.js (2 errors) ==== - /** - * @importType { Foo } from "./types" - ~~~ -!!! error TS2300: Duplicate identifier 'Foo'. - */ - - /** - * @importType { Foo } from "./types" - ~~~ -!!! error TS2300: Duplicate identifier 'Foo'. - */ - - /** - * @param { Foo } foo - */ - function f(foo) {} - \ No newline at end of file diff --git a/tests/baselines/reference/importTypeTag4.symbols b/tests/baselines/reference/importTypeTag4.symbols deleted file mode 100644 index 6da33eedc913c..0000000000000 --- a/tests/baselines/reference/importTypeTag4.symbols +++ /dev/null @@ -1,26 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag4.ts] //// - -=== /types.ts === -export interface Foo { ->Foo : Symbol(Foo, Decl(types.ts, 0, 0)) - - a: number; ->a : Symbol(Foo.a, Decl(types.ts, 0, 22)) -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : Symbol(f, Decl(foo.js, 0, 0)) ->foo : Symbol(foo, Decl(foo.js, 11, 11)) - diff --git a/tests/baselines/reference/importTypeTag4.types b/tests/baselines/reference/importTypeTag4.types deleted file mode 100644 index d7cb442b86362..0000000000000 --- a/tests/baselines/reference/importTypeTag4.types +++ /dev/null @@ -1,24 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag4.ts] //// - -=== /types.ts === -export interface Foo { - a: number; ->a : number -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : (foo: Foo) => void ->foo : Foo - diff --git a/tests/baselines/reference/importTypeTag5.js b/tests/baselines/reference/importTypeTag5.js deleted file mode 100644 index 6c001af0780c7..0000000000000 --- a/tests/baselines/reference/importTypeTag5.js +++ /dev/null @@ -1,32 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// - -//// [types.ts] -export interface Foo { - a: number; -} - -//// [foo.js] -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} - - - - -//// [types.d.ts] -export interface Foo { - a: number; -} -//// [foo.d.ts] -/** - * @importType { Foo } from "./types" - */ -/** - * @param { Foo } foo - */ -declare function f(foo: import("./types").Foo): void; diff --git a/tests/baselines/reference/importTypeTag5.symbols b/tests/baselines/reference/importTypeTag5.symbols deleted file mode 100644 index faac6b1a6c300..0000000000000 --- a/tests/baselines/reference/importTypeTag5.symbols +++ /dev/null @@ -1,22 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// - -=== /types.ts === -export interface Foo { ->Foo : Symbol(Foo, Decl(types.ts, 0, 0)) - - a: number; ->a : Symbol(Foo.a, Decl(types.ts, 0, 22)) -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : Symbol(f, Decl(foo.js, 0, 0)) ->foo : Symbol(foo, Decl(foo.js, 7, 11)) - diff --git a/tests/baselines/reference/importTypeTag5.types b/tests/baselines/reference/importTypeTag5.types deleted file mode 100644 index 9595271509c2b..0000000000000 --- a/tests/baselines/reference/importTypeTag5.types +++ /dev/null @@ -1,20 +0,0 @@ -//// [tests/cases/conformance/jsdoc/importTypeTag5.ts] //// - -=== /types.ts === -export interface Foo { - a: number; ->a : number -} - -=== /foo.js === -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} ->f : (foo: Foo) => void ->foo : Foo - diff --git a/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline b/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline deleted file mode 100644 index 6905eacdea1b1..0000000000000 --- a/tests/baselines/reference/jsdocImportTypeTagCompletion2.baseline +++ /dev/null @@ -1,48 +0,0 @@ -// === Completions === -=== /b.js === -// /** -// * @importType { } from "./a" -// ^ -// | ---------------------------------------------------------------------- -// | interface A -// | ---------------------------------------------------------------------- -// */ - -[ - { - "marker": { - "fileName": "/b.js", - "position": 21, - "name": "" - }, - "item": { - "flags": 0, - "isGlobalCompletion": false, - "isMemberCompletion": true, - "isNewIdentifierLocation": false, - "entries": [ - { - "name": "A", - "kind": "interface", - "kindModifiers": "export", - "sortText": "11", - "displayParts": [ - { - "text": "interface", - "kind": "keyword" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "A", - "kind": "interfaceName" - } - ], - "documentation": [] - } - ] - } - } -] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline b/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline deleted file mode 100644 index 665cbf11fbdcc..0000000000000 --- a/tests/baselines/reference/jsdocImportTypeTagCompletion3.baseline +++ /dev/null @@ -1,51 +0,0 @@ -// === Completions === -=== /tests/cases/fourslash/./c.js === -// /** -// * @importType * as types from "./" -// ^ -// | ---------------------------------------------------------------------- -// | a -// | b -// | ---------------------------------------------------------------------- -// */ - -[ - { - "marker": { - "fileName": "/tests/cases/fourslash/./c.js", - "position": 38, - "name": "" - }, - "item": { - "isGlobalCompletion": false, - "isMemberCompletion": false, - "isNewIdentifierLocation": true, - "entries": [ - { - "name": "a", - "kind": "script", - "kindModifiers": ".ts", - "sortText": "11", - "displayParts": [ - { - "text": "a", - "kind": "text" - } - ] - }, - { - "name": "b", - "kind": "script", - "kindModifiers": ".ts", - "sortText": "11", - "displayParts": [ - { - "text": "b", - "kind": "text" - } - ] - } - ] - } - } -] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline index 52be28e24ed64..eaa52ac7e7b66 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline @@ -40,7 +40,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -137,7 +137,7 @@ // | @host // | @ignore // | @implements -// | @importType +// | @import // | @inheritdoc // | @inner // | @instance @@ -231,7 +231,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -330,7 +330,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -431,7 +431,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -527,7 +527,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -624,7 +624,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -721,7 +721,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -817,7 +817,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -914,7 +914,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1008,7 +1008,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1103,7 +1103,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1198,7 +1198,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1292,7 +1292,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1388,7 +1388,7 @@ // | @host // | @ignore // | @implements -// | @importType +// | @import // | @inheritdoc // | @inner // | @instance @@ -1482,7 +1482,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1578,7 +1578,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -2114,13 +2114,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -3246,13 +3246,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -4378,13 +4378,13 @@ "documentation": [] }, { - "name": "@importType", + "name": "@import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "@importType", + "text": "@import", "kind": "text" } ], @@ -5497,13 +5497,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -6616,13 +6616,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -7735,13 +7735,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -8867,13 +8867,13 @@ "documentation": [] }, { - "name": "@importType", + "name": "@import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "@importType", + "text": "@import", "kind": "text" } ], @@ -9986,13 +9986,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -11105,13 +11105,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -12224,13 +12224,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -13343,13 +13343,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -14462,13 +14462,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -15581,13 +15581,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -16700,13 +16700,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -17832,13 +17832,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -18951,13 +18951,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -20070,13 +20070,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline index d58ae8143f038..61f8d6a823f74 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline @@ -40,7 +40,7 @@ // | @host // | @ignore // | @implements -// | @importType +// | @import // | @inheritdoc // | @inner // | @instance @@ -134,7 +134,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -233,7 +233,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -326,7 +326,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -420,7 +420,7 @@ // | @host // | @ignore // | @implements -// | @importType +// | @import // | @inheritdoc // | @inner // | @instance @@ -954,13 +954,13 @@ "documentation": [] }, { - "name": "@importType", + "name": "@import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "@importType", + "text": "@import", "kind": "text" } ], @@ -2075,13 +2075,13 @@ "documentation": [] }, { - "name": "@importType", + "name": "@import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "@importType", + "text": "@import", "kind": "text" } ], @@ -3196,13 +3196,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -4317,13 +4317,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -5438,13 +5438,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline index 28d7cdbd961d3..e5b6942d334f0 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline @@ -40,7 +40,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -132,7 +132,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -225,7 +225,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -321,7 +321,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -417,7 +417,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -511,7 +511,7 @@ // | host // | ignore // | implements -// | importType +// | import // | inheritdoc // | inner // | instance @@ -1046,13 +1046,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -2165,13 +2165,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -3284,13 +3284,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -4403,13 +4403,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -5522,13 +5522,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], @@ -6641,13 +6641,13 @@ "documentation": [] }, { - "name": "importType", + "name": "import", "kind": "", "kindModifiers": "", "sortText": "11", "displayParts": [ { - "text": "importType", + "text": "import", "kind": "text" } ], diff --git a/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc b/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc deleted file mode 100644 index 89d16ef43ae38..0000000000000 --- a/tests/baselines/reference/renameJsDocImportTypeTag.baseline.jsonc +++ /dev/null @@ -1,10 +0,0 @@ -// === findRenameLocations === -// === /a.js === -// /** -// * <|@importType { /*START PREFIX*/A as [|ARENAME|] } from "./b"; -// |>*/ -// -// /** -// * @param { [|ARENAME|]/*RENAME*/ } a -// */ -// function f(a) {} \ No newline at end of file diff --git a/tests/cases/conformance/jsdoc/importTypeTag1.ts b/tests/cases/conformance/jsdoc/importTypeTag1.ts deleted file mode 100644 index c4ea7011276f8..0000000000000 --- a/tests/cases/conformance/jsdoc/importTypeTag1.ts +++ /dev/null @@ -1,18 +0,0 @@ -// @checkJs: true -// @allowJs: true -// @noEmit: true - -// @filename: /types.ts -export interface Foo { - a: number; -} - -// @filename: /foo.js -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag2.ts b/tests/cases/conformance/jsdoc/importTypeTag2.ts deleted file mode 100644 index 0d095b79d5e9b..0000000000000 --- a/tests/cases/conformance/jsdoc/importTypeTag2.ts +++ /dev/null @@ -1,18 +0,0 @@ -// @checkJs: true -// @allowJs: true -// @noEmit: true - -// @filename: /types.ts -export interface Foo { - a: number; -} - -// @filename: /foo.js -/** - * @importType * as types from "./types" - */ - -/** - * @param { types.Foo } foo - */ -export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag3.ts b/tests/cases/conformance/jsdoc/importTypeTag3.ts deleted file mode 100644 index f081e451772d9..0000000000000 --- a/tests/cases/conformance/jsdoc/importTypeTag3.ts +++ /dev/null @@ -1,18 +0,0 @@ -// @checkJs: true -// @allowJs: true -// @noEmit: true - -// @filename: /types.ts -export default interface Foo { - a: number; -} - -// @filename: /foo.js -/** - * @importType Foo from "./types" - */ - -/** - * @param { Foo } foo - */ -export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag4.ts b/tests/cases/conformance/jsdoc/importTypeTag4.ts deleted file mode 100644 index d0d76cc1d4c03..0000000000000 --- a/tests/cases/conformance/jsdoc/importTypeTag4.ts +++ /dev/null @@ -1,22 +0,0 @@ -// @checkJs: true -// @allowJs: true -// @noEmit: true - -// @filename: /types.ts -export interface Foo { - a: number; -} - -// @filename: /foo.js -/** - * @importType { Foo } from "./types" - */ - -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTypeTag5.ts b/tests/cases/conformance/jsdoc/importTypeTag5.ts deleted file mode 100644 index 48ffe0a77a822..0000000000000 --- a/tests/cases/conformance/jsdoc/importTypeTag5.ts +++ /dev/null @@ -1,19 +0,0 @@ -// @checkJs: true -// @allowJs: true -// @declaration: true -// @emitDeclarationOnly: true - -// @filename: /types.ts -export interface Foo { - a: number; -} - -// @filename: /foo.js -/** - * @importType { Foo } from "./types" - */ - -/** - * @param { Foo } foo - */ -function f(foo) {} diff --git a/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts b/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts deleted file mode 100644 index 2918fd59c1caf..0000000000000 --- a/tests/cases/fourslash/findAllRefsJsDocImportTypeTag.ts +++ /dev/null @@ -1,19 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -////export interface A { } - -// @Filename: /a.js -/////** -//// * @importType { A } from "./b"; -//// */ -//// -/////** -//// * @param { [|A/**/|] } a -//// */ -////function f(a) {} - -verify.baselineFindAllReferences(""); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts deleted file mode 100644 index 393e3f13223df..0000000000000 --- a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag1.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -/////*2*/export interface A { } - -// @Filename: /a.js -/////** -//// * @importType { A } from [|"./b/*1*/"|] -//// */ - -verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts deleted file mode 100644 index 18ef0717769bd..0000000000000 --- a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag2.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -/////*2*/export interface A { } - -// @Filename: /a.js -/////** -//// * @importType { A } [|from/*1*/|] "./b" -//// */ - -verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts deleted file mode 100644 index 6ef9cc078a055..0000000000000 --- a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag3.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -/////*2*/export interface A { } - -// @Filename: /a.js -/////** -//// * @importType { A } [|from /*1*/|] "./b"; -//// */ - -verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts deleted file mode 100644 index b2ead0b378e82..0000000000000 --- a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag4.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -////export interface /*2*/A { } - -// @Filename: /a.js -/////** -//// * @importType { [|A/*1*/|] } from "./b"; -//// */ - -verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts deleted file mode 100644 index 3c374a79b52bb..0000000000000 --- a/tests/cases/fourslash/goToDefinitionJsDocImportTypeTag5.ts +++ /dev/null @@ -1,19 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -////export interface /*2*/A { } - -// @Filename: /a.js -/////** -//// * @importType { A } from "./b"; -//// */ -//// -/////** -//// * @param { [|A/*1*/|] } a -//// */ -////function f(a) {} - -verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts deleted file mode 100644 index 0ef03d9f18263..0000000000000 --- a/tests/cases/fourslash/jsdocImportTypeTagCompletion1.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @filename: /a.js -/////** -//// * @/**/ -//// */ - -verify.completions( - { marker: "", includes: ["importType"] }, -); diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts deleted file mode 100644 index 14d9701627026..0000000000000 --- a/tests/cases/fourslash/jsdocImportTypeTagCompletion2.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @filename: /a.ts -////export interface A {} - -// @filename: /b.js -/////** -//// * @importType { /**/ } from "./a" -//// */ - -verify.baselineCompletions(); diff --git a/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts b/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts deleted file mode 100644 index 7c0e7ad0998e2..0000000000000 --- a/tests/cases/fourslash/jsdocImportTypeTagCompletion3.ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true -// @module: esnext - -// @filename: ./a.ts -////export interface A {} - -// @filename: ./b.ts -////export interface B {} - -// @filename: ./c.js -/////** -//// * @importType * as types from ".//**/" -//// */ - -verify.baselineCompletions(); diff --git a/tests/cases/fourslash/renameJsDocImportTypeTag.ts b/tests/cases/fourslash/renameJsDocImportTypeTag.ts deleted file mode 100644 index dbd09f2ae7ff5..0000000000000 --- a/tests/cases/fourslash/renameJsDocImportTypeTag.ts +++ /dev/null @@ -1,19 +0,0 @@ -/// - -// @allowJS: true -// @checkJs: true - -// @Filename: /b.ts -////export interface A { } - -// @Filename: /a.js -/////** -//// * @importType { A } from "./b"; -//// */ -//// -/////** -//// * @param { [|A/**/|] } a -//// */ -////function f(a) {} - -verify.baselineRename(""); From 08806b6f8881179607d982cd733eb0e82ab56359 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 1 Feb 2024 02:09:11 +0200 Subject: [PATCH 08/23] add tests --- ...ocComments.parsesCorrectly.importTag1.json | 54 +++++++++ ...ocComments.parsesCorrectly.importTag2.json | 76 +++++++++++++ ...ocComments.parsesCorrectly.importTag3.json | 61 ++++++++++ ...ocComments.parsesCorrectly.importTag4.json | 62 +++++++++++ .../findAllRefsJsDocImportTag.baseline.jsonc | 105 ++++++++++++++++++ ...ToDefinitionJsDocImportTag1.baseline.jsonc | 17 +++ ...ToDefinitionJsDocImportTag2.baseline.jsonc | 5 + ...ToDefinitionJsDocImportTag3.baseline.jsonc | 5 + ...ToDefinitionJsDocImportTag4.baseline.jsonc | 20 ++++ ...ToDefinitionJsDocImportTag5.baseline.jsonc | 25 +++++ tests/baselines/reference/importTag1.symbols | 22 ++++ tests/baselines/reference/importTag1.types | 20 ++++ tests/baselines/reference/importTag2.symbols | 22 ++++ tests/baselines/reference/importTag2.types | 20 ++++ tests/baselines/reference/importTag3.symbols | 22 ++++ tests/baselines/reference/importTag3.types | 20 ++++ .../baselines/reference/importTag4.errors.txt | 27 +++++ tests/baselines/reference/importTag4.symbols | 26 +++++ tests/baselines/reference/importTag4.types | 24 ++++ tests/baselines/reference/importTag5.js | 32 ++++++ tests/baselines/reference/importTag5.symbols | 22 ++++ tests/baselines/reference/importTag5.types | 20 ++++ .../jsdocImportTagCompletion2.baseline | 48 ++++++++ .../jsdocImportTagCompletion3.baseline | 51 +++++++++ .../renameJsDocImportTag.baseline.jsonc | 10 ++ tests/cases/conformance/jsdoc/importTag1.ts | 18 +++ tests/cases/conformance/jsdoc/importTag2.ts | 18 +++ tests/cases/conformance/jsdoc/importTag3.ts | 18 +++ tests/cases/conformance/jsdoc/importTag4.ts | 22 ++++ tests/cases/conformance/jsdoc/importTag5.ts | 19 ++++ .../fourslash/findAllRefsJsDocImportTag.ts | 19 ++++ .../goToDefinitionJsDocImportTag1.ts | 14 +++ .../goToDefinitionJsDocImportTag2.ts | 14 +++ .../goToDefinitionJsDocImportTag3.ts | 14 +++ .../goToDefinitionJsDocImportTag4.ts | 14 +++ .../goToDefinitionJsDocImportTag5.ts | 19 ++++ .../fourslash/jsdocImportTagCompletion1.ts | 13 +++ .../fourslash/jsdocImportTagCompletion2.ts | 14 +++ .../fourslash/jsdocImportTagCompletion3.ts | 18 +++ tests/cases/fourslash/renameJsDocImportTag.ts | 19 ++++ 40 files changed, 1069 insertions(+) create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag1.json create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag2.json create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag3.json create mode 100644 tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag4.json create mode 100644 tests/baselines/reference/findAllRefsJsDocImportTag.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTag1.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTag2.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTag3.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTag4.baseline.jsonc create mode 100644 tests/baselines/reference/goToDefinitionJsDocImportTag5.baseline.jsonc create mode 100644 tests/baselines/reference/importTag1.symbols create mode 100644 tests/baselines/reference/importTag1.types create mode 100644 tests/baselines/reference/importTag2.symbols create mode 100644 tests/baselines/reference/importTag2.types create mode 100644 tests/baselines/reference/importTag3.symbols create mode 100644 tests/baselines/reference/importTag3.types create mode 100644 tests/baselines/reference/importTag4.errors.txt create mode 100644 tests/baselines/reference/importTag4.symbols create mode 100644 tests/baselines/reference/importTag4.types create mode 100644 tests/baselines/reference/importTag5.js create mode 100644 tests/baselines/reference/importTag5.symbols create mode 100644 tests/baselines/reference/importTag5.types create mode 100644 tests/baselines/reference/jsdocImportTagCompletion2.baseline create mode 100644 tests/baselines/reference/jsdocImportTagCompletion3.baseline create mode 100644 tests/baselines/reference/renameJsDocImportTag.baseline.jsonc create mode 100644 tests/cases/conformance/jsdoc/importTag1.ts create mode 100644 tests/cases/conformance/jsdoc/importTag2.ts create mode 100644 tests/cases/conformance/jsdoc/importTag3.ts create mode 100644 tests/cases/conformance/jsdoc/importTag4.ts create mode 100644 tests/cases/conformance/jsdoc/importTag5.ts create mode 100644 tests/cases/fourslash/findAllRefsJsDocImportTag.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTag1.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTag2.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTag3.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTag4.ts create mode 100644 tests/cases/fourslash/goToDefinitionJsDocImportTag5.ts create mode 100644 tests/cases/fourslash/jsdocImportTagCompletion1.ts create mode 100644 tests/cases/fourslash/jsdocImportTagCompletion2.ts create mode 100644 tests/cases/fourslash/jsdocImportTagCompletion3.ts create mode 100644 tests/cases/fourslash/renameJsDocImportTag.ts diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag1.json new file mode 100644 index 0000000000000..4b1926859ba6b --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag1.json @@ -0,0 +1,54 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 35, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTag", + "pos": 8, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "import" + }, + "importClause": { + "kind": "ImportClause", + "pos": 16, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "name": { + "kind": "Identifier", + "pos": 16, + "end": 19, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "foo" + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 24, + "end": 30, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 30, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag2.json new file mode 100644 index 0000000000000..a6f633d01dbec --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag2.json @@ -0,0 +1,76 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 39, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTag", + "pos": 8, + "end": 34, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "import" + }, + "importClause": { + "kind": "ImportClause", + "pos": 16, + "end": 23, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamedImports", + "pos": 16, + "end": 23, + "modifierFlagsCache": 0, + "transformFlags": 0, + "elements": { + "0": { + "kind": "ImportSpecifier", + "pos": 17, + "end": 21, + "modifierFlagsCache": 0, + "transformFlags": 0, + "isTypeOnly": false, + "name": { + "kind": "Identifier", + "pos": 17, + "end": 21, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "foo" + } + }, + "length": 1, + "pos": 17, + "end": 21, + "hasTrailingComma": false, + "transformFlags": 0 + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 28, + "end": 34, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 34, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag3.json new file mode 100644 index 0000000000000..fd0b84c089d5a --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag3.json @@ -0,0 +1,61 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 42, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTag", + "pos": 8, + "end": 37, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "import" + }, + "importClause": { + "kind": "ImportClause", + "pos": 16, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamespaceImport", + "pos": 16, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 0, + "name": { + "kind": "Identifier", + "pos": 20, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "types" + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 31, + "end": 37, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 37, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag4.json new file mode 100644 index 0000000000000..f25a957cd57db --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.importTag4.json @@ -0,0 +1,62 @@ +{ + "kind": "JSDoc", + "pos": 0, + "end": 55, + "flags": "JSDoc", + "modifierFlagsCache": 0, + "transformFlags": 0, + "tags": { + "0": { + "kind": "JSDocImportTag", + "pos": 8, + "end": 53, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 9, + "end": 15, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "import" + }, + "comment": "comment part", + "importClause": { + "kind": "ImportClause", + "pos": 16, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 1, + "isTypeOnly": true, + "namedBindings": { + "kind": "NamespaceImport", + "pos": 16, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 0, + "name": { + "kind": "Identifier", + "pos": 20, + "end": 26, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "types" + } + } + }, + "moduleSpecifier": { + "kind": "StringLiteral", + "pos": 31, + "end": 37, + "modifierFlagsCache": 0, + "transformFlags": 0, + "text": "foo" + } + }, + "length": 1, + "pos": 8, + "end": 53, + "hasTrailingComma": false, + "transformFlags": 0 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/findAllRefsJsDocImportTag.baseline.jsonc b/tests/baselines/reference/findAllRefsJsDocImportTag.baseline.jsonc new file mode 100644 index 0000000000000..46b3bdd60105c --- /dev/null +++ b/tests/baselines/reference/findAllRefsJsDocImportTag.baseline.jsonc @@ -0,0 +1,105 @@ +// === findAllReferences === +// === /a.js === +// /** +// * <|@import { [|{| defId: 0, isWriteAccess: true |}A|] } from "./b"; +// |>*/ +// +// /** +// * @param { [|{| defId: 0 |}A|]/*FIND ALL REFS*/ } a +// */ +// function f(a) {} + +// === /b.ts === +// <|export interface [|{| defId: 1, isWriteAccess: true |}A|] { }|> + + // === Definitions === + // === /a.js === + // /** + // * <|@import { [|{| defId: 0 |}A|] } from "./b"; + // |>*/ + // + // /** + // * @param { A/*FIND ALL REFS*/ } a + // */ + // function f(a) {} + + // === /b.ts === + // <|export interface [|{| defId: 1 |}A|] { }|> + + // === Details === + [ + { + "defId": 0, + "containerKind": "", + "containerName": "", + "kind": "alias", + "name": "(alias) interface A\nimport A", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "alias", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "aliasName" + }, + { + "text": "\n", + "kind": "lineBreak" + }, + { + "text": "import", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "aliasName" + } + ] + }, + { + "defId": 1, + "containerKind": "", + "containerName": "", + "kind": "interface", + "name": "interface A", + "displayParts": [ + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "interfaceName" + } + ] + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTag1.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTag1.baseline.jsonc new file mode 100644 index 0000000000000..2ac01a22845c7 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTag1.baseline.jsonc @@ -0,0 +1,17 @@ +// === goToDefinition === +// === /b.ts === +// [||]export interface A { } + +// === /a.js === +// /** +// * @import { A } from [|"./b/*GOTO DEF*/"|] +// */ + + // === Details === + [ + { + "kind": "script", + "name": "./b", + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTag2.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTag2.baseline.jsonc new file mode 100644 index 0000000000000..70db19f1b24fd --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTag2.baseline.jsonc @@ -0,0 +1,5 @@ +// === goToDefinition === +// === /a.js === +// /** +// * @import { A } from/*GOTO DEF*/ "./b" +// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTag3.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTag3.baseline.jsonc new file mode 100644 index 0000000000000..443b3ca3d9c62 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTag3.baseline.jsonc @@ -0,0 +1,5 @@ +// === goToDefinition === +// === /a.js === +// /** +// * @import { A } from /*GOTO DEF*/ "./b"; +// */ \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTag4.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTag4.baseline.jsonc new file mode 100644 index 0000000000000..8db114c5c52f3 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTag4.baseline.jsonc @@ -0,0 +1,20 @@ +// === goToDefinition === +// === /b.ts === +// <|export interface [|A|] { }|> + +// === /a.js === +// /** +// * @import { [|A|]/*GOTO DEF*/ } from "./b"; +// */ + + // === Details === + [ + { + "kind": "interface", + "name": "A", + "containerName": "\"/b\"", + "isLocal": false, + "isAmbient": false, + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionJsDocImportTag5.baseline.jsonc b/tests/baselines/reference/goToDefinitionJsDocImportTag5.baseline.jsonc new file mode 100644 index 0000000000000..e58acd52951ca --- /dev/null +++ b/tests/baselines/reference/goToDefinitionJsDocImportTag5.baseline.jsonc @@ -0,0 +1,25 @@ +// === goToDefinition === +// === /b.ts === +// <|export interface [|A|] { }|> + +// === /a.js === +// /** +// * @import { A } from "./b"; +// */ +// +// /** +// * @param { [|A|]/*GOTO DEF*/ } a +// */ +// function f(a) {} + + // === Details === + [ + { + "kind": "interface", + "name": "A", + "containerName": "\"/b\"", + "isLocal": false, + "isAmbient": false, + "unverified": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/importTag1.symbols b/tests/baselines/reference/importTag1.symbols new file mode 100644 index 0000000000000..ba55b1fac1cc9 --- /dev/null +++ b/tests/baselines/reference/importTag1.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTag1.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 11)) + diff --git a/tests/baselines/reference/importTag1.types b/tests/baselines/reference/importTag1.types new file mode 100644 index 0000000000000..b442a096969a8 --- /dev/null +++ b/tests/baselines/reference/importTag1.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTag1.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTag2.symbols b/tests/baselines/reference/importTag2.symbols new file mode 100644 index 0000000000000..549bf3dd77536 --- /dev/null +++ b/tests/baselines/reference/importTag2.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTag2.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @import * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 18)) + diff --git a/tests/baselines/reference/importTag2.types b/tests/baselines/reference/importTag2.types new file mode 100644 index 0000000000000..5a18d5e849e91 --- /dev/null +++ b/tests/baselines/reference/importTag2.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTag2.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} +>f : (foo: types.Foo) => void +>foo : types.Foo + diff --git a/tests/baselines/reference/importTag3.symbols b/tests/baselines/reference/importTag3.symbols new file mode 100644 index 0000000000000..9c6ecab2ed79f --- /dev/null +++ b/tests/baselines/reference/importTag3.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTag3.ts] //// + +=== /types.ts === +export default interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 30)) +} + +=== /foo.js === +/** + * @import Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 18)) + diff --git a/tests/baselines/reference/importTag3.types b/tests/baselines/reference/importTag3.types new file mode 100644 index 0000000000000..da6d62466da82 --- /dev/null +++ b/tests/baselines/reference/importTag3.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTag3.ts] //// + +=== /types.ts === +export default interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTag4.errors.txt b/tests/baselines/reference/importTag4.errors.txt new file mode 100644 index 0000000000000..dbfd8ad5b4132 --- /dev/null +++ b/tests/baselines/reference/importTag4.errors.txt @@ -0,0 +1,27 @@ +/foo.js(2,14): error TS2300: Duplicate identifier 'Foo'. +/foo.js(6,14): error TS2300: Duplicate identifier 'Foo'. + + +==== /types.ts (0 errors) ==== + export interface Foo { + a: number; + } + +==== /foo.js (2 errors) ==== + /** + * @import { Foo } from "./types" + ~~~ +!!! error TS2300: Duplicate identifier 'Foo'. + */ + + /** + * @import { Foo } from "./types" + ~~~ +!!! error TS2300: Duplicate identifier 'Foo'. + */ + + /** + * @param { Foo } foo + */ + function f(foo) {} + \ No newline at end of file diff --git a/tests/baselines/reference/importTag4.symbols b/tests/baselines/reference/importTag4.symbols new file mode 100644 index 0000000000000..67ce4c4fc307d --- /dev/null +++ b/tests/baselines/reference/importTag4.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/jsdoc/importTag4.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 11, 11)) + diff --git a/tests/baselines/reference/importTag4.types b/tests/baselines/reference/importTag4.types new file mode 100644 index 0000000000000..473a932a89ce2 --- /dev/null +++ b/tests/baselines/reference/importTag4.types @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/jsdoc/importTag4.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/importTag5.js b/tests/baselines/reference/importTag5.js new file mode 100644 index 0000000000000..cd2819da251ea --- /dev/null +++ b/tests/baselines/reference/importTag5.js @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag5.ts] //// + +//// [types.ts] +export interface Foo { + a: number; +} + +//// [foo.js] +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} + + + + +//// [types.d.ts] +export interface Foo { + a: number; +} +//// [foo.d.ts] +/** + * @import { Foo } from "./types" + */ +/** + * @param { Foo } foo + */ +declare function f(foo: import("./types").Foo): void; diff --git a/tests/baselines/reference/importTag5.symbols b/tests/baselines/reference/importTag5.symbols new file mode 100644 index 0000000000000..35242e6c8988e --- /dev/null +++ b/tests/baselines/reference/importTag5.symbols @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTag5.ts] //// + +=== /types.ts === +export interface Foo { +>Foo : Symbol(Foo, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(types.ts, 0, 22)) +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>foo : Symbol(foo, Decl(foo.js, 7, 11)) + diff --git a/tests/baselines/reference/importTag5.types b/tests/baselines/reference/importTag5.types new file mode 100644 index 0000000000000..7d9641be55328 --- /dev/null +++ b/tests/baselines/reference/importTag5.types @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTag5.ts] //// + +=== /types.ts === +export interface Foo { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} +>f : (foo: Foo) => void +>foo : Foo + diff --git a/tests/baselines/reference/jsdocImportTagCompletion2.baseline b/tests/baselines/reference/jsdocImportTagCompletion2.baseline new file mode 100644 index 0000000000000..e05a6ff4579fd --- /dev/null +++ b/tests/baselines/reference/jsdocImportTagCompletion2.baseline @@ -0,0 +1,48 @@ +// === Completions === +=== /b.js === +// /** +// * @import { } from "./a" +// ^ +// | ---------------------------------------------------------------------- +// | interface A +// | ---------------------------------------------------------------------- +// */ + +[ + { + "marker": { + "fileName": "/b.js", + "position": 17, + "name": "" + }, + "item": { + "flags": 0, + "isGlobalCompletion": false, + "isMemberCompletion": true, + "isNewIdentifierLocation": false, + "entries": [ + { + "name": "A", + "kind": "interface", + "kindModifiers": "export", + "sortText": "11", + "displayParts": [ + { + "text": "interface", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "A", + "kind": "interfaceName" + } + ], + "documentation": [] + } + ] + } + } +] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocImportTagCompletion3.baseline b/tests/baselines/reference/jsdocImportTagCompletion3.baseline new file mode 100644 index 0000000000000..6d25b1ae8f40c --- /dev/null +++ b/tests/baselines/reference/jsdocImportTagCompletion3.baseline @@ -0,0 +1,51 @@ +// === Completions === +=== /tests/cases/fourslash/./c.js === +// /** +// * @import * as types from "./" +// ^ +// | ---------------------------------------------------------------------- +// | a +// | b +// | ---------------------------------------------------------------------- +// */ + +[ + { + "marker": { + "fileName": "/tests/cases/fourslash/./c.js", + "position": 34, + "name": "" + }, + "item": { + "isGlobalCompletion": false, + "isMemberCompletion": false, + "isNewIdentifierLocation": true, + "entries": [ + { + "name": "a", + "kind": "script", + "kindModifiers": ".ts", + "sortText": "11", + "displayParts": [ + { + "text": "a", + "kind": "text" + } + ] + }, + { + "name": "b", + "kind": "script", + "kindModifiers": ".ts", + "sortText": "11", + "displayParts": [ + { + "text": "b", + "kind": "text" + } + ] + } + ] + } + } +] \ No newline at end of file diff --git a/tests/baselines/reference/renameJsDocImportTag.baseline.jsonc b/tests/baselines/reference/renameJsDocImportTag.baseline.jsonc new file mode 100644 index 0000000000000..69afeb9c6e35a --- /dev/null +++ b/tests/baselines/reference/renameJsDocImportTag.baseline.jsonc @@ -0,0 +1,10 @@ +// === findRenameLocations === +// === /a.js === +// /** +// * <|@import { /*START PREFIX*/A as [|ARENAME|] } from "./b"; +// |>*/ +// +// /** +// * @param { [|ARENAME|]/*RENAME*/ } a +// */ +// function f(a) {} \ No newline at end of file diff --git a/tests/cases/conformance/jsdoc/importTag1.ts b/tests/cases/conformance/jsdoc/importTag1.ts new file mode 100644 index 0000000000000..b85735da4d96b --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag1.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTag2.ts b/tests/cases/conformance/jsdoc/importTag2.ts new file mode 100644 index 0000000000000..e306afb43a828 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag2.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @import * as types from "./types" + */ + +/** + * @param { types.Foo } foo + */ +export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTag3.ts b/tests/cases/conformance/jsdoc/importTag3.ts new file mode 100644 index 0000000000000..7ebe8894b5243 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag3.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export default interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @import Foo from "./types" + */ + +/** + * @param { Foo } foo + */ +export function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTag4.ts b/tests/cases/conformance/jsdoc/importTag4.ts new file mode 100644 index 0000000000000..1f76717279c5b --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag4.ts @@ -0,0 +1,22 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @import { Foo } from "./types" + */ + +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} diff --git a/tests/cases/conformance/jsdoc/importTag5.ts b/tests/cases/conformance/jsdoc/importTag5.ts new file mode 100644 index 0000000000000..7dfedad464d9b --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag5.ts @@ -0,0 +1,19 @@ +// @checkJs: true +// @allowJs: true +// @declaration: true +// @emitDeclarationOnly: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** + * @import { Foo } from "./types" + */ + +/** + * @param { Foo } foo + */ +function f(foo) {} diff --git a/tests/cases/fourslash/findAllRefsJsDocImportTag.ts b/tests/cases/fourslash/findAllRefsJsDocImportTag.ts new file mode 100644 index 0000000000000..8fb66d013e57f --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsDocImportTag.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface A { } + +// @Filename: /a.js +/////** +//// * @import { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/**/|] } a +//// */ +////function f(a) {} + +verify.baselineFindAllReferences(""); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTag1.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTag1.ts new file mode 100644 index 0000000000000..56983716b193e --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTag1.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @import { A } from [|"./b/*1*/"|] +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTag2.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTag2.ts new file mode 100644 index 0000000000000..bc8ed4cde99e6 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTag2.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @import { A } [|from/*1*/|] "./b" +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTag3.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTag3.ts new file mode 100644 index 0000000000000..239c42803a1a8 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTag3.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +/////*2*/export interface A { } + +// @Filename: /a.js +/////** +//// * @import { A } [|from /*1*/|] "./b"; +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTag4.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTag4.ts new file mode 100644 index 0000000000000..fd47f3555899b --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTag4.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface /*2*/A { } + +// @Filename: /a.js +/////** +//// * @import { [|A/*1*/|] } from "./b"; +//// */ + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionJsDocImportTag5.ts b/tests/cases/fourslash/goToDefinitionJsDocImportTag5.ts new file mode 100644 index 0000000000000..fb8a886d5f6af --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionJsDocImportTag5.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface /*2*/A { } + +// @Filename: /a.js +/////** +//// * @import { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/*1*/|] } a +//// */ +////function f(a) {} + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/jsdocImportTagCompletion1.ts b/tests/cases/fourslash/jsdocImportTagCompletion1.ts new file mode 100644 index 0000000000000..cb7ed23924193 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTagCompletion1.ts @@ -0,0 +1,13 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @filename: /a.js +/////** +//// * @/**/ +//// */ + +verify.completions( + { marker: "", includes: ["import"] }, +); diff --git a/tests/cases/fourslash/jsdocImportTagCompletion2.ts b/tests/cases/fourslash/jsdocImportTagCompletion2.ts new file mode 100644 index 0000000000000..4a249ba7f6054 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTagCompletion2.ts @@ -0,0 +1,14 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @filename: /a.ts +////export interface A {} + +// @filename: /b.js +/////** +//// * @import { /**/ } from "./a" +//// */ + +verify.baselineCompletions(); diff --git a/tests/cases/fourslash/jsdocImportTagCompletion3.ts b/tests/cases/fourslash/jsdocImportTagCompletion3.ts new file mode 100644 index 0000000000000..3b84d092aa6d8 --- /dev/null +++ b/tests/cases/fourslash/jsdocImportTagCompletion3.ts @@ -0,0 +1,18 @@ +/// + +// @allowJS: true +// @checkJs: true +// @module: esnext + +// @filename: ./a.ts +////export interface A {} + +// @filename: ./b.ts +////export interface B {} + +// @filename: ./c.js +/////** +//// * @import * as types from ".//**/" +//// */ + +verify.baselineCompletions(); diff --git a/tests/cases/fourslash/renameJsDocImportTag.ts b/tests/cases/fourslash/renameJsDocImportTag.ts new file mode 100644 index 0000000000000..1e76dc1df8166 --- /dev/null +++ b/tests/cases/fourslash/renameJsDocImportTag.ts @@ -0,0 +1,19 @@ +/// + +// @allowJS: true +// @checkJs: true + +// @Filename: /b.ts +////export interface A { } + +// @Filename: /a.js +/////** +//// * @import { A } from "./b"; +//// */ +//// +/////** +//// * @param { [|A/**/|] } a +//// */ +////function f(a) {} + +verify.baselineRename(""); From d62969332f5f79580c370959a6489b5518527c63 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 1 Feb 2024 23:45:59 +0200 Subject: [PATCH 09/23] auto import fix to existing jsdoc imports --- src/compiler/types.ts | 6 +-- src/services/codefixes/importFixes.ts | 15 +++++-- .../cases/fourslash/autoImportJsDocImport1.ts | 40 +++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/autoImportJsDocImport1.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8a1946e512e68..904bdcb3e5290 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5548,13 +5548,13 @@ export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | Assert export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; /** @internal */ -export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitializedTo; +export type AnyImportOrJsDocImport = AnyImportSyntax | JSDocImportTag; /** @internal */ -export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; +export type AnyImportOrRequire = AnyImportOrJsDocImport | VariableDeclarationInitializedTo; /** @internal */ -export type AnyImportOrJsDocImport = AnyImportSyntax | JSDocImportTag; +export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; /** @internal */ export type AliasDeclarationNode = diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index a634ac334a02f..4724d8c37d504 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -74,6 +74,7 @@ import { isImportEqualsDeclaration, isInJSFile, isIntrinsicJsxName, + isJSDocImportTag, isJsxClosingElement, isJsxOpeningFragment, isJsxOpeningLikeElement, @@ -460,6 +461,7 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program const enum ImportFixKind { UseNamespace, JsdocTypeImport, + JSDocImport, AddToExisting, AddNew, PromoteTypeOnly, @@ -697,6 +699,7 @@ function getNamespaceLikeImportText(declaration: AnyImportOrRequire) { return tryCast(declaration.name, isIdentifier)?.text; case SyntaxKind.ImportEqualsDeclaration: return declaration.name.text; + case SyntaxKind.JSDocImportTag: case SyntaxKind.ImportDeclaration: return tryCast(declaration.importClause?.namedBindings, isNamespaceImport)?.name.text; default: @@ -813,7 +816,7 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile (importMap ||= createMultiMap()).add(getSymbolId(moduleSymbol), i.parent); } } - else if (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration) { + else if (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration || i.kind === SyntaxKind.JSDocImportTag) { const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier); if (moduleSymbol) { (importMap ||= createMultiMap()).add(getSymbolId(moduleSymbol), i); @@ -823,10 +826,16 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile return { getImportsForExportInfo: ({ moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo): readonly FixAddToExistingImportInfo[] => { - // Can't use an es6 import for a type in JS. - if (!(targetFlags & SymbolFlags.Value) && isSourceFileJS(importingFile)) return emptyArray; const matchingDeclarations = importMap?.get(getSymbolId(moduleSymbol)); if (!matchingDeclarations) return emptyArray; + + // Can't use an es6 import for a type in JS. + if ( + isSourceFileJS(importingFile) + && !(targetFlags & SymbolFlags.Value) + && !every(matchingDeclarations, isJSDocImportTag) + ) return emptyArray; + const importKind = getImportKind(importingFile, exportKind, compilerOptions); return matchingDeclarations.map(declaration => ({ declaration, importKind, symbol, targetFlags })); }, diff --git a/tests/cases/fourslash/autoImportJsDocImport1.ts b/tests/cases/fourslash/autoImportJsDocImport1.ts new file mode 100644 index 0000000000000..65fa9f9506de2 --- /dev/null +++ b/tests/cases/fourslash/autoImportJsDocImport1.ts @@ -0,0 +1,40 @@ +/// + +// @verbatimModuleSyntax: true +// @target: esnext +// @allowJs: true +// @checkJs: true + +// @Filename: /foo.ts +//// export const A = 1; +//// export type B = { x: number }; +//// export type C = 1; +//// export class D { y: string } + +// @Filename: /test.js +/////** +//// * @import { A, D, C } from "./foo" +//// */ +//// +/////** +//// * @param { typeof A } a +//// * @param { B/**/ | C } b +//// * @param { C } c +//// * @param { D } d +//// */ +////export function f(a, b, c, d) { } + +goTo.marker(""); +verify.importFixAtPosition([ +`/** + * @import { A, D, C, B } from "./foo" + */ + +/** + * @param { typeof A } a + * @param { B | C } b + * @param { C } c + * @param { D } d + */ +export function f(a, b, c, d) { }` +]); From 6ec3b277c2cce23056f9e2d8f9fb48bf50b3dcfe Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Fri, 2 Feb 2024 19:22:00 +0200 Subject: [PATCH 10/23] cleanup --- src/compiler/utilities.ts | 2 +- src/services/importTracker.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f4e92ea062cd4..71c81a6ba1693 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4072,7 +4072,7 @@ export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqua /** @internal */ export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration | JSDocImportTag): boolean { - return node.kind === SyntaxKind.ImportDeclaration && !!node.importClause && !!node.importClause.name; + return (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.JSDocImportTag) && !!node.importClause && !!node.importClause.name; } /** @internal */ diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index a3c4e9a495ef1..6f54bf158e48d 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -1,5 +1,6 @@ import { __String, + AnyImportOrJsDocImport, AnyImportOrReExport, AssignmentDeclarationKind, BinaryExpression, @@ -269,7 +270,7 @@ function getImportersForExport( }); } - function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration | JSDocImportTag, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { + function handleNamespaceImport(importDeclaration: AnyImportOrJsDocImport, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { if (exportKind === ExportKind.ExportEquals) { // This is a direct import, not import-as-namespace. if (!alreadyAddedDirect) directImports.push(importDeclaration); From ad246240ec22b7ff007d2011f85efd027ef73187 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sun, 4 Feb 2024 00:42:18 +0200 Subject: [PATCH 11/23] handle multiline import clause --- src/compiler/parser.ts | 30 ++++++++++++++++++++++++------ src/compiler/scanner.ts | 12 ++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3aed7f7b9ea1a..5138fafe736e4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3884,7 +3884,7 @@ namespace Parser { } function parseJSDocType(): TypeNode { - scanner.setInJSDocType(true); + scanner.setSkipJsDocLeadingAsterisks(true); const pos = getNodePos(); if (parseOptional(SyntaxKind.ModuleKeyword)) { // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here? @@ -3902,13 +3902,13 @@ namespace Parser { } } - scanner.setInJSDocType(false); + scanner.setSkipJsDocLeadingAsterisks(false); return finishNode(moduleTag, pos); } const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken); let type = parseTypeOrTypePredicate(); - scanner.setInJSDocType(false); + scanner.setSkipJsDocLeadingAsterisks(false); if (hasDotDotDot) { type = finishNode(factory.createJSDocVariadicType(type), pos); } @@ -9471,7 +9471,7 @@ namespace Parser { || token() === SyntaxKind.AsteriskToken // @import * || token() === SyntaxKind.OpenBraceToken // @import { ) { - importClause = parseImportClause(identifier, afterImportTypeTagPos, /*isTypeOnly*/ true); + importClause = parseJsDocImportClause(identifier, afterImportTypeTagPos); parseExpected(SyntaxKind.FromKeyword); } @@ -9482,13 +9482,31 @@ namespace Parser { return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, comments), start); } + function parseJsDocImportClause(identifier: Identifier | undefined, pos: number) { + let namedBindings: NamespaceImport | NamedImports | undefined; + if ( + !identifier || + parseOptional(SyntaxKind.CommaToken) + ) { + if (token() === SyntaxKind.AsteriskToken) { + namedBindings = parseNamespaceImport(); + } + else { + scanner.setSkipJsDocLeadingAsterisks(true); + namedBindings = parseNamedImportsOrExports(SyntaxKind.NamedImports); + scanner.setSkipJsDocLeadingAsterisks(false); + } + } + return finishNode(factory.createImportClause(/*isTypeOnly*/ true, identifier, namedBindings), pos); + } + function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } { const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); const pos = getNodePos(); const expression = parsePropertyAccessEntityNameExpression(); - scanner.setInJSDocType(true); + scanner.setSkipJsDocLeadingAsterisks(true); const typeArguments = tryParseTypeArguments(); - scanner.setInJSDocType(false); + scanner.setSkipJsDocLeadingAsterisks(false); const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; }; const res = finishNode(node, pos); if (usedBrace) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index e774321c95e2d..8813e2eec7f9a 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -103,7 +103,7 @@ export interface Scanner { setTextPos(textPos: number): void; resetTokenState(pos: number): void; /** @internal */ - setInJSDocType(inType: boolean): void; + setSkipJsDocLeadingAsterisks(skip: boolean): void; // Invokes the provided callback then unconditionally restores the scanner to the state it // was in immediately prior to invoking the callback. The result of invoking the callback // is returned from this function. @@ -1005,7 +1005,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean var tokenFlags: TokenFlags; var commentDirectives: CommentDirective[] | undefined; - var inJSDocType = 0; + var skipJsDocLeadingAsterisks = 0; var scriptKind = ScriptKind.Unknown; var jsDocParsingMode = JSDocParsingMode.ParseAll; @@ -1059,7 +1059,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean setOnError, resetTokenState, setTextPos: resetTokenState, - setInJSDocType, + setSkipJsDocLeadingAsterisks, tryScan, lookAhead, scanRange, @@ -1919,7 +1919,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean return pos += 2, token = SyntaxKind.AsteriskAsteriskToken; } pos++; - if (inJSDocType && !asteriskSeen && (tokenFlags & TokenFlags.PrecedingLineBreak)) { + if (skipJsDocLeadingAsterisks && !asteriskSeen && (tokenFlags & TokenFlags.PrecedingLineBreak)) { // decoration at the start of a JSDoc comment line asteriskSeen = true; continue; @@ -2831,8 +2831,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean tokenFlags = TokenFlags.None; } - function setInJSDocType(inType: boolean) { - inJSDocType += inType ? 1 : -1; + function setSkipJsDocLeadingAsterisks(skip: boolean) { + skipJsDocLeadingAsterisks += skip ? 1 : -1; } } From 26f633fdfe959cf96c41784449fe7303170dbd24 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sun, 4 Feb 2024 00:43:12 +0200 Subject: [PATCH 12/23] add tests --- tests/baselines/reference/importTag6.symbols | 33 ++++++++++++++++++++ tests/baselines/reference/importTag6.types | 29 +++++++++++++++++ tests/cases/conformance/jsdoc/importTag6.ts | 25 +++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/baselines/reference/importTag6.symbols create mode 100644 tests/baselines/reference/importTag6.types create mode 100644 tests/cases/conformance/jsdoc/importTag6.ts diff --git a/tests/baselines/reference/importTag6.symbols b/tests/baselines/reference/importTag6.symbols new file mode 100644 index 0000000000000..3b917273f6476 --- /dev/null +++ b/tests/baselines/reference/importTag6.symbols @@ -0,0 +1,33 @@ +//// [tests/cases/conformance/jsdoc/importTag6.ts] //// + +=== /types.ts === +export interface A { +>A : Symbol(A, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(A.a, Decl(types.ts, 0, 20)) +} +export interface B { +>B : Symbol(B, Decl(types.ts, 2, 1)) + + a: number; +>a : Symbol(B.a, Decl(types.ts, 3, 20)) +} + +=== /foo.js === +/** + * @import { + * A, + * B, + * } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>a : Symbol(a, Decl(foo.js, 11, 11)) +>b : Symbol(b, Decl(foo.js, 11, 13)) + diff --git a/tests/baselines/reference/importTag6.types b/tests/baselines/reference/importTag6.types new file mode 100644 index 0000000000000..5adef07704d7e --- /dev/null +++ b/tests/baselines/reference/importTag6.types @@ -0,0 +1,29 @@ +//// [tests/cases/conformance/jsdoc/importTag6.ts] //// + +=== /types.ts === +export interface A { + a: number; +>a : number +} +export interface B { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import { + * A, + * B, + * } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : (a: * A, b: * B) => void +>a : * A +>b : * B + diff --git a/tests/cases/conformance/jsdoc/importTag6.ts b/tests/cases/conformance/jsdoc/importTag6.ts new file mode 100644 index 0000000000000..2d6470c3ff55a --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag6.ts @@ -0,0 +1,25 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface A { + a: number; +} +export interface B { + a: number; +} + +// @filename: /foo.js +/** + * @import { + * A, + * B, + * } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} From 82f79bed851b6bdd725e40bf9db0c8a4b1834621 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 7 Feb 2024 02:10:02 +0200 Subject: [PATCH 13/23] cleanup --- src/services/codefixes/importFixes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 4724d8c37d504..021bec2b8bf91 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -461,7 +461,6 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program const enum ImportFixKind { UseNamespace, JsdocTypeImport, - JSDocImport, AddToExisting, AddNew, PromoteTypeOnly, From a76450e7bb938e427c5ec4fdb3d93a2b0d920e47 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 8 Feb 2024 02:58:40 +0200 Subject: [PATCH 14/23] add additional import tag parsing test --- tests/baselines/reference/importTag7.symbols | 32 ++++++++++++++++++++ tests/baselines/reference/importTag7.types | 28 +++++++++++++++++ tests/cases/conformance/jsdoc/importTag7.ts | 24 +++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/baselines/reference/importTag7.symbols create mode 100644 tests/baselines/reference/importTag7.types create mode 100644 tests/cases/conformance/jsdoc/importTag7.ts diff --git a/tests/baselines/reference/importTag7.symbols b/tests/baselines/reference/importTag7.symbols new file mode 100644 index 0000000000000..b4aa8eaf26004 --- /dev/null +++ b/tests/baselines/reference/importTag7.symbols @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag7.ts] //// + +=== /types.ts === +export interface A { +>A : Symbol(A, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(A.a, Decl(types.ts, 0, 20)) +} +export interface B { +>B : Symbol(B, Decl(types.ts, 2, 1)) + + a: number; +>a : Symbol(B.a, Decl(types.ts, 3, 20)) +} + +=== /foo.js === +/** + * @import { + * A, + * B } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>a : Symbol(a, Decl(foo.js, 10, 11)) +>b : Symbol(b, Decl(foo.js, 10, 13)) + diff --git a/tests/baselines/reference/importTag7.types b/tests/baselines/reference/importTag7.types new file mode 100644 index 0000000000000..f97e3f166e982 --- /dev/null +++ b/tests/baselines/reference/importTag7.types @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/jsdoc/importTag7.ts] //// + +=== /types.ts === +export interface A { + a: number; +>a : number +} +export interface B { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import { + * A, + * B } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : (a: * A, b: * B) => void +>a : * A +>b : * B + diff --git a/tests/cases/conformance/jsdoc/importTag7.ts b/tests/cases/conformance/jsdoc/importTag7.ts new file mode 100644 index 0000000000000..d6643e411f268 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag7.ts @@ -0,0 +1,24 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface A { + a: number; +} +export interface B { + a: number; +} + +// @filename: /foo.js +/** + * @import { + * A, + * B } from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} From 9003fbfa203b842b2a9e170a0ccd8ad8d5782d0d Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 8 Feb 2024 03:16:14 +0200 Subject: [PATCH 15/23] add additional import tag parsing tests --- src/compiler/parser.ts | 11 ++----- tests/baselines/reference/importTag8.symbols | 32 ++++++++++++++++++++ tests/baselines/reference/importTag8.types | 28 +++++++++++++++++ tests/baselines/reference/importTag9.symbols | 32 ++++++++++++++++++++ tests/baselines/reference/importTag9.types | 28 +++++++++++++++++ tests/cases/conformance/jsdoc/importTag8.ts | 24 +++++++++++++++ tests/cases/conformance/jsdoc/importTag9.ts | 24 +++++++++++++++ 7 files changed, 171 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/importTag8.symbols create mode 100644 tests/baselines/reference/importTag8.types create mode 100644 tests/baselines/reference/importTag9.symbols create mode 100644 tests/baselines/reference/importTag9.types create mode 100644 tests/cases/conformance/jsdoc/importTag8.ts create mode 100644 tests/cases/conformance/jsdoc/importTag9.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5138fafe736e4..7808e7a5ad4b5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9488,14 +9488,9 @@ namespace Parser { !identifier || parseOptional(SyntaxKind.CommaToken) ) { - if (token() === SyntaxKind.AsteriskToken) { - namedBindings = parseNamespaceImport(); - } - else { - scanner.setSkipJsDocLeadingAsterisks(true); - namedBindings = parseNamedImportsOrExports(SyntaxKind.NamedImports); - scanner.setSkipJsDocLeadingAsterisks(false); - } + scanner.setSkipJsDocLeadingAsterisks(true); + namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + scanner.setSkipJsDocLeadingAsterisks(false); } return finishNode(factory.createImportClause(/*isTypeOnly*/ true, identifier, namedBindings), pos); } diff --git a/tests/baselines/reference/importTag8.symbols b/tests/baselines/reference/importTag8.symbols new file mode 100644 index 0000000000000..16aae22f55617 --- /dev/null +++ b/tests/baselines/reference/importTag8.symbols @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag8.ts] //// + +=== /types.ts === +export interface A { +>A : Symbol(A, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(A.a, Decl(types.ts, 0, 20)) +} +export interface B { +>B : Symbol(B, Decl(types.ts, 2, 1)) + + a: number; +>a : Symbol(B.a, Decl(types.ts, 3, 20)) +} + +=== /foo.js === +/** + * @import + * { A, B } + * from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>a : Symbol(a, Decl(foo.js, 10, 11)) +>b : Symbol(b, Decl(foo.js, 10, 13)) + diff --git a/tests/baselines/reference/importTag8.types b/tests/baselines/reference/importTag8.types new file mode 100644 index 0000000000000..8494d7cb28c04 --- /dev/null +++ b/tests/baselines/reference/importTag8.types @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/jsdoc/importTag8.ts] //// + +=== /types.ts === +export interface A { + a: number; +>a : number +} +export interface B { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import + * { A, B } + * from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} +>f : (a: A, b: B) => void +>a : A +>b : B + diff --git a/tests/baselines/reference/importTag9.symbols b/tests/baselines/reference/importTag9.symbols new file mode 100644 index 0000000000000..dcd2cf14dd9c6 --- /dev/null +++ b/tests/baselines/reference/importTag9.symbols @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag9.ts] //// + +=== /types.ts === +export interface A { +>A : Symbol(A, Decl(types.ts, 0, 0)) + + a: number; +>a : Symbol(A.a, Decl(types.ts, 0, 20)) +} +export interface B { +>B : Symbol(B, Decl(types.ts, 2, 1)) + + a: number; +>a : Symbol(B.a, Decl(types.ts, 3, 20)) +} + +=== /foo.js === +/** + * @import + * * as types + * from "./types" + */ + +/** + * @param { types.A } a + * @param { types.B } b + */ +function f(a, b) {} +>f : Symbol(f, Decl(foo.js, 0, 0)) +>a : Symbol(a, Decl(foo.js, 10, 11)) +>b : Symbol(b, Decl(foo.js, 10, 13)) + diff --git a/tests/baselines/reference/importTag9.types b/tests/baselines/reference/importTag9.types new file mode 100644 index 0000000000000..22aef4498b3ba --- /dev/null +++ b/tests/baselines/reference/importTag9.types @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/jsdoc/importTag9.ts] //// + +=== /types.ts === +export interface A { + a: number; +>a : number +} +export interface B { + a: number; +>a : number +} + +=== /foo.js === +/** + * @import + * * as types + * from "./types" + */ + +/** + * @param { types.A } a + * @param { types.B } b + */ +function f(a, b) {} +>f : (a: types.A, b: types.B) => void +>a : types.A +>b : types.B + diff --git a/tests/cases/conformance/jsdoc/importTag8.ts b/tests/cases/conformance/jsdoc/importTag8.ts new file mode 100644 index 0000000000000..9832c5485852e --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag8.ts @@ -0,0 +1,24 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface A { + a: number; +} +export interface B { + a: number; +} + +// @filename: /foo.js +/** + * @import + * { A, B } + * from "./types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f(a, b) {} diff --git a/tests/cases/conformance/jsdoc/importTag9.ts b/tests/cases/conformance/jsdoc/importTag9.ts new file mode 100644 index 0000000000000..6cf733d5e83de --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag9.ts @@ -0,0 +1,24 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface A { + a: number; +} +export interface B { + a: number; +} + +// @filename: /foo.js +/** + * @import + * * as types + * from "./types" + */ + +/** + * @param { types.A } a + * @param { types.B } b + */ +function f(a, b) {} From 5a6cb6b218137f91af4cfc935d17f940f9c824bc Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 8 Feb 2024 23:20:59 +0200 Subject: [PATCH 16/23] handle jsdoc import tags in convert import refactoring --- src/compiler/checker.ts | 1 + src/services/refactors/convertImport.ts | 36 ++++++++++--------- .../refactorConvertImport_namespaceToNamed.ts | 18 ---------- 3 files changed, 20 insertions(+), 35 deletions(-) delete mode 100644 tests/cases/fourslash/refactorConvertImport_namespaceToNamed.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c0ccd62ad51a9..4d1902f7a82a4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3382,6 +3382,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocEnumTag: + case SyntaxKind.JSDocImportTag: // js type aliases do not resolve names from their host, so skip past it const root = getJSDocRoot(location); if (root) { diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index 55a19ef6f471e..4dbfd40d89185 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -24,12 +24,14 @@ import { ImportSpecifier, isExportSpecifier, isImportDeclaration, + isJSDocImportTag, isPropertyAccessExpression, isPropertyAccessOrQualifiedName, isShorthandPropertyAssignment, isStringLiteral, NamedImports, NamespaceImport, + or, Program, PropertyAccessExpression, QualifiedName, @@ -42,7 +44,6 @@ import { SymbolFlags, SyntaxKind, textChanges, - tryCast, TypeChecker, } from "../_namespaces/ts"; import { @@ -111,8 +112,8 @@ function getImportConversionInfo(context: RefactorContext, considerPartialSpans const { file } = context; const span = getRefactorContextSpan(context); const token = getTokenAtPosition(file, span.start); - const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) : getParentNodeInSpan(token, file, span); - if (!importDecl || !isImportDeclaration(importDecl)) return { error: "Selection is not an import declaration." }; + const importDecl = considerPartialSpans ? findAncestor(token, or(isImportDeclaration, isJSDocImportTag)) : getParentNodeInSpan(token, file, span); + if (importDecl === undefined || !(isImportDeclaration(importDecl) || isJSDocImportTag(importDecl))) return { error: "Selection is not an import declaration." }; const end = span.start + span.length; const nextToken = findNextToken(importDecl, importDecl.parent, file); @@ -189,15 +190,14 @@ function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, name === propertyName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name))); }); - const importDecl = tryCast(toConvert.parent.parent, isImportDeclaration); - Debug.assert(importDecl, "Unexpected declaration"); - - if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) { + const importDecl = toConvert.parent.parent; + if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports && isImportDeclaration(importDecl)) { // Need to leave the namespace import alone - changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); + changes.insertNodeAfter(sourceFile, importDecl, createImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); } else { - changes.replaceNode(sourceFile, importDecl, updateImport(importDecl, usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined, importSpecifiers)); + const defaultImportName = usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined; + changes.replaceNode(sourceFile, toConvert.parent, createImportClause(defaultImportName, importSpecifiers)); } } @@ -212,10 +212,7 @@ function getLeftOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: P /** @internal */ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault = getShouldUseDefault(program, toConvert.parent)): void { const checker = program.getTypeChecker(); - const importDecl = tryCast(toConvert.parent.parent, isImportDeclaration); - if (importDecl === undefined) { - Debug.assert(importDecl, "Unexpected declaration"); - } + const importDecl = toConvert.parent.parent; const { moduleSpecifier } = importDecl; const toConvertSymbols = new Set(); @@ -272,9 +269,10 @@ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, progra ? factory.createIdentifier(namespaceImportName) : factory.createNamespaceImport(factory.createIdentifier(namespaceImportName)), ); - if (neededNamedImports.size) { + + if (neededNamedImports.size && isImportDeclaration(importDecl)) { const newNamedImports: ImportSpecifier[] = arrayFrom(neededNamedImports.values(), element => factory.createImportSpecifier(element.isTypeOnly, element.propertyName && factory.createIdentifier(element.propertyName.text), factory.createIdentifier(element.name.text))); - changes.insertNodeAfter(sourceFile, toConvert.parent.parent, updateImport(importDecl, /*defaultImportName*/ undefined, newNamedImports)); + changes.insertNodeAfter(sourceFile, toConvert.parent.parent, createImport(importDecl, /*defaultImportName*/ undefined, newNamedImports)); } } @@ -285,6 +283,10 @@ function isExportEqualsModule(moduleSpecifier: Expression, checker: TypeChecker) return externalModule !== exportEquals; } -function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined): ImportDeclaration { - return factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined), old.moduleSpecifier, /*attributes*/ undefined); +function createImport(node: ImportDeclaration, defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined): ImportDeclaration { + return factory.createImportDeclaration(/*modifiers*/ undefined, createImportClause(defaultImportName, elements), node.moduleSpecifier, /*attributes*/ undefined); +} + +function createImportClause(defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined) { + return factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined); } diff --git a/tests/cases/fourslash/refactorConvertImport_namespaceToNamed.ts b/tests/cases/fourslash/refactorConvertImport_namespaceToNamed.ts deleted file mode 100644 index 0a13239217e47..0000000000000 --- a/tests/cases/fourslash/refactorConvertImport_namespaceToNamed.ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -/////*a*/import * as m from "m";/*b*/ -////const a = 0; -////m.a; -////m.b; - -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert import", - actionName: "Convert namespace import to named imports", - actionDescription: "Convert namespace import to named imports", - newContent: -`import { a as a_1, b } from "m"; -const a = 0; -a_1; -b;`, -}); From 67caac116a238f4c99e97dab08d7667b9481a434 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 8 Feb 2024 23:32:55 +0200 Subject: [PATCH 17/23] add additional tests --- src/compiler/emitter.ts | 13 ++++---- src/compiler/factory/nodeFactory.ts | 4 +-- src/compiler/parser.ts | 2 -- src/compiler/types.ts | 6 ++-- tests/baselines/reference/api/typescript.d.ts | 6 ++-- .../reference/importTag10.errors.txt | 11 +++++++ tests/baselines/reference/importTag10.symbols | 8 +++++ tests/baselines/reference/importTag10.types | 8 +++++ .../reference/importTag11.errors.txt | 13 ++++++++ tests/baselines/reference/importTag11.symbols | 8 +++++ tests/baselines/reference/importTag11.types | 8 +++++ .../reference/importTag12.errors.txt | 10 ++++++ tests/baselines/reference/importTag12.symbols | 8 +++++ tests/baselines/reference/importTag12.types | 8 +++++ tests/cases/conformance/jsdoc/importTag10.ts | 8 +++++ tests/cases/conformance/jsdoc/importTag11.ts | 8 +++++ tests/cases/conformance/jsdoc/importTag12.ts | 8 +++++ .../refactorConvertImport_namedToDefault2.ts | 26 ++++++++++++++++ ...efactorConvertImport_namedToNamespace10.ts | 15 +++++++++ ...refactorConvertImport_namespaceToNamed1.ts | 18 +++++++++++ ...refactorConvertImport_namespaceToNamed2.ts | 31 +++++++++++++++++++ 21 files changed, 211 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/importTag10.errors.txt create mode 100644 tests/baselines/reference/importTag10.symbols create mode 100644 tests/baselines/reference/importTag10.types create mode 100644 tests/baselines/reference/importTag11.errors.txt create mode 100644 tests/baselines/reference/importTag11.symbols create mode 100644 tests/baselines/reference/importTag11.types create mode 100644 tests/baselines/reference/importTag12.errors.txt create mode 100644 tests/baselines/reference/importTag12.symbols create mode 100644 tests/baselines/reference/importTag12.types create mode 100644 tests/cases/conformance/jsdoc/importTag10.ts create mode 100644 tests/cases/conformance/jsdoc/importTag11.ts create mode 100644 tests/cases/conformance/jsdoc/importTag12.ts create mode 100644 tests/cases/fourslash/refactorConvertImport_namedToDefault2.ts create mode 100644 tests/cases/fourslash/refactorConvertImport_namedToNamespace10.ts create mode 100644 tests/cases/fourslash/refactorConvertImport_namespaceToNamed1.ts create mode 100644 tests/cases/fourslash/refactorConvertImport_namespaceToNamed2.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2accbf8f872eb..fa32117f7ee65 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4457,16 +4457,17 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitJSDocImportTag(tag: JSDocImportTag) { emitJSDocTagName(tag.tagName); - writeSpace(); - emit(tag.importClause); - writeSpace(); - emitTokenWithComment(SyntaxKind.FromKeyword, tag.importClause.end, writeKeyword, tag); + if (tag.importClause) { + emit(tag.importClause); + writeSpace(); - writeSpace(); - emitExpression(tag.moduleSpecifier); + emitTokenWithComment(SyntaxKind.FromKeyword, tag.importClause.end, writeKeyword, tag); + writeSpace(); + } + emitExpression(tag.moduleSpecifier); emitJSDocComment(tag.comment); } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index a3cbe509e97de..cd69645843895 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5558,7 +5558,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag { + function createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag { const node = createBaseJSDocTag(SyntaxKind.JSDocImportTag, tagName ?? createIdentifier("import"), comment); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; @@ -5566,7 +5566,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return node; } - function updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag { + function updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag { return node.tagName !== tagName || node.comment !== comment || node.importClause !== importClause diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7808e7a5ad4b5..fe769e9989ce2 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9475,8 +9475,6 @@ namespace Parser { parseExpected(SyntaxKind.FromKeyword); } - Debug.assert(importClause); - const moduleSpecifier = parseModuleSpecifier(); const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, comments), start); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 904bdcb3e5290..05467af96cabc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4070,7 +4070,7 @@ export interface JSDocSatisfiesExpression extends ParenthesizedExpression { export interface JSDocImportTag extends JSDocTag { readonly kind: SyntaxKind.JSDocImportTag; readonly parent: JSDoc; - readonly importClause: ImportClause; + readonly importClause?: ImportClause; readonly moduleSpecifier: Expression; } @@ -8818,8 +8818,8 @@ export interface NodeFactory { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; - updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 9b2665a045bc4..3db38c17fdff0 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6388,7 +6388,7 @@ declare namespace ts { interface JSDocImportTag extends JSDocTag { readonly kind: SyntaxKind.JSDocImportTag; readonly parent: JSDoc; - readonly importClause: ImportClause; + readonly importClause?: ImportClause; readonly moduleSpecifier: Expression; } enum FlowFlags { @@ -8355,8 +8355,8 @@ declare namespace ts { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; - updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/tests/baselines/reference/importTag10.errors.txt b/tests/baselines/reference/importTag10.errors.txt new file mode 100644 index 0000000000000..496ce7f502595 --- /dev/null +++ b/tests/baselines/reference/importTag10.errors.txt @@ -0,0 +1,11 @@ +/foo.js(2,11): error TS1109: Expression expected. + + +==== /foo.js (1 errors) ==== + /** + * @import + + */ + +!!! error TS1109: Expression expected. + \ No newline at end of file diff --git a/tests/baselines/reference/importTag10.symbols b/tests/baselines/reference/importTag10.symbols new file mode 100644 index 0000000000000..f5b061a7abad6 --- /dev/null +++ b/tests/baselines/reference/importTag10.symbols @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag10.ts] //// + +=== /foo.js === + +/** + * @import + */ + diff --git a/tests/baselines/reference/importTag10.types b/tests/baselines/reference/importTag10.types new file mode 100644 index 0000000000000..f5b061a7abad6 --- /dev/null +++ b/tests/baselines/reference/importTag10.types @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag10.ts] //// + +=== /foo.js === + +/** + * @import + */ + diff --git a/tests/baselines/reference/importTag11.errors.txt b/tests/baselines/reference/importTag11.errors.txt new file mode 100644 index 0000000000000..e2c5c367f15d8 --- /dev/null +++ b/tests/baselines/reference/importTag11.errors.txt @@ -0,0 +1,13 @@ +/foo.js(2,15): error TS1109: Expression expected. +/foo.js(3,2): error TS1005: 'from' expected. + + +==== /foo.js (2 errors) ==== + /** + * @import foo + +!!! error TS1109: Expression expected. + */ + +!!! error TS1005: 'from' expected. + \ No newline at end of file diff --git a/tests/baselines/reference/importTag11.symbols b/tests/baselines/reference/importTag11.symbols new file mode 100644 index 0000000000000..4f1674c511c55 --- /dev/null +++ b/tests/baselines/reference/importTag11.symbols @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag11.ts] //// + +=== /foo.js === + +/** + * @import foo + */ + diff --git a/tests/baselines/reference/importTag11.types b/tests/baselines/reference/importTag11.types new file mode 100644 index 0000000000000..4f1674c511c55 --- /dev/null +++ b/tests/baselines/reference/importTag11.types @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag11.ts] //// + +=== /foo.js === + +/** + * @import foo + */ + diff --git a/tests/baselines/reference/importTag12.errors.txt b/tests/baselines/reference/importTag12.errors.txt new file mode 100644 index 0000000000000..f557cd1974d0b --- /dev/null +++ b/tests/baselines/reference/importTag12.errors.txt @@ -0,0 +1,10 @@ +/foo.js(2,20): error TS1109: Expression expected. + + +==== /foo.js (1 errors) ==== + /** + * @import foo from + +!!! error TS1109: Expression expected. + */ + \ No newline at end of file diff --git a/tests/baselines/reference/importTag12.symbols b/tests/baselines/reference/importTag12.symbols new file mode 100644 index 0000000000000..8c6cdc2734f7f --- /dev/null +++ b/tests/baselines/reference/importTag12.symbols @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag12.ts] //// + +=== /foo.js === + +/** + * @import foo from + */ + diff --git a/tests/baselines/reference/importTag12.types b/tests/baselines/reference/importTag12.types new file mode 100644 index 0000000000000..8c6cdc2734f7f --- /dev/null +++ b/tests/baselines/reference/importTag12.types @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/jsdoc/importTag12.ts] //// + +=== /foo.js === + +/** + * @import foo from + */ + diff --git a/tests/cases/conformance/jsdoc/importTag10.ts b/tests/cases/conformance/jsdoc/importTag10.ts new file mode 100644 index 0000000000000..ae3f71e74eed4 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag10.ts @@ -0,0 +1,8 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /foo.js +/** + * @import + */ diff --git a/tests/cases/conformance/jsdoc/importTag11.ts b/tests/cases/conformance/jsdoc/importTag11.ts new file mode 100644 index 0000000000000..f4c2d18ecb7cd --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag11.ts @@ -0,0 +1,8 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /foo.js +/** + * @import foo + */ diff --git a/tests/cases/conformance/jsdoc/importTag12.ts b/tests/cases/conformance/jsdoc/importTag12.ts new file mode 100644 index 0000000000000..464444b8f924c --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag12.ts @@ -0,0 +1,8 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /foo.js +/** + * @import foo from + */ diff --git a/tests/cases/fourslash/refactorConvertImport_namedToDefault2.ts b/tests/cases/fourslash/refactorConvertImport_namedToDefault2.ts new file mode 100644 index 0000000000000..07195e88ef19e --- /dev/null +++ b/tests/cases/fourslash/refactorConvertImport_namedToDefault2.ts @@ -0,0 +1,26 @@ +/// + +// @esModuleInterop: true +// @allowJs: true +// @checkJs: true + +// @Filename: /process.d.ts +////declare module "process" { +//// interface Process { +//// pid: number; +//// addListener(event: string, listener: (...args: any[]) => void): void; +//// } +//// var process: Process; +//// export = process; +////} + +// @Filename: /a.js +/////** [|@import { pid, addListener } from "process"|] */ + +goTo.selectRange(test.ranges()[0]); +edit.applyRefactor({ + refactorName: "Convert import", + actionName: "Convert named imports to default import", + actionDescription: "Convert named imports to default import", + newContent: `/** @import process from "process" */`, +}); diff --git a/tests/cases/fourslash/refactorConvertImport_namedToNamespace10.ts b/tests/cases/fourslash/refactorConvertImport_namedToNamespace10.ts new file mode 100644 index 0000000000000..7fe2e578d8ae8 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertImport_namedToNamespace10.ts @@ -0,0 +1,15 @@ +/// + +// @allowJs: true +// @checkJs: true + +// @filename: /a.js +/////** [|@import { join } from "path"|] */ + +goTo.selectRange(test.ranges()[0]); +edit.applyRefactor({ + refactorName: "Convert import", + actionName: "Convert named imports to namespace import", + actionDescription: "Convert named imports to namespace import", + newContent: `/** @import * as path from "path" */`, +}); diff --git a/tests/cases/fourslash/refactorConvertImport_namespaceToNamed1.ts b/tests/cases/fourslash/refactorConvertImport_namespaceToNamed1.ts new file mode 100644 index 0000000000000..0a13239217e47 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertImport_namespaceToNamed1.ts @@ -0,0 +1,18 @@ +/// + +/////*a*/import * as m from "m";/*b*/ +////const a = 0; +////m.a; +////m.b; + +goTo.select("a", "b"); +edit.applyRefactor({ + refactorName: "Convert import", + actionName: "Convert namespace import to named imports", + actionDescription: "Convert namespace import to named imports", + newContent: +`import { a as a_1, b } from "m"; +const a = 0; +a_1; +b;`, +}); diff --git a/tests/cases/fourslash/refactorConvertImport_namespaceToNamed2.ts b/tests/cases/fourslash/refactorConvertImport_namespaceToNamed2.ts new file mode 100644 index 0000000000000..439ab3026fbc1 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertImport_namespaceToNamed2.ts @@ -0,0 +1,31 @@ +/// +// @allowJs: true +// @checkJs: true + +// @filename: /a.js +/////** +//// * [|@import * as types from "types"|] +//// */ +//// +/////** +//// * @param { types.A } a +//// * @param { types.B } b +//// */ +////function f() { } + +goTo.selectRange(test.ranges()[0]); +edit.applyRefactor({ + refactorName: "Convert import", + actionName: "Convert namespace import to named imports", + actionDescription: "Convert namespace import to named imports", + newContent: +`/** + * @import { A, B } from "types" + */ + +/** + * @param { A } a + * @param { B } b + */ +function f() { }`, +}); From dd2a481a24b73c50e0c5cce24e78fccb619cd623 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 14 Feb 2024 01:58:29 +0200 Subject: [PATCH 18/23] add import attrs to import tag. add additional tests --- src/compiler/checker.ts | 16 +++-- src/compiler/emitter.ts | 3 + src/compiler/factory/nodeFactory.ts | 8 ++- src/compiler/parser.ts | 58 ++++++++----------- src/compiler/program.ts | 20 ++----- src/compiler/types.ts | 5 +- tests/baselines/reference/api/typescript.d.ts | 5 +- .../reference/importTag13.errors.txt | 13 +++++ tests/baselines/reference/importTag13.symbols | 6 ++ tests/baselines/reference/importTag13.types | 6 ++ .../reference/importTag14.errors.txt | 14 +++++ tests/baselines/reference/importTag14.symbols | 6 ++ tests/baselines/reference/importTag14.types | 6 ++ .../importTag15(module=es2015).errors.txt | 19 ++++++ .../reference/importTag15(module=es2015).js | 24 ++++++++ .../importTag15(module=es2015).symbols | 16 +++++ .../importTag15(module=es2015).types | 16 +++++ .../importTag15(module=esnext).errors.txt | 19 ++++++ .../reference/importTag15(module=esnext).js | 24 ++++++++ .../importTag15(module=esnext).symbols | 16 +++++ .../importTag15(module=esnext).types | 16 +++++ tests/cases/conformance/jsdoc/importTag13.ts | 11 ++++ tests/cases/conformance/jsdoc/importTag14.ts | 6 ++ tests/cases/conformance/jsdoc/importTag15.ts | 16 +++++ 24 files changed, 288 insertions(+), 61 deletions(-) create mode 100644 tests/baselines/reference/importTag13.errors.txt create mode 100644 tests/baselines/reference/importTag13.symbols create mode 100644 tests/baselines/reference/importTag13.types create mode 100644 tests/baselines/reference/importTag14.errors.txt create mode 100644 tests/baselines/reference/importTag14.symbols create mode 100644 tests/baselines/reference/importTag14.types create mode 100644 tests/baselines/reference/importTag15(module=es2015).errors.txt create mode 100644 tests/baselines/reference/importTag15(module=es2015).js create mode 100644 tests/baselines/reference/importTag15(module=es2015).symbols create mode 100644 tests/baselines/reference/importTag15(module=es2015).types create mode 100644 tests/baselines/reference/importTag15(module=esnext).errors.txt create mode 100644 tests/baselines/reference/importTag15(module=esnext).js create mode 100644 tests/baselines/reference/importTag15(module=esnext).symbols create mode 100644 tests/baselines/reference/importTag15(module=esnext).types create mode 100644 tests/cases/conformance/jsdoc/importTag13.ts create mode 100644 tests/cases/conformance/jsdoc/importTag14.ts create mode 100644 tests/cases/conformance/jsdoc/importTag15.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 20ad9027aa683..79ce38ebee25a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9745,13 +9745,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as NamespaceImport).parent.parent.moduleSpecifier; - const attributes = isImportDeclaration(node.parent) ? node.parent.attributes : undefined; addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), specifier, - attributes, + (node as ImportClause).parent.attributes, ), ModifierFlags.None, ); @@ -9771,7 +9770,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportSpecifier: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; - const attributes = isImportDeclaration(node.parent.parent.parent) ? node.parent.parent.parent.attributes : undefined; addResult( factory.createImportDeclaration( /*modifiers*/ undefined, @@ -9787,7 +9785,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ]), ), specifier, - attributes, + (node as ImportSpecifier).parent.parent.parent.attributes, ), ModifierFlags.None, ); @@ -41898,6 +41896,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function checkJSDocImportTag(node: JSDocImportTag) { + checkImportAttributes(node); + } + function checkJSDocImplementsTag(node: JSDocImplementsTag): void { const classLike = getEffectiveJSDocHost(node); if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { @@ -46078,7 +46080,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkImportAttributes(declaration: ImportDeclaration | ExportDeclaration) { + function checkImportAttributes(declaration: ImportDeclaration | ExportDeclaration | JSDocImportTag) { const node = declaration.attributes; if (node) { const importAttributesType = getGlobalImportAttributesType(/*reportErrors*/ true); @@ -46105,7 +46107,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(node, message); } - if (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { + if (isImportDeclaration(declaration) || isJSDocImportTag(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { return grammarErrorOnNode(node, isImportAttributes ? Diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports : Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); } @@ -46681,6 +46683,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkJSDocSatisfiesTag(node as JSDocSatisfiesTag); case SyntaxKind.JSDocThisTag: return checkJSDocThisTag(node as JSDocThisTag); + case SyntaxKind.JSDocImportTag: + return checkJSDocImportTag(node as JSDocImportTag); case SyntaxKind.IndexedAccessType: return checkIndexedAccessType(node as IndexedAccessTypeNode); case SyntaxKind.MappedType: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d3162e6b6a58c..0ab5dd6c0cccd 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4469,6 +4469,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } emitExpression(tag.moduleSpecifier); + if (tag.attributes) { + emitWithLeadingSpace(tag.attributes); + } emitJSDocComment(tag.comment); } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index cd69645843895..303955b11ffaf 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5558,20 +5558,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag { + function createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes, comment?: string | NodeArray): JSDocImportTag { const node = createBaseJSDocTag(SyntaxKind.JSDocImportTag, tagName ?? createIdentifier("import"), comment); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; + node.attributes = attributes; node.comment = comment; return node; } - function updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag { + function updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined, comment: string | NodeArray | undefined): JSDocImportTag { return node.tagName !== tagName || node.comment !== comment || node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier - ? update(createJSDocImportTag(tagName, importClause, moduleSpecifier, comment), node) + || node.attributes !== attributes + ? update(createJSDocImportTag(tagName, importClause, moduleSpecifier, attributes, comment), node) : node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index fe769e9989ce2..39ad1da0866b0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1220,6 +1220,7 @@ function forEachChildInJSDocImportTag(node: JSDocImportTag, cbNode: (node: No return visitNode(cbNode, node.tagName) || visitNode(cbNode, node.importClause) || visitNode(cbNode, node.moduleSpecifier) + || visitNode(cbNode, node.attributes) || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } @@ -8355,6 +8356,16 @@ namespace Parser { return parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly); } + const importClause = tryParseImportClause(identifier, afterImportPos, isTypeOnly); + const moduleSpecifier = parseModuleSpecifier(); + const attributes = tryParseImportAttributes(); + + parseSemicolon(); + const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, attributes); + return withJSDoc(finishNode(node, pos), hasJSDoc); + } + + function tryParseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean, skipJsDocLeadingAsterisks = false) { // ImportDeclaration: // import ImportClause from ModuleSpecifier ; // import ModuleSpecifier; @@ -8364,18 +8375,17 @@ namespace Parser { token() === SyntaxKind.AsteriskToken || // import * token() === SyntaxKind.OpenBraceToken // import { ) { - importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); + importClause = parseImportClause(identifier, pos, isTypeOnly, skipJsDocLeadingAsterisks); parseExpected(SyntaxKind.FromKeyword); } - const moduleSpecifier = parseModuleSpecifier(); + return importClause; + } + + function tryParseImportAttributes() { const currentToken = token(); - let attributes: ImportAttributes | undefined; if ((currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) && !scanner.hasPrecedingLineBreak()) { - attributes = parseImportAttributes(currentToken); + return parseImportAttributes(currentToken); } - parseSemicolon(); - const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, attributes); - return withJSDoc(finishNode(node, pos), hasJSDoc); } function parseImportAttribute() { @@ -8431,7 +8441,7 @@ namespace Parser { return finished; } - function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) { + function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean, skipJsDocLeadingAsterisks: boolean) { // ImportClause: // ImportedDefaultBinding // NameSpaceImport @@ -8446,7 +8456,9 @@ namespace Parser { !identifier || parseOptional(SyntaxKind.CommaToken) ) { + if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(true); namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(false); } return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); @@ -9458,39 +9470,19 @@ namespace Parser { } function parseImportTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImportTag { - const afterImportTypeTagPos = scanner.getTokenFullStart(); + const afterImportTagPos = scanner.getTokenFullStart(); let identifier: Identifier | undefined; if (isIdentifier()) { identifier = parseIdentifier(); } - let importClause: ImportClause | undefined; - if ( - identifier // @import id - || token() === SyntaxKind.AsteriskToken // @import * - || token() === SyntaxKind.OpenBraceToken // @import { - ) { - importClause = parseJsDocImportClause(identifier, afterImportTypeTagPos); - parseExpected(SyntaxKind.FromKeyword); - } - + const importClause = tryParseImportClause(identifier, afterImportTagPos, /*isTypeOnly*/ true, /*skipJsDocLeadingAsterisks*/ true); const moduleSpecifier = parseModuleSpecifier(); - const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; - return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, comments), start); - } + const attributes = tryParseImportAttributes(); - function parseJsDocImportClause(identifier: Identifier | undefined, pos: number) { - let namedBindings: NamespaceImport | NamedImports | undefined; - if ( - !identifier || - parseOptional(SyntaxKind.CommaToken) - ) { - scanner.setSkipJsDocLeadingAsterisks(true); - namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); - scanner.setSkipJsDocLeadingAsterisks(false); - } - return finishNode(factory.createImportClause(/*isTypeOnly*/ true, identifier, namedBindings), pos); + const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; + return finishNode(factory.createJSDocImportTag(tagName, importClause, moduleSpecifier, attributes, comments), start); } function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression; } { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 23135d4b5ca93..75022d1cc4c29 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -209,6 +209,7 @@ import { isStringLiteral, isStringLiteralLike, isTraceEnabled, + JSDocImportTag, JsonSourceFile, JsxEmit, length, @@ -875,7 +876,7 @@ export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: } /** @internal */ -export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | ExportDeclaration) { +export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | ExportDeclaration | JSDocImportTag) { if (isExportDeclaration(decl)) { return decl.isTypeOnly; } @@ -3368,11 +3369,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) { - collectDynamicImportOrRequireCalls(file); - } - - if (isJavaScriptFile) { - collectJsDocImportTypeReferences(file); + collectDynamicImportOrRequireOrJsDocImportCalls(file); } file.imports = imports || emptyArray; @@ -3429,7 +3426,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function collectDynamicImportOrRequireCalls(file: SourceFile) { + function collectDynamicImportOrRequireOrJsDocImportCalls(file: SourceFile) { const r = /import|require/g; while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null const node = getNodeAtPosition(file, r.lastIndex); @@ -3446,14 +3443,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here imports = append(imports, node.argument.literal); } - } - } - - function collectJsDocImportTypeReferences(file: SourceFile) { - const r = /@import/g; - while (r.exec(file.text) !== null) { // eslint-disable-line no-null/no-null - const node = getNodeAtPosition(file, r.lastIndex); - if (isJSDocImportTag(node)) { + else if (isJavaScriptFile && isJSDocImportTag(node)) { const moduleNameExpr = getExternalModuleName(node); if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) { setParentRecursive(node, /*incremental*/ false); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 17cbd69cbca0d..e79d6d5b3f54b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4072,6 +4072,7 @@ export interface JSDocImportTag extends JSDocTag { readonly parent: JSDoc; readonly importClause?: ImportClause; readonly moduleSpecifier: Expression; + readonly attributes?: ImportAttributes; } // NOTE: Ensure this is up-to-date with src/debug/debug.ts @@ -8820,8 +8821,8 @@ export interface NodeFactory { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; - updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 26517d59f66ae..a5af98f338e1d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6378,6 +6378,7 @@ declare namespace ts { readonly parent: JSDoc; readonly importClause?: ImportClause; readonly moduleSpecifier: Expression; + readonly attributes?: ImportAttributes; } enum FlowFlags { Unreachable = 1, @@ -8343,8 +8344,8 @@ declare namespace ts { updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; - createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment?: string | NodeArray): JSDocImportTag; - updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, comment: string | NodeArray | undefined): JSDocImportTag; + createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes, comment?: string | NodeArray): JSDocImportTag; + updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined, comment: string | NodeArray | undefined): JSDocImportTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; diff --git a/tests/baselines/reference/importTag13.errors.txt b/tests/baselines/reference/importTag13.errors.txt new file mode 100644 index 0000000000000..49025119c000b --- /dev/null +++ b/tests/baselines/reference/importTag13.errors.txt @@ -0,0 +1,13 @@ +/foo.js(1,15): error TS1005: 'from' expected. + + +==== /foo.js (1 errors) ==== + /** @import x = require("types") */ + ~ +!!! error TS1005: 'from' expected. + +==== /types.ts (0 errors) ==== + export interface Foo { + a: number; + } + \ No newline at end of file diff --git a/tests/baselines/reference/importTag13.symbols b/tests/baselines/reference/importTag13.symbols new file mode 100644 index 0000000000000..fbc59963b3da9 --- /dev/null +++ b/tests/baselines/reference/importTag13.symbols @@ -0,0 +1,6 @@ +//// [tests/cases/conformance/jsdoc/importTag13.ts] //// + +=== /foo.js === + +/** @import x = require("types") */ + diff --git a/tests/baselines/reference/importTag13.types b/tests/baselines/reference/importTag13.types new file mode 100644 index 0000000000000..fbc59963b3da9 --- /dev/null +++ b/tests/baselines/reference/importTag13.types @@ -0,0 +1,6 @@ +//// [tests/cases/conformance/jsdoc/importTag13.ts] //// + +=== /foo.js === + +/** @import x = require("types") */ + diff --git a/tests/baselines/reference/importTag14.errors.txt b/tests/baselines/reference/importTag14.errors.txt new file mode 100644 index 0000000000000..20360234a4bfb --- /dev/null +++ b/tests/baselines/reference/importTag14.errors.txt @@ -0,0 +1,14 @@ +/foo.js(1,33): error TS1464: Type import attributes should have exactly one key - 'resolution-mode' - with value 'import' or 'require'. +/foo.js(1,33): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/foo.js(1,38): error TS1005: '{' expected. + + +==== /foo.js (3 errors) ==== + /** @import * as f from "./foo" with */ + ~~~~ +!!! error TS1464: Type import attributes should have exactly one key - 'resolution-mode' - with value 'import' or 'require'. + ~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + +!!! error TS1005: '{' expected. + \ No newline at end of file diff --git a/tests/baselines/reference/importTag14.symbols b/tests/baselines/reference/importTag14.symbols new file mode 100644 index 0000000000000..05e0be8659973 --- /dev/null +++ b/tests/baselines/reference/importTag14.symbols @@ -0,0 +1,6 @@ +//// [tests/cases/conformance/jsdoc/importTag14.ts] //// + +=== /foo.js === + +/** @import * as f from "./foo" with */ + diff --git a/tests/baselines/reference/importTag14.types b/tests/baselines/reference/importTag14.types new file mode 100644 index 0000000000000..05e0be8659973 --- /dev/null +++ b/tests/baselines/reference/importTag14.types @@ -0,0 +1,6 @@ +//// [tests/cases/conformance/jsdoc/importTag14.ts] //// + +=== /foo.js === + +/** @import * as f from "./foo" with */ + diff --git a/tests/baselines/reference/importTag15(module=es2015).errors.txt b/tests/baselines/reference/importTag15(module=es2015).errors.txt new file mode 100644 index 0000000000000..eabac7779f130 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=es2015).errors.txt @@ -0,0 +1,19 @@ +1.js(1,30): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +1.js(2,33): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + + +==== 0.ts (0 errors) ==== + export interface I { } + +==== 1.js (2 errors) ==== + /** @import { I } from './0' with { type: "json" } */ + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + /** @import * as foo from './0' with { type: "json" } */ + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + + /** @param {I} a */ + function f(a) {} + + \ No newline at end of file diff --git a/tests/baselines/reference/importTag15(module=es2015).js b/tests/baselines/reference/importTag15(module=es2015).js new file mode 100644 index 0000000000000..bae25b4498528 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=es2015).js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +//// [0.ts] +export interface I { } + +//// [1.js] +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} + + + + + +//// [0.d.ts] +export interface I { +} +//// [1.d.ts] +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ +/** @param {I} a */ +declare function f(a: import("./0").I): void; diff --git a/tests/baselines/reference/importTag15(module=es2015).symbols b/tests/baselines/reference/importTag15(module=es2015).symbols new file mode 100644 index 0000000000000..1f4f9ffe6fe07 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=es2015).symbols @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +=== 0.ts === +export interface I { } +>I : Symbol(I, Decl(0.ts, 0, 0)) + +=== 1.js === +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} +>f : Symbol(f, Decl(1.js, 0, 0)) +>a : Symbol(a, Decl(1.js, 4, 11)) + + diff --git a/tests/baselines/reference/importTag15(module=es2015).types b/tests/baselines/reference/importTag15(module=es2015).types new file mode 100644 index 0000000000000..71eb8e6b11170 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=es2015).types @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +=== 0.ts === + +export interface I { } + +=== 1.js === +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} +>f : (a: I) => void +>a : I + + diff --git a/tests/baselines/reference/importTag15(module=esnext).errors.txt b/tests/baselines/reference/importTag15(module=esnext).errors.txt new file mode 100644 index 0000000000000..019c729e34b1b --- /dev/null +++ b/tests/baselines/reference/importTag15(module=esnext).errors.txt @@ -0,0 +1,19 @@ +1.js(1,30): error TS2857: Import attributes cannot be used with type-only imports or exports. +1.js(2,33): error TS2857: Import attributes cannot be used with type-only imports or exports. + + +==== 0.ts (0 errors) ==== + export interface I { } + +==== 1.js (2 errors) ==== + /** @import { I } from './0' with { type: "json" } */ + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2857: Import attributes cannot be used with type-only imports or exports. + /** @import * as foo from './0' with { type: "json" } */ + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2857: Import attributes cannot be used with type-only imports or exports. + + /** @param {I} a */ + function f(a) {} + + \ No newline at end of file diff --git a/tests/baselines/reference/importTag15(module=esnext).js b/tests/baselines/reference/importTag15(module=esnext).js new file mode 100644 index 0000000000000..bae25b4498528 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=esnext).js @@ -0,0 +1,24 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +//// [0.ts] +export interface I { } + +//// [1.js] +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} + + + + + +//// [0.d.ts] +export interface I { +} +//// [1.d.ts] +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ +/** @param {I} a */ +declare function f(a: import("./0").I): void; diff --git a/tests/baselines/reference/importTag15(module=esnext).symbols b/tests/baselines/reference/importTag15(module=esnext).symbols new file mode 100644 index 0000000000000..1f4f9ffe6fe07 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=esnext).symbols @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +=== 0.ts === +export interface I { } +>I : Symbol(I, Decl(0.ts, 0, 0)) + +=== 1.js === +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} +>f : Symbol(f, Decl(1.js, 0, 0)) +>a : Symbol(a, Decl(1.js, 4, 11)) + + diff --git a/tests/baselines/reference/importTag15(module=esnext).types b/tests/baselines/reference/importTag15(module=esnext).types new file mode 100644 index 0000000000000..71eb8e6b11170 --- /dev/null +++ b/tests/baselines/reference/importTag15(module=esnext).types @@ -0,0 +1,16 @@ +//// [tests/cases/conformance/jsdoc/importTag15.ts] //// + +=== 0.ts === + +export interface I { } + +=== 1.js === +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} +>f : (a: I) => void +>a : I + + diff --git a/tests/cases/conformance/jsdoc/importTag13.ts b/tests/cases/conformance/jsdoc/importTag13.ts new file mode 100644 index 0000000000000..8f15c41695bb2 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag13.ts @@ -0,0 +1,11 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /types.ts +export interface Foo { + a: number; +} + +// @filename: /foo.js +/** @import x = require("types") */ diff --git a/tests/cases/conformance/jsdoc/importTag14.ts b/tests/cases/conformance/jsdoc/importTag14.ts new file mode 100644 index 0000000000000..98375d7356c39 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag14.ts @@ -0,0 +1,6 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true + +// @filename: /foo.js +/** @import * as f from "./foo" with */ diff --git a/tests/cases/conformance/jsdoc/importTag15.ts b/tests/cases/conformance/jsdoc/importTag15.ts new file mode 100644 index 0000000000000..8a31980fb609b --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag15.ts @@ -0,0 +1,16 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @module: esnext,es2015 +// @checkJs: true +// @allowJs: true + +// @filename: 0.ts +export interface I { } + +// @filename: 1.js +/** @import { I } from './0' with { type: "json" } */ +/** @import * as foo from './0' with { type: "json" } */ + +/** @param {I} a */ +function f(a) {} + From af9bc719c6cdfc155687e7d5973364490ae85a84 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sat, 2 Mar 2024 01:50:00 +0200 Subject: [PATCH 19/23] emit import declarations --- src/compiler/binder.ts | 47 +++++++++++++++++++ .../importTag15(module=es2015).errors.txt | 1 - .../reference/importTag15(module=es2015).js | 5 +- .../importTag15(module=es2015).symbols | 1 - .../importTag15(module=es2015).types | 1 - .../importTag15(module=esnext).errors.txt | 1 - .../reference/importTag15(module=esnext).js | 5 +- .../importTag15(module=esnext).symbols | 1 - .../importTag15(module=esnext).types | 1 - tests/baselines/reference/importTag5.js | 3 +- tests/cases/conformance/jsdoc/importTag15.ts | 1 - 11 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 7e9f3ced07fec..2fc09cab1442d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -94,6 +94,7 @@ import { getExpandoInitializer, getHostSignatureFromJSDoc, getImmediatelyInvokedFunctionExpression, + getJSDocHost, getJSDocTypeTag, getLeftmostAccessExpression, getNameOfDeclaration, @@ -229,6 +230,7 @@ import { JSDocClassTag, JSDocEnumTag, JSDocFunctionType, + JSDocImportTag, JSDocOverloadTag, JSDocParameterTag, JSDocPropertyLikeTag, @@ -525,6 +527,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { var lastContainer: HasLocals; var delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag)[]; var seenThisKeyword: boolean; + var jsDocImports: JSDocImportTag[]; // state used by control flow analysis var currentFlow: FlowNode; @@ -592,6 +595,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { file.symbolCount = symbolCount; file.classifiableNames = classifiableNames; delayedBindJSDocTypedefTag(); + bindJSDocImports(); } file = undefined!; @@ -603,6 +607,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { blockScopeContainer = undefined!; lastContainer = undefined!; delayedTypeAliases = undefined!; + jsDocImports = undefined!; seenThisKeyword = false; currentFlow = undefined!; currentBreakTarget = undefined; @@ -1181,6 +1186,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); break; // In source files and blocks, bind functions first to match hoisting that occurs at runtime + case SyntaxKind.JSDocImportTag: + bindJSDocImportTag(node as JSDocImportTag); + break; case SyntaxKind.SourceFile: { bindEachFunctionsFirst((node as SourceFile).statements); bind((node as SourceFile).endOfFileToken); @@ -2065,6 +2073,14 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } + function bindJSDocImportTag(node: JSDocImportTag) { + bind(node.tagName); + + if (typeof node.comment !== "string") { + bindEach(node.comment); + } + } + function bindOptionalExpression(node: Expression, trueTarget: FlowLabel, falseTarget: FlowLabel) { doWithConditionalBranches(bind, node, trueTarget, falseTarget); if (!isOptionalChain(node) || isOutermostOptionalChain(node)) { @@ -2443,6 +2459,35 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { currentFlow = saveCurrentFlow; } + function bindJSDocImports() { + if (jsDocImports === undefined) { + return; + } + + const saveContainer = container; + const saveLastContainer = lastContainer; + const saveBlockScopeContainer = blockScopeContainer; + const saveParent = parent; + const saveCurrentFlow = currentFlow; + + for (const jsDocImportTag of jsDocImports) { + const host = getJSDocHost(jsDocImportTag); + const enclosingContainer = host ? getEnclosingContainer(host) as IsContainer | undefined : undefined; + const enclosingBlockScopeContainer = host ? getEnclosingBlockScopeContainer(host) as IsBlockScopedContainer | undefined : undefined; + container = enclosingContainer || file; + blockScopeContainer = enclosingBlockScopeContainer || file; + currentFlow = initFlowNode({ flags: FlowFlags.Start }); + parent = jsDocImportTag; + bind(jsDocImportTag.importClause); + } + + container = saveContainer; + lastContainer = saveLastContainer; + blockScopeContainer = saveBlockScopeContainer; + parent = saveParent; + currentFlow = saveCurrentFlow; + } + // The binder visits every node in the syntax tree so it is a convenient place to perform a single localized // check for reserved words used as identifiers in strict mode code, as well as `yield` or `await` in // [Yield] or [Await] contexts, respectively. @@ -2995,6 +3040,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); case SyntaxKind.JSDocOverloadTag: return bind((node as JSDocOverloadTag).typeExpression); + case SyntaxKind.JSDocImportTag: + return (jsDocImports || (jsDocImports = [])).push(node as JSDocImportTag); } } diff --git a/tests/baselines/reference/importTag15(module=es2015).errors.txt b/tests/baselines/reference/importTag15(module=es2015).errors.txt index eabac7779f130..e3dba21b47669 100644 --- a/tests/baselines/reference/importTag15(module=es2015).errors.txt +++ b/tests/baselines/reference/importTag15(module=es2015).errors.txt @@ -15,5 +15,4 @@ /** @param {I} a */ function f(a) {} - \ No newline at end of file diff --git a/tests/baselines/reference/importTag15(module=es2015).js b/tests/baselines/reference/importTag15(module=es2015).js index bae25b4498528..f07b57c5c2641 100644 --- a/tests/baselines/reference/importTag15(module=es2015).js +++ b/tests/baselines/reference/importTag15(module=es2015).js @@ -9,7 +9,6 @@ export interface I { } /** @param {I} a */ function f(a) {} - @@ -21,4 +20,6 @@ export interface I { /** @import { I } from './0' with { type: "json" } */ /** @import * as foo from './0' with { type: "json" } */ /** @param {I} a */ -declare function f(a: import("./0").I): void; +declare function f(a: I): void; +import { I } from './0' with { type: "json" }; +import * as foo from './0'; diff --git a/tests/baselines/reference/importTag15(module=es2015).symbols b/tests/baselines/reference/importTag15(module=es2015).symbols index 1f4f9ffe6fe07..992eb71ede062 100644 --- a/tests/baselines/reference/importTag15(module=es2015).symbols +++ b/tests/baselines/reference/importTag15(module=es2015).symbols @@ -13,4 +13,3 @@ function f(a) {} >f : Symbol(f, Decl(1.js, 0, 0)) >a : Symbol(a, Decl(1.js, 4, 11)) - diff --git a/tests/baselines/reference/importTag15(module=es2015).types b/tests/baselines/reference/importTag15(module=es2015).types index 71eb8e6b11170..fb18e6928b70b 100644 --- a/tests/baselines/reference/importTag15(module=es2015).types +++ b/tests/baselines/reference/importTag15(module=es2015).types @@ -13,4 +13,3 @@ function f(a) {} >f : (a: I) => void >a : I - diff --git a/tests/baselines/reference/importTag15(module=esnext).errors.txt b/tests/baselines/reference/importTag15(module=esnext).errors.txt index 019c729e34b1b..3b98c15768bff 100644 --- a/tests/baselines/reference/importTag15(module=esnext).errors.txt +++ b/tests/baselines/reference/importTag15(module=esnext).errors.txt @@ -15,5 +15,4 @@ /** @param {I} a */ function f(a) {} - \ No newline at end of file diff --git a/tests/baselines/reference/importTag15(module=esnext).js b/tests/baselines/reference/importTag15(module=esnext).js index bae25b4498528..f07b57c5c2641 100644 --- a/tests/baselines/reference/importTag15(module=esnext).js +++ b/tests/baselines/reference/importTag15(module=esnext).js @@ -9,7 +9,6 @@ export interface I { } /** @param {I} a */ function f(a) {} - @@ -21,4 +20,6 @@ export interface I { /** @import { I } from './0' with { type: "json" } */ /** @import * as foo from './0' with { type: "json" } */ /** @param {I} a */ -declare function f(a: import("./0").I): void; +declare function f(a: I): void; +import { I } from './0' with { type: "json" }; +import * as foo from './0'; diff --git a/tests/baselines/reference/importTag15(module=esnext).symbols b/tests/baselines/reference/importTag15(module=esnext).symbols index 1f4f9ffe6fe07..992eb71ede062 100644 --- a/tests/baselines/reference/importTag15(module=esnext).symbols +++ b/tests/baselines/reference/importTag15(module=esnext).symbols @@ -13,4 +13,3 @@ function f(a) {} >f : Symbol(f, Decl(1.js, 0, 0)) >a : Symbol(a, Decl(1.js, 4, 11)) - diff --git a/tests/baselines/reference/importTag15(module=esnext).types b/tests/baselines/reference/importTag15(module=esnext).types index 71eb8e6b11170..fb18e6928b70b 100644 --- a/tests/baselines/reference/importTag15(module=esnext).types +++ b/tests/baselines/reference/importTag15(module=esnext).types @@ -13,4 +13,3 @@ function f(a) {} >f : (a: I) => void >a : I - diff --git a/tests/baselines/reference/importTag5.js b/tests/baselines/reference/importTag5.js index cd2819da251ea..a88d3511a7bd3 100644 --- a/tests/baselines/reference/importTag5.js +++ b/tests/baselines/reference/importTag5.js @@ -29,4 +29,5 @@ export interface Foo { /** * @param { Foo } foo */ -declare function f(foo: import("./types").Foo): void; +declare function f(foo: Foo): void; +import { Foo } from "./types"; diff --git a/tests/cases/conformance/jsdoc/importTag15.ts b/tests/cases/conformance/jsdoc/importTag15.ts index 8a31980fb609b..50004fdb86ac9 100644 --- a/tests/cases/conformance/jsdoc/importTag15.ts +++ b/tests/cases/conformance/jsdoc/importTag15.ts @@ -13,4 +13,3 @@ export interface I { } /** @param {I} a */ function f(a) {} - From 7caacbdc4a3825576c032ed8e39b5d8a66eae432 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sat, 2 Mar 2024 03:24:07 +0200 Subject: [PATCH 20/23] emit type only imports --- src/compiler/checker.ts | 9 ++++++--- tests/baselines/reference/importTag15(module=es2015).js | 4 ++-- tests/baselines/reference/importTag15(module=esnext).js | 4 ++-- tests/baselines/reference/importTag5.js | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b354601f718e6..eca0a58d2fd5e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9722,10 +9722,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportClause).parent.moduleSpecifier; const attributes = isImportDeclaration(node.parent) ? node.parent.attributes : undefined; + const isTypeOnly = isJSDocImportTag((node as ImportClause).parent); addResult( factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, factory.createIdentifier(localName), /*namedBindings*/ undefined), + factory.createImportClause(isTypeOnly, factory.createIdentifier(localName), /*namedBindings*/ undefined), specifier, attributes, ), @@ -9736,10 +9737,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as NamespaceImport).parent.parent.moduleSpecifier; + const isTypeOnly = isJSDocImportTag((node as NamespaceImport).parent.parent); addResult( factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), + factory.createImportClause(isTypeOnly, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), specifier, (node as ImportClause).parent.attributes, ), @@ -9761,11 +9763,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportSpecifier: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; + const isTypeOnly = isJSDocImportTag((node as ImportSpecifier).parent.parent.parent); addResult( factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( - /*isTypeOnly*/ false, + isTypeOnly, /*name*/ undefined, factory.createNamedImports([ factory.createImportSpecifier( diff --git a/tests/baselines/reference/importTag15(module=es2015).js b/tests/baselines/reference/importTag15(module=es2015).js index f07b57c5c2641..ad2c1ac5a07d4 100644 --- a/tests/baselines/reference/importTag15(module=es2015).js +++ b/tests/baselines/reference/importTag15(module=es2015).js @@ -21,5 +21,5 @@ export interface I { /** @import * as foo from './0' with { type: "json" } */ /** @param {I} a */ declare function f(a: I): void; -import { I } from './0' with { type: "json" }; -import * as foo from './0'; +import type { I } from './0' with { type: "json" }; +import type * as foo from './0'; diff --git a/tests/baselines/reference/importTag15(module=esnext).js b/tests/baselines/reference/importTag15(module=esnext).js index f07b57c5c2641..ad2c1ac5a07d4 100644 --- a/tests/baselines/reference/importTag15(module=esnext).js +++ b/tests/baselines/reference/importTag15(module=esnext).js @@ -21,5 +21,5 @@ export interface I { /** @import * as foo from './0' with { type: "json" } */ /** @param {I} a */ declare function f(a: I): void; -import { I } from './0' with { type: "json" }; -import * as foo from './0'; +import type { I } from './0' with { type: "json" }; +import type * as foo from './0'; diff --git a/tests/baselines/reference/importTag5.js b/tests/baselines/reference/importTag5.js index a88d3511a7bd3..a4814bf10fdd0 100644 --- a/tests/baselines/reference/importTag5.js +++ b/tests/baselines/reference/importTag5.js @@ -30,4 +30,4 @@ export interface Foo { * @param { Foo } foo */ declare function f(foo: Foo): void; -import { Foo } from "./types"; +import type { Foo } from "./types"; From 2e4b90da07eb9d86aa773ee9aeff66f0d633d4e3 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Sat, 16 Mar 2024 03:13:03 +0200 Subject: [PATCH 21/23] fix types --- src/services/organizeImports.ts | 5 +++-- tests/baselines/reference/APILibCheck.types | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index a6a300ed82df4..8332494bb565e 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -40,6 +40,7 @@ import { isString, isStringLiteral, isStringLiteralLike, + JSDocImportTag, jsxModeNeedsExplicitImport, LanguageServiceHost, length, @@ -709,7 +710,7 @@ function detectModuleSpecifierCaseBySort(importDeclsByGroup: (readonly AnyImport return detectCaseSensitivityBySort(moduleSpecifiersByGroup, comparersToTest); } -function detectNamedImportOrganizationBySort(originalGroups: readonly ImportDeclaration[], comparersToTest: Comparer[], typesToTest: OrganizeImportsTypeOrder[]): { namedImportComparer: Comparer; typeOrder: OrganizeImportsTypeOrder | undefined; isSorted: boolean; } | undefined { +function detectNamedImportOrganizationBySort(originalGroups: readonly (ImportDeclaration | JSDocImportTag)[], comparersToTest: Comparer[], typesToTest: OrganizeImportsTypeOrder[]): { namedImportComparer: Comparer; typeOrder: OrganizeImportsTypeOrder | undefined; isSorted: boolean; } | undefined { // Filter for import declarations with named imports. Will be a flat array of import declarations without separations by group let bothNamedImports = false; const importDeclsWithNamed = originalGroups.filter(i => { @@ -884,7 +885,7 @@ function getNamedImportSpecifierComparer(pref } /** @internal */ -export function getNamedImportSpecifierComparerWithDetection(importDecl: ImportDeclaration, preferences: UserPreferences, sourceFile?: SourceFile): { specifierComparer: Comparer; isSorted: boolean | undefined; } { +export function getNamedImportSpecifierComparerWithDetection(importDecl: ImportDeclaration | JSDocImportTag, preferences: UserPreferences, sourceFile?: SourceFile): { specifierComparer: Comparer; isSorted: boolean | undefined; } { // sort case sensitivity: // - if the user preference is explicit, use that // - otherwise, if there are enough existing import specifiers in this import to detect unambiguously, use that diff --git a/tests/baselines/reference/APILibCheck.types b/tests/baselines/reference/APILibCheck.types index 0e13955f8192b..11beff94dd62f 100644 --- a/tests/baselines/reference/APILibCheck.types +++ b/tests/baselines/reference/APILibCheck.types @@ -2,7 +2,7 @@ === Performance Stats === Identity cache: 100 / 100 (nearest 100) -Assignability cache: 9,300 / 9,300 (nearest 100) +Assignability cache: 9,500 / 9,500 (nearest 100) Type Count: 22,500 / 22,500 (nearest 100) Instantiation count: 7,000 / 7,000 (nearest 500) Symbol count: 58,500 / 58,500 (nearest 500) From 6bd9d7390a33a4d7765cf77733aecbddf2589d00 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Tue, 19 Mar 2024 00:19:10 +0200 Subject: [PATCH 22/23] always display errors for JSDoc imports in import attributes --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 49db0997b1aea..40914f530ffe6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -46333,7 +46333,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(node, message); } - if (isImportDeclaration(declaration) || isJSDocImportTag(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { + const isTypeOnly = isJSDocImportTag(declaration) || (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly); + if (isTypeOnly) { return grammarErrorOnNode(node, isImportAttributes ? Diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports : Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); } From 653955e93a5b80a9e59dc799a5e274f103eef3e8 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Tue, 26 Mar 2024 22:14:09 +0200 Subject: [PATCH 23/23] add tests --- tests/baselines/reference/importTag16.js | 32 +++++++++++++++++++ tests/baselines/reference/importTag16.symbols | 21 ++++++++++++ tests/baselines/reference/importTag16.types | 19 +++++++++++ tests/cases/conformance/jsdoc/importTag16.ts | 17 ++++++++++ 4 files changed, 89 insertions(+) create mode 100644 tests/baselines/reference/importTag16.js create mode 100644 tests/baselines/reference/importTag16.symbols create mode 100644 tests/baselines/reference/importTag16.types create mode 100644 tests/cases/conformance/jsdoc/importTag16.ts diff --git a/tests/baselines/reference/importTag16.js b/tests/baselines/reference/importTag16.js new file mode 100644 index 0000000000000..63134d7d50256 --- /dev/null +++ b/tests/baselines/reference/importTag16.js @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag16.ts] //// + +//// [a.ts] +export default interface Foo {} +export interface I {} + +//// [b.js] +/** @import Foo, { I } from "./a" */ + +/** + * @param {Foo} a + * @param {I} b + */ +export function foo(a, b) {} + + + + +//// [a.d.ts] +export default interface Foo { +} +export interface I { +} +//// [b.d.ts] +/** @import Foo, { I } from "./a" */ +/** + * @param {Foo} a + * @param {I} b + */ +export function foo(a: Foo, b: I): void; +import type Foo from "./a"; +import type { I } from "./a"; diff --git a/tests/baselines/reference/importTag16.symbols b/tests/baselines/reference/importTag16.symbols new file mode 100644 index 0000000000000..d092f1c89e7bd --- /dev/null +++ b/tests/baselines/reference/importTag16.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/jsdoc/importTag16.ts] //// + +=== a.ts === +export default interface Foo {} +>Foo : Symbol(Foo, Decl(a.ts, 0, 0)) + +export interface I {} +>I : Symbol(I, Decl(a.ts, 0, 31)) + +=== b.js === +/** @import Foo, { I } from "./a" */ + +/** + * @param {Foo} a + * @param {I} b + */ +export function foo(a, b) {} +>foo : Symbol(foo, Decl(b.js, 0, 0)) +>a : Symbol(a, Decl(b.js, 6, 20)) +>b : Symbol(b, Decl(b.js, 6, 22)) + diff --git a/tests/baselines/reference/importTag16.types b/tests/baselines/reference/importTag16.types new file mode 100644 index 0000000000000..13356e92a76d4 --- /dev/null +++ b/tests/baselines/reference/importTag16.types @@ -0,0 +1,19 @@ +//// [tests/cases/conformance/jsdoc/importTag16.ts] //// + +=== a.ts === + +export default interface Foo {} +export interface I {} + +=== b.js === +/** @import Foo, { I } from "./a" */ + +/** + * @param {Foo} a + * @param {I} b + */ +export function foo(a, b) {} +>foo : (a: Foo, b: I) => void +>a : Foo +>b : I + diff --git a/tests/cases/conformance/jsdoc/importTag16.ts b/tests/cases/conformance/jsdoc/importTag16.ts new file mode 100644 index 0000000000000..0a28cd9c8a580 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag16.ts @@ -0,0 +1,17 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @checkJs: true +// @allowJs: true + +// @filename: a.ts +export default interface Foo {} +export interface I {} + +// @filename: b.js +/** @import Foo, { I } from "./a" */ + +/** + * @param {Foo} a + * @param {I} b + */ +export function foo(a, b) {}