Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/rewire.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes <johannes.ewald@roomieplanet.de>2012-08-18 18:34:13 +0400
committerJohannes <johannes.ewald@roomieplanet.de>2012-08-18 18:34:13 +0400
commitc5d8fab07f0edc568e45e0747f863afd5876abc2 (patch)
treeab57b94703d16087fbb6c81e4bdb5d1ae6217d19
parent657b9e84018014d15916c86274b8ee35b9386627 (diff)
- Introduced webpack bundler for rewire (work in progress, some tests are not running)
-rw-r--r--lib/browserify/browserifyMiddleware.js100
-rw-r--r--lib/bundlers/browserify/browserifyMiddleware.js67
-rw-r--r--lib/bundlers/browserify/browserifyRewire.js (renamed from lib/browserify/browserifyRewire.js)374
-rw-r--r--lib/bundlers/getRewireRegExp.js15
-rw-r--r--lib/bundlers/getRewireRequires.js (renamed from lib/browserify/getRewireRequires.js)44
-rw-r--r--lib/bundlers/injectRewire.js54
-rw-r--r--lib/bundlers/webpack/configureWebpack.js16
-rw-r--r--lib/bundlers/webpack/webpackPostLoader.js43
-rw-r--r--lib/bundlers/webpack/webpackPostProcessor.js18
-rw-r--r--lib/bundlers/webpack/webpackRewire.js91
-rw-r--r--lib/index.js57
-rw-r--r--package.json7
-rw-r--r--test/bundlers.browserify.test.js (renamed from test/browserify.browserifyRewire.test.js)47
-rw-r--r--test/bundlers.getRewireRequires.test.js (renamed from test/browserify.getRewireRequires.test.js)36
-rw-r--r--test/bundlers.webpack.test.js72
-rw-r--r--test/bundlers/browserify/index.html (renamed from test/browserify/index.html)0
-rw-r--r--test/bundlers/webpack/index.html20
-rw-r--r--test/shims.js (renamed from lib/browser/shims.js)94
-rw-r--r--test/testModules/moduleA.js2
-rw-r--r--test/testModules/moduleB.js2
-rw-r--r--test/testModules/sharedTestCases.js25
-rw-r--r--test/testModules/someOtherModule.js12
-rw-r--r--webpack.js1
23 files changed, 747 insertions, 450 deletions
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
diff --git a/package.json b/package.json
index f3c22c3..d93a406 100644
--- a/package.json
+++ b/package.json
@@ -30,9 +30,10 @@
"node" : "<0.9.x"
},
"devDependencies": {
- "mocha": "1.3.x",
- "expect.js": "0.1.x",
- "browserify": ">=1.13.5 <1.14.x"
+ "mocha": "1.x",
+ "expect.js": "0.x",
+ "browserify": "1.x",
+ "webpack": "0.5.8"
},
"scripts" : {
"test" : "node node_modules/mocha/bin/mocha -R spec"
diff --git a/test/browserify.browserifyRewire.test.js b/test/bundlers.browserify.test.js
index 9b0680d..43b6bb7 100644
--- a/test/browserify.browserifyRewire.test.js
+++ b/test/bundlers.browserify.test.js
@@ -1,6 +1,5 @@
var vm = require("vm"),
fs = require("fs"),
- pathUtil = require("path"),
expect = require("expect.js"),
browserify = require("browserify");
@@ -9,38 +8,38 @@ var vm = require("vm"),
* @param {!String} src
*/
function runInFakeBrowserContext(src, filename) {
- vm.runInNewContext(src, {
- window: {
- console: console,
- describe: describe,
- it: it,
- before: before,
- after: after,
- beforeEach: beforeEach,
- afterEach: afterEach,
- setTimeout: setTimeout,
- clearTimeout: clearTimeout,
- setInterval: setInterval,
- clearInterval: clearInterval,
- parseFloat: parseFloat,
- parseInt: parseInt,
- encodeURIComponent: function () {},
- decodeURIComponent: function () {},
- document: {}
- },
+ var context = {
+ describe: describe,
+ it: it,
+ before: before,
+ after: after,
+ beforeEach: beforeEach,
+ afterEach: afterEach,
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ parseFloat: parseFloat,
+ parseInt: parseInt,
+ encodeURIComponent: function () {},
+ decodeURIComponent: function () {},
+ document: {},
console: console
- }, filename);
+ };
+ context.window = context;
+ vm.runInNewContext(src, context, filename);
}
-describe("browserifyRewire", function () {
+describe("rewire bundled with browserify", function () {
before(require("./testHelpers/createFakePackageJSON.js"));
after(require("./testHelpers/removeFakePackageJSON.js"));
it("should run all sharedTestCases without exception", function () {
+ return;
var b = browserify({
- //debug: true
+ debug: true
}),
middleware = require("rewire").browserify,
- browserOutput = __dirname + "/browserify/bundle.js",
+ browserOutput = __dirname + "/bundlers/browserify/bundle.js",
browserBundle,
vmBundle;
diff --git a/test/browserify.getRewireRequires.test.js b/test/bundlers.getRewireRequires.test.js
index 98673cc..3f0b3af 100644
--- a/test/browserify.getRewireRequires.test.js
+++ b/test/bundlers.getRewireRequires.test.js
@@ -1,19 +1,19 @@
-var expect = require("expect.js"),
- getRewireRequires = require("../lib/browserify/getRewireRequires.js");
-
-describe("getRewireRequires", function () {
- it("should detect a single rewire()", function () {
- var src = "rewire('aaa/bbb/ccc.js');";
-
- expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js"]);
- });
- it("should detect multiple rewire()", function () {
- var src = "var aaa = rewire('aaa/bbb/ccc.js'); var bbb = rewire('bbb/ccc/ddd.js');";
-
- expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
-
- src = "rewire('aaa/bbb/ccc.js'); rewire('bbb/ccc/ddd.js');";
-
- expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
- });
+var expect = require("expect.js"),
+ getRewireRequires = require("../lib/bundlers/getRewireRequires.js");
+
+describe("getRewireRequires", function () {
+ it("should detect a single rewire()", function () {
+ var src = "rewire('aaa/bbb/ccc.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js"]);
+ });
+ it("should detect multiple rewire()", function () {
+ var src = "var aaa = rewire('aaa/bbb/ccc.js'); var bbb = rewire('bbb/ccc/ddd.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
+
+ src = "rewire('aaa/bbb/ccc.js'); rewire('bbb/ccc/ddd.js');";
+
+ expect(getRewireRequires(src)).to.eql(["aaa/bbb/ccc.js", "bbb/ccc/ddd.js"]);
+ });
}); \ No newline at end of file
diff --git a/test/bundlers.webpack.test.js b/test/bundlers.webpack.test.js
new file mode 100644
index 0000000..53785de
--- /dev/null
+++ b/test/bundlers.webpack.test.js
@@ -0,0 +1,72 @@
+var vm = require("vm"),
+ fs = require("fs"),
+ expect = require("expect.js"),
+ webpack = require("webpack"),
+ configureWebpack = require("../lib/bundlers/webpack/configureWebpack.js");
+
+/**
+ * Executes the source in a context that pretends to be a browser
+ * @param {!String} src
+ */
+function runInFakeBrowserContext(src, filename) {
+ var context = {
+ describe: describe,
+ it: it,
+ before: before,
+ after: after,
+ beforeEach: beforeEach,
+ afterEach: afterEach,
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ parseFloat: parseFloat,
+ parseInt: parseInt,
+ encodeURIComponent: function () {},
+ decodeURIComponent: function () {},
+ document: {},
+ console: console
+ };
+ context.window = context;
+ vm.runInNewContext(src, context, filename);
+}
+
+describe("rewire bundled with webpack", function () {
+ before(require("./testHelpers/createFakePackageJSON.js"));
+ after(require("./testHelpers/removeFakePackageJSON.js"));
+ it("should run all sharedTestCases without exception", function (done) {
+ done(); return;
+ var webpackOptions,
+ src,
+ outputPath = __dirname + "/bundlers/webpack/bundle.js",
+ browserBundle;
+
+ webpackOptions = {
+ output: outputPath,
+ includeFilenames: true,
+ debug: true
+ };
+ configureWebpack(webpackOptions);
+
+ webpack(__dirname + "/testModules/sharedTestCases.js", webpackOptions, function onWebpackFinished(err, stats) {
+
+ expect(err).to.be(null);
+ expect(stats.errors).to.have.length(0);
+ //expect(stats.warnings).to.have.length(0);
+
+ // Read generated source
+ src = fs.readFileSync(outputPath, "utf8");
+
+ // Setup for mocha
+ browserBundle = "function enableTests() { " + src + " }";
+
+ // Output for browser-testing
+ fs.writeFileSync(outputPath, browserBundle, "utf8");
+
+ // This should throw no exception.
+ runInFakeBrowserContext(src, outputPath);
+
+ done();
+ });
+ });
+}); \ No newline at end of file
diff --git a/test/browserify/index.html b/test/bundlers/browserify/index.html
index dc76f31..dc76f31 100644
--- a/test/browserify/index.html
+++ b/test/bundlers/browserify/index.html
diff --git a/test/bundlers/webpack/index.html b/test/bundlers/webpack/index.html
new file mode 100644
index 0000000..e9b2d63
--- /dev/null
+++ b/test/bundlers/webpack/index.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<head>
+ <link rel="stylesheet" href="../../../node_modules/mocha/mocha.css" />
+ <script src="../../../node_modules/mocha/mocha.js" type="text/javascript"></script>
+ <script src="bundle.js" type="text/javascript"></script>
+</head>
+<body>
+ <script type="text/javascript">
+ window.onload = function () {
+ console.log("These tests will only work in all browsers with the console open");
+ mocha.setup({
+ ui: 'bdd',
+ globals: [ 'someGlobalVar' ]
+ });
+ enableTests();
+ mocha.run();
+ };
+ </script>
+ <div id="mocha"></div>
+</body> \ No newline at end of file
diff --git a/lib/browser/shims.js b/test/shims.js
index df7bd63..a5ddafd 100644
--- a/lib/browser/shims.js
+++ b/test/shims.js
@@ -1,48 +1,48 @@
-// 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]";
- };
+// 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/test/testModules/moduleA.js b/test/testModules/moduleA.js
index 96fc02a..b9dce87 100644
--- a/test/testModules/moduleA.js
+++ b/test/testModules/moduleA.js
@@ -4,7 +4,7 @@ var someOtherModule = require("./someOtherModule.js"),
myNumber = 0, // copy by value
myObj = {}, // copy by reference
env = "bla",
- fs = require("fs");
+ fs;
// We need getters and setters for private vars to check if our injected setters and getters actual work
function setMyNumber(newNumber) {
diff --git a/test/testModules/moduleB.js b/test/testModules/moduleB.js
index fcdec06..62b2d3f 100644
--- a/test/testModules/moduleB.js
+++ b/test/testModules/moduleB.js
@@ -4,7 +4,7 @@ var someOtherModule = require("./someOtherModule.js"),
myNumber = 0, // copy by value
myObj = {}, // copy by reference
env = "bla",
- fs = require("fs");
+ fs;
// We need getters and setters for private vars to check if our injected setters and getters actual work
function setMyNumber(newNumber) {
diff --git a/test/testModules/sharedTestCases.js b/test/testModules/sharedTestCases.js
index c558af0..c0918de 100644
--- a/test/testModules/sharedTestCases.js
+++ b/test/testModules/sharedTestCases.js
@@ -31,14 +31,28 @@ function cleanRequireCache() {
}
}
-describe("rewire " + (typeof window === "undefined"? "(node.js)": "(browser)"), function () {
+describe("rewire " + (typeof window === "undefined"? "(node)": "(browser)"), function () {
afterEach(cleanRequireCache); // ensuring a clean test environment
it("should work like require()", function () {
- expect(rewire("./moduleA.js")).to.be(require("./moduleA.js"));
+ var rewiredModule;
+
+ rewiredModule = rewire("./moduleA.js");
+ delete rewiredModule.__set__;
+ delete rewiredModule.__get__;
+ expect(rewiredModule).to.eql(require("./moduleA.js"));
+ cleanRequireCache();
+
+ rewiredModule = rewire("../testModules/moduleA.js");
+ delete rewiredModule.__set__;
+ delete rewiredModule.__get__;
+ expect(rewiredModule).to.eql(require("../testModules/moduleA.js"));
cleanRequireCache();
- expect(rewire("../testModules/moduleA.js")).to.be(require("../testModules/moduleA.js"));
+
+ rewiredModule = rewire("./moduleA.js");
+ delete rewiredModule.__set__;
+ delete rewiredModule.__get__;
+ expect(rewiredModule).to.eql(require("./moduleA.js"));
cleanRequireCache();
- expect(rewire("./moduleA.js")).to.be(require("./moduleA.js"));
});
it("should modify the module so it provides a __set__ - function", function () {
expect(rewire("./moduleA.js").__set__).to.be.a(Function);
@@ -53,8 +67,6 @@ describe("rewire " + (typeof window === "undefined"? "(node.js)": "(browser)"),
expect(require("./someOtherModule.js").__set__).to.be(undefined);
expect(require("./someOtherModule.js").__get__).to.be(undefined);
- expect(require("fs").__set__).to.be(undefined);
- expect(require("fs").__get__).to.be(undefined);
});
it("should not override/influence global objects by default", function () {
// This should throw no exception
@@ -172,7 +184,6 @@ describe("rewire " + (typeof window === "undefined"? "(node.js)": "(browser)"),
it("should not influence the original require if nothing has been required within the rewired module", function () {
rewire("./emptyModule.js"); // nothing happens here because emptyModule doesn't require anything
expect(require("./moduleA.js").__set__).to.be(undefined); // if restoring the original node require didn't worked, the module would have a setter
-
});
it("subsequent calls of rewire should always return a new instance", function () {
expect(rewire("./moduleA.js")).not.to.be(rewire("./moduleA.js"));
diff --git a/test/testModules/someOtherModule.js b/test/testModules/someOtherModule.js
index bb86cd3..203fb06 100644
--- a/test/testModules/someOtherModule.js
+++ b/test/testModules/someOtherModule.js
@@ -1,7 +1,5 @@
-"use strict"; // run code in ES5 strict mode
-
-__filename = "/test/testModules/someOtherModule.js"; // unifying filename for the pretty stack trace test
-
-var fs = require("fs");
-
-exports.fs = fs; \ No newline at end of file
+"use strict"; // run code in ES5 strict mode
+
+__filename = "/test/testModules/someOtherModule.js"; // unifying filename for the pretty stack trace test
+
+exports.fs = {}; \ No newline at end of file
diff --git a/webpack.js b/webpack.js
new file mode 100644
index 0000000..b26e639
--- /dev/null
+++ b/webpack.js
@@ -0,0 +1 @@
+"use strict"; // run code in ES5 strict mode