Repository: facebook/react
File: packages/react-server/src/ReactFlightServer.js (JavaScript)

Code before:
  if (value[0] === '$') {
    // We need to escape $ prefixed strings since we use those to encode
    // references to IDs and as special symbol values.
    return '$' + value;
  } else {
    return value;
  }
}

let insideContextProps = null;
let isInsideContextValue = false;

export function resolveModelToJSON(
  request: Request,
  parent:
    | {+[key: string | number]: ReactClientValue}
    | $ReadOnlyArray<ReactClientValue>,
  key: string,
  value: ReactClientValue,
): ReactJSONValue {
  if (typeof value === 'string' && value[value.length - 1] === 'Z') {
    // Possibly a Date, whose toJSON automatically calls toISOString
    // $FlowFixMe[incompatible-use]
    const originalValue = parent[key];
    // $FlowFixMe[method-unbinding]
    if (Object.prototype.toString.call(originalValue) === '[object Date]') {
      return serializeDateFromDateJSON(value);
    }
  }

  if (__DEV__) {
    // $FlowFixMe[incompatible-use]
    const originalValue = parent[key];
    if (typeof originalValue === 'object' && originalValue !== value) {
      if (objectName(originalValue) !== 'Object') {
        const jsxParentType = jsxChildrenParents.get(parent);
        if (typeof jsxParentType === 'string') {
          console.error(
            '%s objects cannot be rendered as text children. Try formatting it using toString().%s',
            objectName(originalValue),
            describeObjectForErrorMessage(parent, key),
          );
        } else {
          console.error(
            'Only plain objects can be passed to Client Components from Server Components. ' +
              '%s objects are not supported.%s',
            objectName(originalValue),
            describeObjectForErrorMessage(parent, key),
          );
        }
      } else {

Review comment (suggestion):
Probably need to decide on how much we care about cross-realm vs perf and pick the same strategy for FormData and other future values. There will be quite a few. If we go with toString, it might be worth switching on the value.

We could also check isArray/instanceof first and only fallback to the toString for rarer objects.

Code after:
  } = {
    id: getServerReferenceId(request.bundlerConfig, serverReference),
    bound: bound ? Promise.resolve(bound) : null,
  };
  request.pendingChunks++;
  const metadataId = request.nextChunkId++;
  // We assume that this object doesn't suspend.
  const processedChunk = processModelChunk(
    request,
    metadataId,
    serverReferenceMetadata,
  );
  request.completedJSONChunks.push(processedChunk);
  writtenServerReferences.set(serverReference, metadataId);
  return serializeServerReferenceID(metadataId);
}

function escapeStringValue(value: string): string {
  if (value[0] === '$') {
    // We need to escape $ prefixed strings since we use those to encode
    // references to IDs and as special symbol values.
    return '$' + value;
  } else {
    return value;
  }
}

let insideContextProps = null;
let isInsideContextValue = false;

export function resolveModelToJSON(
  request: Request,
  parent:
    | {+[key: string | number]: ReactClientValue}
    | $ReadOnlyArray<ReactClientValue>,
  key: string,
  value: ReactClientValue,
): ReactJSONValue {
  // Make sure that `parent[key]` wasn't JSONified before `value` was passed to us
  if (__DEV__) {
    // $FlowFixMe[incompatible-use]
    const originalValue = parent[key];
    if (
      typeof originalValue === 'object' &&
      originalValue !== value &&
      !(originalValue instanceof Date)
    ) {
      if (objectName(originalValue) !== 'Object') {
        const jsxParentType = jsxChildrenParents.get(parent);
        if (typeof jsxParentType === 'string') {
          console.error(