Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use latest istanbul lib packages #377

Merged
merged 9 commits into from
Jun 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions lib/in-memory-report.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
var Report = require('istanbul').Report
var util = require('util')

function InMemoryReport (opt) {
this.opt = opt
}

util.inherits(InMemoryReport, Report)
InMemoryReport.prototype.onStart = function (root, context) {
this.data = {}
}

InMemoryReport.prototype.onDetail = function (node) {
const fc = node.getFileCoverage()
const key = fc.path
this.data[key] = fc.toJSON()
}

InMemoryReport.prototype.writeReport = function (collector, sync) {
InMemoryReport.prototype.onEnd = function () {
if (!this.opt.emitter || !this.opt.emitter.emit) {
console.error('Could not raise "coverage_complete" event, missing emitter because it was not supplied during initialization of the reporter')
} else {
this.opt.emitter.emit('coverage_complete', this.opt.browser, collector.getFinalCoverage())
this.opt.emitter.emit('coverage_complete', this.opt.browser, this.data)
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Exposes the preprocessor and reporter plugins.

// Registering one additional (karma specific) reporter: in-memory
require('istanbul').Report.register(require('./in-memory-report'))
require('./report-creator').register(require('./in-memory-report'))

module.exports = {
'preprocessor:coverage': ['factory', require('./preprocessor')],
Expand Down
89 changes: 68 additions & 21 deletions lib/preprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
// Dependencies
// ------------

var istanbul = require('istanbul')
var { createInstrumenter } = require('istanbul-lib-instrument')
var minimatch = require('minimatch')
var path = require('path')
var _ = require('lodash')
var SourceMapConsumer = require('source-map').SourceMapConsumer
var SourceMapGenerator = require('source-map').SourceMapGenerator
var globalSourceCache = require('./source-cache')
var coverageMap = require('./coverage-map')
var globalSourceMapStore = require('./source-map-store')
var globalCoverageMap = require('./coverage-map')

// Regexes
// -------
Expand All @@ -27,21 +27,60 @@ function createCoveragePreprocessor (logger, helper, basePath, reporters, covera
// Options
// -------

function isConstructor (Func) {
try {
// eslint-disable-next-line
new Func()
} catch (err) {
// error message should be of the form: "TypeError: func is not a constructor"
// test for this type of message to ensure we failed due to the function not being
// constructable
if (/TypeError.*constructor/.test(err.message)) {
return false
}
}
return true
}

function getCreatorFunction (Obj) {
if (Obj.Instrumenter) {
return function (opts) {
return new Obj.Instrumenter(opts)
}
}
if (!_.isFunction(Obj)) {
// Object doesn't have old instrumenter variable and isn't a
// constructor, so we can't use it to create an instrumenter
return null
}
if (isConstructor(Obj)) {
return function (opts) {
return new Obj(opts)
}
}
return Obj
}

var instrumenterOverrides = {}
var instrumenters = { istanbul: istanbul }
var instrumenters = { istanbul: createInstrumenter }
var includeAllSources = false
var useJSExtensionForCoffeeScript = false

if (coverageReporter) {
instrumenterOverrides = coverageReporter.instrumenter
instrumenters = Object.assign({}, { istanbul: istanbul }, coverageReporter.instrumenters)
_.forEach(coverageReporter.instrumenters, function (instrumenter, literal) {
var creatorFunction = getCreatorFunction(instrumenter)
if (creatorFunction) {
instrumenters[literal] = creatorFunction
}
})
includeAllSources = coverageReporter.includeAllSources === true
useJSExtensionForCoffeeScript = coverageReporter.useJSExtensionForCoffeeScript === true
}

var sourceCache = globalSourceCache.get(basePath)
var sourceMapStore = globalSourceMapStore.get(basePath)

var instrumentersOptions = _.reduce(instrumenters, function getInstumenterOptions (memo, instrument, name) {
var instrumentersOptions = _.reduce(instrumenters, function getInstrumenterOptions (memo, instrument, name) {
memo[name] = {}

if (coverageReporter && coverageReporter.instrumenterOptions) {
Expand Down Expand Up @@ -88,9 +127,11 @@ function createCoveragePreprocessor (logger, helper, basePath, reporters, covera
}
})

var InstrumenterConstructor = instrumenters[instrumenterLiteral].Instrumenter
var instrumenterCreator = instrumenters[instrumenterLiteral]
var constructOptions = instrumentersOptions[instrumenterLiteral] || {}
var options = Object.assign({}, constructOptions)
var codeGenerationOptions = null
options.autoWrap = options.autoWrap || !options.noAutoWrap

if (file.sourceMap) {
log.debug('Enabling source map generation for "%s".', file.originalPath)
Expand All @@ -102,12 +143,12 @@ function createCoveragePreprocessor (logger, helper, basePath, reporters, covera
sourceMapWithCode: true,
file: file.path
}, constructOptions.codeGenerationOptions || {})
options.produceSourceMap = true
}

var options = Object.assign({}, constructOptions)
options = Object.assign({}, options, { codeGenerationOptions: codeGenerationOptions })

var instrumenter = new InstrumenterConstructor(options)
var instrumenter = instrumenterCreator(options)
instrumenter.instrument(content, jsPath, function (err, instrumentedCode) {
if (err) {
log.error('%s\n at %s', err.message, file.originalPath)
Expand All @@ -122,19 +163,25 @@ function createCoveragePreprocessor (logger, helper, basePath, reporters, covera
instrumentedCode += Buffer.from(JSON.stringify(file.sourceMap)).toString('base64') + '\n'
}

// remember the actual immediate instrumented JS for given original path
sourceCache[jsPath] = content
// Register the sourceMap for transformation during reporting
sourceMapStore.registerMap(jsPath, file.sourceMap)

if (includeAllSources) {
// reset stateful regex
coverageObjRegex.lastIndex = 0

var coverageObjMatch = coverageObjRegex.exec(instrumentedCode)

if (coverageObjMatch !== null) {
var coverageObj = JSON.parse(coverageObjMatch[0])

coverageMap.add(coverageObj)
var coverageObj
// Check if the file coverage object is exposed from the instrumenter directly
if (instrumenter.lastFileCoverage) {
coverageObj = instrumenter.lastFileCoverage()
globalCoverageMap.add(coverageObj)
} else {
// Attempt to match and parse coverage object from instrumented code

// reset stateful regex
coverageObjRegex.lastIndex = 0
var coverageObjMatch = coverageObjRegex.exec(instrumentedCode)
if (coverageObjMatch !== null) {
coverageObj = JSON.parse(coverageObjMatch[0])
globalCoverageMap.add(coverageObj)
}
}
}

Expand Down
41 changes: 41 additions & 0 deletions lib/report-creator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Report Creator
// ==============
//
// Wrapper of Istanbul's report creator to allow registering
// custom reporters

// Dependencies
// ------------
var istanbulReports = require('istanbul-reports')

var customReporterMap = {}

function register (reporter) {
var registeredType = reporter.TYPE
if (!registeredType) {
throw new Error('Registering a custom reporter requires a type!')
}

customReporterMap[registeredType] = reporter
return registeredType
}

function create (type, opts) {
var Reporter = customReporterMap[type]
if (Reporter) {
return new Reporter(opts)
}

// fallback to istanbul's report creator if reporter isn't found
return istanbulReports.create(type, opts)
}

function reset () {
customReporterMap = {}
}

module.exports = {
create: create,
register: register,
reset: reset
}
Loading