index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. 'use strict'
  2. const EE = require('events')
  3. const Yallist = require('yallist')
  4. const SD = require('string_decoder').StringDecoder
  5. const EOF = Symbol('EOF')
  6. const MAYBE_EMIT_END = Symbol('maybeEmitEnd')
  7. const EMITTED_END = Symbol('emittedEnd')
  8. const EMITTING_END = Symbol('emittingEnd')
  9. const CLOSED = Symbol('closed')
  10. const READ = Symbol('read')
  11. const FLUSH = Symbol('flush')
  12. const FLUSHCHUNK = Symbol('flushChunk')
  13. const ENCODING = Symbol('encoding')
  14. const DECODER = Symbol('decoder')
  15. const FLOWING = Symbol('flowing')
  16. const PAUSED = Symbol('paused')
  17. const RESUME = Symbol('resume')
  18. const BUFFERLENGTH = Symbol('bufferLength')
  19. const BUFFERPUSH = Symbol('bufferPush')
  20. const BUFFERSHIFT = Symbol('bufferShift')
  21. const OBJECTMODE = Symbol('objectMode')
  22. const DESTROYED = Symbol('destroyed')
  23. // TODO remove when Node v8 support drops
  24. const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1'
  25. const ASYNCITERATOR = doIter && Symbol.asyncIterator
  26. || Symbol('asyncIterator not implemented')
  27. const ITERATOR = doIter && Symbol.iterator
  28. || Symbol('iterator not implemented')
  29. // Buffer in node 4.x < 4.5.0 doesn't have working Buffer.from
  30. // or Buffer.alloc, and Buffer in node 10 deprecated the ctor.
  31. // .M, this is fine .\^/M..
  32. const B = Buffer.alloc ? Buffer
  33. : /* istanbul ignore next */ require('safe-buffer').Buffer
  34. // events that mean 'the stream is over'
  35. // these are treated specially, and re-emitted
  36. // if they are listened for after emitting.
  37. const isEndish = ev =>
  38. ev === 'end' ||
  39. ev === 'finish' ||
  40. ev === 'prefinish'
  41. const isArrayBuffer = b => b instanceof ArrayBuffer ||
  42. typeof b === 'object' &&
  43. b.constructor &&
  44. b.constructor.name === 'ArrayBuffer' &&
  45. b.byteLength >= 0
  46. const isArrayBufferView = b => !B.isBuffer(b) && ArrayBuffer.isView(b)
  47. module.exports = class Minipass extends EE {
  48. constructor (options) {
  49. super()
  50. this[FLOWING] = false
  51. // whether we're explicitly paused
  52. this[PAUSED] = false
  53. this.pipes = new Yallist()
  54. this.buffer = new Yallist()
  55. this[OBJECTMODE] = options && options.objectMode || false
  56. if (this[OBJECTMODE])
  57. this[ENCODING] = null
  58. else
  59. this[ENCODING] = options && options.encoding || null
  60. if (this[ENCODING] === 'buffer')
  61. this[ENCODING] = null
  62. this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null
  63. this[EOF] = false
  64. this[EMITTED_END] = false
  65. this[EMITTING_END] = false
  66. this[CLOSED] = false
  67. this.writable = true
  68. this.readable = true
  69. this[BUFFERLENGTH] = 0
  70. this[DESTROYED] = false
  71. }
  72. get bufferLength () { return this[BUFFERLENGTH] }
  73. get encoding () { return this[ENCODING] }
  74. set encoding (enc) {
  75. if (this[OBJECTMODE])
  76. throw new Error('cannot set encoding in objectMode')
  77. if (this[ENCODING] && enc !== this[ENCODING] &&
  78. (this[DECODER] && this[DECODER].lastNeed || this[BUFFERLENGTH]))
  79. throw new Error('cannot change encoding')
  80. if (this[ENCODING] !== enc) {
  81. this[DECODER] = enc ? new SD(enc) : null
  82. if (this.buffer.length)
  83. this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk))
  84. }
  85. this[ENCODING] = enc
  86. }
  87. setEncoding (enc) {
  88. this.encoding = enc
  89. }
  90. get objectMode () { return this[OBJECTMODE] }
  91. set objectMode (ॐ ) { this[OBJECTMODE] = this[OBJECTMODE] || !!ॐ }
  92. write (chunk, encoding, cb) {
  93. if (this[EOF])
  94. throw new Error('write after end')
  95. if (this[DESTROYED]) {
  96. this.emit('error', Object.assign(
  97. new Error('Cannot call write after a stream was destroyed'),
  98. { code: 'ERR_STREAM_DESTROYED' }
  99. ))
  100. return true
  101. }
  102. if (typeof encoding === 'function')
  103. cb = encoding, encoding = 'utf8'
  104. if (!encoding)
  105. encoding = 'utf8'
  106. // convert array buffers and typed array views into buffers
  107. // at some point in the future, we may want to do the opposite!
  108. // leave strings and buffers as-is
  109. // anything else switches us into object mode
  110. if (!this[OBJECTMODE] && !B.isBuffer(chunk)) {
  111. if (isArrayBufferView(chunk))
  112. chunk = B.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)
  113. else if (isArrayBuffer(chunk))
  114. chunk = B.from(chunk)
  115. else if (typeof chunk !== 'string')
  116. // use the setter so we throw if we have encoding set
  117. this.objectMode = true
  118. }
  119. // this ensures at this point that the chunk is a buffer or string
  120. // don't buffer it up or send it to the decoder
  121. if (!this.objectMode && !chunk.length) {
  122. const ret = this.flowing
  123. if (this[BUFFERLENGTH] !== 0)
  124. this.emit('readable')
  125. if (cb)
  126. cb()
  127. return ret
  128. }
  129. // fast-path writing strings of same encoding to a stream with
  130. // an empty buffer, skipping the buffer/decoder dance
  131. if (typeof chunk === 'string' && !this[OBJECTMODE] &&
  132. // unless it is a string already ready for us to use
  133. !(encoding === this[ENCODING] && !this[DECODER].lastNeed)) {
  134. chunk = B.from(chunk, encoding)
  135. }
  136. if (B.isBuffer(chunk) && this[ENCODING])
  137. chunk = this[DECODER].write(chunk)
  138. try {
  139. return this.flowing
  140. ? (this.emit('data', chunk), this.flowing)
  141. : (this[BUFFERPUSH](chunk), false)
  142. } finally {
  143. if (this[BUFFERLENGTH] !== 0)
  144. this.emit('readable')
  145. if (cb)
  146. cb()
  147. }
  148. }
  149. read (n) {
  150. if (this[DESTROYED])
  151. return null
  152. try {
  153. if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH])
  154. return null
  155. if (this[OBJECTMODE])
  156. n = null
  157. if (this.buffer.length > 1 && !this[OBJECTMODE]) {
  158. if (this.encoding)
  159. this.buffer = new Yallist([
  160. Array.from(this.buffer).join('')
  161. ])
  162. else
  163. this.buffer = new Yallist([
  164. B.concat(Array.from(this.buffer), this[BUFFERLENGTH])
  165. ])
  166. }
  167. return this[READ](n || null, this.buffer.head.value)
  168. } finally {
  169. this[MAYBE_EMIT_END]()
  170. }
  171. }
  172. [READ] (n, chunk) {
  173. if (n === chunk.length || n === null)
  174. this[BUFFERSHIFT]()
  175. else {
  176. this.buffer.head.value = chunk.slice(n)
  177. chunk = chunk.slice(0, n)
  178. this[BUFFERLENGTH] -= n
  179. }
  180. this.emit('data', chunk)
  181. if (!this.buffer.length && !this[EOF])
  182. this.emit('drain')
  183. return chunk
  184. }
  185. end (chunk, encoding, cb) {
  186. if (typeof chunk === 'function')
  187. cb = chunk, chunk = null
  188. if (typeof encoding === 'function')
  189. cb = encoding, encoding = 'utf8'
  190. if (chunk)
  191. this.write(chunk, encoding)
  192. if (cb)
  193. this.once('end', cb)
  194. this[EOF] = true
  195. this.writable = false
  196. // if we haven't written anything, then go ahead and emit,
  197. // even if we're not reading.
  198. // we'll re-emit if a new 'end' listener is added anyway.
  199. // This makes MP more suitable to write-only use cases.
  200. if (this.flowing || !this[PAUSED])
  201. this[MAYBE_EMIT_END]()
  202. return this
  203. }
  204. // don't let the internal resume be overwritten
  205. [RESUME] () {
  206. if (this[DESTROYED])
  207. return
  208. this[PAUSED] = false
  209. this[FLOWING] = true
  210. this.emit('resume')
  211. if (this.buffer.length)
  212. this[FLUSH]()
  213. else if (this[EOF])
  214. this[MAYBE_EMIT_END]()
  215. else
  216. this.emit('drain')
  217. }
  218. resume () {
  219. return this[RESUME]()
  220. }
  221. pause () {
  222. this[FLOWING] = false
  223. this[PAUSED] = true
  224. }
  225. get destroyed () {
  226. return this[DESTROYED]
  227. }
  228. get flowing () {
  229. return this[FLOWING]
  230. }
  231. get paused () {
  232. return this[PAUSED]
  233. }
  234. [BUFFERPUSH] (chunk) {
  235. if (this[OBJECTMODE])
  236. this[BUFFERLENGTH] += 1
  237. else
  238. this[BUFFERLENGTH] += chunk.length
  239. return this.buffer.push(chunk)
  240. }
  241. [BUFFERSHIFT] () {
  242. if (this.buffer.length) {
  243. if (this[OBJECTMODE])
  244. this[BUFFERLENGTH] -= 1
  245. else
  246. this[BUFFERLENGTH] -= this.buffer.head.value.length
  247. }
  248. return this.buffer.shift()
  249. }
  250. [FLUSH] () {
  251. do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]()))
  252. if (!this.buffer.length && !this[EOF])
  253. this.emit('drain')
  254. }
  255. [FLUSHCHUNK] (chunk) {
  256. return chunk ? (this.emit('data', chunk), this.flowing) : false
  257. }
  258. pipe (dest, opts) {
  259. if (this[DESTROYED])
  260. return
  261. const ended = this[EMITTED_END]
  262. opts = opts || {}
  263. if (dest === process.stdout || dest === process.stderr)
  264. opts.end = false
  265. else
  266. opts.end = opts.end !== false
  267. const p = { dest: dest, opts: opts, ondrain: _ => this[RESUME]() }
  268. this.pipes.push(p)
  269. dest.on('drain', p.ondrain)
  270. this[RESUME]()
  271. // piping an ended stream ends immediately
  272. if (ended && p.opts.end)
  273. p.dest.end()
  274. return dest
  275. }
  276. addListener (ev, fn) {
  277. return this.on(ev, fn)
  278. }
  279. on (ev, fn) {
  280. try {
  281. return super.on(ev, fn)
  282. } finally {
  283. if (ev === 'data' && !this.pipes.length && !this.flowing)
  284. this[RESUME]()
  285. else if (isEndish(ev) && this[EMITTED_END]) {
  286. super.emit(ev)
  287. this.removeAllListeners(ev)
  288. }
  289. }
  290. }
  291. get emittedEnd () {
  292. return this[EMITTED_END]
  293. }
  294. [MAYBE_EMIT_END] () {
  295. if (!this[EMITTING_END] &&
  296. !this[EMITTED_END] &&
  297. !this[DESTROYED] &&
  298. this.buffer.length === 0 &&
  299. this[EOF]) {
  300. this[EMITTING_END] = true
  301. this.emit('end')
  302. this.emit('prefinish')
  303. this.emit('finish')
  304. if (this[CLOSED])
  305. this.emit('close')
  306. this[EMITTING_END] = false
  307. }
  308. }
  309. emit (ev, data) {
  310. // error and close are only events allowed after calling destroy()
  311. if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED])
  312. return
  313. else if (ev === 'data') {
  314. if (!data)
  315. return
  316. if (this.pipes.length)
  317. this.pipes.forEach(p =>
  318. p.dest.write(data) === false && this.pause())
  319. } else if (ev === 'end') {
  320. // only actual end gets this treatment
  321. if (this[EMITTED_END] === true)
  322. return
  323. this[EMITTED_END] = true
  324. this.readable = false
  325. if (this[DECODER]) {
  326. data = this[DECODER].end()
  327. if (data) {
  328. this.pipes.forEach(p => p.dest.write(data))
  329. super.emit('data', data)
  330. }
  331. }
  332. this.pipes.forEach(p => {
  333. p.dest.removeListener('drain', p.ondrain)
  334. if (p.opts.end)
  335. p.dest.end()
  336. })
  337. } else if (ev === 'close') {
  338. this[CLOSED] = true
  339. // don't emit close before 'end' and 'finish'
  340. if (!this[EMITTED_END] && !this[DESTROYED])
  341. return
  342. }
  343. // TODO: replace with a spread operator when Node v4 support drops
  344. const args = new Array(arguments.length)
  345. args[0] = ev
  346. args[1] = data
  347. if (arguments.length > 2) {
  348. for (let i = 2; i < arguments.length; i++) {
  349. args[i] = arguments[i]
  350. }
  351. }
  352. try {
  353. return super.emit.apply(this, args)
  354. } finally {
  355. if (!isEndish(ev))
  356. this[MAYBE_EMIT_END]()
  357. else
  358. this.removeAllListeners(ev)
  359. }
  360. }
  361. // const all = await stream.collect()
  362. collect () {
  363. const buf = []
  364. buf.dataLength = 0
  365. this.on('data', c => {
  366. buf.push(c)
  367. buf.dataLength += c.length
  368. })
  369. return this.promise().then(() => buf)
  370. }
  371. // const data = await stream.concat()
  372. concat () {
  373. return this[OBJECTMODE]
  374. ? Promise.reject(new Error('cannot concat in objectMode'))
  375. : this.collect().then(buf =>
  376. this[OBJECTMODE]
  377. ? Promise.reject(new Error('cannot concat in objectMode'))
  378. : this[ENCODING] ? buf.join('') : B.concat(buf, buf.dataLength))
  379. }
  380. // stream.promise().then(() => done, er => emitted error)
  381. promise () {
  382. return new Promise((resolve, reject) => {
  383. this.on(DESTROYED, () => reject(new Error('stream destroyed')))
  384. this.on('end', () => resolve())
  385. this.on('error', er => reject(er))
  386. })
  387. }
  388. // for await (let chunk of stream)
  389. [ASYNCITERATOR] () {
  390. const next = () => {
  391. const res = this.read()
  392. if (res !== null)
  393. return Promise.resolve({ done: false, value: res })
  394. if (this[EOF])
  395. return Promise.resolve({ done: true })
  396. let resolve = null
  397. let reject = null
  398. const onerr = er => {
  399. this.removeListener('data', ondata)
  400. this.removeListener('end', onend)
  401. reject(er)
  402. }
  403. const ondata = value => {
  404. this.removeListener('error', onerr)
  405. this.removeListener('end', onend)
  406. this.pause()
  407. resolve({ value: value, done: !!this[EOF] })
  408. }
  409. const onend = () => {
  410. this.removeListener('error', onerr)
  411. this.removeListener('data', ondata)
  412. resolve({ done: true })
  413. }
  414. const ondestroy = () => onerr(new Error('stream destroyed'))
  415. return new Promise((res, rej) => {
  416. reject = rej
  417. resolve = res
  418. this.once(DESTROYED, ondestroy)
  419. this.once('error', onerr)
  420. this.once('end', onend)
  421. this.once('data', ondata)
  422. })
  423. }
  424. return { next }
  425. }
  426. // for (let chunk of stream)
  427. [ITERATOR] () {
  428. const next = () => {
  429. const value = this.read()
  430. const done = value === null
  431. return { value, done }
  432. }
  433. return { next }
  434. }
  435. destroy (er) {
  436. if (this[DESTROYED]) {
  437. if (er)
  438. this.emit('error', er)
  439. else
  440. this.emit(DESTROYED)
  441. return this
  442. }
  443. this[DESTROYED] = true
  444. // throw away all buffered data, it's never coming out
  445. this.buffer = new Yallist()
  446. this[BUFFERLENGTH] = 0
  447. if (typeof this.close === 'function' && !this[CLOSED])
  448. this.close()
  449. if (er)
  450. this.emit('error', er)
  451. else // if no error to emit, still reject pending promises
  452. this.emit(DESTROYED)
  453. return this
  454. }
  455. static isStream (s) {
  456. return !!s && (s instanceof Minipass || s instanceof EE && (
  457. typeof s.pipe === 'function' || // readable
  458. (typeof s.write === 'function' && typeof s.end === 'function') // writable
  459. ))
  460. }
  461. }