UNPKG

babel-istanbul

Version:

Yet another JS code coverage tool that computes statement, line, function and branch coverage with module loader hooks to transparently add coverage when running tests. Supports all JS coverage use cases including unit tests, server side functional tests

154 lines (139 loc) 4.16 kB
/* Copyright (c) 2012, Yahoo! Inc. All rights reserved. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. */ var path = require('path'), util = require('util'), fs = require('fs'), async = require('async'), mkdirp = require('mkdirp'), writer = require('./writer'), Writer = writer.Writer, ContentWriter = writer.ContentWriter; function extend(cons, proto) { Object.keys(proto).forEach(function (k) { cons.prototype[k] = proto[k]; }); } function BufferedContentWriter() { ContentWriter.call(this); this.content = ''; } util.inherits(BufferedContentWriter, ContentWriter); extend(BufferedContentWriter, { write: function (str) { this.content += str; }, getContent: function () { return this.content; } }); function StreamContentWriter(stream) { ContentWriter.call(this); this.stream = stream; } util.inherits(StreamContentWriter, ContentWriter); extend(StreamContentWriter, { write: function (str) { this.stream.write(str); } }); function SyncFileWriter() { Writer.call(this); } util.inherits(SyncFileWriter, Writer); extend(SyncFileWriter, { writeFile: function (file, callback) { mkdirp.sync(path.dirname(file)); var cw = new BufferedContentWriter(); callback(cw); fs.writeFileSync(file, cw.getContent(), 'utf8'); }, done: function () { this.emit('done'); //everything already done } }); function AsyncFileWriter() { this.queue = async.queue(this.processFile.bind(this), 20); this.openFileMap = {}; } util.inherits(AsyncFileWriter, Writer); extend(AsyncFileWriter, { writeFile: function (file, callback) { this.openFileMap[file] = true; this.queue.push({ file: file, callback: callback }); }, processFile: function (task, cb) { var file = task.file, userCallback = task.callback, that = this, stream, contentWriter; mkdirp.sync(path.dirname(file)); stream = fs.createWriteStream(file); stream.on('close', function () { delete that.openFileMap[file]; cb(); that.checkDone(); }); stream.on('error', function (err) { that.emit('error', err); }); contentWriter = new StreamContentWriter(stream); userCallback(contentWriter); stream.end(); }, done: function () { this.doneCalled = true; this.checkDone(); }, checkDone: function () { if (!this.doneCalled) { return; } if (Object.keys(this.openFileMap).length === 0) { this.emit('done'); } } }); /** * a concrete writer implementation that can write files synchronously or * asynchronously based on the constructor argument passed to it. * * Usage * ----- * * var sync = true, * fileWriter = new require('istanbul').FileWriter(sync); * * fileWriter.on('done', function () { console.log('done'); }); * fileWriter.copyFile('/foo/bar.jpg', '/baz/bar.jpg'); * fileWriter.writeFile('/foo/index.html', function (contentWriter) { * contentWriter.println('<html>'); * contentWriter.println('</html>'); * }); * fileWriter.done(); // will emit the `done` event when all files are written * * @class FileWriter * @extends Writer * @module io * @param sync * @constructor */ function FileWriter(sync) { Writer.call(this); var that = this; this.delegate = sync ? new SyncFileWriter() : new AsyncFileWriter(); this.delegate.on('error', function (err) { that.emit('error', err); }); this.delegate.on('done', function () { that.emit('done'); }); } util.inherits(FileWriter, Writer); extend(FileWriter, { copyFile: function (source, dest) { mkdirp.sync(path.dirname(dest)); fs.writeFileSync(dest, fs.readFileSync(source)); }, writeFile: function (file, callback) { this.delegate.writeFile(file, callback); }, done: function () { this.delegate.done(); } }); module.exports = FileWriter;