Skip to content

Commit

Permalink
[Flight] Add support BigInt support (#26479)
Browse files Browse the repository at this point in the history
## Summary

Adds support for sending `BigInt` to Flight and Flight Reply

## How did you test this change?

- added tests
  • Loading branch information
eps1lon authored Mar 29, 2023
1 parent 85de6fd commit fd0511c
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ module.exports = {
$ReadOnlyArray: 'readonly',
$Shape: 'readonly',
AnimationFrameID: 'readonly',
// For Flow type annotation. Only `BigInt` is valid at runtime.
bigint: 'readonly',
BigInt: 'readonly',
Class: 'readonly',
ClientRect: 'readonly',
CopyInspectedElementPath: 'readonly',
Expand Down
4 changes: 4 additions & 0 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,10 @@ export function parseModelString(
// Special encoding for `undefined` which can't be serialized as JSON otherwise.
return undefined;
}
case 'n': {
// BigInt
return BigInt(value.substring(2));
}
default: {
// We assume that anything else is a reference ID.
const id = parseInt(value.substring(1), 16);
Expand Down
8 changes: 5 additions & 3 deletions packages/react-client/src/ReactFlightReplyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ function serializeUndefined(): string {
return '$undefined';
}

function serializeBigInt(n: bigint): string {
return '$n' + n.toString(10);
}

function escapeStringValue(value: string): string {
if (value[0] === '$') {
// We need to escape $ prefixed strings since we use those to encode
Expand Down Expand Up @@ -264,9 +268,7 @@ export function processReply(
}

if (typeof value === 'bigint') {
throw new Error(
`BigInt (${value}) is not yet supported as an argument to a Server Function.`,
);
return serializeBigInt(value);
}

throw new Error(
Expand Down
19 changes: 19 additions & 0 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,25 @@ describe('ReactFlight', () => {
expect(ReactNoop).toMatchRenderedOutput(null);
});

it('can transport BigInt', async () => {
function ComponentClient({prop}) {
return `prop: ${prop} (${typeof prop})`;
}
const Component = clientReference(ComponentClient);

const model = <Component prop={90071992547409910000n} />;

const transport = ReactNoopFlightServer.render(model);

await act(async () => {
ReactNoop.render(await ReactNoopFlightClient.read(transport));
});

expect(ReactNoop).toMatchRenderedOutput(
'prop: 90071992547409910000 (bigint)',
);
});

it('can render a lazy component as a shared component on the server', async () => {
function SharedComponent({text}) {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ describe('ReactFlightDOMReply', () => {
}
expect(items).toEqual(['A', 'B', 'C']);
});

it('can pass a BigInt as a reply', async () => {
const body = await ReactServerDOMClient.encodeReply(90071992547409910000n);
const n = await ReactServerDOMServer.decodeReply(body, webpackServerMap);

expect(n).toEqual(90071992547409910000n);
});
});
4 changes: 4 additions & 0 deletions packages/react-server/src/ReactFlightReplyServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ function parseModelString(
// Special encoding for `undefined` which can't be serialized as JSON otherwise.
return undefined;
}
case 'n': {
// BigInt
return BigInt(value.substring(2));
}
default: {
// We assume that anything else is a reference ID.
const id = parseInt(value.substring(1), 16);
Expand Down
9 changes: 5 additions & 4 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ function serializeUndefined(): string {
return '$undefined';
}

function serializeBigInt(n: bigint): string {
return '$n' + n.toString(10);
}

function serializeClientReference(
request: Request,
parent:
Expand Down Expand Up @@ -931,10 +935,7 @@ export function resolveModelToJSON(
}

if (typeof value === 'bigint') {
throw new Error(
`BigInt (${value}) is not yet supported in Client Component props.` +
describeObjectForErrorMessage(parent, key),
);
return serializeBigInt(value);
}

throw new Error(
Expand Down
1 change: 1 addition & 0 deletions scripts/rollup/validate/eslintrc.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
},
globals: {
// ES 6
BigInt: 'readonly',
Map: 'readonly',
Set: 'readonly',
Proxy: 'readonly',
Expand Down
1 change: 1 addition & 0 deletions scripts/rollup/validate/eslintrc.fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
},
globals: {
// ES6
BigInt: 'readonly',
Map: 'readonly',
Set: 'readonly',
Symbol: 'readonly',
Expand Down
1 change: 1 addition & 0 deletions scripts/rollup/validate/eslintrc.rn.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
},
globals: {
// ES6
BigInt: 'readonly',
Map: 'readonly',
Set: 'readonly',
Symbol: 'readonly',
Expand Down
1 change: 1 addition & 0 deletions scripts/rollup/validate/eslintrc.umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
},
globals: {
// ES6
BigInt: 'readonly',
Map: 'readonly',
Set: 'readonly',
Symbol: 'readonly',
Expand Down

0 comments on commit fd0511c

Please sign in to comment.