• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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