Skip to content

Commit 6f21783

Browse files
author
HiroyukiYagihashi
committed
fixup! fs: add support for async iterators to fs.writeFile
Fixes: #38075
1 parent 785d76d commit 6f21783

File tree

2 files changed

+83
-15
lines changed

2 files changed

+83
-15
lines changed

lib/fs.js

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,21 +2045,16 @@ function lutimesSync(path, atime, mtime) {
20452045
function writeAll(
20462046
fd, isUserFd, buffer, offset, length, signal, encoding, callback) {
20472047
if (signal?.aborted) {
2048-
const abortError = new AbortError();
2049-
if (isUserFd) {
2050-
callback(abortError);
2051-
} else {
2052-
fs.close(fd, (err) => {
2053-
callback(aggregateTwoErrors(err, abortError));
2054-
});
2055-
}
2048+
handleWriteAllErrorCallback(fd, isUserFd, new AbortError(), callback);
20562049
return;
20572050
}
20582051

20592052
if (isCustomIterable(buffer)) {
20602053
writeAllCustomIterable(
20612054
fd, isUserFd, buffer, offset, length, signal, encoding, callback)
2062-
.catch((reason) => { throw reason; });
2055+
.catch((reason) => {
2056+
handleWriteAllErrorCallback(fd, isUserFd, reason, callback);
2057+
});
20632058
return;
20642059
}
20652060
fs.write(fd, buffer, offset, length, null, (writeErr, written) => {
@@ -2082,20 +2077,29 @@ function writeAll(
20822077

20832078
async function writeAllCustomIterable(
20842079
fd, isUserFd, buffer, offset, length, signal, encoding, callback) {
2080+
if (signal?.aborted) {
2081+
handleWriteAllErrorCallback(fd, isUserFd, new AbortError(), callback);
2082+
return;
2083+
}
2084+
20852085
const result = await buffer.next();
20862086
if (result.done) {
2087-
fs.close(fd, callback);
2087+
if (isUserFd) {
2088+
callback(null);
2089+
} else {
2090+
fs.close(fd, callback);
2091+
}
20882092
return;
20892093
}
2090-
const resultValue = result.value.toString();
2091-
fs.write(fd, resultValue, undefined,
2092-
isArrayBufferView(buffer) ? resultValue.byteLength : encoding,
2094+
const resultValue = isArrayBufferView(result.value) ?
2095+
result.value : Buffer.from(String(result.value), encoding);
2096+
fs.write(fd, resultValue, offset, resultValue.byteLength,
20932097
null, (writeErr, _) => {
20942098
if (writeErr) {
20952099
handleWriteAllErrorCallback(fd, isUserFd, writeErr, callback);
20962100
} else {
2097-
writeAll(fd, isUserFd, buffer, offset,
2098-
length, signal, encoding, callback);
2101+
writeAllCustomIterable(fd, isUserFd, buffer, offset, length,
2102+
signal, encoding, callback);
20992103
}
21002104
}
21012105
);

test/parallel/test-fs-write-file-async-iterators.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ tmpdir.refresh();
4444
);
4545
}
4646

47+
{
48+
const filenameBufferIterableWithEncoding =
49+
join(tmpdir.path, 'testBufferIterableWithEncoding.txt');
50+
const bufferIterableWithEncoding = {
51+
expected: 'ümlaut sechzig',
52+
*[Symbol.iterator]() {
53+
yield Buffer.from('ümlaut');
54+
yield Buffer.from(' ');
55+
yield Buffer.from('sechzig');
56+
}
57+
};
58+
59+
fs.writeFile(
60+
filenameBufferIterableWithEncoding,
61+
bufferIterableWithEncoding, common.mustSucceed(() => {
62+
const data = fs.readFileSync(filenameBufferIterableWithEncoding, 'utf-8');
63+
assert.strictEqual(bufferIterableWithEncoding.expected, data);
64+
})
65+
);
66+
}
4767

4868
{
4969
const filenameAsyncIterable = join(tmpdir.path, 'testAsyncIterable.txt');
@@ -86,3 +106,47 @@ tmpdir.refresh();
86106
})
87107
);
88108
}
109+
110+
{
111+
const controller = new AbortController();
112+
const signal = controller.signal;
113+
const filenameIterableAbort = join(tmpdir.path, 'testIterableAbort.txt');
114+
const iterable = {
115+
expected: 'abc',
116+
*[Symbol.iterator]() {
117+
yield 'a';
118+
yield 'b';
119+
yield 'c';
120+
}
121+
};
122+
123+
124+
fs.writeFile(filenameIterableAbort,
125+
iterable, { signal }, common.mustCall((err) => {
126+
assert.strictEqual(err.name, 'AbortError');
127+
}));
128+
129+
controller.abort();
130+
}
131+
132+
{
133+
const controller = new AbortController();
134+
const signal = controller.signal;
135+
const filenameAsyncIterableAbort =
136+
join(tmpdir.path, 'testAsyncIterableAbort.txt');
137+
const asyncIterable = {
138+
expected: 'abc',
139+
*[Symbol.asyncIterator]() {
140+
yield 'a';
141+
yield 'b';
142+
yield 'c';
143+
}
144+
};
145+
146+
fs.writeFile(filenameAsyncIterableAbort,
147+
asyncIterable, { signal }, common.mustCall((err) => {
148+
assert.strictEqual(err.name, 'AbortError');
149+
}));
150+
151+
process.nextTick(() => controller.abort());
152+
}

0 commit comments

Comments
 (0)