From 88ee1d1f8dac2f1cd08edefea3745d25c00b04d8 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 4 Oct 2024 10:04:52 +0100 Subject: [PATCH] fix: correctly serialize Infinity as island props --- .changeset/beige-rice-tap.md | 5 +++++ .../fixtures/pass-js/src/components/React.tsx | 8 +++++++- .../e2e/fixtures/pass-js/src/pages/index.astro | 2 ++ packages/astro/e2e/pass-js.test.js | 16 ++++++++++++++++ .../astro/src/runtime/server/astro-island.ts | 1 + packages/astro/src/runtime/server/serialize.ts | 13 ++++++++++--- packages/astro/test/serialize.test.js | 5 +++++ 7 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 .changeset/beige-rice-tap.md diff --git a/.changeset/beige-rice-tap.md b/.changeset/beige-rice-tap.md new file mode 100644 index 000000000000..67c7427a9317 --- /dev/null +++ b/.changeset/beige-rice-tap.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Support passing the values `Infinity` and `-Infinity` as island props. diff --git a/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx index 15314461c070..be86090af0ae 100644 --- a/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx +++ b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx @@ -11,12 +11,14 @@ interface Props { array: any[]; map: Map; set: Set; + infinity: number; + negativeInfinity: number; } const isNode = typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]'; /** a counter written in React */ -export default function Component({ undefined: undefinedProp, null: nullProp, boolean, number, string, bigint, object, array, map, set }: Props) { +export default function Component({ undefined: undefinedProp, null: nullProp, boolean, number, string, bigint, object, array, map, set, infinity, negativeInfinity }: Props) { // We are testing hydration, so don't return anything in the server. if(isNode) { return
@@ -30,6 +32,10 @@ export default function Component({ undefined: undefinedProp, null: nullProp, bo {boolean.toString()} {Object.prototype.toString.call(number)} {number.toString()} + {Object.prototype.toString.call(infinity)} + {infinity.toString()} + {Object.prototype.toString.call(negativeInfinity)} + {negativeInfinity.toString()} {Object.prototype.toString.call(string)} {string} {Object.prototype.toString.call(bigint)} diff --git a/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro index 24794367f30d..5d00f535d2e8 100644 --- a/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro @@ -42,6 +42,8 @@ set.add('test2'); array={[0, "foo"]} map={map} set={set} + infinity={Infinity} + negativeInfinity={-Infinity} /> diff --git a/packages/astro/e2e/pass-js.test.js b/packages/astro/e2e/pass-js.test.js index 91e3b5c5e752..c70f2ae39be5 100644 --- a/packages/astro/e2e/pass-js.test.js +++ b/packages/astro/e2e/pass-js.test.js @@ -47,6 +47,22 @@ test.describe('Passing JS into client components', () => { await expect(numberValue, 'is visible').toBeVisible(); await expect(numberValue).toHaveText('16'); + const infinityType = page.locator('#infinity-type'); + await expect(infinityType, 'is visible').toBeVisible(); + await expect(infinityType).toHaveText('[object Number]'); + + const negativeInfinityType = page.locator('#negative-infinity-type'); + await expect(negativeInfinityType, 'is visible').toBeVisible(); + await expect(negativeInfinityType).toHaveText('[object Number]'); + + const infinityValue = page.locator('#infinity-value'); + await expect(infinityValue, 'is visible').toBeVisible(); + await expect(infinityValue).toHaveText('Infinity'); + + const negativeInfinityValue = page.locator('#negative-infinity-value'); + await expect(negativeInfinityValue, 'is visible').toBeVisible(); + await expect(negativeInfinityValue).toHaveText('-Infinity'); + // string const stringType = page.locator('#string-type'); await expect(stringType, 'is visible').toBeVisible(); diff --git a/packages/astro/src/runtime/server/astro-island.ts b/packages/astro/src/runtime/server/astro-island.ts index 3c0404435afd..252ed65c8618 100644 --- a/packages/astro/src/runtime/server/astro-island.ts +++ b/packages/astro/src/runtime/server/astro-island.ts @@ -29,6 +29,7 @@ declare const Astro: { 8: (value) => new Uint8Array(value), 9: (value) => new Uint16Array(value), 10: (value) => new Uint32Array(value), + 11: (value) => Infinity * value, }; // Not using JSON.parse reviver because it's bottom-up but we want top-down diff --git a/packages/astro/src/runtime/server/serialize.ts b/packages/astro/src/runtime/server/serialize.ts index 522b05256601..ccce39bde3ab 100644 --- a/packages/astro/src/runtime/server/serialize.ts +++ b/packages/astro/src/runtime/server/serialize.ts @@ -13,6 +13,7 @@ const PROP_TYPE = { Uint8Array: 8, Uint16Array: 9, Uint32Array: 10, + Infinity: 11, }; function serializeArray( @@ -93,11 +94,17 @@ function convertToSerializedForm( default: { if (value !== null && typeof value === 'object') { return [PROP_TYPE.Value, serializeObject(value, metadata, parents)]; - } else if (value === undefined) { + } + if (value === Infinity) { + return [PROP_TYPE.Infinity, 1]; + } + if (value === -Infinity) { + return [PROP_TYPE.Infinity, -1]; + } + if (value === undefined) { return [PROP_TYPE.Value]; - } else { - return [PROP_TYPE.Value, value]; } + return [PROP_TYPE.Value, value]; } } } diff --git a/packages/astro/test/serialize.test.js b/packages/astro/test/serialize.test.js index 89eb3cc967d3..53a985e3a50a 100644 --- a/packages/astro/test/serialize.test.js +++ b/packages/astro/test/serialize.test.js @@ -89,6 +89,11 @@ describe('serialize', () => { const output = `{"a":[10,[1,2,3]]}`; assert.equal(serializeProps(input), output); }); + it('serializes Infinity and -Infinity', () => { + const input = { a: Infinity, b: -Infinity }; + const output = `{"a":[11,1],"b":[11,-1]}`; + assert.equal(serializeProps(input), output); + }) it('cannot serialize a cyclic reference', () => { const a = {}; a.b = a;