Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the correct this in __self for JSX elements in arrows #11288

Merged
merged 6 commits into from Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
144 changes: 75 additions & 69 deletions packages/babel-helper-builder-react-jsx-experimental/src/index.js
Expand Up @@ -31,6 +31,32 @@ export function helper(babel, options) {
pragmaFrag: PRAGMA_FRAG_DEFAULT = DEFAULT.pragmaFrag,
} = options;

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 source = t.jsxAttribute(
t.jsxIdentifier("__source"),
t.jsxExpressionContainer(makeSource(path, state)),
);
const self = t.jsxAttribute(
t.jsxIdentifier("__self"),
t.jsxExpressionContainer(t.thisExpression()),
);

path.pushContainer("attributes", [source, self]);
},
};

return {
JSXNamespacedName(path, state) {
const throwIfNamespace =
Expand Down Expand Up @@ -214,6 +240,10 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
`Runtime must be either "classic" or "automatic".`,
);
}

if (options.development) {
path.traverse(injectMetaPropertiesVisitor, state);
}
}
},

Expand Down Expand Up @@ -409,7 +439,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
}

function makeSource(path, state) {
const location = path.node.openingElement.loc;
const location = path.node.loc;
if (!location) {
// the element was generated and doesn't have location information
return;
Expand Down Expand Up @@ -532,33 +562,28 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
}

let attribs = [];
let key;
let source;
let self;
const extracted = Object.create(null);

// for React.jsx, key, __source (dev), and __self (dev) is passed in as
// a separate argument rather than in the args object. We go through the
// props and filter out these three keywords so we can pass them in
// as separate arguments later
for (let i = 0; i < openingPath.node.attributes.length; i++) {
const attr = openingPath.node.attributes[i];
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
if (attr.name.name === "key") {
key = convertAttribute(attr).value;
} else if (
attr.name.name === "__source" ||
attr.name.name === "__self"
) {
throw path.buildCodeFrameError(
`__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config.`,
);
} else {
// If someone is still using the __source and __self Babel plugins
// filter the results out
attribs.push(attr);
for (const attr of openingPath.get("attributes")) {
if (attr.isJSXAttribute() && t.isJSXIdentifier(attr.node.name)) {
const { name } = attr.node.name;
switch (name) {
case "__source":
case "__self":
if (extracted[name]) throw sourceSelfError(path, name);
/* falls through */
case "key":
extracted[name] = convertAttributeValue(attr.node.value);
break;
default:
attribs.push(attr.node);
}
} else {
attribs.push(attr);
attribs.push(attr.node);
}
}

Expand All @@ -576,20 +601,18 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
args.push(attribs);

if (!options.development) {
if (key !== undefined) {
args.push(key);
if (extracted.key !== undefined) {
args.push(extracted.key);
}
} else {
// isStaticChildren, __source, and __self are only used in development
// automatically include __source and __self in this plugin
// so we can eliminate the need for separate Babel plugins in Babel 8
source = makeSource(path, file);
self = t.thisExpression();
args.push(
key === undefined ? path.scope.buildUndefinedNode() : key,
extracted.key ?? path.scope.buildUndefinedNode(),
t.booleanLiteral(path.node.children.length > 1),
source ?? path.scope.buildUndefinedNode(),
self,
extracted.__source ?? path.scope.buildUndefinedNode(),
extracted.__self ?? t.thisExpression(),
);
}

Expand All @@ -611,16 +634,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
// Builds props for React.jsx. This function adds children into the props
// and ensures that props is always an object
function buildJSXOpeningElementAttributes(attribs, file, children) {
const _attribs = attribs.filter(
prop =>
!(
t.isJSXAttribute(prop) &&
prop.name &&
(prop.name.name === "__source" || prop.name.name === "__self")
),
);

const props = _attribs.map(convertAttribute);
const props = attribs.map(convertAttribute);

// In React.jsx, children is no longer a separate argument, but passed in
// through the argument object
Expand Down Expand Up @@ -774,7 +788,6 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
const attribs = buildCreateElementOpeningElementAttributes(
path,
openingPath.node.attributes,
file,
);

args.push(attribs, ...path.node.children);
Expand All @@ -796,40 +809,33 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
* breaking on spreads, we then push a new object containing
* all prior attributes to an array for later processing.
*/
function buildCreateElementOpeningElementAttributes(path, attribs, file) {
// We want source and self to be automatically included in the future
// so we will error when we see it

const hasSourceSelf = attribs.some(
prop =>
t.isJSXAttribute(prop) &&
prop.name &&
(prop.name.name === "__source" || prop.name.name === "__self"),
);
function buildCreateElementOpeningElementAttributes(path, attribs) {
const props = [];
const found = Object.create(null);

if (hasSourceSelf) {
throw path.buildCodeFrameError(
`__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config.`,
);
}
for (const attr of attribs) {
const name =
t.isJSXAttribute(attr) &&
t.isJSXIdentifier(attr.name) &&
attr.name.name;

if (options.development) {
attribs.push(
t.jsxAttribute(
t.jsxIdentifier("__source"),
t.jsxExpressionContainer(makeSource(path, file)),
),
);
attribs.push(
t.jsxAttribute(
t.jsxIdentifier("__self"),
t.jsxExpressionContainer(t.thisExpression()),
),
);
}
if (name === "__source" || name === "__self") {
if (found[name]) throw sourceSelfError(path, name);
found[name] = true;
if (!options.development) continue;
}

const props = attribs.map(convertAttribute);
props.push(convertAttribute(attr));
}

return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
}

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.`,
);
}
}
Expand Up @@ -5,5 +5,5 @@
"transform-react-jsx-self"
],
"os": ["linux", "darwin"],
"throws": "__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config."
"throws": "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self 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."
}
@@ -0,0 +1,7 @@
<div />;
() => <div />;

function fn() {
<div />;
() => <div />;
}
@@ -0,0 +1,38 @@
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";

var _jsxFileName = "<CWD>/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/self-inside-arrow/input.mjs",
_this = this;

/*#__PURE__*/
_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 1,
columnNumber: 1
}, this);

(function () {
return /*#__PURE__*/_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 2,
columnNumber: 7
}, _this);
});

function fn() {
var _this2 = this;

/*#__PURE__*/
_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 5,
columnNumber: 3
}, this);

(function () {
return /*#__PURE__*/_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 9
}, _this2);
});
}
Expand Up @@ -6,5 +6,5 @@
],
"sourceType": "module",
"os": ["linux", "darwin"],
"throws": "__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config."
"throws": "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self 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."
}
Expand Up @@ -4,5 +4,6 @@
"transform-react-jsx-source",
"transform-react-jsx-self"
],
"throws": "__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config."
"os": ["windows"],
"throws": "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self 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."
}
Expand Up @@ -2,7 +2,7 @@ var _reactJsxDevRuntime = require("react/jsx-dev-runtime");

var _jsxFileName = "C:\\Users\\travis\\build\\babel\\babel\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\handle-fragments-with-key-windows\\input.js";

var x = /*#__PURE__*/_reactJsxDevRuntime.jsxDEV(React.Fragment, {}, "foo", false, {
var x = /*#__PURE__*/_reactJsxDevRuntime.jsxDEV(React.Fragment, {}, 'foo', false, {
fileName: _jsxFileName,
lineNumber: 1,
columnNumber: 9
Expand Down
@@ -0,0 +1,7 @@
<div />;
() => <div />;

function fn() {
<div />;
() => <div />;
}
@@ -0,0 +1,38 @@
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";

var _jsxFileName = "C:\\Users\\travis\\build\\babel\\babel\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\self-inside-arrow-windows\\input.mjs",
_this = this;

/*#__PURE__*/
_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 1,
columnNumber: 1
}, this);

(function () {
return /*#__PURE__*/_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 2,
columnNumber: 7
}, _this);
});

function fn() {
var _this2 = this;

/*#__PURE__*/
_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 5,
columnNumber: 3
}, this);

(function () {
return /*#__PURE__*/_jsxDEV("div", {}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 9
}, _this2);
});
}
Expand Up @@ -6,5 +6,5 @@
],
"sourceType": "module",
"os": ["windows"],
"throws": "__source and __self should not be defined in props. You are most likely using the deprecated transform-react-jsx-self or transform-react-jsx-source Babel plugins. __source and __self will be set automatically in automatic runtime. Please remove transform-react-jsx-self or transform-react-jsx-source from your Babel config."
"throws": "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self 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."
}

This file was deleted.

This file was deleted.