diff options
author | Johannes <johannes.ewald@roomieplanet.de> | 2012-08-18 18:34:13 +0400 |
---|---|---|
committer | Johannes <johannes.ewald@roomieplanet.de> | 2012-08-18 18:34:13 +0400 |
commit | c5d8fab07f0edc568e45e0747f863afd5876abc2 (patch) | |
tree | ab57b94703d16087fbb6c81e4bdb5d1ae6217d19 /lib | |
parent | 657b9e84018014d15916c86274b8ee35b9386627 (diff) |
- Introduced webpack bundler for rewire (work in progress, some tests are not running)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/browser/shims.js | 48 | ||||
-rw-r--r-- | lib/browserify/browserifyMiddleware.js | 100 | ||||
-rw-r--r-- | lib/bundlers/browserify/browserifyMiddleware.js | 67 | ||||
-rw-r--r-- | lib/bundlers/browserify/browserifyRewire.js (renamed from lib/browserify/browserifyRewire.js) | 374 | ||||
-rw-r--r-- | lib/bundlers/getRewireRegExp.js | 15 | ||||
-rw-r--r-- | lib/bundlers/getRewireRequires.js (renamed from lib/browserify/getRewireRequires.js) | 44 | ||||
-rw-r--r-- | lib/bundlers/injectRewire.js | 54 | ||||
-rw-r--r-- | lib/bundlers/webpack/configureWebpack.js | 16 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackPostLoader.js | 43 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackPostProcessor.js | 18 | ||||
-rw-r--r-- | lib/bundlers/webpack/webpackRewire.js | 91 | ||||
-rw-r--r-- | lib/index.js | 57 |
12 files changed, 537 insertions, 390 deletions
diff --git a/lib/browser/shims.js b/lib/browser/shims.js deleted file mode 100644 index df7bd63..0000000 --- a/lib/browser/shims.js +++ /dev/null @@ -1,48 +0,0 @@ -// Taken from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility
-if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
- "use strict";
- if (this == null) {
- throw new TypeError();
- }
- var t = Object(this);
- var len = t.length >>> 0;
- if (len === 0) {
- return -1;
- }
- var n = 0;
- if (arguments.length > 0) {
- n = Number(arguments[1]);
- if (n != n) { // shortcut for verifying if it's NaN
- n = 0;
- } else if (n != 0 && n != Infinity && n != -Infinity) {
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
- }
- }
- if (n >= len) {
- return -1;
- }
- var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
- for (; k < len; k++) {
- if (k in t && t[k] === searchElement) {
- return k;
- }
- }
- return -1;
- }
-}
-
-
-// Taken from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/trim#Compatibility
-if(!String.prototype.trim) {
- String.prototype.trim = function () {
- return this.replace(/^\s+|\s+$/g,'');
- };
-}
-
-// Taken from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray#Compatibility
-if(!Array.isArray) {
- Array.isArray = function (vArg) {
- return Object.prototype.toString.call(vArg) === "[object Array]";
- };
-}
\ No newline at end of file diff --git a/lib/browserify/browserifyMiddleware.js b/lib/browserify/browserifyMiddleware.js deleted file mode 100644 index fb1887f..0000000 --- a/lib/browserify/browserifyMiddleware.js +++ /dev/null @@ -1,100 +0,0 @@ -var setterSrc = require("../__set__.js").toString(),
- getterSrc = require("../__get__.js").toString(),
- fs = require("fs"),
- path = require("path"),
- getImportGlobalsSrc = require("../getImportGlobalsSrc.js"),
- getRewireRequires = require("./getRewireRequires.js"),
- detectStrictMode = require("../detectStrictMode.js"),
-
- injectionSrc = getInjectionSrc().replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view
-
-/**
- * Returns a string that 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.
- *
- * @return {String}
- */
-function getInjectionSrc() {
- return '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 + ');' +
- // 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);' +
- // Cleaning up
- 'rewire = undefined;';
-}
-
-function browserifyMiddleware(b) {
-
- /**
- * Gets called for every module. Injects special code so rewire is able to access private variables.
- *
- * @param {String} src
- * @param {String} filename
- * @return {String}
- */
- function injectRewire(src, filename) {
- var rewireRequires;
-
- // 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 absolute paths
- if (requirePath.charAt(0) === ".") {
- requirePath = path.resolve(path.dirname(filename), requirePath);
- }
- b.require(requirePath);
- });
-
- // Convert back slashes to normal slashes on windows.
- if (process.platform.indexOf("win") === 0) {
- filename = filename.replace(/\\/g, "/");
- }
-
- // 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"; ': ' ') +
-
- injectionSrc + "\n" +
- src +
-
- "})();";
- }
-
- return src;
- }
-
- // Register file handler
- b.register(".js", injectRewire);
-
- return b;
-}
-
-module.exports = browserifyMiddleware;
\ No newline at end of file diff --git a/lib/bundlers/browserify/browserifyMiddleware.js b/lib/bundlers/browserify/browserifyMiddleware.js new file mode 100644 index 0000000..39d76b1 --- /dev/null +++ b/lib/bundlers/browserify/browserifyMiddleware.js @@ -0,0 +1,67 @@ +var setterSrc = require("../../__set__.js").toString(), + getterSrc = require("../../__get__.js").toString(), + path = require("path"), + injectRewire = require("../injectRewire.js"), + getRewireRequires = require("../getRewireRequires.js"), + + rewireIndex = path.resolve(__dirname, "../../index.js"), + settersAndGettersSrc; + +function browserifyMiddleware(b) { + function doInjectRewire(src, filename) { + var rewireRequires; + + // 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 absolute paths + if (requirePath.charAt(0) === ".") { + requirePath = path.resolve(path.dirname(filename), requirePath); + } + b.require(requirePath); + }); + + src = injectRewire(src, filename, settersAndGettersSrc); + + return src; + } + + function forwardBrowserifyRewire(filename) { + if (filename === rewireIndex) { + filename = __dirname + "/browserifyRewire.js"; + } + + return filename; + } + + // Register file handler + b.register(".js", doInjectRewire); + b.register("path", forwardBrowserifyRewire); + + return b; +} + +/** + * 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(__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);' + + // 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/browserify/browserifyRewire.js b/lib/bundlers/browserify/browserifyRewire.js index e21c0db..2798b69 100644 --- a/lib/browserify/browserifyRewire.js +++ b/lib/bundlers/browserify/browserifyRewire.js @@ -1,189 +1,187 @@ -require("../browser/shims.js"); // some shims for older browsers that are necessary for rewire()
-
-var pathUtil = require("path"),
- getImportGlobalsSrc = require("../getImportGlobalsSrc.js");
-
-/**
- * Clones an object deeply. Used to clone the module-object that is
- * stored in the cache. Because browserify doesn't create the module-
- * object newly if the module is executed again we can't modify the
- * exports object directly. Instead of we have to make an independent copy.
- *
- * @param {!Object} obj
- * @return {Object}
- */
-function clone(obj) {
- var target = {},
- value,
- key;
-
- for (key in obj) {
- if (obj.hasOwnProperty(key)) {
- value = obj[key];
- if (Array.isArray(value)) {
- target[key] = value.slice(0);
- } else if (typeof value === "object" && value !== null) {
- target[key] = clone(value);
- } else {
- target[key] = value;
- }
-
- }
- }
-
- return target;
-}
-
-// 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 = [];
-
-/**
- * Executes the given module and adds a special setter and getter that allow you to set and get private variables.
- * The parentModulePath is usually set by the requireProxy.
- *
- * @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}
- */
-function browserifyRewire(parentModulePath, path, cache) {
- var originalModule,
- absPath,
- rewiredExports,
- rewiredModule,
- registryEntry;
-
- // Default cache to true
- if (cache === undefined) {
- cache = true;
- }
-
- // Normalize path with file extensions
- absPath = pathUtil.resolve(parentModulePath, path);
-
- // Retrieve original module from cache
- originalModule = require.cache[absPath];
-
- if (originalModule && cache) {
- // Delete the original module from the cache so the next call to browserifyRequre()
- // executes the module
- delete require.cache[absPath];
- }
-
- // Require module to trigger rewire.register().
- // Putting (require) in brackets hides it for browserify.
- (require)(absPath);
-
- // 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;
-}
-
-/**
- * Registers the setter and getter of every module according to its filename
- *
- * @param {!String} filename the absolute path to the module (module id)
- * @param {!Function} setter
- * @param {!Function} getter
- */
-browserifyRewire.register = function (filename, module, setter, getter) {
- registry[filename] = {
- module: module,
- setter: setter,
- getter: 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.
- *
- * This is necessary to call rewire() with the original __filename. Thus you can use rewire() like require().
- *
- * @param {!Function} internalRequire the module's own require
- * @param {String} dirname the __dirname of the module
- * @return {Function} requireProxy
- */
-browserifyRewire.getProxy = function (internalRequire, dirname) {
- var rewire = internalRequire("rewire"),
- rewireProxyInit = false;
-
- function copyProperties(from, to) {
- var key;
-
- for (key in from) {
- if (from.hasOwnProperty(key)) {
- to[key] = from[key];
- }
- }
- }
-
- function rewireProxy(path, cache) {
- return rewire(dirname, path, cache);
- }
-
- function requireProxy(path) {
- if (path === "rewire") {
- if (rewireProxyInit === false) {
- copyProperties(rewire, rewireProxy); // lazy copy
- rewireProxyInit = true;
- }
- return rewireProxy;
- } else {
- return internalRequire(path);
- }
- }
-
- copyProperties(internalRequire, requireProxy);
-
- return requireProxy;
-};
-
-/**
- * Scans for global vars and returns an evalable string that declares all globals as a var.
- * This way a global variable can be overridden by __set__ without changing the global instance.
- * It is executed each time again to include global variables that have been added later.
- *
- * @return {String}
- */
-browserifyRewire.getImportGlobalsSrc = function () {
- return getImportGlobalsSrc(['require','module','exports','__dirname','__filename','process']);
-};
-
+var pathUtil = require("path"), + getImportGlobalsSrc = require("./getImportGlobalsSrc.js"); /* must be relative to lib/index.js */ + +/** + * Clones an object deeply. Used to clone the module-object that is + * stored in the cache. Because browserify doesn't create the module- + * object newly if the module is executed again we can't modify the + * exports object directly. Instead of we have to make an independent copy. + * + * @param {!Object} obj + * @return {Object} + */ +function clone(obj) { + var target = {}, + value, + key; + + for (key in obj) { + if (obj.hasOwnProperty(key)) { + value = obj[key]; + if (Array.isArray(value)) { + target[key] = value.slice(0); + } else if (typeof value === "object" && value !== null) { + target[key] = clone(value); + } else { + target[key] = value; + } + + } + } + + return target; +} + +// 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 = []; + +/** + * Executes the given module and adds a special setter and getter that allow you to set and get private variables. + * The parentModulePath is usually set by the requireProxy. + * + * @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} + */ +function browserifyRewire(parentModulePath, path, cache) { + var originalModule, + absPath, + rewiredExports, + rewiredModule, + registryEntry, + _require = require; // hide it from browserify + + // Default cache to true + if (cache === undefined) { + cache = true; + } + + // Normalize path with file extensions + absPath = pathUtil.resolve(parentModulePath, path); + + // Retrieve original module from cache + originalModule = require.cache[absPath]; + + if (originalModule && cache) { + // Delete the original module from the cache so the next call to browserifyRequre() + // executes the module + delete require.cache[absPath]; + } + + // Require module to trigger rewire.register(). + _require(absPath); + + // 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; +} + +/** + * Registers the setter and getter of every module according to its filename + * + * @param {!String} filename the absolute path to the module (module id) + * @param {!Function} setter + * @param {!Function} getter + */ +browserifyRewire.register = function (filename, module, setter, getter) { + registry[filename] = { + module: module, + setter: setter, + getter: 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. + * + * This is necessary to call rewire() with the original __filename. Thus you can use rewire() like require(). + * + * @param {!Function} internalRequire the module's own require + * @param {String} dirname the __dirname of the module + * @return {Function} requireProxy + */ +browserifyRewire.getProxy = function (internalRequire, dirname) { + var rewire = internalRequire("rewire"), + rewireProxyInit = false; + + function copyProperties(from, to) { + var key; + + for (key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } + } + + function rewireProxy(path, cache) { + return rewire(dirname, path, cache); + } + + function requireProxy(path) { + if (path === "rewire") { + if (rewireProxyInit === false) { + copyProperties(rewire, rewireProxy); // lazy copy + rewireProxyInit = true; + } + return rewireProxy; + } else { + return internalRequire(path); + } + } + + copyProperties(internalRequire, requireProxy); + + return requireProxy; +}; + +/** + * Scans for global vars and returns an evalable string that declares all globals as a var. + * This way a global variable can be overridden by __set__ without changing the global instance. + * It is executed each time again to include global variables that have been added later. + * + * @return {String} + */ +browserifyRewire.getImportGlobalsSrc = function () { + return getImportGlobalsSrc(['require','module','exports','__dirname','__filename','process']); +}; + module.exports = browserifyRewire;
\ No newline at end of file diff --git a/lib/bundlers/getRewireRegExp.js b/lib/bundlers/getRewireRegExp.js new file mode 100644 index 0000000..69e4ef5 --- /dev/null +++ b/lib/bundlers/getRewireRegExp.js @@ -0,0 +1,15 @@ +/** + * Returns a regular expression that matches all rewire() statements. + * + * Captures: + * + * 1. the character before rewire + * 2. the path between the parenthesis without quotation marks + * + * @return {RegExp} + */ +function getRewireRegExp() { + return /([^a-zA-Z0-9_])rewire\(["'](.+?)["']\)/g; +} + +module.exports = getRewireRegExp;
\ No newline at end of file diff --git a/lib/browserify/getRewireRequires.js b/lib/bundlers/getRewireRequires.js index 896729e..2c80091 100644 --- a/lib/browserify/getRewireRequires.js +++ b/lib/bundlers/getRewireRequires.js @@ -1,22 +1,24 @@ -/***
- * Searches for rewire(); statements and returns all strings that are between the brackets.
- *
- * @param {!String} src
- * @return {Array}
- */
-function getRewireRequires(src) {
- var result = [],
- regExp = /[^a-zA-Z0-9_]rewire\(["'](.+?)["']\)/g,
- match;
-
- src = " " + src; // ensure that rewire() is not at index 0 otherwise the regexp won't work in this case
- match = regExp.exec(src);
- while (match !== null) {
- result.push(match[1]);
- match = regExp.exec(src);
- }
-
- return result;
-}
-
+var getRewireRegExp = require("./getRewireRegExp.js"); + +/** + * Searches for rewire(); statements and returns all strings that are between the brackets. + * + * @param {!String} src + * @return {Array} + */ +function getRewireRequires(src) { + var result = [], + regExp = getRewireRegExp(), + match; + + src = " " + src; // ensure that rewire() is not at index 0 otherwise the regexp won't work in this case + match = regExp.exec(src); + while (match !== null) { + result.push(match[2]); + match = regExp.exec(src); + } + + return result; +} + module.exports = getRewireRequires;
\ No newline at end of file diff --git a/lib/bundlers/injectRewire.js b/lib/bundlers/injectRewire.js new file mode 100644 index 0000000..dfd56a4 --- /dev/null +++ b/lib/bundlers/injectRewire.js @@ -0,0 +1,54 @@ +"use strict"; // run code in ES5 strict mode + +var path = require("path"), + getRewireRequires = require("./getRewireRequires.js"), + detectStrictMode = require("../detectStrictMode.js"); + +/** + * Gets called by the bundler for every module. Injects special code so rewire is able to access private variables. + * + * @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 + * @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 + + + " })();"; + } + + return src; +} + +module.exports = injectRewire;
\ No newline at end of file diff --git a/lib/bundlers/webpack/configureWebpack.js b/lib/bundlers/webpack/configureWebpack.js new file mode 100644 index 0000000..a302d1c --- /dev/null +++ b/lib/bundlers/webpack/configureWebpack.js @@ -0,0 +1,16 @@ +"use strict"; // run code in ES5 strict mode + +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(); + + options.postLoaders.push(require("./webpackPostLoader.js")); + options.resolve.postprocess.normal.push(require("./webpackPostProcessor.js")); +} + +module.exports = configureWebpack;
\ No newline at end of file diff --git a/lib/bundlers/webpack/webpackPostLoader.js b/lib/bundlers/webpack/webpackPostLoader.js new file mode 100644 index 0000000..620f091 --- /dev/null +++ b/lib/bundlers/webpack/webpackPostLoader.js @@ -0,0 +1,43 @@ +"use strict"; // run code in ES5 strict mode + +var setterSrc = require("../../__set__.js").toString(), + getterSrc = require("../../__get__.js").toString(), + injectRewire = require("../injectRewire.js"), + getRewireRegExp = require("../getRewireRegExp.js"), + + settersAndGettersSrc; + +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); + } + + + return src; +} + +webpackLoader.loader = __filename; +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 + ');' + + // Cleaning up + 'rewire = undefined;' +).replace(/\s+/g, " "); // strip out unnecessary spaces to be unobtrusive in the debug view + +module.exports = webpackLoader;
\ No newline at end of file diff --git a/lib/bundlers/webpack/webpackPostProcessor.js b/lib/bundlers/webpack/webpackPostProcessor.js new file mode 100644 index 0000000..e90a4ad --- /dev/null +++ b/lib/bundlers/webpack/webpackPostProcessor.js @@ -0,0 +1,18 @@ +"use strict"; // run code in ES5 strict mode + +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("/"); + } + + if (filename.indexOf("/rewire/lib/index.js") !== -1) { + filename = __dirname + "/webpackRewire.js"; + } + + callback(null, filename); +} + +module.exports = webpackPostProcessor;
\ No newline at end of file diff --git a/lib/bundlers/webpack/webpackRewire.js b/lib/bundlers/webpack/webpackRewire.js new file mode 100644 index 0000000..bd86f98 --- /dev/null +++ b/lib/bundlers/webpack/webpackRewire.js @@ -0,0 +1,91 @@ +"use strict"; // run code in ES5 strict mode + +var registry = {}, + getImportGlobalsSrc = require("../../getImportGlobalsSrc.js"); + +var requireInDisguise; + +eval("requireInDisguise = require"); + +function getId(module) { + var index = registry.modules.indexOf(module); + + return registry.id[index] || null; +} + +function getIdFromCache(module) { + var cache = require.cache, + id; + + for (id in cache) { + if (cache.hasOwnProperty(id)) { + if (cache[id] === module) { + return Number(id); + } + } + } + + return null; +} + +function getIdByExportsObj(moduleExports) { + var id; + + for (id in registry) { + if (registry.hasOwnProperty(id)) { + if (registry[id].module.exports === moduleExports) { + return Number(id); + } + } + } + + return null; +} + +function webpackRewire(path, moduleExports) { + var id = getIdByExportsObj(moduleExports), + cachedModule, + rewiredModule, + setter, + getter; + + if (typeof id !== "number") { + throw new Error("(rewire) Sorry, rewiring '" + path + "' is currently not supported."); + } + + cachedModule = require.cache[id]; + delete require.cache[id]; + rewiredModule = requireInDisguise(id); + //require.cache[id] = cachedModule; + + setter = registry[id].setter; + getter = registry[id].getter; + + rewiredModule.__set__ = setter; + rewiredModule.__get__ = getter; + + return rewiredModule; +} + +webpackRewire.register = function (module, setter, getter) { + var id = getIdFromCache(module); + + registry[id] = { + module: module, + setter: setter, + getter: getter + }; +}; + +/** + * Scans for global vars and returns an evalable string that declares all globals as a var. + * This way a global variable can be overridden by __set__ without changing the global instance. + * It is executed each time again to include global variables that have been added later. + * + * @return {String} + */ +webpackRewire.getImportGlobalsSrc = function () { + return getImportGlobalsSrc(['require','module','exports','__dirname','__filename','process']); +}; + +module.exports = webpackRewire;
\ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 491599a..4105917 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,33 +1,24 @@ -var rewireModule;
-
-/**
- * Adds a special setter and getter to the module located at filename. After the module has been rewired, you can
- * 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);
-}
-
-// Conditional require for different environments
-if (process.title === "browser") {
- module.exports = require("./browserify/browserifyRewire.js");
-} else {
- delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date
-
- // Putting (require) within brackets is a hack to disable browserify's require sniffing
- // @see https://github.com/substack/node-browserify/issues/132#issuecomment-5281470
- rewireModule = (require)("./internalRewire.js");
-
- rewire.reset = rewireModule.reset;
- rewire.browserify = (require)("./browserify/browserifyMiddleware.js");
-
- module.exports = rewire;
-}
+var rewireModule = require("./internalRewire.js"); + +/** + * Adds a special setter and getter to the module located at filename. After the module has been rewired, you can + * 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); +} + +rewire.reset = rewireModule.reset; +rewire.browserify = require("./bundlers/browserify/browserifyMiddleware.js"); + +module.exports = rewire; + +delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date
\ No newline at end of file |