mochapack
Version:
mocha cli with webpack support
120 lines (98 loc) • 3.33 kB
text/typescript
/* eslint-disable no-underscore-dangle */
// see https://github.com/nodejs/node/blob/master/lib/module.js
import Module from 'module'
// the module in which the require() call originated
let requireCaller
// all custom registered resolvers
let pathResolvers = []
// keep original Module._resolveFilename
// @ts-ignore
const originalResolveFilename = Module._resolveFilename
// override Module._resolveFilename
// @ts-ignore
Module._resolveFilename = function _resolveFilename(...parameters) {
const parent = parameters[1]
// store require() caller (the module in which this require() call originated)
requireCaller = parent
return originalResolveFilename.apply(this, parameters)
}
// keep original Module._findPath
// @ts-ignore
const originalFindPath = Module._findPath
// override Module._findPath
// @ts-ignore
Module._findPath = function _findPath(...parameters) {
const request = parameters[0]
// try to resolve the path with custom resolvers
for (const resolve of pathResolvers) {
const resolved = resolve(request, requireCaller)
if (typeof resolved !== 'undefined') {
return resolved
}
}
// and when none found try to resolve path with original resolver
const filename = originalFindPath.apply(this, parameters)
if (filename !== false) {
return filename
}
return false
}
export default function registerRequireHook(
dotExt: string,
resolve: (
path: string,
parent: Module
) => { path: string | null; source: string | null }
) {
// cache source code after resolving to avoid another access to the fs
const sourceCache = {}
// store all files that were affected by this hook
const affectedFiles = {}
const resolvePath = (path, parent) => {
// get CommonJS module source code for this require() call
const { path: resolvedPath, source } = resolve(path, parent)
// if no CommonJS module source code returned - skip this require() hook
if (resolvedPath == null) {
return undefined
}
// flush require() cache
delete require.cache[resolvedPath]
// put the CommonJS module source code into the hash
sourceCache[resolvedPath] = source
// return the path to be require()d in order to get the CommonJS module source code
return resolvedPath
}
const resolveSource = path => {
const source = sourceCache[path]
delete sourceCache[path]
return source
}
pathResolvers.push(resolvePath)
// keep original extension loader
// @ts-ignore
const originalLoader = Module._extensions[dotExt]
// override extension loader
// @ts-ignore
Module._extensions[dotExt] = (module, filename) => {
const source = resolveSource(filename)
if (typeof source === 'undefined') {
// load the file with the original loader
// @ts-ignore
;(originalLoader || Module._extensions['.js'])(module, filename)
return
}
affectedFiles[filename] = true
// compile javascript module from its source
module._compile(source, filename)
}
return function unmout() {
pathResolvers = pathResolvers.filter(r => r !== resolvePath)
// @ts-ignore
Module._extensions[dotExt] = originalLoader
Object.keys(affectedFiles).forEach(path => {
delete require.cache[path]
delete sourceCache[path]
delete affectedFiles[path]
})
}
}