Skip to content

Commit

Permalink
refactor: Improve maintainability of Omnom
Browse files Browse the repository at this point in the history
  • Loading branch information
notheotherben committed Mar 11, 2016
1 parent 24d5b09 commit c3b842a
Showing 1 changed file with 73 additions and 62 deletions.
135 changes: 73 additions & 62 deletions lib/utils/Omnom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class Omnom {
if (original === undefined || original === null)
return (original !== modified) && this.set(changePath, modified);

if (typeof original == 'number' && typeof modified == 'number' && original !== modified) {
if (typeof original === 'number' && typeof modified === 'number' && original !== modified) {
if (this.options.atomicNumbers) return this.inc(changePath, modified - original);
return this.set(changePath, modified);
}
Expand Down Expand Up @@ -91,67 +91,78 @@ export class Omnom {
}

private onArray(original: any[], modified: any[], changePath: string) {
var i, j;

// Check if we can get from original => modified using just pulls
if (original.length > modified.length) {
var pulls = [];
for (i = 0, j = 0; i < original.length && j < modified.length; i++) {
if (this.almostEqual(original[i], modified[j])) j++;
else pulls.push(original[i]);
}

for (; i < original.length; i++)
pulls.push(original[i]);

if (j === modified.length) {
if (pulls.length === 1) return this.pull(changePath, pulls[0]);
// We can complete using just pulls
return pulls.forEach((pull) => this.pull(changePath, pull));
}

// If we have a smaller target array than our source, we will need to re-create it
// regardless (if we want to do so in a single operation anyway)
else return this.set(changePath, modified);
return this.onSmallerArray(original, modified, changePath);
}

// Check if we can get from original => modified using just pushes
if (original.length < modified.length) {
var canPush = true;
for (i = 0; i < original.length; i++)
if (this.almostEqual(original[i], modified[i]) < 1) {
canPush = false;
break;
}

if (canPush) {
for (i = original.length; i < modified.length; i++)
this.push(changePath, modified[i]);
return;
}
return this.onLargerArray(original, modified, changePath);
}

// Otherwise, we need to use $set to generate the new array
return this.onSimilarArray(original, modified, changePath);
}

// Check how many manipulations would need to be performed, if it's more than half the array size
// then rather re-create the array

var sets = [];
var partials = [];
for (i = 0; i < modified.length; i++) {
var equality = this.almostEqual(original[i], modified[i]);
if (equality === 0) sets.push(i);
else if (equality < 1) partials.push(i);
}

if (sets.length > modified.length / 2)
return this.set(changePath, modified);

for (i = 0; i < sets.length; i++)
this.set(this.resolve(changePath, sets[i].toString()), modified[sets[i]]);

for (i = 0; i < partials.length; i++)
this.onObject(original[partials[i]], modified[partials[i]], this.resolve(changePath, partials[i].toString()));
private onSmallerArray(original: any[], modified: any[], changePath: string) {
let pulls = [];
let i = 0;
let j = 0;

for (; i < original.length && j < modified.length; i++) {
if (this.almostEqual(original[i], modified[j])) j++;
else pulls.push(original[i]);
}

for (; i < original.length; i++)
pulls.push(original[i]);

if (j === modified.length) {
if (pulls.length === 1) return this.pull(changePath, pulls[0]);
// We can complete using just pulls
return pulls.forEach((pull) => this.pull(changePath, pull));
}

// If we have a smaller target array than our source, we will need to re-create it
// regardless (if we want to do so in a single operation anyway)
else return this.set(changePath, modified);
}

private onLargerArray(original: any[], modified: any[], changePath: string) {
let canPush = true;
for (let i = 0; i < original.length; i++)
if (this.almostEqual(original[i], modified[i]) < 1) {
canPush = false;
break;
}

if (canPush) {
for (let i = original.length; i < modified.length; i++)
this.push(changePath, modified[i]);
return;
}
}

private onSimilarArray(original: any[], modified: any[], changePath: string) {
// Check how many manipulations would need to be performed, if it's more than half the array size
// then rather re-create the array
let sets = [];
let partials = [];
for (let i = 0; i < modified.length; i++) {
let equality = this.almostEqual(original[i], modified[i]);
if (equality === 0) sets.push(i);
else if (equality < 1) partials.push(i);
}

if (sets.length > modified.length / 2)
return this.set(changePath, modified);

for (let i = 0; i < sets.length; i++)
this.set(this.resolve(changePath, sets[i].toString()), modified[sets[i]]);

for (let i = 0; i < partials.length; i++)
this.onObject(original[partials[i]], modified[partials[i]], this.resolve(changePath, partials[i].toString()));
}

private set(path: string, value: any) {
Expand Down Expand Up @@ -214,7 +225,7 @@ export class Omnom {
}

private resolve(...args) {
var validArguments = [];
let validArguments = [];
args.forEach(function (arg) {
if (arg) validArguments.push(arg);
});
Expand All @@ -225,18 +236,18 @@ export class Omnom {
private almostEqual(o1: any, o2: any) {
if (!_.isPlainObject(o1) || !_.isPlainObject(o2)) return o1 == o2 ? 1 : 0;

var o1i, o1k = Object.keys(o1);
var o2k = Object.keys(o2);
let object1KeyIndex, object1Keys = Object.keys(o1);
let object2Keys = Object.keys(o2);

var commonKeys = [];
for (o1i = 0; o1i < o1k.length; o1i++)
if (~o2k.indexOf(o1k[o1i])) commonKeys.push(o1k[o1i]);
let commonKeys = [];
for (object1KeyIndex = 0; object1KeyIndex < object1Keys.length; object1KeyIndex++)
if (~object2Keys.indexOf(object1Keys[object1KeyIndex])) commonKeys.push(object1Keys[object1KeyIndex]);

var totalKeys = o1k.length + o2k.length - commonKeys.length;
var keysDifference = totalKeys - commonKeys.length;
let totalKeys = object1Keys.length + object2Keys.length - commonKeys.length;
let keysDifference = totalKeys - commonKeys.length;

var requiredChanges = 0;
for (var i = 0; i < commonKeys.length; i++)
let requiredChanges = 0;
for (let i = 0; i < commonKeys.length; i++)
if (this.almostEqual(o1[commonKeys[i]], o2[commonKeys[i]]) < 1) requiredChanges++;

return 1 - (keysDifference / totalKeys) - (requiredChanges / commonKeys.length);
Expand Down

0 comments on commit c3b842a

Please sign in to comment.