123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = createPlugin;
- var _pluginSyntaxJsx = require("@babel/plugin-syntax-jsx");
- var _helperPluginUtils = require("@babel/helper-plugin-utils");
- var _core = require("@babel/core");
- var _helperModuleImports = require("@babel/helper-module-imports");
- var _helperAnnotateAsPure = require("@babel/helper-annotate-as-pure");
- const DEFAULT = {
- importSource: "react",
- runtime: "automatic",
- pragma: "React.createElement",
- pragmaFrag: "React.Fragment"
- };
- const JSX_SOURCE_ANNOTATION_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/;
- const JSX_RUNTIME_ANNOTATION_REGEX = /\*?\s*@jsxRuntime\s+([^\s]+)/;
- const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
- const JSX_FRAG_ANNOTATION_REGEX = /\*?\s*@jsxFrag\s+([^\s]+)/;
- const get = (pass, name) => pass.get(`@babel/plugin-react-jsx/${name}`);
- const set = (pass, name, v) => pass.set(`@babel/plugin-react-jsx/${name}`, v);
- function createPlugin({
- name,
- development
- }) {
- return (0, _helperPluginUtils.declare)((api, options) => {
- const {
- pure: PURE_ANNOTATION,
- throwIfNamespace = true,
- filter,
- runtime: RUNTIME_DEFAULT = development ? "automatic" : "classic",
- importSource: IMPORT_SOURCE_DEFAULT = DEFAULT.importSource,
- pragma: PRAGMA_DEFAULT = DEFAULT.pragma,
- pragmaFrag: PRAGMA_FRAG_DEFAULT = DEFAULT.pragmaFrag
- } = options;
- {
- var {
- useSpread = false,
- useBuiltIns = false
- } = options;
- if (RUNTIME_DEFAULT === "classic") {
- if (typeof useSpread !== "boolean") {
- throw new Error("transform-react-jsx currently only accepts a boolean option for " + "useSpread (defaults to false)");
- }
- if (typeof useBuiltIns !== "boolean") {
- throw new Error("transform-react-jsx currently only accepts a boolean option for " + "useBuiltIns (defaults to false)");
- }
- if (useSpread && useBuiltIns) {
- throw new Error("transform-react-jsx currently only accepts useBuiltIns or useSpread " + "but not both");
- }
- }
- }
- const injectMetaPropertiesVisitor = {
- JSXOpeningElement(path, state) {
- for (const attr of path.get("attributes")) {
- if (!attr.isJSXElement()) continue;
- const {
- name
- } = attr.node.name;
- if (name === "__source" || name === "__self") {
- throw path.buildCodeFrameError(`__source and __self should not be defined in props and are reserved for internal usage.`);
- }
- }
- const self = _core.types.jsxAttribute(_core.types.jsxIdentifier("__self"), _core.types.jsxExpressionContainer(_core.types.thisExpression()));
- const source = _core.types.jsxAttribute(_core.types.jsxIdentifier("__source"), _core.types.jsxExpressionContainer(makeSource(path, state)));
- path.pushContainer("attributes", [self, source]);
- }
- };
- return {
- name,
- inherits: _pluginSyntaxJsx.default,
- visitor: {
- JSXNamespacedName(path) {
- if (throwIfNamespace) {
- throw path.buildCodeFrameError(`Namespace tags are not supported by default. React's JSX doesn't support namespace tags. \
- You can set \`throwIfNamespace: false\` to bypass this warning.`);
- }
- },
- JSXSpreadChild(path) {
- throw path.buildCodeFrameError("Spread children are not supported in React.");
- },
- Program: {
- enter(path, state) {
- const {
- file
- } = state;
- let runtime = RUNTIME_DEFAULT;
- let source = IMPORT_SOURCE_DEFAULT;
- let pragma = PRAGMA_DEFAULT;
- let pragmaFrag = PRAGMA_FRAG_DEFAULT;
- let sourceSet = !!options.importSource;
- let pragmaSet = !!options.pragma;
- let pragmaFragSet = !!options.pragmaFrag;
- if (file.ast.comments) {
- for (const comment of file.ast.comments) {
- const sourceMatches = JSX_SOURCE_ANNOTATION_REGEX.exec(comment.value);
- if (sourceMatches) {
- source = sourceMatches[1];
- sourceSet = true;
- }
- const runtimeMatches = JSX_RUNTIME_ANNOTATION_REGEX.exec(comment.value);
- if (runtimeMatches) {
- runtime = runtimeMatches[1];
- }
- const jsxMatches = JSX_ANNOTATION_REGEX.exec(comment.value);
- if (jsxMatches) {
- pragma = jsxMatches[1];
- pragmaSet = true;
- }
- const jsxFragMatches = JSX_FRAG_ANNOTATION_REGEX.exec(comment.value);
- if (jsxFragMatches) {
- pragmaFrag = jsxFragMatches[1];
- pragmaFragSet = true;
- }
- }
- }
- set(state, "runtime", runtime);
- if (runtime === "classic") {
- if (sourceSet) {
- throw path.buildCodeFrameError(`importSource cannot be set when runtime is classic.`);
- }
- const createElement = toMemberExpression(pragma);
- const fragment = toMemberExpression(pragmaFrag);
- set(state, "id/createElement", () => _core.types.cloneNode(createElement));
- set(state, "id/fragment", () => _core.types.cloneNode(fragment));
- set(state, "defaultPure", pragma === DEFAULT.pragma);
- } else if (runtime === "automatic") {
- if (pragmaSet || pragmaFragSet) {
- throw path.buildCodeFrameError(`pragma and pragmaFrag cannot be set when runtime is automatic.`);
- }
- const define = (name, id) => set(state, name, createImportLazily(state, path, id, source));
- define("id/jsx", development ? "jsxDEV" : "jsx");
- define("id/jsxs", development ? "jsxDEV" : "jsxs");
- define("id/createElement", "createElement");
- define("id/fragment", "Fragment");
- set(state, "defaultPure", source === DEFAULT.importSource);
- } else {
- throw path.buildCodeFrameError(`Runtime must be either "classic" or "automatic".`);
- }
- if (development) {
- path.traverse(injectMetaPropertiesVisitor, state);
- }
- }
- },
- JSXElement: {
- exit(path, file) {
- let callExpr;
- if (get(file, "runtime") === "classic" || shouldUseCreateElement(path)) {
- callExpr = buildCreateElementCall(path, file);
- } else {
- callExpr = buildJSXElementCall(path, file);
- }
- path.replaceWith(_core.types.inherits(callExpr, path.node));
- }
- },
- JSXFragment: {
- exit(path, file) {
- let callExpr;
- if (get(file, "runtime") === "classic") {
- callExpr = buildCreateElementFragmentCall(path, file);
- } else {
- callExpr = buildJSXFragmentCall(path, file);
- }
- path.replaceWith(_core.types.inherits(callExpr, path.node));
- }
- },
- JSXAttribute(path) {
- if (_core.types.isJSXElement(path.node.value)) {
- path.node.value = _core.types.jsxExpressionContainer(path.node.value);
- }
- }
- }
- };
- function call(pass, name, args) {
- const node = _core.types.callExpression(get(pass, `id/${name}`)(), args);
- if (PURE_ANNOTATION != null ? PURE_ANNOTATION : get(pass, "defaultPure")) (0, _helperAnnotateAsPure.default)(node);
- return node;
- }
- function shouldUseCreateElement(path) {
- const openingPath = path.get("openingElement");
- const attributes = openingPath.node.attributes;
- let seenPropsSpread = false;
- for (let i = 0; i < attributes.length; i++) {
- const attr = attributes[i];
- if (seenPropsSpread && _core.types.isJSXAttribute(attr) && attr.name.name === "key") {
- return true;
- } else if (_core.types.isJSXSpreadAttribute(attr)) {
- seenPropsSpread = true;
- }
- }
- return false;
- }
- function convertJSXIdentifier(node, parent) {
- if (_core.types.isJSXIdentifier(node)) {
- if (node.name === "this" && _core.types.isReferenced(node, parent)) {
- return _core.types.thisExpression();
- } else if (_core.types.isValidIdentifier(node.name, false)) {
- node.type = "Identifier";
- } else {
- return _core.types.stringLiteral(node.name);
- }
- } else if (_core.types.isJSXMemberExpression(node)) {
- return _core.types.memberExpression(convertJSXIdentifier(node.object, node), convertJSXIdentifier(node.property, node));
- } else if (_core.types.isJSXNamespacedName(node)) {
- return _core.types.stringLiteral(`${node.namespace.name}:${node.name.name}`);
- }
- return node;
- }
- function convertAttributeValue(node) {
- if (_core.types.isJSXExpressionContainer(node)) {
- return node.expression;
- } else {
- return node;
- }
- }
- function accumulateAttribute(array, attribute) {
- if (_core.types.isJSXSpreadAttribute(attribute.node)) {
- const arg = attribute.node.argument;
- if (_core.types.isObjectExpression(arg)) {
- array.push(...arg.properties);
- } else {
- array.push(_core.types.spreadElement(arg));
- }
- return array;
- }
- const value = convertAttributeValue(attribute.node.name.name !== "key" ? attribute.node.value || _core.types.booleanLiteral(true) : attribute.node.value);
- if (attribute.node.name.name === "key" && value === null) {
- throw attribute.buildCodeFrameError('Please provide an explicit key value. Using "key" as a shorthand for "key={true}" is not allowed.');
- }
- if (_core.types.isStringLiteral(value) && !_core.types.isJSXExpressionContainer(attribute.node.value)) {
- var _value$extra;
- value.value = value.value.replace(/\n\s+/g, " ");
- (_value$extra = value.extra) == null ? true : delete _value$extra.raw;
- }
- if (_core.types.isJSXNamespacedName(attribute.node.name)) {
- attribute.node.name = _core.types.stringLiteral(attribute.node.name.namespace.name + ":" + attribute.node.name.name.name);
- } else if (_core.types.isValidIdentifier(attribute.node.name.name, false)) {
- attribute.node.name.type = "Identifier";
- } else {
- attribute.node.name = _core.types.stringLiteral(attribute.node.name.name);
- }
- array.push(_core.types.inherits(_core.types.objectProperty(attribute.node.name, value), attribute.node));
- return array;
- }
- function buildChildrenProperty(children) {
- let childrenNode;
- if (children.length === 1) {
- childrenNode = children[0];
- } else if (children.length > 1) {
- childrenNode = _core.types.arrayExpression(children);
- } else {
- return undefined;
- }
- return _core.types.objectProperty(_core.types.identifier("children"), childrenNode);
- }
- function buildJSXElementCall(path, file) {
- const openingPath = path.get("openingElement");
- const args = [getTag(openingPath)];
- const attribsArray = [];
- const extracted = Object.create(null);
- for (const attr of openingPath.get("attributes")) {
- if (attr.isJSXAttribute() && _core.types.isJSXIdentifier(attr.node.name)) {
- const {
- name
- } = attr.node.name;
- switch (name) {
- case "__source":
- case "__self":
- if (extracted[name]) throw sourceSelfError(path, name);
- case "key":
- {
- const keyValue = convertAttributeValue(attr.node.value);
- if (keyValue === null) {
- throw attr.buildCodeFrameError('Please provide an explicit key value. Using "key" as a shorthand for "key={true}" is not allowed.');
- }
- extracted[name] = keyValue;
- break;
- }
- default:
- attribsArray.push(attr);
- }
- } else {
- attribsArray.push(attr);
- }
- }
- const children = _core.types.react.buildChildren(path.node);
- let attribs;
- if (attribsArray.length || children.length) {
- attribs = buildJSXOpeningElementAttributes(attribsArray, file, children);
- } else {
- attribs = _core.types.objectExpression([]);
- }
- args.push(attribs);
- if (development) {
- var _extracted$key, _extracted$__source, _extracted$__self;
- args.push((_extracted$key = extracted.key) != null ? _extracted$key : path.scope.buildUndefinedNode(), _core.types.booleanLiteral(children.length > 1), (_extracted$__source = extracted.__source) != null ? _extracted$__source : path.scope.buildUndefinedNode(), (_extracted$__self = extracted.__self) != null ? _extracted$__self : _core.types.thisExpression());
- } else if (extracted.key !== undefined) {
- args.push(extracted.key);
- }
- return call(file, children.length > 1 ? "jsxs" : "jsx", args);
- }
- function buildJSXOpeningElementAttributes(attribs, file, children) {
- const props = attribs.reduce(accumulateAttribute, []);
- if ((children == null ? void 0 : children.length) > 0) {
- props.push(buildChildrenProperty(children));
- }
- return _core.types.objectExpression(props);
- }
- function buildJSXFragmentCall(path, file) {
- const args = [get(file, "id/fragment")()];
- const children = _core.types.react.buildChildren(path.node);
- args.push(_core.types.objectExpression(children.length > 0 ? [buildChildrenProperty(children)] : []));
- if (development) {
- args.push(path.scope.buildUndefinedNode(), _core.types.booleanLiteral(children.length > 1));
- }
- return call(file, children.length > 1 ? "jsxs" : "jsx", args);
- }
- function buildCreateElementFragmentCall(path, file) {
- if (filter && !filter(path.node, file)) return;
- return call(file, "createElement", [get(file, "id/fragment")(), _core.types.nullLiteral(), ..._core.types.react.buildChildren(path.node)]);
- }
- function buildCreateElementCall(path, file) {
- const openingPath = path.get("openingElement");
- return call(file, "createElement", [getTag(openingPath), buildCreateElementOpeningElementAttributes(file, path, openingPath.get("attributes")), ..._core.types.react.buildChildren(path.node)]);
- }
- function getTag(openingPath) {
- const tagExpr = convertJSXIdentifier(openingPath.node.name, openingPath.node);
- let tagName;
- if (_core.types.isIdentifier(tagExpr)) {
- tagName = tagExpr.name;
- } else if (_core.types.isLiteral(tagExpr)) {
- tagName = tagExpr.value;
- }
- if (_core.types.react.isCompatTag(tagName)) {
- return _core.types.stringLiteral(tagName);
- } else {
- return tagExpr;
- }
- }
- function buildCreateElementOpeningElementAttributes(file, path, attribs) {
- const runtime = get(file, "runtime");
- {
- if (runtime !== "automatic") {
- const objs = [];
- const props = attribs.reduce(accumulateAttribute, []);
- if (!useSpread) {
- let start = 0;
- props.forEach((prop, i) => {
- if (_core.types.isSpreadElement(prop)) {
- if (i > start) {
- objs.push(_core.types.objectExpression(props.slice(start, i)));
- }
- objs.push(prop.argument);
- start = i + 1;
- }
- });
- if (props.length > start) {
- objs.push(_core.types.objectExpression(props.slice(start)));
- }
- } else if (props.length) {
- objs.push(_core.types.objectExpression(props));
- }
- if (!objs.length) {
- return _core.types.nullLiteral();
- }
- if (objs.length === 1) {
- return objs[0];
- }
- if (!_core.types.isObjectExpression(objs[0])) {
- objs.unshift(_core.types.objectExpression([]));
- }
- const helper = useBuiltIns ? _core.types.memberExpression(_core.types.identifier("Object"), _core.types.identifier("assign")) : file.addHelper("extends");
- return _core.types.callExpression(helper, objs);
- }
- }
- const props = [];
- const found = Object.create(null);
- for (const attr of attribs) {
- const name = _core.types.isJSXAttribute(attr) && _core.types.isJSXIdentifier(attr.name) && attr.name.name;
- if (runtime === "automatic" && (name === "__source" || name === "__self")) {
- if (found[name]) throw sourceSelfError(path, name);
- found[name] = true;
- }
- accumulateAttribute(props, attr);
- }
- return props.length === 1 && _core.types.isSpreadElement(props[0]) ? props[0].argument : props.length > 0 ? _core.types.objectExpression(props) : _core.types.nullLiteral();
- }
- });
- function getSource(source, importName) {
- switch (importName) {
- case "Fragment":
- return `${source}/${development ? "jsx-dev-runtime" : "jsx-runtime"}`;
- case "jsxDEV":
- return `${source}/jsx-dev-runtime`;
- case "jsx":
- case "jsxs":
- return `${source}/jsx-runtime`;
- case "createElement":
- return source;
- }
- }
- function createImportLazily(pass, path, importName, source) {
- return () => {
- const actualSource = getSource(source, importName);
- if ((0, _helperModuleImports.isModule)(path)) {
- let reference = get(pass, `imports/${importName}`);
- if (reference) return _core.types.cloneNode(reference);
- reference = (0, _helperModuleImports.addNamed)(path, importName, actualSource, {
- importedInterop: "uncompiled",
- importPosition: "after"
- });
- set(pass, `imports/${importName}`, reference);
- return reference;
- } else {
- let reference = get(pass, `requires/${actualSource}`);
- if (reference) {
- reference = _core.types.cloneNode(reference);
- } else {
- reference = (0, _helperModuleImports.addNamespace)(path, actualSource, {
- importedInterop: "uncompiled"
- });
- set(pass, `requires/${actualSource}`, reference);
- }
- return _core.types.memberExpression(reference, _core.types.identifier(importName));
- }
- };
- }
- }
- function toMemberExpression(id) {
- return id.split(".").map(name => _core.types.identifier(name)).reduce((object, property) => _core.types.memberExpression(object, property));
- }
- function makeSource(path, state) {
- const location = path.node.loc;
- if (!location) {
- return path.scope.buildUndefinedNode();
- }
- if (!state.fileNameIdentifier) {
- const {
- filename = ""
- } = state;
- const fileNameIdentifier = path.scope.generateUidIdentifier("_jsxFileName");
- const scope = path.hub.getScope();
- if (scope) {
- scope.push({
- id: fileNameIdentifier,
- init: _core.types.stringLiteral(filename)
- });
- }
- state.fileNameIdentifier = fileNameIdentifier;
- }
- return makeTrace(_core.types.cloneNode(state.fileNameIdentifier), location.start.line, location.start.column);
- }
- function makeTrace(fileNameIdentifier, lineNumber, column0Based) {
- const fileLineLiteral = lineNumber != null ? _core.types.numericLiteral(lineNumber) : _core.types.nullLiteral();
- const fileColumnLiteral = column0Based != null ? _core.types.numericLiteral(column0Based + 1) : _core.types.nullLiteral();
- const fileNameProperty = _core.types.objectProperty(_core.types.identifier("fileName"), fileNameIdentifier);
- const lineNumberProperty = _core.types.objectProperty(_core.types.identifier("lineNumber"), fileLineLiteral);
- const columnNumberProperty = _core.types.objectProperty(_core.types.identifier("columnNumber"), fileColumnLiteral);
- return _core.types.objectExpression([fileNameProperty, lineNumberProperty, columnNumberProperty]);
- }
- function sourceSelfError(path, name) {
- const pluginName = `transform-react-jsx-${name.slice(2)}`;
- return path.buildCodeFrameError(`Duplicate ${name} prop found. You are most likely using the deprecated ${pluginName} Babel plugin. Both __source and __self are automatically set when using the automatic runtime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.`);
- }
|