mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
buffer: extract Blob's .arrayBuffer() & webidl changes
- Extracts Blob.prototype.arrayBuffer so it cannot be overridden in .text(), etc. - Make .bytes() enumerable. I guess the WPT runner is not running the idlharness tests? - Make .text() return a Promise, rather than being explicitly async. This is a non-documented part of the webidl spec. Refs: #49936 - Have .text(), .arrayBuffer(), and .bytes() reject for an invalid this instead of throwing. Fix the tests regarding this. PR-URL: https://github.com/nodejs/node/pull/53372 Refs: https://github.com/nodejs/node/pull/49936 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
This commit is contained in:
parent
9bb6a1a790
commit
da5887d8e9
@ -273,43 +273,21 @@ class Blob {
|
||||
if (!isBlob(this))
|
||||
return PromiseReject(new ERR_INVALID_THIS('Blob'));
|
||||
|
||||
const { promise, resolve, reject } = createDeferredPromise();
|
||||
const reader = this[kHandle].getReader();
|
||||
const buffers = [];
|
||||
const readNext = () => {
|
||||
reader.pull((status, buffer) => {
|
||||
if (status === 0) {
|
||||
// EOS, concat & resolve
|
||||
// buffer should be undefined here
|
||||
resolve(concat(buffers));
|
||||
return;
|
||||
} else if (status < 0) {
|
||||
// The read could fail for many different reasons when reading
|
||||
// from a non-memory resident blob part (e.g. file-backed blob).
|
||||
// The error details the system error code.
|
||||
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
if (buffer !== undefined)
|
||||
buffers.push(buffer);
|
||||
queueMicrotask(() => readNext());
|
||||
});
|
||||
};
|
||||
readNext();
|
||||
return promise;
|
||||
return arrayBuffer(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async text() {
|
||||
text() {
|
||||
if (!isBlob(this))
|
||||
throw new ERR_INVALID_THIS('Blob');
|
||||
return PromiseReject(new ERR_INVALID_THIS('Blob'));
|
||||
|
||||
dec ??= new TextDecoder();
|
||||
|
||||
return dec.decode(await this.arrayBuffer());
|
||||
return PromisePrototypeThen(
|
||||
arrayBuffer(this),
|
||||
(buffer) => dec.decode(buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -317,10 +295,10 @@ class Blob {
|
||||
*/
|
||||
bytes() {
|
||||
if (!isBlob(this))
|
||||
throw new ERR_INVALID_THIS('Blob');
|
||||
return PromiseReject(new ERR_INVALID_THIS('Blob'));
|
||||
|
||||
return PromisePrototypeThen(
|
||||
this.arrayBuffer(),
|
||||
arrayBuffer(this),
|
||||
(buffer) => new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
@ -439,6 +417,7 @@ ObjectDefineProperties(Blob.prototype, {
|
||||
stream: kEnumerableProperty,
|
||||
text: kEnumerableProperty,
|
||||
arrayBuffer: kEnumerableProperty,
|
||||
bytes: kEnumerableProperty,
|
||||
});
|
||||
|
||||
function resolveObjectURL(url) {
|
||||
@ -490,6 +469,34 @@ function createBlobFromFilePath(path, options) {
|
||||
return res;
|
||||
}
|
||||
|
||||
function arrayBuffer(blob) {
|
||||
const { promise, resolve, reject } = createDeferredPromise();
|
||||
const reader = blob[kHandle].getReader();
|
||||
const buffers = [];
|
||||
const readNext = () => {
|
||||
reader.pull((status, buffer) => {
|
||||
if (status === 0) {
|
||||
// EOS, concat & resolve
|
||||
// buffer should be undefined here
|
||||
resolve(concat(buffers));
|
||||
return;
|
||||
} else if (status < 0) {
|
||||
// The read could fail for many different reasons when reading
|
||||
// from a non-memory resident blob part (e.g. file-backed blob).
|
||||
// The error details the system error code.
|
||||
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
if (buffer !== undefined)
|
||||
buffers.push(buffer);
|
||||
queueMicrotask(() => readNext());
|
||||
});
|
||||
};
|
||||
readNext();
|
||||
return promise;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Blob,
|
||||
createBlob,
|
||||
|
@ -197,6 +197,7 @@ assert.throws(() => new Blob({}), {
|
||||
'stream',
|
||||
'text',
|
||||
'arrayBuffer',
|
||||
'bytes',
|
||||
];
|
||||
|
||||
for (const prop of enumerable) {
|
||||
@ -409,10 +410,13 @@ assert.throws(() => new Blob({}), {
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await assert.rejects(async () => Blob.prototype.arrayBuffer.call(), {
|
||||
await assert.rejects(() => Blob.prototype.arrayBuffer.call(), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
await assert.rejects(async () => Blob.prototype.text.call(), {
|
||||
await assert.rejects(() => Blob.prototype.text.call(), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
await assert.rejects(() => Blob.prototype.bytes.call(), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
@ -490,3 +494,16 @@ assert.throws(() => new Blob({}), {
|
||||
assert.ok(structuredClone(blob).size === blob.size);
|
||||
assert.ok((await structuredClone(blob).text()) === (await blob.text()));
|
||||
})().then(common.mustCall());
|
||||
|
||||
(async () => {
|
||||
const blob = new Blob(['hello']);
|
||||
const { arrayBuffer } = Blob.prototype;
|
||||
|
||||
Blob.prototype.arrayBuffer = common.mustNotCall();
|
||||
|
||||
try {
|
||||
assert.strictEqual(await blob.text(), 'hello');
|
||||
} finally {
|
||||
Blob.prototype.arrayBuffer = arrayBuffer;
|
||||
}
|
||||
})().then(common.mustCall());
|
||||
|
Loading…
Reference in New Issue
Block a user