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

Code before:
        value,
      );
      if (tempRef !== undefined) {
        return serializeTemporaryReference(request, tempRef);
      }
    }

    // Serialize the body of the function as an eval so it can be printed.
    // $FlowFixMe[method-unbinding]
    return serializeEval('(' + Function.prototype.toString.call(value) + ')');
  }

  if (typeof value === 'symbol') {
    const writtenSymbols = request.writtenSymbols;
    const existingId = writtenSymbols.get(value);
    if (existingId !== undefined) {
      return serializeByValueID(existingId);
    }
    // $FlowFixMe[incompatible-type] `description` might be undefined
    const name: string = value.description;
    // We use the Symbol.for version if it's not a global symbol. Close enough.
    request.pendingChunks++;
    const symbolId = request.nextChunkId++;
    emitSymbolChunk(request, symbolId, name);
    return serializeByValueID(symbolId);
  }

  if (typeof value === 'bigint') {
    return serializeBigInt(value);
  }

  if (value instanceof Date) {
    return serializeDate(value);
  }

  return 'unknown type ' + typeof value;
}

function outlineConsoleValue(
  request: Request,
  counter: {objectLimit: number},
  model: ReactClientValue,
): number {
  if (!__DEV__) {
    // These errors should never make it into a build so we don't need to encode them in codes.json
    // eslint-disable-next-line react-internal/prod-error-codes
    throw new Error(
      'outlineConsoleValue should never be called in production mode. This is a bug in React.',
    );
  }


Review comment (suggestion):
There's a problem with this set today that it's not safe to write into this from `renderConsoleValue` because `renderConsoleValue` has a different serialization logic (e.g. it can serialize functions like this and can cut off properties at a certain depth).

That's why we don't actually dedupe objects neither unless they also appear in the actual RSC payload elsewhere. Currently we only read from it and assume that if you're sending it across anyway, then whatever serialization happened in the production path is good enough also for the console value path.

We should really have a separate writtenObjects set just for the renderConsoleValue serialization.

Code after:
        value,
      );
      if (tempRef !== undefined) {
        return serializeTemporaryReference(request, tempRef);
      }
    }

    // Serialize the body of the function as an eval so it can be printed.
    const writtenObjects = request.writtenObjects;
    const existingReference = writtenObjects.get(value);
    if (existingReference !== undefined) {
      // We've already emitted this function, so we can
      // just refer to that by its existing reference.
      return existingReference;
    }

    const serializedValue = serializeEval(
      // $FlowFixMe[method-unbinding]
      '(' + Function.prototype.toString.call(value) + ')',
    );
    request.pendingChunks++;
    const id = request.nextChunkId++;
    const processedChunk = encodeReferenceChunk(request, id, serializedValue);
    request.completedRegularChunks.push(processedChunk);
    const reference = serializeByValueID(id);
    writtenObjects.set(value, reference);
    return reference;
  }

  if (typeof value === 'symbol') {
    const writtenSymbols = request.writtenSymbols;
    const existingId = writtenSymbols.get(value);
    if (existingId !== undefined) {
      return serializeByValueID(existingId);
    }
    // $FlowFixMe[incompatible-type] `description` might be undefined
    const name: string = value.description;
    // We use the Symbol.for version if it's not a global symbol. Close enough.
    request.pendingChunks++;
    const symbolId = request.nextChunkId++;
    emitSymbolChunk(request, symbolId, name);
    return serializeByValueID(symbolId);
  }

  if (typeof value === 'bigint') {
    return serializeBigInt(value);
  }

  if (value instanceof Date) {
    return serializeDate(value);
  }