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) {} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy