1'use strict' 2// Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js 3// (MIT licensed) 4 5const Buffer = require('safe-buffer').Buffer 6 7const BUFFER = Symbol('buffer') 8const TYPE = Symbol('type') 9const CLOSED = Symbol('closed') 10 11class Blob { 12 constructor () { 13 Object.defineProperty(this, Symbol.toStringTag, { 14 value: 'Blob', 15 writable: false, 16 enumerable: false, 17 configurable: true 18 }) 19 20 this[CLOSED] = false 21 this[TYPE] = '' 22 23 const blobParts = arguments[0] 24 const options = arguments[1] 25 26 const buffers = [] 27 28 if (blobParts) { 29 const a = blobParts 30 const length = Number(a.length) 31 for (let i = 0; i < length; i++) { 32 const element = a[i] 33 let buffer 34 if (Buffer.isBuffer(element)) { 35 buffer = element 36 } else if (ArrayBuffer.isView(element)) { 37 buffer = Buffer.from(new Uint8Array(element.buffer, element.byteOffset, element.byteLength)) 38 } else if (element instanceof ArrayBuffer) { 39 buffer = Buffer.from(new Uint8Array(element)) 40 } else if (element instanceof Blob) { 41 buffer = element[BUFFER] 42 } else { 43 buffer = Buffer.from(typeof element === 'string' ? element : String(element)) 44 } 45 buffers.push(buffer) 46 } 47 } 48 49 this[BUFFER] = Buffer.concat(buffers) 50 51 let type = options && options.type !== undefined && String(options.type).toLowerCase() 52 if (type && !/[^\u0020-\u007E]/.test(type)) { 53 this[TYPE] = type 54 } 55 } 56 get size () { 57 return this[CLOSED] ? 0 : this[BUFFER].length 58 } 59 get type () { 60 return this[TYPE] 61 } 62 get isClosed () { 63 return this[CLOSED] 64 } 65 slice () { 66 const size = this.size 67 68 const start = arguments[0] 69 const end = arguments[1] 70 let relativeStart, relativeEnd 71 if (start === undefined) { 72 relativeStart = 0 73 } else if (start < 0) { 74 relativeStart = Math.max(size + start, 0) 75 } else { 76 relativeStart = Math.min(start, size) 77 } 78 if (end === undefined) { 79 relativeEnd = size 80 } else if (end < 0) { 81 relativeEnd = Math.max(size + end, 0) 82 } else { 83 relativeEnd = Math.min(end, size) 84 } 85 const span = Math.max(relativeEnd - relativeStart, 0) 86 87 const buffer = this[BUFFER] 88 const slicedBuffer = buffer.slice( 89 relativeStart, 90 relativeStart + span 91 ) 92 const blob = new Blob([], { type: arguments[2] }) 93 blob[BUFFER] = slicedBuffer 94 blob[CLOSED] = this[CLOSED] 95 return blob 96 } 97 close () { 98 this[CLOSED] = true 99 } 100} 101exports = module.exports = Blob 102exports.BUFFER = BUFFER 103 104Object.defineProperty(Blob.prototype, Symbol.toStringTag, { 105 value: 'BlobPrototype', 106 writable: false, 107 enumerable: false, 108 configurable: true 109}) 110