Skip to content

Commit 2d592ba

Browse files
committed
Merge branch 'async'
Merges #2 Merges #3
2 parents 557e9a0 + d5dbb22 commit 2d592ba

File tree

10 files changed

+147
-67
lines changed

10 files changed

+147
-67
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
/coverage/
22
/lib/
33
/node_modules/
4-
/npm-debug.log
4+
/npm-debug.*

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/coverage/
22
/src/
3+
/test/
34
/.babelrc
45
/.editorconfig
56
/.eslintrc.yml

README.md

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@
1010
[Gulp][Gulp link] plugin for applying arbitrary transformations to
1111
the contents of files.
1212

13-
* **Simple**. Just pass a callback function that takes the current file
14-
contents and returns the desired contents.
15-
* **Flexible**. Receive file contents as a Buffer or a string. Compatible with
16-
pipelines in both buffer mode and streaming mode.
17-
* **Economical**. Reduce the need for gulp-specific plugins by pairing
18-
gulp-transform with ordinary node packages and functions.
19-
2013
## Install
2114

2215
Install via [npm][NPM link]:
@@ -89,9 +82,10 @@ gulp.task('cheerio', function() {
8982

9083
##### transformFn `function`
9184

92-
The callback responsible for the transformation. The return value must be a
93-
string or a Buffer, which will replace the file's contents. The callback
94-
is invoked once per file with the following arguments:
85+
The callback responsible for the transformation, whose return value will replace
86+
the file's contents. The return value may be a string, a Buffer, or a Promise
87+
resolvable to a string or Buffer. The callback is invoked once per file with the
88+
following arguments:
9589

9690
* **contents** `Buffer` | `string` <br>
9791
The initial contents of the file. Contents are passed as a Buffer unless the

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"gulp": "3.x"
3939
},
4040
"dependencies": {
41+
"es6-promise": "^4.0.5",
4142
"gulp-util": "^3.0.7",
4243
"lodash": "^4.13.1"
4344
},
@@ -49,10 +50,10 @@
4950
"chai": "^3.5.0",
5051
"coffee-script": "^1.10.0",
5152
"coveralls": "^2.11.9",
52-
"eslint": "^2.11.1",
53+
"eslint": "^2.13.1",
5354
"event-stream": "^3.3.2",
54-
"istanbul": "1.0.0-alpha.2",
55-
"mocha": "^2.5.3",
55+
"istanbul": "1.1.0-alpha.1",
56+
"mocha": "^3.1.2",
5657
"rimraf": "^2.5.2",
5758
"sinon": "^1.17.4",
5859
"sinon-chai": "^2.8.0"

src/file-stream.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ export class FileStream extends Transform {
1919

2020
_flush(done) {
2121
let contents = Buffer.concat(this.data);
22-
this.push(transform(this.fn, contents, this.file, this.opts));
2322

24-
done();
23+
transform(this.fn, contents, this.file, this.opts).then((result) => {
24+
this.push(result);
25+
done();
26+
}).catch((err) => {
27+
done(err);
28+
});
2529
}
2630

2731
}

src/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@ import {err} from './err';
55
export default function gulpTransform(transformFn, options) {
66
if (isNil(transformFn)) {
77
err('transformFn must be defined');
8-
98
} else if (!isFunction(transformFn)) {
109
err('transformFn must be a function');
11-
1210
} else if (!isNil(options) && !isObject(options)) {
1311
err('options must be an object');
14-
1512
} else {
1613
return new PluginStream(transformFn, options);
1714
}

src/plugin-stream.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ export class PluginStream extends Transform {
1515
let {fn, opts} = this;
1616

1717
if (file.isBuffer()) {
18-
file.contents = transform(fn, file.contents, file, opts);
19-
}
20-
21-
if (file.isStream()) {
18+
transform(fn, file.contents, file, opts).then((result) => {
19+
file.contents = result;
20+
next(null, file);
21+
}).catch((err) => {
22+
next(err);
23+
});
24+
} else if (file.isStream()) {
2225
file.contents = file.contents.pipe(new FileStream(fn, file, opts));
26+
next(null, file);
27+
} else {
28+
next(null, file);
2329
}
24-
25-
next(null, file);
2630
}
27-
2831
}

src/transform.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import {isBuffer, isString} from 'lodash';
1+
import {Promise} from 'es6-promise';
2+
import {isBuffer} from 'lodash';
23
import {err} from './err';
34

4-
export function transform(fn, contents, file, opts) {
5-
let encoded = opts.encoding ? contents.toString(opts.encoding) : contents;
6-
let transformed = fn.call(opts.thisArg, encoded, file);
5+
export function transform(fn, contents, file, {encoding, thisArg}) {
6+
let decoded = encoding ? contents.toString(encoding) : contents;
7+
let transformed = fn.call(thisArg, decoded, file);
78

8-
return isBuffer(transformed) ? transformed :
9-
isString(transformed) ? new Buffer(transformed) :
10-
err('transformFn must return a string or a Buffer');
9+
return Promise.resolve(transformed).then(toBuffer);
10+
}
11+
12+
function toBuffer(contents) {
13+
if (isBuffer(contents)) {
14+
return contents;
15+
} else if (contents != null) {
16+
return new Buffer(String(contents));
17+
} else {
18+
err('transformFn may not return or resolve to null or undefined');
19+
}
1120
}

test/fixtures/fn.coffee

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{Promise} = require 'es6-promise';
12
{spy} = require 'sinon'
23

34
re = /one|two|three/g
@@ -7,11 +8,17 @@ dict =
78
two: 'deux'
89
three: 'trois'
910

11+
translate = (content) ->
12+
content.replace(re, (match) -> dict[match])
13+
1014
exports.stringFn = ->
1115
spy (content) ->
12-
content.replace re, (match) ->
13-
dict[match]
16+
translate(content)
1417

1518
exports.bufferFn = ->
1619
spy (content) ->
1720
Buffer.concat([content, content])
21+
22+
exports.asyncFn = ->
23+
spy (content) ->
24+
return Promise.resolve(translate(content))

test/index.coffee

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
chai = require 'chai'
22
sinonChai = require 'sinon-chai'
33
{match: {any, instanceOf}} = require 'sinon'
4-
{File: {isVinyl}} = require 'gulp-util'
4+
{File: {isVinyl}, PluginError} = require 'gulp-util'
55
{wait} = require 'event-stream'
66
{buffer, string} = require './fixtures/content'
77
{buffered, streaming} = require './fixtures/file'
8-
{bufferFn, stringFn} = require './fixtures/fn'
8+
{bufferFn, stringFn, asyncFn} = require './fixtures/fn'
99
err = require './helpers/err'
1010
transform = require '../src'
1111

@@ -30,10 +30,14 @@ describe 'plugin: gulp-transform', ->
3030
it 'throws PluginError', ->
3131
err -> transform 42
3232

33-
context 'returns neither a string nor a Buffer', ->
33+
context 'returns null or undefined', ->
3434

35-
it 'throws PluginError', ->
36-
err -> transform((content) -> 42).write buffered()
35+
it 'emits PluginError', (done) ->
36+
stream = transform((content) -> null)
37+
stream.write buffered()
38+
stream.on 'error', (err) ->
39+
err.should.be.instanceOf PluginError
40+
done()
3741

3842
context 'returns a Buffer or string', ->
3943
[fn, file] = [null, null]
@@ -52,6 +56,23 @@ describe 'plugin: gulp-transform', ->
5256
it 'is called with vinyl File as second argument', ->
5357
fn.should.have.been.calledWith any, file
5458

59+
context 'returns a Promise that resolves to a string or Buffer', ->
60+
[fn, file] = [null, null]
61+
62+
beforeEach ->
63+
file = buffered()
64+
fn = asyncFn()
65+
transform(fn, {encoding: 'utf8'}).write(file)
66+
67+
it 'is called once per file', ->
68+
fn.should.have.been.calledOnce
69+
70+
it 'is called with contents as first argument', ->
71+
fn.should.have.been.calledWith string
72+
73+
it 'is called with vinyl File as second argument', ->
74+
fn.should.have.been.calledWith any, file
75+
5576
describe 'param: options', ->
5677

5778
context 'not an object', ->
@@ -80,40 +101,83 @@ describe 'plugin: gulp-transform', ->
80101
fn.should.have.been.calledOn undefined
81102

82103
describe 'mode: buffer', ->
83-
file = null
84104

85-
beforeEach (done) ->
86-
transform(bufferFn()).once('data', (_file) ->
87-
file = _file
88-
done()
89-
).write buffered()
105+
context 'synchronous', ->
106+
file = null
107+
108+
beforeEach (done) ->
109+
transform(bufferFn()).once('data', (_file) ->
110+
file = _file
111+
done()
112+
).write buffered()
113+
114+
it 'returns a stream of vinyl Files', ->
115+
isVinyl(file).should.be.true
116+
117+
it 'files are in buffer mode', ->
118+
file.isBuffer().should.be.true;
90119

91-
it 'returns a stream of vinyl Files', ->
92-
isVinyl(file).should.be.true
120+
it 'transforms file contents', ->
121+
file.contents.should.deep.equal Buffer.concat([buffer, buffer])
93122

94-
it 'files are in buffer mode', ->
95-
file.isBuffer().should.be.true;
123+
context 'async', ->
124+
file = null
96125

97-
it 'transforms file contents', ->
98-
file.contents.should.deep.equal Buffer.concat([buffer, buffer])
126+
beforeEach (done) ->
127+
transform(asyncFn(), {encoding: 'utf8'}).once('data', (_file) ->
128+
file = _file
129+
done()
130+
).write buffered()
131+
132+
it 'returns a stream of vinyl Files', ->
133+
isVinyl(file).should.be.true
134+
135+
it 'files are in buffer mode', ->
136+
file.isBuffer().should.be.true;
137+
138+
it 'transforms file contents', ->
139+
file.contents.should.deep.equal new Buffer('un deux trois')
99140

100141
describe 'mode: streaming', ->
101-
file = null
102142

103-
beforeEach (done) ->
104-
transform(stringFn(), {encoding: 'utf8'}).once('data', (_file) ->
105-
file = _file
106-
done()
107-
).write streaming()
143+
context 'synchronous', ->
144+
file = null
108145

109-
it 'returns a stream of vinyl Files', ->
110-
isVinyl(file).should.be.true
146+
beforeEach (done) ->
147+
transform(stringFn(), {encoding: 'utf8'}).once('data', (_file) ->
148+
file = _file
149+
done()
150+
).write streaming()
111151

112-
it 'files are in streaming mode', ->
113-
file.isStream().should.be.true
152+
it 'returns a stream of vinyl Files', ->
153+
isVinyl(file).should.be.true
114154

115-
it 'transforms file contents', (done) ->
116-
file.pipe(wait((err, data) ->
117-
data.should.deep.equal new Buffer('un deux trois')
118-
done()
119-
))
155+
it 'files are in streaming mode', ->
156+
file.isStream().should.be.true
157+
158+
it 'transforms file contents', (done) ->
159+
file.pipe(wait((err, data) ->
160+
data.should.deep.equal new Buffer('un deux trois')
161+
done()
162+
))
163+
164+
context 'async', ->
165+
file = null
166+
167+
beforeEach (done) ->
168+
transform(asyncFn(), {encoding: 'utf8'}).once('data', (_file) ->
169+
file = _file
170+
done()
171+
).write streaming()
172+
173+
it 'returns a stream of vinyl Files', ->
174+
isVinyl(file).should.be.true
175+
176+
it 'files are in streaming mode', ->
177+
file.isStream().should.be.true
178+
179+
it 'transforms file contents', (done) ->
180+
file.pipe(wait((err, data) ->
181+
data.should.deep.equal new Buffer('un deux trois')
182+
done()
183+
))

0 commit comments

Comments
 (0)