diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2be7199e179e8..f66f0f26fe1e7 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2638,7 +2638,7 @@ namespace Parser { function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { if (isIdentifier) { identifierCount++; - const pos = getNodePos(); + const pos = scanner.hasLeadingAsterisks() ? scanner.getTokenStart() : getNodePos(); // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker const originalKeywordKind = token(); const text = internIdentifier(scanner.getTokenValue()); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index e93cc82b0a5db..21b011ca73a7f 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -112,6 +112,8 @@ export interface Scanner { resetTokenState(pos: number): void; /** @internal */ setSkipJsDocLeadingAsterisks(skip: boolean): void; + /** @internal */ + hasLeadingAsterisks(): boolean; // 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. @@ -1042,6 +1044,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean var commentDirectives: CommentDirective[] | undefined; var skipJsDocLeadingAsterisks = 0; + var asteriskSeen = false; var scriptKind = ScriptKind.Unknown; var jsDocParsingMode = JSDocParsingMode.ParseAll; @@ -1096,6 +1099,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean resetTokenState, setTextPos: resetTokenState, setSkipJsDocLeadingAsterisks, + hasLeadingAsterisks, tryScan, lookAhead, scanRange, @@ -1877,7 +1881,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean function scan(): SyntaxKind { fullStartPos = pos; tokenFlags = TokenFlags.None; - let asteriskSeen = false; + asteriskSeen = false; while (true) { tokenStart = pos; if (pos >= end) { @@ -4004,6 +4008,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean function setSkipJsDocLeadingAsterisks(skip: boolean) { skipJsDocLeadingAsterisks += skip ? 1 : -1; } + + function hasLeadingAsterisks() { + return asteriskSeen; + } } function codePointAt(s: string, i: number): number { diff --git a/tests/baselines/reference/importTag18.js b/tests/baselines/reference/importTag18.js new file mode 100644 index 0000000000000..e6526792832e9 --- /dev/null +++ b/tests/baselines/reference/importTag18.js @@ -0,0 +1,34 @@ +//// [tests/cases/conformance/jsdoc/importTag18.ts] //// + +//// [a.ts] +export interface Foo {} + +//// [b.js] +/** + * @import { + * Foo + * } from "./a" + */ + +/** + * @param {Foo} a + */ +export function foo(a) {} + + + + +//// [a.d.ts] +export interface Foo { +} +//// [b.d.ts] +/** + * @import { + * Foo + * } from "./a" + */ +/** + * @param {Foo} a + */ +export function foo(a: Foo): void; +import type { Foo } from "./a"; diff --git a/tests/baselines/reference/importTag18.symbols b/tests/baselines/reference/importTag18.symbols new file mode 100644 index 0000000000000..1bffb3f5ac8f5 --- /dev/null +++ b/tests/baselines/reference/importTag18.symbols @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/jsdoc/importTag18.ts] //// + +=== a.ts === +export interface Foo {} +>Foo : Symbol(Foo, Decl(a.ts, 0, 0)) + +=== b.js === +/** + * @import { + * Foo + * } from "./a" + */ + +/** + * @param {Foo} a + */ +export function foo(a) {} +>foo : Symbol(foo, Decl(b.js, 0, 0)) +>a : Symbol(a, Decl(b.js, 9, 20)) + diff --git a/tests/baselines/reference/importTag18.types b/tests/baselines/reference/importTag18.types new file mode 100644 index 0000000000000..f5be5b5fdfec8 --- /dev/null +++ b/tests/baselines/reference/importTag18.types @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/jsdoc/importTag18.ts] //// + +=== a.ts === + +export interface Foo {} + +=== b.js === +/** + * @import { + * Foo + * } from "./a" + */ + +/** + * @param {Foo} a + */ +export function foo(a) {} +>foo : (a: Foo) => void +> : ^ ^^^^^^^^^^^^^^ +>a : Foo +> : ^^^ + diff --git a/tests/baselines/reference/importTag6.types b/tests/baselines/reference/importTag6.types index b6df22ac87727..3918c3df37128 100644 --- a/tests/baselines/reference/importTag6.types +++ b/tests/baselines/reference/importTag6.types @@ -25,10 +25,10 @@ export interface B { * @param { B } b */ function f(a, b) {} ->f : (a: * A, b: * B) => void -> : ^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ->a : * A -> : ^^^^^^^ ->b : * B -> : ^^^^^^^ +>f : (a: A, b: B) => void +> : ^ ^^^^^ ^^^^^^^^^^^^ +>a : A +> : ^ +>b : B +> : ^ diff --git a/tests/baselines/reference/importTag7.types b/tests/baselines/reference/importTag7.types index e80491c8496c3..2732407d16240 100644 --- a/tests/baselines/reference/importTag7.types +++ b/tests/baselines/reference/importTag7.types @@ -24,10 +24,10 @@ export interface B { * @param { B } b */ function f(a, b) {} ->f : (a: * A, b: * B) => void -> : ^ ^^^^^^^ ^^^^^^^^^^^^^^ ->a : * A -> : ^^^ ->b : * B -> : ^^^ +>f : (a: A, b: B) => void +> : ^ ^^^^^ ^^^^^^^^^^^^ +>a : A +> : ^ +>b : B +> : ^ diff --git a/tests/cases/conformance/jsdoc/importTag18.ts b/tests/cases/conformance/jsdoc/importTag18.ts new file mode 100644 index 0000000000000..bdbb2bc7a0908 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag18.ts @@ -0,0 +1,19 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @checkJs: true +// @allowJs: true + +// @filename: a.ts +export interface Foo {} + +// @filename: b.js +/** + * @import { + * Foo + * } from "./a" + */ + +/** + * @param {Foo} a + */ +export function foo(a) {}