Skip to content

Commit 13d3e19

Browse files
authored
Hoist @typedef and @import tags to containing scopes that permit them (#2003)
1 parent d67385b commit 13d3e19

23 files changed

+230
-137
lines changed

internal/ast/ast.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,6 +4845,10 @@ func IsImportDeclaration(node *Node) bool {
48454845
return node.Kind == KindImportDeclaration
48464846
}
48474847

4848+
func IsJSImportDeclaration(node *Node) bool {
4849+
return node.Kind == KindJSImportDeclaration
4850+
}
4851+
48484852
func IsImportDeclarationOrJSImportDeclaration(node *Node) bool {
48494853
return node.Kind == KindImportDeclaration || node.Kind == KindJSImportDeclaration
48504854
}

internal/parser/parser.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,12 +498,21 @@ func (p *Parser) reparseTopLevelAwait(sourceFile *ast.SourceFile) *ast.Node {
498498
func (p *Parser) parseListIndex(kind ParsingContext, parseElement func(p *Parser, index int) *ast.Node) []*ast.Node {
499499
saveParsingContexts := p.parsingContexts
500500
p.parsingContexts |= 1 << kind
501+
outerReparseList := p.reparseList
502+
p.reparseList = nil
501503
list := make([]*ast.Node, 0, 16)
502504
for i := 0; !p.isListTerminator(kind); i++ {
503505
if p.isListElement(kind, false /*inErrorRecovery*/) {
504506
elt := parseElement(p, i)
505507
if len(p.reparseList) > 0 {
506-
list = append(list, p.reparseList...)
508+
for _, e := range p.reparseList {
509+
// Propagate @typedef type alias declarations outwards to a context that permits them.
510+
if (ast.IsJSTypeAliasDeclaration(e) || ast.IsJSImportDeclaration(e)) && kind != PCSourceElements && kind != PCBlockStatements {
511+
outerReparseList = append(outerReparseList, e)
512+
} else {
513+
list = append(list, e)
514+
}
515+
}
507516
p.reparseList = nil
508517
}
509518
list = append(list, elt)
@@ -513,6 +522,7 @@ func (p *Parser) parseListIndex(kind ParsingContext, parseElement func(p *Parser
513522
break
514523
}
515524
}
525+
p.reparseList = outerReparseList
516526
p.parsingContexts = saveParsingContexts
517527
return p.nodeSlicePool.Clone(list)
518528
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error TS5055: Cannot write file 'x.js' because it would overwrite input file.
2+
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
3+
error TS5055: Cannot write file 'y.js' because it would overwrite input file.
4+
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
5+
6+
7+
!!! error TS5055: Cannot write file 'x.js' because it would overwrite input file.
8+
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
9+
!!! error TS5055: Cannot write file 'y.js' because it would overwrite input file.
10+
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
11+
==== x.js (0 errors) ====
12+
class C {
13+
/** @import {Bar} from "./y" */
14+
/** @typedef {Bar[]} Bars */
15+
/** @type {Bars} */
16+
foo = ["abc", "def"]
17+
bar(/** @type {Bar} */ x) {
18+
return x
19+
}
20+
}
21+
22+
==== y.js (0 errors) ====
23+
/** @typedef {string} Bar */
24+
export {}
25+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/typedefHoisting.ts] ////
2+
3+
//// [x.js]
4+
class C {
5+
/** @import {Bar} from "./y" */
6+
/** @typedef {Bar[]} Bars */
7+
/** @type {Bars} */
8+
foo = ["abc", "def"]
9+
bar(/** @type {Bar} */ x) {
10+
return x
11+
}
12+
}
13+
14+
//// [y.js]
15+
/** @typedef {string} Bar */
16+
export {}
17+
18+
19+
20+
21+
//// [y.d.ts]
22+
export type Bar = string;
23+
/** @typedef {string} Bar */
24+
export {};
25+
//// [x.d.ts]
26+
import type { Bar } from "./y";
27+
type Bars = Bar[];
28+
declare class C {
29+
/** @import {Bar} from "./y" */
30+
/** @typedef {Bar[]} Bars */
31+
/** @type {Bars} */
32+
foo: Bars;
33+
bar(/** @type {Bar} */ x: Bar): string;
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [tests/cases/compiler/typedefHoisting.ts] ////
2+
3+
=== x.js ===
4+
class C {
5+
>C : Symbol(C, Decl(x.js, 0, 0))
6+
7+
/** @import {Bar} from "./y" */
8+
/** @typedef {Bar[]} Bars */
9+
/** @type {Bars} */
10+
foo = ["abc", "def"]
11+
>foo : Symbol(C.foo, Decl(x.js, 0, 9))
12+
13+
bar(/** @type {Bar} */ x) {
14+
>bar : Symbol(C.bar, Decl(x.js, 4, 24))
15+
>x : Symbol(x, Decl(x.js, 5, 8))
16+
17+
return x
18+
>x : Symbol(x, Decl(x.js, 5, 8))
19+
}
20+
}
21+
22+
=== y.js ===
23+
24+
/** @typedef {string} Bar */
25+
export {}
26+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [tests/cases/compiler/typedefHoisting.ts] ////
2+
3+
=== x.js ===
4+
class C {
5+
>C : C
6+
7+
/** @import {Bar} from "./y" */
8+
/** @typedef {Bar[]} Bars */
9+
/** @type {Bars} */
10+
foo = ["abc", "def"]
11+
>foo : Bars
12+
>["abc", "def"] : string[]
13+
>"abc" : "abc"
14+
>"def" : "def"
15+
16+
bar(/** @type {Bar} */ x) {
17+
>bar : (x: string) => string
18+
>x : string
19+
20+
return x
21+
>x : string
22+
}
23+
}
24+
25+
=== y.js ===
26+
27+
/** @typedef {string} Bar */
28+
export {}
29+

testdata/baselines/reference/submodule/conformance/callbackOnConstructor.errors.txt

Lines changed: 0 additions & 20 deletions
This file was deleted.

testdata/baselines/reference/submodule/conformance/callbackOnConstructor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ var ooscope2 = s => s.length > 0;
3535

3636

3737
//// [callbackOnConstructor.d.ts]
38+
export type ValueGetter_2 = (name: string) => boolean | number | string | undefined;
3839
export declare class Preferences {
3940
assignability: string;
40-
export type ValueGetter_2 = (name: string) => boolean | number | string | undefined;
4141
/**
4242
* @callback ValueGetter_2
4343
* @param {string} name

testdata/baselines/reference/submodule/conformance/callbackOnConstructor.js.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222

2323
//// [callbackOnConstructor.d.ts]
2424
-export class Preferences {
25+
+export type ValueGetter_2 = (name: string) => boolean | number | string | undefined;
2526
+export declare class Preferences {
2627
assignability: string;
27-
+ export type ValueGetter_2 = (name: string) => boolean | number | string | undefined;
2828
+ /**
2929
+ * @callback ValueGetter_2
3030
+ * @param {string} name

testdata/baselines/reference/submodule/conformance/callbackOnConstructor.symbols

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ export class Preferences {
2020
var ooscope2 = s => s.length > 0
2121
>ooscope2 : Symbol(ooscope2, Decl(callbackOnConstructor.js, 12, 3))
2222
>s : Symbol(s, Decl(callbackOnConstructor.js, 12, 14))
23+
>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
2324
>s : Symbol(s, Decl(callbackOnConstructor.js, 12, 14))
25+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
2426

0 commit comments

Comments
 (0)