happy-dom
Version:
Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.
148 lines (126 loc) • 3.48 kB
text/typescript
import { Buffer } from 'buffer';
import * as PropertySymbol from '../PropertySymbol.js';
/**
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/Blob.
*
* Based on:
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/file-api/Blob-impl.js (MIT licensed).
*/
export default class Blob {
public readonly type: string = '';
public [PropertySymbol.buffer]: Buffer = null;
/**
* Constructor.
*
* @param bits Bits.
* @param [options] Options.
* @param [options.type] MIME type.
*/
constructor(
bits: (ArrayBuffer | ArrayBufferView | Blob | Buffer | string)[],
options?: { type?: string }
) {
const buffers = [];
if (bits) {
for (const bit of bits) {
let buffer: Buffer;
if (bit instanceof ArrayBuffer) {
buffer = Buffer.from(new Uint8Array(bit));
} else if (bit instanceof Blob) {
buffer = bit[PropertySymbol.buffer];
} else if (bit instanceof Buffer) {
buffer = bit;
} else if (ArrayBuffer.isView(bit)) {
buffer = Buffer.from(new Uint8Array(bit.buffer, bit.byteOffset, bit.byteLength));
} else {
buffer = Buffer.from(typeof bit === 'string' ? bit : String(bit));
}
buffers.push(buffer);
}
}
this[PropertySymbol.buffer] = Buffer.concat(buffers);
if (options && options.type && options.type.match(/^[\u0020-\u007E]*$/)) {
this.type = String(options.type).toLowerCase();
}
}
/**
* Returns size.
*
* @returns Size.
*/
public get size(): number {
return this[PropertySymbol.buffer].length;
}
/**
* Slices the blob.
*
* @param start Start.
* @param end End.
* @param contentType Content type.
* @returns New Blob.
*/
public slice(start = 0, end: number = null, contentType = ''): Blob {
const size = this.size;
let relativeStart;
let relativeEnd;
let relativeContentType;
if (start === undefined) {
relativeStart = 0;
} else if (start < 0) {
relativeStart = Math.max(size + start, 0);
} else {
relativeStart = Math.min(start, size);
}
if (end === null) {
relativeEnd = size;
} else if (end < 0) {
relativeEnd = Math.max(size + end, 0);
} else {
relativeEnd = Math.min(end, size);
}
if (contentType === undefined) {
relativeContentType = '';
} else {
// Sanitization (lower case and invalid char check) is done in the
// Constructor
relativeContentType = contentType;
}
const span = Math.max(relativeEnd - relativeStart, 0);
const buffer = this[PropertySymbol.buffer];
const slicedBuffer = buffer.slice(relativeStart, relativeStart + span);
const blob = new Blob([], { type: relativeContentType });
(<Buffer>blob[PropertySymbol.buffer]) = slicedBuffer;
return blob;
}
/**
* Returns a Promise that resolves to a ArrayBuffer.
*
* @returns ArrayBuffer.
*/
// Reference:
// https://github.com/web-std/io/blob/c88170bf24f064adfbb3586a21fb76650ca5a9ab/packages/blob/src/blob.js#L139-L148
// https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
/**
*
*/
public async arrayBuffer(): Promise<ArrayBuffer> {
return new Uint8Array(this[PropertySymbol.buffer]).buffer;
}
/**
* Returns a Promise that resolves to a text.
*
* @returns Text.
*/
public async text(): Promise<string> {
return this[PropertySymbol.buffer].toString();
}
/**
* Returns the object converted to string.
*
* @returns String.
*/
public toString(): string {
return '[object Blob]';
}
}