mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Add full support for React.Children.map mock (#2519)
Summary: Release notes: none The `React.Children.map` mock was not fully finished and had side-effects. This fixes that and adds a test to show it properly working. Pull Request resolved: https://github.com/facebook/prepack/pull/2519 Differential Revision: D9614166 Pulled By: trueadm fbshipit-source-id: b646d13cc46f3747b07a111dc5bc9de295e25212
This commit is contained in:
parent
e0a90f82ba
commit
8f03c5f445
80
src/intrinsics/fb-www/react-mocks.js
vendored
80
src/intrinsics/fb-www/react-mocks.js
vendored
@ -17,13 +17,14 @@ import {
|
||||
AbstractValue,
|
||||
ECMAScriptSourceFunctionValue,
|
||||
FunctionValue,
|
||||
NativeFunctionValue,
|
||||
NullValue,
|
||||
NumberValue,
|
||||
ObjectValue,
|
||||
Value,
|
||||
} from "../../values/index.js";
|
||||
import { Environment } from "../../singletons.js";
|
||||
import { getReactSymbol } from "../../react/utils.js";
|
||||
import { createInternalReactElement, getReactSymbol } from "../../react/utils.js";
|
||||
import { cloneReactElement, createReactElement } from "../../react/elements.js";
|
||||
import { Properties, Create, To } from "../../singletons.js";
|
||||
import invariant from "../../invariant.js";
|
||||
@ -37,6 +38,7 @@ let reactCode = `
|
||||
REACT_FRAGMENT_TYPE,
|
||||
REACT_PORTAL_TYPE,
|
||||
REACT_FORWARD_REF_TYPE,
|
||||
ReactElement,
|
||||
ReactCurrentOwner
|
||||
) {
|
||||
function makeEmptyFunction(arg) {
|
||||
@ -123,30 +125,19 @@ let reactCode = `
|
||||
var SEPARATOR = '.';
|
||||
var SUBSEPARATOR = ':';
|
||||
var POOL_SIZE = 10;
|
||||
var traverseContextPool = [];
|
||||
function getPooledTraverseContext(
|
||||
mapResult,
|
||||
keyPrefix,
|
||||
mapFunction,
|
||||
mapContext,
|
||||
) {
|
||||
if (traverseContextPool.length) {
|
||||
const traverseContext = traverseContextPool.pop();
|
||||
traverseContext.result = mapResult;
|
||||
traverseContext.keyPrefix = keyPrefix;
|
||||
traverseContext.func = mapFunction;
|
||||
traverseContext.context = mapContext;
|
||||
traverseContext.count = 0;
|
||||
return traverseContext;
|
||||
} else {
|
||||
return {
|
||||
result: mapResult,
|
||||
keyPrefix: keyPrefix,
|
||||
func: mapFunction,
|
||||
context: mapContext,
|
||||
count: 0,
|
||||
};
|
||||
}
|
||||
return {
|
||||
result: mapResult,
|
||||
keyPrefix: keyPrefix,
|
||||
func: mapFunction,
|
||||
context: mapContext,
|
||||
count: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function releaseTraverseContext(traverseContext) {
|
||||
@ -155,9 +146,6 @@ let reactCode = `
|
||||
traverseContext.func = null;
|
||||
traverseContext.context = null;
|
||||
traverseContext.count = 0;
|
||||
if (traverseContextPool.length < POOL_SIZE) {
|
||||
traverseContextPool.push(traverseContext);
|
||||
}
|
||||
}
|
||||
|
||||
function traverseAllChildren(children, callback, traverseContext) {
|
||||
@ -268,6 +256,40 @@ let reactCode = `
|
||||
return subtreeCount;
|
||||
}
|
||||
|
||||
function cloneAndReplaceKey(oldElement, newKey) {
|
||||
var newElement = ReactElement(
|
||||
oldElement.type,
|
||||
newKey,
|
||||
oldElement.ref,
|
||||
oldElement.props,
|
||||
);
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
function mapSingleChildIntoContext(bookKeeping, child, childKey) {
|
||||
var {result, keyPrefix, func, context} = bookKeeping;
|
||||
|
||||
let mappedChild = func.call(context, child, bookKeeping.count++);
|
||||
if (Array.isArray(mappedChild)) {
|
||||
mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);
|
||||
} else if (mappedChild != null) {
|
||||
if (isValidElement(mappedChild)) {
|
||||
mappedChild = cloneAndReplaceKey(
|
||||
mappedChild,
|
||||
// Keep both the (mapped) and old keys if they differ, just as
|
||||
// traverseAllChildren used to do for objects as children
|
||||
keyPrefix +
|
||||
(mappedChild.key && (!child || child.key !== mappedChild.key)
|
||||
? escapeUserProvidedKey(mappedChild.key) + '/'
|
||||
: '') +
|
||||
childKey,
|
||||
);
|
||||
}
|
||||
result.push(mappedChild);
|
||||
}
|
||||
}
|
||||
|
||||
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
|
||||
var escapedPrefix = '';
|
||||
if (prefix != null) {
|
||||
@ -284,7 +306,7 @@ let reactCode = `
|
||||
}
|
||||
|
||||
function forEachSingleChild(bookKeeping, child, name) {
|
||||
const {func, context} = bookKeeping;
|
||||
var {func, context} = bookKeeping;
|
||||
func.call(context, child, bookKeeping.count++);
|
||||
}
|
||||
|
||||
@ -409,11 +431,23 @@ export function createMockReact(realm: Realm, reactRequireName: string): ObjectV
|
||||
let factory = reactFactory.$Call;
|
||||
invariant(factory !== undefined);
|
||||
|
||||
let mockReactElementBuilder = new NativeFunctionValue(
|
||||
realm,
|
||||
undefined,
|
||||
"ReactElement",
|
||||
0,
|
||||
(context, [type, key, ref, props]) => {
|
||||
invariant(props instanceof ObjectValue);
|
||||
return createInternalReactElement(realm, type, key, ref, props);
|
||||
}
|
||||
);
|
||||
|
||||
let reactValue = factory(realm.intrinsics.undefined, [
|
||||
getReactSymbol("react.element", realm),
|
||||
getReactSymbol("react.fragment", realm),
|
||||
getReactSymbol("react.portal", realm),
|
||||
getReactSymbol("react.forward_ref", realm),
|
||||
mockReactElementBuilder,
|
||||
currentOwner,
|
||||
]);
|
||||
invariant(reactValue instanceof ObjectValue);
|
||||
|
@ -136,6 +136,10 @@ it("Bound type 2", () => {
|
||||
runTest(__dirname + "/FunctionalComponents/bound-type2.js");
|
||||
});
|
||||
|
||||
it("React.Children.map", () => {
|
||||
runTest(__dirname + "/FunctionalComponents/react-children-map.js");
|
||||
});
|
||||
|
||||
it("Two roots", () => {
|
||||
runTest(__dirname + "/FunctionalComponents/two-roots.js");
|
||||
});
|
||||
|
26
test/react/FunctionalComponents/react-children-map.js
vendored
Normal file
26
test/react/FunctionalComponents/react-children-map.js
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
var React = require("react");
|
||||
|
||||
function Child(props) {
|
||||
return React.Children.map(props.children, function(child) {
|
||||
return <span>{child}</span>;
|
||||
});
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Child>{[1, 2, 3]}</Child>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
App.getTrials = function(renderer, Root) {
|
||||
renderer.update(<Root />);
|
||||
return [["simple conditions #3", renderer.toJSON()]];
|
||||
};
|
||||
|
||||
if (this.__optimizeReactComponentTree) {
|
||||
__optimizeReactComponentTree(App);
|
||||
}
|
||||
|
||||
module.exports = App;
|
@ -8944,6 +8944,102 @@ ReactStatistics {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React.Children.map: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 2,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "Child",
|
||||
"status": "INLINED",
|
||||
},
|
||||
],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 1,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React.Children.map: (JSX => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 2,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "Child",
|
||||
"status": "INLINED",
|
||||
},
|
||||
],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 1,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React.Children.map: (createElement => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 2,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "Child",
|
||||
"status": "INLINED",
|
||||
},
|
||||
],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 1,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React.Children.map: (createElement => createElement) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 2,
|
||||
"evaluatedRootNodes": Array [
|
||||
Object {
|
||||
"children": Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"message": "",
|
||||
"name": "Child",
|
||||
"status": "INLINED",
|
||||
},
|
||||
],
|
||||
"message": "",
|
||||
"name": "App",
|
||||
"status": "ROOT",
|
||||
},
|
||||
],
|
||||
"inlinedComponents": 1,
|
||||
"optimizedNestedClosures": 0,
|
||||
"optimizedTrees": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`React.cloneElement 2: (JSX => JSX) 1`] = `
|
||||
ReactStatistics {
|
||||
"componentsEvaluated": 1,
|
||||
|
Loading…
Reference in New Issue
Block a user