Skip to content

Commit ecf3619

Browse files
crowlKatsdsherret
authored andcommitted
feat: allow passing a ReadableStream to Deno.writeFile/Deno.writeTextFile (#17329)
Closes #13229
1 parent 4909798 commit ecf3619

File tree

4 files changed

+70
-14
lines changed

4 files changed

+70
-14
lines changed

cli/tests/unit/write_file_test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,3 +393,19 @@ function pathExists(path: string | URL) {
393393
return false;
394394
}
395395
}
396+
397+
Deno.test(
398+
{ permissions: { read: true, write: true } },
399+
async function writeFileStream() {
400+
const stream = new ReadableStream({
401+
pull(controller) {
402+
controller.enqueue(new Uint8Array([1]));
403+
controller.enqueue(new Uint8Array([2]));
404+
controller.close();
405+
},
406+
});
407+
const filename = Deno.makeTempDirSync() + "/test.txt";
408+
await Deno.writeFile(filename, stream);
409+
assertEquals(Deno.readFileSync(filename), new Uint8Array([1, 2]));
410+
},
411+
);

cli/tests/unit/write_text_file_test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,19 @@ Deno.test(
198198
assertEquals(Deno.readTextFileSync(filename), "Hello");
199199
},
200200
);
201+
202+
Deno.test(
203+
{ permissions: { read: true, write: true } },
204+
async function writeTextFileStream() {
205+
const stream = new ReadableStream({
206+
pull(controller) {
207+
controller.enqueue("Hello");
208+
controller.enqueue("World");
209+
controller.close();
210+
},
211+
});
212+
const filename = Deno.makeTempDirSync() + "/test.txt";
213+
await Deno.writeTextFile(filename, stream);
214+
assertEquals(Deno.readTextFileSync(filename), "HelloWorld");
215+
},
216+
);

cli/tsc/dts/lib.deno.ns.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,7 +3364,7 @@ declare namespace Deno {
33643364
*/
33653365
export function writeFile(
33663366
path: string | URL,
3367-
data: Uint8Array,
3367+
data: Uint8Array | ReadableStream<Uint8Array>,
33683368
options?: WriteFileOptions,
33693369
): Promise<void>;
33703370

@@ -3407,7 +3407,7 @@ declare namespace Deno {
34073407
*/
34083408
export function writeTextFile(
34093409
path: string | URL,
3410-
data: string,
3410+
data: string | ReadableStream<string>,
34113411
options?: WriteFileOptions,
34123412
): Promise<void>;
34133413

runtime/js/40_write_file.js

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
const ops = core.ops;
66
const { abortSignal } = window.__bootstrap;
77
const { pathFromURL } = window.__bootstrap.util;
8+
const { open } = window.__bootstrap.files;
9+
const { ReadableStreamPrototype } = window.__bootstrap.streams;
10+
const { ObjectPrototypeIsPrototypeOf } = window.__bootstrap.primordials;
811

912
function writeFileSync(
1013
path,
@@ -36,16 +39,29 @@
3639
options.signal[abortSignal.add](abortHandler);
3740
}
3841
try {
39-
await core.opAsync(
40-
"op_write_file_async",
41-
pathFromURL(path),
42-
options.mode,
43-
options.append ?? false,
44-
options.create ?? true,
45-
options.createNew ?? false,
46-
data,
47-
cancelRid,
48-
);
42+
if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, data)) {
43+
const file = await open(path, {
44+
mode: options.mode,
45+
append: options.append ?? false,
46+
create: options.create ?? true,
47+
createNew: options.createNew ?? false,
48+
write: true,
49+
});
50+
await data.pipeTo(file.writable, {
51+
signal: options.signal,
52+
});
53+
} else {
54+
await core.opAsync(
55+
"op_write_file_async",
56+
pathFromURL(path),
57+
options.mode,
58+
options.append ?? false,
59+
options.create ?? true,
60+
options.createNew ?? false,
61+
data,
62+
cancelRid,
63+
);
64+
}
4965
} finally {
5066
if (options.signal) {
5167
options.signal[abortSignal.remove](abortHandler);
@@ -70,8 +86,16 @@
7086
data,
7187
options = {},
7288
) {
73-
const encoder = new TextEncoder();
74-
return writeFile(path, encoder.encode(data), options);
89+
if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, data)) {
90+
return writeFile(
91+
path,
92+
data.pipeThrough(new TextEncoderStream()),
93+
options,
94+
);
95+
} else {
96+
const encoder = new TextEncoder();
97+
return writeFile(path, encoder.encode(data), options);
98+
}
7599
}
76100

77101
window.__bootstrap.writeFile = {

0 commit comments

Comments
 (0)