Add jsxPragmaFrag support to typescript transform (#11950)
This commit is contained in:
parent
94b5f92e39
commit
d0d1fdb921
@ -49,7 +49,8 @@ export default declare(
|
|||||||
(
|
(
|
||||||
api,
|
api,
|
||||||
{
|
{
|
||||||
jsxPragma = "React",
|
jsxPragma = "React.createElement",
|
||||||
|
jsxPragmaFrag = "React.Fragment",
|
||||||
allowNamespaces = false,
|
allowNamespaces = false,
|
||||||
allowDeclareFields = false,
|
allowDeclareFields = false,
|
||||||
onlyRemoveTypeImports = false,
|
onlyRemoveTypeImports = false,
|
||||||
@ -57,7 +58,7 @@ export default declare(
|
|||||||
) => {
|
) => {
|
||||||
api.assertVersion(7);
|
api.assertVersion(7);
|
||||||
|
|
||||||
const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
|
const JSX_PRAGMA_REGEX = /\*?\s*@jsx((?:Frag)?)\s+([^\s]+)/;
|
||||||
|
|
||||||
const classMemberVisitors = {
|
const classMemberVisitors = {
|
||||||
field(path) {
|
field(path) {
|
||||||
@ -168,6 +169,7 @@ export default declare(
|
|||||||
Program(path, state) {
|
Program(path, state) {
|
||||||
const { file } = state;
|
const { file } = state;
|
||||||
let fileJsxPragma = null;
|
let fileJsxPragma = null;
|
||||||
|
let fileJsxPragmaFrag = null;
|
||||||
|
|
||||||
if (!GLOBAL_TYPES.has(path.node)) {
|
if (!GLOBAL_TYPES.has(path.node)) {
|
||||||
GLOBAL_TYPES.set(path.node, new Set());
|
GLOBAL_TYPES.set(path.node, new Set());
|
||||||
@ -175,9 +177,14 @@ export default declare(
|
|||||||
|
|
||||||
if (file.ast.comments) {
|
if (file.ast.comments) {
|
||||||
for (const comment of (file.ast.comments: Array<Object>)) {
|
for (const comment of (file.ast.comments: Array<Object>)) {
|
||||||
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
const jsxMatches = JSX_PRAGMA_REGEX.exec(comment.value);
|
||||||
if (jsxMatches) {
|
if (jsxMatches) {
|
||||||
fileJsxPragma = jsxMatches[1];
|
if (jsxMatches[1]) {
|
||||||
|
// isFragment
|
||||||
|
fileJsxPragmaFrag = jsxMatches[2];
|
||||||
|
} else {
|
||||||
|
fileJsxPragma = jsxMatches[2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,6 +194,11 @@ export default declare(
|
|||||||
[pragmaImportName] = pragmaImportName.split(".");
|
[pragmaImportName] = pragmaImportName.split(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pragmaFragImportName = fileJsxPragmaFrag || jsxPragmaFrag;
|
||||||
|
if (pragmaFragImportName) {
|
||||||
|
[pragmaFragImportName] = pragmaFragImportName.split(".");
|
||||||
|
}
|
||||||
|
|
||||||
// remove type imports
|
// remove type imports
|
||||||
for (let stmt of path.get("body")) {
|
for (let stmt of path.get("body")) {
|
||||||
if (t.isImportDeclaration(stmt)) {
|
if (t.isImportDeclaration(stmt)) {
|
||||||
@ -221,7 +233,8 @@ export default declare(
|
|||||||
isImportTypeOnly({
|
isImportTypeOnly({
|
||||||
binding,
|
binding,
|
||||||
programPath: path,
|
programPath: path,
|
||||||
jsxPragma: pragmaImportName,
|
pragmaImportName,
|
||||||
|
pragmaFragImportName,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
importsToRemove.push(binding.path);
|
importsToRemove.push(binding.path);
|
||||||
@ -456,25 +469,31 @@ export default declare(
|
|||||||
// 'access' and 'readonly' are only for parameter properties, so constructor visitor will handle them.
|
// 'access' and 'readonly' are only for parameter properties, so constructor visitor will handle them.
|
||||||
}
|
}
|
||||||
|
|
||||||
function isImportTypeOnly({ binding, programPath, jsxPragma }) {
|
function isImportTypeOnly({
|
||||||
|
binding,
|
||||||
|
programPath,
|
||||||
|
pragmaImportName,
|
||||||
|
pragmaFragImportName,
|
||||||
|
}) {
|
||||||
for (const path of binding.referencePaths) {
|
for (const path of binding.referencePaths) {
|
||||||
if (!isInType(path)) {
|
if (!isInType(path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binding.identifier.name !== jsxPragma) {
|
if (
|
||||||
|
binding.identifier.name !== pragmaImportName &&
|
||||||
|
binding.identifier.name !== pragmaFragImportName
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "React" or the JSX pragma is referenced as a value if there are any JSX elements in the code.
|
// "React" or the JSX pragma is referenced as a value if there are any JSX elements/fragments in the code.
|
||||||
let sourceFileHasJsx = false;
|
let sourceFileHasJsx = false;
|
||||||
programPath.traverse({
|
programPath.traverse({
|
||||||
JSXElement() {
|
"JSXElement|JSXFragment"(path) {
|
||||||
sourceFileHasJsx = true;
|
|
||||||
},
|
|
||||||
JSXFragment() {
|
|
||||||
sourceFileHasJsx = true;
|
sourceFileHasJsx = true;
|
||||||
|
path.stop();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return !sourceFileHasJsx;
|
return !sourceFileHasJsx;
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
/* @jsxFrag jsx.htm */
|
||||||
|
// Don't elide htm if a JSX fragment appears somewhere.
|
||||||
|
import * as jsx from "fake-jsx-package";
|
||||||
|
<></>;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["transform-typescript", { "isTSX": true }]]
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
/* @jsxFrag jsx.htm */
|
||||||
|
// Don't elide htm if a JSX fragment appears somewhere.
|
||||||
|
import * as jsx from "fake-jsx-package";
|
||||||
|
<></>;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
/* @jsxFrag htm */
|
||||||
|
// Don't elide htm if a JSX fragment appears somewhere.
|
||||||
|
import { htm } from "fake-jsx-package";
|
||||||
|
<></>;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["transform-typescript", { "isTSX": true }]]
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
/* @jsxFrag htm */
|
||||||
|
// Don't elide htm if a JSX fragment appears somewhere.
|
||||||
|
import { htm } from "fake-jsx-package";
|
||||||
|
<></>;
|
||||||
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-preact-no-2/input.ts
vendored
Normal file
3
packages/babel-plugin-transform-typescript/test/fixtures/imports/elide-preact-no-2/input.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// Don't elide Preact if a JSX fragment appears somewhere.
|
||||||
|
import { Fragment, render } from "preact";
|
||||||
|
<></>;
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"transform-typescript",
|
||||||
|
{ "jsxPragma": "h", "jsxPragmaFrag": "Fragment", "isTSX": true }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
// Don't elide Preact if a JSX fragment appears somewhere.
|
||||||
|
import { Fragment } from "preact";
|
||||||
|
<></>;
|
||||||
@ -1,3 +1,4 @@
|
|||||||
// Don't elide Preact if a JSX element appears somewhere.
|
// Don't elide Preact if a JSX element appears somewhere.
|
||||||
import { h, render } from "preact";
|
import { h, Fragment, render } from "preact";
|
||||||
<div></div>;
|
<div></div>;
|
||||||
|
<></>;
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
{
|
{
|
||||||
"plugins": [["transform-typescript", { "jsxPragma": "h", "isTSX": true }]]
|
"plugins": [
|
||||||
|
[
|
||||||
|
"transform-typescript",
|
||||||
|
{ "jsxPragma": "h", "jsxPragmaFrag": "Fragment", "isTSX": true }
|
||||||
|
]
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
// Don't elide Preact if a JSX element appears somewhere.
|
// Don't elide Preact if a JSX element appears somewhere.
|
||||||
import { h } from "preact";
|
import { h, Fragment } from "preact";
|
||||||
<div></div>;
|
<div></div>;
|
||||||
|
<></>;
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
import { FooBar, h } from "preact";
|
import { FooBar, h, Fragment } from "preact";
|
||||||
const x: FooBar = 0;
|
const x: FooBar = 0;
|
||||||
|
|||||||
@ -9,12 +9,17 @@ export default declare(
|
|||||||
allowDeclareFields,
|
allowDeclareFields,
|
||||||
allowNamespaces,
|
allowNamespaces,
|
||||||
jsxPragma,
|
jsxPragma,
|
||||||
|
jsxPragmaFrag = "React.Fragment",
|
||||||
isTSX = false,
|
isTSX = false,
|
||||||
onlyRemoveTypeImports,
|
onlyRemoveTypeImports,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
api.assertVersion(7);
|
api.assertVersion(7);
|
||||||
|
|
||||||
|
if (typeof jsxPragmaFrag !== "string") {
|
||||||
|
throw new Error(".jsxPragmaFrag must be a string, or undefined");
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof allExtensions !== "boolean") {
|
if (typeof allExtensions !== "boolean") {
|
||||||
throw new Error(".allExtensions must be a boolean, or undefined");
|
throw new Error(".allExtensions must be a boolean, or undefined");
|
||||||
}
|
}
|
||||||
@ -32,6 +37,7 @@ export default declare(
|
|||||||
allowNamespaces,
|
allowNamespaces,
|
||||||
isTSX,
|
isTSX,
|
||||||
jsxPragma,
|
jsxPragma,
|
||||||
|
jsxPragmaFrag,
|
||||||
onlyRemoveTypeImports,
|
onlyRemoveTypeImports,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user