Skip to content

Commit b4a86c9

Browse files
committed
fs: add docs and tests for AsyncIterable support in fh.writeFile
Refs: nodejs#37490
1 parent af45be7 commit b4a86c9

File tree

2 files changed

+130
-5
lines changed

2 files changed

+130
-5
lines changed

doc/api/fs.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,9 @@ the end of the file.
545545
<!-- YAML
546546
added: v10.0.0
547547
changes:
548+
- version: v15.14.0
549+
pr-url: https://github.com/nodejs/node/pull/37490
550+
description: The `data` argument supports `AsyncIterable`, `Iterable` & `Stream`.
548551
- version: v14.12.0
549552
pr-url: https://github.com/nodejs/node/pull/34993
550553
description: The `data` parameter will stringify an object with an
@@ -555,14 +558,15 @@ changes:
555558
strings anymore.
556559
-->
557560
558-
* `data` {string|Buffer|TypedArray|DataView|Object}
561+
* `data` {string|Buffer|TypedArray|DataView|Object|AsyncIterable|Iterable|Stream}
559562
* `options` {Object|string}
560563
* `encoding` {string|null} The expected character encoding when `data` is a
561564
string. **Default:** `'utf8'`
562565
* Returns: {Promise}
563566
564567
Asynchronously writes data to a file, replacing the file if it already exists.
565-
`data` can be a string, a buffer, or an object with an own `toString` function
568+
`data` can be a string, a buffer, an {AsyncIterable} or {Iterable} object, or an
569+
object with an own `toString` function
566570
property. The promise is resolved with no arguments upon success.
567571
568572
If `options` is a string, then it specifies the `encoding`.

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

+124-3
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;
@@ -43,6 +44,126 @@ async function doWriteAndCancel() {
4344
}
4445
}
4546

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

0 commit comments

Comments
 (0)