Comparing version 0.0.2 to 0.1.0
75
index.js
@@ -5,2 +5,4 @@ // cache the real JS module loader | ||
, registeredOverrides = {} | ||
, declaredOverrides = {} | ||
, cachedModules = {} | ||
, overrides = {} | ||
@@ -11,14 +13,16 @@ ; | ||
/** | ||
* Searches for available overriden modules in the caller context | ||
* @param {Module} mod Module being loaded | ||
* Searches for available overriden modules in the caller context. | ||
* | ||
* @param {Object} modContent Module being loaded | ||
* @param {String} modPath module path | ||
*/ | ||
function applyOverrides(mod, modPath) { | ||
function applyOverrides(modContent, modPath) { | ||
// save original current module path | ||
var originalPaths = module.paths; | ||
module.paths = mod.parent.paths; | ||
module.paths = modContent.parent.paths; | ||
// go over exports and register all declared overrides | ||
Object.keys(module.exports).forEach(function (moduleName) { | ||
Object.keys(declaredOverrides).forEach(function (moduleName) { | ||
if (!registeredOverrides[moduleName]) { | ||
registeredOverrides[moduleName] = module.exports[moduleName]; | ||
registeredOverrides[moduleName] = declaredOverrides[moduleName]; | ||
} | ||
@@ -32,6 +36,7 @@ }); | ||
overrides[modulePath] = registeredOverrides[moduleName]; | ||
cachedModules[moduleName] = modulePath; | ||
} catch (e) { | ||
// maybe it's a relative-path module? let's try | ||
try { | ||
var relativeModuleName = mod.paths[0].split('/'); | ||
var relativeModuleName = modContent.paths[0].split('/'); | ||
relativeModuleName = relativeModuleName[relativeModuleName.length-2]; | ||
@@ -42,2 +47,3 @@ | ||
overrides[modPath] = registeredOverrides[moduleName]; | ||
cachedModules[moduleName] = modPath; | ||
} | ||
@@ -55,10 +61,53 @@ } catch (e) { | ||
require.extensions['.js'] = function (mod, modPath) { | ||
applyOverrides(mod, modPath); | ||
if (!overrides[modPath]) return jsLoader(mod, modPath); | ||
mod.exports = overrides[modPath]; | ||
}; | ||
require.extensions['.js'] = load; | ||
/** | ||
* Returns stubbed content or a real module. | ||
* | ||
* @param modContent | ||
* @param modPath | ||
*/ | ||
function load(modContent, modPath) { | ||
applyOverrides(modContent, modPath); | ||
if (!overrides[modPath]) return jsLoader(modContent, modPath); | ||
modContent.exports = overrides[modPath]; | ||
} | ||
module.exports = {}; | ||
/** | ||
* Attempts to replace a cached module with a stub. | ||
* | ||
* @param {String} name | ||
* @param {Object} content | ||
*/ | ||
function stubCache(name, content) { | ||
if (cachedModules[name]) require.cache[cachedModules[name]] = content; | ||
else { | ||
try { | ||
var realPaths = module.paths; | ||
module.paths = module.parent.paths; | ||
var resolvedPath = require.resolve(name); | ||
require.cache[resolvedPath].exports = content; | ||
module.paths = realPaths; | ||
} catch(e) { | ||
console.log('Module', name, 'appears to be not cached.'); | ||
} | ||
} | ||
} | ||
/** | ||
* Adds module name to declared overrides | ||
* and attempts to replace a cached module. | ||
* @param name | ||
* @param content | ||
*/ | ||
function stub(name, content) { | ||
declaredOverrides[name] = content; | ||
stubCache(name, content); | ||
} | ||
module.exports = stub; |
@@ -18,4 +18,4 @@ { "name": "embargo" | ||
} | ||
, "version": "0.0.2" | ||
, "version": "0.1.0" | ||
, "main": "index.js" | ||
} |
@@ -0,1 +1,8 @@ | ||
#### Breaking interface change in v0.1.0 | ||
In v0.1.0 `embargo` supports overriding cached modules, e.g. a module already `require()`d can be stubbed. | ||
This prompted interface change from using subscript notation to a function call (`[]` -> `()`). | ||
________ | ||
# Embargo | ||
@@ -15,7 +22,7 @@ | ||
embargo.someModule = { | ||
embargo(someModule, { | ||
'doStuff': function(arg, cb) { | ||
cb(null, 'it worked!'); | ||
} | ||
} | ||
}) | ||
@@ -28,2 +35,4 @@ var someModule = require('someModule'); | ||
Signature of `embargo` function is (`module_name_string`, `stub`). | ||
By doing this, you're saying that `require('someModule')` will return an object with a `doStuff` property that you specified in `overrides` object, instead of actual module exports. | ||
@@ -30,0 +39,0 @@ This override will propagate to all `require` calls in the current VM. It should also work for modules `require`d through relative path. |
var embargo = require('../'); | ||
// override value is what fake module .exports | ||
embargo['node_mod'] = { | ||
embargo('node_mod', { | ||
'getValue': function () { | ||
return 'Fake node_mod'; | ||
} | ||
}; | ||
}); | ||
embargo['relative_mod'] = { | ||
embargo('relative_mod', { | ||
'getValue': function () { | ||
return 'Fake relative_mod'; | ||
} | ||
}; | ||
}); | ||
@@ -44,2 +44,24 @@ var mod1 = require('./lib/mod1/mod1') | ||
}) | ||
}); | ||
describe('Exports of cached mod', function () { | ||
var cached_mod = require('cached_mod'); | ||
it('return real content', function () { | ||
assert(/real cached/i.test(cached_mod.getValue())); | ||
}); | ||
it('returns stubbed content', function () { | ||
embargo('cached_mod', { | ||
'getValue': function () { | ||
return 'fake cached_mod'; | ||
} | ||
}); | ||
var cached_mod = require('cached_mod'); | ||
assert(/fake cached/i.test(cached_mod.getValue())); | ||
}); | ||
}); |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
8122
18
161
50
0
2
1