Skip to content

Commit 061f02c

Browse files
authored
fix(44021): reference jsx pragma when JsxFragment is used (microsoft#45894)
1 parent 5d0d7ae commit 061f02c

File tree

6 files changed

+426
-20
lines changed

6 files changed

+426
-20
lines changed

src/compiler/checker.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,17 +1036,9 @@ namespace ts {
10361036
}
10371037
}
10381038
else {
1039-
if (file.localJsxNamespace) {
1040-
return file.localJsxNamespace;
1041-
}
1042-
const jsxPragma = file.pragmas.get("jsx");
1043-
if (jsxPragma) {
1044-
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
1045-
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
1046-
visitNode(file.localJsxFactory, markAsSynthetic);
1047-
if (file.localJsxFactory) {
1048-
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
1049-
}
1039+
const localJsxNamespace = getLocalJsxNamespace(file);
1040+
if (localJsxNamespace) {
1041+
return file.localJsxNamespace = localJsxNamespace;
10501042
}
10511043
}
10521044
}
@@ -1068,13 +1060,28 @@ namespace ts {
10681060
_jsxFactoryEntity = factory.createQualifiedName(factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement");
10691061
}
10701062
return _jsxNamespace;
1063+
}
10711064

1072-
function markAsSynthetic(node: Node): VisitResult<Node> {
1073-
setTextRangePosEnd(node, -1, -1);
1074-
return visitEachChild(node, markAsSynthetic, nullTransformationContext);
1065+
function getLocalJsxNamespace(file: SourceFile): __String | undefined {
1066+
if (file.localJsxNamespace) {
1067+
return file.localJsxNamespace;
1068+
}
1069+
const jsxPragma = file.pragmas.get("jsx");
1070+
if (jsxPragma) {
1071+
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
1072+
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
1073+
visitNode(file.localJsxFactory, markAsSynthetic);
1074+
if (file.localJsxFactory) {
1075+
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
1076+
}
10751077
}
10761078
}
10771079

1080+
function markAsSynthetic(node: Node): VisitResult<Node> {
1081+
setTextRangePosEnd(node, -1, -1);
1082+
return visitEachChild(node, markAsSynthetic, nullTransformationContext);
1083+
}
1084+
10781085
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
10791086
// Ensure we have all the type information in place for this file so that all the
10801087
// emitter questions of this resolver will return the right information.
@@ -27598,6 +27605,15 @@ namespace ts {
2759827605
markAliasSymbolAsReferenced(jsxFactorySym);
2759927606
}
2760027607
}
27608+
27609+
// For JsxFragment, mark jsx pragma as referenced via resolveName
27610+
if (isJsxOpeningFragment(node)) {
27611+
const file = getSourceFileOfNode(node);
27612+
const localJsxNamespace = getLocalJsxNamespace(file);
27613+
if (localJsxNamespace) {
27614+
resolveName(jsxFactoryLocation, localJsxNamespace, SymbolFlags.Value, jsxFactoryRefErr, localJsxNamespace, /*isUse*/ true);
27615+
}
27616+
}
2760127617
}
2760227618

2760327619
if (isNodeOpeningLikeElement) {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
tests/cases/conformance/jsx/inline/preacty-no-fragment.tsx(5,12): error TS6133: 'Fragment' is declared but its value is never read.
2+
tests/cases/conformance/jsx/inline/preacty-only-fragment-no-jsx.tsx(6,1): error TS2304: Cannot find name 'h'.
3+
tests/cases/conformance/jsx/inline/snabbdomy-only-fragment-no-jsx.tsx(4,1): error TS2304: Cannot find name 'jsx'.
4+
5+
6+
==== tests/cases/conformance/jsx/inline/renderer.d.ts (0 errors) ====
7+
declare global {
8+
namespace JSX {
9+
interface IntrinsicElements {
10+
[e: string]: any;
11+
}
12+
}
13+
}
14+
export function h(): void;
15+
export function jsx(): void;
16+
export function Fragment(): void;
17+
18+
==== tests/cases/conformance/jsx/inline/preacty.tsx (0 errors) ====
19+
/**
20+
* @jsx h
21+
* @jsxFrag Fragment
22+
*/
23+
import {h, Fragment} from "./renderer";
24+
<><div></div></>
25+
26+
==== tests/cases/conformance/jsx/inline/snabbdomy.tsx (0 errors) ====
27+
/* @jsx jsx */
28+
/* @jsxfrag null */
29+
import {jsx} from "./renderer";
30+
<><span></span></>
31+
32+
==== tests/cases/conformance/jsx/inline/preacty-only-fragment.tsx (0 errors) ====
33+
/**
34+
* @jsx h
35+
* @jsxFrag Fragment
36+
*/
37+
import {h, Fragment} from "./renderer";
38+
<></>
39+
40+
==== tests/cases/conformance/jsx/inline/snabbdomy-only-fragment.tsx (0 errors) ====
41+
/* @jsx jsx */
42+
/* @jsxfrag null */
43+
import {jsx} from "./renderer";
44+
<></>
45+
46+
==== tests/cases/conformance/jsx/inline/preacty-only-fragment-no-jsx.tsx (1 errors) ====
47+
/**
48+
* @jsx h
49+
* @jsxFrag Fragment
50+
*/
51+
import {Fragment} from "./renderer";
52+
<></>
53+
~~
54+
!!! error TS2304: Cannot find name 'h'.
55+
56+
==== tests/cases/conformance/jsx/inline/snabbdomy-only-fragment-no-jsx.tsx (1 errors) ====
57+
/* @jsx jsx */
58+
/* @jsxfrag null */
59+
import {} from "./renderer";
60+
<></>
61+
~~
62+
!!! error TS2304: Cannot find name 'jsx'.
63+
64+
==== tests/cases/conformance/jsx/inline/preacty-no-fragment.tsx (1 errors) ====
65+
/**
66+
* @jsx h
67+
* @jsxFrag Fragment
68+
*/
69+
import {h, Fragment} from "./renderer";
70+
~~~~~~~~
71+
!!! error TS6133: 'Fragment' is declared but its value is never read.
72+
<div></div>
73+
74+
==== tests/cases/conformance/jsx/inline/snabbdomy-no-fragment.tsx (0 errors) ====
75+
/* @jsx jsx */
76+
/* @jsxfrag null */
77+
import {jsx} from "./renderer";
78+
<div></div>
79+
80+
==== tests/cases/conformance/jsx/inline/preacty-only-component.tsx (0 errors) ====
81+
/**
82+
* @jsx h
83+
*/
84+
import {h} from "./renderer";
85+
function Component() { return null; }
86+
<Component />
87+

tests/baselines/reference/inlineJsxAndJsxFragPragma.js

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,58 @@ import {h, Fragment} from "./renderer";
2424
/* @jsx jsx */
2525
/* @jsxfrag null */
2626
import {jsx} from "./renderer";
27-
<><span></span></>
27+
<><span></span></>
28+
29+
//// [preacty-only-fragment.tsx]
30+
/**
31+
* @jsx h
32+
* @jsxFrag Fragment
33+
*/
34+
import {h, Fragment} from "./renderer";
35+
<></>
36+
37+
//// [snabbdomy-only-fragment.tsx]
38+
/* @jsx jsx */
39+
/* @jsxfrag null */
40+
import {jsx} from "./renderer";
41+
<></>
42+
43+
//// [preacty-only-fragment-no-jsx.tsx]
44+
/**
45+
* @jsx h
46+
* @jsxFrag Fragment
47+
*/
48+
import {Fragment} from "./renderer";
49+
<></>
50+
51+
//// [snabbdomy-only-fragment-no-jsx.tsx]
52+
/* @jsx jsx */
53+
/* @jsxfrag null */
54+
import {} from "./renderer";
55+
<></>
56+
57+
//// [preacty-no-fragment.tsx]
58+
/**
59+
* @jsx h
60+
* @jsxFrag Fragment
61+
*/
62+
import {h, Fragment} from "./renderer";
63+
<div></div>
64+
65+
//// [snabbdomy-no-fragment.tsx]
66+
/* @jsx jsx */
67+
/* @jsxfrag null */
68+
import {jsx} from "./renderer";
69+
<div></div>
70+
71+
//// [preacty-only-component.tsx]
72+
/**
73+
* @jsx h
74+
*/
75+
import {h} from "./renderer";
76+
function Component() { return null; }
77+
<Component />
78+
2879

2980
//// [preacty.js]
3081
"use strict";
@@ -44,3 +95,54 @@ exports.__esModule = true;
4495
var renderer_1 = require("./renderer");
4596
(0, renderer_1.jsx)(null, null,
4697
(0, renderer_1.jsx)("span", null));
98+
//// [preacty-only-fragment.js]
99+
"use strict";
100+
exports.__esModule = true;
101+
/**
102+
* @jsx h
103+
* @jsxFrag Fragment
104+
*/
105+
var renderer_1 = require("./renderer");
106+
(0, renderer_1.h)(renderer_1.Fragment, null);
107+
//// [snabbdomy-only-fragment.js]
108+
"use strict";
109+
exports.__esModule = true;
110+
(0, renderer_1.jsx)(null, null);
111+
//// [preacty-only-fragment-no-jsx.js]
112+
"use strict";
113+
exports.__esModule = true;
114+
/**
115+
* @jsx h
116+
* @jsxFrag Fragment
117+
*/
118+
var renderer_1 = require("./renderer");
119+
h(renderer_1.Fragment, null);
120+
//// [snabbdomy-only-fragment-no-jsx.js]
121+
"use strict";
122+
exports.__esModule = true;
123+
jsx(null, null);
124+
//// [preacty-no-fragment.js]
125+
"use strict";
126+
exports.__esModule = true;
127+
/**
128+
* @jsx h
129+
* @jsxFrag Fragment
130+
*/
131+
var renderer_1 = require("./renderer");
132+
(0, renderer_1.h)("div", null);
133+
//// [snabbdomy-no-fragment.js]
134+
"use strict";
135+
exports.__esModule = true;
136+
/* @jsx jsx */
137+
/* @jsxfrag null */
138+
var renderer_1 = require("./renderer");
139+
(0, renderer_1.jsx)("div", null);
140+
//// [preacty-only-component.js]
141+
"use strict";
142+
exports.__esModule = true;
143+
/**
144+
* @jsx h
145+
*/
146+
var renderer_1 = require("./renderer");
147+
function Component() { return null; }
148+
(0, renderer_1.h)(Component, null);

tests/baselines/reference/inlineJsxAndJsxFragPragma.symbols

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,74 @@ import {jsx} from "./renderer";
4545
>span : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
4646
>span : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
4747

48+
=== tests/cases/conformance/jsx/inline/preacty-only-fragment.tsx ===
49+
/**
50+
* @jsx h
51+
* @jsxFrag Fragment
52+
*/
53+
import {h, Fragment} from "./renderer";
54+
>h : Symbol(h, Decl(preacty-only-fragment.tsx, 4, 8))
55+
>Fragment : Symbol(Fragment, Decl(preacty-only-fragment.tsx, 4, 10))
56+
57+
<></>
58+
59+
=== tests/cases/conformance/jsx/inline/snabbdomy-only-fragment.tsx ===
60+
/* @jsx jsx */
61+
/* @jsxfrag null */
62+
import {jsx} from "./renderer";
63+
>jsx : Symbol(jsx, Decl(snabbdomy-only-fragment.tsx, 2, 8))
64+
65+
<></>
66+
67+
=== tests/cases/conformance/jsx/inline/preacty-only-fragment-no-jsx.tsx ===
68+
/**
69+
* @jsx h
70+
* @jsxFrag Fragment
71+
*/
72+
import {Fragment} from "./renderer";
73+
>Fragment : Symbol(Fragment, Decl(preacty-only-fragment-no-jsx.tsx, 4, 8))
74+
75+
<></>
76+
77+
=== tests/cases/conformance/jsx/inline/snabbdomy-only-fragment-no-jsx.tsx ===
78+
/* @jsx jsx */
79+
No type information for this code./* @jsxfrag null */
80+
No type information for this code.import {} from "./renderer";
81+
No type information for this code.<></>
82+
No type information for this code.
83+
No type information for this code.=== tests/cases/conformance/jsx/inline/preacty-no-fragment.tsx ===
84+
/**
85+
* @jsx h
86+
* @jsxFrag Fragment
87+
*/
88+
import {h, Fragment} from "./renderer";
89+
>h : Symbol(h, Decl(preacty-no-fragment.tsx, 4, 8))
90+
>Fragment : Symbol(Fragment, Decl(preacty-no-fragment.tsx, 4, 10))
91+
92+
<div></div>
93+
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
94+
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
95+
96+
=== tests/cases/conformance/jsx/inline/snabbdomy-no-fragment.tsx ===
97+
/* @jsx jsx */
98+
/* @jsxfrag null */
99+
import {jsx} from "./renderer";
100+
>jsx : Symbol(jsx, Decl(snabbdomy-no-fragment.tsx, 2, 8))
101+
102+
<div></div>
103+
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
104+
>div : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19))
105+
106+
=== tests/cases/conformance/jsx/inline/preacty-only-component.tsx ===
107+
/**
108+
* @jsx h
109+
*/
110+
import {h} from "./renderer";
111+
>h : Symbol(h, Decl(preacty-only-component.tsx, 3, 8))
112+
113+
function Component() { return null; }
114+
>Component : Symbol(Component, Decl(preacty-only-component.tsx, 3, 29))
115+
116+
<Component />
117+
>Component : Symbol(Component, Decl(preacty-only-component.tsx, 3, 29))
118+

0 commit comments

Comments
 (0)