babel-plugin-transform-react-create-element
Advanced tools
Comparing version 0.1.0 to 0.2.0
{ | ||
"name": "babel-plugin-transform-react-create-element", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Shorten JSX React.createElement calls using a local variable.", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -49,5 +49,5 @@ # babel-plugin-transform-react-create-element | ||
It works by inserting a JSX pragma that points to the local variable. Hence, it needs to run before any JSX compilers. If you're using `@babel/preset-react` everything will work out of the box. If you're using `@babel/plugin-transform-react-jsx` directly, make sure to list this plugin before it. | ||
It works by translating any found calls to `React.createElement` to use the newly inserted local variable instead. | ||
This plugin _does_ respect any existing JSX pragmas in the file and does not modify them. | ||
As such, it automatically respects any existing JSX pragmas in the file and does not interfer with their use. | ||
@@ -63,1 +63,3 @@ ## Why? | ||
MIT | ||
Loosely based on https://github.com/facebook/create-react-app/pull/6219. |
@@ -1,7 +0,11 @@ | ||
import { Visitor } from "@babel/core"; | ||
import * as t from "@babel/types"; | ||
declare const transform: () => { | ||
name: string; | ||
visitor: Visitor<{}>; | ||
visitor: { | ||
CallExpression(path: any, state: { | ||
localVariableIdent: t.Identifier; | ||
}): void; | ||
}; | ||
}; | ||
export default transform; | ||
//# sourceMappingURL=index.d.ts.map |
134
src/index.js
@@ -5,74 +5,76 @@ "use strict"; | ||
const template_1 = tslib_1.__importDefault(require("@babel/template")); | ||
const PRAGMA_ELEM_NAME = "createElement"; | ||
const LOCAL_VARIABLE_TEMPLATE = template_1.default(` | ||
const %%pragma%% = React.createElement; | ||
`); | ||
const PRAGMA_ELEM_NAME = "createElement"; | ||
const transform = () => { | ||
let createElementIdent; | ||
let hasInsertedJsxLocalVariable = false; | ||
let usesJsx = false; | ||
const checkUsesJsxVisitor = { | ||
JSX() { | ||
usesJsx = true; | ||
}, | ||
}; | ||
const insertingVisitor = { | ||
ImportDeclaration(path) { | ||
if (path.node.source.value !== "react" || hasInsertedJsxLocalVariable) { | ||
const %%pragma%% = /*#__PURE__*/ React.createElement; | ||
`, { | ||
preserveComments: true, | ||
}); | ||
const getReactImport = (path) => { | ||
const binding = path.scope.getBinding(path.node.name); | ||
if (!binding) { | ||
return null; | ||
} | ||
const bindingPath = binding.path; | ||
if (bindingPath.isImportDefaultSpecifier()) { | ||
const parentPath = bindingPath.parentPath; | ||
if (parentPath.isImportDeclaration() && | ||
parentPath.node.source.value === "react") { | ||
return bindingPath; | ||
} | ||
} | ||
else if (bindingPath.isVariableDeclarator()) { | ||
const init = bindingPath.get("init"); | ||
if (init.isCallExpression() && | ||
init.node.callee.isIdentifier() && | ||
init.node.callee.name === "require" && | ||
init.node.arguments.length === 1 && | ||
init.node.arguments[0].isStringLiteral() && | ||
init.node.arguments[0].value === "react") { | ||
return bindingPath; | ||
} | ||
} | ||
return null; | ||
}; | ||
const getCreateElementAndImport = (path) => { | ||
const callee = path.get("callee"); | ||
if (!callee.isMemberExpression()) { | ||
return null; | ||
} | ||
const property = callee.get("property"); | ||
if (!property.isIdentifier() || property.node.name !== "createElement") { | ||
return null; | ||
} | ||
const object = callee.get("object"); | ||
const reactImport = getReactImport(object); | ||
if (!reactImport) { | ||
return null; | ||
} | ||
return [callee, reactImport]; | ||
}; | ||
const insertLocalVariable = (importSite) => { | ||
const uniqueIdent = importSite.scope.generateUidIdentifier(PRAGMA_ELEM_NAME); | ||
const variableDeclaration = LOCAL_VARIABLE_TEMPLATE({ | ||
pragma: uniqueIdent, | ||
}); | ||
const [node] = importSite.parentPath.insertAfter(variableDeclaration); | ||
importSite.parentPath.scope.registerDeclaration(node); | ||
return uniqueIdent; | ||
}; | ||
const transform = () => ({ | ||
name: "transform-create-element", | ||
visitor: { | ||
CallExpression(path, state) { | ||
const data = getCreateElementAndImport(path); | ||
if (!data) { | ||
return; | ||
} | ||
const defaultImportSpec = path.node.specifiers.find((spec) => spec.type === "ImportDefaultSpecifier"); | ||
if (!defaultImportSpec) { | ||
return; | ||
const [callee, importSite] = data; | ||
if (!state.localVariableIdent) { | ||
state.localVariableIdent = insertLocalVariable(importSite); | ||
} | ||
const spec = defaultImportSpec; | ||
if (spec.local.name !== "React") { | ||
return; | ||
} | ||
path.insertAfter(LOCAL_VARIABLE_TEMPLATE({ pragma: createElementIdent })); | ||
hasInsertedJsxLocalVariable = true; | ||
callee.replaceWith(state.localVariableIdent); | ||
}, | ||
}; | ||
const programVisitor = { | ||
Program(path, { file }) { | ||
var _a; | ||
/* | ||
* Check if we already have an existing pragma in the source code and if so, | ||
* leave the file be. | ||
*/ | ||
const alreadyContainsJsxPragma = file.ast.comments.some((c) => c.value.indexOf("@jsx") !== -1); | ||
if (alreadyContainsJsxPragma) { | ||
return; | ||
} | ||
/* | ||
* Leave the file be if it doesn't use any JSX. | ||
*/ | ||
path.traverse(checkUsesJsxVisitor); | ||
if (!usesJsx) { | ||
return; | ||
} | ||
createElementIdent = path.scope.generateUidIdentifier(PRAGMA_ELEM_NAME); | ||
path.traverse(insertingVisitor); | ||
if (!hasInsertedJsxLocalVariable) { | ||
return; | ||
} | ||
const commentText = `* @jsx ${createElementIdent.name} `; | ||
path.addComment("leading", commentText); | ||
/* | ||
* Because babel doesn't reparse the source code, our new comment does not | ||
* show up in `file.ast.comments`, where @babel/plugin-transform-react-jsx | ||
* expects it. | ||
* | ||
* Hence add it manually. | ||
*/ | ||
const insertedCommentNode = (_a = path.node.leadingComments) === null || _a === void 0 ? void 0 : _a.find((c) => c.value === commentText); | ||
file.ast.comments.push(insertedCommentNode); | ||
}, | ||
}; | ||
return { | ||
name: "transform-react-imports", | ||
visitor: programVisitor, | ||
}; | ||
}; | ||
}, | ||
}); | ||
exports.default = transform; | ||
//# sourceMappingURL=index.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8817
88
64