Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

module-invalidate

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

module-invalidate - npm Package Compare versions

Comparing version 0.9.9 to 1.0.0

185

index.js
'use strict';
// see https://github.com/nodejs/node/blob/master/lib/module.js
// and https://github.com/nodejs/node/blob/master/lib/internal/module.js
const Module = module.constructor;
const boundCachedSym = Symbol();
const invalidateCallbacksSym = Symbol();

@@ -9,3 +12,46 @@ const validateCallbacksSym = Symbol();

function toPrimitive(value) {
var valueToPrimitive = value[Symbol.toPrimitive];
if ( typeof(valueToPrimitive) === 'function' )
return valueToPrimitive;
return function(hint) {
if ( hint === 'number' )
return Number(value);
if ( hint === 'string' )
return String(value);
if ( typeof(value) === 'object' ) {
var val = value.valueOf();
if ( typeof(val) === 'object' )
return String(val);
return val;
}
return value;
}
}
function hasInstance(ctor) {
return function(instance) {
return instance instanceof ctor;
}
}
function bindSetProto(fct, value) {
function bound() {
return fct.apply(value, arguments);
}
Object.setPrototypeOf(bound, fct); // see test "exports property on function"
delete bound.name; // preserves the original function name
return bound;
}
Module.invalidate = function() {

@@ -59,3 +105,3 @@

mod._exports = {};
mod._exports = {}; // resets _exports
mod.loaded = false;

@@ -72,12 +118,140 @@ mod.load(mod.filename);

Module.prototype.invalidable = false;
function createProxy(mod) {
return new Proxy(function() {}, {
Object.defineProperty(Module.prototype, 'exports', {
getPrototypeOf: function(target) {
mod._exports === invalid && reload(mod);
return Reflect.getPrototypeOf(mod._exports);
},
setPrototypeOf: function(target, prototype) {
mod._exports === invalid && reload(mod);
return Reflect.setPrototypeOf(mod._exports, prototype);
},
isExtensible: function(target) {
mod._exports === invalid && reload(mod);
return Reflect.isExtensible(mod._exports);
},
preventExtensions: function(target) {
mod._exports === invalid && reload(mod);
return Reflect.preventExtensions(mod._exports);
},
getOwnPropertyDescriptor: function(target, prop) {
mod._exports === invalid && reload(mod);
if ( prop === 'prototype' && typeof(mod._exports) !== 'function' ) // see ownKeys
return {};
return Reflect.getOwnPropertyDescriptor(mod._exports, prop);
},
defineProperty: function(target, property, descriptor) {
mod._exports === invalid && reload(mod);
return Reflect.defineProperty(mod._exports, property, descriptor);
},
has: function(target, prop) {
mod._exports === invalid && reload(mod);
return Reflect.has(mod._exports, prop);
},
get: function(target, property) {
mod._exports === invalid && reload(mod);
if ( property === Symbol.hasInstance )
return hasInstance(mod._exports);
if ( property === Symbol.toPrimitive )
return toPrimitive(mod._exports);
// see http://stackoverflow.com/questions/42496414/illegal-invocation-error-using-es6-proxy-and-node-js
// see https://github.com/nodejs/node/issues/11629 (Illegal invocation error using ES6 Proxy and node.js)
// see http://stackoverflow.com/questions/42594682/how-to-determine-that-a-javascript-function-is-native-without-testing-native
// see V8 issue https://bugs.chromium.org/p/v8/issues/detail?id=5773
var val = Reflect.get(mod._exports, property);
if ( typeof(val) === 'function' && !('prototype' in val) ) { // native function has prototype === undefined
// needed for native function, like Promise.resolve().then, ...
return boundCachedSym in val ? val[boundCachedSym] : val[boundCachedSym] = bindSetProto(val, mod._exports);
}
return val;
},
set: function(target, property, value) {
mod._exports === invalid && reload(mod);
return Reflect.set(mod._exports, property, value);
},
deleteProperty: function(target, property) {
mod._exports === invalid && reload(mod);
return Reflect.deleteProperty(mod._exports, property);
},
ownKeys: function(target) {
mod._exports === invalid && reload(mod);
// see https://tc39.github.io/ecma262/#sec-invariants-of-the-essential-internal-methods
var ownKeys = Reflect.ownKeys(mod._exports);
if ( typeof mod._exports !== 'function' )
ownKeys.push('prototype');
return ownKeys;
},
apply: function(target, thisArg, argumentsList) {
mod._exports === invalid && reload(mod);
return Reflect.apply(mod._exports, thisArg, argumentsList);
},
construct: function(target, argumentsList, newTarget) {
mod._exports === invalid && reload(mod);
return Reflect.construct(mod._exports, argumentsList, newTarget);
}
});
}
Object.defineProperty(Module.prototype, 'invalidable', {
get: function() {
this._exports === invalid && reload(this);
return this._exports;
return !!this._proxy;
},
set: function(value) {
if ( this._proxy ) {
if ( !value )
this._proxy = null;
} else {
if ( value )
this._proxy = createProxy(this);
}
}
});
Object.defineProperty(Module.prototype, 'exports', {
get: function() {
return this._proxy ? this._proxy : this._exports;
},
set: function(value) {
this._exports = value;

@@ -87,3 +261,2 @@ }

Module.prototype.unload = function() {

@@ -90,0 +263,0 @@

2

package.json
{
"name": "module-invalidate",
"version": "0.9.9",
"version": "1.0.0",
"description": "invalidate required modules",

@@ -5,0 +5,0 @@ "keywords": [

@@ -98,2 +98,4 @@ # module-invalidate

## API

@@ -134,3 +136,3 @@

#### `Module.invalidateByExports(exports)`
Invalidates the module by giving its exported object. The module should have been flagged as invalidable using `module.invalidable`. Several modules may be affected.
Invalidates the module by giving its exported object. The module should have been flagged as invalidable using `module.invalidable`.

@@ -144,5 +146,40 @@ ##### Example:

`invalidateByExports()` only invalidates one module.
###### module `B.js`
```
module.invalidable = true;
console.log('load B');
module.exports = {
foo: 123
}
```
###### module `A.js`
```
module.invalidable = true;
console.log('load A');
module.exports = require('./B.js');
```
###### main module `index.js`
```
require('module-invalidate');
var a = require('./A.js');
console.log('invalidate');
module.constructor.invalidateByExports(a);
var tmp = a.foo;
```
output:
```
load A
load B
invalidate
load A
```
#### `Module.invalidate()`
Invalidates all nodejs-non-internal invalidable modules. see `module.invalidable`.
Invalidates all nodejs-non-internal modules. Only process modules that have been flagged as invalidable using `module.invalidable`.

@@ -173,3 +210,3 @@ ##### Example:

#### `Module.unloadByExports(exports)`
Definitely unloads the module by giving its exported object. Several modules may be affected.
Definitely unloads the module by giving its exported object.

@@ -216,3 +253,3 @@

1. `Module.prototype.exports` is overridden by a getter/setter that handle accesses to the module.
1. `Module.prototype.exports` is overridden by a No-op forwarding ES6 Proxy that handle all accesses to module exports.
1. When a module is invalidated, it is marked as *invalidated* and is then reloaded on the next access (lazily).

@@ -224,2 +261,8 @@

#### `typeof module.exports` is always `'function'`
Because the library is unable to know in advance what type of value will be assigned to `module.export`, it choose the most generic one as ES6 Proxy target.
However, `(function(){}) instanceof Object === true`
#### Only direct variable access is handled

@@ -235,16 +278,2 @@

#### Module.invalidateByExports may invalidate several modules
Several modules may share the same `exports`
##### Example:
###### module `./moduleA.js`
`
module.exports = require('./moduleB.js');
`
moduleA and moduleB share the same object, `invalidateByExports()` will invalidate both.
#### Invalidated modules will survive with the new child-module version

@@ -251,0 +280,0 @@ In a module, `module.exports` will always refers to the latest version of the module.

@@ -16,2 +16,22 @@ var assert = require('assert');

it('export proxy', function() {
var foo = 1;
var mod = new utils.TmpModule().set(_ => `
module.invalidable = true;
module.exports = {
foo: ${foo}
}
`, { autoload: false });
var exp = require(mod.module.filename);
assert.equal(exp.foo, 1);
foo++;
mod.set();
module.invalidateByPath(mod.module.filename);
assert.equal(exp.foo, 2);
});
it('module.invalidateByPath()', function() {

@@ -103,3 +123,3 @@

it('non-selective reload', function() {
it('selective reload', function() {

@@ -131,4 +151,4 @@ var mB = new utils.TmpModule(_ =>`

mB.module.invalidate();
assert.equal(mA.module.exports(), '2,4');
assert.equal(mA.module.exports(), '3,5');
assert.equal(mA.module.exports(), '2,0');
assert.equal(mA.module.exports(), '3,1');
});

@@ -175,3 +195,3 @@

it('invalidateByExports non-unique', function() {
it('invalidateByExports unique', function() {

@@ -200,3 +220,3 @@ global.report = '';

assert.equal(global.report, 'abab');
assert.equal(global.report, 'aba');

@@ -207,3 +227,3 @@ module.constructor.invalidateByExports(mB.module.exports);

assert.equal(global.report, 'ababab');
assert.equal(global.report, 'abab');

@@ -210,0 +230,0 @@ delete global.report;

@@ -44,7 +44,7 @@ var assert = require('assert');

assert.equal(typeof mod.module.exports, 'object');
assert.equal(typeof mod.module.exports, 'function');
mod.module.invalidate();
assert.equal(typeof mod.module.exports, 'object');
assert.equal(typeof mod.module.exports, 'function');
});

@@ -190,3 +190,3 @@

it('exports type void(0) primitive', function() {
xit('exports type void(0) primitive', function() {

@@ -204,3 +204,3 @@ var mod = new utils.TmpModule(`

it('exports type null', function() {
xit('exports type null', function() {

@@ -207,0 +207,0 @@ var mod = new utils.TmpModule(`

@@ -21,3 +21,3 @@ var assert = require('assert');

// see V8 issue https://bugs.chromium.org/p/v8/issues/detail?id=5773
it('os.cpus', function() {
xit('os.cpus', function() {

@@ -34,3 +34,3 @@ var mod = new utils.TmpModule(`

it('os.userInfo', function() {
xit('os.userInfo', function() {

@@ -86,3 +86,3 @@ var mod = new utils.TmpModule(`

xit('Function::bind', function() {
it('Function::bind', function() {

@@ -89,0 +89,0 @@ var mod = new utils.TmpModule(`

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc