# Transform Stream
> [Transform stream][transform-stream].
## Usage
```javascript
var transformStream = require( '@stdlib/streams/node/transform' );
```
#### transformStream( \[options] )
Creates a [transform stream][transform-stream].
```javascript
var stdout = require( '@stdlib/streams/node/stdout' );
function transform( chunk, enc, clbk ) {
clbk( null, chunk.toString()+'\n' );
}
var stream = transformStream({
'transform': transform
});
stream.pipe( stdout );
stream.write( '1' );
stream.write( '2' );
stream.write( '3' );
stream.end();
// e.g., => '1\n2\n3\n'
```
The function accepts the following `options`:
- **transform**: callback to invoke upon receiving a new chunk.
- **flush**: callback to invoke after receiving all chunks and prior to a stream closing.
- **objectMode**: specifies whether a [stream][stream] should operate in [objectMode][object-mode]. Default: `false`.
- **encoding**: specifies how `Buffer` objects should be decoded to `strings`. Default: `null`.
- **highWaterMark**: specifies the `Buffer` level at which `write()` calls start returning `false`.
- **allowHalfOpen**: specifies whether a [stream][stream] should remain open even if one side ends. Default: `false`.
- **decodeStrings**: specifies whether to decode `strings` into `Buffer` objects when writing. Default: `true`.
To set [stream][stream] `options`,
```javascript
var opts = {
'objectMode': true,
'encoding': 'utf8',
'highWaterMark': 64,
'allowHalfOpen': true,
'decodeStrings': false
};
var stream = transformStream( opts );
```
The `transform` option should be a `function` having the following signature:
```javascript
function transform( chunk, enc, clbk ) {
var multipleData;
var err;
if ( multipleData ) {
// Push as many chunks as required...
this.push( chunk );
this.push( chunk );
// ...
if ( err ) {
return clbk( err );
}
return clbk();
}
if ( err ) {
return clbk( err );
}
clbk( null, chunk );
}
```
The `flush` option should be a `function` which performs any remaining tasks before the stream closes, such as unfinished data processing.
```javascript
function flush( clbk ) {
var err;
// Push any remaining chunks...
this.push( '...' );
this.push( '...' );
// ...
if ( err ) {
return clbk( err );
}
clbk();
}
```
If no `transform` is provided, the returned `stream` will be a simple pass through stream.
#### transformStream.factory( \[options] )
Returns a `function` for creating [streams][transform-stream] which are identically configured according to provided `options`.
```javascript
var opts = {
'objectMode': true,
'encoding': 'utf8',
'highWaterMark': 64
};
var factory = transformStream.factory( opts );
```
This method accepts the same `options` as [`transformStream()`](#transform-stream), **except** for the `transform` and `flush` options which must be provided **explicitly**, as shown below.
##### factory( transform\[, flush] )
Creates a [transform stream][transform-stream].
```javascript
function transform1( chunk, enc, clbk ) {
clbk( null, chunk.toString()+'\n' );
}
function transform2( chunk, enc, clbk ) {
clbk( null, chunk.toString()+'\t' );
}
function flush( clbk ) {
clbk();
}
var factory = transformStream.factory();
var s1 = factory( transform1 );
var s2 = factory( transform2, flush );
```
#### transformStream.objectMode( \[options] )
This method is a convenience function to create [streams][stream] which always operate in [objectMode][object-mode].
```javascript
var stdout = require( '@stdlib/streams/node/stdout' );
function stringify( chunk, enc, clbk ) {
clbk( null, JSON.stringify( chunk ) );
}
function newline( chunk, enc, clbk ) {
clbk( null, chunk+'\n' );
}
var s1 = transformStream.objectMode({
'transform': stringify
});
var s2 = transformStream.objectMode({
'transform': newline
});
s1.pipe( s2 ).pipe( stdout );
s1.write( { 'value': 'a' } );
s1.write( { 'value': 'b' } );
s1.write( { 'value': 'c' } );
s1.end();
// e.g., => '{"value":"a"}\n{"value":"b"}\n{"value":"c"}\n'
```
This method accepts the same `options` as [`transformStream()`](#transform-stream); however, the method will **always** override the [objectMode][object-mode] option in `options`.
#### transformStream.ctor( \[options] )
Instead of returning a [transform stream][transform-stream] instance, this method returns a custom [transform stream][transform-stream] constructor. If provided `transform` and `flush` options, these methods are bound to the constructor prototype. If not provided a `transform`, the returned constructor creates simple pass through streams.
```javascript
function transform( chunk, enc, clbk ) {
clbk( null, chunk.toString()+'\n' );
}
function flush( clbk ) {
this.push( 'beep' );
clbk();
}
var opts = {
'transform': transform,
'flush': flush
};
var TransformStream = transformStream.ctor( opts );
var bool = ( TransformStream.prototype._transform === transform );
// returns true
bool = ( TransformStream.prototype._flush === flush );
// returns true
```
The returned constructor accepts the same `options` as documented above, **except** for the `transform` and `flush` options, which are not supported. Any `options` provided to the constructor **override** `options` provided to the constructor factory.
## Examples
```javascript
var stdout = require( '@stdlib/streams/node/stdout' );
var factory = require( '@stdlib/streams/node/transform' ).factory;
function parse( chunk, enc, clbk ) {
clbk( null, JSON.parse( chunk ) );
}
function pluck( chunk, enc, clbk ) {
clbk( null, chunk.value );
}
function square( chunk, enc, clbk ) {
var v = +chunk;
clbk( null, v*v );
}
function toStr( chunk, enc, clbk ) {
clbk( null, chunk.toString() );
}
function join( chunk, enc, clbk ) {
clbk( null, chunk+'\n' );
}
// Create a factory which generates streams running in `objectMode`:
var tStream = factory({
'objectMode': true
});
// Create streams for each transform:
var s1 = tStream( parse );
var s2 = tStream( pluck );
var s3 = tStream( square );
var s4 = tStream( toStr );
var s5 = tStream( join );
// Create the pipeline:
s1.pipe( s2 )
.pipe( s3 )
.pipe( s4 )
.pipe( s5 )
.pipe( stdout );
// Write data to the pipeline...
var v;
var i;
for ( i = 0; i < 100; i++ ) {
v = '{"value":'+i+'}';
s1.write( v, 'utf8' );
}
s1.end();
```
[stream]: https://nodejs.org/api/stream.html
[object-mode]: https://nodejs.org/api/stream.html#stream_object_mode
[transform-stream]: https://nodejs.org/api/stream.html