diff --git a/README.md b/README.md index 5e8bf66..0571f66 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,23 @@ gulp.task('test', ['pre-test'], function () { }); ``` +#### Source Maps +gulp-istanbul supports [gulp-sourcemaps][gulp-sourcemaps] when instrumenting: + + +```javascript +gulp.task('pre-test', function () { + return gulp.src(['lib/**/*.js']) + // optionally load existing source maps + .pipe(sourcemaps.init()) + // Covering files + .pipe(istanbul()) + .pipe(sourcemaps.write('.')) + // Write the covered files to a temporary directory + .pipe(gulp.dest('test-tmp/')); +}); +``` + API -------------- @@ -305,6 +322,7 @@ License [istanbul]: http://gotwarlost.github.io/istanbul/ [gulp]: https://github.com/gulpjs/gulp +[gulp-sourcemaps]: https://github.com/floridoo/gulp-sourcemaps [npm-url]: https://npmjs.org/package/gulp-istanbul [npm-image]: https://badge.fury.io/js/gulp-istanbul.svg diff --git a/index.js b/index.js index 0ad4e27..043ced9 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ var checker = require('istanbul-threshold-checker'); var istanbul = require('istanbul'); var gutil = require('gulp-util'); var _ = require('lodash'); +var applySourceMap = require('vinyl-sourcemaps-apply'); var Report = istanbul.Report; var Collector = istanbul.Collector; var PluginError = gutil.PluginError; @@ -23,15 +24,29 @@ var plugin = module.exports = function (opts) { }); opts.includeUntested = opts.includeUntested === true; - var instrumenter = new opts.instrumenter(opts); - return through(function (file, enc, cb) { + var fileContents = file.contents.toString(); + var fileOpts = _.cloneDeep(opts); + + if (file.sourceMap) { + fileOpts = _.defaultsDeep(fileOpts, { + codeGenerationOptions: { + sourceMap: file.sourceMap.file, + sourceMapWithCode: true, + sourceContent: fileContents, + sourceMapRoot: file.sourceMap.sourceRoot, + file: file.path + } + }); + } + var instrumenter = new opts.instrumenter(fileOpts); + cb = _.once(cb); if (!(file.contents instanceof Buffer)) { return cb(new PluginError(PLUGIN_NAME, 'streams not supported')); } - instrumenter.instrument(file.contents.toString(), file.path, function (err, code) { + instrumenter.instrument(fileContents, file.path, function (err, code) { if (err) { return cb(new PluginError( PLUGIN_NAME, @@ -39,6 +54,11 @@ var plugin = module.exports = function (opts) { )); } + var sourceMap = instrumenter.lastSourceMap(); + if (sourceMap !== null) { + applySourceMap(file, sourceMap.toString()); + } + file.contents = new Buffer(code); // Parse the blank coverage object from the instrumented file and save it diff --git a/package.json b/package.json index 0b9bfe9..72d9b72 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,13 @@ "istanbul": "^0.4.0", "istanbul-threshold-checker": "^0.1.0", "lodash": "^4.0.0", - "through2": "^2.0.0" + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.1" }, "devDependencies": { "gulp": "^3.6.2", "gulp-mocha": "^2.0.0", + "gulp-sourcemaps": "^1.6.0", "isparta": "^3.0.0", "jshint": "^2.5.0", "mocha": "^2.0.1", diff --git a/test/main.js b/test/main.js index 484d258..e9d2ba6 100644 --- a/test/main.js +++ b/test/main.js @@ -8,6 +8,7 @@ var gulp = require('gulp'); var istanbul = require('../'); var isparta = require('isparta'); var mocha = require('gulp-mocha'); +var sourcemaps = require('gulp-sourcemaps'); var Report = require('istanbul').Report; var out = process.stdout.write.bind(process.stdout); @@ -19,16 +20,18 @@ describe('gulp-istanbul', function () { require.cache = {}; }); - var libFile = new gutil.File({ - path: 'test/fixtures/lib/add.js', - cwd: 'test/', - base: 'test/fixtures/lib', - contents: fs.readFileSync('test/fixtures/lib/add.js') - }); + var libFile; describe('istanbul()', function () { beforeEach(function () { this.stream = istanbul(); + libFile = new gutil.File({ + path: 'test/fixtures/lib/add.js', + cwd: 'test/', + base: 'test/fixtures/lib', + contents: fs.readFileSync('test/fixtures/lib/add.js') + }); + }); it('instrument files', function (done) { @@ -74,6 +77,51 @@ describe('gulp-istanbul', function () { this.stream.write(srcFile); this.stream.end(); }); + + it('is compatible to gulp-sourcemaps', function(done) { + var initStream = sourcemaps.init(); + var sourceMapStream = initStream.pipe(this.stream); + sourceMapStream.on('data', function (file) { + assert(file.sourceMap !== undefined); + assert.equal(file.sourceMap.file, file.path); + done(); + }); + + initStream.write(libFile); + initStream.end(); + }); + + it('handles existing source maps', function(done) { + var initStream = sourcemaps.init(); + var sourceMapStream = initStream.pipe(this.stream); + sourceMapStream.on('data', function (file) { + assert.equal(file.sourceMap.sourceRoot, 'testSourceRoot'); + assert(file.sourceMap.sources.indexOf('testInputFile.js') >= 0); + done(); + }); + + libFile.sourceMap = { + version: 3, + sources: [ 'add.js' ], + names: [ 'exports', 'add', 'a', 'b', 'missed' ], + mappings: ';;;;;;;;;AAEAA,OAAA,CAAQC,GAAR,GAAc,UAAUC,CAAV,EAAaC,CAAb,EAAgB;AAAA,I,sCAAA;AAAA,I,sCAAA;AAAA,IAC5B,OAAOD,CAAA,GAAIC,CAAX,CAD4B;AAAA,CAA9B,C;;AAIAH,OAAA,CAAQI,MAAR,GAAiB,YAAY;AAAA,I,sCAAA;AAAA,I,sCAAA;AAAA,IAC3B,OAAO,aAAP,CAD2B;AAAA,CAA7B', + file: 'testInputFile.js', + sourcesContent: [ '' ], + sourceRoot: 'testSourceRoot' + }; + initStream.write(libFile); + initStream.end(); + }); + + it('creates sourcemaps only if requested', function(done) { + this.stream.on('data', function (file) { + assert(file.sourceMap === undefined); + done(); + }); + + this.stream.write(libFile); + this.stream.end(); + }); }); describe('istanbul() with custom instrumentor', function() {