Setup JSX runtime even if the file doesn't contain JSX (#12479)

This commit is contained in:
Nicolò Ribaudo 2020-12-10 19:27:22 +01:00 committed by GitHub
parent e5b2680756
commit bf417186bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 130 deletions

View File

@ -138,136 +138,134 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
Program: { Program: {
enter(path, state) { enter(path, state) {
if (hasJSX(path)) { const { file } = state;
const { file } = state; let runtime = RUNTIME_DEFAULT;
let runtime = RUNTIME_DEFAULT;
// For jsx mode // For jsx mode
let source = IMPORT_SOURCE_DEFAULT; let source = IMPORT_SOURCE_DEFAULT;
let sourceSet = !!options.importSource; let sourceSet = !!options.importSource;
// For createElement mode // For createElement mode
let pragma = PRAGMA_DEFAULT; let pragma = PRAGMA_DEFAULT;
let pragmaFrag = PRAGMA_FRAG_DEFAULT; let pragmaFrag = PRAGMA_FRAG_DEFAULT;
let pragmaSet = !!options.pragma; let pragmaSet = !!options.pragma;
let pragmaFragSet = !!options.pragmaFrag; let pragmaFragSet = !!options.pragmaFrag;
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 sourceMatches = JSX_SOURCE_ANNOTATION_REGEX.exec( const sourceMatches = JSX_SOURCE_ANNOTATION_REGEX.exec(
comment.value, comment.value,
); );
if (sourceMatches) { if (sourceMatches) {
source = sourceMatches[1]; source = sourceMatches[1];
sourceSet = true; sourceSet = true;
} }
const runtimeMatches = JSX_RUNTIME_ANNOTATION_REGEX.exec( const runtimeMatches = JSX_RUNTIME_ANNOTATION_REGEX.exec(
comment.value, comment.value,
); );
if (runtimeMatches) { if (runtimeMatches) {
runtime = runtimeMatches[1]; runtime = runtimeMatches[1];
} }
const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value); const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
if (jsxMatches) { if (jsxMatches) {
pragma = jsxMatches[1]; pragma = jsxMatches[1];
pragmaSet = true; pragmaSet = true;
} }
const jsxFragMatches = JSX_FRAG_ANNOTATION_REGEX.exec( const jsxFragMatches = JSX_FRAG_ANNOTATION_REGEX.exec(
comment.value, comment.value,
); );
if (jsxFragMatches) { if (jsxFragMatches) {
pragmaFrag = jsxFragMatches[1]; pragmaFrag = jsxFragMatches[1];
pragmaFragSet = true; pragmaFragSet = true;
}
} }
} }
}
state.set("@babel/plugin-react-jsx/runtime", runtime); state.set("@babel/plugin-react-jsx/runtime", runtime);
if (runtime === "classic") { if (runtime === "classic") {
if (sourceSet) { if (sourceSet) {
throw path.buildCodeFrameError(
`importSource cannot be set when runtime is classic.`,
);
}
state.set(
"@babel/plugin-react-jsx/createElementIdentifier",
createIdentifierParser(pragma),
);
state.set(
"@babel/plugin-react-jsx/jsxFragIdentifier",
createIdentifierParser(pragmaFrag),
);
state.set("@babel/plugin-react-jsx/usedFragment", false);
state.set(
"@babel/plugin-react-jsx/pragmaSet",
pragma !== DEFAULT.pragma,
);
state.set(
"@babel/plugin-react-jsx/pragmaFragSet",
pragmaFrag !== DEFAULT.pragmaFrag,
);
} else if (runtime === "automatic") {
if (pragmaSet || pragmaFragSet) {
throw path.buildCodeFrameError(
`pragma and pragmaFrag cannot be set when runtime is automatic.`,
);
}
const importName = addAutoImports(path, {
...state.opts,
source,
});
state.set(
"@babel/plugin-react-jsx/jsxIdentifier",
createIdentifierParser(
createIdentifierName(
path,
options.development ? "jsxDEV" : "jsx",
importName,
),
),
);
state.set(
"@babel/plugin-react-jsx/jsxStaticIdentifier",
createIdentifierParser(
createIdentifierName(
path,
options.development ? "jsxDEV" : "jsxs",
importName,
),
),
);
state.set(
"@babel/plugin-react-jsx/createElementIdentifier",
createIdentifierParser(
createIdentifierName(path, "createElement", importName),
),
);
state.set(
"@babel/plugin-react-jsx/jsxFragIdentifier",
createIdentifierParser(
createIdentifierName(path, "Fragment", importName),
),
);
state.set(
"@babel/plugin-react-jsx/importSourceSet",
source !== DEFAULT.importSource,
);
} else {
throw path.buildCodeFrameError( throw path.buildCodeFrameError(
`Runtime must be either "classic" or "automatic".`, `importSource cannot be set when runtime is classic.`,
);
}
state.set(
"@babel/plugin-react-jsx/createElementIdentifier",
createIdentifierParser(pragma),
);
state.set(
"@babel/plugin-react-jsx/jsxFragIdentifier",
createIdentifierParser(pragmaFrag),
);
state.set("@babel/plugin-react-jsx/usedFragment", false);
state.set(
"@babel/plugin-react-jsx/pragmaSet",
pragma !== DEFAULT.pragma,
);
state.set(
"@babel/plugin-react-jsx/pragmaFragSet",
pragmaFrag !== DEFAULT.pragmaFrag,
);
} else if (runtime === "automatic") {
if (pragmaSet || pragmaFragSet) {
throw path.buildCodeFrameError(
`pragma and pragmaFrag cannot be set when runtime is automatic.`,
); );
} }
if (options.development) { const importName = addAutoImports(path, {
path.traverse(injectMetaPropertiesVisitor, state); ...state.opts,
} source,
});
state.set(
"@babel/plugin-react-jsx/jsxIdentifier",
createIdentifierParser(
createIdentifierName(
path,
options.development ? "jsxDEV" : "jsx",
importName,
),
),
);
state.set(
"@babel/plugin-react-jsx/jsxStaticIdentifier",
createIdentifierParser(
createIdentifierName(
path,
options.development ? "jsxDEV" : "jsxs",
importName,
),
),
);
state.set(
"@babel/plugin-react-jsx/createElementIdentifier",
createIdentifierParser(
createIdentifierName(path, "createElement", importName),
),
);
state.set(
"@babel/plugin-react-jsx/jsxFragIdentifier",
createIdentifierParser(
createIdentifierName(path, "Fragment", importName),
),
);
state.set(
"@babel/plugin-react-jsx/importSourceSet",
source !== DEFAULT.importSource,
);
} else {
throw path.buildCodeFrameError(
`Runtime must be either "classic" or "automatic".`,
);
}
if (options.development) {
path.traverse(injectMetaPropertiesVisitor, state);
} }
}, },
@ -353,18 +351,6 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
return imports; return imports;
} }
function hasJSX(parentPath) {
let fileHasJSX = false;
parentPath.traverse({
"JSXElement|JSXFragment"(path) {
fileHasJSX = true;
path.stop();
},
});
return fileHasJSX;
}
function getSource(source, importName) { function getSource(source, importName) {
switch (importName) { switch (importName) {
case "Fragment": case "Fragment":

View File

@ -0,0 +1,6 @@
{
"plugins": [
["transform-react-jsx", { "runtime": "automatic" }],
"./plugin.js"
]
}

View File

@ -0,0 +1 @@
const foo = /*#__PURE__*/undefined.jsx("p", {});

View File

@ -0,0 +1,13 @@
module.exports = ({ types: t }) => ({
visitor: {
NumericLiteral(path) {
path.replaceWith(
t.jsxElement(
t.jsxOpeningElement(t.jsxIdentifier("p"), []),
t.jsxClosingElement(t.jsxIdentifier("p")),
[]
)
);
}
}
});

View File

@ -0,0 +1 @@
const foo = 2;

View File

@ -0,0 +1,6 @@
{
"plugins": [
["transform-react-jsx", { "runtime": "classic" }],
"./plugin.js"
]
}

View File

@ -0,0 +1 @@
const foo = /*#__PURE__*/React.createElement("p", null);

View File

@ -0,0 +1,13 @@
module.exports = ({ types: t }) => ({
visitor: {
NumericLiteral(path) {
path.replaceWith(
t.jsxElement(
t.jsxOpeningElement(t.jsxIdentifier("p"), []),
t.jsxClosingElement(t.jsxIdentifier("p")),
[]
)
);
}
}
});