mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-01 01:38:07 +08:00
162 lines
5.1 KiB
JavaScript
162 lines
5.1 KiB
JavaScript
// Coverage Preprocessor
|
|
// =====================
|
|
//
|
|
// Depends on the the reporter to generate an actual report
|
|
|
|
// Dependencies
|
|
// ------------
|
|
|
|
var istanbul = require('istanbul')
|
|
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 extend = require('util')._extend
|
|
var coverageMap = require('./coverage-map')
|
|
|
|
// Regexes
|
|
// -------
|
|
|
|
var coverageObjRegex = /\{.*"path".*"fnMap".*"statementMap".*"branchMap".*\}/g
|
|
|
|
// Preprocessor creator function
|
|
function createCoveragePreprocessor (logger, helper, basePath, reporters, coverageReporter) {
|
|
var log = logger.create('preprocessor.coverage')
|
|
|
|
// Options
|
|
// -------
|
|
|
|
var instrumenterOverrides = {}
|
|
var instrumenters = {istanbul: istanbul}
|
|
var includeAllSources = false
|
|
var useJSExtensionForCoffeeScript = false
|
|
|
|
if (coverageReporter) {
|
|
instrumenterOverrides = coverageReporter.instrumenter
|
|
instrumenters = extend({istanbul: istanbul}, coverageReporter.instrumenters)
|
|
includeAllSources = coverageReporter.includeAllSources === true
|
|
useJSExtensionForCoffeeScript = coverageReporter.useJSExtensionForCoffeeScript === true
|
|
}
|
|
|
|
var sourceCache = globalSourceCache.get(basePath)
|
|
|
|
var instrumentersOptions = _.reduce(instrumenters, function getInstumenterOptions (memo, instrument, name) {
|
|
memo[name] = {}
|
|
|
|
if (coverageReporter && coverageReporter.instrumenterOptions) {
|
|
memo[name] = coverageReporter.instrumenterOptions[name]
|
|
}
|
|
|
|
return memo
|
|
}, {})
|
|
|
|
// if coverage reporter is not used, do not preprocess the files
|
|
if (!_.includes(reporters, 'coverage')) {
|
|
return function (content, _, done) {
|
|
done(content)
|
|
}
|
|
}
|
|
|
|
// check instrumenter override requests
|
|
function checkInstrumenters () {
|
|
return _.reduce(instrumenterOverrides, function (acc, literal, pattern) {
|
|
if (!_.includes(_.keys(instrumenters), String(literal))) {
|
|
log.error('Unknown instrumenter: %s', literal)
|
|
return false
|
|
}
|
|
return acc
|
|
}, true)
|
|
}
|
|
|
|
if (!checkInstrumenters()) {
|
|
return function (content, _, done) {
|
|
return done(1)
|
|
}
|
|
}
|
|
|
|
return function (content, file, done) {
|
|
log.debug('Processing "%s".', file.originalPath)
|
|
|
|
var jsPath = path.resolve(file.originalPath)
|
|
// default instrumenters
|
|
var instrumenterLiteral = 'istanbul'
|
|
|
|
_.forEach(instrumenterOverrides, function (literal, pattern) {
|
|
if (minimatch(file.originalPath, pattern, {dot: true})) {
|
|
instrumenterLiteral = String(literal)
|
|
}
|
|
})
|
|
|
|
var InstrumenterConstructor = instrumenters[instrumenterLiteral].Instrumenter
|
|
var constructOptions = instrumentersOptions[instrumenterLiteral] || {}
|
|
var codeGenerationOptions = null
|
|
|
|
if (file.sourceMap) {
|
|
log.debug('Enabling source map generation for "%s".', file.originalPath)
|
|
codeGenerationOptions = extend({
|
|
format: {
|
|
compact: !constructOptions.noCompact
|
|
},
|
|
sourceMap: file.sourceMap.file,
|
|
sourceMapWithCode: true,
|
|
file: file.path
|
|
}, constructOptions.codeGenerationOptions || {})
|
|
}
|
|
|
|
var options = extend({}, constructOptions)
|
|
options = extend(options, {codeGenerationOptions: codeGenerationOptions})
|
|
|
|
var instrumenter = new InstrumenterConstructor(options)
|
|
instrumenter.instrument(content, jsPath, function (err, instrumentedCode) {
|
|
if (err) {
|
|
log.error('%s\n at %s', err.message, file.originalPath)
|
|
done(err.message)
|
|
} else {
|
|
if (file.sourceMap && instrumenter.lastSourceMap()) {
|
|
log.debug('Adding source map to instrumented file for "%s".', file.originalPath)
|
|
var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(instrumenter.lastSourceMap().toString()))
|
|
generator.applySourceMap(new SourceMapConsumer(file.sourceMap))
|
|
file.sourceMap = JSON.parse(generator.toString())
|
|
instrumentedCode += '\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,'
|
|
instrumentedCode += new Buffer(JSON.stringify(file.sourceMap)).toString('base64') + '\n'
|
|
}
|
|
|
|
// remember the actual immediate instrumented JS for given original path
|
|
sourceCache[jsPath] = content
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
// RequireJS expects JavaScript files to end with `.js`
|
|
if (useJSExtensionForCoffeeScript && instrumenterLiteral === 'ibrik') {
|
|
file.path = file.path.replace(/\.coffee$/, '.js')
|
|
}
|
|
|
|
done(instrumentedCode)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
createCoveragePreprocessor.$inject = [
|
|
'logger',
|
|
'helper',
|
|
'config.basePath',
|
|
'config.reporters',
|
|
'config.coverageReporter'
|
|
]
|
|
|
|
module.exports = createCoveragePreprocessor
|