codekingpro/portable-devtools
114k
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.Minipass = exports.isWritable = exports.isReadable = exports.isStream = void 0;
7const proc = typeof process === 'object' && process
8 ? process
9 : {
10 stdout: null,
11 stderr: null,
12 };
13const node_events_1 = require("node:events");
14const node_stream_1 = __importDefault(require("node:stream"));
15const node_string_decoder_1 = require("node:string_decoder");
16/**
17 * Return true if the argument is a Minipass stream, Node stream, or something
18 * else that Minipass can interact with.
19 */
20const isStream = (s) => !!s &&
21 typeof s === 'object' &&
22 (s instanceof Minipass ||
23 s instanceof node_stream_1.default ||
24 (0, exports.isReadable)(s) ||
25 (0, exports.isWritable)(s))
26/**
27 * Return true if the argument is a valid {@link Minipass.Readable}
28 */
29;
30exports.isStream = isStream;
31/**
32 * Return true if the argument is a valid {@link Minipass.Readable}
33 */
34const isReadable = (s) => !!s &&
35 typeof s === 'object' &&
36 s instanceof node_events_1.EventEmitter &&
37 typeof s.pipe === 'function' &&
38 // node core Writable streams have a pipe() method, but it throws
39 s.pipe !== node_stream_1.default.Writable.prototype.pipe
40/**
41 * Return true if the argument is a valid {@link Minipass.Writable}
42 */
43;
44exports.isReadable = isReadable;
45/**
46 * Return true if the argument is a valid {@link Minipass.Writable}
47 */
48const isWritable = (s) => !!s &&
49 typeof s === 'object' &&
50 s instanceof node_events_1.EventEmitter &&
51 typeof s.write === 'function' &&
52 typeof s.end === 'function';
53exports.isWritable = isWritable;
54const EOF = Symbol('EOF');
55const MAYBE_EMIT_END = Symbol('maybeEmitEnd');
56const EMITTED_END = Symbol('emittedEnd');
57const EMITTING_END = Symbol('emittingEnd');
58const EMITTED_ERROR = Symbol('emittedError');
59const CLOSED = Symbol('closed');
60const READ = Symbol('read');
61const FLUSH = Symbol('flush');
62const FLUSHCHUNK = Symbol('flushChunk');
63const ENCODING = Symbol('encoding');
64const DECODER = Symbol('decoder');
65const FLOWING = Symbol('flowing');
66const PAUSED = Symbol('paused');
67const RESUME = Symbol('resume');
68const BUFFER = Symbol('buffer');
69const PIPES = Symbol('pipes');
70const BUFFERLENGTH = Symbol('bufferLength');
71const BUFFERPUSH = Symbol('bufferPush');
72const BUFFERSHIFT = Symbol('bufferShift');
73const OBJECTMODE = Symbol('objectMode');
74// internal event when stream is destroyed
75const DESTROYED = Symbol('destroyed');
76// internal event when stream has an error
77const ERROR = Symbol('error');
78const EMITDATA = Symbol('emitData');
79const EMITEND = Symbol('emitEnd');
80const EMITEND2 = Symbol('emitEnd2');
81const ASYNC = Symbol('async');
82const ABORT = Symbol('abort');
83const ABORTED = Symbol('aborted');
84const SIGNAL = Symbol('signal');
85const DATALISTENERS = Symbol('dataListeners');
86const DISCARDED = Symbol('discarded');
87const defer = (fn) => Promise.resolve().then(fn);
88const nodefer = (fn) => fn();
89const isEndish = (ev) => ev === 'end' || ev === 'finish' || ev === 'prefinish';
90const isArrayBufferLike = (b) => b instanceof ArrayBuffer ||
91 (!!b &&
92 typeof b === 'object' &&
93 b.constructor &&
94 b.constructor.name === 'ArrayBuffer' &&
95 b.byteLength >= 0);
96const isArrayBufferView = (b) => !Buffer.isBuffer(b) && ArrayBuffer.isView(b);
97/**
98 * Internal class representing a pipe to a destination stream.
99 *
100 * @internal
101 */
102class Pipe {
103 src;
104 dest;
105 opts;
106 ondrain;
107 constructor(src, dest, opts) {
108 this.src = src;
109 this.dest = dest;
110 this.opts = opts;
111 this.ondrain = () => src[RESUME]();
112 this.dest.on('drain', this.ondrain);
113 }
114 unpipe() {
115 this.dest.removeListener('drain', this.ondrain);
116 }
117 // only here for the prototype
118 /* c8 ignore start */
119 proxyErrors(_er) { }
120 /* c8 ignore stop */
121 end() {
122 this.unpipe();
123 if (this.opts.end)
124 this.dest.end();
125 }
126}
127/**
128 * Internal class representing a pipe to a destination stream where
129 * errors are proxied.
130 *
131 * @internal
132 */
133class PipeProxyErrors extends Pipe {
134 unpipe() {
135 this.src.removeListener('error', this.proxyErrors);
136 super.unpipe();
137 }
138 constructor(src, dest, opts) {
139 super(src, dest, opts);
140 this.proxyErrors = (er) => this.dest.emit('error', er);
141 src.on('error', this.proxyErrors);
142 }
143}
144const isObjectModeOptions = (o) => !!o.objectMode;
145const isEncodingOptions = (o) => !o.objectMode && !!o.encoding && o.encoding !== 'buffer';
146/**
147 * Main export, the Minipass class
148 *
149 * `RType` is the type of data emitted, defaults to Buffer
150 *
151 * `WType` is the type of data to be written, if RType is buffer or string,
152 * then any {@link Minipass.ContiguousData} is allowed.
153 *
154 * `Events` is the set of event handler signatures that this object
155 * will emit, see {@link Minipass.Events}
156 */
157class Minipass extends node_events_1.EventEmitter {
158 [FLOWING] = false;
159 [PAUSED] = false;
160 [PIPES] = [];
161 [BUFFER] = [];
162 [OBJECTMODE];
163 [ENCODING];
164 [ASYNC];
165 [DECODER];
166 [EOF] = false;
167 [EMITTED_END] = false;
168 [EMITTING_END] = false;
169 [CLOSED] = false;
170 [EMITTED_ERROR] = null;
171 [BUFFERLENGTH] = 0;
172 [DESTROYED] = false;
173 [SIGNAL];
174 [ABORTED] = false;
175 [DATALISTENERS] = 0;
176 [DISCARDED] = false;
177 /**
178 * true if the stream can be written
179 */
180 writable = true;
181 /**
182 * true if the stream can be read
183 */
184 readable = true;
185 /**
186 * If `RType` is Buffer, then options do not need to be provided.
187 * Otherwise, an options object must be provided to specify either
188 * {@link Minipass.SharedOptions.objectMode} or
189 * {@link Minipass.SharedOptions.encoding}, as appropriate.
190 */
191 constructor(...args) {
192 const options = (args[0] ||
193 {});
194 super();
195 if (options.objectMode && typeof options.encoding === 'string') {
196 throw new TypeError('Encoding and objectMode may not be used together');
197 }
198 if (isObjectModeOptions(options)) {
199 this[OBJECTMODE] = true;
200 this[ENCODING] = null;
201 }
202 else if (isEncodingOptions(options)) {
203 this[ENCODING] = options.encoding;
204 this[OBJECTMODE] = false;
205 }
206 else {
207 this[OBJECTMODE] = false;
208 this[ENCODING] = null;
209 }
210 this[ASYNC] = !!options.async;
211 this[DECODER] = this[ENCODING]
212 ? new node_string_decoder_1.StringDecoder(this[ENCODING])
213 : null;
214 //@ts-ignore - private option for debugging and testing
215 if (options && options.debugExposeBuffer === true) {
216 Object.defineProperty(this, 'buffer', { get: () => this[BUFFER] });
217 }
218 //@ts-ignore - private option for debugging and testing
219 if (options && options.debugExposePipes === true) {
220 Object.defineProperty(this, 'pipes', { get: () => this[PIPES] });
221 }
222 const { signal } = options;
223 if (signal) {
224 this[SIGNAL] = signal;
225 if (signal.aborted) {
226 this[ABORT]();
227 }
228 else {
229 signal.addEventListener('abort', () => this[ABORT]());
230 }
231 }
232 }
233 /**
234 * The amount of data stored in the buffer waiting to be read.
235 *
236 * For Buffer strings, this will be the total byte length.
237 * For string encoding streams, this will be the string character length,
238 * according to JavaScript's `string.length` logic.
239 * For objectMode streams, this is a count of the items waiting to be
240 * emitted.
241 */
242 get bufferLength() {
243 return this[BUFFERLENGTH];
244 }
245 /**
246 * The `BufferEncoding` currently in use, or `null`
247 */
248 get encoding() {
249 return this[ENCODING];
250 }
251 /**
252 * @deprecated - This is a read only property
253 */
254 set encoding(_enc) {
255 throw new Error('Encoding must be set at instantiation time');
256 }
257 /**
258 * @deprecated - Encoding may only be set at instantiation time
259 */
260 setEncoding(_enc) {
261 throw new Error('Encoding must be set at instantiation time');
262 }
263 /**
264 * True if this is an objectMode stream
265 */
266 get objectMode() {
267 return this[OBJECTMODE];
268 }
269 /**
270 * @deprecated - This is a read-only property
271 */
272 set objectMode(_om) {
273 throw new Error('objectMode must be set at instantiation time');
274 }
275 /**
276 * true if this is an async stream
277 */
278 get ['async']() {
279 return this[ASYNC];
280 }
281 /**
282 * Set to true to make this stream async.
283 *
284 * Once set, it cannot be unset, as this would potentially cause incorrect
285 * behavior. Ie, a sync stream can be made async, but an async stream
286 * cannot be safely made sync.
287 */
288 set ['async'](a) {
289 this[ASYNC] = this[ASYNC] || !!a;
290 }
291 // drop everything and get out of the flow completely
292 [ABORT]() {
293 this[ABORTED] = true;
294 this.emit('abort', this[SIGNAL]?.reason);
295 this.destroy(this[SIGNAL]?.reason);
296 }
297 /**
298 * True if the stream has been aborted.
299 */
300 get aborted() {
301 return this[ABORTED];
302 }
303 /**
304 * No-op setter. Stream aborted status is set via the AbortSignal provided
305 * in the constructor options.
306 */
307 set aborted(_) { }
308 write(chunk, encoding, cb) {
309 if (this[ABORTED])
310 return false;
311 if (this[EOF])
312 throw new Error('write after end');
313 if (this[DESTROYED]) {
314 this.emit('error', Object.assign(new Error('Cannot call write after a stream was destroyed'), { code: 'ERR_STREAM_DESTROYED' }));
315 return true;
316 }
317 if (typeof encoding === 'function') {
318 cb = encoding;
319 encoding = 'utf8';
320 }
321 if (!encoding)
322 encoding = 'utf8';
323 const fn = this[ASYNC] ? defer : nodefer;
324 // convert array buffers and typed array views into buffers
325 // at some point in the future, we may want to do the opposite!
326 // leave strings and buffers as-is
327 // anything is only allowed if in object mode, so throw
328 if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) {
329 if (isArrayBufferView(chunk)) {
330 //@ts-ignore - sinful unsafe type changing
331 chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
332 }
333 else if (isArrayBufferLike(chunk)) {
334 //@ts-ignore - sinful unsafe type changing
335 chunk = Buffer.from(chunk);
336 }
337 else if (typeof chunk !== 'string') {
338 throw new Error('Non-contiguous data written to non-objectMode stream');
339 }
340 }
341 // handle object mode up front, since it's simpler
342 // this yields better performance, fewer checks later.
343 if (this[OBJECTMODE]) {
344 // maybe impossible?
345 /* c8 ignore start */
346 if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
347 this[FLUSH](true);
348 /* c8 ignore stop */
349 if (this[FLOWING])
350 this.emit('data', chunk);
351 else
352 this[BUFFERPUSH](chunk);
353 if (this[BUFFERLENGTH] !== 0)
354 this.emit('readable');
355 if (cb)
356 fn(cb);
357 return this[FLOWING];
358 }
359 // at this point the chunk is a buffer or string
360 // don't buffer it up or send it to the decoder
361 if (!chunk.length) {
362 if (this[BUFFERLENGTH] !== 0)
363 this.emit('readable');
364 if (cb)
365 fn(cb);
366 return this[FLOWING];
367 }
368 // fast-path writing strings of same encoding to a stream with
369 // an empty buffer, skipping the buffer/decoder dance
370 if (typeof chunk === 'string' &&
371 // unless it is a string already ready for us to use
372 !(encoding === this[ENCODING] && !this[DECODER]?.lastNeed)) {
373 //@ts-ignore - sinful unsafe type change
374 chunk = Buffer.from(chunk, encoding);
375 }
376 if (Buffer.isBuffer(chunk) && this[ENCODING]) {
377 //@ts-ignore - sinful unsafe type change
378 chunk = this[DECODER].write(chunk);
379 }
380 // Note: flushing CAN potentially switch us into not-flowing mode
381 if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
382 this[FLUSH](true);
383 if (this[FLOWING])
384 this.emit('data', chunk);
385 else
386 this[BUFFERPUSH](chunk);
387 if (this[BUFFERLENGTH] !== 0)
388 this.emit('readable');
389 if (cb)
390 fn(cb);
391 return this[FLOWING];
392 }
393 /**
394 * Low-level explicit read method.
395 *
396 * In objectMode, the argument is ignored, and one item is returned if
397 * available.
398 *
399 * `n` is the number of bytes (or in the case of encoding streams,
400 * characters) to consume. If `n` is not provided, then the entire buffer
401 * is returned, or `null` is returned if no data is available.
402 *
403 * If `n` is greater that the amount of data in the internal buffer,
404 * then `null` is returned.
405 */
406 read(n) {
407 if (this[DESTROYED])
408 return null;
409 this[DISCARDED] = false;
410 if (this[BUFFERLENGTH] === 0 ||
411 n === 0 ||
412 (n && n > this[BUFFERLENGTH])) {
413 this[MAYBE_EMIT_END]();
414 return null;
415 }
416 if (this[OBJECTMODE])
417 n = null;
418 if (this[BUFFER].length > 1 && !this[OBJECTMODE]) {
419 // not object mode, so if we have an encoding, then RType is string
420 // otherwise, must be Buffer
421 this[BUFFER] = [
422 (this[ENCODING]
423 ? this[BUFFER].join('')
424 : Buffer.concat(this[BUFFER], this[BUFFERLENGTH])),
425 ];
426 }
427 const ret = this[READ](n || null, this[BUFFER][0]);
428 this[MAYBE_EMIT_END]();
429 return ret;
430 }
431 [READ](n, chunk) {
432 if (this[OBJECTMODE])
433 this[BUFFERSHIFT]();
434 else {
435 const c = chunk;
436 if (n === c.length || n === null)
437 this[BUFFERSHIFT]();
438 else if (typeof c === 'string') {
439 this[BUFFER][0] = c.slice(n);
440 chunk = c.slice(0, n);
441 this[BUFFERLENGTH] -= n;
442 }
443 else {
444 this[BUFFER][0] = c.subarray(n);
445 chunk = c.subarray(0, n);
446 this[BUFFERLENGTH] -= n;
447 }
448 }
449 this.emit('data', chunk);
450 if (!this[BUFFER].length && !this[EOF])
451 this.emit('drain');
452 return chunk;
453 }
454 end(chunk, encoding, cb) {
455 if (typeof chunk === 'function') {
456 cb = chunk;
457 chunk = undefined;
458 }
459 if (typeof encoding === 'function') {
460 cb = encoding;
461 encoding = 'utf8';
462 }
463 if (chunk !== undefined)
464 this.write(chunk, encoding);
465 if (cb)
466 this.once('end', cb);
467 this[EOF] = true;
468 this.writable = false;
469 // if we haven't written anything, then go ahead and emit,
470 // even if we're not reading.
471 // we'll re-emit if a new 'end' listener is added anyway.
472 // This makes MP more suitable to write-only use cases.
473 if (this[FLOWING] || !this[PAUSED])
474 this[MAYBE_EMIT_END]();
475 return this;
476 }
477 // don't let the internal resume be overwritten
478 [RESUME]() {
479 if (this[DESTROYED])
480 return;
481 if (!this[DATALISTENERS] && !this[PIPES].length) {
482 this[DISCARDED] = true;
483 }
484 this[PAUSED] = false;
485 this[FLOWING] = true;
486 this.emit('resume');
487 if (this[BUFFER].length)
488 this[FLUSH]();
489 else if (this[EOF])
490 this[MAYBE_EMIT_END]();
491 else
492 this.emit('drain');
493 }
494 /**
495 * Resume the stream if it is currently in a paused state
496 *
497 * If called when there are no pipe destinations or `data` event listeners,
498 * this will place the stream in a "discarded" state, where all data will
499 * be thrown away. The discarded state is removed if a pipe destination or
500 * data handler is added, if pause() is called, or if any synchronous or
501 * asynchronous iteration is started.
502 */
503 resume() {
504 return this[RESUME]();
505 }
506 /**
507 * Pause the stream
508 */
509 pause() {
510 this[FLOWING] = false;
511 this[PAUSED] = true;
512 this[DISCARDED] = false;
513 }
514 /**
515 * true if the stream has been forcibly destroyed
516 */
517 get destroyed() {
518 return this[DESTROYED];
519 }
520 /**
521 * true if the stream is currently in a flowing state, meaning that
522 * any writes will be immediately emitted.
523 */
524 get flowing() {
525 return this[FLOWING];
526 }
527 /**
528 * true if the stream is currently in a paused state
529 */
530 get paused() {
531 return this[PAUSED];
532 }
533 [BUFFERPUSH](chunk) {
534 if (this[OBJECTMODE])
535 this[BUFFERLENGTH] += 1;
536 else
537 this[BUFFERLENGTH] += chunk.length;
538 this[BUFFER].push(chunk);
539 }
540 [BUFFERSHIFT]() {
541 if (this[OBJECTMODE])
542 this[BUFFERLENGTH] -= 1;
543 else
544 this[BUFFERLENGTH] -= this[BUFFER][0].length;
545 return this[BUFFER].shift();
546 }
547 [FLUSH](noDrain = false) {
548 do { } while (this[FLUSHCHUNK](this[BUFFERSHIFT]()) &&
549 this[BUFFER].length);
550 if (!noDrain && !this[BUFFER].length && !this[EOF])
551 this.emit('drain');
552 }
553 [FLUSHCHUNK](chunk) {
554 this.emit('data', chunk);
555 return this[FLOWING];
556 }
557 /**
558 * Pipe all data emitted by this stream into the destination provided.
559 *
560 * Triggers the flow of data.
561 */
562 pipe(dest, opts) {
563 if (this[DESTROYED])
564 return dest;
565 this[DISCARDED] = false;
566 const ended = this[EMITTED_END];
567 opts = opts || {};
568 if (dest === proc.stdout || dest === proc.stderr)
569 opts.end = false;
570 else
571 opts.end = opts.end !== false;
572 opts.proxyErrors = !!opts.proxyErrors;
573 // piping an ended stream ends immediately
574 if (ended) {
575 if (opts.end)
576 dest.end();
577 }
578 else {
579 // "as" here just ignores the WType, which pipes don't care about,
580 // since they're only consuming from us, and writing to the dest
581 this[PIPES].push(!opts.proxyErrors
582 ? new Pipe(this, dest, opts)
583 : new PipeProxyErrors(this, dest, opts));
584 if (this[ASYNC])
585 defer(() => this[RESUME]());
586 else
587 this[RESUME]();
588 }
589 return dest;
590 }
591 /**
592 * Fully unhook a piped destination stream.
593 *
594 * If the destination stream was the only consumer of this stream (ie,
595 * there are no other piped destinations or `'data'` event listeners)
596 * then the flow of data will stop until there is another consumer or
597 * {@link Minipass#resume} is explicitly called.
598 */
599 unpipe(dest) {
600 const p = this[PIPES].find(p => p.dest === dest);
601 if (p) {
602 if (this[PIPES].length === 1) {
603 if (this[FLOWING] && this[DATALISTENERS] === 0) {
604 this[FLOWING] = false;
605 }
606 this[PIPES] = [];
607 }
608 else
609 this[PIPES].splice(this[PIPES].indexOf(p), 1);
610 p.unpipe();
611 }
612 }
613 /**
614 * Alias for {@link Minipass#on}
615 */
616 addListener(ev, handler) {
617 return this.on(ev, handler);
618 }
619 /**
620 * Mostly identical to `EventEmitter.on`, with the following
621 * behavior differences to prevent data loss and unnecessary hangs:
622 *
623 * - Adding a 'data' event handler will trigger the flow of data
624 *
625 * - Adding a 'readable' event handler when there is data waiting to be read
626 * will cause 'readable' to be emitted immediately.
627 *
628 * - Adding an 'endish' event handler ('end', 'finish', etc.) which has
629 * already passed will cause the event to be emitted immediately and all
630 * handlers removed.
631 *
632 * - Adding an 'error' event handler after an error has been emitted will
633 * cause the event to be re-emitted immediately with the error previously
634 * raised.
635 */
636 on(ev, handler) {
637 const ret = super.on(ev, handler);
638 if (ev === 'data') {
639 this[DISCARDED] = false;
640 this[DATALISTENERS]++;
641 if (!this[PIPES].length && !this[FLOWING]) {
642 this[RESUME]();
643 }
644 }
645 else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) {
646 super.emit('readable');
647 }
648 else if (isEndish(ev) && this[EMITTED_END]) {
649 super.emit(ev);
650 this.removeAllListeners(ev);
651 }
652 else if (ev === 'error' && this[EMITTED_ERROR]) {
653 const h = handler;
654 if (this[ASYNC])
655 defer(() => h.call(this, this[EMITTED_ERROR]));
656 else
657 h.call(this, this[EMITTED_ERROR]);
658 }
659 return ret;
660 }
661 /**
662 * Alias for {@link Minipass#off}
663 */
664 removeListener(ev, handler) {
665 return this.off(ev, handler);
666 }
667 /**
668 * Mostly identical to `EventEmitter.off`
669 *
670 * If a 'data' event handler is removed, and it was the last consumer
671 * (ie, there are no pipe destinations or other 'data' event listeners),
672 * then the flow of data will stop until there is another consumer or
673 * {@link Minipass#resume} is explicitly called.
674 */
675 off(ev, handler) {
676 const ret = super.off(ev, handler);
677 // if we previously had listeners, and now we don't, and we don't
678 // have any pipes, then stop the flow, unless it's been explicitly
679 // put in a discarded flowing state via stream.resume().
680 if (ev === 'data') {
681 this[DATALISTENERS] = this.listeners('data').length;
682 if (this[DATALISTENERS] === 0 &&
683 !this[DISCARDED] &&
684 !this[PIPES].length) {
685 this[FLOWING] = false;
686 }
687 }
688 return ret;
689 }
690 /**
691 * Mostly identical to `EventEmitter.removeAllListeners`
692 *
693 * If all 'data' event handlers are removed, and they were the last consumer
694 * (ie, there are no pipe destinations), then the flow of data will stop
695 * until there is another consumer or {@link Minipass#resume} is explicitly
696 * called.
697 */
698 removeAllListeners(ev) {
699 const ret = super.removeAllListeners(ev);
700 if (ev === 'data' || ev === undefined) {
701 this[DATALISTENERS] = 0;
702 if (!this[DISCARDED] && !this[PIPES].length) {
703 this[FLOWING] = false;
704 }
705 }
706 return ret;
707 }
708 /**
709 * true if the 'end' event has been emitted
710 */
711 get emittedEnd() {
712 return this[EMITTED_END];
713 }
714 [MAYBE_EMIT_END]() {
715 if (!this[EMITTING_END] &&
716 !this[EMITTED_END] &&
717 !this[DESTROYED] &&
718 this[BUFFER].length === 0 &&
719 this[EOF]) {
720 this[EMITTING_END] = true;
721 this.emit('end');
722 this.emit('prefinish');
723 this.emit('finish');
724 if (this[CLOSED])
725 this.emit('close');
726 this[EMITTING_END] = false;
727 }
728 }
729 /**
730 * Mostly identical to `EventEmitter.emit`, with the following
731 * behavior differences to prevent data loss and unnecessary hangs:
732 *
733 * If the stream has been destroyed, and the event is something other
734 * than 'close' or 'error', then `false` is returned and no handlers
735 * are called.
736 *
737 * If the event is 'end', and has already been emitted, then the event
738 * is ignored. If the stream is in a paused or non-flowing state, then
739 * the event will be deferred until data flow resumes. If the stream is
740 * async, then handlers will be called on the next tick rather than
741 * immediately.
742 *
743 * If the event is 'close', and 'end' has not yet been emitted, then
744 * the event will be deferred until after 'end' is emitted.
745 *
746 * If the event is 'error', and an AbortSignal was provided for the stream,
747 * and there are no listeners, then the event is ignored, matching the
748 * behavior of node core streams in the presense of an AbortSignal.
749 *
750 * If the event is 'finish' or 'prefinish', then all listeners will be
751 * removed after emitting the event, to prevent double-firing.
752 */
753 emit(ev, ...args) {
754 const data = args[0];
755 // error and close are only events allowed after calling destroy()
756 if (ev !== 'error' &&
757 ev !== 'close' &&
758 ev !== DESTROYED &&
759 this[DESTROYED]) {
760 return false;
761 }
762 else if (ev === 'data') {
763 return !this[OBJECTMODE] && !data
764 ? false
765 : this[ASYNC]
766 ? (defer(() => this[EMITDATA](data)), true)
767 : this[EMITDATA](data);
768 }
769 else if (ev === 'end') {
770 return this[EMITEND]();
771 }
772 else if (ev === 'close') {
773 this[CLOSED] = true;
774 // don't emit close before 'end' and 'finish'
775 if (!this[EMITTED_END] && !this[DESTROYED])
776 return false;
777 const ret = super.emit('close');
778 this.removeAllListeners('close');
779 return ret;
780 }
781 else if (ev === 'error') {
782 this[EMITTED_ERROR] = data;
783 super.emit(ERROR, data);
784 const ret = !this[SIGNAL] || this.listeners('error').length
785 ? super.emit('error', data)
786 : false;
787 this[MAYBE_EMIT_END]();
788 return ret;
789 }
790 else if (ev === 'resume') {
791 const ret = super.emit('resume');
792 this[MAYBE_EMIT_END]();
793 return ret;
794 }
795 else if (ev === 'finish' || ev === 'prefinish') {
796 const ret = super.emit(ev);
797 this.removeAllListeners(ev);
798 return ret;
799 }
800 // Some other unknown event
801 const ret = super.emit(ev, ...args);
802 this[MAYBE_EMIT_END]();
803 return ret;
804 }
805 [EMITDATA](data) {
806 for (const p of this[PIPES]) {
807 if (p.dest.write(data) === false)
808 this.pause();
809 }
810 const ret = this[DISCARDED] ? false : super.emit('data', data);
811 this[MAYBE_EMIT_END]();
812 return ret;
813 }
814 [EMITEND]() {
815 if (this[EMITTED_END])
816 return false;
817 this[EMITTED_END] = true;
818 this.readable = false;
819 return this[ASYNC]
820 ? (defer(() => this[EMITEND2]()), true)
821 : this[EMITEND2]();
822 }
823 [EMITEND2]() {
824 if (this[DECODER]) {
825 const data = this[DECODER].end();
826 if (data) {
827 for (const p of this[PIPES]) {
828 p.dest.write(data);
829 }
830 if (!this[DISCARDED])
831 super.emit('data', data);
832 }
833 }
834 for (const p of this[PIPES]) {
835 p.end();
836 }
837 const ret = super.emit('end');
838 this.removeAllListeners('end');
839 return ret;
840 }
841 /**
842 * Return a Promise that resolves to an array of all emitted data once
843 * the stream ends.
844 */
845 async collect() {
846 const buf = Object.assign([], {
847 dataLength: 0,
848 });
849 if (!this[OBJECTMODE])
850 buf.dataLength = 0;
851 // set the promise first, in case an error is raised
852 // by triggering the flow here.
853 const p = this.promise();
854 this.on('data', c => {
855 buf.push(c);
856 if (!this[OBJECTMODE])
857 buf.dataLength += c.length;
858 });
859 await p;
860 return buf;
861 }
862 /**
863 * Return a Promise that resolves to the concatenation of all emitted data
864 * once the stream ends.
865 *
866 * Not allowed on objectMode streams.
867 */
868 async concat() {
869 if (this[OBJECTMODE]) {
870 throw new Error('cannot concat in objectMode');
871 }
872 const buf = await this.collect();
873 return (this[ENCODING]
874 ? buf.join('')
875 : Buffer.concat(buf, buf.dataLength));
876 }
877 /**
878 * Return a void Promise that resolves once the stream ends.
879 */
880 async promise() {
881 return new Promise((resolve, reject) => {
882 this.on(DESTROYED, () => reject(new Error('stream destroyed')));
883 this.on('error', er => reject(er));
884 this.on('end', () => resolve());
885 });
886 }
887 /**
888 * Asynchronous `for await of` iteration.
889 *
890 * This will continue emitting all chunks until the stream terminates.
891 */
892 [Symbol.asyncIterator]() {
893 // set this up front, in case the consumer doesn't call next()
894 // right away.
895 this[DISCARDED] = false;
896 let stopped = false;
897 const stop = async () => {
898 this.pause();
899 stopped = true;
900 return { value: undefined, done: true };
901 };
902 const next = () => {
903 if (stopped)
904 return stop();
905 const res = this.read();
906 if (res !== null)
907 return Promise.resolve({ done: false, value: res });
908 if (this[EOF])
909 return stop();
910 let resolve;
911 let reject;
912 const onerr = (er) => {
913 this.off('data', ondata);
914 this.off('end', onend);
915 this.off(DESTROYED, ondestroy);
916 stop();
917 reject(er);
918 };
919 const ondata = (value) => {
920 this.off('error', onerr);
921 this.off('end', onend);
922 this.off(DESTROYED, ondestroy);
923 this.pause();
924 resolve({ value, done: !!this[EOF] });
925 };
926 const onend = () => {
927 this.off('error', onerr);
928 this.off('data', ondata);
929 this.off(DESTROYED, ondestroy);
930 stop();
931 resolve({ done: true, value: undefined });
932 };
933 const ondestroy = () => onerr(new Error('stream destroyed'));
934 return new Promise((res, rej) => {
935 reject = rej;
936 resolve = res;
937 this.once(DESTROYED, ondestroy);
938 this.once('error', onerr);
939 this.once('end', onend);
940 this.once('data', ondata);
941 });
942 };
943 return {
944 next,
945 throw: stop,
946 return: stop,
947 [Symbol.asyncIterator]() {
948 return this;
949 },
950 [Symbol.asyncDispose]: async () => { },
951 };
952 }
953 /**
954 * Synchronous `for of` iteration.
955 *
956 * The iteration will terminate when the internal buffer runs out, even
957 * if the stream has not yet terminated.
958 */
959 [Symbol.iterator]() {
960 // set this up front, in case the consumer doesn't call next()
961 // right away.
962 this[DISCARDED] = false;
963 let stopped = false;
964 const stop = () => {
965 this.pause();
966 this.off(ERROR, stop);
967 this.off(DESTROYED, stop);
968 this.off('end', stop);
969 stopped = true;
970 return { done: true, value: undefined };
971 };
972 const next = () => {
973 if (stopped)
974 return stop();
975 const value = this.read();
976 return value === null ? stop() : { done: false, value };
977 };
978 this.once('end', stop);
979 this.once(ERROR, stop);
980 this.once(DESTROYED, stop);
981 return {
982 next,
983 throw: stop,
984 return: stop,
985 [Symbol.iterator]() {
986 return this;
987 },
988 [Symbol.dispose]: () => { },
989 };
990 }
991 /**
992 * Destroy a stream, preventing it from being used for any further purpose.
993 *
994 * If the stream has a `close()` method, then it will be called on
995 * destruction.
996 *
997 * After destruction, any attempt to write data, read data, or emit most
998 * events will be ignored.
999 *
1000 * If an error argument is provided, then it will be emitted in an
1001 * 'error' event.
1002 */
1003 destroy(er) {
1004 if (this[DESTROYED]) {
1005 if (er)
1006 this.emit('error', er);
1007 else
1008 this.emit(DESTROYED);
1009 return this;
1010 }
1011 this[DESTROYED] = true;
1012 this[DISCARDED] = true;
1013 // throw away all buffered data, it's never coming out
1014 this[BUFFER].length = 0;
1015 this[BUFFERLENGTH] = 0;
1016 const wc = this;
1017 if (typeof wc.close === 'function' && !this[CLOSED])
1018 wc.close();
1019 if (er)
1020 this.emit('error', er);
1021 // if no error to emit, still reject pending promises
1022 else
1023 this.emit(DESTROYED);
1024 return this;
1025 }
1026 /**
1027 * Alias for {@link isStream}
1028 *
1029 * Former export location, maintained for backwards compatibility.
1030 *
1031 * @deprecated
1032 */
1033 static get isStream() {
1034 return exports.isStream;
1035 }
1036}
1037exports.Minipass = Minipass;
1038//# sourceMappingURL=index.js.map