Skip to content

Commit

Permalink
mark localJsxFactory as used and type elision test
Browse files Browse the repository at this point in the history
  • Loading branch information
nojvek committed May 22, 2020
1 parent fe8099a commit df5a194
Show file tree
Hide file tree
Showing 7 changed files with 339 additions and 20 deletions.
61 changes: 42 additions & 19 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -952,16 +952,32 @@ namespace ts {
if (location) {
const file = getSourceFileOfNode(location);
if (file) {
if (file.localJsxNamespace) {
return file.localJsxNamespace;
if (isJsxOpeningFragment(location)) {
if (file.localJsxFragmentNamespace) {
return file.localJsxFragmentNamespace;
}
const jsxFragmentPragma = file.pragmas.get("jsxfrag");
if (jsxFragmentPragma) {
const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma;
file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
visitNode(file.localJsxFragmentFactory, markAsSynthetic);
if (file.localJsxFragmentFactory) {
return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText;
}
}
}
const jsxPragma = file.pragmas.get("jsx");
if (jsxPragma) {
const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion);
visitNode(file.localJsxFactory, markAsSynthetic);
if (file.localJsxFactory) {
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
else {
if (file.localJsxNamespace) {
return file.localJsxNamespace;
}
const jsxPragma = file.pragmas.get("jsx");
if (jsxPragma) {
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
visitNode(file.localJsxFactory, markAsSynthetic);
if (file.localJsxFactory) {
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
}
}
}
}
Expand Down Expand Up @@ -23978,21 +23994,28 @@ namespace ts {
if (isNodeOpeningLikeElement) {
checkGrammarJsxElement(<JsxOpeningLikeElement>node);
}

checkJsxPreconditions(node);
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
// And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
const reactNamespace = getJsxNamespace(node);
const reactLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;
const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true);
if (reactSym) {
const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
const jsxFactoryNamespace = getJsxNamespace(node);
const jsxFactoryLocation = isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>node).tagName : node;

// allow null as jsxFragmentFactory
let jsxFactorySym: Symbol | undefined;
if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) {
jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true);
}

if (jsxFactorySym) {
// Mark local symbol as referenced here because it might not have been marked
// if jsx emit was not react as there wont be error being emitted
reactSym.isReferenced = SymbolFlags.All;
// if jsx emit was not jsxFactory as there wont be error being emitted
jsxFactorySym.isReferenced = SymbolFlags.All;

// If react symbol is alias, mark it as refereced
if (reactSym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(reactSym)) {
markAliasSymbolAsReferenced(reactSym);
// If react/jsxFactory symbol is alias, mark it as refereced
if (jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
markAliasSymbolAsReferenced(jsxFactorySym);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3011,6 +3011,7 @@ namespace ts {
/* @internal */ version: string;
/* @internal */ pragmas: ReadonlyPragmaMap;
/* @internal */ localJsxNamespace?: __String;
/* @internal */ localJsxFragmentNamespace?: __String;
/* @internal */ localJsxFactory?: EntityName;
/* @internal */ localJsxFragmentFactory?: EntityName;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//// [tests/cases/conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx] ////

//// [react.d.ts]
declare global {
namespace JSX {
interface IntrinsicElements {
[e: string]: any;
}
}
}
export function createElement(): void;
export function Fragment(): void;

//// [preact.d.ts]
export function h(): void;
export function Frag(): void;

//// [snabbdom.d.ts]
export function h(): void;

//// [reacty.tsx]
import {createElement, Fragment} from "./react";
<><span></span></>

//// [preacty.tsx]
/**
* @jsx h
* @jsxFrag Frag
*/
import {h, Frag} from "./preact";
<><div></div></>

//// [snabbdomy.tsx]
/**
* @jsx h
* @jsxfrag null
*/
import {h} from "./snabbdom";
<><div></div></>

//// [mix-n-match.tsx]
/* @jsx h */
/* @jsxFrag Fragment */
import {h} from "./preact";
import {Fragment} from "./react";
<><span></span></>

//// [reacty.js]
"use strict";
exports.__esModule = true;
var react_1 = require("./react");
react_1.createElement(react_1.Fragment, null,
react_1.createElement("span", null));
//// [preacty.js]
"use strict";
exports.__esModule = true;
/**
* @jsx h
* @jsxFrag Frag
*/
var preact_1 = require("./preact");
preact_1.h(preact_1.Frag, null,
preact_1.h("div", null));
//// [snabbdomy.js]
"use strict";
exports.__esModule = true;
/**
* @jsx h
* @jsxfrag null
*/
var snabbdom_1 = require("./snabbdom");
snabbdom_1.h(null, null,
snabbdom_1.h("div", null));
//// [mix-n-match.js]
"use strict";
exports.__esModule = true;
/* @jsx h */
/* @jsxFrag Fragment */
var preact_1 = require("./preact");
var react_1 = require("./react");
preact_1.h(react_1.Fragment, null,
preact_1.h("span", null));
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
=== tests/cases/conformance/jsx/inline/react.d.ts ===
declare global {
>global : Symbol(global, Decl(react.d.ts, 0, 0))

namespace JSX {
>JSX : Symbol(JSX, Decl(react.d.ts, 0, 16))

interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(react.d.ts, 1, 19))

[e: string]: any;
>e : Symbol(e, Decl(react.d.ts, 3, 13))
}
}
}
export function createElement(): void;
>createElement : Symbol(createElement, Decl(react.d.ts, 6, 1))

export function Fragment(): void;
>Fragment : Symbol(Fragment, Decl(react.d.ts, 7, 38))

=== tests/cases/conformance/jsx/inline/preact.d.ts ===
export function h(): void;
>h : Symbol(h, Decl(preact.d.ts, 0, 0))

export function Frag(): void;
>Frag : Symbol(Frag, Decl(preact.d.ts, 0, 26))

=== tests/cases/conformance/jsx/inline/snabbdom.d.ts ===
export function h(): void;
>h : Symbol(h, Decl(snabbdom.d.ts, 0, 0))

=== tests/cases/conformance/jsx/inline/reacty.tsx ===
import {createElement, Fragment} from "./react";
>createElement : Symbol(createElement, Decl(reacty.tsx, 0, 8))
>Fragment : Symbol(Fragment, Decl(reacty.tsx, 0, 22))

<><span></span></>
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))

=== tests/cases/conformance/jsx/inline/preacty.tsx ===
/**
* @jsx h
* @jsxFrag Frag
*/
import {h, Frag} from "./preact";
>h : Symbol(h, Decl(preacty.tsx, 4, 8))
>Frag : Symbol(Frag, Decl(preacty.tsx, 4, 10))

<><div></div></>
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))

=== tests/cases/conformance/jsx/inline/snabbdomy.tsx ===
/**
* @jsx h
* @jsxfrag null
*/
import {h} from "./snabbdom";
>h : Symbol(h, Decl(snabbdomy.tsx, 4, 8))

<><div></div></>
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>div : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))

=== tests/cases/conformance/jsx/inline/mix-n-match.tsx ===
/* @jsx h */
/* @jsxFrag Fragment */
import {h} from "./preact";
>h : Symbol(h, Decl(mix-n-match.tsx, 2, 8))

import {Fragment} from "./react";
>Fragment : Symbol(Fragment, Decl(mix-n-match.tsx, 3, 8))

<><span></span></>
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))
>span : Symbol(JSX.IntrinsicElements, Decl(react.d.ts, 1, 19))

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
=== tests/cases/conformance/jsx/inline/react.d.ts ===
declare global {
>global : any

namespace JSX {
interface IntrinsicElements {
[e: string]: any;
>e : string
}
}
}
export function createElement(): void;
>createElement : () => void

export function Fragment(): void;
>Fragment : () => void

=== tests/cases/conformance/jsx/inline/preact.d.ts ===
export function h(): void;
>h : () => void

export function Frag(): void;
>Frag : () => void

=== tests/cases/conformance/jsx/inline/snabbdom.d.ts ===
export function h(): void;
>h : () => void

=== tests/cases/conformance/jsx/inline/reacty.tsx ===
import {createElement, Fragment} from "./react";
>createElement : () => void
>Fragment : () => void

<><span></span></>
><><span></span></> : error
><span></span> : error
>span : any
>span : any

=== tests/cases/conformance/jsx/inline/preacty.tsx ===
/**
* @jsx h
* @jsxFrag Frag
*/
import {h, Frag} from "./preact";
>h : () => void
>Frag : () => void

<><div></div></>
><><div></div></> : error
><div></div> : error
>div : any
>div : any

=== tests/cases/conformance/jsx/inline/snabbdomy.tsx ===
/**
* @jsx h
* @jsxfrag null
*/
import {h} from "./snabbdom";
>h : () => void

<><div></div></>
><><div></div></> : error
><div></div> : error
>div : any
>div : any

=== tests/cases/conformance/jsx/inline/mix-n-match.tsx ===
/* @jsx h */
/* @jsxFrag Fragment */
import {h} from "./preact";
>h : () => void

import {Fragment} from "./react";
>Fragment : () => void

<><span></span></>
><><span></span></> : error
><span></span> : error
>span : any
>span : any

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
tests/cases/conformance/jsx/inline/index.tsx(3,1): error TS2304: Cannot find name 'React'.
tests/cases/conformance/jsx/inline/index.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.
tests/cases/conformance/jsx/inline/reacty.tsx(3,1): error TS17017: An @jsxFrag pragma is required when using an @jsx pragma with JSX fragments.

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

0 comments on commit df5a194

Please sign in to comment.