MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add transform streams

+1296 -40
+386
examples/spec/streams-transform.js
··· 1 + import { test, testDeep, testThrows, summary } from './helpers.js'; 2 + 3 + console.log('TransformStream / TransformStreamDefaultController Tests\n'); 4 + 5 + test('TS typeof', typeof TransformStream, 'function'); 6 + test('TS toStringTag', Object.prototype.toString.call(new TransformStream()), '[object TransformStream]'); 7 + 8 + testThrows('TS requires new', () => TransformStream()); 9 + testThrows('TS rejects readableType', () => new TransformStream({ readableType: 'bytes' })); 10 + testThrows('TS rejects writableType', () => new TransformStream({ writableType: 'bytes' })); 11 + 12 + const ts0 = new TransformStream(); 13 + test('TS readable is ReadableStream', ts0.readable instanceof ReadableStream, true); 14 + test('TS writable is WritableStream', ts0.writable instanceof WritableStream, true); 15 + 16 + testThrows('TSController cannot be constructed', () => new TransformStreamDefaultController()); 17 + test('TSController toStringTag', typeof TransformStreamDefaultController, 'function'); 18 + 19 + test('TS can be constructed with no transform', true, (() => { new TransformStream({}); return true; })()); 20 + 21 + let startCtrl = null; 22 + const ts1 = new TransformStream({ start(c) { startCtrl = c; } }); 23 + test('start called with controller', startCtrl !== null, true); 24 + test('controller toStringTag', Object.prototype.toString.call(startCtrl), '[object TransformStreamDefaultController]'); 25 + 26 + async function testIdentity() { 27 + const ts = new TransformStream(); 28 + const writer = ts.writable.getWriter(); 29 + writer.write('a'); 30 + const reader = ts.readable.getReader(); 31 + const result = await reader.read(); 32 + test('identity value', result.value, 'a'); 33 + test('identity done', result.done, false); 34 + } 35 + 36 + async function testTransformUppercase() { 37 + let c; 38 + const ts = new TransformStream({ 39 + start(controller) { c = controller; }, 40 + transform(chunk) { c.enqueue(chunk.toUpperCase()); } 41 + }); 42 + const writer = ts.writable.getWriter(); 43 + writer.write('hello'); 44 + const reader = ts.readable.getReader(); 45 + const result = await reader.read(); 46 + test('uppercase transform', result.value, 'HELLO'); 47 + } 48 + 49 + async function testTransformDoubler() { 50 + let c; 51 + const ts = new TransformStream({ 52 + start(controller) { c = controller; }, 53 + transform(chunk) { 54 + c.enqueue(chunk.toUpperCase()); 55 + c.enqueue(chunk.toUpperCase()); 56 + } 57 + }); 58 + const writer = ts.writable.getWriter(); 59 + writer.write('x'); 60 + const reader = ts.readable.getReader(); 61 + const r1 = await reader.read(); 62 + const r2 = await reader.read(); 63 + test('doubler chunk 1', r1.value, 'X'); 64 + test('doubler chunk 2', r2.value, 'X'); 65 + } 66 + 67 + async function testFlush() { 68 + let flushed = false; 69 + const ts = new TransformStream({ 70 + transform() {}, 71 + flush() { flushed = true; } 72 + }); 73 + await ts.writable.getWriter().close(); 74 + test('flush called on close', flushed, true); 75 + } 76 + 77 + async function testFlushEnqueue() { 78 + let c; 79 + const ts = new TransformStream({ 80 + start(controller) { c = controller; }, 81 + transform() {}, 82 + flush() { c.enqueue('flushed'); } 83 + }); 84 + const writer = ts.writable.getWriter(); 85 + writer.write('a'); 86 + writer.close(); 87 + const reader = ts.readable.getReader(); 88 + const r1 = await reader.read(); 89 + test('flush enqueue value', r1.value, 'flushed'); 90 + } 91 + 92 + async function testCloseClosesReadable() { 93 + const ts = new TransformStream({ transform() {} }); 94 + const writer = ts.writable.getWriter(); 95 + writer.close(); 96 + await Promise.all([writer.closed, ts.readable.getReader().closed]); 97 + test('close propagates to readable', true, true); 98 + } 99 + 100 + async function testTransformError() { 101 + const err = new Error('transform boom'); 102 + const ts = new TransformStream({ 103 + transform() { throw err; } 104 + }); 105 + const writer = ts.writable.getWriter(); 106 + const reader = ts.readable.getReader(); 107 + try { 108 + await writer.write('a'); 109 + test('write should reject on transform error', false, true); 110 + } catch (e) { 111 + test('write rejects with transform error', e, err); 112 + } 113 + try { 114 + await reader.read(); 115 + test('read should reject on transform error', false, true); 116 + } catch (e) { 117 + test('read rejects with transform error', e, err); 118 + } 119 + } 120 + 121 + async function testFlushError() { 122 + const err = new Error('flush boom'); 123 + const ts = new TransformStream({ 124 + transform() {}, 125 + flush() { throw err; } 126 + }); 127 + const writer = ts.writable.getWriter(); 128 + await writer.write('a'); 129 + try { 130 + await writer.close(); 131 + test('close should reject on flush error', false, true); 132 + } catch (e) { 133 + test('close rejects with flush error', e, err); 134 + } 135 + } 136 + 137 + async function testControllerError() { 138 + let ctrl; 139 + const ts = new TransformStream({ 140 + start(c) { ctrl = c; } 141 + }); 142 + ctrl.error(new Error('controller error')); 143 + const reader = ts.readable.getReader(); 144 + try { 145 + await reader.read(); 146 + test('read should reject after controller.error', false, true); 147 + } catch (e) { 148 + test('controller.error errors readable', e.message, 'controller error'); 149 + } 150 + } 151 + 152 + async function testControllerTerminate() { 153 + let ctrl; 154 + const ts = new TransformStream({ 155 + start(c) { ctrl = c; } 156 + }); 157 + ctrl.terminate(); 158 + const reader = ts.readable.getReader(); 159 + const result = await reader.read(); 160 + test('terminate closes readable', result.done, true); 161 + } 162 + 163 + async function testDesiredSize() { 164 + let ctrl; 165 + const ts = new TransformStream({ 166 + start(c) { ctrl = c; } 167 + }); 168 + test('desiredSize initially 0', ctrl.desiredSize, 0); 169 + } 170 + 171 + async function testDefaultHWM() { 172 + const ts = new TransformStream(); 173 + const writer = ts.writable.getWriter(); 174 + test('writable default HWM is 1', writer.desiredSize, 1); 175 + } 176 + 177 + async function testCustomWritableHWM() { 178 + const ts = new TransformStream({}, { highWaterMark: 17 }); 179 + const writer = ts.writable.getWriter(); 180 + test('writable custom HWM', writer.desiredSize, 17); 181 + } 182 + 183 + async function testBackpressure() { 184 + const ts = new TransformStream(undefined, undefined, { highWaterMark: 0 }); 185 + const writer = ts.writable.getWriter(); 186 + const reader = ts.readable.getReader(); 187 + const readPromise = reader.read(); 188 + writer.write('a'); 189 + const result = await readPromise; 190 + test('backpressure read value', result.value, 'a'); 191 + test('backpressure read done', result.done, false); 192 + } 193 + 194 + async function testAsyncTransform() { 195 + let c; 196 + const ts = new TransformStream({ 197 + start(controller) { c = controller; }, 198 + transform(chunk) { 199 + return new Promise(resolve => { 200 + setTimeout(() => { 201 + c.enqueue(chunk.toUpperCase()); 202 + resolve(); 203 + }, 10); 204 + }); 205 + } 206 + }); 207 + const writer = ts.writable.getWriter(); 208 + writer.write('a'); 209 + const reader = ts.readable.getReader(); 210 + const result = await reader.read(); 211 + test('async transform value', result.value, 'A'); 212 + } 213 + 214 + async function testStartThrows() { 215 + try { 216 + new TransformStream({ 217 + start() { throw new URIError('start thrown'); } 218 + }); 219 + test('TS ctor should throw on start error', false, true); 220 + } catch (e) { 221 + test('TS ctor throws start error', e instanceof URIError, true); 222 + } 223 + } 224 + 225 + async function testCancelCallable() { 226 + let cancelled = null; 227 + const reason = new Error('cancel reason'); 228 + const ts = new TransformStream({ 229 + cancel(r) { cancelled = r; } 230 + }); 231 + await ts.readable.cancel(reason); 232 + test('cancel called with reason', cancelled, reason); 233 + } 234 + 235 + async function testAbortCallsCancel() { 236 + let aborted = null; 237 + const reason = new Error('abort reason'); 238 + const ts = new TransformStream({ 239 + cancel(r) { aborted = r; } 240 + }); 241 + await ts.writable.abort(reason); 242 + test('abort calls cancel with reason', aborted, reason); 243 + } 244 + 245 + async function testTransformThisBinding() { 246 + let c; 247 + const ts = new TransformStream({ 248 + suffix: '-suffix', 249 + start(controller) { c = controller; }, 250 + transform(chunk) { c.enqueue(chunk + this.suffix); }, 251 + flush() { c.enqueue('flushed' + this.suffix); } 252 + }); 253 + const writer = ts.writable.getWriter(); 254 + writer.write('a'); 255 + writer.close(); 256 + const reader = ts.readable.getReader(); 257 + const r1 = await reader.read(); 258 + test('this binding transform', r1.value, 'a-suffix'); 259 + const r2 = await reader.read(); 260 + test('this binding flush', r2.value, 'flushed-suffix'); 261 + } 262 + 263 + async function testSubclass() { 264 + class MyTS extends TransformStream { 265 + myMethod() { return 42; } 266 + } 267 + const ts = new MyTS(); 268 + test('subclass instanceof', ts instanceof TransformStream, true); 269 + test('subclass method', ts.myMethod(), 42); 270 + test('subclass readable', ts.readable instanceof ReadableStream, true); 271 + } 272 + 273 + async function testReadableHWM() { 274 + let ctrl; 275 + const ts = new TransformStream({ 276 + start(c) { ctrl = c; } 277 + }, undefined, { highWaterMark: 9 }); 278 + test('readable custom HWM desiredSize', ctrl.desiredSize, 9); 279 + } 280 + 281 + async function testNegativeHWMThrows() { 282 + testThrows('negative writable HWM', () => new TransformStream(undefined, { highWaterMark: -1 })); 283 + testThrows('negative readable HWM', () => new TransformStream(undefined, undefined, { highWaterMark: -1 })); 284 + testThrows('NaN writable HWM', () => new TransformStream(undefined, { highWaterMark: NaN })); 285 + testThrows('NaN readable HWM', () => new TransformStream(undefined, undefined, { highWaterMark: NaN })); 286 + } 287 + 288 + async function testCancelReadableErrorsWritable() { 289 + const err = new Error('cancel reason'); 290 + const ts = new TransformStream(); 291 + const writer = ts.writable.getWriter(); 292 + ts.readable.cancel(err); 293 + try { 294 + await writer.closed; 295 + test('writer.closed should reject after cancel', false, true); 296 + } catch (e) { 297 + test('writer.closed rejects with cancel reason', e, err); 298 + } 299 + } 300 + 301 + async function testWritableStrategySize() { 302 + let writableSizeCalled = false; 303 + let readableSizeCalled = false; 304 + const ts = new TransformStream( 305 + { 306 + transform(chunk, controller) { 307 + controller.enqueue(chunk); 308 + } 309 + }, 310 + { 311 + size() { writableSizeCalled = true; return 1; } 312 + }, 313 + { 314 + size() { readableSizeCalled = true; return 1; }, 315 + highWaterMark: Infinity 316 + } 317 + ); 318 + await ts.writable.getWriter().write('x'); 319 + test('writable size called', writableSizeCalled, true); 320 + test('readable size called', readableSizeCalled, true); 321 + } 322 + 323 + async function testPipeThrough() { 324 + const rs = new ReadableStream({ 325 + start(c) { c.enqueue(1); c.enqueue(2); c.enqueue(3); c.close(); } 326 + }); 327 + const ts = new TransformStream({ 328 + transform(chunk, controller) { 329 + controller.enqueue(chunk * 10); 330 + } 331 + }); 332 + const result = rs.pipeThrough(ts); 333 + test('pipeThrough returns readable', result instanceof ReadableStream, true); 334 + const reader = result.getReader(); 335 + const chunks = []; 336 + while (true) { 337 + const { value, done } = await reader.read(); 338 + if (done) break; 339 + chunks.push(value); 340 + } 341 + testDeep('pipeThrough transforms data', chunks, [10, 20, 30]); 342 + } 343 + 344 + async function testEnqueueAfterTerminateThrows() { 345 + let threw = false; 346 + new TransformStream({ 347 + start(controller) { 348 + controller.terminate(); 349 + try { 350 + controller.enqueue('x'); 351 + } catch (e) { 352 + threw = true; 353 + } 354 + } 355 + }); 356 + test('enqueue after terminate throws', threw, true); 357 + } 358 + 359 + await testIdentity(); 360 + await testTransformUppercase(); 361 + await testTransformDoubler(); 362 + await testFlush(); 363 + await testFlushEnqueue(); 364 + await testCloseClosesReadable(); 365 + await testTransformError(); 366 + await testFlushError(); 367 + await testControllerError(); 368 + await testControllerTerminate(); 369 + await testDesiredSize(); 370 + await testDefaultHWM(); 371 + await testCustomWritableHWM(); 372 + await testBackpressure(); 373 + await testAsyncTransform(); 374 + await testStartThrows(); 375 + await testCancelCallable(); 376 + await testAbortCallsCancel(); 377 + await testTransformThisBinding(); 378 + await testSubclass(); 379 + await testReadableHWM(); 380 + testNegativeHWMThrows(); 381 + await testCancelReadableErrorsWritable(); 382 + await testWritableStrategySize(); 383 + await testPipeThrough(); 384 + await testEnqueueAfterTerminateThrows(); 385 + 386 + summary();
+1
include/gc/modules.h
··· 24 24 void gc_mark_queuing_strategies(ant_t *js, gc_mark_fn mark); 25 25 void gc_mark_readable_streams(ant_t *js, gc_mark_fn mark); 26 26 void gc_mark_writable_streams(ant_t *js, gc_mark_fn mark); 27 + void gc_mark_transform_streams(ant_t *js, gc_mark_fn mark); 27 28 28 29 #endif
+10
include/streams/transform.h
··· 1 + #ifndef STREAMS_TRANSFORM_H 2 + #define STREAMS_TRANSFORM_H 3 + 4 + #include "types.h" 5 + #include <stdbool.h> 6 + 7 + void init_transform_stream_module(void); 8 + void gc_mark_transform_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)); 9 + 10 + #endif
+6
include/streams/writable.h
··· 29 29 bool pending_abort_was_already_erroring; 30 30 } ws_stream_t; 31 31 32 + extern ant_value_t g_ws_proto; 33 + extern ant_value_t g_ws_writer_proto; 34 + extern ant_value_t g_ws_controller_proto; 35 + 32 36 void init_writable_stream_module(void); 33 37 void gc_mark_writable_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)); 34 38 ··· 45 49 ant_value_t writable_stream_abort(ant_t *js, ant_value_t stream_obj, ant_value_t reason); 46 50 47 51 bool writable_stream_close_queued_or_in_flight(ant_value_t stream_obj); 52 + void writable_stream_finish_erroring(ant_t *js, ant_value_t stream_obj); 48 53 void ws_default_controller_error(ant_t *js, ant_value_t ctrl_obj, ant_value_t error); 54 + void ws_default_controller_advance_queue_if_needed(ant_t *js, ant_value_t ctrl_obj); 49 55 50 56 #endif
+1
src/gc/objects.c
··· 457 457 gc_mark_queuing_strategies(js, gc_mark_value); 458 458 gc_mark_readable_streams(js, gc_mark_value); 459 459 gc_mark_writable_streams(js, gc_mark_value); 460 + gc_mark_transform_streams(js, gc_mark_value); 460 461 461 462 for ( 462 463 ant_object_t *obj = g_pending_promises;
+4 -2
src/main.c
··· 82 82 #include "streams/queuing.h" 83 83 #include "streams/readable.h" 84 84 #include "streams/writable.h" 85 + #include "streams/transform.h" 85 86 86 87 int js_result = EXIT_SUCCESS; 87 88 typedef int (*cmd_fn)(int argc, char **argv); ··· 588 589 init_timer_module(); 589 590 init_domexception_module(); 590 591 init_globals_module(); 592 + init_builtin_module(); 593 + init_buffer_module(); 591 594 init_structured_clone_module(); 592 595 init_abort_module(); 593 596 init_headers_module(); ··· 601 604 init_queuing_strategies_module(); 602 605 init_readable_stream_module(); 603 606 init_writable_stream_module(); 604 - init_builtin_module(); 605 - init_buffer_module(); 607 + init_transform_stream_module(); 606 608 init_fs_module(); 607 609 init_atomics_module(); 608 610 init_crypto_module();
+857
src/streams/transform.c
··· 1 + #include <stdlib.h> 2 + #include <string.h> 3 + 4 + #include "ant.h" 5 + #include "errors.h" 6 + #include "runtime.h" 7 + #include "internal.h" 8 + #include "descriptors.h" 9 + 10 + #include "silver/engine.h" 11 + #include "modules/symbol.h" 12 + #include "streams/transform.h" 13 + #include "streams/readable.h" 14 + #include "streams/writable.h" 15 + 16 + static ant_value_t g_ts_proto; 17 + static ant_value_t g_ts_ctrl_proto; 18 + 19 + static void ts_ws_finalize(ant_t *js, ant_object_t *obj) { 20 + if (!obj->extra_slots) return; 21 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 22 + for (uint8_t i = 0; i < obj->extra_count; i++) { 23 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 24 + free((ws_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 25 + return; 26 + }} 27 + } 28 + 29 + static void ts_ws_ctrl_finalize(ant_t *js, ant_object_t *obj) { 30 + if (!obj->extra_slots) return; 31 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 32 + for (uint8_t i = 0; i < obj->extra_count; i++) { 33 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 34 + ws_controller_t *ctrl = (ws_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 35 + free(ctrl->queue_sizes); 36 + free(ctrl); 37 + return; 38 + }} 39 + } 40 + 41 + static void ts_rs_finalize(ant_t *js, ant_object_t *obj) { 42 + if (!obj->extra_slots) return; 43 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 44 + for (uint8_t i = 0; i < obj->extra_count; i++) { 45 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 46 + free((rs_stream_t *)(uintptr_t)(size_t)js_getnum(entries[i].value)); 47 + return; 48 + }} 49 + } 50 + 51 + static void ts_rs_ctrl_finalize(ant_t *js, ant_object_t *obj) { 52 + if (!obj->extra_slots) return; 53 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 54 + for (uint8_t i = 0; i < obj->extra_count; i++) { 55 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 56 + rs_controller_t *ctrl = (rs_controller_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 57 + free(ctrl->queue_sizes); 58 + free(ctrl); 59 + return; 60 + }} 61 + } 62 + 63 + static inline bool ts_is_valid(ant_value_t ts_obj) { 64 + return vtype(js_get_slot(ts_obj, SLOT_DATA)) == T_NUM; 65 + } 66 + 67 + static inline bool ts_get_backpressure(ant_value_t ts_obj) { 68 + return js_getnum(js_get_slot(ts_obj, SLOT_DATA)) != 0; 69 + } 70 + 71 + static inline void ts_set_bp_flag(ant_value_t ts_obj, bool bp) { 72 + js_set_slot(ts_obj, SLOT_DATA, js_mknum(bp ? 1 : 0)); 73 + } 74 + 75 + static inline ant_value_t ts_readable(ant_value_t ts_obj) { 76 + return js_get_slot(ts_obj, SLOT_ENTRIES); 77 + } 78 + 79 + static inline ant_value_t ts_writable(ant_value_t ts_obj) { 80 + return js_get_slot(ts_obj, SLOT_CTOR); 81 + } 82 + 83 + static inline ant_value_t ts_bp_promise(ant_value_t ts_obj) { 84 + return js_get_slot(ts_obj, SLOT_BUFFER); 85 + } 86 + 87 + static inline ant_value_t ts_controller(ant_value_t ts_obj) { 88 + return js_get_slot(ts_obj, SLOT_DEFAULT); 89 + } 90 + 91 + static inline ant_value_t ts_ctrl_transform_fn(ant_value_t ctrl_obj) { 92 + return js_get_slot(ctrl_obj, SLOT_ENTRIES); 93 + } 94 + 95 + static inline ant_value_t ts_ctrl_flush_fn(ant_value_t ctrl_obj) { 96 + return js_get_slot(ctrl_obj, SLOT_CTOR); 97 + } 98 + 99 + static inline ant_value_t ts_ctrl_cancel_fn(ant_value_t ctrl_obj) { 100 + return js_get_slot(ctrl_obj, SLOT_BUFFER); 101 + } 102 + 103 + static inline ant_value_t ts_ctrl_stream(ant_value_t ctrl_obj) { 104 + return js_get_slot(ctrl_obj, SLOT_DATA); 105 + } 106 + 107 + static inline ant_value_t ts_ctrl_finish_promise(ant_value_t ctrl_obj) { 108 + return js_get_slot(ctrl_obj, SLOT_RS_PULL); 109 + } 110 + 111 + static void ts_ctrl_clear_algorithms(ant_value_t ctrl_obj) { 112 + js_set_slot(ctrl_obj, SLOT_ENTRIES, js_mkundef()); 113 + js_set_slot(ctrl_obj, SLOT_CTOR, js_mkundef()); 114 + js_set_slot(ctrl_obj, SLOT_BUFFER, js_mkundef()); 115 + } 116 + 117 + static bool ts_is_thenable(ant_t *js, ant_value_t val) { 118 + if (vtype(val) == T_PROMISE) return true; 119 + if (!is_object_type(val)) return false; 120 + ant_value_t then = js_get(js, val, "then"); 121 + return is_callable(then); 122 + } 123 + 124 + static void ts_chain_thenable(ant_t *js, ant_value_t val, ant_value_t res_fn, ant_value_t rej_fn) { 125 + if (vtype(val) == T_PROMISE) { 126 + ant_value_t then_fn = js_get(js, val, "then"); 127 + if (is_callable(then_fn)) { 128 + ant_value_t then_args[2] = { res_fn, rej_fn }; 129 + sv_vm_call(js->vm, js, then_fn, val, then_args, 2, NULL, false); 130 + } 131 + } else { 132 + ant_value_t resolved = js_mkpromise(js); 133 + js_resolve_promise(js, resolved, val); 134 + ant_value_t then_fn = js_get(js, resolved, "then"); 135 + if (is_callable(then_fn)) { 136 + ant_value_t then_args[2] = { res_fn, rej_fn }; 137 + sv_vm_call(js->vm, js, then_fn, resolved, then_args, 2, NULL, false); 138 + } 139 + } 140 + } 141 + 142 + static void ts_error(ant_t *js, ant_value_t ts_obj, ant_value_t e) { 143 + ant_value_t readable = ts_readable(ts_obj); 144 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 145 + rs_controller_t *rc = rs_get_controller(rs_ctrl); 146 + if (rc) { 147 + rc->queue_total_size = 0; 148 + rc->queue_sizes_len = 0; 149 + rs_default_controller_clear_algorithms(rs_ctrl); 150 + } 151 + readable_stream_error(js, readable, e); 152 + 153 + if (ts_get_backpressure(ts_obj)) { 154 + ant_value_t bp = ts_bp_promise(ts_obj); 155 + if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef()); 156 + ts_set_bp_flag(ts_obj, false); 157 + } 158 + } 159 + 160 + static void ts_error_writable_and_unblock_write(ant_t *js, ant_value_t ts_obj, ant_value_t e) { 161 + ant_value_t ctrl_obj = ts_controller(ts_obj); 162 + ts_ctrl_clear_algorithms(ctrl_obj); 163 + 164 + ant_value_t writable = ts_writable(ts_obj); 165 + ws_stream_t *ws = ws_get_stream(writable); 166 + if (ws && ws->state == WS_STATE_WRITABLE) 167 + ws_default_controller_error(js, ws_stream_controller(writable), e); 168 + 169 + if (ts_get_backpressure(ts_obj)) { 170 + ant_value_t bp = ts_bp_promise(ts_obj); 171 + if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef()); 172 + ts_set_bp_flag(ts_obj, false); 173 + } 174 + } 175 + 176 + static void ts_set_backpressure(ant_t *js, ant_value_t ts_obj, bool backpressure) { 177 + if (ts_get_backpressure(ts_obj)) { 178 + ant_value_t bp = ts_bp_promise(ts_obj); 179 + if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef()); 180 + } 181 + ant_value_t new_bp = js_mkpromise(js); 182 + js_set_slot(ts_obj, SLOT_BUFFER, new_bp); 183 + ts_set_bp_flag(ts_obj, backpressure); 184 + } 185 + 186 + static void ts_ctrl_enqueue(ant_t *js, ant_value_t ctrl_obj, ant_value_t chunk) { 187 + ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj); 188 + ant_value_t readable = ts_readable(ts_obj); 189 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 190 + rs_stream_t *rs = rs_get_stream(readable); 191 + if (!rs || rs->state != RS_STATE_READABLE) return; 192 + 193 + rs_controller_enqueue(js, rs_ctrl, chunk); 194 + 195 + rs_controller_t *rc = rs_get_controller(rs_ctrl); 196 + bool bp = rc && (rc->queue_total_size > 0); 197 + if (bp != ts_get_backpressure(ts_obj)) 198 + ts_set_backpressure(js, ts_obj, bp); 199 + } 200 + 201 + static void ts_ctrl_error(ant_t *js, ant_value_t ctrl_obj, ant_value_t e) { 202 + ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj); 203 + ts_error(js, ts_obj, e); 204 + ts_error_writable_and_unblock_write(js, ts_obj, e); 205 + } 206 + 207 + static void ts_ctrl_terminate(ant_t *js, ant_value_t ctrl_obj) { 208 + ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj); 209 + ant_value_t readable = ts_readable(ts_obj); 210 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 211 + rs_controller_close(js, rs_ctrl); 212 + 213 + ant_value_t writable = ts_writable(ts_obj); 214 + ws_stream_t *ws = ws_get_stream(writable); 215 + if (ws && ws->state == WS_STATE_WRITABLE) { 216 + bool had_throw = js->thrown_exists; 217 + ant_value_t saved_value = had_throw ? js->thrown_value : js_mkundef(); 218 + ant_value_t saved_stack = had_throw ? js->thrown_stack : js_mkundef(); 219 + 220 + js_mkerr_typed(js, JS_ERR_TYPE, "TransformStream readable side terminated"); 221 + ant_value_t err = js->thrown_value; 222 + 223 + js->thrown_exists = had_throw; 224 + js->thrown_value = saved_value; 225 + js->thrown_stack = saved_stack; 226 + 227 + ts_error_writable_and_unblock_write(js, ts_obj, err); 228 + } 229 + } 230 + 231 + static ant_value_t ts_transform_resolve(ant_t *js, ant_value_t *args, int nargs) { 232 + ant_value_t p = js_get_slot(js->current_func, SLOT_DATA); 233 + js_resolve_promise(js, p, js_mkundef()); 234 + return js_mkundef(); 235 + } 236 + 237 + static ant_value_t ts_transform_reject(ant_t *js, ant_value_t *args, int nargs) { 238 + ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 239 + ant_value_t p = js_get_slot(wrapper, SLOT_DATA); 240 + ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES); 241 + ant_value_t e = (nargs > 0) ? args[0] : js_mkundef(); 242 + ts_error(js, ts_obj, e); 243 + js_reject_promise(js, p, e); 244 + return js_mkundef(); 245 + } 246 + 247 + static ant_value_t ts_ctrl_perform_transform(ant_t *js, ant_value_t ctrl_obj, ant_value_t chunk) { 248 + ant_value_t transform_fn = ts_ctrl_transform_fn(ctrl_obj); 249 + ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj); 250 + ant_value_t p = js_mkpromise(js); 251 + 252 + if (is_callable(transform_fn)) { 253 + ant_value_t call_args[2] = { chunk, ctrl_obj }; 254 + ant_value_t result = sv_vm_call(js->vm, js, transform_fn, js_mkundef(), call_args, 2, NULL, false); 255 + 256 + if (is_err(result)) { 257 + ant_value_t thrown = js->thrown_value; 258 + ant_value_t err = is_object_type(thrown) ? thrown : result; 259 + ts_error(js, ts_obj, err); 260 + js_reject_promise(js, p, err); 261 + return p; 262 + } 263 + 264 + ant_value_t res_fn = js_heavy_mkfun(js, ts_transform_resolve, p); 265 + ant_value_t wrapper = js_mkobj(js); 266 + js_set_slot(wrapper, SLOT_DATA, p); 267 + js_set_slot(wrapper, SLOT_ENTRIES, ts_obj); 268 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_transform_reject, wrapper); 269 + 270 + if (ts_is_thenable(js, result)) ts_chain_thenable(js, result, res_fn, rej_fn); 271 + else { 272 + ant_value_t resolved = js_mkpromise(js); 273 + js_resolve_promise(js, resolved, js_mkundef()); 274 + ts_chain_thenable(js, resolved, res_fn, rej_fn); 275 + } 276 + } else { 277 + ts_ctrl_enqueue(js, ctrl_obj, chunk); 278 + js_resolve_promise(js, p, js_mkundef()); 279 + } 280 + 281 + return p; 282 + } 283 + 284 + static ant_value_t ts_sink_write_bp_resolve(ant_t *js, ant_value_t *args, int nargs) { 285 + ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 286 + ant_value_t ctrl_obj = js_get_slot(wrapper, SLOT_DATA); 287 + ant_value_t chunk = js_get_slot(wrapper, SLOT_ENTRIES); 288 + ant_value_t ts_obj = js_get_slot(wrapper, SLOT_CTOR); 289 + 290 + ws_stream_t *ws = ws_get_stream(ts_writable(ts_obj)); 291 + 292 + if (ws && ws->state == WS_STATE_ERRORING) { 293 + bool had_throw = js->thrown_exists; 294 + ant_value_t saved_value = had_throw ? js->thrown_value : js_mkundef(); 295 + ant_value_t saved_stack = had_throw ? js->thrown_stack : js_mkundef(); 296 + 297 + js_mkerr_typed(js, JS_ERR_TYPE, "WritableStream is in erroring state"); 298 + ant_value_t err = js->thrown_value; 299 + 300 + js->thrown_exists = had_throw; 301 + js->thrown_value = saved_value; 302 + js->thrown_stack = saved_stack; 303 + 304 + ant_value_t fp = ts_ctrl_finish_promise(ctrl_obj); 305 + if (vtype(fp) == T_PROMISE) js_reject_promise(js, fp, err); 306 + return js_mkundef(); 307 + } 308 + 309 + ant_value_t transform_p = ts_ctrl_perform_transform(js, ctrl_obj, chunk); 310 + ant_value_t fp = ts_ctrl_finish_promise(ctrl_obj); 311 + if (vtype(fp) == T_PROMISE) { 312 + ant_value_t resolve_fn = js_heavy_mkfun(js, ts_transform_resolve, fp); 313 + ant_value_t rej_wrapper = js_mkobj(js); 314 + js_set_slot(rej_wrapper, SLOT_DATA, fp); 315 + js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj); 316 + ant_value_t reject_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper); 317 + ts_chain_thenable(js, transform_p, resolve_fn, reject_fn); 318 + } 319 + return js_mkundef(); 320 + } 321 + 322 + static ant_value_t ts_sink_write(ant_t *js, ant_value_t *args, int nargs) { 323 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 324 + ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef(); 325 + ant_value_t ctrl_obj = ts_controller(ts_obj); 326 + 327 + ant_value_t finish_p = js_mkpromise(js); 328 + js_set_slot(ctrl_obj, SLOT_RS_PULL, finish_p); 329 + 330 + if (ts_get_backpressure(ts_obj)) { 331 + ant_value_t wrapper = js_mkobj(js); 332 + js_set_slot(wrapper, SLOT_DATA, ctrl_obj); 333 + js_set_slot(wrapper, SLOT_ENTRIES, chunk); 334 + js_set_slot(wrapper, SLOT_CTOR, ts_obj); 335 + ant_value_t res_fn = js_heavy_mkfun(js, ts_sink_write_bp_resolve, wrapper); 336 + ant_value_t rej_wrapper = js_mkobj(js); 337 + js_set_slot(rej_wrapper, SLOT_DATA, finish_p); 338 + js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj); 339 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper); 340 + ant_value_t bp = ts_bp_promise(ts_obj); 341 + ts_chain_thenable(js, bp, res_fn, rej_fn); 342 + } else { 343 + ant_value_t transform_p = ts_ctrl_perform_transform(js, ctrl_obj, chunk); 344 + ant_value_t resolve_fn = js_heavy_mkfun(js, ts_transform_resolve, finish_p); 345 + ant_value_t rej_wrapper = js_mkobj(js); 346 + js_set_slot(rej_wrapper, SLOT_DATA, finish_p); 347 + js_set_slot(rej_wrapper, SLOT_ENTRIES, ts_obj); 348 + ant_value_t reject_fn = js_heavy_mkfun(js, ts_transform_reject, rej_wrapper); 349 + ts_chain_thenable(js, transform_p, resolve_fn, reject_fn); 350 + } 351 + 352 + return finish_p; 353 + } 354 + 355 + static ant_value_t ts_sink_abort(ant_t *js, ant_value_t *args, int nargs) { 356 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 357 + ant_value_t ctrl_obj = ts_controller(ts_obj); 358 + ant_value_t cancel_fn = ts_ctrl_cancel_fn(ctrl_obj); 359 + ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef(); 360 + 361 + if (is_callable(cancel_fn)) { 362 + ant_value_t cancel_args[1] = { reason }; 363 + ant_value_t result = sv_vm_call(js->vm, js, cancel_fn, js_mkundef(), cancel_args, 1, NULL, false); 364 + if (is_err(result)) { 365 + ant_value_t thrown = js->thrown_value; 366 + reason = is_object_type(thrown) ? thrown : reason; 367 + } 368 + } 369 + 370 + ts_error(js, ts_obj, reason); 371 + ant_value_t p = js_mkpromise(js); 372 + js_resolve_promise(js, p, js_mkundef()); 373 + return p; 374 + } 375 + 376 + static ant_value_t ts_sink_close_resolve(ant_t *js, ant_value_t *args, int nargs) { 377 + ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 378 + ant_value_t p = js_get_slot(wrapper, SLOT_DATA); 379 + ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES); 380 + 381 + ant_value_t readable = ts_readable(ts_obj); 382 + rs_stream_t *rs = rs_get_stream(readable); 383 + if (rs && rs->state == RS_STATE_READABLE) 384 + js_resolve_promise(js, p, js_mkundef()); 385 + else { 386 + bool had_throw = js->thrown_exists; 387 + ant_value_t saved_value = had_throw ? js->thrown_value : js_mkundef(); 388 + ant_value_t saved_stack = had_throw ? js->thrown_stack : js_mkundef(); 389 + 390 + js_mkerr_typed(js, JS_ERR_TYPE, "TransformStream readable side is not in a readable state"); 391 + ant_value_t err = js->thrown_value; 392 + 393 + js->thrown_exists = had_throw; 394 + js->thrown_value = saved_value; 395 + js->thrown_stack = saved_stack; 396 + 397 + js_reject_promise(js, p, err); 398 + } 399 + 400 + return js_mkundef(); 401 + } 402 + 403 + static ant_value_t ts_sink_close_reject(ant_t *js, ant_value_t *args, int nargs) { 404 + ant_value_t wrapper = js_get_slot(js->current_func, SLOT_DATA); 405 + ant_value_t p = js_get_slot(wrapper, SLOT_DATA); 406 + ant_value_t ts_obj = js_get_slot(wrapper, SLOT_ENTRIES); 407 + ant_value_t e = (nargs > 0) ? args[0] : js_mkundef(); 408 + ts_error(js, ts_obj, e); 409 + js_reject_promise(js, p, e); 410 + return js_mkundef(); 411 + } 412 + 413 + static ant_value_t ts_sink_close(ant_t *js, ant_value_t *args, int nargs) { 414 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 415 + ant_value_t ctrl_obj = ts_controller(ts_obj); 416 + ant_value_t readable = ts_readable(ts_obj); 417 + 418 + ant_value_t flush_fn = ts_ctrl_flush_fn(ctrl_obj); 419 + ts_ctrl_clear_algorithms(ctrl_obj); 420 + 421 + ant_value_t p = js_mkpromise(js); 422 + 423 + if (is_callable(flush_fn)) { 424 + ant_value_t flush_args[1] = { ctrl_obj }; 425 + ant_value_t result = sv_vm_call(js->vm, js, flush_fn, js_mkundef(), flush_args, 1, NULL, false); 426 + 427 + if (is_err(result)) { 428 + ant_value_t thrown = js->thrown_value; 429 + ant_value_t err = is_object_type(thrown) ? thrown : result; 430 + ts_error(js, ts_obj, err); 431 + js_reject_promise(js, p, err); 432 + return p; 433 + } 434 + 435 + ant_value_t wrapper = js_mkobj(js); 436 + js_set_slot(wrapper, SLOT_DATA, p); 437 + js_set_slot(wrapper, SLOT_ENTRIES, ts_obj); 438 + ant_value_t res_fn = js_heavy_mkfun(js, ts_sink_close_resolve, wrapper); 439 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_sink_close_reject, wrapper); 440 + 441 + if (ts_is_thenable(js, result)) ts_chain_thenable(js, result, res_fn, rej_fn); 442 + else { 443 + ant_value_t resolved = js_mkpromise(js); 444 + js_resolve_promise(js, resolved, js_mkundef()); 445 + ts_chain_thenable(js, resolved, res_fn, rej_fn); 446 + } 447 + } else { 448 + rs_stream_t *rs = rs_get_stream(readable); 449 + if (rs && rs->state == RS_STATE_READABLE) { 450 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 451 + rs_controller_close(js, rs_ctrl); 452 + } 453 + js_resolve_promise(js, p, js_mkundef()); 454 + } 455 + 456 + return p; 457 + } 458 + 459 + static ant_value_t ts_source_pull_resolve(ant_t *js, ant_value_t *args, int nargs) { 460 + ant_value_t p = js_get_slot(js->current_func, SLOT_DATA); 461 + js_resolve_promise(js, p, js_mkundef()); 462 + return js_mkundef(); 463 + } 464 + 465 + static ant_value_t ts_source_pull(ant_t *js, ant_value_t *args, int nargs) { 466 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 467 + 468 + if (ts_get_backpressure(ts_obj)) { 469 + ts_set_backpressure(js, ts_obj, false); 470 + ant_value_t p = js_mkpromise(js); 471 + js_resolve_promise(js, p, js_mkundef()); 472 + return p; 473 + } 474 + 475 + ant_value_t p = js_mkpromise(js); 476 + js_resolve_promise(js, p, js_mkundef()); 477 + return p; 478 + } 479 + 480 + static ant_value_t ts_source_cancel(ant_t *js, ant_value_t *args, int nargs) { 481 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 482 + ant_value_t ctrl_obj = ts_controller(ts_obj); 483 + ant_value_t cancel_fn = ts_ctrl_cancel_fn(ctrl_obj); 484 + ant_value_t reason = (nargs > 0) ? args[0] : js_mkundef(); 485 + 486 + ts_ctrl_clear_algorithms(ctrl_obj); 487 + 488 + if (is_callable(cancel_fn)) { 489 + ant_value_t cancel_args[1] = { reason }; 490 + ant_value_t result = sv_vm_call(js->vm, js, cancel_fn, js_mkundef(), cancel_args, 1, NULL, false); 491 + 492 + if (is_err(result)) { 493 + ant_value_t thrown = js->thrown_value; 494 + reason = is_object_type(thrown) ? thrown : reason; 495 + } else if (ts_is_thenable(js, result)) { 496 + ant_value_t p = js_mkpromise(js); 497 + ant_value_t wrapper = js_mkobj(js); 498 + js_set_slot(wrapper, SLOT_DATA, p); 499 + js_set_slot(wrapper, SLOT_ENTRIES, ts_obj); 500 + 501 + ant_value_t res_fn = js_heavy_mkfun(js, ts_source_pull_resolve, p); 502 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_sink_close_reject, wrapper); 503 + ts_chain_thenable(js, result, res_fn, rej_fn); 504 + 505 + ts_error_writable_and_unblock_write(js, ts_obj, reason); 506 + return p; 507 + } 508 + } 509 + 510 + ts_error_writable_and_unblock_write(js, ts_obj, reason); 511 + 512 + ant_value_t p = js_mkpromise(js); 513 + js_resolve_promise(js, p, js_mkundef()); 514 + return p; 515 + } 516 + 517 + static ant_value_t js_ts_ctrl_get_desired_size(ant_t *js, ant_value_t *args, int nargs) { 518 + ant_value_t ts_obj = ts_ctrl_stream(js->this_val); 519 + ant_value_t readable = ts_readable(ts_obj); 520 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 521 + rs_controller_t *rc = rs_get_controller(rs_ctrl); 522 + rs_stream_t *rs = rs_get_stream(readable); 523 + if (!rc || !rs) return js_mknull(); 524 + if (rs->state == RS_STATE_ERRORED) return js_mknull(); 525 + if (rs->state == RS_STATE_CLOSED) return js_mknum(0); 526 + return js_mknum(rc->strategy_hwm - rc->queue_total_size); 527 + } 528 + 529 + static ant_value_t js_ts_ctrl_enqueue(ant_t *js, ant_value_t *args, int nargs) { 530 + ant_value_t ts_obj = ts_ctrl_stream(js->this_val); 531 + ant_value_t readable = ts_readable(ts_obj); 532 + rs_stream_t *rs = rs_get_stream(readable); 533 + if (!rs || rs->state != RS_STATE_READABLE) 534 + return js_mkerr_typed(js, JS_ERR_TYPE, "Readable side is not in a readable state"); 535 + 536 + ant_value_t chunk = (nargs > 0) ? args[0] : js_mkundef(); 537 + ts_ctrl_enqueue(js, js->this_val, chunk); 538 + return js_mkundef(); 539 + } 540 + 541 + static ant_value_t js_ts_ctrl_error(ant_t *js, ant_value_t *args, int nargs) { 542 + ant_value_t e = (nargs > 0) ? args[0] : js_mkundef(); 543 + ts_ctrl_error(js, js->this_val, e); 544 + return js_mkundef(); 545 + } 546 + 547 + static ant_value_t js_ts_ctrl_terminate(ant_t *js, ant_value_t *args, int nargs) { 548 + ts_ctrl_terminate(js, js->this_val); 549 + return js_mkundef(); 550 + } 551 + 552 + static ant_value_t js_ts_get_readable(ant_t *js, ant_value_t *args, int nargs) { 553 + if (!ts_is_valid(js->this_val)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStream"); 554 + return ts_readable(js->this_val); 555 + } 556 + 557 + static ant_value_t js_ts_get_writable(ant_t *js, ant_value_t *args, int nargs) { 558 + if (!ts_is_valid(js->this_val)) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid TransformStream"); 559 + return ts_writable(js->this_val); 560 + } 561 + 562 + static ant_value_t ts_start_resolve(ant_t *js, ant_value_t *args, int nargs) { 563 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 564 + ant_value_t writable = ts_writable(ts_obj); 565 + ant_value_t ws_ctrl = ws_stream_controller(writable); 566 + ws_controller_t *wc = ws_get_controller(ws_ctrl); 567 + if (wc) wc->started = true; 568 + ws_default_controller_advance_queue_if_needed(js, ws_ctrl); 569 + 570 + ant_value_t readable = ts_readable(ts_obj); 571 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 572 + rs_controller_t *rc = rs_get_controller(rs_ctrl); 573 + if (rc) { 574 + rc->started = true; 575 + rc->pulling = false; 576 + rc->pull_again = false; 577 + rs_default_controller_call_pull_if_needed(js, rs_ctrl); 578 + } 579 + 580 + return js_mkundef(); 581 + } 582 + 583 + static ant_value_t ts_start_reject(ant_t *js, ant_value_t *args, int nargs) { 584 + ant_value_t ts_obj = js_get_slot(js->current_func, SLOT_DATA); 585 + ant_value_t e = (nargs > 0) ? args[0] : js_mkundef(); 586 + 587 + ant_value_t writable = ts_writable(ts_obj); 588 + ant_value_t ws_ctrl = ws_stream_controller(writable); 589 + ws_controller_t *wc = ws_get_controller(ws_ctrl); 590 + if (wc) wc->started = true; 591 + 592 + ant_value_t readable = ts_readable(ts_obj); 593 + ant_value_t rs_ctrl = rs_stream_controller(js, readable); 594 + rs_controller_t *rc = rs_get_controller(rs_ctrl); 595 + if (rc) rc->started = true; 596 + 597 + readable_stream_error(js, readable, e); 598 + 599 + ws_stream_t *ws = ws_get_stream(writable); 600 + if (ws && ws->state == WS_STATE_WRITABLE) 601 + ws_default_controller_error(js, ws_ctrl, e); 602 + 603 + return js_mkundef(); 604 + } 605 + 606 + static ant_value_t js_ts_ctor(ant_t *js, ant_value_t *args, int nargs) { 607 + if (vtype(js->new_target) == T_UNDEF) 608 + return js_mkerr_typed(js, JS_ERR_TYPE, "TransformStream constructor requires 'new'"); 609 + 610 + ant_value_t transformer = js_mkundef(); 611 + if (nargs > 0 && !is_undefined(args[0])) 612 + transformer = args[0]; 613 + 614 + if (is_object_type(transformer)) { 615 + ant_value_t rt_val = js_get(js, transformer, "readableType"); 616 + if (!is_undefined(rt_val)) 617 + return js_mkerr_typed(js, JS_ERR_RANGE, "readableType is not supported"); 618 + ant_value_t wt_val = js_get(js, transformer, "writableType"); 619 + if (!is_undefined(wt_val)) 620 + return js_mkerr_typed(js, JS_ERR_RANGE, "writableType is not supported"); 621 + } 622 + 623 + ant_value_t writable_strategy = js_mkundef(); 624 + if (nargs > 1 && !is_undefined(args[1]) && !is_null(args[1])) 625 + writable_strategy = args[1]; 626 + 627 + ant_value_t readable_strategy = js_mkundef(); 628 + if (nargs > 2 && !is_undefined(args[2]) && !is_null(args[2])) 629 + readable_strategy = args[2]; 630 + 631 + double writable_hwm = 1; 632 + ant_value_t writable_size_fn = js_mkundef(); 633 + if (is_object_type(writable_strategy)) { 634 + ant_value_t hwm_val = js_get(js, writable_strategy, "highWaterMark"); 635 + if (is_err(hwm_val)) return hwm_val; 636 + if (!is_undefined(hwm_val)) { 637 + writable_hwm = js_to_number(js, hwm_val); 638 + if (writable_hwm != writable_hwm || writable_hwm < 0) 639 + return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid highWaterMark"); 640 + } 641 + ant_value_t s = js_get(js, writable_strategy, "size"); 642 + if (is_err(s)) return s; 643 + if (!is_undefined(s)) { 644 + if (!is_callable(s)) return js_mkerr_typed(js, JS_ERR_TYPE, "size must be a function"); 645 + writable_size_fn = s; 646 + } 647 + } 648 + 649 + double readable_hwm = 0; 650 + ant_value_t readable_size_fn = js_mkundef(); 651 + if (is_object_type(readable_strategy)) { 652 + ant_value_t hwm_val = js_get(js, readable_strategy, "highWaterMark"); 653 + if (is_err(hwm_val)) return hwm_val; 654 + if (!is_undefined(hwm_val)) { 655 + readable_hwm = js_to_number(js, hwm_val); 656 + if (readable_hwm != readable_hwm || readable_hwm < 0) 657 + return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid highWaterMark"); 658 + } 659 + ant_value_t s = js_get(js, readable_strategy, "size"); 660 + if (is_err(s)) return s; 661 + if (!is_undefined(s)) { 662 + if (!is_callable(s)) return js_mkerr_typed(js, JS_ERR_TYPE, "size must be a function"); 663 + readable_size_fn = s; 664 + } 665 + } 666 + 667 + ant_value_t transform_fn = js_mkundef(); 668 + ant_value_t flush_fn = js_mkundef(); 669 + ant_value_t cancel_fn = js_mkundef(); 670 + ant_value_t start_fn = js_mkundef(); 671 + 672 + if (is_object_type(transformer)) { 673 + ant_value_t tv = js_get(js, transformer, "transform"); 674 + if (is_err(tv)) return tv; 675 + if (!is_undefined(tv)) { 676 + if (!is_callable(tv)) return js_mkerr_typed(js, JS_ERR_TYPE, "transform must be a function"); 677 + transform_fn = tv; 678 + } 679 + ant_value_t fv = js_get(js, transformer, "flush"); 680 + if (is_err(fv)) return fv; 681 + if (!is_undefined(fv)) { 682 + if (!is_callable(fv)) return js_mkerr_typed(js, JS_ERR_TYPE, "flush must be a function"); 683 + flush_fn = fv; 684 + } 685 + ant_value_t cv = js_get(js, transformer, "cancel"); 686 + if (is_err(cv)) return cv; 687 + if (!is_undefined(cv)) { 688 + if (!is_callable(cv)) return js_mkerr_typed(js, JS_ERR_TYPE, "cancel must be a function"); 689 + cancel_fn = cv; 690 + } 691 + ant_value_t sv = js_get(js, transformer, "start"); 692 + if (is_err(sv)) return sv; 693 + if (!is_undefined(sv)) { 694 + if (!is_callable(sv)) return js_mkerr_typed(js, JS_ERR_TYPE, "start must be a function"); 695 + start_fn = sv; 696 + } 697 + } 698 + 699 + ant_value_t ts_obj = js_mkobj(js); 700 + ant_value_t proto = js_instance_proto_from_new_target(js, g_ts_proto); 701 + if (is_object_type(proto)) js_set_proto_init(ts_obj, proto); 702 + js_set_slot(ts_obj, SLOT_DATA, js_mknum(0)); 703 + 704 + ant_value_t ctrl_obj = js_mkobj(js); 705 + js_set_proto_init(ctrl_obj, g_ts_ctrl_proto); 706 + js_set_slot(ctrl_obj, SLOT_DATA, ts_obj); 707 + js_set_slot(ctrl_obj, SLOT_ENTRIES, transform_fn); 708 + js_set_slot(ctrl_obj, SLOT_CTOR, flush_fn); 709 + js_set_slot(ctrl_obj, SLOT_BUFFER, cancel_fn); 710 + js_set_slot(ctrl_obj, SLOT_RS_PULL, js_mkundef()); 711 + js_set_slot(ts_obj, SLOT_DEFAULT, ctrl_obj); 712 + 713 + ant_value_t sink_write = js_heavy_mkfun(js, ts_sink_write, ts_obj); 714 + ant_value_t sink_abort = js_heavy_mkfun(js, ts_sink_abort, ts_obj); 715 + ant_value_t sink_close = js_heavy_mkfun(js, ts_sink_close, ts_obj); 716 + 717 + ant_value_t source_pull = js_heavy_mkfun(js, ts_source_pull, ts_obj); 718 + ant_value_t source_cancel = js_heavy_mkfun(js, ts_source_cancel, ts_obj); 719 + 720 + rs_stream_t *rst = calloc(1, sizeof(rs_stream_t)); 721 + if (!rst) return js_mkerr(js, "out of memory"); 722 + rst->state = RS_STATE_READABLE; 723 + 724 + ant_value_t rs_obj = js_mkobj(js); 725 + js_set_proto_init(rs_obj, g_rs_proto); 726 + js_set_slot(rs_obj, SLOT_DATA, ANT_PTR(rst)); 727 + js_set_finalizer(rs_obj, ts_rs_finalize); 728 + 729 + rs_controller_t *rcc = calloc(1, sizeof(rs_controller_t)); 730 + if (!rcc) { free(rst); return js_mkerr(js, "out of memory"); } 731 + rcc->strategy_hwm = readable_hwm; 732 + 733 + ant_value_t rs_ctrl_obj = js_mkobj(js); 734 + js_set_proto_init(rs_ctrl_obj, g_controller_proto); 735 + js_set_slot(rs_ctrl_obj, SLOT_DATA, ANT_PTR(rcc)); 736 + js_set_slot(rs_ctrl_obj, SLOT_ENTRIES, rs_obj); 737 + js_set_slot(rs_ctrl_obj, SLOT_RS_PULL, source_pull); 738 + js_set_slot(rs_ctrl_obj, SLOT_RS_CANCEL, source_cancel); 739 + js_set_slot(rs_ctrl_obj, SLOT_RS_SIZE, readable_size_fn); 740 + js_set_slot(rs_ctrl_obj, SLOT_BUFFER, js_mkarr(js)); 741 + js_set_finalizer(rs_ctrl_obj, ts_rs_ctrl_finalize); 742 + js_set_slot(rs_obj, SLOT_ENTRIES, rs_ctrl_obj); 743 + 744 + js_set_slot(ts_obj, SLOT_ENTRIES, rs_obj); 745 + 746 + ws_stream_t *wst = calloc(1, sizeof(ws_stream_t)); 747 + if (!wst) return js_mkerr(js, "out of memory"); 748 + wst->state = WS_STATE_WRITABLE; 749 + 750 + ant_value_t ws_obj = js_mkobj(js); 751 + js_set_proto_init(ws_obj, g_ws_proto); 752 + js_set_slot(ws_obj, SLOT_DATA, ANT_PTR(wst)); 753 + js_set_slot(ws_obj, SLOT_SETTLED, js_mkarr(js)); 754 + js_set_finalizer(ws_obj, ts_ws_finalize); 755 + 756 + js_set_slot(ts_obj, SLOT_CTOR, ws_obj); 757 + 758 + ant_value_t bp_promise = js_mkpromise(js); 759 + js_set_slot(ts_obj, SLOT_BUFFER, bp_promise); 760 + 761 + ts_set_backpressure(js, ts_obj, true); 762 + 763 + ws_controller_t *wc = calloc(1, sizeof(ws_controller_t)); 764 + if (!wc) { free(wst); return js_mkerr(js, "out of memory"); } 765 + wc->strategy_hwm = writable_hwm; 766 + 767 + ant_value_t ws_ctrl_obj = js_mkobj(js); 768 + js_set_proto_init(ws_ctrl_obj, g_ws_controller_proto); 769 + js_set_slot(ws_ctrl_obj, SLOT_DATA, ANT_PTR(wc)); 770 + js_set_slot(ws_ctrl_obj, SLOT_ENTRIES, ws_obj); 771 + js_set_slot(ws_ctrl_obj, SLOT_WS_WRITE, sink_write); 772 + js_set_slot(ws_ctrl_obj, SLOT_WS_CLOSE, sink_close); 773 + js_set_slot(ws_ctrl_obj, SLOT_WS_ABORT, sink_abort); 774 + js_set_slot(ws_ctrl_obj, SLOT_RS_SIZE, writable_size_fn); 775 + js_set_slot(ws_ctrl_obj, SLOT_CTOR, js_mkundef()); 776 + js_set_slot(ws_ctrl_obj, SLOT_BUFFER, js_mkarr(js)); 777 + js_set_finalizer(ws_ctrl_obj, ts_ws_ctrl_finalize); 778 + 779 + js_set_slot(ws_obj, SLOT_ENTRIES, ws_ctrl_obj); 780 + 781 + if (is_callable(start_fn)) { 782 + ant_value_t start_args[1] = { ctrl_obj }; 783 + ant_value_t start_result = sv_vm_call(js->vm, js, start_fn, transformer, start_args, 1, NULL, false); 784 + if (is_err(start_result)) { return start_result; } 785 + 786 + if (vtype(start_result) == T_PROMISE) { 787 + ant_value_t resolve_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj); 788 + ant_value_t reject_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj); 789 + ant_value_t then_fn = js_get(js, start_result, "then"); 790 + if (is_callable(then_fn)) { 791 + ant_value_t then_args[2] = { resolve_fn, reject_fn }; 792 + sv_vm_call(js->vm, js, then_fn, start_result, then_args, 2, NULL, false); 793 + } 794 + } 795 + 796 + if (vtype(start_result) != T_PROMISE) { 797 + ant_value_t resolved = js_mkpromise(js); 798 + js_resolve_promise(js, resolved, js_mkundef()); 799 + ant_value_t res_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj); 800 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj); 801 + ant_value_t then_fn = js_get(js, resolved, "then"); 802 + if (is_callable(then_fn)) { 803 + ant_value_t then_args[2] = { res_fn, rej_fn }; 804 + sv_vm_call(js->vm, js, then_fn, resolved, then_args, 2, NULL, false); 805 + } 806 + } 807 + } else { 808 + ant_value_t resolved = js_mkpromise(js); 809 + js_resolve_promise(js, resolved, js_mkundef()); 810 + ant_value_t res_fn = js_heavy_mkfun(js, ts_start_resolve, ts_obj); 811 + ant_value_t rej_fn = js_heavy_mkfun(js, ts_start_reject, ts_obj); 812 + ant_value_t then_fn = js_get(js, resolved, "then"); 813 + if (is_callable(then_fn)) { 814 + ant_value_t then_args[2] = { res_fn, rej_fn }; 815 + sv_vm_call(js->vm, js, then_fn, resolved, then_args, 2, NULL, false); 816 + } 817 + } 818 + 819 + return ts_obj; 820 + } 821 + 822 + static ant_value_t js_ts_ctrl_ctor(ant_t *js, ant_value_t *args, int nargs) { 823 + return js_mkerr_typed(js, JS_ERR_TYPE, "TransformStreamDefaultController cannot be constructed directly"); 824 + } 825 + 826 + void init_transform_stream_module(void) { 827 + ant_t *js = rt->js; 828 + ant_value_t g = js_glob(js); 829 + 830 + g_ts_ctrl_proto = js_mkobj(js); 831 + js_set_getter_desc(js, g_ts_ctrl_proto, "desiredSize", 11, js_mkfun(js_ts_ctrl_get_desired_size), JS_DESC_C); 832 + js_set(js, g_ts_ctrl_proto, "enqueue", js_mkfun(js_ts_ctrl_enqueue)); 833 + js_set_descriptor(js, g_ts_ctrl_proto, "enqueue", 7, JS_DESC_W | JS_DESC_C); 834 + js_set(js, g_ts_ctrl_proto, "error", js_mkfun(js_ts_ctrl_error)); 835 + js_set_descriptor(js, g_ts_ctrl_proto, "error", 5, JS_DESC_W | JS_DESC_C); 836 + js_set(js, g_ts_ctrl_proto, "terminate", js_mkfun(js_ts_ctrl_terminate)); 837 + js_set_descriptor(js, g_ts_ctrl_proto, "terminate", 9, JS_DESC_W | JS_DESC_C); 838 + js_set_sym(js, g_ts_ctrl_proto, get_toStringTag_sym(), js_mkstr(js, "TransformStreamDefaultController", 32)); 839 + 840 + ant_value_t ctrl_ctor = js_make_ctor(js, js_ts_ctrl_ctor, g_ts_ctrl_proto, "TransformStreamDefaultController", 32); 841 + js_set(js, g, "TransformStreamDefaultController", ctrl_ctor); 842 + js_set_descriptor(js, g, "TransformStreamDefaultController", 32, JS_DESC_W | JS_DESC_C); 843 + 844 + g_ts_proto = js_mkobj(js); 845 + js_set_getter_desc(js, g_ts_proto, "readable", 8, js_mkfun(js_ts_get_readable), JS_DESC_C); 846 + js_set_getter_desc(js, g_ts_proto, "writable", 8, js_mkfun(js_ts_get_writable), JS_DESC_C); 847 + js_set_sym(js, g_ts_proto, get_toStringTag_sym(), js_mkstr(js, "TransformStream", 15)); 848 + 849 + ant_value_t ts_ctor = js_make_ctor(js, js_ts_ctor, g_ts_proto, "TransformStream", 15); 850 + js_set(js, g, "TransformStream", ts_ctor); 851 + js_set_descriptor(js, g, "TransformStream", 15, JS_DESC_W | JS_DESC_C); 852 + } 853 + 854 + void gc_mark_transform_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 855 + mark(js, g_ts_proto); 856 + mark(js, g_ts_ctrl_proto); 857 + }
+31 -38
src/streams/writable.c
··· 13 13 #include "modules/abort.h" 14 14 #include "streams/writable.h" 15 15 16 - static ant_value_t g_ws_proto; 17 - static ant_value_t g_writer_proto; 18 - static ant_value_t g_controller_proto; 16 + ant_value_t g_ws_proto; 17 + ant_value_t g_ws_writer_proto; 18 + ant_value_t g_ws_controller_proto; 19 19 static ant_value_t g_close_sentinel; 20 20 21 21 ws_stream_t *ws_get_stream(ant_value_t obj) { ··· 179 179 return val; 180 180 } 181 181 182 - static void ws_default_controller_advance_queue_if_needed(ant_t *js, ant_value_t ctrl_obj); 183 - static void writable_stream_finish_erroring(ant_t *js, ant_value_t stream_obj); 184 - static void writable_stream_start_erroring(ant_t *js, ant_value_t stream_obj, ant_value_t reason); 185 - static void writable_stream_deal_with_rejection(ant_t *js, ant_value_t stream_obj, ant_value_t error); 186 - static void writable_stream_update_backpressure(ant_t *js, ant_value_t stream_obj, bool backpressure); 187 - static ant_value_t js_ws_writer_ctor(ant_t *js, ant_value_t *args, int nargs); 188 - 189 182 static bool ws_is_thenable(ant_t *js, ant_value_t val) { 190 183 if (vtype(val) == T_PROMISE) return true; 191 184 if (!is_object_type(val)) return false; ··· 306 299 return js_mkundef(); 307 300 } 308 301 309 - static void writable_stream_finish_erroring(ant_t *js, ant_value_t stream_obj) { 302 + void writable_stream_finish_erroring(ant_t *js, ant_value_t stream_obj) { 310 303 ws_stream_t *stream = ws_get_stream(stream_obj); 311 304 if (!stream || stream->state != WS_STATE_ERRORING) return; 312 305 stream->state = WS_STATE_ERRORED; ··· 580 573 } 581 574 } 582 575 583 - static void ws_default_controller_advance_queue_if_needed(ant_t *js, ant_value_t ctrl_obj) { 576 + void ws_default_controller_advance_queue_if_needed(ant_t *js, ant_value_t ctrl_obj) { 584 577 ws_controller_t *ctrl = ws_get_controller(ctrl_obj); 585 578 if (!ctrl || !ctrl->started) return; 586 579 ··· 966 959 return js_mkerr_typed(js, JS_ERR_TYPE, "WritableStream is already locked to a writer"); 967 960 968 961 ant_value_t obj = js_mkobj(js); 969 - ant_value_t proto = js_instance_proto_from_new_target(js, g_writer_proto); 962 + ant_value_t proto = js_instance_proto_from_new_target(js, g_ws_writer_proto); 970 963 if (is_object_type(proto)) js_set_proto_init(obj, proto); 971 964 972 965 ant_value_t closed = js_mkpromise(js); ··· 998 991 ant_value_t writer_args[1] = { stream_obj }; 999 992 ant_value_t saved = js->new_target; 1000 993 1001 - js->new_target = g_writer_proto; 994 + js->new_target = g_ws_writer_proto; 1002 995 ant_value_t writer = js_ws_writer_ctor(js, writer_args, 1); 1003 996 js->new_target = saved; 1004 997 ··· 1048 1041 1049 1042 ant_value_t writer_args[1] = { js->this_val }; 1050 1043 ant_value_t saved_new_target = js->new_target; 1051 - js->new_target = g_writer_proto; 1044 + js->new_target = g_ws_writer_proto; 1052 1045 ant_value_t writer = js_ws_writer_ctor(js, writer_args, 1); 1053 1046 js->new_target = saved_new_target; 1054 1047 return writer; ··· 1064 1057 ctrl->strategy_hwm = hwm; 1065 1058 1066 1059 ant_value_t ctrl_obj = js_mkobj(js); 1067 - js_set_proto_init(ctrl_obj, g_controller_proto); 1060 + js_set_proto_init(ctrl_obj, g_ws_controller_proto); 1068 1061 js_set_slot(ctrl_obj, SLOT_DATA, ANT_PTR(ctrl)); 1069 1062 js_set_slot(ctrl_obj, SLOT_ENTRIES, stream_obj); 1070 1063 js_set_slot(ctrl_obj, SLOT_WS_WRITE, write_fn); ··· 1234 1227 1235 1228 void gc_mark_writable_streams(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 1236 1229 mark(js, g_ws_proto); 1237 - mark(js, g_writer_proto); 1238 - mark(js, g_controller_proto); 1230 + mark(js, g_ws_writer_proto); 1231 + mark(js, g_ws_controller_proto); 1239 1232 mark(js, g_close_sentinel); 1240 1233 } 1241 1234 ··· 1244 1237 ant_value_t g = js_glob(js); 1245 1238 1246 1239 g_close_sentinel = js_mkobj(js); 1247 - g_controller_proto = js_mkobj(js); 1240 + g_ws_controller_proto = js_mkobj(js); 1248 1241 1249 - js_set_getter_desc(js, g_controller_proto, "signal", 6, js_mkfun(js_ws_controller_get_signal), JS_DESC_C); 1250 - js_set(js, g_controller_proto, "error", js_mkfun(js_ws_controller_error)); 1251 - js_set_descriptor(js, g_controller_proto, "error", 5, JS_DESC_W | JS_DESC_C); 1252 - js_set_sym(js, g_controller_proto, get_toStringTag_sym(), js_mkstr(js, "WritableStreamDefaultController", 31)); 1242 + js_set_getter_desc(js, g_ws_controller_proto, "signal", 6, js_mkfun(js_ws_controller_get_signal), JS_DESC_C); 1243 + js_set(js, g_ws_controller_proto, "error", js_mkfun(js_ws_controller_error)); 1244 + js_set_descriptor(js, g_ws_controller_proto, "error", 5, JS_DESC_W | JS_DESC_C); 1245 + js_set_sym(js, g_ws_controller_proto, get_toStringTag_sym(), js_mkstr(js, "WritableStreamDefaultController", 31)); 1253 1246 1254 - ant_value_t ctrl_ctor = js_make_ctor(js, js_ws_controller_ctor, g_controller_proto, "WritableStreamDefaultController", 31); 1247 + ant_value_t ctrl_ctor = js_make_ctor(js, js_ws_controller_ctor, g_ws_controller_proto, "WritableStreamDefaultController", 31); 1255 1248 js_set(js, g, "WritableStreamDefaultController", ctrl_ctor); 1256 1249 js_set_descriptor(js, g, "WritableStreamDefaultController", 31, JS_DESC_W | JS_DESC_C); 1257 1250 1258 - g_writer_proto = js_mkobj(js); 1259 - js_set_getter_desc(js, g_writer_proto, "closed", 6, js_mkfun(js_ws_writer_get_closed), JS_DESC_C); 1260 - js_set_getter_desc(js, g_writer_proto, "desiredSize", 11, js_mkfun(js_ws_writer_get_desired_size), JS_DESC_C); 1261 - js_set_getter_desc(js, g_writer_proto, "ready", 5, js_mkfun(js_ws_writer_get_ready), JS_DESC_C); 1262 - js_set(js, g_writer_proto, "abort", js_mkfun(js_ws_writer_abort)); 1263 - js_set_descriptor(js, g_writer_proto, "abort", 5, JS_DESC_W | JS_DESC_C); 1264 - js_set(js, g_writer_proto, "close", js_mkfun(js_ws_writer_close)); 1265 - js_set_descriptor(js, g_writer_proto, "close", 5, JS_DESC_W | JS_DESC_C); 1266 - js_set(js, g_writer_proto, "releaseLock", js_mkfun(js_ws_writer_release_lock)); 1267 - js_set_descriptor(js, g_writer_proto, "releaseLock", 11, JS_DESC_W | JS_DESC_C); 1268 - js_set(js, g_writer_proto, "write", js_mkfun(js_ws_writer_write)); 1269 - js_set_descriptor(js, g_writer_proto, "write", 5, JS_DESC_W | JS_DESC_C); 1270 - js_set_sym(js, g_writer_proto, get_toStringTag_sym(), js_mkstr(js, "WritableStreamDefaultWriter", 27)); 1251 + g_ws_writer_proto = js_mkobj(js); 1252 + js_set_getter_desc(js, g_ws_writer_proto, "closed", 6, js_mkfun(js_ws_writer_get_closed), JS_DESC_C); 1253 + js_set_getter_desc(js, g_ws_writer_proto, "desiredSize", 11, js_mkfun(js_ws_writer_get_desired_size), JS_DESC_C); 1254 + js_set_getter_desc(js, g_ws_writer_proto, "ready", 5, js_mkfun(js_ws_writer_get_ready), JS_DESC_C); 1255 + js_set(js, g_ws_writer_proto, "abort", js_mkfun(js_ws_writer_abort)); 1256 + js_set_descriptor(js, g_ws_writer_proto, "abort", 5, JS_DESC_W | JS_DESC_C); 1257 + js_set(js, g_ws_writer_proto, "close", js_mkfun(js_ws_writer_close)); 1258 + js_set_descriptor(js, g_ws_writer_proto, "close", 5, JS_DESC_W | JS_DESC_C); 1259 + js_set(js, g_ws_writer_proto, "releaseLock", js_mkfun(js_ws_writer_release_lock)); 1260 + js_set_descriptor(js, g_ws_writer_proto, "releaseLock", 11, JS_DESC_W | JS_DESC_C); 1261 + js_set(js, g_ws_writer_proto, "write", js_mkfun(js_ws_writer_write)); 1262 + js_set_descriptor(js, g_ws_writer_proto, "write", 5, JS_DESC_W | JS_DESC_C); 1263 + js_set_sym(js, g_ws_writer_proto, get_toStringTag_sym(), js_mkstr(js, "WritableStreamDefaultWriter", 27)); 1271 1264 1272 - ant_value_t writer_ctor = js_make_ctor(js, js_ws_writer_ctor, g_writer_proto, "WritableStreamDefaultWriter", 27); 1265 + ant_value_t writer_ctor = js_make_ctor(js, js_ws_writer_ctor, g_ws_writer_proto, "WritableStreamDefaultWriter", 27); 1273 1266 js_set(js, g, "WritableStreamDefaultWriter", writer_ctor); 1274 1267 js_set_descriptor(js, g, "WritableStreamDefaultWriter", 27, JS_DESC_W | JS_DESC_C); 1275 1268