UNPKG

2.01 kBJavaScriptView Raw
1var flat = require('flat');
2var traverse = require('traverse');
3
4var isArray = Array.isArray;
5var isObject = function(obj) {
6 return obj !== null && (typeof obj === 'object') && obj.constructor === Object;
7};
8
9var flatten = function(o, all, prefixes) {
10 var result = {};
11 var add = function(path, value) {
12 var key = path.join('.');
13 var l = 0;
14
15 for(var i = 0; i < path.length - 1; i++) {
16 l += path[i].length;
17 prefixes[key.slice(0, l + i)] = true;
18 }
19
20 all[key] = true;
21 result[key] = value;
22 };
23
24 traverse(o).forEach(function(obj) {
25 if(!isArray(obj) && !isObject(obj)) {
26 if(obj === null || obj === undefined) {
27 return;
28 }
29
30 var v = obj.constructor.name + '#' + obj;
31 add(this.path, v);
32
33 this.block();
34 } else if(this.isLeaf && !this.isRoot) {
35 // Empty array or object
36 add(this.path, isArray(obj) ? 'Array#[]' : 'Object#{}');
37 }
38 });
39
40 return result;
41};
42
43var diff = function(a, b, options) {
44 options = options || {};
45
46 var all = {};
47 var prefixes = {};
48
49 a = flatten(a, all, prefixes);
50 b = flatten(b, all, prefixes);
51
52 var result = options.accumulate || {};
53
54 Object.keys(all).forEach(function(k) {
55 if(prefixes[k]) {
56 return;
57 }
58 if (a[k] === b[k]) {
59 return;
60 }
61
62 var resultK = options.group ? k.replace(/\.\d+(\.|$)/, '.[*]$1') : k;
63 var r = result[resultK];
64
65 result[resultK] = r = r || { added: 0, removed: 0, updated: 0 };
66
67 if(!(k in b)) {
68 return r.removed++;
69 }
70 if(!(k in a)) {
71 return r.added++;
72 }
73
74 r.updated++;
75 });
76
77 return result;
78};
79
80var deep = function(a, b) {
81 var change = diff(a, b);
82
83 Object.keys(change).forEach(function(key) {
84 var c = change[key];
85 change[key] = (c.added && 'added') || (c.removed && 'removed') || (c.updated && 'updated');
86 });
87
88 change = flat.unflatten(change);
89 change = traverse(change).map(function(obj) {
90 if(!Array.isArray(obj)) {
91 return;
92 }
93
94 this.update(obj.filter(function(value) {
95 return value !== undefined;
96 }));
97 });
98
99 return change;
100};
101
102diff.deep = deep;
103
104module.exports = diff;