Skip to content

Commit d48ed95

Browse files
jasnellflakey5
authored andcommitted
src, lib: fixup lint and format issues for DataQueue/Blob
Co-authored-by: flakey5 <73616808+flakey5@users.noreply.github.com> PR-URL: #45258 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 36f36b9 commit d48ed95

18 files changed

+1251
-1127
lines changed

doc/api/fs.md

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,6 @@ When operating on file handles, the mode cannot be changed from what it was set
202202
to with [`fsPromises.open()`][]. Therefore, this is equivalent to
203203
[`filehandle.writeFile()`][].
204204

205-
#### `filehandle.blob()`
206-
<!-- YAML
207-
added: REPLACEME
208-
-->
209-
210-
> Stability: 1 - Experimental
211-
212-
Returns a {Blob} whose data is backed by this file.
213-
214205
#### `filehandle.chmod(mode)`
215206

216207
<!-- YAML
@@ -3333,6 +3324,45 @@ a colon, Node.js will open a file system stream, as described by
33333324
Functions based on `fs.open()` exhibit this behavior as well:
33343325
`fs.writeFile()`, `fs.readFile()`, etc.
33353326
3327+
### `fs.openAsBlob(path[, options])`
3328+
3329+
<!-- YAML
3330+
added: REPLACEME
3331+
-->
3332+
3333+
> Stability: 1 - Experimental
3334+
3335+
* `path` {string|Buffer|URL}
3336+
* `options` {Object}
3337+
* `type` {string} An optional mime type for the blob.
3338+
* Return: {Promise} containing {Blob}
3339+
3340+
Returns a {Blob} whose data is backed by the given file.
3341+
3342+
The file must not be modified after the {Blob} is created. Any modifications
3343+
will cause reading the {Blob} data to fail with a `DOMException`.
3344+
error. Synchronous stat operations on the file when the `Blob` is created, and
3345+
before each read in order to detect whether the file data has been modified
3346+
on disk.
3347+
3348+
```mjs
3349+
import { openAsBlob } from 'node:fs';
3350+
3351+
const blob = await openAsBlob('the.file.txt');
3352+
const ab = await blob.arrayBuffer();
3353+
blob.stream();
3354+
```
3355+
3356+
```cjs
3357+
const { openAsBlob } = require('node:fs');
3358+
3359+
(async () => {
3360+
const blob = await openAsBlob('the.file.txt');
3361+
const ab = await blob.arrayBuffer();
3362+
blob.stream();
3363+
})();
3364+
```
3365+
33363366
### `fs.opendir(path[, options], callback)`
33373367
33383368
<!-- YAML

lib/fs.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const {
3232
ObjectDefineProperties,
3333
ObjectDefineProperty,
3434
Promise,
35+
PromiseResolve,
3536
ReflectApply,
3637
SafeMap,
3738
SafeSet,
@@ -62,6 +63,9 @@ const { isArrayBufferView } = require('internal/util/types');
6263
// it's re-initialized after deserialization.
6364

6465
const binding = internalBinding('fs');
66+
67+
const { createBlobFromFilePath } = require('internal/blob');
68+
6569
const { Buffer } = require('buffer');
6670
const {
6771
aggregateTwoErrors,
@@ -586,6 +590,20 @@ function openSync(path, flags, mode) {
586590
return result;
587591
}
588592

593+
/**
594+
* @param {string | Buffer | URL } path
595+
* @returns {Promise<Blob>}
596+
*/
597+
function openAsBlob(path, options = kEmptyObject) {
598+
validateObject(options, 'options');
599+
const type = options.type || '';
600+
validateString(type, 'options.type');
601+
// The underlying implementation here returns the Blob synchronously for now.
602+
// To give ourselves flexibility to maybe return the Blob asynchronously,
603+
// this API returns a Promise.
604+
return PromiseResolve(createBlobFromFilePath(getValidatedPath(path), { type }));
605+
}
606+
589607
/**
590608
* Reads file from the specified `fd` (file descriptor).
591609
* @param {number} fd
@@ -3022,6 +3040,7 @@ module.exports = fs = {
30223040
mkdtempSync,
30233041
open,
30243042
openSync,
3043+
openAsBlob,
30253044
readdir,
30263045
readdirSync,
30273046
read,

lib/internal/blob.js

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const {
4+
ArrayBuffer,
45
ArrayFrom,
56
MathMax,
67
MathMin,
@@ -21,7 +22,7 @@ const {
2122

2223
const {
2324
createBlob: _createBlob,
24-
createBlobFromFileHandle: _createBlobFromFileHandle,
25+
createBlobFromFilePath: _createBlobFromFilePath,
2526
concat,
2627
getDataObject,
2728
} = internalBinding('blob');
@@ -48,6 +49,7 @@ const {
4849
customInspectSymbol: kInspect,
4950
kEmptyObject,
5051
kEnumerableProperty,
52+
lazyDOMException,
5153
} = require('internal/util');
5254
const { inspect } = require('internal/util/inspect');
5355

@@ -58,14 +60,17 @@ const {
5860
ERR_INVALID_THIS,
5961
ERR_BUFFER_TOO_LARGE,
6062
},
61-
errnoException,
6263
} = require('internal/errors');
6364

6465
const {
6566
isUint32,
6667
validateDictionary,
6768
} = require('internal/validators');
6869

70+
const {
71+
CountQueuingStrategy,
72+
} = require('internal/webstreams/queuingstrategies');
73+
6974
const kHandle = Symbol('kHandle');
7075
const kType = Symbol('kType');
7176
const kLength = Symbol('kLength');
@@ -265,16 +270,23 @@ class Blob {
265270
return PromiseResolve(new ArrayBuffer(0));
266271
}
267272

268-
const { promise, resolve } = createDeferredPromise();
273+
const { promise, resolve, reject } = createDeferredPromise();
269274
const reader = this[kHandle].getReader();
270275
const buffers = [];
271276
const readNext = () => {
272277
reader.pull((status, buffer) => {
273-
if (status === -1) {
278+
if (status === 0) {
274279
// EOS, concat & resolve
275280
// buffer should be undefined here
276281
resolve(concat(buffers));
277282
return;
283+
} else if (status < 0) {
284+
// The read could fail for many different reasons when reading
285+
// from a non-memory resident blob part (e.g. file-backed blob).
286+
// The error details the system error code.
287+
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
288+
reject(error);
289+
return;
278290
}
279291
if (buffer !== undefined)
280292
buffers.push(buffer);
@@ -319,7 +331,7 @@ class Blob {
319331
},
320332
pull(c) {
321333
const { promise, resolve, reject } = createDeferredPromise();
322-
this.pendingPulls.push({resolve, reject});
334+
this.pendingPulls.push({ resolve, reject });
323335
reader.pull((status, buffer) => {
324336
// If pendingPulls is empty here, the stream had to have
325337
// been canceled, and we don't really care about the result.
@@ -328,18 +340,24 @@ class Blob {
328340
return;
329341
}
330342
const pending = this.pendingPulls.shift();
331-
if (status === -1 || (status === 0 && buffer === undefined)) {
343+
if (status === 0) {
332344
// EOS
333345
c.close();
334346
pending.resolve();
335347
return;
336348
} else if (status < 0) {
337-
const error = errnoException(status, 'read');
349+
// The read could fail for many different reasons when reading
350+
// from a non-memory resident blob part (e.g. file-backed blob).
351+
// The error details the system error code.
352+
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
353+
338354
c.error(error);
339355
pending.reject(error);
340356
return;
341357
}
342-
c.enqueue(new Uint8Array(buffer));
358+
if (buffer !== undefined) {
359+
c.enqueue(new Uint8Array(buffer));
360+
}
343361
pending.resolve();
344362
});
345363
return promise;
@@ -422,16 +440,22 @@ function resolveObjectURL(url) {
422440
}
423441
}
424442

425-
function createBlobFromFileHandle(handle) {
426-
const [blob, length] = _createBlobFromFileHandle(handle);
427-
return createBlob(blob, length);
443+
// TODO(@jasnell): Now that the File class exists, we might consider having
444+
// this return a `File` instead of a `Blob`.
445+
function createBlobFromFilePath(path, options) {
446+
const maybeBlob = _createBlobFromFilePath(path);
447+
if (maybeBlob === undefined) {
448+
return lazyDOMException('The blob could not be read', 'NotReadableError');
449+
}
450+
const { 0: blob, 1: length } = maybeBlob;
451+
return createBlob(blob, length, options?.type);
428452
}
429453

430454
module.exports = {
431455
Blob,
432456
ClonedBlob,
433457
createBlob,
434-
createBlobFromFileHandle,
458+
createBlobFromFilePath,
435459
isBlob,
436460
kHandle,
437461
resolveObjectURL,

lib/internal/fs/promises.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ const {
2525
S_IFREG
2626
} = constants;
2727

28-
const { createBlobFromFileHandle } = require('internal/blob');
29-
3028
const binding = internalBinding('fs');
3129
const { Buffer } = require('buffer');
3230

@@ -312,14 +310,6 @@ class FileHandle extends EventEmitterMixin(JSTransferable) {
312310
return new WriteStream(undefined, { ...options, fd: this });
313311
}
314312

315-
/**
316-
* @typedef {import('../blob').Blob} Blob
317-
* @returns {Blob}
318-
*/
319-
blob() {
320-
return createBlobFromFileHandle(this[kHandle]);
321-
}
322-
323313
[kTransfer]() {
324314
if (this[kClosePromise] || this[kRefs] > 1) {
325315
throw lazyDOMException('Cannot transfer FileHandle while in use',

src/async_wrap.h

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -31,49 +31,49 @@
3131

3232
namespace node {
3333

34-
#define NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \
35-
V(NONE) \
36-
V(DIRHANDLE) \
37-
V(DNSCHANNEL) \
38-
V(ELDHISTOGRAM) \
39-
V(FILEHANDLE) \
40-
V(FILEHANDLECLOSEREQ) \
41-
V(BLOBREADER) \
42-
V(FSEVENTWRAP) \
43-
V(FSREQCALLBACK) \
44-
V(FSREQPROMISE) \
45-
V(GETADDRINFOREQWRAP) \
46-
V(GETNAMEINFOREQWRAP) \
47-
V(HEAPSNAPSHOT) \
48-
V(HTTP2SESSION) \
49-
V(HTTP2STREAM) \
50-
V(HTTP2PING) \
51-
V(HTTP2SETTINGS) \
52-
V(HTTPINCOMINGMESSAGE) \
53-
V(HTTPCLIENTREQUEST) \
54-
V(JSSTREAM) \
55-
V(JSUDPWRAP) \
56-
V(MESSAGEPORT) \
57-
V(PIPECONNECTWRAP) \
58-
V(PIPESERVERWRAP) \
59-
V(PIPEWRAP) \
60-
V(PROCESSWRAP) \
61-
V(PROMISE) \
62-
V(QUERYWRAP) \
63-
V(SHUTDOWNWRAP) \
64-
V(SIGNALWRAP) \
65-
V(STATWATCHER) \
66-
V(STREAMPIPE) \
67-
V(TCPCONNECTWRAP) \
68-
V(TCPSERVERWRAP) \
69-
V(TCPWRAP) \
70-
V(TTYWRAP) \
71-
V(UDPSENDWRAP) \
72-
V(UDPWRAP) \
73-
V(SIGINTWATCHDOG) \
74-
V(WORKER) \
75-
V(WORKERHEAPSNAPSHOT) \
76-
V(WRITEWRAP) \
34+
#define NODE_ASYNC_NON_CRYPTO_PROVIDER_TYPES(V) \
35+
V(NONE) \
36+
V(DIRHANDLE) \
37+
V(DNSCHANNEL) \
38+
V(ELDHISTOGRAM) \
39+
V(FILEHANDLE) \
40+
V(FILEHANDLECLOSEREQ) \
41+
V(BLOBREADER) \
42+
V(FSEVENTWRAP) \
43+
V(FSREQCALLBACK) \
44+
V(FSREQPROMISE) \
45+
V(GETADDRINFOREQWRAP) \
46+
V(GETNAMEINFOREQWRAP) \
47+
V(HEAPSNAPSHOT) \
48+
V(HTTP2SESSION) \
49+
V(HTTP2STREAM) \
50+
V(HTTP2PING) \
51+
V(HTTP2SETTINGS) \
52+
V(HTTPINCOMINGMESSAGE) \
53+
V(HTTPCLIENTREQUEST) \
54+
V(JSSTREAM) \
55+
V(JSUDPWRAP) \
56+
V(MESSAGEPORT) \
57+
V(PIPECONNECTWRAP) \
58+
V(PIPESERVERWRAP) \
59+
V(PIPEWRAP) \
60+
V(PROCESSWRAP) \
61+
V(PROMISE) \
62+
V(QUERYWRAP) \
63+
V(SHUTDOWNWRAP) \
64+
V(SIGNALWRAP) \
65+
V(STATWATCHER) \
66+
V(STREAMPIPE) \
67+
V(TCPCONNECTWRAP) \
68+
V(TCPSERVERWRAP) \
69+
V(TCPWRAP) \
70+
V(TTYWRAP) \
71+
V(UDPSENDWRAP) \
72+
V(UDPWRAP) \
73+
V(SIGINTWATCHDOG) \
74+
V(WORKER) \
75+
V(WORKERHEAPSNAPSHOT) \
76+
V(WRITEWRAP) \
7777
V(ZLIB)
7878

7979
#if HAVE_OPENSSL

0 commit comments

Comments
 (0)