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

Improve support for custom require hooks #65

Merged
merged 1 commit into from
Dec 1, 2015
Merged
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
67 changes: 41 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var _ = require('lodash')
var fs = require('fs')
var glob = require('glob')
var mkdirp = require('mkdirp')
var Module = require('module')
var path = require('path')
var rimraf = require('rimraf')
var onExit = require('signal-exit')
Expand Down Expand Up @@ -129,40 +130,54 @@ NYC.prototype.addAllFiles = function () {
NYC.prototype._wrapRequire = function () {
var _this = this

var babelRequireHook = null
var requireHook = function (module, filename) {
// allow babel's compile hoook to compile
// the code -- ignore node_modules, this
// helps avoid cyclical require behavior.
var content = null
if (babelRequireHook && filename.indexOf('node_modules/') === -1) {
babelRequireHook({
_compile: function (compiledSrc) {
_this.sourceMapCache.add(filename, compiledSrc)
content = compiledSrc
}
}, filename)
}
var defaultHook = function (module, filename) {
// instrument the required file.
var obj = _this.addFile(filename, false)

// now instrument the compiled code.
var obj = null
if (content) {
obj = _this.addContent(filename, content)
} else {
obj = _this.addFile(filename, false)
}
// always use node's original _compile method to compile the instrumented
// code. if a custom hook invoked the default hook the code should not be
// compiled using the custom hook.
Module.prototype._compile.call(module, obj.content, filename)
}

module._compile(obj.content, filename)
var wrapCustomHook = function (hook) {
return function (module, filename) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this approach, much cleaner than what I was doing before -- also I think that it fixes the issue I was originally having that required me to ignore the node_modules folder -- great job.

// override the _compile method so the code can be instrumented first.
module._compile = function (compiledSrc) {
_this.sourceMapCache.add(filename, compiledSrc)

// now instrument the compiled code.
var obj = _this.addContent(filename, compiledSrc)
Module.prototype._compile.call(module, obj.content, filename)
}

// allow the custom hook to compile the code. it can fall back to the
// default hook if necessary (accessed via require.extensions['.js'] prior
// to setting itself)
hook(module, filename)
}
}

// use a getter and setter to capture any external
// require hooks that are registered, e.g., babel-core/register
var requireHook = defaultHook
// track existing hooks so they can be restored without wrapping them a second
// time.
var hooks = [requireHook]

// use a getter and setter to capture any external require hooks that are
// registered, e.g., babel-core/register
require.extensions.__defineGetter__('.js', function () {
return requireHook
})

require.extensions.__defineSetter__('.js', function (value) {
babelRequireHook = value
require.extensions.__defineSetter__('.js', function (hook) {
var restoreIndex = hooks.indexOf(hook)
if (restoreIndex !== -1) {
requireHook = hook
hooks.splice(restoreIndex + 1, hooks.length)
} else {
requireHook = wrapCustomHook(hook)
hooks.push(requireHook)
}
})
}

Expand Down