mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add Diffs to Hydration Warnings (#28512)
Stacked on #28502.
This builds on the mechanism in #28502 by adding a diff of everything
we've collected so far to the thrown error or logged error.
This isn't actually a longest common subsequence diff. This means that
there are certain cases that can appear confusing such as a node being
added/removed when it really would've appeared later in the list. In
fact once a node mismatches, we abort rendering so we don't have the
context of what would've been rendered. It's not quite right to use the
result of the recovery render because it can use client-only code paths
using useSyncExternalStore which would yield false differences. That's
why diffing the HTML isn't quite right.
I also present abstract components in the stack, these are presented
with the client props and no diff since we don't have the props that
were on the server. The lack of difference might be confusing but it's
useful for context.
The main thing that's data new here is that we're adding some siblings
and props for context.
Examples in the [snapshot
commit](https://github.com/facebook/react/pull/28512/commits/e14532fd8df858a319d3eca687d83227209a498c).
DiffTrain build for [2ec2aaea98](https://github.com/facebook/react/commit/2ec2aaea98588178525f83495669e11e96815a00)
This commit is contained in:
@@ -1 +1 @@
|
||||
f7aa5e0aa3e2aa51279af4b6cb5413912cacd7f5
|
||||
2ec2aaea98588178525f83495669e11e96815a00
|
||||
|
||||
@@ -66,7 +66,7 @@ if (__DEV__) {
|
||||
return self;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-classic-6c991e9f";
|
||||
var ReactVersion = "19.0.0-www-classic-be0d91b4";
|
||||
|
||||
var LegacyRoot = 0;
|
||||
var ConcurrentRoot = 1;
|
||||
@@ -3719,8 +3719,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches
|
||||
@@ -3791,7 +4446,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
|
||||
@@ -66,7 +66,7 @@ if (__DEV__) {
|
||||
return self;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-modern-515161fd";
|
||||
var ReactVersion = "19.0.0-www-modern-71808898";
|
||||
|
||||
var LegacyRoot = 0;
|
||||
var ConcurrentRoot = 1;
|
||||
@@ -3484,8 +3484,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches
|
||||
@@ -3556,7 +4211,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
|
||||
@@ -8147,8 +8147,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// This may have been an insertion or a hydration.
|
||||
@@ -8165,7 +8820,7 @@ if (__DEV__) {
|
||||
var hydrationErrors = null;
|
||||
var rootOrSingletonContext = false; // Builds a common ancestor tree from the root down for collecting diffs.
|
||||
|
||||
function buildHydrationDiffNode(fiber) {
|
||||
function buildHydrationDiffNode(fiber, distanceFromLeaf) {
|
||||
if (fiber.return === null) {
|
||||
// We're at the root.
|
||||
if (hydrationDiffRootDEV === null) {
|
||||
@@ -8173,18 +8828,24 @@ if (__DEV__) {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
} else if (hydrationDiffRootDEV.fiber !== fiber) {
|
||||
throw new Error(
|
||||
"Saw multiple hydration diff roots in a pass. This is a bug in React."
|
||||
);
|
||||
} else if (hydrationDiffRootDEV.distanceFromLeaf > distanceFromLeaf) {
|
||||
hydrationDiffRootDEV.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return hydrationDiffRootDEV;
|
||||
}
|
||||
|
||||
var siblings = buildHydrationDiffNode(fiber.return).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
var siblings = buildHydrationDiffNode(
|
||||
fiber.return,
|
||||
distanceFromLeaf + 1
|
||||
).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
// and rerender if we suspend or terminate early, if a shared ancestor was added we should still
|
||||
// be inside of that shared ancestor which means it was the last one to be added. If this changes
|
||||
// we may have to scan the whole set.
|
||||
@@ -8193,14 +8854,21 @@ if (__DEV__) {
|
||||
siblings.length > 0 &&
|
||||
siblings[siblings.length - 1].fiber === fiber
|
||||
) {
|
||||
return siblings[siblings.length - 1];
|
||||
var existing = siblings[siblings.length - 1];
|
||||
|
||||
if (existing.distanceFromLeaf > distanceFromLeaf) {
|
||||
existing.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var newNode = {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
siblings.push(newNode);
|
||||
return newNode;
|
||||
@@ -8266,7 +8934,7 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function warnNonHydratedInstance(fiber) {
|
||||
function warnNonHydratedInstance(fiber, rejectedCandidate) {
|
||||
{
|
||||
if (didSuspendOrErrorDEV) {
|
||||
// Inside a boundary that already suspended. We're currently rendering the
|
||||
@@ -8275,13 +8943,19 @@ if (__DEV__) {
|
||||
return;
|
||||
} // Add this fiber to the diff tree.
|
||||
|
||||
var diffNode = buildHydrationDiffNode(fiber); // We use null as a signal that there was no node to match.
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0); // We use null as a signal that there was no node to match.
|
||||
|
||||
diffNode.serverProps = null;
|
||||
|
||||
if (rejectedCandidate !== null) {
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(rejectedCandidate);
|
||||
diffNode.serverTail.push(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryHydrateInstance(fiber, nextInstance) {
|
||||
function tryHydrateInstance(fiber, nextInstance, hostContext) {
|
||||
// fiber is a HostComponent Fiber
|
||||
var instance = canHydrateInstance(
|
||||
nextInstance,
|
||||
@@ -8292,6 +8966,23 @@ if (__DEV__) {
|
||||
|
||||
if (instance !== null) {
|
||||
fiber.stateNode = instance;
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
rootOrSingletonContext = false;
|
||||
@@ -8363,7 +9054,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
diff = describeDiff();
|
||||
diff = describeDiff(diffRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8398,6 +9089,23 @@ if (__DEV__) {
|
||||
currentHostContext,
|
||||
false
|
||||
));
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
currentHostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
rootOrSingletonContext = true;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
@@ -8417,9 +9125,12 @@ if (__DEV__) {
|
||||
);
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateInstance(fiber, nextInstance)) {
|
||||
if (
|
||||
!nextInstance ||
|
||||
!tryHydrateInstance(fiber, nextInstance, currentHostContext)
|
||||
) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8443,7 +9154,7 @@ if (__DEV__) {
|
||||
|
||||
if (!nextInstance || !tryHydrateText(fiber, nextInstance)) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8458,7 +9169,7 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateSuspense(fiber, nextInstance)) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
throwOnHydrationMismatch();
|
||||
}
|
||||
}
|
||||
@@ -8493,25 +9204,6 @@ if (__DEV__) {
|
||||
|
||||
function prepareToHydrateHostInstance(fiber, hostContext) {
|
||||
var instance = fiber.stateNode;
|
||||
|
||||
{
|
||||
var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV;
|
||||
|
||||
if (shouldWarnIfMismatchDev) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.memoizedProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var didHydrate = hydrateInstance(
|
||||
instance,
|
||||
fiber.type,
|
||||
@@ -8546,7 +9238,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (difference !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = difference;
|
||||
}
|
||||
}
|
||||
@@ -8568,7 +9260,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (_difference !== null) {
|
||||
var _diffNode = buildHydrationDiffNode(fiber);
|
||||
var _diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
|
||||
_diffNode.serverProps = _difference;
|
||||
}
|
||||
@@ -8704,11 +9396,18 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
while (nextInstance) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(nextInstance);
|
||||
diffNode.serverTail.push(description);
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
|
||||
if (description.type === "Suspense") {
|
||||
var suspenseInstance = nextInstance;
|
||||
nextInstance =
|
||||
getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
|
||||
} else {
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8749,7 +9448,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -35604,7 +36303,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-classic-257063d3";
|
||||
var ReactVersion = "19.0.0-www-classic-441ec386";
|
||||
|
||||
function createPortal$1(
|
||||
children,
|
||||
@@ -40284,7 +40983,7 @@ if (__DEV__) {
|
||||
) {
|
||||
{
|
||||
attributeNames.forEach(function (attributeName) {
|
||||
serverDifferences[attributeName] =
|
||||
serverDifferences[getPropNameFromAttributeName(attributeName)] =
|
||||
attributeName === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: domElement.getAttribute(attributeName);
|
||||
@@ -42123,13 +42822,27 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPropNameFromAttributeName(attrName) {
|
||||
switch (attrName) {
|
||||
case "class":
|
||||
return "className";
|
||||
|
||||
case "for":
|
||||
return "htmlFor";
|
||||
// TODO: The rest of the aliases.
|
||||
|
||||
default:
|
||||
return attrName;
|
||||
}
|
||||
}
|
||||
|
||||
function getPropsFromElement(domElement) {
|
||||
var serverDifferences = {};
|
||||
var attributes = domElement.attributes;
|
||||
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attr = attributes[i];
|
||||
serverDifferences[attr.name] =
|
||||
serverDifferences[getPropNameFromAttributeName(attr.name)] =
|
||||
attr.name.toLowerCase() === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: attr.value;
|
||||
|
||||
@@ -8109,8 +8109,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// This may have been an insertion or a hydration.
|
||||
@@ -8127,7 +8782,7 @@ if (__DEV__) {
|
||||
var hydrationErrors = null;
|
||||
var rootOrSingletonContext = false; // Builds a common ancestor tree from the root down for collecting diffs.
|
||||
|
||||
function buildHydrationDiffNode(fiber) {
|
||||
function buildHydrationDiffNode(fiber, distanceFromLeaf) {
|
||||
if (fiber.return === null) {
|
||||
// We're at the root.
|
||||
if (hydrationDiffRootDEV === null) {
|
||||
@@ -8135,18 +8790,24 @@ if (__DEV__) {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
} else if (hydrationDiffRootDEV.fiber !== fiber) {
|
||||
throw new Error(
|
||||
"Saw multiple hydration diff roots in a pass. This is a bug in React."
|
||||
);
|
||||
} else if (hydrationDiffRootDEV.distanceFromLeaf > distanceFromLeaf) {
|
||||
hydrationDiffRootDEV.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return hydrationDiffRootDEV;
|
||||
}
|
||||
|
||||
var siblings = buildHydrationDiffNode(fiber.return).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
var siblings = buildHydrationDiffNode(
|
||||
fiber.return,
|
||||
distanceFromLeaf + 1
|
||||
).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
// and rerender if we suspend or terminate early, if a shared ancestor was added we should still
|
||||
// be inside of that shared ancestor which means it was the last one to be added. If this changes
|
||||
// we may have to scan the whole set.
|
||||
@@ -8155,14 +8816,21 @@ if (__DEV__) {
|
||||
siblings.length > 0 &&
|
||||
siblings[siblings.length - 1].fiber === fiber
|
||||
) {
|
||||
return siblings[siblings.length - 1];
|
||||
var existing = siblings[siblings.length - 1];
|
||||
|
||||
if (existing.distanceFromLeaf > distanceFromLeaf) {
|
||||
existing.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var newNode = {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
siblings.push(newNode);
|
||||
return newNode;
|
||||
@@ -8228,7 +8896,7 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function warnNonHydratedInstance(fiber) {
|
||||
function warnNonHydratedInstance(fiber, rejectedCandidate) {
|
||||
{
|
||||
if (didSuspendOrErrorDEV) {
|
||||
// Inside a boundary that already suspended. We're currently rendering the
|
||||
@@ -8237,13 +8905,19 @@ if (__DEV__) {
|
||||
return;
|
||||
} // Add this fiber to the diff tree.
|
||||
|
||||
var diffNode = buildHydrationDiffNode(fiber); // We use null as a signal that there was no node to match.
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0); // We use null as a signal that there was no node to match.
|
||||
|
||||
diffNode.serverProps = null;
|
||||
|
||||
if (rejectedCandidate !== null) {
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(rejectedCandidate);
|
||||
diffNode.serverTail.push(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryHydrateInstance(fiber, nextInstance) {
|
||||
function tryHydrateInstance(fiber, nextInstance, hostContext) {
|
||||
// fiber is a HostComponent Fiber
|
||||
var instance = canHydrateInstance(
|
||||
nextInstance,
|
||||
@@ -8254,6 +8928,23 @@ if (__DEV__) {
|
||||
|
||||
if (instance !== null) {
|
||||
fiber.stateNode = instance;
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
rootOrSingletonContext = false;
|
||||
@@ -8325,7 +9016,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
diff = describeDiff();
|
||||
diff = describeDiff(diffRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8360,6 +9051,23 @@ if (__DEV__) {
|
||||
currentHostContext,
|
||||
false
|
||||
));
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
currentHostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
rootOrSingletonContext = true;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
@@ -8379,9 +9087,12 @@ if (__DEV__) {
|
||||
);
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateInstance(fiber, nextInstance)) {
|
||||
if (
|
||||
!nextInstance ||
|
||||
!tryHydrateInstance(fiber, nextInstance, currentHostContext)
|
||||
) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8405,7 +9116,7 @@ if (__DEV__) {
|
||||
|
||||
if (!nextInstance || !tryHydrateText(fiber, nextInstance)) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8420,7 +9131,7 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateSuspense(fiber, nextInstance)) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
throwOnHydrationMismatch();
|
||||
}
|
||||
}
|
||||
@@ -8455,25 +9166,6 @@ if (__DEV__) {
|
||||
|
||||
function prepareToHydrateHostInstance(fiber, hostContext) {
|
||||
var instance = fiber.stateNode;
|
||||
|
||||
{
|
||||
var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV;
|
||||
|
||||
if (shouldWarnIfMismatchDev) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.memoizedProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var didHydrate = hydrateInstance(
|
||||
instance,
|
||||
fiber.type,
|
||||
@@ -8508,7 +9200,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (difference !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = difference;
|
||||
}
|
||||
}
|
||||
@@ -8530,7 +9222,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (_difference !== null) {
|
||||
var _diffNode = buildHydrationDiffNode(fiber);
|
||||
var _diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
|
||||
_diffNode.serverProps = _difference;
|
||||
}
|
||||
@@ -8666,11 +9358,18 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
while (nextInstance) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(nextInstance);
|
||||
diffNode.serverTail.push(description);
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
|
||||
if (description.type === "Suspense") {
|
||||
var suspenseInstance = nextInstance;
|
||||
nextInstance =
|
||||
getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
|
||||
} else {
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8711,7 +9410,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -35451,7 +36150,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-modern-e485b93c";
|
||||
var ReactVersion = "19.0.0-www-modern-3cd5f1d2";
|
||||
|
||||
function createPortal$1(
|
||||
children,
|
||||
@@ -40937,7 +41636,7 @@ if (__DEV__) {
|
||||
) {
|
||||
{
|
||||
attributeNames.forEach(function (attributeName) {
|
||||
serverDifferences[attributeName] =
|
||||
serverDifferences[getPropNameFromAttributeName(attributeName)] =
|
||||
attributeName === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: domElement.getAttribute(attributeName);
|
||||
@@ -42773,13 +43472,27 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPropNameFromAttributeName(attrName) {
|
||||
switch (attrName) {
|
||||
case "class":
|
||||
return "className";
|
||||
|
||||
case "for":
|
||||
return "htmlFor";
|
||||
// TODO: The rest of the aliases.
|
||||
|
||||
default:
|
||||
return attrName;
|
||||
}
|
||||
}
|
||||
|
||||
function getPropsFromElement(domElement) {
|
||||
var serverDifferences = {};
|
||||
var attributes = domElement.attributes;
|
||||
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attr = attributes[i];
|
||||
serverDifferences[attr.name] =
|
||||
serverDifferences[getPropNameFromAttributeName(attr.name)] =
|
||||
attr.name.toLowerCase() === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: attr.value;
|
||||
|
||||
@@ -8284,8 +8284,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// This may have been an insertion or a hydration.
|
||||
@@ -8302,7 +8957,7 @@ if (__DEV__) {
|
||||
var hydrationErrors = null;
|
||||
var rootOrSingletonContext = false; // Builds a common ancestor tree from the root down for collecting diffs.
|
||||
|
||||
function buildHydrationDiffNode(fiber) {
|
||||
function buildHydrationDiffNode(fiber, distanceFromLeaf) {
|
||||
if (fiber.return === null) {
|
||||
// We're at the root.
|
||||
if (hydrationDiffRootDEV === null) {
|
||||
@@ -8310,18 +8965,24 @@ if (__DEV__) {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
} else if (hydrationDiffRootDEV.fiber !== fiber) {
|
||||
throw new Error(
|
||||
"Saw multiple hydration diff roots in a pass. This is a bug in React."
|
||||
);
|
||||
} else if (hydrationDiffRootDEV.distanceFromLeaf > distanceFromLeaf) {
|
||||
hydrationDiffRootDEV.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return hydrationDiffRootDEV;
|
||||
}
|
||||
|
||||
var siblings = buildHydrationDiffNode(fiber.return).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
var siblings = buildHydrationDiffNode(
|
||||
fiber.return,
|
||||
distanceFromLeaf + 1
|
||||
).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
// and rerender if we suspend or terminate early, if a shared ancestor was added we should still
|
||||
// be inside of that shared ancestor which means it was the last one to be added. If this changes
|
||||
// we may have to scan the whole set.
|
||||
@@ -8330,14 +8991,21 @@ if (__DEV__) {
|
||||
siblings.length > 0 &&
|
||||
siblings[siblings.length - 1].fiber === fiber
|
||||
) {
|
||||
return siblings[siblings.length - 1];
|
||||
var existing = siblings[siblings.length - 1];
|
||||
|
||||
if (existing.distanceFromLeaf > distanceFromLeaf) {
|
||||
existing.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var newNode = {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
siblings.push(newNode);
|
||||
return newNode;
|
||||
@@ -8403,7 +9071,7 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function warnNonHydratedInstance(fiber) {
|
||||
function warnNonHydratedInstance(fiber, rejectedCandidate) {
|
||||
{
|
||||
if (didSuspendOrErrorDEV) {
|
||||
// Inside a boundary that already suspended. We're currently rendering the
|
||||
@@ -8412,13 +9080,19 @@ if (__DEV__) {
|
||||
return;
|
||||
} // Add this fiber to the diff tree.
|
||||
|
||||
var diffNode = buildHydrationDiffNode(fiber); // We use null as a signal that there was no node to match.
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0); // We use null as a signal that there was no node to match.
|
||||
|
||||
diffNode.serverProps = null;
|
||||
|
||||
if (rejectedCandidate !== null) {
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(rejectedCandidate);
|
||||
diffNode.serverTail.push(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryHydrateInstance(fiber, nextInstance) {
|
||||
function tryHydrateInstance(fiber, nextInstance, hostContext) {
|
||||
// fiber is a HostComponent Fiber
|
||||
var instance = canHydrateInstance(
|
||||
nextInstance,
|
||||
@@ -8429,6 +9103,23 @@ if (__DEV__) {
|
||||
|
||||
if (instance !== null) {
|
||||
fiber.stateNode = instance;
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
rootOrSingletonContext = false;
|
||||
@@ -8500,7 +9191,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
diff = describeDiff();
|
||||
diff = describeDiff(diffRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8535,6 +9226,23 @@ if (__DEV__) {
|
||||
currentHostContext,
|
||||
false
|
||||
));
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
currentHostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
rootOrSingletonContext = true;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
@@ -8554,9 +9262,12 @@ if (__DEV__) {
|
||||
);
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateInstance(fiber, nextInstance)) {
|
||||
if (
|
||||
!nextInstance ||
|
||||
!tryHydrateInstance(fiber, nextInstance, currentHostContext)
|
||||
) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8580,7 +9291,7 @@ if (__DEV__) {
|
||||
|
||||
if (!nextInstance || !tryHydrateText(fiber, nextInstance)) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8595,7 +9306,7 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateSuspense(fiber, nextInstance)) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
throwOnHydrationMismatch();
|
||||
}
|
||||
}
|
||||
@@ -8630,25 +9341,6 @@ if (__DEV__) {
|
||||
|
||||
function prepareToHydrateHostInstance(fiber, hostContext) {
|
||||
var instance = fiber.stateNode;
|
||||
|
||||
{
|
||||
var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV;
|
||||
|
||||
if (shouldWarnIfMismatchDev) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.memoizedProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var didHydrate = hydrateInstance(
|
||||
instance,
|
||||
fiber.type,
|
||||
@@ -8683,7 +9375,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (difference !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = difference;
|
||||
}
|
||||
}
|
||||
@@ -8705,7 +9397,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (_difference !== null) {
|
||||
var _diffNode = buildHydrationDiffNode(fiber);
|
||||
var _diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
|
||||
_diffNode.serverProps = _difference;
|
||||
}
|
||||
@@ -8841,11 +9533,18 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
while (nextInstance) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(nextInstance);
|
||||
diffNode.serverTail.push(description);
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
|
||||
if (description.type === "Suspense") {
|
||||
var suspenseInstance = nextInstance;
|
||||
nextInstance =
|
||||
getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
|
||||
} else {
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8886,7 +9585,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -36228,7 +36927,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-classic-f6343974";
|
||||
var ReactVersion = "19.0.0-www-classic-009e5152";
|
||||
|
||||
function createPortal$1(
|
||||
children,
|
||||
@@ -40908,7 +41607,7 @@ if (__DEV__) {
|
||||
) {
|
||||
{
|
||||
attributeNames.forEach(function (attributeName) {
|
||||
serverDifferences[attributeName] =
|
||||
serverDifferences[getPropNameFromAttributeName(attributeName)] =
|
||||
attributeName === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: domElement.getAttribute(attributeName);
|
||||
@@ -42747,13 +43446,27 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPropNameFromAttributeName(attrName) {
|
||||
switch (attrName) {
|
||||
case "class":
|
||||
return "className";
|
||||
|
||||
case "for":
|
||||
return "htmlFor";
|
||||
// TODO: The rest of the aliases.
|
||||
|
||||
default:
|
||||
return attrName;
|
||||
}
|
||||
}
|
||||
|
||||
function getPropsFromElement(domElement) {
|
||||
var serverDifferences = {};
|
||||
var attributes = domElement.attributes;
|
||||
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attr = attributes[i];
|
||||
serverDifferences[attr.name] =
|
||||
serverDifferences[getPropNameFromAttributeName(attr.name)] =
|
||||
attr.name.toLowerCase() === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: attr.value;
|
||||
|
||||
@@ -8246,8 +8246,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// This may have been an insertion or a hydration.
|
||||
@@ -8264,7 +8919,7 @@ if (__DEV__) {
|
||||
var hydrationErrors = null;
|
||||
var rootOrSingletonContext = false; // Builds a common ancestor tree from the root down for collecting diffs.
|
||||
|
||||
function buildHydrationDiffNode(fiber) {
|
||||
function buildHydrationDiffNode(fiber, distanceFromLeaf) {
|
||||
if (fiber.return === null) {
|
||||
// We're at the root.
|
||||
if (hydrationDiffRootDEV === null) {
|
||||
@@ -8272,18 +8927,24 @@ if (__DEV__) {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
} else if (hydrationDiffRootDEV.fiber !== fiber) {
|
||||
throw new Error(
|
||||
"Saw multiple hydration diff roots in a pass. This is a bug in React."
|
||||
);
|
||||
} else if (hydrationDiffRootDEV.distanceFromLeaf > distanceFromLeaf) {
|
||||
hydrationDiffRootDEV.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return hydrationDiffRootDEV;
|
||||
}
|
||||
|
||||
var siblings = buildHydrationDiffNode(fiber.return).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
var siblings = buildHydrationDiffNode(
|
||||
fiber.return,
|
||||
distanceFromLeaf + 1
|
||||
).children; // The same node may already exist in the parent. Since we currently always render depth first
|
||||
// and rerender if we suspend or terminate early, if a shared ancestor was added we should still
|
||||
// be inside of that shared ancestor which means it was the last one to be added. If this changes
|
||||
// we may have to scan the whole set.
|
||||
@@ -8292,14 +8953,21 @@ if (__DEV__) {
|
||||
siblings.length > 0 &&
|
||||
siblings[siblings.length - 1].fiber === fiber
|
||||
) {
|
||||
return siblings[siblings.length - 1];
|
||||
var existing = siblings[siblings.length - 1];
|
||||
|
||||
if (existing.distanceFromLeaf > distanceFromLeaf) {
|
||||
existing.distanceFromLeaf = distanceFromLeaf;
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
var newNode = {
|
||||
fiber: fiber,
|
||||
children: [],
|
||||
serverProps: undefined,
|
||||
serverTail: []
|
||||
serverTail: [],
|
||||
distanceFromLeaf: distanceFromLeaf
|
||||
};
|
||||
siblings.push(newNode);
|
||||
return newNode;
|
||||
@@ -8365,7 +9033,7 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function warnNonHydratedInstance(fiber) {
|
||||
function warnNonHydratedInstance(fiber, rejectedCandidate) {
|
||||
{
|
||||
if (didSuspendOrErrorDEV) {
|
||||
// Inside a boundary that already suspended. We're currently rendering the
|
||||
@@ -8374,13 +9042,19 @@ if (__DEV__) {
|
||||
return;
|
||||
} // Add this fiber to the diff tree.
|
||||
|
||||
var diffNode = buildHydrationDiffNode(fiber); // We use null as a signal that there was no node to match.
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0); // We use null as a signal that there was no node to match.
|
||||
|
||||
diffNode.serverProps = null;
|
||||
|
||||
if (rejectedCandidate !== null) {
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(rejectedCandidate);
|
||||
diffNode.serverTail.push(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryHydrateInstance(fiber, nextInstance) {
|
||||
function tryHydrateInstance(fiber, nextInstance, hostContext) {
|
||||
// fiber is a HostComponent Fiber
|
||||
var instance = canHydrateInstance(
|
||||
nextInstance,
|
||||
@@ -8391,6 +9065,23 @@ if (__DEV__) {
|
||||
|
||||
if (instance !== null) {
|
||||
fiber.stateNode = instance;
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
rootOrSingletonContext = false;
|
||||
@@ -8462,7 +9153,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
diff = describeDiff();
|
||||
diff = describeDiff(diffRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8497,6 +9188,23 @@ if (__DEV__) {
|
||||
currentHostContext,
|
||||
false
|
||||
));
|
||||
|
||||
{
|
||||
if (!didSuspendOrErrorDEV) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.pendingProps,
|
||||
currentHostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hydrationParentFiber = fiber;
|
||||
rootOrSingletonContext = true;
|
||||
nextHydratableInstance = getFirstHydratableChild(instance);
|
||||
@@ -8516,9 +9224,12 @@ if (__DEV__) {
|
||||
);
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateInstance(fiber, nextInstance)) {
|
||||
if (
|
||||
!nextInstance ||
|
||||
!tryHydrateInstance(fiber, nextInstance, currentHostContext)
|
||||
) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8542,7 +9253,7 @@ if (__DEV__) {
|
||||
|
||||
if (!nextInstance || !tryHydrateText(fiber, nextInstance)) {
|
||||
if (shouldKeepWarning) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
}
|
||||
|
||||
throwOnHydrationMismatch();
|
||||
@@ -8557,7 +9268,7 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
if (!nextInstance || !tryHydrateSuspense(fiber, nextInstance)) {
|
||||
warnNonHydratedInstance(fiber);
|
||||
warnNonHydratedInstance(fiber, nextInstance);
|
||||
throwOnHydrationMismatch();
|
||||
}
|
||||
}
|
||||
@@ -8592,25 +9303,6 @@ if (__DEV__) {
|
||||
|
||||
function prepareToHydrateHostInstance(fiber, hostContext) {
|
||||
var instance = fiber.stateNode;
|
||||
|
||||
{
|
||||
var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV;
|
||||
|
||||
if (shouldWarnIfMismatchDev) {
|
||||
var differences = diffHydratedPropsForDevWarnings(
|
||||
instance,
|
||||
fiber.type,
|
||||
fiber.memoizedProps,
|
||||
hostContext
|
||||
);
|
||||
|
||||
if (differences !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
diffNode.serverProps = differences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var didHydrate = hydrateInstance(
|
||||
instance,
|
||||
fiber.type,
|
||||
@@ -8645,7 +9337,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (difference !== null) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
diffNode.serverProps = difference;
|
||||
}
|
||||
}
|
||||
@@ -8667,7 +9359,7 @@ if (__DEV__) {
|
||||
);
|
||||
|
||||
if (_difference !== null) {
|
||||
var _diffNode = buildHydrationDiffNode(fiber);
|
||||
var _diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
|
||||
_diffNode.serverProps = _difference;
|
||||
}
|
||||
@@ -8803,11 +9495,18 @@ if (__DEV__) {
|
||||
var nextInstance = nextHydratableInstance;
|
||||
|
||||
while (nextInstance) {
|
||||
var diffNode = buildHydrationDiffNode(fiber);
|
||||
var diffNode = buildHydrationDiffNode(fiber, 0);
|
||||
var description =
|
||||
describeHydratableInstanceForDevWarnings(nextInstance);
|
||||
diffNode.serverTail.push(description);
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
|
||||
if (description.type === "Suspense") {
|
||||
var suspenseInstance = nextInstance;
|
||||
nextInstance =
|
||||
getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
|
||||
} else {
|
||||
nextInstance = getNextHydratableSibling(nextInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8848,7 +9547,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -36075,7 +36774,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-modern-31c2f9f1";
|
||||
var ReactVersion = "19.0.0-www-modern-ee915528";
|
||||
|
||||
function createPortal$1(
|
||||
children,
|
||||
@@ -41561,7 +42260,7 @@ if (__DEV__) {
|
||||
) {
|
||||
{
|
||||
attributeNames.forEach(function (attributeName) {
|
||||
serverDifferences[attributeName] =
|
||||
serverDifferences[getPropNameFromAttributeName(attributeName)] =
|
||||
attributeName === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: domElement.getAttribute(attributeName);
|
||||
@@ -43397,13 +44096,27 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPropNameFromAttributeName(attrName) {
|
||||
switch (attrName) {
|
||||
case "class":
|
||||
return "className";
|
||||
|
||||
case "for":
|
||||
return "htmlFor";
|
||||
// TODO: The rest of the aliases.
|
||||
|
||||
default:
|
||||
return attrName;
|
||||
}
|
||||
}
|
||||
|
||||
function getPropsFromElement(domElement) {
|
||||
var serverDifferences = {};
|
||||
var attributes = domElement.attributes;
|
||||
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attr = attributes[i];
|
||||
serverDifferences[attr.name] =
|
||||
serverDifferences[getPropNameFromAttributeName(attr.name)] =
|
||||
attr.name.toLowerCase() === "style"
|
||||
? getStylesObjectFromElement(domElement)
|
||||
: attr.value;
|
||||
|
||||
@@ -2688,8 +2688,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches
|
||||
@@ -2760,7 +3415,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -26120,7 +26775,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-classic-52b71d6a";
|
||||
var ReactVersion = "19.0.0-www-classic-b112ab1e";
|
||||
|
||||
// Might add PROFILE later.
|
||||
|
||||
|
||||
@@ -2688,8 +2688,663 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
var maxRowLength = 120;
|
||||
var idealDepth = 15;
|
||||
|
||||
function findNotableNode(node, indent) {
|
||||
if (
|
||||
node.serverProps === undefined &&
|
||||
node.serverTail.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.distanceFromLeaf > 3 &&
|
||||
node.distanceFromLeaf > idealDepth - indent
|
||||
) {
|
||||
// This is not an interesting node for contextual purposes so we can skip it.
|
||||
var child = node.children[0];
|
||||
return findNotableNode(child, indent);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function indentation(indent) {
|
||||
return " " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function added(indent) {
|
||||
return "+ " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function removed(indent) {
|
||||
return "- " + " ".repeat(indent);
|
||||
}
|
||||
|
||||
function describeFiberType(fiber) {
|
||||
switch (fiber.tag) {
|
||||
case HostHoistable:
|
||||
case HostSingleton:
|
||||
case HostComponent:
|
||||
return fiber.type;
|
||||
|
||||
case LazyComponent:
|
||||
return "Lazy";
|
||||
|
||||
case SuspenseComponent:
|
||||
return "Suspense";
|
||||
|
||||
case SuspenseListComponent:
|
||||
return "SuspenseList";
|
||||
|
||||
case FunctionComponent:
|
||||
case IndeterminateComponent:
|
||||
case SimpleMemoComponent:
|
||||
var fn = fiber.type;
|
||||
return fn.displayName || fn.name || null;
|
||||
|
||||
case ForwardRef:
|
||||
var render = fiber.type.render;
|
||||
return render.displayName || render.name || null;
|
||||
|
||||
case ClassComponent:
|
||||
var ctr = fiber.type;
|
||||
return ctr.displayName || ctr.name || null;
|
||||
|
||||
default:
|
||||
// Skip
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var needsEscaping = /["'&<>\n\t]/;
|
||||
|
||||
function describeTextNode(content, maxLength) {
|
||||
if (needsEscaping.test(content)) {
|
||||
var encoded = JSON.stringify(content);
|
||||
|
||||
if (encoded.length > maxLength - 2) {
|
||||
if (maxLength < 8) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded.slice(0, maxLength - 7) + '..."}';
|
||||
}
|
||||
|
||||
return "{" + encoded + "}";
|
||||
} else {
|
||||
if (content.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '{"..."}';
|
||||
}
|
||||
|
||||
return content.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function describeTextDiff(clientText, serverProps, indent) {
|
||||
var maxLength = maxRowLength - indent * 2;
|
||||
|
||||
if (serverProps === null) {
|
||||
return added(indent) + describeTextNode(clientText, maxLength) + "\n";
|
||||
} else if (typeof serverProps === "string") {
|
||||
var serverText = serverProps;
|
||||
var firstDiff = 0;
|
||||
|
||||
for (
|
||||
;
|
||||
firstDiff < serverText.length && firstDiff < clientText.length;
|
||||
firstDiff++
|
||||
) {
|
||||
if (
|
||||
serverText.charCodeAt(firstDiff) !==
|
||||
clientText.charCodeAt(firstDiff)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstDiff > maxLength - 8 && firstDiff > 10) {
|
||||
// The first difference between the two strings would be cut off, so cut off in
|
||||
// the beginning instead.
|
||||
clientText = "..." + clientText.slice(firstDiff - 8);
|
||||
serverText = "..." + serverText.slice(firstDiff - 8);
|
||||
}
|
||||
|
||||
return (
|
||||
added(indent) +
|
||||
describeTextNode(clientText, maxLength) +
|
||||
"\n" +
|
||||
removed(indent) +
|
||||
describeTextNode(serverText, maxLength) +
|
||||
"\n"
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
indentation(indent) + describeTextNode(clientText, maxLength) + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function objectName(object) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
var name = Object.prototype.toString.call(object);
|
||||
return name.replace(/^\[object (.*)\]$/, function (m, p0) {
|
||||
return p0;
|
||||
});
|
||||
}
|
||||
|
||||
function describeValue(value, maxLength) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
var encoded = JSON.stringify(value);
|
||||
|
||||
if (encoded.length > maxLength) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return encoded.slice(0, maxLength - 4) + '..."';
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
if (value.$$typeof === REACT_ELEMENT_TYPE) {
|
||||
var type = getComponentNameFromType(value.type);
|
||||
return type ? "<" + type + ">" : "<...>";
|
||||
}
|
||||
|
||||
var name = objectName(value);
|
||||
|
||||
if (name === "Object") {
|
||||
var properties = "";
|
||||
maxLength -= 2;
|
||||
|
||||
for (var propName in value) {
|
||||
if (!value.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var jsonPropName = JSON.stringify(propName);
|
||||
|
||||
if (jsonPropName !== '"' + propName + '"') {
|
||||
propName = jsonPropName;
|
||||
}
|
||||
|
||||
maxLength -= propName.length - 2;
|
||||
var propValue = describeValue(
|
||||
value[propName],
|
||||
maxLength < 15 ? maxLength : 15
|
||||
);
|
||||
maxLength -= propValue.length;
|
||||
|
||||
if (maxLength < 0) {
|
||||
properties += properties === "" ? "..." : ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
properties +=
|
||||
(properties === "" ? "" : ",") + propName + ":" + propValue;
|
||||
}
|
||||
|
||||
return "{" + properties + "}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
case "function": {
|
||||
var _name = value.displayName || value.name;
|
||||
|
||||
return _name ? "function " + _name : "function";
|
||||
}
|
||||
|
||||
default:
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropValue(value, maxLength) {
|
||||
if (typeof value === "string" && !needsEscaping.test(value)) {
|
||||
if (value.length > maxLength - 2) {
|
||||
if (maxLength < 5) {
|
||||
return '"..."';
|
||||
}
|
||||
|
||||
return '"' + value.slice(0, maxLength - 5) + '..."';
|
||||
}
|
||||
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return "{" + describeValue(value, maxLength - 2) + "}";
|
||||
}
|
||||
|
||||
function describeCollapsedElement(type, props, indent) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var maxLength = maxRowLength - indent * 2 - type.length - 2;
|
||||
var content = "";
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var propValue = describePropValue(props[propName], 15);
|
||||
maxLength -= propName.length + propValue.length + 2;
|
||||
|
||||
if (maxLength < 0) {
|
||||
content += " ...";
|
||||
break;
|
||||
}
|
||||
|
||||
content += " " + propName + "=" + propValue;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + content + ">\n";
|
||||
}
|
||||
|
||||
function describeExpandedElement(type, props, rowPrefix) {
|
||||
// This function tries to fit the props into a single line for non-essential elements.
|
||||
// We also ignore children because we're not going deeper.
|
||||
var remainingRowLength = maxRowLength - rowPrefix.length - type.length; // We add the properties to a set so we can choose later whether we'll put it on one
|
||||
// line or multiple lines.
|
||||
|
||||
var properties = [];
|
||||
|
||||
for (var propName in props) {
|
||||
if (!props.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propName === "children") {
|
||||
// Ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - rowPrefix.length - propName.length - 1;
|
||||
var propValue = describePropValue(props[propName], maxLength);
|
||||
remainingRowLength -= propName.length + propValue.length + 2;
|
||||
properties.push(propName + "=" + propValue);
|
||||
}
|
||||
|
||||
if (properties.length === 0) {
|
||||
return rowPrefix + "<" + type + ">\n";
|
||||
} else if (remainingRowLength > 0) {
|
||||
// We can fit all on one row.
|
||||
return rowPrefix + "<" + type + " " + properties.join(" ") + ">\n";
|
||||
} else {
|
||||
// Split into one row per property:
|
||||
return (
|
||||
rowPrefix +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
" " +
|
||||
properties.join("\n" + rowPrefix + " ") +
|
||||
"\n" +
|
||||
rowPrefix +
|
||||
">\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function describePropertiesDiff(clientObject, serverObject, indent) {
|
||||
var properties = "";
|
||||
var remainingServerProperties = assign({}, serverObject);
|
||||
|
||||
for (var propName in clientObject) {
|
||||
if (!clientObject.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete remainingServerProperties[propName];
|
||||
var maxLength = maxRowLength - indent * 2 - propName.length - 2;
|
||||
var clientValue = clientObject[propName];
|
||||
var clientPropValue = describeValue(clientValue, maxLength);
|
||||
|
||||
if (serverObject.hasOwnProperty(propName)) {
|
||||
var serverValue = serverObject[propName];
|
||||
var serverPropValue = describeValue(serverValue, maxLength);
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
properties +=
|
||||
removed(indent) + propName + ": " + serverPropValue + "\n";
|
||||
} else {
|
||||
properties +=
|
||||
added(indent) + propName + ": " + clientPropValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (var _propName in remainingServerProperties) {
|
||||
if (!remainingServerProperties.hasOwnProperty(_propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var _maxLength = maxRowLength - indent * 2 - _propName.length - 2;
|
||||
|
||||
var _serverValue = remainingServerProperties[_propName];
|
||||
|
||||
var _serverPropValue = describeValue(_serverValue, _maxLength);
|
||||
|
||||
properties +=
|
||||
removed(indent) + _propName + ": " + _serverPropValue + "\n";
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function describeElementDiff(type, clientProps, serverProps, indent) {
|
||||
var content = ""; // Maps any previously unmatched lower case server prop name to its full prop name
|
||||
|
||||
var serverPropNames = new Map();
|
||||
|
||||
for (var propName in serverProps) {
|
||||
if (!serverProps.hasOwnProperty(propName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
serverPropNames.set(propName.toLowerCase(), propName);
|
||||
}
|
||||
|
||||
if (serverPropNames.size === 1 && serverPropNames.has("children")) {
|
||||
content += describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
indentation(indent)
|
||||
);
|
||||
} else {
|
||||
for (var _propName2 in clientProps) {
|
||||
if (!clientProps.hasOwnProperty(_propName2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_propName2 === "children") {
|
||||
// Handled below.
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxLength =
|
||||
maxRowLength - (indent + 1) * 2 - _propName2.length - 1;
|
||||
var serverPropName = serverPropNames.get(_propName2.toLowerCase());
|
||||
|
||||
if (serverPropName !== undefined) {
|
||||
serverPropNames.delete(_propName2.toLowerCase()); // There's a diff here.
|
||||
|
||||
var clientValue = clientProps[_propName2];
|
||||
var serverValue = serverProps[serverPropName];
|
||||
var clientPropValue = describePropValue(clientValue, maxLength);
|
||||
var serverPropValue = describePropValue(serverValue, maxLength);
|
||||
|
||||
if (
|
||||
typeof clientValue === "object" &&
|
||||
clientValue !== null &&
|
||||
typeof serverValue === "object" &&
|
||||
serverValue !== null &&
|
||||
objectName(clientValue) === "Object" &&
|
||||
objectName(serverValue) === "Object" && // Only do the diff if the object has a lot of keys or was shortened.
|
||||
(Object.keys(clientValue).length > 2 ||
|
||||
Object.keys(serverValue).length > 2 ||
|
||||
clientPropValue.indexOf("...") > -1 ||
|
||||
serverPropValue.indexOf("...") > -1)
|
||||
) {
|
||||
// We're comparing two plain objects. We can diff the nested objects instead.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"={{\n" +
|
||||
describePropertiesDiff(clientValue, serverValue, indent + 2) +
|
||||
indentation(indent + 1) +
|
||||
"}}\n";
|
||||
} else {
|
||||
content +=
|
||||
added(indent + 1) + _propName2 + "=" + clientPropValue + "\n";
|
||||
content +=
|
||||
removed(indent + 1) + _propName2 + "=" + serverPropValue + "\n";
|
||||
}
|
||||
} else {
|
||||
// Considered equal.
|
||||
content +=
|
||||
indentation(indent + 1) +
|
||||
_propName2 +
|
||||
"=" +
|
||||
describePropValue(clientProps[_propName2], maxLength) +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
serverPropNames.forEach(function (propName) {
|
||||
if (propName === "children") {
|
||||
// Handled below.
|
||||
return;
|
||||
}
|
||||
|
||||
var maxLength = maxRowLength - (indent + 1) * 2 - propName.length - 1;
|
||||
content +=
|
||||
removed(indent + 1) +
|
||||
propName +
|
||||
"=" +
|
||||
describePropValue(serverProps[propName], maxLength) +
|
||||
"\n";
|
||||
});
|
||||
|
||||
if (content === "") {
|
||||
// No properties
|
||||
content = indentation(indent) + "<" + type + ">\n";
|
||||
} else {
|
||||
// Had properties
|
||||
content =
|
||||
indentation(indent) +
|
||||
"<" +
|
||||
type +
|
||||
"\n" +
|
||||
content +
|
||||
indentation(indent) +
|
||||
">\n";
|
||||
}
|
||||
}
|
||||
|
||||
var serverChildren = serverProps.children;
|
||||
var clientChildren = clientProps.children;
|
||||
|
||||
if (
|
||||
typeof serverChildren === "string" ||
|
||||
typeof serverChildren === "number" ||
|
||||
typeof serverChildren === "bigint"
|
||||
) {
|
||||
// There's a diff of the children.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
var serverText = "" + serverChildren;
|
||||
var clientText = "";
|
||||
|
||||
if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
clientText = "" + clientChildren;
|
||||
}
|
||||
|
||||
content += describeTextDiff(clientText, serverText, indent + 1);
|
||||
} else if (
|
||||
typeof clientChildren === "string" ||
|
||||
typeof clientChildren === "number" ||
|
||||
typeof clientChildren === "bigint"
|
||||
) {
|
||||
// The client has children but it's not considered a difference from the server.
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
content += describeTextDiff("" + clientChildren, undefined, indent + 1);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
function describeSiblingFiber(fiber, indent) {
|
||||
var type = describeFiberType(fiber);
|
||||
|
||||
if (type === null) {
|
||||
// Skip this type of fiber. We currently treat this as a fragment
|
||||
// so it's just part of the parent's children.
|
||||
var flatContent = "";
|
||||
var childFiber = fiber.child;
|
||||
|
||||
while (childFiber) {
|
||||
flatContent += describeSiblingFiber(childFiber, indent);
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
return flatContent;
|
||||
}
|
||||
|
||||
return indentation(indent) + "<" + type + ">" + "\n";
|
||||
}
|
||||
|
||||
function describeNode(node, indent) {
|
||||
var skipToNode = findNotableNode(node, indent);
|
||||
|
||||
if (
|
||||
skipToNode !== node &&
|
||||
(node.children.length !== 1 || node.children[0] !== skipToNode)
|
||||
) {
|
||||
return (
|
||||
indentation(indent) + "...\n" + describeNode(skipToNode, indent + 1)
|
||||
);
|
||||
} // Prefix with any server components for context
|
||||
|
||||
var parentContent = "";
|
||||
var debugInfo = node.fiber._debugInfo;
|
||||
|
||||
if (debugInfo) {
|
||||
for (var i = 0; i < debugInfo.length; i++) {
|
||||
var serverComponentName = debugInfo[i].name;
|
||||
|
||||
if (typeof serverComponentName === "string") {
|
||||
parentContent +=
|
||||
indentation(indent) + "<" + serverComponentName + ">" + "\n";
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Self
|
||||
|
||||
var selfContent = ""; // We use the pending props since we might be generating a diff before the complete phase
|
||||
// when something throws.
|
||||
|
||||
var clientProps = node.fiber.pendingProps;
|
||||
|
||||
if (node.fiber.tag === HostText) {
|
||||
// Text Node
|
||||
selfContent = describeTextDiff(clientProps, node.serverProps, indent);
|
||||
} else {
|
||||
var type = describeFiberType(node.fiber);
|
||||
|
||||
if (type !== null) {
|
||||
// Element Node
|
||||
if (node.serverProps === undefined) {
|
||||
// Just a reference node for context.
|
||||
selfContent = describeCollapsedElement(type, clientProps, indent);
|
||||
indent++;
|
||||
} else if (node.serverProps === null) {
|
||||
selfContent = describeExpandedElement(
|
||||
type,
|
||||
clientProps,
|
||||
added(indent)
|
||||
); // If this was an insertion we won't step down further. Any tail
|
||||
// are considered siblings so we don't indent.
|
||||
// TODO: Model this a little better.
|
||||
} else if (typeof node.serverProps === "string") {
|
||||
{
|
||||
error(
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
selfContent = describeElementDiff(
|
||||
type,
|
||||
clientProps,
|
||||
node.serverProps,
|
||||
indent
|
||||
);
|
||||
indent++;
|
||||
}
|
||||
}
|
||||
} // Compute children
|
||||
|
||||
var childContent = "";
|
||||
var childFiber = node.fiber.child;
|
||||
var diffIdx = 0;
|
||||
|
||||
while (childFiber && diffIdx < node.children.length) {
|
||||
var childNode = node.children[diffIdx];
|
||||
|
||||
if (childNode.fiber === childFiber) {
|
||||
// This was a match in the diff.
|
||||
childContent += describeNode(childNode, indent);
|
||||
diffIdx++;
|
||||
} else {
|
||||
// This is an unrelated previous sibling.
|
||||
childContent += describeSiblingFiber(childFiber, indent);
|
||||
}
|
||||
|
||||
childFiber = childFiber.sibling;
|
||||
}
|
||||
|
||||
if (childFiber && node.children.length > 0) {
|
||||
// If we had any further siblings after the last mismatch, we can't be sure if it's
|
||||
// actually a valid match since it might not have found a match. So we exclude next
|
||||
// siblings to avoid confusion.
|
||||
childContent += indentation(indent) + "..." + "\n";
|
||||
} // Deleted tail nodes
|
||||
|
||||
var serverTail = node.serverTail;
|
||||
|
||||
for (var _i = 0; _i < serverTail.length; _i++) {
|
||||
var tailNode = serverTail[_i];
|
||||
|
||||
if (typeof tailNode === "string") {
|
||||
// Removed text node
|
||||
childContent +=
|
||||
removed(indent) +
|
||||
describeTextNode(tailNode, maxRowLength - indent * 2) +
|
||||
"\n";
|
||||
} else {
|
||||
// Removed element
|
||||
childContent += describeExpandedElement(
|
||||
tailNode.type,
|
||||
tailNode.props,
|
||||
removed(indent)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return parentContent + selfContent + childContent;
|
||||
}
|
||||
|
||||
function describeDiff(rootNode) {
|
||||
return "\n";
|
||||
try {
|
||||
return "\n\n" + describeNode(rootNode, 0);
|
||||
} catch (x) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches
|
||||
@@ -2760,7 +3415,7 @@ if (__DEV__) {
|
||||
|
||||
if (diffRoot !== null) {
|
||||
hydrationDiffRootDEV = null;
|
||||
var diff = describeDiff();
|
||||
var diff = describeDiff(diffRoot);
|
||||
|
||||
error(
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. " +
|
||||
@@ -26120,7 +26775,7 @@ if (__DEV__) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var ReactVersion = "19.0.0-www-modern-52b71d6a";
|
||||
var ReactVersion = "19.0.0-www-modern-b112ab1e";
|
||||
|
||||
// Might add PROFILE later.
|
||||
|
||||
|
||||
@@ -267,6 +267,7 @@ export default [
|
||||
"Select elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled select element and remove one of these props. More info: https://react.dev/link/controlled-components",
|
||||
"Setting defaultProps as an instance property on %s is not supported and will be ignored. Instead, define defaultProps as a static property on %s.",
|
||||
"Should have found matching lanes. This is a bug in React.",
|
||||
"Should not have matched a non HostText fiber to a Text node. This is a bug in React.",
|
||||
"State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().",
|
||||
"String refs are no longer supported.",
|
||||
"Style property values shouldn't contain a semicolon. Try \"%s: %s\" instead.",
|
||||
|
||||
Reference in New Issue
Block a user