From 6040974a2f0bc91b3aed0a389584c967831dd1dd Mon Sep 17 00:00:00 2001 From: Johannes Ewald Date: Sat, 23 Feb 2013 14:52:22 +0100 Subject: - added Coffee-Script support closes #8 (jashkenas/coffee-script#2707) - renamed internalRewire.js to simply rewire.js - moved all the stuff related to manipulating the module environment to moduleEnv.js --- lib/index.js | 2 +- lib/internalRewire.js | 88 --------------------------------------------------- lib/moduleEnv.js | 82 +++++++++++++++++++++++++++++++++++++++++++++++ lib/rewire.js | 56 ++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 89 deletions(-) delete mode 100644 lib/internalRewire.js create mode 100644 lib/moduleEnv.js create mode 100644 lib/rewire.js (limited to 'lib') diff --git a/lib/index.js b/lib/index.js index 14f308b..6858598 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,4 @@ -var rewireModule = require("./internalRewire.js"); +var rewireModule = require("./rewire.js"); /** * Adds a special setter and getter to the module located at filename. After the module has been rewired, you can diff --git a/lib/internalRewire.js b/lib/internalRewire.js deleted file mode 100644 index 1500e5d..0000000 --- a/lib/internalRewire.js +++ /dev/null @@ -1,88 +0,0 @@ -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 diff --git a/lib/moduleEnv.js b/lib/moduleEnv.js new file mode 100644 index 0000000..d17918b --- /dev/null +++ b/lib/moduleEnv.js @@ -0,0 +1,82 @@ +"use strict"; + +var Module = require("module"), + fs = require("fs"); + + // caching original wrapper +var moduleWrapper0 = Module.wrapper[0], + moduleWrapper1 = Module.wrapper[1], + originalExtensions = {}, + nodeRequire, + currentModule; + +function load(targetModule) { + nodeRequire = targetModule.require; + targetModule.require = requireProxy; + currentModule = targetModule; + + registerExtensions(); + targetModule.load(targetModule.id); + + // This is only necessary if nothing has been required within the module + reset(); +} + +function reset() { + Module.wrapper[0] = moduleWrapper0; + Module.wrapper[1] = moduleWrapper1; + restoreExtensions(); +} + +function inject(prelude, appendix) { + Module.wrapper[0] = moduleWrapper0 + prelude; + Module.wrapper[1] = appendix + moduleWrapper1; +} + +/** + * 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) { + reset(); + currentModule.require = nodeRequire; + return nodeRequire.call(currentModule, path); // node's require only works when "this" points to the module +} + +function registerExtensions() { + originalExtensions.coffee = require.extensions[".coffee"]; + require.extensions[".coffee"] = coffeeExtension; +} + +function restoreExtensions() { + require.extensions[".coffee"] = originalExtensions.coffee; +} + +function coffeeExtension(module, filename) { + var coffee = require("coffee-script"), + content = stripBOM(fs.readFileSync(filename, "utf8")); + + content = coffee.compile(content, { + filename: filename, + bare: true + }); + module._compile(content, filename); +} + +/** + * @see https://github.com/joyent/node/blob/master/lib/module.js + */ +function stripBOM(content) { + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + // because the buffer-to-string conversion in `fs.readFileSync()` + // translates it to FEFF, the UTF-16 BOM. + if (content.charCodeAt(0) === 0xFEFF) { + content = content.slice(1); + } + return content; +} + +exports.load = load; +exports.inject = inject; \ No newline at end of file diff --git a/lib/rewire.js b/lib/rewire.js new file mode 100644 index 0000000..3556533 --- /dev/null +++ b/lib/rewire.js @@ -0,0 +1,56 @@ +var Module = require("module"), + fs = require("fs"), + __get__ = require("./__get__.js"), + __set__ = require("./__set__.js"), + getImportGlobalsSrc = require("./getImportGlobalsSrc.js"), + detectStrictMode = require("./detectStrictMode.js"), + moduleEnv = require("./moduleEnv.js"); + +/** + * Does actual rewiring the module. For further documentation @see index.js + */ +function internalRewire(parentModulePath, targetPath) { + var targetModule, + prelude, + appendix, + src; + + // 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 + // TODO Remove this switch on the next major release + if (Array.isArray(targetPath)) { + targetPath = targetPath[1]; + } + + // Create testModule as it would be created by require() + targetModule = new Module(targetPath, parentModulePath); + + // We prepend a list of all globals declared with var so they can be overridden (without changing original globals) + prelude = getImportGlobalsSrc(); + + // We append our special setter and getter. + appendix = "module.exports.__set__ = " + __set__.toString() + "; "; + appendix += "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) { + prelude = ' "use strict"; ' + prelude; + } + + moduleEnv.inject(prelude, appendix); + moduleEnv.load(targetModule); + + return targetModule.exports; +} + +module.exports = internalRewire; \ No newline at end of file -- cgit v1.2.3