-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
111 lines (89 loc) · 2.6 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"use strict";
const path = require("path");
const rewire = require("rewire");
const CALLS_DEPTH = 2; // Important to keep it actual
const getCallerPath = () => {
const _ = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const stack = new Error().stack.slice(1);
Error.prepareStackTrace = _;
return stack[CALLS_DEPTH].getFileName();
};
const rewire_ = filename => {
const mod = rewire(filename);
let cache = {};
const set = mod.__set__;
mod.__set__ = function (obj, mock) {
if (typeof(obj) === "string") {
obj = { [obj]: mock };
}
for (const name of Object.keys(obj)) {
if (!(name in cache)) {
cache[name] = this.__get__(name);
}
}
return set.call(this, obj);
};
mod.__reset__ = function () {
this.__set__(cache);
cache = {};
};
return mod;
};
let originalDependencies = {};
const patchDependencies = deps => {
for (const [k, v] of Object.entries(deps)) {
if (k in require.cache) {
originalDependencies[k] = require.cache[k];
}
require.cache[k] = v;
}
};
const resetDependencies = deps => {
for (let k of Object.keys(deps)) {
if (k in originalDependencies) {
require.cache[k] = originalDependencies[k];
} else {
delete require.cache[k];
}
}
originalDependencies = {};
};
const normalizeDependencies = (deps, root) => {
const result = {};
for (const [k, v] of Object.entries(deps)) {
result[normalizeDepPath(k, root)] = { exports: v };
}
return result;
};
const normalizeDepPath = (dep, root) => {
if (dep.startsWith(".")) {
dep = path.resolve(root, dep);
}
return require.resolve(dep);
};
const normalizeModulePath = filename => {
// absolute path or global module, let's rewire resolves it
if (!filename.startsWith(".")) {
return filename;
}
// relative path should be normalized because rewire can't resolve it proper
const callerPath = getCallerPath();
const callerDir = callerPath ? path.dirname(callerPath) : process.cwd();
return require.resolve(path.resolve(callerDir, filename));
};
const rehire_ = (filename, deps) => {
deps = deps || {};
filename = normalizeModulePath(filename);
deps = normalizeDependencies(deps, path.dirname(filename));
patchDependencies(deps);
try {
return rewire_(filename);
} finally {
resetDependencies(deps);
}
};
rehire_.global = () => {
global.rehire = rehire_;
};
module.exports = rehire_;