Socket
Socket
Sign inDemoInstall

json-diff

Package Overview
Dependencies
Maintainers
2
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-diff - npm Package Compare versions

Comparing version 0.5.5 to 0.6.0

.eslintrc.js

109

lib/cli.js

@@ -1,63 +0,68 @@

// Generated by CoffeeScript 1.12.7
(function() {
var colorize, diff, fs, tty;
const fs = require('fs')
const tty = require('tty')
fs = require('fs');
const { diff } = require('./index')
const { colorize } = require('./colorize')
tty = require('tty');
module.exports = function (argv) {
const options = require('dreamopt')(
[
'Usage: json-diff [-vjCkf] first.json second.json',
' <first.json> Old file #var(file1) #required',
' <second.json> New file #var(file2) #required',
'General options:',
' -v, --verbose Output progress info',
' -C, --[no-]color Colored output',
' -j, --raw-json Display raw JSON encoding of the diff #var(raw)',
' -f, --full Include the equal sections of the document, not just the deltas #var(full)',
' -k, --keys-only Compare only the keys, ignore the differences in values #var(keysOnly)',
],
argv
)
diff = require('./index').diff;
if (options.verbose) {
process.stderr.write(`${JSON.stringify(options, null, 2)}\n`)
}
colorize = require('./colorize').colorize;
if (options.verbose) {
process.stderr.write('Loading files...\n')
}
const data1 = fs.readFileSync(options.file1, 'utf8')
const data2 = fs.readFileSync(options.file2, 'utf8')
module.exports = function(argv) {
var data1, data2, json1, json2, options, result;
options = require('dreamopt')(["Usage: json-diff [-vjCk] first.json second.json", "Arguments:", " first.json Old file #var(file1) #required", " second.json New file #var(file2) #required", "General options:", " -v, --verbose Output progress info", " -C, --[no-]color Colored output", " -j, --raw-json Display raw JSON encoding of the diff #var(raw)", " -k, --keys-only Compare only the keys, ignore the differences in values #var(keysOnly)"], argv);
if (options.verbose) {
process.stderr.write((JSON.stringify(options, null, 2)) + "\n");
}
if (options.verbose) {
process.stderr.write("Loading files...\n");
}
data1 = fs.readFileSync(options.file1, 'utf8');
data2 = fs.readFileSync(options.file2, 'utf8');
if (options.verbose) {
process.stderr.write("Parsing old file...\n");
}
json1 = JSON.parse(data1);
if (options.verbose) {
process.stderr.write("Parsing new file...\n");
}
json2 = JSON.parse(data2);
if (options.verbose) {
process.stderr.write("Running diff...\n");
}
result = diff(json1, json2, options);
if (options.color == null) {
options.color = tty.isatty(process.stdout.fd);
}
if (result) {
if (options.raw) {
if (options.verbose) {
process.stderr.write("Serializing JSON output...\n");
}
process.stdout.write(JSON.stringify(result, null, 2));
} else {
if (options.verbose) {
process.stderr.write("Producing colored output...\n");
}
process.stdout.write(colorize(result, {
color: options.color
}));
if (options.verbose) {
process.stderr.write('Parsing old file...\n')
}
const json1 = JSON.parse(data1)
if (options.verbose) {
process.stderr.write('Parsing new file...\n')
}
const json2 = JSON.parse(data2)
if (options.verbose) {
process.stderr.write('Running diff...\n')
}
const result = diff(json1, json2, options)
if (options.color == null) {
options.color = tty.isatty(process.stdout.fd)
}
if (result) {
if (options.raw) {
if (options.verbose) {
process.stderr.write('Serializing JSON output...\n')
}
process.stdout.write(JSON.stringify(result, null, 2) + '\n')
} else {
if (options.verbose) {
process.stderr.write("No diff");
process.stderr.write('Producing colored output...\n')
}
process.stdout.write(colorize(result, { color: options.color }))
}
if (result) {
return process.exit(1);
} else {
if (options.verbose) {
process.stderr.write('No diff')
}
};
}).call(this);
}
}

@@ -1,117 +0,96 @@

// Generated by CoffeeScript 1.12.7
(function() {
var Theme, color, colorize, colorizeToArray, colorizeToCallback, extendedTypeOf, subcolorizeToCallback,
hasProp = {}.hasOwnProperty;
const color = require('cli-color')
color = require('cli-color');
const { extendedTypeOf } = require('./util')
extendedTypeOf = require('./util').extendedTypeOf;
const Theme = {
' ' (s) { return s },
'+': color.green,
'-': color.red
}
Theme = {
' ': function(s) {
return s;
},
'+': color.green,
'-': color.red
};
const subcolorizeToCallback = function (key, diff, output, color, indent) {
let subvalue
const prefix = key ? `${key}: ` : ''
const subindent = indent + ' '
subcolorizeToCallback = function(key, diff, output, color, indent) {
var i, item, j, k, len, len1, len2, looksLikeDiff, m, op, prefix, ref, ref1, subindent, subkey, subvalue;
prefix = key ? key + ": " : '';
subindent = indent + ' ';
switch (extendedTypeOf(diff)) {
case 'object':
if (('__old' in diff) && ('__new' in diff) && (Object.keys(diff).length === 2)) {
subcolorizeToCallback(key, diff.__old, output, '-', indent);
return subcolorizeToCallback(key, diff.__new, output, '+', indent);
} else {
output(color, "" + indent + prefix + "{");
for (subkey in diff) {
if (!hasProp.call(diff, subkey)) continue;
subvalue = diff[subkey];
if (m = subkey.match(/^(.*)__deleted$/)) {
subcolorizeToCallback(m[1], subvalue, output, '-', subindent);
} else if (m = subkey.match(/^(.*)__added$/)) {
subcolorizeToCallback(m[1], subvalue, output, '+', subindent);
} else {
subcolorizeToCallback(subkey, subvalue, output, color, subindent);
}
switch (extendedTypeOf(diff)) {
case 'object':
if (('__old' in diff) && ('__new' in diff) && (Object.keys(diff).length === 2)) {
subcolorizeToCallback(key, diff.__old, output, '-', indent)
return subcolorizeToCallback(key, diff.__new, output, '+', indent)
} else {
output(color, `${indent}${prefix}{`)
for (const subkey of Object.keys(diff)) {
let m
subvalue = diff[subkey]
if ((m = subkey.match(/^(.*)__deleted$/))) {
subcolorizeToCallback(m[1], subvalue, output, '-', subindent)
} else if ((m = subkey.match(/^(.*)__added$/))) {
subcolorizeToCallback(m[1], subvalue, output, '+', subindent)
} else {
subcolorizeToCallback(subkey, subvalue, output, color, subindent)
}
return output(color, indent + "}");
}
break;
case 'array':
output(color, "" + indent + prefix + "[");
looksLikeDiff = true;
for (i = 0, len = diff.length; i < len; i++) {
item = diff[i];
if ((extendedTypeOf(item) !== 'array') || !((item.length === 2) || ((item.length === 1) && (item[0] === ' '))) || !(typeof item[0] === 'string') || item[0].length !== 1 || !((ref = item[0]) === ' ' || ref === '-' || ref === '+' || ref === '~')) {
looksLikeDiff = false;
}
return output(color, `${indent}}`)
}
case 'array': {
output(color, `${indent}${prefix}[`)
let looksLikeDiff = true
for (const item of diff) {
if ((extendedTypeOf(item) !== 'array') || !((item.length === 2) || ((item.length === 1) && (item[0] === ' '))) || !(typeof (item[0]) === 'string') || (item[0].length !== 1) || !([' ', '-', '+', '~'].includes(item[0]))) {
looksLikeDiff = false
}
if (looksLikeDiff) {
for (j = 0, len1 = diff.length; j < len1; j++) {
ref1 = diff[j], op = ref1[0], subvalue = ref1[1];
if (op === ' ' && (subvalue == null)) {
output(' ', subindent + '...');
} else {
if (op !== ' ' && op !== '~' && op !== '+' && op !== '-') {
throw new Error("Unexpected op '" + op + "' in " + (JSON.stringify(diff, null, 2)));
}
if (op === '~') {
op = ' ';
}
subcolorizeToCallback('', subvalue, output, op, subindent);
}
if (looksLikeDiff) {
let op
for ([op, subvalue] of diff) {
if (op === ' ' && subvalue == null) {
output(' ', subindent + '...')
} else {
if (![' ', '~', '+', '-'].includes(op)) {
throw new Error(`Unexpected op '${op}' in ${JSON.stringify(diff, null, 2)}`)
}
if (op === '~') { op = ' ' }
subcolorizeToCallback('', subvalue, output, op, subindent)
}
} else {
for (k = 0, len2 = diff.length; k < len2; k++) {
subvalue = diff[k];
subcolorizeToCallback('', subvalue, output, color, subindent);
}
}
return output(color, indent + "]");
default:
if (diff === 0 || diff === null || diff === false || diff) {
return output(color, indent + prefix + JSON.stringify(diff));
} else {
for (subvalue of diff) {
subcolorizeToCallback('', subvalue, output, color, subindent)
}
}
return output(color, `${indent}]`)
}
};
colorizeToCallback = function(diff, output) {
return subcolorizeToCallback('', diff, output, ' ', '');
};
default:
if (diff === 0 || diff === null || diff === false || diff === '' || diff) {
return output(color, indent + prefix + JSON.stringify(diff))
}
}
}
colorizeToArray = function(diff) {
var output;
output = [];
colorizeToCallback(diff, function(color, line) {
return output.push("" + color + line);
});
return output;
};
const colorizeToCallback = (diff, output) => subcolorizeToCallback('', diff, output, ' ', '')
colorize = function(diff, options) {
var output;
if (options == null) {
options = {};
const colorizeToArray = function (diff) {
const output = []
colorizeToCallback(diff, (color, line) => output.push(`${color}${line}`))
return output
}
const colorize = function (diff, options = {}) {
const output = []
colorizeToCallback(diff, function (color, line) {
if (options.color != null ? options.color : true) {
return output.push(((options.theme != null ? options.theme[color] : undefined) != null ? (options.theme != null ? options.theme[color] : undefined) : Theme[color])(`${color}${line}`) + '\n')
} else {
return output.push(`${color}${line}\n`)
}
output = [];
colorizeToCallback(diff, function(color, line) {
var ref, ref1, ref2;
if ((ref = options.color) != null ? ref : true) {
return output.push(((ref1 = (ref2 = options.theme) != null ? ref2[color] : void 0) != null ? ref1 : Theme[color])("" + color + line) + "\n");
} else {
return output.push("" + color + line + "\n");
}
});
return output.join('');
};
})
return output.join('')
}
module.exports = {
colorize: colorize,
colorizeToArray: colorizeToArray,
colorizeToCallback: colorizeToCallback
};
}).call(this);
module.exports = { colorize, colorizeToArray, colorizeToCallback }

@@ -1,288 +0,322 @@

// Generated by CoffeeScript 1.12.7
(function() {
var SequenceMatcher, arrayDiff, colorize, descalarize, diff, diffScore, diffString, diffWithScore, extendedTypeOf, findMatchingObject, isScalar, isScalarized, objectDiff, scalarize,
hasProp = {}.hasOwnProperty;
const { SequenceMatcher } = require('difflib')
const { extendedTypeOf } = require('./util')
const { colorize } = require('./colorize')
SequenceMatcher = require('difflib').SequenceMatcher;
class JsonDiff {
constructor (options) {
this.options = options
}
extendedTypeOf = require('./util').extendedTypeOf;
isScalar (obj) {
return typeof obj !== 'object' || obj === null
}
colorize = require('./colorize').colorize;
objectDiff (obj1, obj2) {
let result = {}
let score = 0
let equal = true
isScalar = function(obj) {
return typeof obj !== 'object' || obj === null;
};
for (const [key, value] of Object.entries(obj1)) {
if (!(key in obj2)) {
result[`${key}__deleted`] = value
score -= 30
equal = false
}
}
objectDiff = function(obj1, obj2, options) {
var change, key, ref, ref1, result, score, subscore, value1, value2;
if (options == null) {
options = {};
}
result = {};
score = 0;
for (key in obj1) {
if (!hasProp.call(obj1, key)) continue;
value1 = obj1[key];
if (!(!(key in obj2))) {
continue;
for (const [key, value] of Object.entries(obj2)) {
if (!(key in obj1)) {
result[`${key}__added`] = value
score -= 30
equal = false
}
result[key + "__deleted"] = value1;
score -= 30;
}
for (key in obj2) {
if (!hasProp.call(obj2, key)) continue;
value2 = obj2[key];
if (!(!(key in obj1))) {
continue;
for (const [key, value1] of Object.entries(obj1)) {
if (key in obj2) {
score += 20
const value2 = obj2[key]
const change = this.diff(value1, value2)
if (!change.equal) {
result[key] = change.result
equal = false
} else if (this.options.full) {
result[key] = value1
}
// console.log(`key ${key} change.score=${change.score} ${change.result}`)
score += Math.min(20, Math.max(-10, change.score / 5)) // BATMAN!
}
result[key + "__added"] = value2;
score -= 30;
}
for (key in obj1) {
if (!hasProp.call(obj1, key)) continue;
value1 = obj1[key];
if (!(key in obj2)) {
continue;
if (equal) {
score = 100 * Math.max(Object.keys(obj1).length, 0.5)
if (!this.options.full) {
result = undefined
}
score += 20;
value2 = obj2[key];
ref = diffWithScore(value1, value2, options), subscore = ref[0], change = ref[1];
if (change) {
result[key] = change;
}
score += Math.min(20, Math.max(-10, subscore / 5));
}
if (Object.keys(result).length === 0) {
ref1 = [100 * Math.max(Object.keys(obj1).length, 0.5), void 0], score = ref1[0], result = ref1[1];
} else {
score = Math.max(0, score);
score = Math.max(0, score)
}
return [score, result];
};
findMatchingObject = function(item, index, fuzzyOriginals) {
var bestMatch, candidate, indexDistance, key, matchIndex, score;
bestMatch = null;
matchIndex = 0;
for (key in fuzzyOriginals) {
if (!hasProp.call(fuzzyOriginals, key)) continue;
candidate = fuzzyOriginals[key];
if (!(key !== '__next')) {
continue;
}
indexDistance = Math.abs(matchIndex - index);
if (extendedTypeOf(item) === extendedTypeOf(candidate)) {
score = diffScore(item, candidate);
if (!bestMatch || score > bestMatch.score || (score === bestMatch.score && indexDistance < bestMatch.indexDistance)) {
bestMatch = {
score: score,
key: key,
indexDistance: indexDistance
};
// console.log(`objectDiff(${JSON.stringify(obj1, null, 2)} <=> ${JSON.stringify(obj2, null, 2)}) == ${JSON.stringify({score, result, equal})}`)
return { score, result, equal }
}
findMatchingObject (item, index, fuzzyOriginals) {
// console.log("findMatchingObject: " + JSON.stringify({item, fuzzyOriginals}, null, 2))
let bestMatch = null
let matchIndex = 0
for (const [key, candidate] of Object.entries(fuzzyOriginals)) {
if (key !== '__next') {
const indexDistance = Math.abs(matchIndex - index)
if (extendedTypeOf(item) === extendedTypeOf(candidate)) {
const { score } = this.diff(item, candidate)
if (
!bestMatch ||
score > bestMatch.score ||
(score === bestMatch.score &&
indexDistance < bestMatch.indexDistance)
) {
bestMatch = { score, key, indexDistance }
}
}
matchIndex++
}
matchIndex++;
}
return bestMatch;
};
scalarize = function(array, originals, fuzzyOriginals) {
var bestMatch, fuzzyMatches, index, item, k, key, keyScores, l, len, len1, match, results;
fuzzyMatches = [];
// console.log"findMatchingObject result = " + JSON.stringify(bestMatch, null, 2)
return bestMatch
}
scalarize (array, originals, fuzzyOriginals) {
const fuzzyMatches = []
if (fuzzyOriginals) {
keyScores = {};
for (index = k = 0, len = array.length; k < len; index = ++k) {
item = array[index];
if (isScalar(item)) {
continue;
// Find best fuzzy match for each object in the array
const keyScores = {}
for (let index = 0; index < array.length; index++) {
const item = array[index]
if (this.isScalar(item)) {
continue
}
bestMatch = findMatchingObject(item, index, fuzzyOriginals);
if (!keyScores[bestMatch.key] || bestMatch.score > keyScores[bestMatch.key].score) {
keyScores[bestMatch.key] = {
score: bestMatch.score,
index: index
};
const bestMatch = this.findMatchingObject(item, index, fuzzyOriginals)
if (
!keyScores[bestMatch.key] ||
bestMatch.score > keyScores[bestMatch.key].score
) {
keyScores[bestMatch.key] = { score: bestMatch.score, index }
}
}
for (key in keyScores) {
match = keyScores[key];
fuzzyMatches[match.index] = key;
for (const [key, match] of Object.entries(keyScores)) {
fuzzyMatches[match.index] = key
}
}
results = [];
for (index = l = 0, len1 = array.length; l < len1; index = ++l) {
item = array[index];
if (isScalar(item)) {
results.push(item);
const result = []
for (let index = 0; index < array.length; index++) {
const item = array[index]
if (this.isScalar(item)) {
result.push(item)
} else {
key = fuzzyMatches[index] || "__$!SCALAR" + originals.__next++;
originals[key] = item;
results.push(key);
const key = fuzzyMatches[index] || '__$!SCALAR' + originals.__next++
originals[key] = item
result.push(key)
}
}
return results;
};
return result
}
isScalarized = function(item, originals) {
return (typeof item === 'string') && (item in originals);
};
isScalarized (item, originals) {
return typeof item === 'string' && item in originals
}
descalarize = function(item, originals) {
if (isScalarized(item, originals)) {
return originals[item];
descalarize (item, originals) {
if (this.isScalarized(item, originals)) {
return originals[item]
} else {
return item;
return item
}
};
}
arrayDiff = function(obj1, obj2, options) {
var allEqual, change, i, i1, i2, item, item1, item2, j, j1, j2, k, l, len, m, n, o, op, opcodes, originals1, originals2, p, q, ref, ref1, ref10, ref11, ref12, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, result, score, seq1, seq2;
if (options == null) {
options = {};
}
originals1 = {
__next: 1
};
seq1 = scalarize(obj1, originals1);
originals2 = {
__next: originals1.__next
};
seq2 = scalarize(obj2, originals2, originals1);
opcodes = new SequenceMatcher(null, seq1, seq2).getOpcodes();
result = [];
score = 0;
allEqual = true;
for (k = 0, len = opcodes.length; k < len; k++) {
ref = opcodes[k], op = ref[0], i1 = ref[1], i2 = ref[2], j1 = ref[3], j2 = ref[4];
if (!(op === 'equal' || (options.keysOnly && op === 'replace'))) {
allEqual = false;
arrayDiff (obj1, obj2) {
const originals1 = { __next: 1 }
const seq1 = this.scalarize(obj1, originals1)
const originals2 = { __next: originals1.__next }
const seq2 = this.scalarize(obj2, originals2, originals1)
const opcodes = new SequenceMatcher(null, seq1, seq2).getOpcodes()
// console.log(`arrayDiff:\nobj1 = ${JSON.stringify(obj1, null, 2)}\nobj2 = ${JSON.stringify(obj2, null, 2)}\nseq1 = ${JSON.stringify(seq1, null, 2)}\nseq2 = ${JSON.stringify(seq2, null, 2)}\nopcodes = ${JSON.stringify(opcodes, null, 2)}`)
let result = []
let score = 0
let equal = true
for (const [op, i1, i2, j1, j2] of opcodes) {
let i, j
let asc, end
let asc1, end1
let asc2, end2
if (!(op === 'equal' || (this.options.keysOnly && op === 'replace'))) {
equal = false
}
switch (op) {
case 'equal':
for (i = l = ref1 = i1, ref2 = i2; ref1 <= ref2 ? l < ref2 : l > ref2; i = ref1 <= ref2 ? ++l : --l) {
item = seq1[i];
if (isScalarized(item, originals1)) {
if (!isScalarized(item, originals2)) {
throw new AssertionError("internal bug: isScalarized(item, originals1) != isScalarized(item, originals2) for item " + (JSON.stringify(item)));
for (
i = i1, end = i2, asc = i1 <= end;
asc ? i < end : i > end;
asc ? i++ : i--
) {
const item = seq1[i]
if (this.isScalarized(item, originals1)) {
if (!this.isScalarized(item, originals2)) {
throw new Error(
`internal bug: isScalarized(item, originals1) != isScalarized(item, originals2) for item ${JSON.stringify(
item
)}`
)
}
item1 = descalarize(item, originals1);
item2 = descalarize(item, originals2);
change = diff(item1, item2, options);
if (change) {
result.push(['~', change]);
allEqual = false;
const item1 = this.descalarize(item, originals1)
const item2 = this.descalarize(item, originals2)
const change = this.diff(item1, item2)
if (!change.equal) {
result.push(['~', change.result])
equal = false
} else {
result.push([' ']);
if (this.options.full) {
result.push([' ', item1])
} else {
result.push([' '])
}
}
} else {
result.push([' ', item]);
if (this.options.full) {
result.push([' ', item])
} else {
result.push([' '])
}
}
score += 10;
score += 10
}
break;
break
case 'delete':
for (i = m = ref3 = i1, ref4 = i2; ref3 <= ref4 ? m < ref4 : m > ref4; i = ref3 <= ref4 ? ++m : --m) {
result.push(['-', descalarize(seq1[i], originals1)]);
score -= 5;
for (
i = i1, end1 = i2, asc1 = i1 <= end1;
asc1 ? i < end1 : i > end1;
asc1 ? i++ : i--
) {
result.push(['-', this.descalarize(seq1[i], originals1)])
score -= 5
}
break;
break
case 'insert':
for (j = n = ref5 = j1, ref6 = j2; ref5 <= ref6 ? n < ref6 : n > ref6; j = ref5 <= ref6 ? ++n : --n) {
result.push(['+', descalarize(seq2[j], originals2)]);
score -= 5;
for (
j = j1, end2 = j2, asc2 = j1 <= end2;
asc2 ? j < end2 : j > end2;
asc2 ? j++ : j--
) {
result.push(['+', this.descalarize(seq2[j], originals2)])
score -= 5
}
break;
break
case 'replace':
if (!options.keysOnly) {
for (i = o = ref7 = i1, ref8 = i2; ref7 <= ref8 ? o < ref8 : o > ref8; i = ref7 <= ref8 ? ++o : --o) {
result.push(['-', descalarize(seq1[i], originals1)]);
score -= 5;
if (!this.options.keysOnly) {
let asc3, end3
let asc4, end4
for (
i = i1, end3 = i2, asc3 = i1 <= end3;
asc3 ? i < end3 : i > end3;
asc3 ? i++ : i--
) {
result.push(['-', this.descalarize(seq1[i], originals1)])
score -= 5
}
for (j = p = ref9 = j1, ref10 = j2; ref9 <= ref10 ? p < ref10 : p > ref10; j = ref9 <= ref10 ? ++p : --p) {
result.push(['+', descalarize(seq2[j], originals2)]);
score -= 5;
for (
j = j1, end4 = j2, asc4 = j1 <= end4;
asc4 ? j < end4 : j > end4;
asc4 ? j++ : j--
) {
result.push(['+', this.descalarize(seq2[j], originals2)])
score -= 5
}
} else {
for (i = q = ref11 = i1, ref12 = i2; ref11 <= ref12 ? q < ref12 : q > ref12; i = ref11 <= ref12 ? ++q : --q) {
change = diff(descalarize(seq1[i], originals1), descalarize(seq2[i - i1 + j1], originals2), options);
if (change) {
result.push(['~', change]);
allEqual = false;
let asc5, end5
for (
i = i1, end5 = i2, asc5 = i1 <= end5;
asc5 ? i < end5 : i > end5;
asc5 ? i++ : i--
) {
const change = this.diff(
this.descalarize(seq1[i], originals1),
this.descalarize(seq2[i - i1 + j1], originals2)
)
if (!change.equal) {
result.push(['~', change.result])
equal = false
} else {
result.push([' ']);
result.push([' '])
}
}
}
break
}
}
if (allEqual || (opcodes.length === 0)) {
result = void 0;
score = 100;
if (equal || opcodes.length === 0) {
if (!this.options.full) {
result = undefined
} else {
result = obj1
}
score = 100
} else {
score = Math.max(0, score);
score = Math.max(0, score)
}
return [score, result];
};
diffWithScore = function(obj1, obj2, options) {
var type1, type2;
if (options == null) {
options = {};
}
type1 = extendedTypeOf(obj1);
type2 = extendedTypeOf(obj2);
return { score, result, equal }
}
diff (obj1, obj2) {
const type1 = extendedTypeOf(obj1)
const type2 = extendedTypeOf(obj2)
if (type1 === type2) {
switch (type1) {
case 'object':
return objectDiff(obj1, obj2, options);
return this.objectDiff(obj1, obj2)
case 'array':
return arrayDiff(obj1, obj2, options);
return this.arrayDiff(obj1, obj2)
}
}
if (!options.keysOnly) {
if (obj1 !== obj2) {
return [
0, {
__old: obj1,
__new: obj2
}
];
} else {
return [100, void 0];
// Compare leaf nodes or complex objects of different types
let score = 100
let result = obj1
let equal
if (!this.options.keysOnly) {
equal = obj1 === obj2
if (!equal) {
score = 0
result = { __old: obj1, __new: obj2 }
} else if (!this.options.full) {
result = undefined
}
} else {
return [100, void 0];
equal = true
result = undefined
}
};
diff = function(obj1, obj2, options) {
var change, ref, score;
if (options == null) {
options = {};
}
ref = diffWithScore(obj1, obj2, options), score = ref[0], change = ref[1];
return change;
};
return { score, result, equal }
}
}
diffScore = function(obj1, obj2, options) {
var change, ref, score;
if (options == null) {
options = {};
}
ref = diffWithScore(obj1, obj2, options), score = ref[0], change = ref[1];
return score;
};
function diff (obj1, obj2, options = {}) {
return new JsonDiff(options).diff(obj1, obj2).result
}
diffString = function(obj1, obj2, colorizeOptions, diffOptions) {
if (diffOptions == null) {
diffOptions = {};
}
return colorize(diff(obj1, obj2, diffOptions), colorizeOptions);
};
function diffString (obj1, obj2, options = {}) {
return colorize(diff(obj1, obj2, options), options)
}
module.exports = {
diff: diff,
diffString: diffString
};
}).call(this);
module.exports = { diff, diffString }

@@ -1,21 +0,12 @@

// Generated by CoffeeScript 1.12.7
(function() {
var extendedTypeOf;
const extendedTypeOf = function (obj) {
const result = typeof obj
if (obj == null) {
return 'null'
} else if (result === 'object' && obj.constructor === Array) {
return 'array'
} else {
return result
}
}
extendedTypeOf = function(obj) {
var result;
result = typeof obj;
if (obj == null) {
return 'null';
} else if (result === 'object' && obj.constructor === Array) {
return 'array';
} else {
return result;
}
};
module.exports = {
extendedTypeOf: extendedTypeOf
};
}).call(this);
module.exports = { extendedTypeOf }
{
"author": "Andrey Tarantsov <andreyvit@me.com>",
"contributors": [
"Gavriel Fleischer <flocsy@gmail.com>"
"Gavriel Fleischer <flocsy@gmail.com>",
"Eric Woudenberg <eaw@woudy.org>"
],
"name": "json-diff",
"description": "JSON diff",
"version": "0.5.5",
"version": "0.6.0",
"homepage": "https://github.com/andreyvit/json-diff",

@@ -17,4 +18,4 @@ "license": "MIT",

"scripts": {
"prepare": "coffee -c lib",
"test": "mocha test/*.coffee",
"fix": "eslint --fix lib",
"test": "coffee -c test; mocha test/*.js",
"cov": "rm -rf lib-cov; jscoverage lib lib-cov; env JSLIB=lib-cov mocha -R dot && env JSLIB=lib-cov mocha -R html-cov >coverage.html; open coverage.html"

@@ -25,9 +26,11 @@ },

"difflib": "~0.2.1",
"dreamopt": "~0.6.0"
"dreamopt": "~0.8.0",
"jscoverage": "^0.6.0"
},
"devDependencies": {
"coffee-script": "^1.12.7",
"mocha": "~1.7.0"
"coffeescript": "^2.6.1",
"eslint": "^8.4.1",
"eslint-config-standard": "^16.0.3",
"mocha": "9.1.3"
},
"optionalDependencies": {},
"engines": {

@@ -34,0 +37,0 @@ "node": "*"

@@ -35,14 +35,16 @@ JSON structural diff

% json-diff --help
Usage: json-diff [-vjCk] first.json second.json
Usage: json-diff [-vCjfk] first.json second.json
Arguments:
first.json Old file
second.json New file
<first.json> Old file
<second.json> New file
General options:
-v, --verbose Output progress info
-C, --[no-]color Colored output
-j, --raw-json Display raw JSON encoding of the diff
-k, --keys-only Compare only the keys, ignore the differences in values
-h, --help Display this usage information
-v, --verbose Output progress info
-C, --[no-]color Colored output
-j, --raw-json Display raw JSON encoding of the diff
-f, --full Include the equal sections of the document, not just the deltas
-k, --keys-only Compare only the keys, ignore the differences in values
-h, --help Display this usage information

@@ -82,6 +84,56 @@ In javascript (ES5):

* fuzzy matching of modified array elements (when array elements are object hierarchies)
* compare only the json structure (keys), ignoring the values
* "keysOnly" option to compare only the json structure (keys), ignoring the values
* "full" option to output the entire json tree, not just the deltas
* reasonable test coverage (far from 100%, though)
Output Language in Raw-json mode ("full" mode)
--------
### ARRAYS
Unless two arrays are equal, all array elements are transformed into 2-tuple arrays:
* The first element is a one character string denoting the equality ('+', '-', '~', ' ')
* The second element is the old (-), new (+), altered sub-object (~), or unchanged (' ') value
>
json-diff.js --full --raw-json <(echo '[1,7,3]') <(echo '[1,2,3]')
[ [ " ", 1 ], [ "-", 7 ], [ "+", 2 ], [ " ", 3 ] ]
json-diff.js --full --raw-json <(echo '[1,["a","b"],4]') <(echo '[1,["a","c"],4]')
[ [ " ", 1 ], [ "~", [ [ " ", "a" ], [ "-", "b" ], [ "+", "c" ] ] ], [ " ", 4 ] ]
* If two arrays are equal, they are left as is.
### OBJECTS
Object property values:
* If equal, they are left as is
* Unequal scalar values are replaced by an object containing the old and new value:
>
json-diff.js --full --raw-json <(echo '{"a":4}') <(echo '{"a":5}')
{ "a": { "__old": 4, "__new": 5 } }
* Unequal arrays and objects are replaced by their diff:
>
json-diff.js --full --raw-json <(echo '{"a":[4,5]}') <(echo '{"a":[4,6]}')
{ "a": [ [ " ", 4 ], [ "-", 5 ], [ "+", 6 ] ] }
Object property keys:
* Object keys that are deleted or added between two objects are marked as such:
>
json-diff.js --full --raw-json <(echo '{"a":[4,5]}') <(echo '{"b":[4,5]}')
{ "a__deleted": [ 4, 5 ], "b__added": [ 4, 5 ] }
json-diff.js --full --raw-json <(echo '{"a":[4,5]}') <(echo '{"b":[4,6]}')
{ "a__deleted": [ 4, 5 ], "b__added": [ 4, 6 ] }
### Non-full mode
* In regular, delta-only (non-"full") mode, equal properties and values are omitted:
>
json-diff.js --raw-json <(echo '{"a":4, "b":6}') <(echo '{"a":5,"b":6}')
{ "a": { "__old": 4, "__new": 5 } }
* Equal array elements are represented by a one-tuple containing only a space " ":
>
json-diff.js --raw-json <(echo '[1,7,3]') <(echo '[1,2,3]')
[ [ " " ], [ "-", 7 ], [ "+", 2 ], [ " " ] ]
Tests

@@ -94,45 +146,127 @@ -----

Test coverage report:
Output:
npm run-script cov
json-diff@0.5.3 test
coffee -c test; mocha test/*.js
Output:
colorizeToArray
✔ should return ' <value>' for a scalar value
✔ should return ' <value>' for 'null' value
✔ should return ' <value>' for 'false' value
✔ should return '-<old value>', '+<new value>' for a scalar diff
✔ should return '-<old value>', '+<new value>' for 'null' and 'false' diff
✔ should return '-<removed key>: <removed value>' for an object diff with a removed key
✔ should return '+<added key>: <added value>' for an object diff with an added key
✔ should return '+<added key>: <added value>' for an object diff with an added key with 'null' value
✔ should return '+<added key>: <added value>' for an object diff with an added key with 'false' value
✔ should return '+<added key>: <added stringified value>' for an object diff with an added key and a non-scalar value
✔ should return ' <modified key>: <colorized diff>' for an object diff with a modified key
✔ should return '+<inserted item>' for an array diff
✔ should return '-<deleted item>' for an array diff
✔ should handle an array diff with subobject diff
colorize
✓ should return ' <value>' for a scalar value
✓ should return '-<old value>', '+<new value>' for a scalar diff
✓ should return '-<removed key>: <removed value>' for an object diff with a removed key
✓ should return '+<added key>: <added value>' for an object diff with an added key
✓ should return '+<added key>: <added stringified value>' for an object diff with an added key and a non-scalar value
✓ should return ' <modified key>: <colorized diff>' for an object diff with a modified key
✓ should return '+<inserted item>' for an array diff
✓ should return '-<deleted item>' for an array diff
✔ should return a string with ANSI escapes
✔ should return a string without ANSI escapes on { color: false }
diff
with simple scalar values
✓ should return undefined for two identical numbers
✓ should return undefined for two identical strings
✓ should return { __old: <old value>, __new: <new value> } object for two different numbers
with objects
✓ should return undefined for two objects with identical contents
✓ should return undefined for two object hierarchies with identical contents
✓ should return { <key>__deleted: <old value> } when the second object is missing a key
✓ should return { <key>__added: <new value> } when the first object is missing a key
✓ should return { <key>: { __old: <old value>, __new: <new value> } } for two objects with diffent scalar values for a key
✓ should return { <key>: <diff> } with a recursive diff for two objects with diffent values for a key
with arrays of scalars
✓ should return undefined for two arrays with identical contents
✓ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✓ should return [..., ['+', <added item>], ...] for two arrays when the second one has an extra value
✓ should return [..., ['+', <added item>]] for two arrays when the second one has an extra value at the end (edge case test)
with arrays of objects
✓ should return undefined for two arrays with identical contents
✓ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✓ should return [..., ['+', <added item>], ...] for two arrays when the second array has an extra value
✓ should return [..., ['~', <diff>], ...] for two arrays when an item has been modified (note: involves a crazy heuristic)
with simple scalar values
✔ should return undefined for two identical numbers
✔ should return undefined for two identical strings
✔ should return { __old: <old value>, __new: <new value> } object for two different numbers
with objects
✔ should return undefined for two empty objects
✔ should return undefined for two objects with identical contents
✔ should return undefined for two object hierarchies with identical contents
✔ should return { <key>__deleted: <old value> } when the second object is missing a key
✔ should return { <key>__added: <new value> } when the first object is missing a key
✔ should return { <key>: { __old: <old value>, __new: <new value> } } for two objects with different scalar values for a key
✔ should return { <key>: <diff> } with a recursive diff for two objects with different values for a key
with arrays of scalars
✔ should return undefined for two arrays with identical contents
✔ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✔ should return [..., ['+', <added item>], ...] for two arrays when the second one has an extra value
✔ should return [..., ['+', <added item>]] for two arrays when the second one has an extra value at the end (edge case test)
with arrays of objects
✔ should return undefined for two arrays with identical contents
✔ should return undefined for two arrays with identical, empty object contents
✔ should return undefined for two arrays with identical, empty array contents
✔ should return undefined for two arrays with identical array contents including 'null'
✔ should return undefined for two arrays with identical, repeated contents
✔ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✔ should return [..., ['+', <added item>], ...] for two arrays when the second array has an extra value
✔ should return [['+', <added item>], ..., ['+', <added item>]] for two arrays containing objects of 3 or more properties when the second array has extra values (fixes issue #57)
✔ should return [..., ['+', <added item>], ...] for two arrays when the second array has a new but nearly identical object added
✔ should return [..., ['~', <diff>], ...] for two arrays when an item has been modified
✔ 25 tests complete (12ms)
diff({full: true})
with simple scalar values
✔ should return the number for two identical numbers
✔ should return the string for two identical strings
✔ should return { __old: <old value>, __new: <new value> } object for two different numbers
with objects
✔ should return an empty object for two empty objects
✔ should return the object for two objects with identical contents
✔ should return the object for two object hierarchies with identical contents
✔ should return { <key>__deleted: <old value>, <remaining properties>} when the second object is missing a key
✔ should return { <key>__added: <new value>, <remaining properties> } when the first object is missing a key
✔ should return { <key>: { __old: <old value>, __new: <new value> } } for two objects with different scalar values for a key
✔ should return { <key>: <diff>, <equal properties> } with a recursive diff for two objects with different values for a key
✔ should return { <key>: <diff>, <equal properties> } with a recursive diff for two objects with different values for a key
with arrays of scalars
✔ should return an array showing no changes for any element for two arrays with identical contents
✔ should return [[' ', <unchanged item>], ['-', <removed item>], [' ', <unchanged item>]] for two arrays when the second array is missing a value
✔ should return [' ', <unchanged item>], ['+', <added item>], [' ', <unchanged item>]] for two arrays when the second one has an extra value
✔ should return [' ', <unchanged item>s], ['+', <added item>]] for two arrays when the second one has an extra value at the end (edge case test)
with arrays of objects
✔ should return an array of unchanged elements for two arrays with identical contents
✔ should return an array with an unchanged element for two arrays with identical, empty object contents
✔ should return an array with an unchanged element for two arrays with identical, empty array contents
✔ should return an array of unchanged elements for two arrays with identical array contents including 'null'
✔ should return an array of unchanged elements for two arrays with identical, repeated contents
✔ should return [[' ', <unchanged item>], ['-', <removed item>], [' ', <unchanged item>]] for two arrays when the second array is missing a value
✔ should return [[' ', <unchanged item>], ['+', <added item>], [' ', <unchanged item>]] for two arrays when the second array has an extra value
✔ should return [[' ', <unchanged item>], ['+', <added item>], [' ', <unchanged item>]] for two arrays when the second array has a new but nearly identical object added
✔ should return [[' ', <unchanged item>], ['~', <diff>], [' ', <unchanged item>]] for two arrays when an item has been modified
diff({keysOnly: true})
with simple scalar values
✔ should return undefined for two identical numbers
✔ should return undefined for two identical strings
✔ should return undefined object for two different numbers
with objects
✔ should return undefined for two empty objects
✔ should return undefined for two objects with identical contents
✔ should return undefined for two object hierarchies with identical contents
✔ should return { <key>__deleted: <old value> } when the second object is missing a key
✔ should return { <key>__added: <new value> } when the first object is missing a key
✔ should return undefined for two objects with different scalar values for a key
✔ should return undefined with a recursive diff for two objects with different values for a key
✔ should return { <key>: <diff> } with a recursive diff when second object is missing a key and two objects with different values for a key
with arrays of scalars
✔ should return undefined for two arrays with identical contents
✔ should return undefined for two arrays with when an item has been modified
✔ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✔ should return [..., ['+', <added item>], ...] for two arrays when the second one has an extra value
✔ should return [..., ['+', <added item>]] for two arrays when the second one has an extra value at the end (edge case test)
with arrays of objects
✔ should return undefined for two arrays with identical contents
✔ should return undefined for two arrays with identical, empty object contents
✔ should return undefined for two arrays with identical, empty array contents
✔ should return undefined for two arrays with identical, repeated contents
✔ should return [..., ['-', <removed item>], ...] for two arrays when the second array is missing a value
✔ should return [..., ['+', <added item>], ...] for two arrays when the second array has an extra value
✔ should return [..., ['~', <diff>], ...] for two arrays when an item has been modified
diffString
✔ should produce the expected result for the example JSON files
✔ should produce the expected colored result for the example JSON files
✔ return an empty string when no diff found
90 passing (42ms)
Change Log
----------
* 0.6.0 Convert project code to ES6
* 0.5.5 Fix bug in scalarize fuzzy compare logic

@@ -139,0 +273,0 @@ * 0.4.0 Add --keys-only feature

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc