Comparing version 1.1.1 to 1.1.2
93
diff.js
import { compare } from './equal'; | ||
function pushAll(array, items) { | ||
return Array.prototype.push.apply(array, items); | ||
} | ||
/** | ||
@@ -9,7 +6,7 @@ subtract(a, b) returns the keys in `a` that are not in `b`. | ||
function subtract(a, b) { | ||
var obj = {}; | ||
for (var add_key in a) { | ||
const obj = {}; | ||
for (let add_key in a) { | ||
obj[add_key] = 1; | ||
} | ||
for (var del_key in b) { | ||
for (let del_key in b) { | ||
delete obj[del_key]; | ||
@@ -24,5 +21,5 @@ } | ||
// initialize like union() | ||
var key_counts = {}; | ||
const key_counts = {}; | ||
objects.forEach(object => { | ||
for (var key in object) { | ||
for (let key in object) { | ||
key_counts[key] = (key_counts[key] || 0) + 1; | ||
@@ -32,4 +29,4 @@ } | ||
// but then, extra requirement: delete less commonly-seen keys | ||
var threshold = objects.length; | ||
for (var key in key_counts) { | ||
const threshold = objects.length; | ||
for (let key in key_counts) { | ||
if (key_counts[key] < threshold) { | ||
@@ -53,2 +50,11 @@ delete key_counts[key]; | ||
} | ||
function isArrayAdd(array_operation) { | ||
return array_operation.op === 'add'; | ||
} | ||
function isArrayRemove(array_operation) { | ||
return array_operation.op === 'remove'; | ||
} | ||
function isArrayReplace(array_operation) { | ||
return array_operation.op === 'replace'; | ||
} | ||
/** | ||
@@ -80,3 +86,3 @@ Array-diffing smarter (levenshtein-like) diffing here | ||
// set up cost matrix (very simple initialization: just a map) | ||
var memo = { | ||
const memo = { | ||
'0,0': { operations: [], cost: 0 } | ||
@@ -96,3 +102,3 @@ }; | ||
// memoized | ||
var memoized = memo[i + ',' + j]; | ||
let memoized = memo[i + ',' + j]; | ||
if (memoized === undefined) { | ||
@@ -104,6 +110,6 @@ if (compare(input[i - 1], output[j - 1])) { | ||
else { | ||
var alternatives = []; | ||
const alternatives = []; | ||
if (i > 0) { | ||
// NOT topmost row | ||
var remove_alternative = dist(i - 1, j); | ||
const remove_alternative = dist(i - 1, j); | ||
alternatives.push({ | ||
@@ -120,3 +126,3 @@ // the new operation must be pushed on the end | ||
// NOT leftmost column | ||
var add_alternative = dist(i, j - 1); | ||
const add_alternative = dist(i, j - 1); | ||
alternatives.push({ | ||
@@ -133,3 +139,7 @@ operations: add_alternative.operations.concat({ | ||
// TABLE MIDDLE | ||
var replace_alternative = dist(i - 1, j - 1); | ||
// supposing we replaced it, compute the rest of the costs: | ||
const replace_alternative = dist(i - 1, j - 1); | ||
// okay, the general plan is to replace it, but we can be smarter, | ||
// recursing into the structure and replacing only part of it if | ||
// possible, but to do so we'll need the original value | ||
alternatives.push({ | ||
@@ -139,2 +149,3 @@ operations: replace_alternative.operations.concat({ | ||
index: i - 1, | ||
original: input[i - 1], | ||
value: output[j - 1], | ||
@@ -149,3 +160,3 @@ }), | ||
// [4, 6, 7, 1, 2].sort(function(a, b) {return a - b;}); -> [ 1, 2, 4, 6, 7 ] | ||
var best = alternatives.sort((a, b) => a.cost - b.cost)[0]; | ||
const best = alternatives.sort((a, b) => a.cost - b.cost)[0]; | ||
memoized = best; | ||
@@ -157,9 +168,8 @@ } | ||
} | ||
var array_operations = dist(input.length, output.length).operations; | ||
var padding = 0; | ||
var operations = array_operations.map(array_operation => { | ||
if (array_operation.op === 'add') { | ||
var padded_index = array_operation.index + 1 + padding; | ||
var index_token = padded_index < input.length ? String(padded_index) : '-'; | ||
var operation = { | ||
const array_operations = dist(input.length, output.length).operations; | ||
const [operations, padding] = array_operations.reduce(([operations, padding], array_operation) => { | ||
if (isArrayAdd(array_operation)) { | ||
const padded_index = array_operation.index + 1 + padding; | ||
const index_token = padded_index < input.length ? String(padded_index) : '-'; | ||
const operation = { | ||
op: array_operation.op, | ||
@@ -169,21 +179,19 @@ path: ptr.add(index_token).toString(), | ||
}; | ||
padding++; // maybe only if array_operation.index > -1 ? | ||
return operation; | ||
// padding++; // maybe only if array_operation.index > -1 ? | ||
return [operations.concat(operation), padding + 1]; | ||
} | ||
else if (array_operation.op === 'remove') { | ||
var operation = { | ||
else if (isArrayRemove(array_operation)) { | ||
const operation = { | ||
op: array_operation.op, | ||
path: ptr.add(String(array_operation.index + padding)).toString(), | ||
}; | ||
padding--; | ||
return operation; | ||
// padding--; | ||
return [operations.concat(operation), padding - 1]; | ||
} | ||
else { | ||
return { | ||
op: array_operation.op, | ||
path: ptr.add(String(array_operation.index + padding)).toString(), | ||
value: array_operation.value, | ||
}; | ||
const replace_ptr = ptr.add(String(array_operation.index + padding)); | ||
const replace_operations = diffAny(array_operation.original, array_operation.value, replace_ptr); | ||
return [operations.concat(...replace_operations), padding]; | ||
} | ||
}); | ||
}, [[], 0]); | ||
return operations; | ||
@@ -193,3 +201,3 @@ } | ||
// if a key is in input but not output -> remove it | ||
var operations = []; | ||
const operations = []; | ||
subtract(input, output).forEach(key => { | ||
@@ -204,3 +212,3 @@ operations.push({ op: 'remove', path: ptr.add(key).toString() }); | ||
intersection([input, output]).forEach(key => { | ||
pushAll(operations, diffAny(input[key], output[key], ptr.add(key))); | ||
operations.push(...diffAny(input[key], output[key], ptr.add(key))); | ||
}); | ||
@@ -210,11 +218,10 @@ return operations; | ||
function diffValues(input, output, ptr) { | ||
var operations = []; | ||
if (!compare(input, output)) { | ||
operations.push({ op: 'replace', path: ptr.toString(), value: output }); | ||
return [{ op: 'replace', path: ptr.toString(), value: output }]; | ||
} | ||
return operations; | ||
return []; | ||
} | ||
export function diffAny(input, output, ptr) { | ||
var input_type = objectType(input); | ||
var output_type = objectType(output); | ||
const input_type = objectType(input); | ||
const output_type = objectType(output); | ||
if (input_type == 'array' && output_type == 'array') { | ||
@@ -221,0 +228,0 @@ return diffArrays(input, output, ptr); |
{ | ||
"name": "rfc6902", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"description": "Complete implementation of RFC6902 (patch and diff)", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -66,1 +66,19 @@ import assert from 'assert'; | ||
}); | ||
describe('issues/9', () => { | ||
var input = [{A: 1, B: 2}, {C: 3}]; | ||
var output = [{A: 1, B: 20}, {C: 3}]; | ||
var expected_patch = [ | ||
{op: 'replace', path: '/0/B', value: 20}, | ||
]; | ||
var actual_patch = createPatch(input, output); | ||
it('should produce patch equal to expectation', () => { | ||
assert.deepEqual(actual_patch, expected_patch); | ||
}); | ||
it('should apply patch to arrive at output', () => { | ||
var actual_output = clone(input); | ||
var patch_results = applyPatch(actual_output, actual_patch); | ||
assert.deepEqual(actual_output, output); | ||
assert.deepEqual(patch_results, [null]); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
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
83056
18
1585