feature: Support whitelisting mutable props for react-constant-elements (#5307)

This commit is contained in:
Samuel Reed
2017-07-25 13:34:21 -05:00
committed by Brian Ng
parent 248743e6c5
commit e0b4543601
11 changed files with 166 additions and 2 deletions

View File

@@ -41,10 +41,12 @@ export default function({ types: t }) {
// We know the result; check its mutability.
const { value } = expressionResult;
const isMutable =
(value && typeof value === "object") ||
(!state.mutablePropsAllowed &&
(value && typeof value === "object")) ||
typeof value === "function";
if (!isMutable) {
// It evaluated to an immutable value, so we can hoist it.
path.skip();
return;
}
} else if (t.isIdentifier(expressionResult.deopt)) {
@@ -65,6 +67,29 @@ export default function({ types: t }) {
HOISTED.add(path.node);
const state = { isImmutable: true };
// This transform takes the option `allowMutablePropsOnTags`, which is an array
// of JSX tags to allow mutable props (such as objects, functions) on. Use sparingly
// and only on tags you know will never modify their own props.
if (this.opts.allowMutablePropsOnTags != null) {
if (!Array.isArray(this.opts.allowMutablePropsOnTags)) {
throw new Error(
".allowMutablePropsOnTags must be an array, null, or undefined.",
);
}
// Get the element's name. If it's a member expression, we use the last part of the path.
// So the option ["FormattedMessage"] would match "Intl.FormattedMessage".
let namePath = path.get("openingElement.name");
while (namePath.isJSXMemberExpression()) {
namePath = namePath.get("property");
}
const elementName = namePath.node.name;
state.mutablePropsAllowed =
this.opts.allowMutablePropsOnTags.indexOf(elementName) > -1;
}
// Traverse all props passed to this element for immutability.
path.traverse(immutabilityVisitor, state);
if (state.isImmutable) {