Comparing version 1.4.0 to 1.4.1
44
index.js
@@ -108,9 +108,12 @@ /** | ||
* @param {String} [id] - identifier for removing this listener | ||
* @param {Boolean} [once] - whether this listener will run only once or always | ||
*/ | ||
reservedFunctions.on = function(dataNode, objects, event, path, listener, id) { | ||
reservedFunctions.on = function(dataNode, objects, event, path, listener, id, once=false) { | ||
if(acceptableEvents.includes(event)) { | ||
if(arguments.length < 6 && typeof path !== 'string') { //if called without path | ||
if(typeof path === 'function') { //if called without path | ||
id = listener; | ||
listener = path; | ||
path = ''; | ||
} else if(typeof listener !== 'function') { | ||
throw new Error(`invalid arguments were given. listener must be a function`); | ||
} | ||
@@ -131,3 +134,3 @@ | ||
} | ||
dataNode[ND].listeners.push([event, listener, id]); | ||
dataNode[ND].listeners.push([event, listener, id, once]); | ||
} | ||
@@ -140,2 +143,15 @@ else { | ||
/** | ||
* add event listener on a proxy or on a descending path which will run only once | ||
* @param {Object} dataNode | ||
* @param {Object} objects | ||
* @param {String} event | ||
* @param {String} [path] - path selector | ||
* @param {Function} listener | ||
* @param {String} [id] - identifier for removing this listener | ||
*/ | ||
reservedFunctions.once = function(dataNode, objects, event, path, listener, id) { | ||
reservedFunctions.on.call(this, dataNode, objects, event, path, listener, id, true); | ||
} | ||
/** | ||
* removes a listener from a path by an identifier (can have multiple listeners with the same ID) | ||
@@ -386,5 +402,12 @@ * or by the listener function itself | ||
for(let change of eventPool) { //FIFO - first event in, first event out | ||
for(let listener of listeners) { //listener = [event, function, id] | ||
if(listener[0] === change.type) { //will invoke create/update/delete listeners one by one. | ||
//FIFO - first event in, first event out. listeners will be called by their turn according to which event fires first | ||
for(let change of eventPool) { | ||
for(let i = listeners.length-1; i >= 0; i--) { | ||
let listener = listeners[i]; //listener = [event, function, id, once] | ||
if(listener[0] === change.type) { //will invoke only create/update/delete listeners | ||
if(listener[3] === true) { //first delete the one-time listener, so the upcoming listener's-function won't meddle with it | ||
listeners.splice(i, 1); | ||
} | ||
listener[1].call(dataNode[ND].objects.proxy, change); | ||
@@ -395,4 +418,11 @@ } | ||
for(let listener of listeners) { | ||
//iterate over all 'change' listeners and emit with an (ordered) array of all events | ||
for(let i = listeners.length-1; i >= 0; i--) { | ||
let listener = listeners[i]; //listener = [event, function, id, once] | ||
if(listener[0] === acceptableEvents[0]) { // 'change' | ||
if(listener[3] === true) { //first delete the one-time listener, so the upcoming listener's-function won't meddle with it | ||
listeners.splice(i, 1); | ||
} | ||
listener[1].call(dataNode[ND].objects.proxy, eventPool); //on(change) is always called with an array of one or more changes | ||
@@ -399,0 +429,0 @@ } |
{ | ||
"name": "proxserve", | ||
"version": "1.4.0", | ||
"version": "1.4.1", | ||
"description": "Proxy Observe on objects and properties changes", | ||
@@ -14,3 +14,3 @@ "license": "Apache 2.0", | ||
"jest": "^25.1.0", | ||
"lodash": "^4.17.15" | ||
"lodash": "^4.17.19" | ||
}, | ||
@@ -17,0 +17,0 @@ "engines": { |
@@ -545,2 +545,125 @@ /** | ||
} | ||
}); | ||
test('9. Events for future sub objects and primitives not yet created', (done) => { | ||
let proxy = new Proxserve({}); | ||
proxy.on('change', function(changes) { | ||
expect(changes[0].path).toBe('.arr'); | ||
part2(); | ||
}, 123); | ||
proxy.arr = []; | ||
function part2() { | ||
proxy.removeListener(123); | ||
proxy.arr.on('change', function(changes) { | ||
expect(changes.length).toBe(2); | ||
expect(changes[0].path).toBe('[2]'); | ||
expect(changes[0].value).toEqual({ a: { b: 'cc' } }); //looking at a reference. [2].a.b was 'b' and then 'cc' | ||
expect(changes[0].type).toBe('create'); | ||
expect(changes[1].path).toBe('[2].a.b'); | ||
expect(changes[1].value).toBe('cc'); | ||
expect(changes[1].type).toBe('update'); | ||
proxy.arr.removeListener('zxc'); | ||
this[2].a = { b: 'ddd' }; //will trigger the next listener again | ||
}, 'zxc'); | ||
proxy.arr.on('change', '[2].a.b', function(changes) { | ||
if(changes.length === 2) { | ||
expect(changes[0].path).toBe(''); | ||
expect(changes[0].value).toBe('b'); | ||
expect(changes[0].type).toBe('create'); | ||
expect(changes[1].path).toBe(''); | ||
expect(changes[1].value).toBe('cc'); | ||
expect(changes[1].type).toBe('update'); | ||
} | ||
else if(changes.length === 1) { | ||
expect(changes[0].path).toBe(''); | ||
expect(changes[0].value).toBe('ddd'); | ||
expect(changes[0].type).toBe('update'); | ||
part3(); | ||
} | ||
}); | ||
proxy.arr[2] = { a: { b: 'b' } }; | ||
proxy.arr[2].a.b = 'cc'; | ||
} | ||
function part3() { | ||
proxy.on('create', '.obj.1.2.3', function(change) { //on(create) | ||
expect(change.path).toBe(''); | ||
expect(change.value).toBe(987); | ||
expect(change.type).toBe('create'); | ||
}); | ||
proxy.on('create', '.obj.1', function(change) { //on(create) | ||
expect(change.path).toBe(''); | ||
expect(change.value).toEqual({ '2': { '3': 987 } }); | ||
expect(change.type).toBe('create'); | ||
this['2'] = { '3': 654 }; | ||
}); | ||
proxy.on('update', '.obj.1.2', function(change) { //on(update) | ||
expect(change.path).toBe(''); | ||
expect(change.oldValue).toEqual({ '3': 987 }); | ||
expect(change.value).toEqual({ '3': 654 }); | ||
expect(change.type).toBe('update'); | ||
}); | ||
proxy.on('update', '.obj.1', function(change) { //on(update) | ||
expect(change.path).toBe('.2'); | ||
expect(change.oldValue).toEqual({ '3': 987 }); | ||
expect(change.value).toEqual({ '3': 654 }); | ||
expect(change.type).toBe('update'); | ||
part4(); | ||
}); | ||
proxy.obj = { '1': { '2': { '3': 987 } } }; | ||
} | ||
function part4() { | ||
proxy.removeAllListeners('.obj.1.2.3'); | ||
proxy.removeAllListeners('.obj.1.2'); | ||
proxy.removeAllListeners('.obj.1'); | ||
proxy.obj.on('update', function(change) { | ||
expect(change.path).toEqual(''); | ||
expect(change.value).toEqual([0, [0, 1, [0, 1, 2, []] ] ]); | ||
expect(change.type).toBe('update'); | ||
}); | ||
proxy.on('update', '.obj.1', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, [0, 1, 2, []] ]); | ||
}); | ||
proxy.obj.on('update', '.1[2]', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, 2, []]); | ||
part5(); | ||
}); | ||
proxy.obj = [0, [0, 1, [0, 1, 2, []] ] ]; | ||
} | ||
function part5() { | ||
proxy.removeAllListeners('.obj.1.2'); //should still work | ||
proxy.removeAllListeners('.obj.1'); | ||
proxy.removeAllListeners('.obj'); | ||
proxy.obj.on('update', function(change) { | ||
expect(change.path).toEqual(''); | ||
expect(change.oldValue).toEqual([0, [0, 1, [0, 1, 2, []] ] ]); | ||
expect(change.value).toBe(true); | ||
this.removeListener(-20); | ||
proxy.obj = { '1': [0, 1, ['a']] }; | ||
}, -20); | ||
proxy.on('create', '.obj[1]', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, ['a']]); | ||
}); | ||
proxy.obj.on('create', '[1].2', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual(['a']); | ||
setImmediate(done); | ||
}); | ||
proxy.obj = true; | ||
} | ||
}); |
@@ -482,3 +482,3 @@ /** | ||
test('12. On/Remove/RemoveAll listeners', () => { | ||
test('12. on/once/removeListener/removeAllListeners', () => { | ||
let proxy = new Proxserve(cloneDeep(testObject), {delay: 0}); | ||
@@ -509,128 +509,24 @@ let counter = 0; | ||
expect(counter).toBe(6); | ||
}); | ||
test('13. Events for future sub objects and primitives not yet created', (done) => { | ||
let proxy = new Proxserve({}); | ||
proxy.on('change', function(changes) { | ||
expect(changes[0].path).toBe('.arr'); | ||
part2(); | ||
}, 123); | ||
proxy.arr = []; | ||
proxy.on('change', countFunction); | ||
proxy.new.will.exist.later++; | ||
proxy.removeAllListeners(); | ||
expect(counter).toBe(7); | ||
proxy.new.will.exist.later++; | ||
expect(counter).toBe(7); | ||
function part2() { | ||
proxy.removeListener(123); | ||
proxy.arr.on('change', function(changes) { | ||
expect(changes.length).toBe(2); | ||
expect(changes[0].path).toBe('[2]'); | ||
expect(changes[0].value).toEqual({ a: { b: 'cc' } }); //looking at a reference. [2].a.b was 'b' and then 'cc' | ||
expect(changes[0].type).toBe('create'); | ||
expect(changes[1].path).toBe('[2].a.b'); | ||
expect(changes[1].value).toBe('cc'); | ||
expect(changes[1].type).toBe('update'); | ||
proxy.once('change', countFunction); | ||
proxy.new.will.exist.later++; | ||
expect(counter).toBe(8); | ||
proxy.new.will.exist.later++; | ||
expect(counter).toBe(8); | ||
proxy.arr.removeListener('zxc'); | ||
this[2].a = { b: 'ddd' }; //will trigger the next listener again | ||
}, 'zxc'); | ||
proxy.arr.on('change', '[2].a.b', function(changes) { | ||
if(changes.length === 2) { | ||
expect(changes[0].path).toBe(''); | ||
expect(changes[0].value).toBe('b'); | ||
expect(changes[0].type).toBe('create'); | ||
expect(changes[1].path).toBe(''); | ||
expect(changes[1].value).toBe('cc'); | ||
expect(changes[1].type).toBe('update'); | ||
} | ||
else if(changes.length === 1) { | ||
expect(changes[0].path).toBe(''); | ||
expect(changes[0].value).toBe('ddd'); | ||
expect(changes[0].type).toBe('update'); | ||
part3(); | ||
} | ||
}); | ||
proxy.arr[2] = { a: { b: 'b' } }; | ||
proxy.arr[2].a.b = 'cc'; | ||
} | ||
function part3() { | ||
proxy.on('create', '.obj.1.2.3', function(change) { //on(create) | ||
expect(change.path).toBe(''); | ||
expect(change.value).toBe(987); | ||
expect(change.type).toBe('create'); | ||
}); | ||
proxy.on('create', '.obj.1', function(change) { //on(create) | ||
expect(change.path).toBe(''); | ||
expect(change.value).toEqual({ '2': { '3': 987 } }); | ||
expect(change.type).toBe('create'); | ||
this['2'] = { '3': 654 }; | ||
}); | ||
proxy.on('update', '.obj.1.2', function(change) { //on(update) | ||
expect(change.path).toBe(''); | ||
expect(change.oldValue).toEqual({ '3': 987 }); | ||
expect(change.value).toEqual({ '3': 654 }); | ||
expect(change.type).toBe('update'); | ||
}); | ||
proxy.on('update', '.obj.1', function(change) { //on(update) | ||
expect(change.path).toBe('.2'); | ||
expect(change.oldValue).toEqual({ '3': 987 }); | ||
expect(change.value).toEqual({ '3': 654 }); | ||
expect(change.type).toBe('update'); | ||
part4(); | ||
}); | ||
proxy.obj = { '1': { '2': { '3': 987 } } }; | ||
} | ||
function part4() { | ||
proxy.removeAllListeners('.obj.1.2.3'); | ||
proxy.removeAllListeners('.obj.1.2'); | ||
proxy.removeAllListeners('.obj.1'); | ||
proxy.obj.on('update', function(change) { | ||
expect(change.path).toEqual(''); | ||
expect(change.value).toEqual([0, [0, 1, [0, 1, 2, []] ] ]); | ||
expect(change.type).toBe('update'); | ||
}); | ||
proxy.on('update', '.obj.1', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, [0, 1, 2, []] ]); | ||
}); | ||
proxy.obj.on('update', '.1[2]', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, 2, []]); | ||
part5(); | ||
}); | ||
proxy.obj = [0, [0, 1, [0, 1, 2, []] ] ]; | ||
} | ||
function part5() { | ||
proxy.removeAllListeners('.obj.1.2'); //should still work | ||
proxy.removeAllListeners('.obj.1'); | ||
proxy.removeAllListeners('.obj'); | ||
proxy.obj.on('update', function(change) { | ||
expect(change.path).toEqual(''); | ||
expect(change.oldValue).toEqual([0, [0, 1, [0, 1, 2, []] ] ]); | ||
expect(change.value).toBe(true); | ||
this.removeListener(-20); | ||
proxy.obj = { '1': [0, 1, ['a']] }; | ||
}, -20); | ||
proxy.on('create', '.obj[1]', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual([0, 1, ['a']]); | ||
}); | ||
proxy.obj.on('create', '[1].2', function(change) { //path-selector can be with either dots or squared parenthesis | ||
expect(change.path).toBe(''); //change path does match actual path | ||
expect(change.value).toEqual(['a']); | ||
setImmediate(done); | ||
}); | ||
proxy.obj = true; | ||
} | ||
proxy.once('update', '.new.will', countFunction); | ||
proxy.new.will.exist.later++; | ||
expect(counter).toBe(9); | ||
proxy.new.will.exist.later++; | ||
expect(counter).toBe(9); | ||
}); | ||
test('14. Listen for delete event of sub-properties when parent is deleted', (done) => { | ||
test('13. Listen for delete event of sub-properties when parent is deleted', (done) => { | ||
let proxy = new Proxserve({}); | ||
@@ -637,0 +533,0 @@ let step = 1; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
84444
1878