Permalink
Browse files

Prevent RED.node.registerNode from overriding a constructor's prototy…

…pe (#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
  • Loading branch information...
1 parent e1d0934 commit b909e32201c5cc0394e43cdabbcc3d54b07bdb19 @gabejohnson gabejohnson committed with knolleary Apr 7, 2016
Showing with 56 additions and 6 deletions.
  1. +3 −2 .jshintrc
  2. +25 −1 red/runtime/nodes/registry/registry.js
  3. +28 −3 test/red/runtime/nodes/registry/registry_spec.js
View
@@ -8,6 +8,7 @@
//"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
"loopfunc": true, // allow functions to be defined in loops
- //"expr": true, // allow ternery operator syntax...
- "sub": true // don't warn that foo['bar'] should be written as foo.bar
+ //"expr": true, // allow ternery operator syntax...
+ "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,14 +326,38 @@ function getCaller(){
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) {
if (nodeConstructors[type]) {
throw new Error(type+" already registered");
}
//TODO: Ensure type is known - but doing so will break some tests
// that don't have a way to register a node template ahead
// of registering the constructor
- util.inherits(constructor,Node);
+ if(!(constructor.prototype instanceof Node)) {
+ inheritNode(constructor);
+ }
+
nodeConstructors[type] = constructor;
events.emit("type-registered",type);
}
@@ -20,8 +20,12 @@ var sinon = require("sinon");
var typeRegistry = require("../../../../../red/runtime/nodes/registry/registry");
+var Node = require("../../../../../red/runtime/nodes/Node");
+
var events = require("../../../../../red/runtime/events");
+var inherits = require("util").inherits;
+
describe("red/nodes/registry/registry",function() {
afterEach(function() {
@@ -428,9 +432,10 @@ describe("red/nodes/registry/registry",function() {
});
describe('#registerNodeConstructor', function() {
- function TestNodeConstructor() {
- }
+ var TestNodeConstructor;
beforeEach(function() {
+ TestNodeConstructor = function TestNodeConstructor() {
+ };
sinon.stub(events,'emit');
});
afterEach(function() {
@@ -452,7 +457,27 @@ describe("red/nodes/registry/registry",function() {
typeRegistry.registerNodeConstructor('node-type',TestNodeConstructor);
}).should.throw("node-type already registered");
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);
+ });
});
});

0 comments on commit b909e32

Please sign in to comment.