Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/api/buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,18 @@ added:
Returns a promise that fulfills with the contents of the `Blob` decoded as a
UTF-8 string.

### `blob.textStream()`

<!-- YAML
added: REPLACEME
-->

* Returns: {ReadableStream}

Returns a new `ReadableStream` that allows the content of the `Blob` to be read
as a stream of UTF-8 decoded strings. It is equivalent to piping
[`blob.stream()`][] through a [`TextDecoderStream`][] set up with UTF-8.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "set up with" matches the spec operation, but sounds a bit unnatural here.

Suggested change
[`blob.stream()`][] through a [`TextDecoderStream`][] set up with UTF-8.
[`blob.stream()`][] through a UTF-8 [`TextDecoderStream`][].


### `blob.type`

<!-- YAML
Expand Down Expand Up @@ -5610,10 +5622,12 @@ introducing security vulnerabilities into an application.
[`String.prototype.indexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
[`String.prototype.lastIndexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf
[`String.prototype.length`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length
[`TextDecoderStream`]: webstreams.md#class-textdecoderstream
[`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from
[`TypedArray.prototype.set()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set
[`TypedArray.prototype.slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice
[`TypedArray.prototype.subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray
[`blob.stream()`]: #blobstream
[`buf.buffer`]: #bufbuffer
[`buf.compare()`]: #bufcomparetarget-targetstart-targetend-sourcestart-sourceend
[`buf.entries()`]: #bufentries
Expand Down
20 changes: 20 additions & 0 deletions lib/internal/blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const kNotCloneable = Symbol('kNotCloneable');
const disallowedTypeCharacters = /[^\u{0020}-\u{007E}]/u;

let ReadableStream;
let TextDecoderStream;

const enc = new TextEncoder();
let dec;
Expand All @@ -100,6 +101,13 @@ function lazyReadableStream(options) {
return new ReadableStream(options);
}

function lazyTextDecoderStream() {
// eslint-disable-next-line no-global-assign
TextDecoderStream ??=
require('internal/webstreams/encoding').TextDecoderStream;
return new TextDecoderStream();
}

const { EOL } = require('internal/constants');

function isBlob(object) {
Expand Down Expand Up @@ -331,6 +339,17 @@ class Blob {
throw new ERR_INVALID_THIS('Blob');
return createBlobReaderStream(this[kHandle].getReader());
}

/**
* @returns {ReadableStream}
*/
textStream() {
if (!isBlob(this))
throw new ERR_INVALID_THIS('Blob');
const stream = createBlobReaderStream(this[kHandle].getReader());
const decoder = lazyTextDecoderStream();
return stream.pipeThrough(decoder);
}
}

function TransferableBlob(handle, length, type = '') {
Expand Down Expand Up @@ -364,6 +383,7 @@ ObjectDefineProperties(Blob.prototype, {
type: kEnumerableProperty,
slice: kEnumerableProperty,
stream: kEnumerableProperty,
textStream: kEnumerableProperty,
text: kEnumerableProperty,
arrayBuffer: kEnumerableProperty,
bytes: kEnumerableProperty,
Expand Down
21 changes: 20 additions & 1 deletion test/parallel/test-blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

const common = require('../common');
const assert = require('assert');
const { Blob } = require('buffer');
const { Blob, File } = require('buffer');
const { inspect } = require('util');
const { EOL } = require('os');
const { kState } = require('internal/webstreams/util');
Expand Down Expand Up @@ -524,3 +524,22 @@ assert.throws(() => new Blob({}), {
Blob.prototype.arrayBuffer = arrayBuffer;
}
})().then(common.mustCall());

{
assert.strictEqual(typeof Blob.prototype.textStream, 'function');
assert.strictEqual(typeof File.prototype.textStream, 'function');
assert.strictEqual(File.prototype.textStream, Blob.prototype.textStream);
}

(async () => {
const smiley = Buffer.from('😀', 'utf8');
const blob = new Blob(['hello ', smiley.subarray(0, 2), smiley.subarray(2)]);
const stream = blob.textStream();
assert.ok(stream instanceof ReadableStream);
let result = '';
for await (const chunk of stream) {
assert.strictEqual(typeof chunk, 'string');
result += chunk;
}
assert.strictEqual(result, 'hello 😀');
})().then(common.mustCall());
Loading