Skip to content

Commit df5a194

Browse files
committed
mark localJsxFactory as used and type elision test
1 parent fe8099a commit df5a194

7 files changed

+339
-20
lines changed

src/compiler/checker.ts

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -952,16 +952,32 @@ namespace ts {
952952
if (location) {
953953
const file = getSourceFileOfNode(location);
954954
if (file) {
955-
if (file.localJsxNamespace) {
956-
return file.localJsxNamespace;
955+
if (isJsxOpeningFragment(location)) {
956+
if (file.localJsxFragmentNamespace) {
957+
return file.localJsxFragmentNamespace;
958+
}
959+
const jsxFragmentPragma = file.pragmas.get("jsxfrag");
960+
if (jsxFragmentPragma) {
961+
const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma;
962+
file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
963+
visitNode(file.localJsxFragmentFactory, markAsSynthetic);
964+
if (file.localJsxFragmentFactory) {
965+
return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText;
966+
}
967+
}
957968
}
958-
const jsxPragma = file.pragmas.get("jsx");
959-
if (jsxPragma) {
960-
const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
961-
file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion);
962-
visitNode(file.localJsxFactory, markAsSynthetic);
963-
if (file.localJsxFactory) {
964-
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
969+
else {
970+
if (file.localJsxNamespace) {
971+
return file.localJsxNamespace;
972+
}
973+
const jsxPragma = file.pragmas.get("jsx");
974+
if (jsxPragma) {
975+
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
976+
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
977+
visitNode(file.localJsxFactory, markAsSynthetic);
978+
if (file.localJsxFactory) {
979+
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
980+
}
965981
}
966982
}
967983
}
@@ -23978,21 +23994,28 @@ namespace ts {
2397823994
if (isNodeOpeningLikeElement) {
2397923995
checkGrammarJsxElement(<JsxOpeningLikeElement>node);
2398023996
}
23997+
2398123998
checkJsxPreconditions(node);
2398223999
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
2398324000
// And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
23984-
const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
23985-
const reactNamespace = getJsxNamespace(node);
23986-
const reactLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
23987-
const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
23988-
if (reactSym) {
24001+
const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
24002+
const jsxFactoryNamespace = getJsxNamespace(node);
24003+
const jsxFactoryLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
24004+
24005+
// allow null as jsxFragmentFactory
24006+
let jsxFactorySym: Symbol | undefined;
24007+
if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) {
24008+
jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true);
24009+
}
24010+
24011+
if (jsxFactorySym) {
2398924012
// Mark local symbol as referenced here because it might not have been marked
23990-
// if jsx emit was not react as there wont be error being emitted
23991-
reactSym.isReferenced = SymbolFlags.All;
24013+
// if jsx emit was not jsxFactory as there wont be error being emitted
24014+
jsxFactorySym.isReferenced = SymbolFlags.All;
2399224015

23993-
// If react symbol is alias, mark it as refereced
23994-
if (reactSym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(reactSym)) {
23995-
markAliasSymbolAsReferenced(reactSym);
24016+
// If react/jsxFactory symbol is alias, mark it as refereced
24017+
if (jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
24018+
markAliasSymbolAsReferenced(jsxFactorySym);
2399624019
}
2399724020
}
2399824021

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3011,6 +3011,7 @@ namespace ts {
30113011
/* @internal */ version: string;
30123012
/* @internal */ pragmas: ReadonlyPragmaMap;
30133013
/* @internal */ localJsxNamespace?: __String;
3014+
/* @internal */ localJsxFragmentNamespace?: __String;
30143015
/* @internal */ localJsxFactory?: EntityName;
30153016
/* @internal */ localJsxFragmentFactory?: EntityName;
30163017

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//// [tests/cases/conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx] ////
2+
3+
//// [react.d.ts]
4+
declare global {
5+
namespace JSX {
6+
interface IntrinsicElements {
7+
[e: string]: any;
8+
}
9+
}
10+
}
11+
export function createElement(): void;
12+
export function Fragment(): void;
13+
14+
//// [preact.d.ts]
15+
export function h(): void;
16+
export function Frag(): void;
17+
18+
//// [snabbdom.d.ts]
19+
export function h(): void;
20+
21+
//// [reacty.tsx]
22+
import {createElement, Fragment} from "./react";
23+
<><span></span></>
24+
25+
//// [preacty.tsx]
26+
/**
27+
* @jsx h
28+
* @jsxFrag Frag
29+
*/
30+
import {h, Frag} from "./preact";
31+
<><div></div></>
32+
33+
//// [snabbdomy.tsx]
34+
/**
35+
* @jsx h
36+
* @jsxfrag null
37+
*/
38+
import {h} from "./snabbdom";
39+
<><div></div></>
40+
41+
//// [mix-n-match.tsx]
42+
/* @jsx h */
43+
/* @jsxFrag Fragment */
44+
import {h} from "./preact";
45+
import {Fragment} from "./react";
46+
<><span></span></>
47+
48+
//// [reacty.js]
49+
"use strict";
50+
exports.__esModule = true;
51+
var react_1 = require("./react");
52+
react_1.createElement(react_1.Fragment, null,
53+
react_1.createElement("span", null));
54+
//// [preacty.js]
55+
"use strict";
56+
exports.__esModule = true;
57+
/**
58+
* @jsx h
59+
* @jsxFrag Frag
60+
*/
61+
var preact_1 = require("./preact");
62+
preact_1.h(preact_1.Frag, null,
63+
preact_1.h("div", null));
64+
//// [snabbdomy.js]
65+
"use strict";
66+
exports.__esModule = true;
67+
/**
68+
* @jsx h
69+
* @jsxfrag null
70+
*/
71+
var snabbdom_1 = require("./snabbdom");
72+
snabbdom_1.h(null, null,
73+
snabbdom_1.h("div", null));
74+
//// [mix-n-match.js]
75+
"use strict";
76+
exports.__esModule = true;
77+
/* @jsx h */
78+
/* @jsxFrag Fragment */
79+
var preact_1 = require("./preact");
80+
var react_1 = require("./react");
81+
preact_1.h(react_1.Fragment, null,
82+
preact_1.h("span", null));
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
=== tests/cases/conformance/jsx/inline/react.d.ts ===
2+
declare global {
3+
>global : Symbol(global, Decl(react.d.ts, 0, 0))
4+
5+
namespace JSX {
6+
>JSX : Symbol(JSX, Decl(react.d.ts, 0, 16))
7+
8+
interface IntrinsicElements {
9+
>IntrinsicElements : Symbol(IntrinsicElements, Decl(react.d.ts, 1, 19))
10+
11+
[e: string]: any;
12+
>e : Symbol(e, Decl(react.d.ts, 3, 13))
13+
}
14+
}
15+
}
16+
export function createElement(): void;
17+
>createElement : Symbol(createElement, Decl(react.d.ts, 6, 1))
18+
19+
export function Fragment(): void;
20+
>Fragment : Symbol(Fragment, Decl(react.d.ts, 7, 38))
21+
22+
=== tests/cases/conformance/jsx/inline/preact.d.ts ===
23+
export function h(): void;
24+
>h : Symbol(h, Decl(preact.d.ts, 0, 0))
25+
26+
export function Frag(): void;
27+
>Frag : Symbol(Frag, Decl(preact.d.ts, 0, 26))
28+
29+
=== tests/cases/conformance/jsx/inline/snabbdom.d.ts ===
30+
export function h(): void;
31+
>h : Symbol(h, Decl(snabbdom.d.ts, 0, 0))
32+
33+
=== tests/cases/conformance/jsx/inline/reacty.tsx ===
34+
import {createElement, Fragment} from "./react";
35+
>createElement : Symbol(createElement, Decl(reacty.tsx, 0, 8))
36+
>Fragment : Symbol(Fragment, Decl(reacty.tsx, 0, 22))
37+
38+
<><span></span></>
39+
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
40+
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
41+
42+
=== tests/cases/conformance/jsx/inline/preacty.tsx ===
43+
/**
44+
* @jsx h
45+
* @jsxFrag Frag
46+
*/
47+
import {h, Frag} from "./preact";
48+
>h : Symbol(h, Decl(preacty.tsx, 4, 8))
49+
>Frag : Symbol(Frag, Decl(preacty.tsx, 4, 10))
50+
51+
<><div></div></>
52+
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
53+
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
54+
55+
=== tests/cases/conformance/jsx/inline/snabbdomy.tsx ===
56+
/**
57+
* @jsx h
58+
* @jsxfrag null
59+
*/
60+
import {h} from "./snabbdom";
61+
>h : Symbol(h, Decl(snabbdomy.tsx, 4, 8))
62+
63+
<><div></div></>
64+
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
65+
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
66+
67+
=== tests/cases/conformance/jsx/inline/mix-n-match.tsx ===
68+
/* @jsx h */
69+
/* @jsxFrag Fragment */
70+
import {h} from "./preact";
71+
>h : Symbol(h, Decl(mix-n-match.tsx, 2, 8))
72+
73+
import {Fragment} from "./react";
74+
>Fragment : Symbol(Fragment, Decl(mix-n-match.tsx, 3, 8))
75+
76+
<><span></span></>
77+
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
78+
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
79+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
=== tests/cases/conformance/jsx/inline/react.d.ts ===
2+
declare global {
3+
>global : any
4+
5+
namespace JSX {
6+
interface IntrinsicElements {
7+
[e: string]: any;
8+
>e : string
9+
}
10+
}
11+
}
12+
export function createElement(): void;
13+
>createElement : () => void
14+
15+
export function Fragment(): void;
16+
>Fragment : () => void
17+
18+
=== tests/cases/conformance/jsx/inline/preact.d.ts ===
19+
export function h(): void;
20+
>h : () => void
21+
22+
export function Frag(): void;
23+
>Frag : () => void
24+
25+
=== tests/cases/conformance/jsx/inline/snabbdom.d.ts ===
26+
export function h(): void;
27+
>h : () => void
28+
29+
=== tests/cases/conformance/jsx/inline/reacty.tsx ===
30+
import {createElement, Fragment} from "./react";
31+
>createElement : () => void
32+
>Fragment : () => void
33+
34+
<><span></span></>
35+
><><span></span></> : error
36+
><span></span> : error
37+
>span : any
38+
>span : any
39+
40+
=== tests/cases/conformance/jsx/inline/preacty.tsx ===
41+
/**
42+
* @jsx h
43+
* @jsxFrag Frag
44+
*/
45+
import {h, Frag} from "./preact";
46+
>h : () => void
47+
>Frag : () => void
48+
49+
<><div></div></>
50+
><><div></div></> : error
51+
><div></div> : error
52+
>div : any
53+
>div : any
54+
55+
=== tests/cases/conformance/jsx/inline/snabbdomy.tsx ===
56+
/**
57+
* @jsx h
58+
* @jsxfrag null
59+
*/
60+
import {h} from "./snabbdom";
61+
>h : () => void
62+
63+
<><div></div></>
64+
><><div></div></> : error
65+
><div></div> : error
66+
>div : any
67+
>div : any
68+
69+
=== tests/cases/conformance/jsx/inline/mix-n-match.tsx ===
70+
/* @jsx h */
71+
/* @jsxFrag Fragment */
72+
import {h} from "./preact";
73+
>h : () => void
74+
75+
import {Fragment} from "./react";
76+
>Fragment : () => void
77+
78+
<><span></span></>
79+
><><span></span></> : error
80+
><span></span> : error
81+
>span : any
82+
>span : any
83+

tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
tests/cases/conformance/jsx/inline/index.tsx(3,1): error TS2304: Cannot find name 'React'.
12
tests/cases/conformance/jsx/inline/index.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
23
tests/cases/conformance/jsx/inline/reacty.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
34

@@ -18,9 +19,11 @@ tests/cases/conformance/jsx/inline/reacty.tsx(3,1): error TS17017: An @jsxFrag p
1819
<><h></h></>
1920
~~~~~~~~~~~~
2021
!!! error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
21-
==== tests/cases/conformance/jsx/inline/index.tsx (1 errors) ====
22+
==== tests/cases/conformance/jsx/inline/index.tsx (2 errors) ====
2223
/** @jsx dom */
2324
import { dom } from "./renderer";
2425
<><h></h></>
26+
~~
27+
!!! error TS2304: Cannot find name 'React'.
2528
~~~~~~~~~~~~
2629
!!! error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.

0 commit comments

Comments
 (0)