Skip to content

Commit

Permalink
async mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonpecora committed May 14, 2015
1 parent e157cae commit 451a5eb
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 14 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,26 @@ gulp.task('minify', function() {

## API ##

### `map(mapper(contents, filename))` ###
### `map(mapper(contents, filename[, done]))` ###

Returns a transform stream that takes vinyl files as input and spits out
their modified copies as output.

`mapper` is a function which will be called once for each file, with two
`mapper` is a function which will be called once for each file, with three
arguments:

* `contents` is a string or [Buffer](http://nodejs.org/api/buffer.html)
* `filename` is the value of `file.path`, which should generally be the file's
absolute path. Might be convenient if you want to filter based on file
extension etc.
* `done` is an _optional_ callback function. If your `mapper` function has a third argument, it will be called asynchronously. If not, the `mapper` will be called synchronously.

The `mapper` function is expected to return a modified string value for the
updated file contents. If nothing is returned, no modifications will be made
to the file contents, but the output file will be cloned.

If you run the `mapper` function asynchronously (by using a third `done` argument), you must call it instead of returning the file contents. It is a node-style callback: `done(err, contents)`

## License ##

MIT. See [LICENSE.md](http://github.com/hughsk/vinyl-map/blob/master/LICENSE.md) for details.
33 changes: 23 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,36 @@ function map(fn) {
}))
}

function postMap(file, next, contents, mapped) {
if (mapped === undefined) mapped = contents
if (file.isBuffer()) file.contents = new Buffer(mapped)
if (file.isStream()) file.contents = from([mapped])

push(file, next)
}

function map(file, next, contents) {
file = file.clone()
contents = arguments.length < 3
? file.contents
: contents

try {
var mapped = fn(contents, file.path)
} catch(err) {
return stream.emit('error', err)
}

if (mapped === undefined) mapped = contents
if (file.isBuffer()) file.contents = new Buffer(mapped)
if (file.isStream()) file.contents = from([mapped])
if (fn.length === 3) {
// contents, filename, done (async)
fn(contents, file.path, function(err, mapped) {
if (err) stream.emit('error', err)
else postMap(file, next, contents, mapped)
})
} else {
// contents and/or filename (sync)
try {
var mapped = fn(contents, file.path)
} catch(err) {
return stream.emit('error', err)
}

push(file, next)
postMap(file, next, contents, mapped)
}
}

function push(file, next) {
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
"new-from": "0.0.3"
},
"devDependencies": {
"concat-stream": "^1.4.8",
"gulp": "~3.5.2",
"tape": "~2.3.2",
"vinyl": "~0.2.1",
"uglify-js": "~2.4.12",
"gulp": "~3.5.2"
"vinyl": "~0.2.1"
},
"scripts": {
"test": "node test"
Expand Down
38 changes: 38 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,41 @@ test('first thrown error in sync mapper gets emitted as an error', function(t) {
stream.write(new File({ contents: new Buffer(' ') }))
stream.end()
})

test('async with third arg passed in', function(t) {
t.plan(5)

var contents = fs.readFileSync(__filename)
var file = new File({
contents: contents
})

var stream = map(function(src, filename, done) {
t.ok(Buffer.isBuffer(src), 'Buffer.isBuffer(contents)')
t.equal(String(contents), String(src), 'Buffer contents are correct')
done(null, String(src).toUpperCase())
}).on('data', function(file) {
t.ok(Buffer.isBuffer(file.contents), 'output contents are a buffer')
t.equal(String(file.contents), String(contents).toUpperCase())
})

stream.once('end', function() {
t.pass('Reached "end" event')
}).end(file)
})

test('async emits error if passed to done', function(t) {
t.plan(1)

var stream = map(function(src, filename, done) {
done(new Error('should be caught'))
}).on('error', function(err) {
t.ok(err, 'error was caught and emitted')
}).on('data', function() {
t.fail('should not get emitted as "data"')
})

stream.write(new File({ contents: new Buffer(' ') }))
stream.write(new File({ contents: new Buffer(' ') }))
stream.end()
})

0 comments on commit 451a5eb

Please sign in to comment.