🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

primitive

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

primitive - npm Package Compare versions

Comparing version

to
0.2.0

274

lib/delta.js
var walk = require('./walk');
var flatten = require('./flatten');
var traverse = require('./traverse');
var del = require('./del');
var deepCompare = require('./deep-compare');

@@ -25,2 +27,3 @@ exports.apply = function(data, delta) {

'$inc',
'$push',
'$pull'

@@ -34,3 +37,3 @@ ].indexOf(prop) < 0) {

if(delta.$unset) {
var unset = flatten(delta.$unset);
var unset = delta.$unset;
for(var path in unset) {

@@ -43,12 +46,33 @@ del(path, data);

if(delta.$pull) {
var pull = flatten(delta.$pull);
var pull = delta.$pull;
for(var path in pull) {
var arr = traverse(path, data);
arr.splice(arr.indexOf(pull[path]), 1);
if(pull[path].$each) {
for(var i = 0; i < pull[path].$each.length; i += 1) {
arr.splice(arr.indexOf(pull[path].$each[i]), 1);
}
} else {
arr.splice(arr.indexOf(pull[path]), 1);
}
}
}
// pull.
if(delta.$push) {
var push = delta.$push;
for(var path in push) {
var arr = traverse(path, data);
if(push[path].$each) {
for(var i = 0; i < push[path].$each.length; i += 1) {
arr.push(push[path].$each[i]);
}
} else {
arr.push(push[path]);
}
}
}
// rename.
if(delta.$rename) {
var rename = flatten(delta.$rename);
var rename = delta.$rename;
for(var path in rename) {

@@ -63,3 +87,3 @@ var val = traverse(path, data);

if(delta.$setOnInsert) {
var setOnInsert = flatten(delta.$setOnInsert);
var setOnInsert = delta.$setOnInsert;
for(var path in setOnInsert) {

@@ -74,3 +98,3 @@ if(traverse(path, data) === undefined) {

if(delta.$set) {
var set = flatten(delta.$set);
var set = delta.$set;
for(var path in set) {

@@ -83,3 +107,3 @@ traverse(path, data, set[path]);

if(delta.$inc) {
var inc = flatten(delta.$inc);
var inc = delta.$inc;
for(var path in inc) {

@@ -96,3 +120,2 @@ var val = traverse(path, data) + inc[path];

exports.create = function(original, current) {
var delta = {};

@@ -107,42 +130,155 @@ // throw on non objects.

// flatten the data.
var o = flatten(original);
var c = flatten(current);
var delta = { $unset: {}, $set: {}, $push: {}, $pull: {}, $rename: {} };
var arrayPaths = [];
var handledPaths = [];
// compare the original object to the new
// one.
for(var path in o) {
var oVal = o[path];
var cVal = c[path];
// walk through the original.
walk(original, function(oVal, path) {
var cVal = traverse(path, current);
// removals.
// if the current path points to an array in
// both the original object and the current
// then look for array diffs
if(
typeof cVal == 'object' && typeof oVal == 'object' &&
cVal.constructor == Array && oVal.constructor == Array
) {
var oRArr = oVal;
var cRArr = cVal;
var oArr = oRArr.slice(0);
var cArr = cRArr.slice(0);
// loop through the original array
while(oArr.length > 0) {
oVal = oArr.shift();
// look for the oVal within the current
// array.
for(var i = 0; i < cRArr.length; i += 1) {
cVal = cRArr[i];
// if the oVal and cVal are in both
// arrays, then move on.
if(deepCompare(oVal, cVal)) { oVal = undefined; break; }
}
// if the oVal is no longer in the current
// array, then it has been removed.
if(oVal) {
if(!delta.$pull) { delta.$pull = {}; }
if(!delta.$pull[path]) { delta.$pull[path] = {}; }
if(!delta.$pull[path].$each) { delta.$pull[path].$each = []; }
delta.$pull[path].$each.push(oVal);
}
}
// loop through the current array
while(cArr.length > 0) {
cVal = cArr.shift();
// look for the cVal within the original
// array.
for(var i = 0; i < oRArr.length; i += 1) {
oVal = oRArr[i];
// if the oVal and cVal are in both
// arrays, then move on.
if(deepCompare(oVal, cVal)) { cVal = undefined; break; }
}
// if the cVal is not in the original
// array, then it has been added.
if(cVal) {
if(!delta.$push) { delta.$push = {}; }
if(!delta.$push[path]) { delta.$push[path] = {}; }
if(!delta.$push[path].$each) { delta.$push[path].$each = []; }
delta.$push[path].$each.push(cVal);
}
}
handledPaths.push(path);
}
// if both the current and the original
// value at the current path are both objects,
// or they are the same value, then do
// nothing.
if(
typeof cVal == 'object' && typeof oVal == 'object' ||
cVal === oVal
) {
return;
}
// if the path is a decendent of a handled
// path, then do nothing.
for(var i = 0; i < handledPaths.length; i += 1) {
if(path.slice(0, handledPaths[i].length) == handledPaths[i]) {
return;
}
}
// if the path is a decendent of an array
// path, then do nothing.
for(var i = 0; i < arrayPaths.length; i += 1) {
if(path.slice(0, arrayPaths[i].length) == arrayPaths[i]) {
return;
}
}
// If oVal is defined and cVal is not then
// a deletion has occured. Save the original
// value temporarity so we can track renames.
if(cVal === undefined) {
if(!delta.$unset) { delta.$unset = {}; }
delta.$unset[path] = oVal;
handledPaths.push(path);
}
// additions.
else if(cVal !== oVal) {
// if oVal does not equal cVal then note an
// addition was made.
else {
if(!delta.$set) { delta.$set = {}; }
delta.$set[path] = cVal;
handledPaths.push(path);
}
// remove the path.
delete o[path];
delete c[path];
}
});
// whatever is left in c become additions.
for(var path in c) {
if(!delta.$set) { delta.$set = {}; }
delta.$set[path] = c[path];
delete c[path];
}
// walk through the current
walk(current, function(cVal, path) {
var oVal = traverse(path, original);
// if both the current and the original
// value at the current path are both objects,
// or they are equal then do nothing.
if(typeof cVal == typeof oVal == 'object' || cVal == oVal) {
return;
}
// if the path is a decendent of a handled
// path, then do nothing.
for(var i = 0; i < handledPaths.length; i += 1) {
var handledPath = handledPaths[i];
if(path.slice(0, handledPath.length) == handledPath) {
return;
}
}
// if the oVal is undefined then an addition
// was made.
if(oVal === undefined) {
if(!delta.$set) { delta.$set = {}; }
delta.$set[path] = cVal;
handledPaths.push(path);
}
});
// look for renames.
for(var uPath in delta.$unset) {
var uVal = delta.$unset[uPath];
for(var sPath in delta.$set) {
var sVal = delta.$set[sPath];
walk(delta.$unset, function(uVal, uPath) {
if(typeof uVal == 'object') { return; }
walk(delta.$set, function(sVal, sPath) {
if(typeof sVal == 'object') { return; }
// if the values match, assume a rename.

@@ -152,51 +288,39 @@ if(uVal == sVal) {

delta.$rename[uPath] = sPath;
delete delta.$unset[uPath];
delete delta.$set[sPath];
// delete the delta.$unset and/or
// delta.$set objects if they are empty.
for(var ok in delta.$unset) { break; }
if(ok === undefined) { delete delta.$unset; }
else { ok = undefined; }
for(var ok in delta.$set) { break; }
if(ok === undefined) { delete delta.$set; }
else { ok = undefined; }
del(uPath, delta.$unset);
del(sPath, delta.$set);
}
}
}
});
});
// replace array unsets with $pull commands
if(delta.$unset) {
for(var uPath in delta.$unset) {
// replace all unset values with 1.
walk(delta.$unset, function(cVal, uPath) {
if(typeof cVal == 'object') { return; }
traverse(uPath, delta.$unset, 1);
});
// get the path chunks and check for index
// property denoting existance of an array.
var uPathChunks = uPath.split('.');
var prop = uPathChunks.pop();
if((prop|0) != prop) { continue; }
var aPath = uPathChunks.join('.');
// delete set if its empty
for(var ok in delta.$set) { break; }
if(ok === undefined) { delete delta.$set; }
else { ok = undefined; }
// convert all paths to the same array to
// pull commands.
for(var uPath in delta.$unset) {
if(uPath.slice(0, aPath.length) != aPath) { continue; }
if(!delta.$pull) { delta.$pull = {}; }
delta.$pull[aPath] = delta.$unset[uPath];
delete delta.$unset[uPath];
// delete unset if its empty
for(var ok in delta.$unset) { break; }
if(ok === undefined) { delete delta.$unset; }
else { ok = undefined; }
// delete $unset if its empty
for(var ok in delta.$unset) { break; }
if(ok === undefined) { delete delta.$unset; }
else { ok = undefined; }
}
}
}
// delete push if its empty
for(var ok in delta.$push) { break; }
if(ok === undefined) { delete delta.$push; }
else { ok = undefined; }
// set the value of unset commands to 1
if(delta.$unset) {
for(var uPath in delta.$unset) {
delta.$unset[uPath] = 1;
}
}
// delete pull if its empty
for(var ok in delta.$pull) { break; }
if(ok === undefined) { delete delta.$pull; }
else { ok = undefined; }
// delete rename if its empty
for(var ok in delta.$rename) { break; }
if(ok === undefined) { delete delta.$rename; }
else { ok = undefined; }
// if the delta is empty return undefined.

@@ -203,0 +327,0 @@ for(var ok in delta) { break; }

@@ -11,3 +11,3 @@

while(i < s.length) {
if(s[i].match(/[A-Z]/)) {
if(s[i].match(/[A-Z\d]/)) {
o += '-' + s[i].toLowerCase();

@@ -14,0 +14,0 @@ } else if(s[i].match(/[ _]/)) {

@@ -8,4 +8,4 @@

var objs = Array.prototype.slice.call(arguments, 1);
var deppMerge = objs[objs.length - 1] == true;
if(deppMerge) { objs.pop(); }
var deepMerge = objs[objs.length - 1] == true;
if(deepMerge) { objs.pop(); }
while(objs[0]) {

@@ -17,6 +17,7 @@ var obj = objs.shift();

if(
deppMerge && typeof obj[key] == 'object' && (
deepMerge && typeof obj[key] == 'object' && (
typeof targetObj[key] == 'object' ||
typeof targetObj[key] == undefined
)) {
)
) {
if(typeof targetObj[key] == undefined) {

@@ -23,0 +24,0 @@ targetObj[key] = {};

@@ -11,3 +11,3 @@

while(i < s.length) {
if(s[i].match(/[A-Z]/)) {
if(s[i].match(/[A-Z\d]/)) {
o += '_' + s[i].toLowerCase();

@@ -14,0 +14,0 @@ } else {

{
"name": "primitive",
"version": "0.1.7",
"version": "0.2.0",
"description": "",

@@ -5,0 +5,0 @@ "main": "./lib/primitive.js",

@@ -37,3 +37,3 @@

var d = delta.create({}, { a: { b: 'c' }});
d.$set['a.b'].should.equal('c');
d.$set.a.b.should.equal('c');
});

@@ -48,3 +48,3 @@

var d = delta.create({ a: { b: 'c' }}, {});
d.$unset['a.b'].should.equal(1);
d.$unset.a.b.should.equal(1);
});

@@ -58,28 +58,21 @@

it('adds the new and original path to $rename', function() {
var d = delta.create({ a: { b: 'c' }}, { a: 'c' });
d.$rename['a.b'].should.equal('a');
var d = delta.create({ a: { b: 'c' } }, { a: { c: 'c' } });
d.$rename['a.b'].should.equal('a.c');
});
it('can handle very complex data', function() {
it('can arrays', function() {
var d = delta.create({
a: {
b: 'a',
c: 'c',
},
z: 'z',
g: ['i', 'g', 'w']
arr: ['i', 'g', 'w']
}, {
a: 'a',
b: 'b',
x: { y: 'y' },
g: ['g', 'h']
arr: ['g', 'h']
});
d.$unset['a.c'].should.equal(1);
d.$unset['z'].should.equal(1);
d.$set['g.0'].should.equal('g');
d.$set['g.1'].should.equal('h');
d.$set['b'].should.equal('b');
d.$set['x.y'].should.equal('y');
d.$rename['a.b'].should.equal('a');
d.$pull['g'].should.equal('w');
d.$push.should.be.OK;
d.$push.arr.should.be.OK;
d.$push.arr.$each.should.be.OK;
d.$push.arr.$each[0].should.equal('h');
d.$pull.should.be.OK;
d.$pull.arr.should.be.OK;
d.$pull.arr.$each.should.be.OK;
d.$pull.arr.$each[0].should.equal('i');
d.$pull.arr.$each[1].should.equal('w');
});

@@ -92,17 +85,21 @@

before(function() {
this.data = {
a: 'a',
b: 'b',
e: ['e', 'x'],
x: 'x'
this.original = {
a: {
b: {
c: '1'
}
},
d: '2',
e: '3',
f: [1, 2, 3]
};
this.d = delta.create(this.data, {
a: 'a',
b: {
c: 'c'
this.current = {
a: {
b: '1'
},
d: {
e: ['e', 'y']
}
});
c: '2',
d: '3',
f: [2, 5, 3]
};
this.delta = delta.create(this.original, this.current);
});

@@ -136,17 +133,17 @@

it('adds values to the correct path from $set', function() {
var obj = delta.apply(this.data, this.d);
obj.b.c.should.equal('c');
var obj = delta.apply(this.original, this.delta);
obj.c.should.equal('2');
});
it('removes paths from $unset', function() {
var obj = delta.apply(this.data, this.d);
(obj.x === undefined).should.be.true;
var obj = delta.apply(this.original, this.delta);
(obj.e === undefined).should.be.true;
});
it('renames paths from $rename', function() {
var obj = delta.apply(this.data, this.d);
(obj.e[0] === undefined).should.be.true;
obj.d.e[0].should.equal('e');
var obj = delta.apply(this.original, this.delta);
(obj.e === undefined).should.be.true;
obj.d.should.equal('3');
});
});