diff --git a/packages/plugins/.eslintrc.cjs b/packages/plugins/.eslintrc.cjs index 42e284e9..fbb0f7d1 100644 --- a/packages/plugins/.eslintrc.cjs +++ b/packages/plugins/.eslintrc.cjs @@ -13,6 +13,7 @@ module.exports = { "devDependencies": ["**/*.test.ts"] } ], - "prefer-template": "off" + "prefer-template": "off", + "@typescript-eslint/no-explicit-any": "off" } }; \ No newline at end of file diff --git a/packages/plugins/tests/web/__snapshots__/readable-stream.test.ts.snap b/packages/plugins/tests/web/__snapshots__/readable-stream.test.ts.snap new file mode 100644 index 00000000..affc636a --- /dev/null +++ b/packages/plugins/tests/web/__snapshots__/readable-stream.test.ts.snap @@ -0,0 +1,69 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ReadableStream > crossSerializeAsync > scoped > supports ReadableStream 1`] = `"($R=>$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))(($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),$R[2].next("foo"),$R[2].next("bar"),$R[2].next("baz"),$R[2].return(void 0),$R[2])))($R["example"])"`; + +exports[`ReadableStream > crossSerializeAsync > scoped > supports ReadableStream errors 1`] = `"($R=>$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))(($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),$R[2].throw($R[4]=Object.assign(new Error("Oops!"),{stack:""})),$R[2])))($R["example"])"`; + +exports[`ReadableStream > crossSerializeAsync > supports ReadableStream 1`] = `"$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))(($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),$R[2].next("foo"),$R[2].next("bar"),$R[2].next("baz"),$R[2].return(void 0),$R[2]))"`; + +exports[`ReadableStream > crossSerializeAsync > supports ReadableStream errors 1`] = `"$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))(($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),$R[2].throw($R[4]=Object.assign(new Error("Oops!"),{stack:""})),$R[2]))"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 1`] = `"($R=>$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))()))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 2`] = `"($R=>$R[2].next("foo"))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 3`] = `"($R=>$R[2].next("bar"))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 4`] = `"($R=>$R[2].next("baz"))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream 5`] = `"($R=>$R[2].return(void 0))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 1`] = `"($R=>$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))()))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > scoped > supports ReadableStream errors 2`] = `"($R=>$R[2].throw($R[4]=Object.assign(new Error("Oops!"),{stack:""})))($R["example"])"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 1`] = `"$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))())"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 2`] = `"$R[2].next("foo")"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 3`] = `"$R[2].next("bar")"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 4`] = `"$R[2].next("baz")"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream 5`] = `"$R[2].return(void 0)"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream errors 1`] = `"$R[0]=($R[1]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))($R[2]=($R[3]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))())"`; + +exports[`ReadableStream > crossSerializeStream > supports ReadableStream errors 2`] = `"$R[2].throw($R[4]=Object.assign(new Error("Oops!"),{stack:""}))"`; + +exports[`ReadableStream > serializeAsync > supports ReadableStream 1`] = `"((h,j)=>((d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))((j=((b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),j.next("foo"),j.next("bar"),j.next("baz"),j.return(void 0),j))))()"`; + +exports[`ReadableStream > serializeAsync > supports ReadableStream errors 1`] = `"((h,j)=>((d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))((j=((b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],s=0,f=(v,m,x)=>{for(x=0;x{for(x=0,z=b.length;x(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))(),j.throw(Object.assign(new Error("Oops!"),{stack:""})),j))))()"`; + +exports[`ReadableStream > serializeAsync > supports ReadableStream errors 2`] = `[Error: Oops!]`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream 1`] = `"{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[{"t":48,"i":2,"f":{"t":1,"s":"foo"}},{"t":48,"i":2,"f":{"t":1,"s":"bar"}},{"t":48,"i":2,"f":{"t":1,"s":"baz"}},{"t":50,"i":2,"f":{"t":2,"s":1}}],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"}"`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream errors 1`] = `"{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[{"t":49,"i":2,"f":{"t":13,"i":4,"s":0,"m":"Oops!","p":{"k":["stack"],"v":[{"t":1,"s":""}],"s":1}}}],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"}"`; + +exports[`ReadableStream > toCrossJSONAsync > supports ReadableStream errors 2`] = `[Error: Oops!]`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 1`] = `"{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 2`] = `"{"t":48,"i":2,"f":{"t":1,"s":"foo"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 3`] = `"{"t":48,"i":2,"f":{"t":1,"s":"bar"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 4`] = `"{"t":48,"i":2,"f":{"t":1,"s":"baz"}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream 5`] = `"{"t":50,"i":2,"f":{"t":2,"s":1}}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream errors 1`] = `"{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"}"`; + +exports[`ReadableStream > toCrossJSONStream > supports ReadableStream errors 2`] = `"{"t":49,"i":2,"f":{"t":13,"i":4,"s":0,"m":"Oops!","p":{"k":["stack"],"v":[{"t":1,"s":""}],"s":1}}}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream 1`] = `"{"t":{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[{"t":48,"i":2,"f":{"t":1,"s":"foo"}},{"t":48,"i":2,"f":{"t":1,"s":"bar"}},{"t":48,"i":2,"f":{"t":1,"s":"baz"}},{"t":50,"i":2,"f":{"t":2,"s":1}}],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"},"f":16383,"m":[2]}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream errors 1`] = `"{"t":{"t":40,"i":0,"s":{"factory":{"t":40,"i":1,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":47,"i":2,"a":[{"t":49,"i":2,"f":{"t":13,"i":4,"s":0,"m":"Oops!","p":{"k":["stack"],"v":[{"t":1,"s":""}],"s":1}}}],"f":{"t":41,"i":3,"s":9}}},"c":"seroval/plugins/web/ReadableStream"},"f":16383,"m":[2]}"`; + +exports[`ReadableStream > toJSONAsync > supports ReadableStream errors 2`] = `[Error: Oops!]`; diff --git a/packages/plugins/tests/web/readable-stream.test.ts b/packages/plugins/tests/web/readable-stream.test.ts new file mode 100644 index 00000000..852faff3 --- /dev/null +++ b/packages/plugins/tests/web/readable-stream.test.ts @@ -0,0 +1,419 @@ +import { describe, it, expect } from 'vitest'; +import { + crossSerializeAsync, + crossSerializeStream, + deserialize, + fromCrossJSON, + fromJSON, + serializeAsync, + toCrossJSONAsync, + toCrossJSONStream, + toJSONAsync, +} from 'seroval'; +import ReadableStreamPlugin from '../../web/readable-stream'; + +describe('ReadableStream', () => { + describe('serializeAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await serializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await serializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(result).toMatchSnapshot(); + const back = deserialize(result); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('toJSONAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await toJSONAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await toJSONAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromJSON(result, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('crossSerializeAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await crossSerializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(result).toMatchSnapshot(); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await crossSerializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(result).toMatchSnapshot(); + }); + describe('scoped', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await crossSerializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + scopeId: 'example', + }); + expect(result).toMatchSnapshot(); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await crossSerializeAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + scopeId: 'example', + }); + expect(result).toMatchSnapshot(); + }); + }); + }); + describe('crossSerializeStream', () => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + crossSerializeStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + crossSerializeStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + describe('scoped', () => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + crossSerializeStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + crossSerializeStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + scopeId: 'example', + onSerialize(data) { + expect(data).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); + }); + describe('toCrossJSONAsync', () => { + it('supports ReadableStream', async () => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + const result = await toCrossJSONAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + plugins: [ + ReadableStreamPlugin, + ], + refs: new Map(), + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'foo', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'bar', + }); + expect(await reader.read()).toMatchObject({ + done: false, + value: 'baz', + }); + expect(await reader.read()).toMatchObject({ + done: true, + value: undefined, + }); + }); + it('supports ReadableStream errors', async () => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + const result = await toCrossJSONAsync(example, { + plugins: [ + ReadableStreamPlugin, + ], + }); + expect(JSON.stringify(result)).toMatchSnapshot(); + const back = fromCrossJSON(result, { + plugins: [ + ReadableStreamPlugin, + ], + refs: new Map(), + }); + expect(back).toBeInstanceOf(ReadableStream); + const reader = back.getReader(); + await expect(async () => reader.read()).rejects.toThrowErrorMatchingSnapshot(); + }); + }); + describe('toCrossJSONStream', () => { + it('supports ReadableStream', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + controller.enqueue('foo'); + controller.enqueue('bar'); + controller.enqueue('baz'); + controller.close(); + }, + }); + toCrossJSONStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + it('supports ReadableStream errors', async () => new Promise((resolve, reject) => { + const example = new ReadableStream({ + start(controller): void { + const error = new Error('Oops!'); + error.stack = ''; + controller.error(error); + }, + }); + toCrossJSONStream(example, { + plugins: [ + ReadableStreamPlugin, + ], + onParse(data) { + expect(JSON.stringify(data)).toMatchSnapshot(); + }, + onDone() { + resolve(); + }, + onError(error) { + reject(error); + }, + }); + })); + }); +}); diff --git a/packages/plugins/web/readable-stream.ts b/packages/plugins/web/readable-stream.ts new file mode 100644 index 00000000..e845235a --- /dev/null +++ b/packages/plugins/web/readable-stream.ts @@ -0,0 +1,133 @@ +import type { SerovalNode, Stream } from 'seroval'; +import { createPlugin, createStream } from 'seroval'; + +const READABLE_STREAM_FACTORY = {}; + +const ReadableStreamFactoryPlugin = /* @__PURE__ */createPlugin({ + tag: 'seroval-plugins/web/ReadableStreamFactory', + test(value) { + return value === READABLE_STREAM_FACTORY; + }, + parse: { + sync() { + return undefined; + }, + async async() { + return Promise.resolve(undefined); + }, + stream() { + return undefined; + }, + }, + serialize(node, ctx) { + return ctx.createFunction( + ['d'], + 'new ReadableStream({start:' + ctx.createEffectfulFunction( + ['c'], + 'd.on({next:' + ctx.createEffectfulFunction( + ['v'], + 'c.enqueue(v)', + ) + ',throw:' + ctx.createEffectfulFunction( + ['v'], + 'c.error(v)', + ) + ',return:' + ctx.createEffectfulFunction( + [], + 'c.close()', + ) + '})', + ) + '})', + ); + }, + deserialize() { + return READABLE_STREAM_FACTORY; + }, +}); + +function toStream(value: ReadableStream): Stream { + const stream = createStream(); + + const reader = value.getReader(); + + async function push(): Promise { + try { + const result = await reader.read(); + if (result.done) { + stream.return(result.value); + } else { + stream.next(result.value); + await push(); + } + } catch (error) { + stream.throw(error); + } + } + + push().catch(() => { + // + }); + + return stream; +} + +interface ReadableStreamNode { + factory: SerovalNode; + stream: SerovalNode; +} + +const ReadableStreamPlugin = /* @__PURE__ */createPlugin({ + tag: 'seroval/plugins/web/ReadableStream', + extends: [ + ReadableStreamFactoryPlugin, + ], + test(value) { + if (typeof ReadableStream === 'undefined') { + return false; + } + return value instanceof ReadableStream; + }, + parse: { + sync(value, ctx) { + return { + factory: ctx.parse(READABLE_STREAM_FACTORY), + stream: ctx.parse(createStream()), + }; + }, + async async(value, ctx) { + return { + factory: await ctx.parse(READABLE_STREAM_FACTORY), + stream: await ctx.parse(toStream(value)), + }; + }, + stream(value, ctx) { + return { + factory: ctx.parse(READABLE_STREAM_FACTORY), + stream: ctx.parse(toStream(value)), + }; + }, + }, + serialize(node, ctx) { + return '(' + ctx.serialize(node.factory) + ')(' + ctx.serialize(node.stream) + ')'; + }, + deserialize(node, ctx) { + const stream = ctx.deserialize(node.stream) as Stream; + return new ReadableStream({ + start(controller): void { + stream.on({ + next(value) { + console.log('next', value); + controller.enqueue(value); + }, + throw(value) { + console.log('throw', value); + controller.error(value); + }, + return() { + console.log('return'); + controller.close(); + }, + }); + }, + }); + }, +}); + +export default ReadableStreamPlugin; diff --git a/packages/plugins/web/readable-stream/index.ts b/packages/plugins/web/readable-stream/index.ts deleted file mode 100644 index 8198ea08..00000000 --- a/packages/plugins/web/readable-stream/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { SerovalNode, Stream } from 'seroval'; -import { createPlugin, createStream } from 'seroval'; - -function toStream(value: ReadableStream): Stream { - const stream = createStream(); - - const reader = value.getReader(); - - async function push(): Promise { - try { - const result = await reader.read(); - if (result.done) { - stream.return(result.value); - } else { - stream.next(result.value); - await push(); - } - } catch (error) { - stream.throw(error); - } - } - - push().catch(() => { - // - }); - - return stream; -} - -interface ReadableStreamNode { - stream: SerovalNode; -} - -export default createPlugin({ - tag: 'seroval/plugins/web/readable-stream', - test(value) { - if (typeof ReadableStream === 'undefined') { - return false; - } - return value instanceof ReadableStream; - }, - parse: { - sync(value, ctx, data) { - return { - stream: ctx.parse(createStream()), - }; - }, - async async(value, ctx, data) { - return { - stream: await ctx.parse(toStream(value)), - }; - }, - stream(value, ctx, data) { - return { - stream: ctx.parse(toStream(value)), - }; - }, - }, - serialize(node, ctx, data) { - - }, - deserialize(node, ctx, data) { - - }, -}); diff --git a/packages/seroval/src/core/constants.ts b/packages/seroval/src/core/constants.ts index d095fef0..b191cb38 100644 --- a/packages/seroval/src/core/constants.ts +++ b/packages/seroval/src/core/constants.ts @@ -35,10 +35,6 @@ export const enum SerovalNodeType { PromiseConstructor = 28, PromiseResolve = 29, PromiseReject = 30, - ReadableStreamConstructor = 31, - ReadableStreamEnqueue = 32, - ReadableStreamClose = 33, - ReadableStreamError = 34, Request = 35, Response = 36, Event = 37, @@ -50,7 +46,6 @@ export const enum SerovalNodeType { IteratorFactoryInstance = 43, AsyncIteratorFactory = 44, AsyncIteratorFactoryInstance = 45, - ReadableStream = 46, StreamConstructor = 47, StreamNext = 48, StreamThrow = 49, diff --git a/packages/seroval/src/core/context/deserializer.ts b/packages/seroval/src/core/context/deserializer.ts index 71886f30..6ecadffd 100644 --- a/packages/seroval/src/core/context/deserializer.ts +++ b/packages/seroval/src/core/context/deserializer.ts @@ -27,11 +27,6 @@ import type { SerovalPromiseNode, SerovalPromiseRejectNode, SerovalPromiseResolveNode, - SerovalReadableStreamCloseNode, - SerovalReadableStreamConstructorNode, - SerovalReadableStreamEnqueueNode, - SerovalReadableStreamErrorNode, - SerovalReadableStreamNode, SerovalReferenceNode, SerovalRegExpNode, SerovalRequestNode, @@ -56,11 +51,10 @@ import { readableStreamToAsyncIterator, sequenceToAsyncIterator, sequenceToIterator, - sequenceToReadableStream, } from '../utils/iterator-to-sequence'; import { getTypedArrayConstructor } from '../utils/typed-array'; -import type { Deferred, DeferredStream } from '../utils/deferred'; -import { createDeferred, createDeferredStream } from '../utils/deferred'; +import type { Deferred } from '../utils/deferred'; +import { createDeferred } from '../utils/deferred'; import assert from '../utils/assert'; import type { Stream } from '../stream'; import { createStream } from '../stream'; @@ -398,40 +392,6 @@ export default abstract class BaseDeserializerContext implements PluginAccessOpt return undefined; } - private deserializeReadableStreamConstructor( - node: SerovalReadableStreamConstructorNode, - ): unknown { - return this.assignIndexedValue( - node.i, - createDeferredStream(), - ).stream; - } - - private deserializeReadableStreamEnqueue(node: SerovalReadableStreamEnqueueNode): unknown { - const deferred = this.refs.get(node.i) as DeferredStream | undefined; - assert(deferred, new Error('Missing ReadableStream instance.')); - deferred.enqueue( - this.deserialize(node.a[1]), - ); - return undefined; - } - - private deserializeReadableStreamError(node: SerovalReadableStreamErrorNode): unknown { - const deferred = this.refs.get(node.i) as DeferredStream | undefined; - assert(deferred, new Error('Missing Promise instance.')); - deferred.error( - this.deserialize(node.a[1]), - ); - return undefined; - } - - private deserializeReadableStreamClose(node: SerovalReadableStreamCloseNode): unknown { - const deferred = this.refs.get(node.i) as DeferredStream | undefined; - assert(deferred, new Error('Missing Promise instance.')); - deferred.close(); - return undefined; - } - private deserializeIteratorFactoryInstance( node: SerovalIteratorFactoryInstanceNode, ): unknown { @@ -451,31 +411,27 @@ export default abstract class BaseDeserializerContext implements PluginAccessOpt return sequenceToAsyncIterator(source as Sequence); } - private deserializeReadableStream( - node: SerovalReadableStreamNode, - ): unknown { - return this.assignIndexedValue( - node.i, - sequenceToReadableStream( - this.deserialize(node.a[1]) as Sequence, - ), - ); - } - private deserializeStreamConstructor( node: SerovalStreamConstructorNode, ): unknown { - return this.assignIndexedValue( + const result = this.assignIndexedValue( node.i, createStream(), ); + const len = node.a.length; + if (len) { + for (let i = 0; i < len; i++) { + this.deserialize(node.a[i]); + } + } + return result; } private deserializeStreamNext( node: SerovalStreamNextNode, ): unknown { const deferred = this.refs.get(node.i) as Stream | undefined; - assert(deferred, new Error('Missing ReadableStream instance.')); + assert(deferred, new Error('Missing Stream instance.')); deferred.next( this.deserialize(node.f), ); @@ -486,7 +442,7 @@ export default abstract class BaseDeserializerContext implements PluginAccessOpt node: SerovalStreamThrowNode, ): unknown { const deferred = this.refs.get(node.i) as Stream | undefined; - assert(deferred, new Error('Missing ReadableStream instance.')); + assert(deferred, new Error('Missing Stream instance.')); deferred.throw( this.deserialize(node.f), ); @@ -497,7 +453,7 @@ export default abstract class BaseDeserializerContext implements PluginAccessOpt node: SerovalStreamReturnNode, ): unknown { const deferred = this.refs.get(node.i) as Stream | undefined; - assert(deferred, new Error('Missing ReadableStream instance.')); + assert(deferred, new Error('Missing Stream instance.')); deferred.return( this.deserialize(node.f), ); @@ -566,20 +522,10 @@ export default abstract class BaseDeserializerContext implements PluginAccessOpt return this.deserializePromiseResolve(node); case SerovalNodeType.PromiseReject: return this.deserializePromiseReject(node); - case SerovalNodeType.ReadableStreamConstructor: - return this.deserializeReadableStreamConstructor(node); - case SerovalNodeType.ReadableStreamEnqueue: - return this.deserializeReadableStreamEnqueue(node); - case SerovalNodeType.ReadableStreamError: - return this.deserializeReadableStreamError(node); - case SerovalNodeType.ReadableStreamClose: - return this.deserializeReadableStreamClose(node); case SerovalNodeType.IteratorFactoryInstance: return this.deserializeIteratorFactoryInstance(node); case SerovalNodeType.AsyncIteratorFactoryInstance: return this.deserializeAsyncIteratorFactoryInstance(node); - case SerovalNodeType.ReadableStream: - return this.deserializeReadableStream(node); case SerovalNodeType.StreamConstructor: return this.deserializeStreamConstructor(node); case SerovalNodeType.StreamNext: diff --git a/packages/seroval/src/core/context/parser/async.ts b/packages/seroval/src/core/context/parser/async.ts index 1abd5bd5..57dd013f 100644 --- a/packages/seroval/src/core/context/parser/async.ts +++ b/packages/seroval/src/core/context/parser/async.ts @@ -42,7 +42,7 @@ import { FALSE_NODE, UNDEFINED_NODE, } from '../../literals'; -import { iteratorToSequence, readableStreamToSequence } from '../../utils/iterator-to-sequence'; +import { iteratorToSequence } from '../../utils/iterator-to-sequence'; import { BaseParserContext } from '../parser'; import promiseToResult from '../../utils/promise-to-result'; import { getErrorOptions } from '../../utils/error'; @@ -69,14 +69,12 @@ import type { SerovalResponseNode, SerovalSetNode, SerovalDataViewNode, - SerovalReadableStreamNode, SerovalStreamConstructorNode, } from '../../types'; import { createDOMExceptionNode, createEventNode, createCustomEventNode, - createReadableStreamNode, } from '../../web-api'; import { SpecialReference, UNIVERSAL_SENTINEL } from '../../special-reference'; import type { Stream } from '../../stream'; @@ -396,19 +394,6 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { return undefined; } - private async parseReadableStream( - id: number, - current: ReadableStream, - ): Promise { - return createReadableStreamNode( - id, - this.parseSpecialReference(SpecialReference.ReadableStream), - await this.parse( - await readableStreamToSequence(current), - ), - ); - } - private async parseStream( id: number, current: Stream, @@ -581,8 +566,6 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext { return this.parseCustomEvent(id, current as unknown as CustomEvent); case (typeof DOMException !== 'undefined' ? DOMException : UNIVERSAL_SENTINEL): return createDOMExceptionNode(id, current as unknown as DOMException); - case (typeof ReadableStream !== 'undefined' ? ReadableStream : UNIVERSAL_SENTINEL): - return this.parseReadableStream(id, current as unknown as ReadableStream); default: break; } diff --git a/packages/seroval/src/core/context/parser/stream.ts b/packages/seroval/src/core/context/parser/stream.ts index 44ae8405..0a2153c1 100644 --- a/packages/seroval/src/core/context/parser/stream.ts +++ b/packages/seroval/src/core/context/parser/stream.ts @@ -26,7 +26,6 @@ import type { SerovalObjectRecordNode, SerovalPluginNode, SerovalPromiseConstructorNode, - SerovalReadableStreamConstructorNode, SerovalRequestNode, SerovalResponseNode, } from '../../types'; @@ -180,106 +179,6 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont }; } - private pushReadableStreamReader( - id: number, - reader: ReadableStreamDefaultReader, - ): void { - reader.read().then( - (data) => { - if (this.alive) { - if (data.done) { - this.onParse({ - t: SerovalNodeType.ReadableStreamClose, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parseSpecialReference(SpecialReference.ReadableStreamClose), - b: undefined, - o: undefined, - }); - this.popPendingState(); - } else { - const parsed = this.parseWithError(data.value); - if (parsed) { - this.onParse({ - t: SerovalNodeType.ReadableStreamEnqueue, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: [ - this.parseSpecialReference(SpecialReference.ReadableStreamEnqueue), - parsed, - ], - f: undefined, - b: undefined, - o: undefined, - }); - this.pushReadableStreamReader(id, reader); - } - } - } - }, - (value) => { - if (this.alive) { - const parsed = this.parseWithError(value); - if (parsed) { - this.onParse({ - t: SerovalNodeType.ReadableStreamError, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: [ - this.parseSpecialReference(SpecialReference.ReadableStreamError), - parsed, - ], - f: undefined, - b: undefined, - o: undefined, - }); - } - this.popPendingState(); - } - }, - ); - } - - private parseReadableStream( - id: number, - current: ReadableStream, - ): SerovalReadableStreamConstructorNode { - const reader = current.getReader(); - this.pushPendingState(); - this.pushReadableStreamReader(id, reader); - - return { - t: SerovalNodeType.ReadableStreamConstructor, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: undefined, - f: this.parseSpecialReference(SpecialReference.ReadableStreamConstructor), - b: undefined, - o: undefined, - }; - } - private parseRequest( id: number, current: Request, @@ -564,8 +463,6 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont // Web APIs if (currentFeatures & Feature.WebAPI) { switch (currentClass) { - case (typeof ReadableStream !== 'undefined' ? ReadableStream : UNIVERSAL_SENTINEL): - return this.parseReadableStream(id, current as unknown as ReadableStream); case (typeof Request !== 'undefined' ? Request : UNIVERSAL_SENTINEL): return this.parseRequest(id, current as unknown as Request); case (typeof Response !== 'undefined' ? Response : UNIVERSAL_SENTINEL): diff --git a/packages/seroval/src/core/context/serializer.ts b/packages/seroval/src/core/context/serializer.ts index 82dab802..9f99c78f 100644 --- a/packages/seroval/src/core/context/serializer.ts +++ b/packages/seroval/src/core/context/serializer.ts @@ -40,15 +40,10 @@ import type { SerovalPromiseConstructorNode, SerovalPromiseResolveNode, SerovalPromiseRejectNode, - SerovalReadableStreamConstructorNode, - SerovalReadableStreamEnqueueNode, - SerovalReadableStreamErrorNode, - SerovalReadableStreamCloseNode, SerovalIteratorFactoryInstanceNode, SerovalIteratorFactoryNode, SerovalAsyncIteratorFactoryInstanceNode, SerovalAsyncIteratorFactoryNode, - SerovalReadableStreamNode, SerovalSpecialReferenceNode, SerovalNodeWithID, SerovalStreamConstructorNode, @@ -938,48 +933,10 @@ export default abstract class BaseSerializerContext implements PluginAccessOptio return this.getConstructor(node.a[0]) + '(' + this.getRefParam(node.i) + ',' + this.serialize(node.a[1]) + ')'; } - protected serializeReadableStreamConstructor( - node: SerovalReadableStreamConstructorNode, - ): string { - return this.assignIndexedValue( - node.i, - this.getConstructor(node.f) + '()', - ); - } - - protected serializeReadableStreamEnqueue( - node: SerovalReadableStreamEnqueueNode, - ): string { - return this.getConstructor(node.a[0]) + '(' + this.getRefParam(node.i) + ',' + this.serialize(node.a[1]) + ')'; - } - - protected serializeReadableStreamError( - node: SerovalReadableStreamErrorNode, - ): string { - return this.getConstructor(node.a[0]) + '(' + this.getRefParam(node.i) + ',' + this.serialize(node.a[1]) + ')'; - } - - protected serializeReadableStreamClose( - node: SerovalReadableStreamCloseNode, - ): string { - return this.getConstructor(node.f) + '(' + this.getRefParam(node.i) + ')'; - } - private serializeSpecialReferenceValue(ref: SpecialReference): string { switch (ref) { case SpecialReference.MapSentinel: return '[]'; - case SpecialReference.ReadableStream: - return this.createFunction( - ['s'], - 'new ReadableStream({start:' + this.createFunction( - ['c'], - 'Promise.resolve().then(' + this.createEffectfulFunction( - ['i', 'v'], - 'for(i=0;i = { [SpecialReference.MapSentinel]: {}, - [SpecialReference.ReadableStream]: {}, [SpecialReference.PromiseConstructor]: {}, [SpecialReference.PromiseResolve]: {}, [SpecialReference.PromiseReject]: {}, - [SpecialReference.ReadableStreamConstructor]: {}, - [SpecialReference.ReadableStreamEnqueue]: {}, - [SpecialReference.ReadableStreamError]: {}, - [SpecialReference.ReadableStreamClose]: {}, [SpecialReference.StreamConstructor]: {}, }; diff --git a/packages/seroval/src/core/stream.ts b/packages/seroval/src/core/stream.ts index 71f584d4..ba30bcf0 100644 --- a/packages/seroval/src/core/stream.ts +++ b/packages/seroval/src/core/stream.ts @@ -21,7 +21,7 @@ export function isStream(value: object): value is Stream { export function createStream(): Stream { const listeners = new Set>(); const buffer: unknown[] = []; - let done = true; + let alive = true; let success = false; function flushNext(value: T): void { @@ -45,7 +45,7 @@ export function createStream(): Stream { return { __SEROVAL_STREAM__: true, on(listener: StreamListener): () => void { - if (done) { + if (alive) { listeners.add(listener); } for (let i = 0, len = buffer.length; i < len; i++) { @@ -61,31 +61,31 @@ export function createStream(): Stream { } } return () => { - if (done) { + if (alive) { listeners.delete(listener); } }; }, next(value): void { - if (done) { + if (alive) { buffer.push(value); flushNext(value); } }, throw(value): void { - if (done) { + if (alive) { buffer.push(value); flushThrow(value); - done = false; + alive = false; success = false; listeners.clear(); } }, return(value): void { - if (done) { + if (alive) { buffer.push(value); flushReturn(value); - done = false; + alive = false; success = true; listeners.clear(); } diff --git a/packages/seroval/src/core/tree/serializer.ts b/packages/seroval/src/core/tree/serializer.ts index 5746e111..dc13a0e9 100644 --- a/packages/seroval/src/core/tree/serializer.ts +++ b/packages/seroval/src/core/tree/serializer.ts @@ -3,10 +3,6 @@ import type { SerovalPromiseConstructorNode, SerovalPromiseRejectNode, SerovalPromiseResolveNode, - SerovalReadableStreamCloseNode, - SerovalReadableStreamConstructorNode, - SerovalReadableStreamEnqueueNode, - SerovalReadableStreamErrorNode, } from '../types'; import type { BaseSerializerContextOptions } from '../context/serializer'; import BaseSerializerContext from '../context/serializer'; @@ -83,30 +79,6 @@ export default class VanillaSerializerContext extends BaseSerializerContext { throw new Error('Unsupported node type "' + node.t + '".'); } - protected serializeReadableStreamConstructor( - node: SerovalReadableStreamConstructorNode, - ): string { - throw new Error('Unsupported node type "' + node.t + '".'); - } - - protected serializeReadableStreamEnqueue( - node: SerovalReadableStreamEnqueueNode, - ): string { - throw new Error('Unsupported node type "' + node.t + '".'); - } - - protected serializeReadableStreamError( - node: SerovalReadableStreamErrorNode, - ): string { - throw new Error('Unsupported node type "' + node.t + '".'); - } - - protected serializeReadableStreamClose( - node: SerovalReadableStreamCloseNode, - ): string { - throw new Error('Unsupported node type "' + node.t + '".'); - } - serializeTop(tree: SerovalNode): string { const result = this.serialize(tree); // Shared references detected diff --git a/packages/seroval/src/core/types.ts b/packages/seroval/src/core/types.ts index 5ae9cdc1..3925c381 100644 --- a/packages/seroval/src/core/types.ts +++ b/packages/seroval/src/core/types.ts @@ -274,36 +274,6 @@ export interface SerovalPromiseRejectNode extends SerovalBaseNode { ]; } -export interface SerovalReadableStreamConstructorNode extends SerovalBaseNode { - t: SerovalNodeType.ReadableStreamConstructor; - i: number; - f: SerovalNodeWithID; -} - -export interface SerovalReadableStreamEnqueueNode extends SerovalBaseNode { - t: SerovalNodeType.ReadableStreamEnqueue; - i: number; - a: [ - resolver: SerovalNodeWithID, - resolved: SerovalNode, - ]; -} - -export interface SerovalReadableStreamErrorNode extends SerovalBaseNode { - t: SerovalNodeType.ReadableStreamError; - i: number; - a: [ - resolver: SerovalNodeWithID, - resolved: SerovalNode, - ]; -} - -export interface SerovalReadableStreamCloseNode extends SerovalBaseNode { - t: SerovalNodeType.ReadableStreamClose; - i: number; - f: SerovalNodeWithID; -} - export interface SerovalRequestNode extends SerovalBaseNode { t: SerovalNodeType.Request; i: number; @@ -389,15 +359,6 @@ export interface SerovalAsyncIteratorFactoryInstanceNode extends SerovalBaseNode ]; } -export interface SerovalReadableStreamNode extends SerovalBaseNode { - t: SerovalNodeType.ReadableStream; - i: number; - a: [ - instance: SerovalNodeWithID, - sequence: SerovalNode, - ]; -} - export interface SerovalStreamConstructorNode extends SerovalBaseNode { t: SerovalNodeType.StreamConstructor; i: number; @@ -455,13 +416,8 @@ export type SerovalAsyncNode = | SerovalPromiseConstructorNode | SerovalPromiseResolveNode | SerovalPromiseRejectNode - | SerovalReadableStreamConstructorNode - | SerovalReadableStreamEnqueueNode - | SerovalReadableStreamCloseNode - | SerovalReadableStreamErrorNode | SerovalRequestNode | SerovalResponseNode - | SerovalReadableStreamNode | SerovalStreamConstructorNode | SerovalStreamNextNode | SerovalStreamThrowNode diff --git a/packages/seroval/src/core/utils/deferred.ts b/packages/seroval/src/core/utils/deferred.ts index fdefc664..04439a29 100644 --- a/packages/seroval/src/core/utils/deferred.ts +++ b/packages/seroval/src/core/utils/deferred.ts @@ -20,30 +20,3 @@ export function createDeferred(): Deferred { }, }; } - -export interface DeferredStream { - stream: ReadableStream; - close(): void; - enqueue(chunk?: unknown): void; - error(e?: unknown): void; -} - -export function createDeferredStream(): DeferredStream { - let controller: ReadableStreamDefaultController; - return { - stream: new ReadableStream({ - start(current): void { - controller = current; - }, - }), - close(): void { - controller.close(); - }, - enqueue(data): void { - controller.enqueue(data); - }, - error(e): void { - controller.error(e); - }, - }; -} diff --git a/packages/seroval/src/core/utils/iterator-to-sequence.ts b/packages/seroval/src/core/utils/iterator-to-sequence.ts index 7d220712..b931dedf 100644 --- a/packages/seroval/src/core/utils/iterator-to-sequence.ts +++ b/packages/seroval/src/core/utils/iterator-to-sequence.ts @@ -219,20 +219,3 @@ export async function readableStreamToSequence( d: doneAt, }; } - -export function sequenceToReadableStream( - sequence: Sequence, -): ReadableStream { - return new ReadableStream({ - start(controller): void { - for (let i = 0; i < sequence.d; i++) { - controller.enqueue(sequence.v[i] as T); - } - if (sequence.t === -1) { - controller.close(); - } else { - controller.error(sequence.v[sequence.t] as T); - } - }, - }); -} diff --git a/packages/seroval/src/core/web-api.ts b/packages/seroval/src/core/web-api.ts index f7541426..73e5baa0 100644 --- a/packages/seroval/src/core/web-api.ts +++ b/packages/seroval/src/core/web-api.ts @@ -5,8 +5,6 @@ import type { SerovalDOMExceptionNode, SerovalEventNode, SerovalNode, - SerovalNodeWithID, - SerovalReadableStreamNode, } from './types'; export function createDOMExceptionNode( @@ -70,27 +68,3 @@ export function createCustomEventNode( o: undefined, }; } - -export function createReadableStreamNode( - id: number, - factory: SerovalNodeWithID, - items: SerovalNode, -): SerovalReadableStreamNode { - return { - t: SerovalNodeType.ReadableStream, - i: id, - s: undefined, - l: undefined, - c: undefined, - m: undefined, - p: undefined, - e: undefined, - a: [ - factory, - items, - ], - f: undefined, - b: undefined, - o: undefined, - }; -} diff --git a/packages/seroval/test2.js b/packages/seroval/test2.js deleted file mode 100644 index 1ebc00b5..00000000 --- a/packages/seroval/test2.js +++ /dev/null @@ -1,15 +0,0 @@ -import { serialize, Feature } from 'seroval'; - -const y = Object.create(null); -y.self = y; -y.example = 'Hello World'; - -function serializeWithTarget(value, disabledFeatures) { - const result = serialize(value, { - disabledFeatures, - }); - console.log(result); -} - -serializeWithTarget(y, Feature.ArrowFunction | Feature.ObjectAssign); -serializeWithTarget(y, 0); \ No newline at end of file diff --git a/packages/seroval/theory.js b/packages/seroval/theory.js deleted file mode 100644 index 0d7c16da..00000000 --- a/packages/seroval/theory.js +++ /dev/null @@ -1,21 +0,0 @@ -import { createStream, crossSerializeStream, serializeAsync } from "./dist/esm/development/index.mjs"; - -const sleep = (value, ms) => ( - new Promise((res) => setTimeout(res, ms, value)) -); - -const stream = createStream({ - b: [], - a: true, -}); - -stream.next('foo'); -stream.next('bar'); -stream.return('baz'); - -// crossSerializeStream(stream, { -// onSerialize(data) { -// console.log(data); -// } -// }) -console.log(await serializeAsync(stream)); \ No newline at end of file