• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2const { Minipass } = require('minipass')
3const TYPE = Symbol('type')
4const BUFFER = Symbol('buffer')
5
6class Blob {
7  constructor (blobParts, options) {
8    this[TYPE] = ''
9
10    const buffers = []
11    let size = 0
12
13    if (blobParts) {
14      const a = blobParts
15      const length = Number(a.length)
16      for (let i = 0; i < length; i++) {
17        const element = a[i]
18        const buffer = element instanceof Buffer ? element
19          : ArrayBuffer.isView(element)
20            ? Buffer.from(element.buffer, element.byteOffset, element.byteLength)
21            : element instanceof ArrayBuffer ? Buffer.from(element)
22            : element instanceof Blob ? element[BUFFER]
23            : typeof element === 'string' ? Buffer.from(element)
24            : Buffer.from(String(element))
25        size += buffer.length
26        buffers.push(buffer)
27      }
28    }
29
30    this[BUFFER] = Buffer.concat(buffers, size)
31
32    const type = options && options.type !== undefined
33      && String(options.type).toLowerCase()
34    if (type && !/[^\u0020-\u007E]/.test(type)) {
35      this[TYPE] = type
36    }
37  }
38
39  get size () {
40    return this[BUFFER].length
41  }
42
43  get type () {
44    return this[TYPE]
45  }
46
47  text () {
48    return Promise.resolve(this[BUFFER].toString())
49  }
50
51  arrayBuffer () {
52    const buf = this[BUFFER]
53    const off = buf.byteOffset
54    const len = buf.byteLength
55    const ab = buf.buffer.slice(off, off + len)
56    return Promise.resolve(ab)
57  }
58
59  stream () {
60    return new Minipass().end(this[BUFFER])
61  }
62
63  slice (start, end, type) {
64    const size = this.size
65    const relativeStart = start === undefined ? 0
66      : start < 0 ? Math.max(size + start, 0)
67      : Math.min(start, size)
68    const relativeEnd = end === undefined ? size
69      : end < 0 ? Math.max(size + end, 0)
70      : Math.min(end, size)
71    const span = Math.max(relativeEnd - relativeStart, 0)
72
73    const buffer = this[BUFFER]
74    const slicedBuffer = buffer.slice(
75      relativeStart,
76      relativeStart + span
77    )
78    const blob = new Blob([], { type })
79    blob[BUFFER] = slicedBuffer
80    return blob
81  }
82
83  get [Symbol.toStringTag] () {
84    return 'Blob'
85  }
86
87  static get BUFFER () {
88    return BUFFER
89  }
90}
91
92Object.defineProperties(Blob.prototype, {
93  size: { enumerable: true },
94  type: { enumerable: true },
95})
96
97module.exports = Blob
98