Skip to content

Commit 112af69

Browse files
aduh95targos
authored andcommitted
fs: add docs and tests for AsyncIterable support in fh.writeFile
Refs: #37490 PR-URL: #39836 Reviewed-By: Nitzan Uziely <[email protected]>
1 parent 34c627e commit 112af69

File tree

3 files changed

+177
-18
lines changed

3 files changed

+177
-18
lines changed

doc/api/fs.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,9 @@ the end of the file.
499499
<!-- YAML
500500
added: v10.0.0
501501
changes:
502+
- version: v15.14.0
503+
pr-url: https://github.com/nodejs/node/pull/37490
504+
description: The `data` argument supports `AsyncIterable`, `Iterable` and `Stream`.
502505
- version: v14.12.0
503506
pr-url: https://github.com/nodejs/node/pull/34993
504507
description: The `data` parameter will stringify an object with an
@@ -509,14 +512,16 @@ changes:
509512
strings anymore.
510513
-->
511514
512-
* `data` {string|Buffer|TypedArray|DataView|Object}
515+
* `data` {string|Buffer|TypedArray|DataView|Object|AsyncIterable|Iterable
516+
|Stream}
513517
* `options` {Object|string}
514518
* `encoding` {string|null} The expected character encoding when `data` is a
515519
string. **Default:** `'utf8'`
516520
* Returns: {Promise}
517521
518522
Asynchronously writes data to a file, replacing the file if it already exists.
519-
`data` can be a string, a buffer, or an object with an own `toString` function
523+
`data` can be a string, a buffer, an {AsyncIterable} or {Iterable} object, or an
524+
object with an own `toString` function
520525
property. The promise is resolved with no arguments upon success.
521526
522527
If `options` is a string, then it specifies the `encoding`.
@@ -1295,7 +1300,7 @@ added: v10.0.0
12951300
changes:
12961301
- version: v15.14.0
12971302
pr-url: https://github.com/nodejs/node/pull/37490
1298-
description: The `data` argument supports `AsyncIterable`, `Iterable` & `Stream`.
1303+
description: The `data` argument supports `AsyncIterable`, `Iterable` and `Stream`.
12991304
- version: v15.2.0
13001305
pr-url: https://github.com/nodejs/node/pull/35993
13011306
description: The options argument may include an AbortSignal to abort an

test/parallel/test-fs-promises-file-handle-writeFile.js

+161-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const common = require('../common');
88
const fs = require('fs');
99
const { open, writeFile } = fs.promises;
1010
const path = require('path');
11+
const { Readable } = require('stream');
1112
const tmpdir = require('../common/tmpdir');
1213
const assert = require('assert');
1314
const tmpDir = tmpdir.path;
@@ -17,13 +18,15 @@ tmpdir.refresh();
1718
async function validateWriteFile() {
1819
const filePathForHandle = path.resolve(tmpDir, 'tmp-write-file2.txt');
1920
const fileHandle = await open(filePathForHandle, 'w+');
20-
const buffer = Buffer.from('Hello world'.repeat(100), 'utf8');
21+
try {
22+
const buffer = Buffer.from('Hello world'.repeat(100), 'utf8');
2123

22-
await fileHandle.writeFile(buffer);
23-
const readFileData = fs.readFileSync(filePathForHandle);
24-
assert.deepStrictEqual(buffer, readFileData);
25-
26-
await fileHandle.close();
24+
await fileHandle.writeFile(buffer);
25+
const readFileData = fs.readFileSync(filePathForHandle);
26+
assert.deepStrictEqual(buffer, readFileData);
27+
} finally {
28+
await fileHandle.close();
29+
}
2730
}
2831

2932
// Signal aborted while writing file
@@ -39,6 +42,155 @@ async function doWriteAndCancel() {
3942
});
4043
}
4144

42-
validateWriteFile()
43-
.then(doWriteAndCancel)
44-
.then(common.mustCall());
45+
const dest = path.resolve(tmpDir, 'tmp.txt');
46+
const otherDest = path.resolve(tmpDir, 'tmp-2.txt');
47+
const stream = Readable.from(['a', 'b', 'c']);
48+
const stream2 = Readable.from(['ümlaut', ' ', 'sechzig']);
49+
const iterable = {
50+
expected: 'abc',
51+
*[Symbol.iterator]() {
52+
yield 'a';
53+
yield 'b';
54+
yield 'c';
55+
}
56+
};
57+
function iterableWith(value) {
58+
return {
59+
*[Symbol.iterator]() {
60+
yield value;
61+
}
62+
};
63+
}
64+
const bufferIterable = {
65+
expected: 'abc',
66+
*[Symbol.iterator]() {
67+
yield Buffer.from('a');
68+
yield Buffer.from('b');
69+
yield Buffer.from('c');
70+
}
71+
};
72+
const asyncIterable = {
73+
expected: 'abc',
74+
async* [Symbol.asyncIterator]() {
75+
yield 'a';
76+
yield 'b';
77+
yield 'c';
78+
}
79+
};
80+
81+
async function doWriteStream() {
82+
const fileHandle = await open(dest, 'w+');
83+
try {
84+
await fileHandle.writeFile(stream);
85+
const expected = 'abc';
86+
const data = fs.readFileSync(dest, 'utf-8');
87+
assert.deepStrictEqual(data, expected);
88+
} finally {
89+
await fileHandle.close();
90+
}
91+
}
92+
93+
async function doWriteStreamWithCancel() {
94+
const controller = new AbortController();
95+
const { signal } = controller;
96+
process.nextTick(() => controller.abort());
97+
const fileHandle = await open(otherDest, 'w+');
98+
try {
99+
await assert.rejects(
100+
fileHandle.writeFile(stream, { signal }),
101+
{ name: 'AbortError' }
102+
);
103+
} finally {
104+
await fileHandle.close();
105+
}
106+
}
107+
108+
async function doWriteIterable() {
109+
const fileHandle = await open(dest, 'w+');
110+
try {
111+
await fileHandle.writeFile(iterable);
112+
const data = fs.readFileSync(dest, 'utf-8');
113+
assert.deepStrictEqual(data, iterable.expected);
114+
} finally {
115+
await fileHandle.close();
116+
}
117+
}
118+
119+
async function doWriteInvalidIterable() {
120+
const fileHandle = await open(dest, 'w+');
121+
try {
122+
await Promise.all(
123+
[42, 42n, {}, Symbol('42'), true, undefined, null, NaN].map((value) =>
124+
assert.rejects(
125+
fileHandle.writeFile(iterableWith(value)),
126+
{ code: 'ERR_INVALID_ARG_TYPE' }
127+
)
128+
)
129+
);
130+
} finally {
131+
await fileHandle.close();
132+
}
133+
}
134+
135+
async function doWriteIterableWithEncoding() {
136+
const fileHandle = await open(dest, 'w+');
137+
try {
138+
await fileHandle.writeFile(stream2, 'latin1');
139+
const expected = 'ümlaut sechzig';
140+
const data = fs.readFileSync(dest, 'latin1');
141+
assert.deepStrictEqual(data, expected);
142+
} finally {
143+
await fileHandle.close();
144+
}
145+
}
146+
147+
async function doWriteBufferIterable() {
148+
const fileHandle = await open(dest, 'w+');
149+
try {
150+
await fileHandle.writeFile(bufferIterable);
151+
const data = fs.readFileSync(dest, 'utf-8');
152+
assert.deepStrictEqual(data, bufferIterable.expected);
153+
} finally {
154+
await fileHandle.close();
155+
}
156+
}
157+
158+
async function doWriteAsyncIterable() {
159+
const fileHandle = await open(dest, 'w+');
160+
try {
161+
await fileHandle.writeFile(asyncIterable);
162+
const data = fs.readFileSync(dest, 'utf-8');
163+
assert.deepStrictEqual(data, asyncIterable.expected);
164+
} finally {
165+
await fileHandle.close();
166+
}
167+
}
168+
169+
async function doWriteInvalidValues() {
170+
const fileHandle = await open(dest, 'w+');
171+
try {
172+
await Promise.all(
173+
[42, 42n, {}, Symbol('42'), true, undefined, null, NaN].map((value) =>
174+
assert.rejects(
175+
fileHandle.writeFile(value),
176+
{ code: 'ERR_INVALID_ARG_TYPE' }
177+
)
178+
)
179+
);
180+
} finally {
181+
await fileHandle.close();
182+
}
183+
}
184+
185+
(async () => {
186+
await validateWriteFile();
187+
await doWriteAndCancel();
188+
await doWriteStream();
189+
await doWriteStreamWithCancel();
190+
await doWriteIterable();
191+
await doWriteInvalidIterable();
192+
await doWriteIterableWithEncoding();
193+
await doWriteBufferIterable();
194+
await doWriteAsyncIterable();
195+
await doWriteInvalidValues();
196+
})().then(common.mustCall());

test/parallel/test-fs-promises-writefile.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ async function doWriteStreamWithCancel() {
7474
const controller = new AbortController();
7575
const { signal } = controller;
7676
process.nextTick(() => controller.abort());
77-
assert.rejects(fsPromises.writeFile(otherDest, stream, { signal }), {
78-
name: 'AbortError'
79-
});
77+
await assert.rejects(
78+
fsPromises.writeFile(otherDest, stream, { signal }),
79+
{ name: 'AbortError' }
80+
);
8081
}
8182

8283
async function doWriteIterable() {
@@ -134,9 +135,10 @@ async function doWriteWithCancel() {
134135
const controller = new AbortController();
135136
const { signal } = controller;
136137
process.nextTick(() => controller.abort());
137-
assert.rejects(fsPromises.writeFile(otherDest, buffer, { signal }), {
138-
name: 'AbortError'
139-
});
138+
await assert.rejects(
139+
fsPromises.writeFile(otherDest, buffer, { signal }),
140+
{ name: 'AbortError' }
141+
);
140142
}
141143

142144
async function doAppend() {

0 commit comments

Comments
 (0)