mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Prevent RED.node.registerNode from overriding a constructor's prototype (#865)
* prevent registry.registerNodeConstructor from overriding a constructors protoype * fix for node < v5.0.0 * exercise another code path * altering __proto__ for node < v0.12 * move inheritance code to helper function
This commit is contained in:
parent
e1d09349ff
commit
b909e32201
@ -8,6 +8,7 @@
|
|||||||
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
||||||
//"unused": true, // Check for unused functions and variables
|
//"unused": true, // Check for unused functions and variables
|
||||||
"loopfunc": true, // allow functions to be defined in loops
|
"loopfunc": true, // allow functions to be defined in loops
|
||||||
//"expr": true, // allow ternery operator syntax...
|
//"expr": true, // allow ternery operator syntax...
|
||||||
"sub": true // don't warn that foo['bar'] should be written as foo.bar
|
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||||
|
"proto": true // allow setting of __proto__ in node < v0.12
|
||||||
}
|
}
|
||||||
|
@ -326,6 +326,27 @@ function getCaller(){
|
|||||||
return stack[0].getFileName();
|
return stack[0].getFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inheritNode(constructor) {
|
||||||
|
if(Object.getPrototypeOf(constructor.prototype) === Object.prototype) {
|
||||||
|
util.inherits(constructor,Node);
|
||||||
|
} else {
|
||||||
|
var proto = constructor.prototype;
|
||||||
|
while(Object.getPrototypeOf(proto) !== Object.prototype) {
|
||||||
|
proto = Object.getPrototypeOf(proto);
|
||||||
|
}
|
||||||
|
//TODO: This is a partial implementation of util.inherits >= node v5.0.0
|
||||||
|
// which should be changed when support for node < v5.0.0 is dropped
|
||||||
|
// see: https://github.com/nodejs/node/pull/3455
|
||||||
|
proto.constructor.super_ = Node;
|
||||||
|
if(Object.setPrototypeOf) {
|
||||||
|
Object.setPrototypeOf(proto, Node.prototype);
|
||||||
|
} else {
|
||||||
|
// hack for node v0.10
|
||||||
|
proto.__proto__ = Node.prototype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function registerNodeConstructor(type,constructor) {
|
function registerNodeConstructor(type,constructor) {
|
||||||
if (nodeConstructors[type]) {
|
if (nodeConstructors[type]) {
|
||||||
throw new Error(type+" already registered");
|
throw new Error(type+" already registered");
|
||||||
@ -333,7 +354,10 @@ function registerNodeConstructor(type,constructor) {
|
|||||||
//TODO: Ensure type is known - but doing so will break some tests
|
//TODO: Ensure type is known - but doing so will break some tests
|
||||||
// that don't have a way to register a node template ahead
|
// that don't have a way to register a node template ahead
|
||||||
// of registering the constructor
|
// of registering the constructor
|
||||||
util.inherits(constructor,Node);
|
if(!(constructor.prototype instanceof Node)) {
|
||||||
|
inheritNode(constructor);
|
||||||
|
}
|
||||||
|
|
||||||
nodeConstructors[type] = constructor;
|
nodeConstructors[type] = constructor;
|
||||||
events.emit("type-registered",type);
|
events.emit("type-registered",type);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,12 @@ var sinon = require("sinon");
|
|||||||
|
|
||||||
var typeRegistry = require("../../../../../red/runtime/nodes/registry/registry");
|
var typeRegistry = require("../../../../../red/runtime/nodes/registry/registry");
|
||||||
|
|
||||||
|
var Node = require("../../../../../red/runtime/nodes/Node");
|
||||||
|
|
||||||
var events = require("../../../../../red/runtime/events");
|
var events = require("../../../../../red/runtime/events");
|
||||||
|
|
||||||
|
var inherits = require("util").inherits;
|
||||||
|
|
||||||
describe("red/nodes/registry/registry",function() {
|
describe("red/nodes/registry/registry",function() {
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
@ -428,9 +432,10 @@ describe("red/nodes/registry/registry",function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#registerNodeConstructor', function() {
|
describe('#registerNodeConstructor', function() {
|
||||||
function TestNodeConstructor() {
|
var TestNodeConstructor;
|
||||||
}
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
TestNodeConstructor = function TestNodeConstructor() {
|
||||||
|
};
|
||||||
sinon.stub(events,'emit');
|
sinon.stub(events,'emit');
|
||||||
});
|
});
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
@ -452,7 +457,27 @@ describe("red/nodes/registry/registry",function() {
|
|||||||
typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor);
|
typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor);
|
||||||
}).should.throw("node-type already registered");
|
}).should.throw("node-type already registered");
|
||||||
events.emit.calledOnce.should.be.true;
|
events.emit.calledOnce.should.be.true;
|
||||||
})
|
});
|
||||||
|
it('extends a constructor with the Node constructor', function() {
|
||||||
|
TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node);
|
||||||
|
typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor);
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
|
||||||
|
});
|
||||||
|
it('does not override a constructor\'s prototype', function() {
|
||||||
|
function Foo(){};
|
||||||
|
inherits(TestNodeConstructor,Foo);
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
|
||||||
|
TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node);
|
||||||
|
|
||||||
|
typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor);
|
||||||
|
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
|
||||||
|
|
||||||
|
typeRegistry.registerNodeConstructor('node-type2',TestNodeConstructor);
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
|
||||||
|
TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user