summaryrefslogtreecommitdiff
path: root/node_modules/minipass/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/minipass/README.md')
-rw-r--r--node_modules/minipass/README.md825
1 files changed, 825 insertions, 0 deletions
diff --git a/node_modules/minipass/README.md b/node_modules/minipass/README.md
new file mode 100644
index 0000000..1126330
--- /dev/null
+++ b/node_modules/minipass/README.md
@@ -0,0 +1,825 @@
+# minipass
+
+A _very_ minimal implementation of a [PassThrough
+stream](https://nodejs.org/api/stream.html#stream_class_stream_passthrough)
+
+[It's very
+fast](https://docs.google.com/spreadsheets/d/1K_HR5oh3r80b8WVMWCPPjfuWXUgfkmhlX7FGI6JJ8tY/edit?usp=sharing)
+for objects, strings, and buffers.
+
+Supports `pipe()`ing (including multi-`pipe()` and backpressure
+transmission), buffering data until either a `data` event handler
+or `pipe()` is added (so you don't lose the first chunk), and
+most other cases where PassThrough is a good idea.
+
+There is a `read()` method, but it's much more efficient to
+consume data from this stream via `'data'` events or by calling
+`pipe()` into some other stream. Calling `read()` requires the
+buffer to be flattened in some cases, which requires copying
+memory.
+
+If you set `objectMode: true` in the options, then whatever is
+written will be emitted. Otherwise, it'll do a minimal amount of
+Buffer copying to ensure proper Streams semantics when `read(n)`
+is called.
+
+`objectMode` can only be set at instantiation. Attempting to
+write something other than a String or Buffer without having set
+`objectMode` in the options will throw an error.
+
+This is not a `through` or `through2` stream. It doesn't
+transform the data, it just passes it right through. If you want
+to transform the data, extend the class, and override the
+`write()` method. Once you're done transforming the data however
+you want, call `super.write()` with the transform output.
+
+For some examples of streams that extend Minipass in various
+ways, check out:
+
+- [minizlib](http://npm.im/minizlib)
+- [fs-minipass](http://npm.im/fs-minipass)
+- [tar](http://npm.im/tar)
+- [minipass-collect](http://npm.im/minipass-collect)
+- [minipass-flush](http://npm.im/minipass-flush)
+- [minipass-pipeline](http://npm.im/minipass-pipeline)
+- [tap](http://npm.im/tap)
+- [tap-parser](http://npm.im/tap-parser)
+- [treport](http://npm.im/treport)
+- [minipass-fetch](http://npm.im/minipass-fetch)
+- [pacote](http://npm.im/pacote)
+- [make-fetch-happen](http://npm.im/make-fetch-happen)
+- [cacache](http://npm.im/cacache)
+- [ssri](http://npm.im/ssri)
+- [npm-registry-fetch](http://npm.im/npm-registry-fetch)
+- [minipass-json-stream](http://npm.im/minipass-json-stream)
+- [minipass-sized](http://npm.im/minipass-sized)
+
+## Usage in TypeScript
+
+The `Minipass` class takes three type template definitions:
+
+- `RType` the type being read, which defaults to `Buffer`. If
+ `RType` is `string`, then the constructor _must_ get an options
+ object specifying either an `encoding` or `objectMode: true`.
+ If it's anything other than `string` or `Buffer`, then it
+ _must_ get an options object specifying `objectMode: true`.
+- `WType` the type being written. If `RType` is `Buffer` or
+ `string`, then this defaults to `ContiguousData` (Buffer,
+ string, ArrayBuffer, or ArrayBufferView). Otherwise, it
+ defaults to `RType`.
+- `Events` type mapping event names to the arguments emitted
+ with that event, which extends `Minipass.Events`.
+
+To declare types for custom events in subclasses, extend the
+third parameter with your own event signatures. For example:
+
+```js
+import { Minipass } from 'minipass'
+
+// a NDJSON stream that emits 'jsonError' when it can't stringify
+export interface Events extends Minipass.Events {
+ jsonError: [e: Error]
+}
+
+export class NDJSONStream extends Minipass<string, any, Events> {
+ constructor() {
+ super({ objectMode: true })
+ }
+
+ // data is type `any` because that's WType
+ write(data, encoding, cb) {
+ try {
+ const json = JSON.stringify(data)
+ return super.write(json + '\n', encoding, cb)
+ } catch (er) {
+ if (!er instanceof Error) {
+ er = Object.assign(new Error('json stringify failed'), {
+ cause: er,
+ })
+ }
+ // trying to emit with something OTHER than an error will
+ // fail, because we declared the event arguments type.
+ this.emit('jsonError', er)
+ }
+ }
+}
+
+const s = new NDJSONStream()
+s.on('jsonError', e => {
+ // here, TS knows that e is an Error
+})
+```
+
+Emitting/handling events that aren't declared in this way is
+fine, but the arguments will be typed as `unknown`.
+
+## Differences from Node.js Streams
+
+There are several things that make Minipass streams different
+from (and in some ways superior to) Node.js core streams.
+
+Please read these caveats if you are familiar with node-core
+streams and intend to use Minipass streams in your programs.
+
+You can avoid most of these differences entirely (for a very
+small performance penalty) by setting `{async: true}` in the
+constructor options.
+
+### Timing
+
+Minipass streams are designed to support synchronous use-cases.
+Thus, data is emitted as soon as it is available, always. It is
+buffered until read, but no longer. Another way to look at it is
+that Minipass streams are exactly as synchronous as the logic
+that writes into them.
+
+This can be surprising if your code relies on
+`PassThrough.write()` always providing data on the next tick
+rather than the current one, or being able to call `resume()` and
+not have the entire buffer disappear immediately.
+
+However, without this synchronicity guarantee, there would be no
+way for Minipass to achieve the speeds it does, or support the
+synchronous use cases that it does. Simply put, waiting takes
+time.
+
+This non-deferring approach makes Minipass streams much easier to
+reason about, especially in the context of Promises and other
+flow-control mechanisms.
+
+Example:
+
+```js
+// hybrid module, either works
+import { Minipass } from 'minipass'
+// or:
+const { Minipass } = require('minipass')
+
+const stream = new Minipass()
+stream.on('data', () => console.log('data event'))
+console.log('before write')
+stream.write('hello')
+console.log('after write')
+// output:
+// before write
+// data event
+// after write
+```
+
+### Exception: Async Opt-In
+
+If you wish to have a Minipass stream with behavior that more
+closely mimics Node.js core streams, you can set the stream in
+async mode either by setting `async: true` in the constructor
+options, or by setting `stream.async = true` later on.
+
+```js
+// hybrid module, either works
+import { Minipass } from 'minipass'
+// or:
+const { Minipass } = require('minipass')
+
+const asyncStream = new Minipass({ async: true })
+asyncStream.on('data', () => console.log('data event'))
+console.log('before write')
+asyncStream.write('hello')
+console.log('after write')
+// output:
+// before write
+// after write
+// data event <-- this is deferred until the next tick
+```
+
+Switching _out_ of async mode is unsafe, as it could cause data
+corruption, and so is not enabled. Example:
+
+```js
+import { Minipass } from 'minipass'
+const stream = new Minipass({ encoding: 'utf8' })
+stream.on('data', chunk => console.log(chunk))
+stream.async = true
+console.log('before writes')
+stream.write('hello')
+setStreamSyncAgainSomehow(stream) // <-- this doesn't actually exist!
+stream.write('world')
+console.log('after writes')
+// hypothetical output would be:
+// before writes
+// world
+// after writes
+// hello
+// NOT GOOD!
+```
+
+To avoid this problem, once set into async mode, any attempt to
+make the stream sync again will be ignored.
+
+```js
+const { Minipass } = require('minipass')
+const stream = new Minipass({ encoding: 'utf8' })
+stream.on('data', chunk => console.log(chunk))
+stream.async = true
+console.log('before writes')
+stream.write('hello')
+stream.async = false // <-- no-op, stream already async
+stream.write('world')
+console.log('after writes')
+// actual output:
+// before writes
+// after writes
+// hello
+// world
+```
+
+### No High/Low Water Marks
+
+Node.js core streams will optimistically fill up a buffer,
+returning `true` on all writes until the limit is hit, even if
+the data has nowhere to go. Then, they will not attempt to draw
+more data in until the buffer size dips below a minimum value.
+
+Minipass streams are much simpler. The `write()` method will
+return `true` if the data has somewhere to go (which is to say,
+given the timing guarantees, that the data is already there by
+the time `write()` returns).
+
+If the data has nowhere to go, then `write()` returns false, and
+the data sits in a buffer, to be drained out immediately as soon
+as anyone consumes it.
+
+Since nothing is ever buffered unnecessarily, there is much less
+copying data, and less bookkeeping about buffer capacity levels.
+
+### Hazards of Buffering (or: Why Minipass Is So Fast)
+
+Since data written to a Minipass stream is immediately written
+all the way through the pipeline, and `write()` always returns
+true/false based on whether the data was fully flushed,
+backpressure is communicated immediately to the upstream caller.
+This minimizes buffering.
+
+Consider this case:
+
+```js
+const { PassThrough } = require('stream')
+const p1 = new PassThrough({ highWaterMark: 1024 })
+const p2 = new PassThrough({ highWaterMark: 1024 })
+const p3 = new PassThrough({ highWaterMark: 1024 })
+const p4 = new PassThrough({ highWaterMark: 1024 })
+
+p1.pipe(p2).pipe(p3).pipe(p4)
+p4.on('data', () => console.log('made it through'))
+
+// this returns false and buffers, then writes to p2 on next tick (1)
+// p2 returns false and buffers, pausing p1, then writes to p3 on next tick (2)
+// p3 returns false and buffers, pausing p2, then writes to p4 on next tick (3)
+// p4 returns false and buffers, pausing p3, then emits 'data' and 'drain'
+// on next tick (4)
+// p3 sees p4's 'drain' event, and calls resume(), emitting 'resume' and
+// 'drain' on next tick (5)
+// p2 sees p3's 'drain', calls resume(), emits 'resume' and 'drain' on next tick (6)
+// p1 sees p2's 'drain', calls resume(), emits 'resume' and 'drain' on next
+// tick (7)
+
+p1.write(Buffer.alloc(2048)) // returns false
+```
+
+Along the way, the data was buffered and deferred at each stage,
+and multiple event deferrals happened, for an unblocked pipeline
+where it was perfectly safe to write all the way through!
+
+Furthermore, setting a `highWaterMark` of `1024` might lead
+someone reading the code to think an advisory maximum of 1KiB is
+being set for the pipeline. However, the actual advisory
+buffering level is the _sum_ of `highWaterMark` values, since
+each one has its own bucket.
+
+Consider the Minipass case:
+
+```js
+const m1 = new Minipass()
+const m2 = new Minipass()
+const m3 = new Minipass()
+const m4 = new Minipass()
+
+m1.pipe(m2).pipe(m3).pipe(m4)
+m4.on('data', () => console.log('made it through'))
+
+// m1 is flowing, so it writes the data to m2 immediately
+// m2 is flowing, so it writes the data to m3 immediately
+// m3 is flowing, so it writes the data to m4 immediately
+// m4 is flowing, so it fires the 'data' event immediately, returns true
+// m4's write returned true, so m3 is still flowing, returns true
+// m3's write returned true, so m2 is still flowing, returns true
+// m2's write returned true, so m1 is still flowing, returns true
+// No event deferrals or buffering along the way!
+
+m1.write(Buffer.alloc(2048)) // returns true
+```
+
+It is extremely unlikely that you _don't_ want to buffer any data
+written, or _ever_ buffer data that can be flushed all the way
+through. Neither node-core streams nor Minipass ever fail to
+buffer written data, but node-core streams do a lot of
+unnecessary buffering and pausing.
+
+As always, the faster implementation is the one that does less
+stuff and waits less time to do it.
+
+### Immediately emit `end` for empty streams (when not paused)
+
+If a stream is not paused, and `end()` is called before writing
+any data into it, then it will emit `end` immediately.
+
+If you have logic that occurs on the `end` event which you don't
+want to potentially happen immediately (for example, closing file
+descriptors, moving on to the next entry in an archive parse
+stream, etc.) then be sure to call `stream.pause()` on creation,
+and then `stream.resume()` once you are ready to respond to the
+`end` event.
+
+However, this is _usually_ not a problem because:
+
+### Emit `end` When Asked
+
+One hazard of immediately emitting `'end'` is that you may not
+yet have had a chance to add a listener. In order to avoid this
+hazard, Minipass streams safely re-emit the `'end'` event if a
+new listener is added after `'end'` has been emitted.
+
+Ie, if you do `stream.on('end', someFunction)`, and the stream
+has already emitted `end`, then it will call the handler right
+away. (You can think of this somewhat like attaching a new
+`.then(fn)` to a previously-resolved Promise.)
+
+To prevent calling handlers multiple times who would not expect
+multiple ends to occur, all listeners are removed from the
+`'end'` event whenever it is emitted.
+
+### Emit `error` When Asked
+
+The most recent error object passed to the `'error'` event is
+stored on the stream. If a new `'error'` event handler is added,
+and an error was previously emitted, then the event handler will
+be called immediately (or on `process.nextTick` in the case of
+async streams).
+
+This makes it much more difficult to end up trying to interact
+with a broken stream, if the error handler is added after an
+error was previously emitted.
+
+### Impact of "immediate flow" on Tee-streams
+
+A "tee stream" is a stream piping to multiple destinations:
+
+```js
+const tee = new Minipass()
+t.pipe(dest1)
+t.pipe(dest2)
+t.write('foo') // goes to both destinations
+```
+
+Since Minipass streams _immediately_ process any pending data
+through the pipeline when a new pipe destination is added, this
+can have surprising effects, especially when a stream comes in
+from some other function and may or may not have data in its
+buffer.
+
+```js
+// WARNING! WILL LOSE DATA!
+const src = new Minipass()
+src.write('foo')
+src.pipe(dest1) // 'foo' chunk flows to dest1 immediately, and is gone
+src.pipe(dest2) // gets nothing!
+```
+
+One solution is to create a dedicated tee-stream junction that
+pipes to both locations, and then pipe to _that_ instead.
+
+```js
+// Safe example: tee to both places
+const src = new Minipass()
+src.write('foo')
+const tee = new Minipass()
+tee.pipe(dest1)
+tee.pipe(dest2)
+src.pipe(tee) // tee gets 'foo', pipes to both locations
+```
+
+The same caveat applies to `on('data')` event listeners. The
+first one added will _immediately_ receive all of the data,
+leaving nothing for the second:
+
+```js
+// WARNING! WILL LOSE DATA!
+const src = new Minipass()
+src.write('foo')
+src.on('data', handler1) // receives 'foo' right away
+src.on('data', handler2) // nothing to see here!
+```
+
+Using a dedicated tee-stream can be used in this case as well:
+
+```js
+// Safe example: tee to both data handlers
+const src = new Minipass()
+src.write('foo')
+const tee = new Minipass()
+tee.on('data', handler1)
+tee.on('data', handler2)
+src.pipe(tee)
+```
+
+All of the hazards in this section are avoided by setting `{
+async: true }` in the Minipass constructor, or by setting
+`stream.async = true` afterwards. Note that this does add some
+overhead, so should only be done in cases where you are willing
+to lose a bit of performance in order to avoid having to refactor
+program logic.
+
+## USAGE
+
+It's a stream! Use it like a stream and it'll most likely do what
+you want.
+
+```js
+import { Minipass } from 'minipass'
+const mp = new Minipass(options) // options is optional
+mp.write('foo')
+mp.pipe(someOtherStream)
+mp.end('bar')
+```
+
+### OPTIONS
+
+- `encoding` How would you like the data coming _out_ of the
+ stream to be encoded? Accepts any values that can be passed to
+ `Buffer.toString()`.
+- `objectMode` Emit data exactly as it comes in. This will be
+ flipped on by default if you write() something other than a
+ string or Buffer at any point. Setting `objectMode: true` will
+ prevent setting any encoding value.
+- `async` Defaults to `false`. Set to `true` to defer data
+ emission until next tick. This reduces performance slightly,
+ but makes Minipass streams use timing behavior closer to Node
+ core streams. See [Timing](#timing) for more details.
+- `signal` An `AbortSignal` that will cause the stream to unhook
+ itself from everything and become as inert as possible. Note
+ that providing a `signal` parameter will make `'error'` events
+ no longer throw if they are unhandled, but they will still be
+ emitted to handlers if any are attached.
+
+### API
+
+Implements the user-facing portions of Node.js's `Readable` and
+`Writable` streams.
+
+### Methods
+
+- `write(chunk, [encoding], [callback])` - Put data in. (Note
+ that, in the base Minipass class, the same data will come out.)
+ Returns `false` if the stream will buffer the next write, or
+ true if it's still in "flowing" mode.
+- `end([chunk, [encoding]], [callback])` - Signal that you have
+ no more data to write. This will queue an `end` event to be
+ fired when all the data has been consumed.
+- `pause()` - No more data for a while, please. This also
+ prevents `end` from being emitted for empty streams until the
+ stream is resumed.
+- `resume()` - Resume the stream. If there's data in the buffer,
+ it is all discarded. Any buffered events are immediately
+ emitted.
+- `pipe(dest)` - Send all output to the stream provided. When
+ data is emitted, it is immediately written to any and all pipe
+ destinations. (Or written on next tick in `async` mode.)
+- `unpipe(dest)` - Stop piping to the destination stream. This is
+ immediate, meaning that any asynchronously queued data will
+ _not_ make it to the destination when running in `async` mode.
+ - `options.end` - Boolean, end the destination stream when the
+ source stream ends. Default `true`.
+ - `options.proxyErrors` - Boolean, proxy `error` events from
+ the source stream to the destination stream. Note that errors
+ are _not_ proxied after the pipeline terminates, either due
+ to the source emitting `'end'` or manually unpiping with
+ `src.unpipe(dest)`. Default `false`.
+- `on(ev, fn)`, `emit(ev, fn)` - Minipass streams are
+ EventEmitters. Some events are given special treatment,
+ however. (See below under "events".)
+- `promise()` - Returns a Promise that resolves when the stream
+ emits `end`, or rejects if the stream emits `error`.
+- `collect()` - Return a Promise that resolves on `end` with an
+ array containing each chunk of data that was emitted, or
+ rejects if the stream emits `error`. Note that this consumes
+ the stream data.
+- `concat()` - Same as `collect()`, but concatenates the data
+ into a single Buffer object. Will reject the returned promise
+ if the stream is in objectMode, or if it goes into objectMode
+ by the end of the data.
+- `read(n)` - Consume `n` bytes of data out of the buffer. If `n`
+ is not provided, then consume all of it. If `n` bytes are not
+ available, then it returns null. **Note** consuming streams in
+ this way is less efficient, and can lead to unnecessary Buffer
+ copying.
+- `destroy([er])` - Destroy the stream. If an error is provided,
+ then an `'error'` event is emitted. If the stream has a
+ `close()` method, and has not emitted a `'close'` event yet,
+ then `stream.close()` will be called. Any Promises returned by
+ `.promise()`, `.collect()` or `.concat()` will be rejected.
+ After being destroyed, writing to the stream will emit an
+ error. No more data will be emitted if the stream is destroyed,
+ even if it was previously buffered.
+
+### Properties
+
+- `bufferLength` Read-only. Total number of bytes buffered, or in
+ the case of objectMode, the total number of objects.
+- `encoding` Read-only. The encoding that has been set.
+- `flowing` Read-only. Boolean indicating whether a chunk written
+ to the stream will be immediately emitted.
+- `emittedEnd` Read-only. Boolean indicating whether the end-ish
+ events (ie, `end`, `prefinish`, `finish`) have been emitted.
+ Note that listening on any end-ish event will immediateyl
+ re-emit it if it has already been emitted.
+- `writable` Whether the stream is writable. Default `true`. Set
+ to `false` when `end()`
+- `readable` Whether the stream is readable. Default `true`.
+- `pipes` An array of Pipe objects referencing streams that this
+ stream is piping into.
+- `destroyed` A getter that indicates whether the stream was
+ destroyed.
+- `paused` True if the stream has been explicitly paused,
+ otherwise false.
+- `objectMode` Indicates whether the stream is in `objectMode`.
+- `aborted` Readonly property set when the `AbortSignal`
+ dispatches an `abort` event.
+
+### Events
+
+- `data` Emitted when there's data to read. Argument is the data
+ to read. This is never emitted while not flowing. If a listener
+ is attached, that will resume the stream.
+- `end` Emitted when there's no more data to read. This will be
+ emitted immediately for empty streams when `end()` is called.
+ If a listener is attached, and `end` was already emitted, then
+ it will be emitted again. All listeners are removed when `end`
+ is emitted.
+- `prefinish` An end-ish event that follows the same logic as
+ `end` and is emitted in the same conditions where `end` is
+ emitted. Emitted after `'end'`.
+- `finish` An end-ish event that follows the same logic as `end`
+ and is emitted in the same conditions where `end` is emitted.
+ Emitted after `'prefinish'`.
+- `close` An indication that an underlying resource has been
+ released. Minipass does not emit this event, but will defer it
+ until after `end` has been emitted, since it throws off some
+ stream libraries otherwise.
+- `drain` Emitted when the internal buffer empties, and it is
+ again suitable to `write()` into the stream.
+- `readable` Emitted when data is buffered and ready to be read
+ by a consumer.
+- `resume` Emitted when stream changes state from buffering to
+ flowing mode. (Ie, when `resume` is called, `pipe` is called,
+ or a `data` event listener is added.)
+
+### Static Methods
+
+- `Minipass.isStream(stream)` Returns `true` if the argument is a
+ stream, and false otherwise. To be considered a stream, the
+ object must be either an instance of Minipass, or an
+ EventEmitter that has either a `pipe()` method, or both
+ `write()` and `end()` methods. (Pretty much any stream in
+ node-land will return `true` for this.)
+
+## EXAMPLES
+
+Here are some examples of things you can do with Minipass
+streams.
+
+### simple "are you done yet" promise
+
+```js
+mp.promise().then(
+ () => {
+ // stream is finished
+ },
+ er => {
+ // stream emitted an error
+ }
+)
+```
+
+### collecting
+
+```js
+mp.collect().then(all => {
+ // all is an array of all the data emitted
+ // encoding is supported in this case, so
+ // so the result will be a collection of strings if
+ // an encoding is specified, or buffers/objects if not.
+ //
+ // In an async function, you may do
+ // const data = await stream.collect()
+})
+```
+
+### collecting into a single blob
+
+This is a bit slower because it concatenates the data into one
+chunk for you, but if you're going to do it yourself anyway, it's
+convenient this way:
+
+```js
+mp.concat().then(onebigchunk => {
+ // onebigchunk is a string if the stream
+ // had an encoding set, or a buffer otherwise.
+})
+```
+
+### iteration
+
+You can iterate over streams synchronously or asynchronously in
+platforms that support it.
+
+Synchronous iteration will end when the currently available data
+is consumed, even if the `end` event has not been reached. In
+string and buffer mode, the data is concatenated, so unless
+multiple writes are occurring in the same tick as the `read()`,
+sync iteration loops will generally only have a single iteration.
+
+To consume chunks in this way exactly as they have been written,
+with no flattening, create the stream with the `{ objectMode:
+true }` option.
+
+```js
+const mp = new Minipass({ objectMode: true })
+mp.write('a')
+mp.write('b')
+for (let letter of mp) {
+ console.log(letter) // a, b
+}
+mp.write('c')
+mp.write('d')
+for (let letter of mp) {
+ console.log(letter) // c, d
+}
+mp.write('e')
+mp.end()
+for (let letter of mp) {
+ console.log(letter) // e
+}
+for (let letter of mp) {
+ console.log(letter) // nothing
+}
+```
+
+Asynchronous iteration will continue until the end event is reached,
+consuming all of the data.
+
+```js
+const mp = new Minipass({ encoding: 'utf8' })
+
+// some source of some data
+let i = 5
+const inter = setInterval(() => {
+ if (i-- > 0) mp.write(Buffer.from('foo\n', 'utf8'))
+ else {
+ mp.end()
+ clearInterval(inter)
+ }
+}, 100)
+
+// consume the data with asynchronous iteration
+async function consume() {
+ for await (let chunk of mp) {
+ console.log(chunk)
+ }
+ return 'ok'
+}
+
+consume().then(res => console.log(res))
+// logs `foo\n` 5 times, and then `ok`
+```
+
+### subclass that `console.log()`s everything written into it
+
+```js
+class Logger extends Minipass {
+ write(chunk, encoding, callback) {
+ console.log('WRITE', chunk, encoding)
+ return super.write(chunk, encoding, callback)
+ }
+ end(chunk, encoding, callback) {
+ console.log('END', chunk, encoding)
+ return super.end(chunk, encoding, callback)
+ }
+}
+
+someSource.pipe(new Logger()).pipe(someDest)
+```
+
+### same thing, but using an inline anonymous class
+
+```js
+// js classes are fun
+someSource
+ .pipe(
+ new (class extends Minipass {
+ emit(ev, ...data) {
+ // let's also log events, because debugging some weird thing
+ console.log('EMIT', ev)
+ return super.emit(ev, ...data)
+ }
+ write(chunk, encoding, callback) {
+ console.log('WRITE', chunk, encoding)
+ return super.write(chunk, encoding, callback)
+ }
+ end(chunk, encoding, callback) {
+ console.log('END', chunk, encoding)
+ return super.end(chunk, encoding, callback)
+ }
+ })()
+ )
+ .pipe(someDest)
+```
+
+### subclass that defers 'end' for some reason
+
+```js
+class SlowEnd extends Minipass {
+ emit(ev, ...args) {
+ if (ev === 'end') {
+ console.log('going to end, hold on a sec')
+ setTimeout(() => {
+ console.log('ok, ready to end now')
+ super.emit('end', ...args)
+ }, 100)
+ return true
+ } else {
+ return super.emit(ev, ...args)
+ }
+ }
+}
+```
+
+### transform that creates newline-delimited JSON
+
+```js
+class NDJSONEncode extends Minipass {
+ write(obj, cb) {
+ try {
+ // JSON.stringify can throw, emit an error on that
+ return super.write(JSON.stringify(obj) + '\n', 'utf8', cb)
+ } catch (er) {
+ this.emit('error', er)
+ }
+ }
+ end(obj, cb) {
+ if (typeof obj === 'function') {
+ cb = obj
+ obj = undefined
+ }
+ if (obj !== undefined) {
+ this.write(obj)
+ }
+ return super.end(cb)
+ }
+}
+```
+
+### transform that parses newline-delimited JSON
+
+```js
+class NDJSONDecode extends Minipass {
+ constructor(options) {
+ // always be in object mode, as far as Minipass is concerned
+ super({ objectMode: true })
+ this._jsonBuffer = ''
+ }
+ write(chunk, encoding, cb) {
+ if (
+ typeof chunk === 'string' &&
+ typeof encoding === 'string' &&
+ encoding !== 'utf8'
+ ) {
+ chunk = Buffer.from(chunk, encoding).toString()
+ } else if (Buffer.isBuffer(chunk)) {
+ chunk = chunk.toString()
+ }
+ if (typeof encoding === 'function') {
+ cb = encoding
+ }
+ const jsonData = (this._jsonBuffer + chunk).split('\n')
+ this._jsonBuffer = jsonData.pop()
+ for (let i = 0; i < jsonData.length; i++) {
+ try {
+ // JSON.parse can throw, emit an error on that
+ super.write(JSON.parse(jsonData[i]))
+ } catch (er) {
+ this.emit('error', er)
+ continue
+ }
+ }
+ if (cb) cb()
+ }
+}
+```