javascriptnode.js

How to create a writable byte stream I can evaluate?


I want to wrap a array, e.g. an Uint8Array, into a NodeJS.WritableStream so I can read its content later. How can I do that?

Background: For testing my winston logger, I want to set up a custom transport which just holds all the logged data in a manner I can evaluate it later. The example reads like this:

logger.add(new winston.transports.Stream({
  stream: fs.createWriteStream('/dev/null')
  /* other options */
}));

But if I create the stream like fs.createWriteStream('/dev/null'), I cannot see its content, and it won't run under Windows (or at least I'm having issues here atm). And why would I need fs anyway?

To give another illustration where I'm coming from, let's take this arbitraty example from Go:

buf := bytes.Buffer{}
// zerolog.New() expects an io.Writable, similar to a NodeJS.WritableStream
logger := zerolog.New(&buf)
logger.Info().Msg("Hello World")
// I can access the written data by acessing the underlying buffer
assert.Equal(t, buf.String(), "{\"level\":\"info\",\"message\":\"Hello World\"}\n")

Note this isn't a specific thing for zerolog, but a illustration on how to set up an io.writer in manner to access the underlying, "written" data. This is what I hope to achieve with a NodeJS.WritableStream implementation as well.

I tried to find a way around with an event listener, but didn't suceed yet.


Solution

  • For completeness sake, here the solution @Bergi provided. While it's not possible to set an underlying buffer as in Go oder Java, we work a callback to create a writable stream which can be evaluated. For that we have to create an own implementation of WritableStream with the help of the (abstract) implementation Writable:

    import { Writable } from 'node:stream';
    import * as winston from 'winston';
    
    let logged: string = '';
    const writable = new Writable({
      write(chunk: Buffer, _encoding, done) {
        logged += chunk.toString();
        done();
      },
    });
    
    // for my concrete use case
    expect(logged).toEqual(winston.createLogger({transports: new winston.transports.Stream({ stream: writable })}).info('some text'))