From 626e7b0c5a36fba948f6be349020e62794a79377 Mon Sep 17 00:00:00 2001 From: Douglas Duteil Date: Fri, 29 Aug 2014 16:07:17 +0100 Subject: [PATCH] feat(preprocessor): free instrumenter Allow any Istanbul instrumenter to be used in the karma-coverage. Will help #120 Closes #101 #49 BREAKING CHANGE: Karma-coverage does not ship with additional instrumenter. You need to explicitly install the instrumenter you need. Removed **Ibrik** instrumenter that need to be installed explicitly. Quick list of known community instrumenters : - [Ibrik](https://github.com/Constellation/ibrik) (CoffeeScript files instrumenter). - [Ismailia](https://github.com/Spote/ismailia) (ES6 files instrumenter using Traceur). - [Isparta](https://github.com/douglasduteil/isparta) (ES6 files instrumenter using 6to5). --- README.md | 33 +++++++++++++++++++++++------ lib/preprocessor.js | 26 ++++++++++++----------- package.json | 1 - test/preprocessor.spec.coffee | 40 ++++++++++++++++++++++++++++++----- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 02b24d8..617e40f 100644 --- a/README.md +++ b/README.md @@ -206,26 +206,47 @@ coverageReporter: { ``` #### instrumenter -Karma-coverage infers the instrumenter regarding of the file extension. - The `.coffee` files are by default covered using - [Ibrik](https://github.com/Constellation/ibrik) (an - [Istanbul](https://github.com/gotwarlost/istanbul) analog for - CoffeeScript files). It is possible to override this behavior and point out an +Karma-coverage can infers the instrumenter regarding of the file extension. + It is possible to override this behavior and point out an instrumenter for the files matching a specific pattern. To do so, you need to declare an object under with the keys represents the pattern to match, and the instrumenter to apply. The matching will be done using [minimatch](https://github.com/isaacs/minimatch). If two patterns match, the last one will take the precedence. +For example you can use [Ibrik](https://github.com/Constellation/ibrik) (an + [Istanbul](https://github.com/gotwarlost/istanbul) analog for + CoffeeScript files) with: + ```javascript coverageReporter: { + instrumenters: { ibrik : require('ibrik') } instrumenter: { - '**/*.coffee': 'istanbul' // Force the use of the Istanbul instrumenter to cover CoffeeScript files + '**/*.coffee': 'ibrik' }, // ... } ``` +You can pass options additional options to specific instrumenter with: + +```javascript +var to5Options = { experimental: true }; + +// [...] + +coverageReporter: { + instrumenters: { isparta : require('isparta') }, + instrumenter: { + '**/*.js': 'isparta' + }, + instrumenterOptions: { + isparta: { to5 : to5Options } + } +} +``` + + ---- For more information on Karma see the [homepage]. diff --git a/lib/preprocessor.js b/lib/preprocessor.js index 822a150..ac61eea 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -1,13 +1,17 @@ var istanbul = require('istanbul'), - ibrik = require('ibrik'), minimatch = require('minimatch'), - globalSourceCache = require('./sourceCache'); + globalSourceCache = require('./sourceCache'), + extend = require('util')._extend; var createCoveragePreprocessor = function(logger, basePath, reporters, coverageReporter) { var log = logger.create('preprocessor.coverage'); var instrumenterOverrides = (coverageReporter && coverageReporter.instrumenter) || {}; - var instrumenters = {istanbul: istanbul, ibrik: ibrik}; + var instrumenters = extend({istanbul: istanbul}, (coverageReporter && coverageReporter.instrumenters)); var sourceCache = globalSourceCache.getByBasePath(basePath); + var instrumentersOptions = Object.keys(instrumenters).reduce(function getInstumenterOptions(memo, instrumenterName){ + memo[instrumenterName] = (coverageReporter && coverageReporter.instrumenterOptions && coverageReporter.instrumenterOptions[instrumenterName]) || {}; + return memo; + }, {}); // if coverage reporter is not used, do not preprocess the files if (reporters.indexOf('coverage') === -1) { @@ -20,8 +24,8 @@ var createCoveragePreprocessor = function(logger, basePath, reporters, coverageR function checkInstrumenters() { var literal; for (var pattern in instrumenterOverrides) { - literal = String(instrumenterOverrides[pattern]).toLowerCase(); - if (literal !== 'istanbul' && literal !== 'ibrik') { + literal = String(instrumenterOverrides[pattern]); + if (Object.keys(instrumenters).indexOf(literal) < 0) { log.error('Unknown instrumenter: %s', literal); return false; } @@ -38,25 +42,23 @@ var createCoveragePreprocessor = function(logger, basePath, reporters, coverageR log.debug('Processing "%s".', file.originalPath); var jsPath = file.originalPath.replace(basePath + '/', './'); - var instrumenterLiteral = jsPath.match(/\.coffee$/) ? 'ibrik' : 'istanbul'; + // default instrumenters + var instrumenterLiteral = 'istanbul'; for (var pattern in instrumenterOverrides) { if (minimatch(file.originalPath, pattern, {dot: true})) { - instrumenterLiteral = String(instrumenterOverrides[pattern]).toLowerCase(); + instrumenterLiteral = String(instrumenterOverrides[pattern]); } } - var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter(); + var instrumenter = new instrumenters[instrumenterLiteral].Instrumenter(instrumentersOptions[instrumenterLiteral] || {}); instrumenter.instrument(content, jsPath, function(err, instrumentedCode) { + if (err) { log.error('%s\n at %s', err.message, file.originalPath); } - if (instrumenterLiteral === 'ibrik') { - file.path = file.path.replace(/\.coffee$/, '.js'); - } - // remember the actual immediate instrumented JS for given original path sourceCache[jsPath] = content; diff --git a/package.json b/package.json index 453df78..54a5e6b 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "author": "SATO taichi ", "dependencies": { "istanbul": "~0.3.0", - "ibrik": "~2.0.0", "dateformat": "~1.0.6", "minimatch": "~0.3.0" }, diff --git a/test/preprocessor.spec.coffee b/test/preprocessor.spec.coffee index 1963e6e..81da4ae 100644 --- a/test/preprocessor.spec.coffee +++ b/test/preprocessor.spec.coffee @@ -57,9 +57,18 @@ describe 'preprocessor', -> expect(sandbox.__coverage__).to.have.ownProperty './file.js' done() - it 'should preprocess the coffee code', (done) -> - process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], {} - file = new File '/base/path/file.coffee' + it 'should preprocess the fake code', (done) -> + fakeInstanbulLikeInstrumenter = -> + fakeInstanbulLikeInstrumenter::instrument = (_a, _b, callback) -> + callback() + return + process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], + instrumenters: + fakeInstanbulLike : + Instrumenter : fakeInstanbulLikeInstrumenter + instrumenter: + '**/*.fake': 'fakeInstanbulLike' + file = new File '/base/path/file.fake' process ORIGINAL_COFFEE_CODE, file, (preprocessedCode) -> sandbox = @@ -67,10 +76,31 @@ describe 'preprocessor', -> something: -> vm.runInNewContext preprocessedCode, sandbox - expect(file.path).to.equal '/base/path/file.js' - expect(sandbox.__coverage__).to.have.ownProperty './file.coffee' + expect(file.path).to.equal '/base/path/file.fake' done() + it 'should preprocess the fake code with the config options', (done) -> + fakeInstanbulLikeInstrumenter = (options) -> + expect(options.experimental).to.be.ok + return + fakeInstanbulLikeInstrumenter::instrument = (_a, _b, callback) -> + callback() + return + + process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], + instrumenters: + fakeInstanbulLike: + Instrumenter: fakeInstanbulLikeInstrumenter + instrumenterOptions: + fakeInstanbulLike: + experimental: yes + instrumenter: + '**/*.fake': 'fakeInstanbulLike' + + file = new File '/base/path/file.fake' + + process ORIGINAL_COFFEE_CODE, file, done + it 'should not preprocess the coffee code', (done) -> process = createPreprocessor mockLogger, '/base/path', ['coverage', 'progress'], instrumenter: