diff options
author | Johannes <johannes.ewald@roomieplanet.de> | 2012-08-20 04:36:35 +0400 |
---|---|---|
committer | Johannes <johannes.ewald@roomieplanet.de> | 2012-08-20 04:36:35 +0400 |
commit | 3cc25aec3698c7becd463bd75524a3b2a319ecab (patch) | |
tree | cff8c03016f05a7646ed864ca7238e5f9f09b7ce /lib | |
parent | c5d8fab07f0edc568e45e0747f863afd5876abc2 (diff) |
- All tests running
- Added changelog
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bundlers/browserify/browserifyMiddleware.js | 76 | ||||
-rw-r--r-- | lib/bundlers/browserify/browserifyRewire.js | 98 | ||||
-rw-r--r-- | lib/bundlers/injectRewire.js | 68 | ||||
-rw-r--r-- | lib/bundlers/webpack/configureWebpack.js | 14 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackPostLoader.js | 33 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackPostProcessor.js | 20 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackRewire.js | 13 | ||||
-rw-r--r-- | lib/index.js | 14 | ||||
-rw-r--r-- | lib/internalRewire.js | 194 |
9 files changed, 294 insertions, 236 deletions
diff --git a/lib/bundlers/browserify/browserifyMiddleware.js b/lib/bundlers/browserify/browserifyMiddleware.js index 39d76b1..3c26e96 100644 --- a/lib/bundlers/browserify/browserifyMiddleware.js +++ b/lib/bundlers/browserify/browserifyMiddleware.js @@ -5,30 +5,70 @@ var setterSrc = require("../../__set__.js").toString(), getRewireRequires = require("../getRewireRequires.js"), rewireIndex = path.resolve(__dirname, "../../index.js"), + rewireLib = path.join("rewire", "lib"), settersAndGettersSrc; +/** + * This function can be added to browserify via b.use(). + * @see https://github.com/substack/node-browserify/blob/master/doc/methods.markdown#methods + * + * It injects special code before every module in order to gain access to the private scope + * of the module. Additionally it forwards all calls of require("rewire") to the module + * browserifyRewire.js. Thus we don't need any cumbersome client/server-switches in the index.js. + * + * @param {browserify} b the bundle returned by browserify() + * @return {browserify} b + */ function browserifyMiddleware(b) { + + /** + * Does actually the injecting of the special code. It is called by browserify for every + * js-module. + * + * @param {String} src + * @param {String} filename + * @return {String} src + */ function doInjectRewire(src, filename) { var rewireRequires; - // Search for all rewire() statements an return the required path. - rewireRequires = getRewireRequires(src); + // We don't want to inject this code at the beginning of a rewire/lib-module. Otherwise + // it would cause a black hole that devours our universe. + if (filename.indexOf(rewireLib) === -1) { + // Search for all rewire() statements an return the required path. + rewireRequires = getRewireRequires(src); + + // Add all modules that are loaded by rewire() manually to browserify because browserify's + // require-sniffing doesn't work here. + rewireRequires.forEach(function forEachRewireRequire(requirePath) { + + // Resolve to absolute paths + if (requirePath.charAt(0) === ".") { + requirePath = path.resolve(path.dirname(filename), requirePath); + } + b.require(requirePath); - // Add all modules that are loaded by rewire() manually to browserify because browserify's - // require-sniffing doesn't work here. - rewireRequires.forEach(function forEachRewireRequire(requirePath) { - // Resolve absolute paths - if (requirePath.charAt(0) === ".") { - requirePath = path.resolve(path.dirname(filename), requirePath); - } - b.require(requirePath); - }); + }); - src = injectRewire(src, filename, settersAndGettersSrc); + // Injects the special code + src = injectRewire(src, settersAndGettersSrc); + + // Because browserify doesn't create a new, independent module instance each time the module is + // executed we have to make it fake-independent. Thus the rewired module doesn't influence the original module. + // This is a crazy hack, but: hey don't blame me! Make a pull-request to browserify :) + src += ' module = require("rewire").getIndependentModule(module);'; + } return src; } + /** + * Gets called before each module is loaded. + * This function ensures that lib/bundlers/browserify/browserifyRewire.js is returned instead of lib/index.js + * + * @param {String} filename + * @return {String} filename + */ function forwardBrowserifyRewire(filename) { if (filename === rewireIndex) { filename = __dirname + "/browserifyRewire.js"; @@ -54,14 +94,18 @@ function browserifyMiddleware(b) { */ settersAndGettersSrc = ( 'var rewire = require("rewire"); ' + - // Registers the setters and getters of every module according to their filename. The setters and getters must be - // injected as string here to gain access to the private scope of the module. - 'rewire.register(__filename, module, ' + setterSrc + ', ' + getterSrc + ');' + + + // Registers the setters and getters of every module according to their filename. These setter and getter + // allow us to gain access to the private scope of the module. + 'rewire.register(__filename, module, ' + setterSrc + ', ' + getterSrc + '); ' + + // Overrides the module internal require with a require proxy. This proxy is necessary to call rewire with the // module's filename at the first parameter to resolve the path. This way rewire() works exactly like require(). - 'require = rewire.getProxy(require, __dirname);' + + 'require = rewire.getProxy(require, __dirname); ' + + // Cleaning up 'rewire = undefined;' + ).replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view module.exports = browserifyMiddleware;
\ No newline at end of file diff --git a/lib/bundlers/browserify/browserifyRewire.js b/lib/bundlers/browserify/browserifyRewire.js index 2798b69..b09b51a 100644 --- a/lib/bundlers/browserify/browserifyRewire.js +++ b/lib/bundlers/browserify/browserifyRewire.js @@ -1,5 +1,5 @@ var pathUtil = require("path"), - getImportGlobalsSrc = require("./getImportGlobalsSrc.js"); /* must be relative to lib/index.js */ + getImportGlobalsSrc = require("./getImportGlobalsSrc.js"); // must be relative to lib/index.js because of forwardBrowserifyRewire() /** * Clones an object deeply. Used to clone the module-object that is @@ -33,9 +33,7 @@ function clone(obj) { } // Saves all setters and getters for every module according to its filename -var registry = {}, -// Cache for all rewired modules so it can be reset anytime - rewiredModules = []; +var registry = {}; /** * Executes the given module and adds a special setter and getter that allow you to set and get private variables. @@ -43,30 +41,31 @@ var registry = {}, * * @param {!String} parentModulePath __filename of the module, that wants to rewire() another module. * @param {!String} path path to the module that shall be rewired - * @param {Boolean=true} cache indicates whether the rewired module should be cached or not - * @return {Object} + * @return {Object} the rewired module */ -function browserifyRewire(parentModulePath, path, cache) { - var originalModule, +function browserifyRewire(parentModulePath, path) { + var cached, + originalModule, + originalExports, absPath, - rewiredExports, - rewiredModule, + rewiredExports = {}, registryEntry, - _require = require; // hide it from browserify - - // Default cache to true - if (cache === undefined) { - cache = true; - } + _require = require; // hide it from browserify to avoid annoying console warnings // Normalize path with file extensions absPath = pathUtil.resolve(parentModulePath, path); // Retrieve original module from cache - originalModule = require.cache[absPath]; + cached = originalModule = require.cache[absPath]; - if (originalModule && cache) { - // Delete the original module from the cache so the next call to browserifyRequre() + if (cached) { + // If there is already a module instance in the cache we have to store the original exports-object + // manually so it won't be overwritten by the next execution. This is all necessary due to browserify's + // odd way of module creation. + originalExports = originalModule.exports; + originalModule.exports = rewiredExports; + + // Delete the original module from the cache so the next call to _require() // executes the module delete require.cache[absPath]; } @@ -74,26 +73,24 @@ function browserifyRewire(parentModulePath, path, cache) { // Require module to trigger rewire.register(). _require(absPath); + originalModule = require.cache[absPath]; + + // Now we're cloning the exports-obj so later modifications of the rewired module won't influence the + // cached, original version of this module. + rewiredExports = clone(originalModule.exports); + + if (cached) { + // Restore original exports + originalModule.exports = originalExports; + } + // Get registry entry of the target module registryEntry = registry[absPath]; - originalModule = registryEntry.module; - - // Make an independent copy of the original module so we can modify the copy - // without influencing the original module. - rewiredModule = clone(originalModule); - rewiredExports = rewiredModule.exports; // Apply setter and getters rewiredExports.__set__ = registryEntry.setter; rewiredExports.__get__ = registryEntry.getter; - if (cache) { - require.cache[absPath] = rewiredModule; - } - - // Store rewired modules for rewire.reset() - rewiredModules.push(absPath); - return rewiredExports; } @@ -113,22 +110,6 @@ browserifyRewire.register = function (filename, module, setter, getter) { }; /** - * Deletes all rewired modules from the cache - */ -browserifyRewire.reset = function () { - var cache = require.cache, - i, - absPath; - - for (i = 0; i < rewiredModules.length; i++) { - absPath = rewiredModules[i]; - delete cache[absPath]; - } - - rewiredModules = []; -}; - -/** * Provides a special require-proxy. Every module calls require("rewire").getProxy(require, __filename) at the * beginning and overrides its own require with this proxy. * @@ -184,4 +165,25 @@ browserifyRewire.getImportGlobalsSrc = function () { return getImportGlobalsSrc(['require','module','exports','__dirname','__filename','process']); }; +/** + * Returns a new object that inherits from the original module via prototype inheritance. + * + * Any changes to the module, e.g. assigning another exports-object will now modify the object + * instead of original module. + * + * @param {Object} originalModule + * @return {Object} the independent module + */ +browserifyRewire.getIndependentModule = function (originalModule) { + var independentModule; + + function IndependentModule() {} + IndependentModule.prototype = originalModule; + + independentModule = new IndependentModule(); + independentModule.exports = originalModule.exports; + + return independentModule; +}; + module.exports = browserifyRewire;
\ No newline at end of file diff --git a/lib/bundlers/injectRewire.js b/lib/bundlers/injectRewire.js index dfd56a4..b6fbef1 100644 --- a/lib/bundlers/injectRewire.js +++ b/lib/bundlers/injectRewire.js @@ -6,47 +6,39 @@ var path = require("path"), /** * Gets called by the bundler for every module. Injects special code so rewire is able to access private variables. + * This module doesn't contain bundler specific code. All bundler specific stuff should be done in the settersAndGettersSrc. * - * @param {String} src the module's src - * @param {String} filename the module's filename - * @param {String} settersAndGettersSrc source that injects the setters and getters into the module scope + * @param {!String} src the module's src + * @param {!String} settersAndGettersSrc source that injects the setters and getters into the module scope * @return {String} */ -function injectRewire(src, filename, settersAndGettersSrc) { - // Convert back slashes to normal slashes on windows. - if (path.sep !== "/") { - filename = filename.split(path.sep).join("/"); - } - - // We don't want to inject this code at the beginning of a rewire/lib-module. Otherwise - // it would cause a black hole that devours our universe. - if (filename.indexOf("/rewire/lib/") === -1) { - src = - // Trying to hide the injected line in the debug view with extra whitespaces. - ' ' + - '/* this line was injected by rewire() */ ' + // Comment for the curious developer - - // Now all global variables are declared with a var statement so they can be changed via __set__() - // without influencing global objects. - 'var global = window; ' + // window is our new global object - 'eval(require("rewire").getImportGlobalsSrc()); ' + - - // The module src is wrapped inside a self-executing function. - // This is necessary to separate the module src from the preceding eval(importGlobalsSrc), - // because the module src can be in strict mode. - // In strict mode eval() can only declare vars in the current scope. In this case our setters - // and getters won't work. - // @see https://developer.mozilla.org/en/JavaScript/Strict_mode#Making_eval_and_arguments_simpler - "(function () { " + - - // If the module uses strict mode we must ensure that "use strict" stays at the beginning of the function. - (detectStrictMode(src)? ' "use strict"; ': ' ') + - - settersAndGettersSrc + "\n" + - src + - - " })();"; - } +function injectRewire(src, settersAndGettersSrc) { + + src = + // Trying to hide the injected line in the debug view with extra whitespaces. + ' ' + + '/* this line was injected by rewire() */ ' + // Comment for the curious developer + + // Now all global variables are declared with a var statement so they can be changed via __set__() + // without influencing global objects. + 'var global = window; ' + // window is our new global object + 'eval(require("rewire").getImportGlobalsSrc()); ' + + + // The module src is wrapped inside a self-executing function. + // This is necessary to separate the module src from the preceding eval(importGlobalsSrc), + // because the module src can be in strict mode. + // In strict mode eval() can only declare vars in the current scope. In this case our setters + // and getters won't work. + // @see https://developer.mozilla.org/en/JavaScript/Strict_mode#Making_eval_and_arguments_simpler + "(function () { " + + + // If the module uses strict mode we must ensure that "use strict" stays at the beginning of the function. + (detectStrictMode(src)? ' "use strict"; ': ' ') + + + settersAndGettersSrc + "\n" + + src + + + " })();"; return src; } diff --git a/lib/bundlers/webpack/configureWebpack.js b/lib/bundlers/webpack/configureWebpack.js index a302d1c..b180fe8 100644 --- a/lib/bundlers/webpack/configureWebpack.js +++ b/lib/bundlers/webpack/configureWebpack.js @@ -1,15 +1,23 @@ "use strict"; // run code in ES5 strict mode +/** + * Configures webpack so it can be used with rewire. Make sure that the options aren't modified + * after calling this function. It's important that the rewire()-postLoader is the last loader called on a module. + * + * @see https://github.com/webpack/webpack + * + * @param {Object} options a webpack option object + */ function configureWebpack(options) { options.resolve = options.resolve || {}; options.postLoaders = options.postLoaders || []; options.resolve.postprocess = options.resolve.postprocess || {}; options.resolve.postprocess.normal = options.resolve.postprocess.normal || []; - // @see https://github.com/webpack/webpack/issues/21 - options.context = options.context || process.cwd(); - + // Registering the postLoader for injecting the special rewire code options.postLoaders.push(require("./webpackPostLoader.js")); + + // Registering the postProcessor for resolving paths options.resolve.postprocess.normal.push(require("./webpackPostProcessor.js")); } diff --git a/lib/bundlers/webpack/webpackPostLoader.js b/lib/bundlers/webpack/webpackPostLoader.js index 620f091..40c8cb2 100644 --- a/lib/bundlers/webpack/webpackPostLoader.js +++ b/lib/bundlers/webpack/webpackPostLoader.js @@ -2,20 +2,40 @@ var setterSrc = require("../../__set__.js").toString(), getterSrc = require("../../__get__.js").toString(), + path = require("path"), injectRewire = require("../injectRewire.js"), getRewireRegExp = require("../getRewireRegExp.js"), + rewireLib = path.join("rewire", "lib"), + webpackBuildin = path.join("webpack", "buildin", "__webpack"), settersAndGettersSrc; +/** + * Injects special code so rewire gains access to the module's private scope. + * + * Furthermore it changes all calls of rewire("some/path") to rewire("some/path", require("some/path")) so webpack + * recognizes the additional dependency. This also enables rewire to resolve the module because webpack replaces all + * paths to numeric ids. + * + * @param {!String} src + * @return {String} src + */ function webpackLoader(src) { var filename = this.request.split("!").pop(), rewireRegExp = getRewireRegExp(); - if (filename.indexOf("/webpack/buildin/__webpack") === -1) { - src = src.replace(rewireRegExp, '$1rewire("$2", require("$2"))'); // replaces rewire("some/path") into rewire("some/path", require("some/path")) - src = injectRewire(src, filename, settersAndGettersSrc); - } + // We don't want to inject this code at the beginning of a rewire/lib-module. Otherwise + // it would cause a black hole that devours our universe. + // We're also omitting webpack's buildin because it doesn't makes sense to rewire these modules. There's also + // a bug if the special code is injecting into these modules. + if (filename.indexOf(rewireLib) === -1 && filename.indexOf(webpackBuildin) === -1) { + // replaces rewire("some/path") into rewire("some/path", require("some/path")) + src = src.replace(rewireRegExp, '$1rewire("$2", require("$2"))'); + + // Inject special code + src = injectRewire(src, settersAndGettersSrc); + } return src; } @@ -26,16 +46,17 @@ webpackLoader.test = /\.js$/; /** * This string gets injected at the beginning of every module. Its purpose is to * - register the setters and getters according to the module's filename - * - override the internal require with a require proxy. * * @private * @type {String} */ settersAndGettersSrc = ( 'var rewire = require("rewire"); ' + + // Registers the setters and getters of every module according to their filename. The setters and getters must be // injected as string here to gain access to the private scope of the module. - 'rewire.register(module, ' + setterSrc + ', ' + getterSrc + ');' + + 'rewire.register(module, ' + setterSrc + ', ' + getterSrc + '); ' + + // Cleaning up 'rewire = undefined;' ).replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view diff --git a/lib/bundlers/webpack/webpackPostProcessor.js b/lib/bundlers/webpack/webpackPostProcessor.js index e90a4ad..ee10c40 100644 --- a/lib/bundlers/webpack/webpackPostProcessor.js +++ b/lib/bundlers/webpack/webpackPostProcessor.js @@ -1,14 +1,20 @@ "use strict"; // run code in ES5 strict mode -var path = require("path"); +var path = require("path"), -function webpackPostProcessor(filename, callback) { - // Convert back slashes to normal slashes on windows. - if (path.sep !== "/") { - filename = filename.split(path.sep).join("/"); - } + rewireLibIndex = path.join("rewire", "lib", "index.js"); - if (filename.indexOf("/rewire/lib/index.js") !== -1) { +/** + * Gets called before each module is loaded. + * This function ensures that lib/bundlers/webpack/webpackRewire.js is returned instead of lib/index.js. + * + * The callback gets called with (null, filename) + * + * @param {!String} filename + * @param {!Function} callback + */ +function webpackPostProcessor(filename, callback) { + if (filename.indexOf(rewireLibIndex) !== -1) { filename = __dirname + "/webpackRewire.js"; } diff --git a/lib/bundlers/webpack/webpackRewire.js b/lib/bundlers/webpack/webpackRewire.js index bd86f98..521cf26 100644 --- a/lib/bundlers/webpack/webpackRewire.js +++ b/lib/bundlers/webpack/webpackRewire.js @@ -29,11 +29,13 @@ function getIdFromCache(module) { } function getIdByExportsObj(moduleExports) { - var id; + var id, + entry; for (id in registry) { if (registry.hasOwnProperty(id)) { - if (registry[id].module.exports === moduleExports) { + entry = registry[id]; + if (entry.module.exports === moduleExports) { return Number(id); } } @@ -44,6 +46,7 @@ function getIdByExportsObj(moduleExports) { function webpackRewire(path, moduleExports) { var id = getIdByExportsObj(moduleExports), + previousRegistryEntry, cachedModule, rewiredModule, setter, @@ -53,14 +56,18 @@ function webpackRewire(path, moduleExports) { throw new Error("(rewire) Sorry, rewiring '" + path + "' is currently not supported."); } + previousRegistryEntry = registry[id]; + cachedModule = require.cache[id]; delete require.cache[id]; rewiredModule = requireInDisguise(id); - //require.cache[id] = cachedModule; + require.cache[id] = cachedModule; setter = registry[id].setter; getter = registry[id].getter; + registry[id] = previousRegistryEntry; + rewiredModule.__set__ = setter; rewiredModule.__get__ = getter; diff --git a/lib/index.js b/lib/index.js index 4105917..e88d7e5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,19 +5,17 @@ var rewireModule = require("./internalRewire.js"); * call myModule.__set__(name, value) and myModule.__get__(name) to manipulate private variables. * * @param {!String} filename Path to the module that shall be rewired. Use it exactly like require(). - * @param {Boolean} cache Indicates whether the rewired module should be cached by node so subsequent calls of require() will return the rewired module. Subsequent calls of rewire() will always overwrite the cache. * @return {*} the rewired module */ -function rewire(filename, cache) { - if (cache === undefined) { - cache = true; - } - - return rewireModule(module.parent, filename, cache); +function rewire(filename) { + return rewireModule(module.parent, filename); } rewire.reset = rewireModule.reset; -rewire.browserify = require("./bundlers/browserify/browserifyMiddleware.js"); +rewire.bundlers = { + browserify: require("./bundlers/browserify/browserifyMiddleware.js"), + webpack: require("./bundlers/webpack/configureWebpack.js") +}; module.exports = rewire; diff --git a/lib/internalRewire.js b/lib/internalRewire.js index b4c8e62..1500e5d 100644 --- a/lib/internalRewire.js +++ b/lib/internalRewire.js @@ -1,108 +1,88 @@ -var Module = require("module"),
- fs = require("fs"),
- __get__ = require("./__get__.js"),
- __set__ = require("./__set__.js"),
- getImportGlobalsSrc = require("./getImportGlobalsSrc.js"),
- detectStrictMode = require("./detectStrictMode.js"),
-
- moduleWrapper0 = Module.wrapper[0], // caching original wrapper
- moduleWrapper1 = Module.wrapper[1], // caching original wrapper
- rewiredModules = []; // cache for all rewired modules so it can be reset anytime
-
-function restoreOriginalWrappers() {
- Module.wrapper[0] = moduleWrapper0;
- Module.wrapper[1] = moduleWrapper1;
-}
-
-/**
- * Does actual rewiring the module. For further documentation @see index.js
- */
-function internalRewire(parentModulePath, targetPath, cache) {
- var testModule,
- nodeRequire,
- prepend,
- append,
- src;
-
- /**
- * Proxies the first require call in order to draw back all changes.
- * Thus our changes don't influence other modules
- *
- * @param {!String} path
- */
- function requireProxy(path) {
- restoreOriginalWrappers(); // we need to restore the wrappers now so we don't influence other modules
- testModule.require = nodeRequire; // restoring original nodeRequire
- return nodeRequire.call(testModule, path); // node's require only works when "this" points to the module
- }
-
- // Checking params
- if (typeof targetPath !== "string") {
- throw new TypeError("Filename must be a string");
- }
-
- // Resolve full filename relative to the parent module
- targetPath = Module._resolveFilename(targetPath, parentModulePath);
-
- // Special support for older node versions that returned an array on Module._resolveFilename
- // @see https://github.com/joyent/node/blob/865b077819a9271a29f982faaef99dc635b57fbc/lib/module.js#L319
- if (Array.isArray(targetPath)) {
- targetPath = targetPath[1];
- }
-
- // Create testModule as it would be created by require()
- testModule = new Module(targetPath, parentModulePath);
-
- // Patching requireProxy
- nodeRequire = testModule.require;
- testModule.require = requireProxy;
-
- // We prepend a list of all globals declared with var so they can be overridden (without changing original globals)
- prepend = getImportGlobalsSrc();
-
- // We append our special setter and getter.
- append = "module.exports.__set__ = " + __set__.toString() + "; ";
- append += "module.exports.__get__ = " + __get__.toString() + "; ";
-
- // Check if the module uses the strict mode.
- // If so we must ensure that "use strict"; stays at the beginning of the module.
- src = fs.readFileSync(targetPath, "utf8");
- if (detectStrictMode(src) === true) {
- prepend = ' "use strict"; ' + prepend;
- }
-
- // Apply prepend and appends
- Module.wrapper[0] = moduleWrapper0 + prepend;
- Module.wrapper[1] = append + moduleWrapper1;
-
- //console.log(Module.wrapper);
-
- // Let the show begin
- testModule.load(testModule.id);
-
- // Store the rewired module in the cache when enabled
- if (cache) {
- rewiredModules.push(targetPath); // save in private cache for .reset()
- require.cache[targetPath] = testModule;
- }
-
- // This is only necessary if nothing has been required within the module
- restoreOriginalWrappers();
-
- return testModule.exports;
-}
-
-/**
- * Deletes all rewired modules from the cache
- */
-internalRewire.reset = function () {
- var i;
-
- for (i = 0; i < rewiredModules.length; i++) {
- delete require.cache[rewiredModules[i]];
- }
-
- rewiredModules = [];
-};
-
+var Module = require("module"), + fs = require("fs"), + __get__ = require("./__get__.js"), + __set__ = require("./__set__.js"), + getImportGlobalsSrc = require("./getImportGlobalsSrc.js"), + detectStrictMode = require("./detectStrictMode.js"), + + moduleWrapper0 = Module.wrapper[0], // caching original wrapper + moduleWrapper1 = Module.wrapper[1]; // caching original wrapper + +function restoreOriginalWrappers() { + Module.wrapper[0] = moduleWrapper0; + Module.wrapper[1] = moduleWrapper1; +} + +/** + * Does actual rewiring the module. For further documentation @see index.js + */ +function internalRewire(parentModulePath, targetPath) { + var testModule, + nodeRequire, + prepend, + append, + src; + + /** + * Proxies the first require call in order to draw back all changes to the Module.wrapper. + * Thus our changes don't influence other modules + * + * @param {!String} path + */ + function requireProxy(path) { + restoreOriginalWrappers(); + testModule.require = nodeRequire; + return nodeRequire.call(testModule, path); // node's require only works when "this" points to the module + } + + // Checking params + if (typeof targetPath !== "string") { + throw new TypeError("Filename must be a string"); + } + + // Resolve full filename relative to the parent module + targetPath = Module._resolveFilename(targetPath, parentModulePath); + + // Special support for older node versions that returned an array on Module._resolveFilename + // @see https://github.com/joyent/node/blob/865b077819a9271a29f982faaef99dc635b57fbc/lib/module.js#L319 + if (Array.isArray(targetPath)) { + targetPath = targetPath[1]; + } + + // Create testModule as it would be created by require() + testModule = new Module(targetPath, parentModulePath); + + // Patching requireProxy + nodeRequire = testModule.require; + testModule.require = requireProxy; + + // We prepend a list of all globals declared with var so they can be overridden (without changing original globals) + prepend = getImportGlobalsSrc(); + + // We append our special setter and getter. + append = "module.exports.__set__ = " + __set__.toString() + "; "; + append += "module.exports.__get__ = " + __get__.toString() + "; "; + + // Check if the module uses the strict mode. + // If so we must ensure that "use strict"; stays at the beginning of the module. + src = fs.readFileSync(targetPath, "utf8"); + if (detectStrictMode(src) === true) { + prepend = ' "use strict"; ' + prepend; + } + + // Apply prepend and appends + Module.wrapper[0] = moduleWrapper0 + prepend; + Module.wrapper[1] = append + moduleWrapper1; + + //console.log(Module.wrapper); + + // Let the show begin + testModule.load(testModule.id); + + // This is only necessary if nothing has been required within the module + restoreOriginalWrappers(); + + return testModule.exports; +} + module.exports = internalRewire;
\ No newline at end of file |