Skip to content

Commit

Permalink
Fix helper-builder-react-jsx compat with Babel 7.9 (#14886)
Browse files Browse the repository at this point in the history
* add test

* fix: build-react-jsx should pass PluginPass in post
  • Loading branch information
JLHwung committed Aug 27, 2022
1 parent cf0b1e7 commit cad4ea7
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 21 deletions.
1 change: 1 addition & 0 deletions packages/babel-helper-builder-react-jsx/package.json
Expand Up @@ -18,6 +18,7 @@
"@babel/types": "workspace:^"
},
"devDependencies": {
"@babel/core": "workspace:^",
"@babel/traverse": "workspace:^"
},
"engines": {
Expand Down
42 changes: 21 additions & 21 deletions packages/babel-helper-builder-react-jsx/src/index.ts
Expand Up @@ -24,7 +24,7 @@ import {
} from "@babel/types";
import annotateAsPure from "@babel/helper-annotate-as-pure";
import type { NodePath, Visitor } from "@babel/traverse";
import type { PluginPass, File } from "@babel/core";
import type { PluginPass } from "@babel/core";
import type * as t from "@babel/types";

type ElementState = {
Expand All @@ -37,9 +37,9 @@ type ElementState = {
};

export interface Options {
filter?: (node: t.Node, file: File) => boolean;
pre?: (state: ElementState, file: File) => void;
post?: (state: ElementState, file: File) => void;
filter?: (node: t.Node, pass: PluginPass) => boolean;
pre?: (state: ElementState, pass: PluginPass) => void;
post?: (state: ElementState, pass: PluginPass) => void;
compat?: boolean;
pure?: string;
throwIfNamespace?: boolean;
Expand All @@ -65,7 +65,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,

visitor.JSXElement = {
exit(path, state) {
const callExpr = buildElementCall(path, state.file);
const callExpr = buildElementCall(path, state);
if (callExpr) {
path.replaceWith(inherits(callExpr, path.node));
}
Expand All @@ -79,7 +79,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
"Fragment tags are only supported in React 16 and up.",
);
}
const callExpr = buildFragmentCall(path, state.file);
const callExpr = buildFragmentCall(path, state);
if (callExpr) {
path.replaceWith(inherits(callExpr, path.node));
}
Expand Down Expand Up @@ -164,8 +164,8 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
);
}

function buildElementCall(path: NodePath<t.JSXElement>, file: File) {
if (opts.filter && !opts.filter(path.node, file)) return;
function buildElementCall(path: NodePath<t.JSXElement>, pass: PluginPass) {
if (opts.filter && !opts.filter(path.node, pass)) return;

const openingPath = path.get("openingElement");
// @ts-expect-error mutating AST nodes
Expand All @@ -192,7 +192,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
};

if (opts.pre) {
opts.pre(state, file);
opts.pre(state, pass);
}

const attribs = openingPath.node.attributes;
Expand All @@ -201,7 +201,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
if (process.env.BABEL_8_BREAKING) {
convertedAttributes = objectExpression(attribs.map(convertAttribute));
} else {
convertedAttributes = buildOpeningElementAttributes(attribs, file);
convertedAttributes = buildOpeningElementAttributes(attribs, pass);
}
} else {
convertedAttributes = nullLiteral();
Expand All @@ -214,7 +214,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
);

if (opts.post) {
opts.post(state, file);
opts.post(state, pass);
}

const call = state.call || callExpression(state.callee, args);
Expand Down Expand Up @@ -242,20 +242,20 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,

function buildOpeningElementAttributes(
attribs: (t.JSXAttribute | t.JSXSpreadAttribute)[],
file: File,
pass: PluginPass,
): t.Expression {
let _props: (t.ObjectProperty | t.SpreadElement)[] = [];
const objs: t.Expression[] = [];

const { useSpread = false } = file.opts;
const { useSpread = false } = pass.opts;
if (typeof useSpread !== "boolean") {
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
"useSpread (defaults to false)",
);
}

const useBuiltIns = file.opts.useBuiltIns || false;
const useBuiltIns = pass.opts.useBuiltIns || false;
if (typeof useBuiltIns !== "boolean") {
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
Expand Down Expand Up @@ -299,7 +299,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,

const helper = useBuiltIns
? memberExpression(identifier("Object"), identifier("assign"))
: file.addHelper("extends");
: pass.addHelper("extends");

// spread it
convertedAttribs = callExpression(helper, objs);
Expand All @@ -308,15 +308,15 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
return convertedAttribs;
}

function buildFragmentCall(path: NodePath<t.JSXFragment>, file: File) {
if (opts.filter && !opts.filter(path.node, file)) return;
function buildFragmentCall(path: NodePath<t.JSXFragment>, pass: PluginPass) {
if (opts.filter && !opts.filter(path.node, pass)) return;

// @ts-expect-error mutating AST nodes
path.node.children = react.buildChildren(path.node);

const args: t.Expression[] = [];
const tagName: null = null;
const tagExpr = file.get("jsxFragIdentifier")();
const tagExpr = pass.get("jsxFragIdentifier")();

const state: ElementState = {
tagExpr: tagExpr,
Expand All @@ -326,7 +326,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
};

if (opts.pre) {
opts.pre(state, file);
opts.pre(state, pass);
}

// no attributes are allowed with <> syntax
Expand All @@ -337,10 +337,10 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
);

if (opts.post) {
opts.post(state, file);
opts.post(state, pass);
}

file.set("usedFragment", true);
pass.set("usedFragment", true);

const call = state.call || callExpression(state.callee, args);
if (state.pure) annotateAsPure(call);
Expand Down
72 changes: 72 additions & 0 deletions packages/babel-helper-builder-react-jsx/test/index.js
@@ -0,0 +1,72 @@
import _helper from "../lib/index.js";
import { transformSync } from "@babel/core";
import * as t from "@babel/types";

const helper = _helper.default || _helper;

describe("@babel/helper-builder-react-jsx", () => {
// The builder-react-jsx usage in transform-react-jsx 7.9.0
// https://github.com/babel/babel/blob/v7.9.0/packages/babel-plugin-transform-react-jsx/src/transform-classic.js#L43
it("shuold pass post with plugin pass", () => {
const fn = jest.fn().mockReturnValue(t.identifier("foo"));
const visitor = helper({
post(state, pass) {
state.callee = pass.get("jsxIdentifier")();
},
});
visitor.Program = function enter(_, state) {
state.set("jsxIdentifier", fn);
};
const plugin = () => ({ visitor });
const input = `<element></element>`;
transformSync(input, {
filename: "builder-react-jsx-test.jsx",
configFile: false,
plugins: [plugin],
parserOpts: { plugins: ["jsx"] },
});
expect(fn).toBeCalledTimes(1);
});

it("shuold pass pre with plugin pass", () => {
const fn = jest.fn().mockReturnValue(t.identifier("foo"));
const visitor = helper({
pre(state, pass) {
state.callee = pass.get("jsxIdentifier")();
},
});
visitor.Program = function enter(_, state) {
state.set("jsxIdentifier", fn);
};
const plugin = () => ({ visitor });
const input = `<element></element>`;
transformSync(input, {
filename: "builder-react-jsx-test.jsx",
configFile: false,
plugins: [plugin],
parserOpts: { plugins: ["jsx"] },
});
expect(fn).toBeCalledTimes(1);
});

it("shuold pass filter with plugin pass", () => {
const fn = jest.fn().mockReturnValue(false);
const visitor = helper({
filter(_, pass) {
return pass.get("filterAll")();
},
});
visitor.Program = function enter(_, state) {
state.set("filterAll", fn);
};
const plugin = () => ({ visitor });
const input = `<element></element>`;
transformSync(input, {
filename: "builder-react-jsx-test.jsx",
configFile: false,
plugins: [plugin],
parserOpts: { plugins: ["jsx"] },
});
expect(fn).toBeCalledTimes(1);
});
});
1 change: 1 addition & 0 deletions packages/babel-helper-builder-react-jsx/test/package.json
@@ -0,0 +1 @@
{ "type": "module" }
1 change: 1 addition & 0 deletions yarn.lock
Expand Up @@ -511,6 +511,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@babel/helper-builder-react-jsx@workspace:packages/babel-helper-builder-react-jsx"
dependencies:
"@babel/core": "workspace:^"
"@babel/helper-annotate-as-pure": "workspace:^"
"@babel/traverse": "workspace:^"
"@babel/types": "workspace:^"
Expand Down

0 comments on commit cad4ea7

Please sign in to comment.