index.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Generated by CoffeeScript 1.12.7
  2. (function() {
  3. var SequenceMatcher, arrayDiff, colorize, descalarize, diff, diffScore, diffString, diffWithScore, extendedTypeOf, findMatchingObject, isScalar, isScalarized, objectDiff, scalarize,
  4. hasProp = {}.hasOwnProperty;
  5. SequenceMatcher = require('difflib').SequenceMatcher;
  6. extendedTypeOf = require('./util').extendedTypeOf;
  7. colorize = require('./colorize').colorize;
  8. isScalar = function(obj) {
  9. return typeof obj !== 'object' || obj === null;
  10. };
  11. objectDiff = function(obj1, obj2, options) {
  12. var change, key, ref, ref1, result, score, subscore, value1, value2;
  13. if (options == null) {
  14. options = {};
  15. }
  16. result = {};
  17. score = 0;
  18. for (key in obj1) {
  19. if (!hasProp.call(obj1, key)) continue;
  20. value1 = obj1[key];
  21. if (!(!(key in obj2))) {
  22. continue;
  23. }
  24. result[key + "__deleted"] = value1;
  25. score -= 30;
  26. }
  27. for (key in obj2) {
  28. if (!hasProp.call(obj2, key)) continue;
  29. value2 = obj2[key];
  30. if (!(!(key in obj1))) {
  31. continue;
  32. }
  33. result[key + "__added"] = value2;
  34. score -= 30;
  35. }
  36. for (key in obj1) {
  37. if (!hasProp.call(obj1, key)) continue;
  38. value1 = obj1[key];
  39. if (!(key in obj2)) {
  40. continue;
  41. }
  42. score += 20;
  43. value2 = obj2[key];
  44. ref = diffWithScore(value1, value2, options), subscore = ref[0], change = ref[1];
  45. if (change) {
  46. result[key] = change;
  47. }
  48. score += Math.min(20, Math.max(-10, subscore / 5));
  49. }
  50. if (Object.keys(result).length === 0) {
  51. ref1 = [100 * Math.max(Object.keys(obj1).length, 0.5), void 0], score = ref1[0], result = ref1[1];
  52. } else {
  53. score = Math.max(0, score);
  54. }
  55. return [score, result];
  56. };
  57. findMatchingObject = function(item, index, fuzzyOriginals) {
  58. var bestMatch, candidate, indexDistance, key, matchIndex, score;
  59. bestMatch = null;
  60. matchIndex = 0;
  61. for (key in fuzzyOriginals) {
  62. if (!hasProp.call(fuzzyOriginals, key)) continue;
  63. candidate = fuzzyOriginals[key];
  64. if (!(key !== '__next')) {
  65. continue;
  66. }
  67. indexDistance = Math.abs(matchIndex - index);
  68. if (extendedTypeOf(item) === extendedTypeOf(candidate)) {
  69. score = diffScore(item, candidate);
  70. if (!bestMatch || score > bestMatch.score || (score === bestMatch.score && indexDistance < bestMatch.indexDistance)) {
  71. bestMatch = {
  72. score: score,
  73. key: key,
  74. indexDistance: indexDistance
  75. };
  76. }
  77. }
  78. matchIndex++;
  79. }
  80. return bestMatch;
  81. };
  82. scalarize = function(array, originals, fuzzyOriginals) {
  83. var bestMatch, fuzzyMatches, index, item, k, key, keyScores, l, len, len1, match, results;
  84. fuzzyMatches = [];
  85. if (fuzzyOriginals) {
  86. keyScores = {};
  87. for (index = k = 0, len = array.length; k < len; index = ++k) {
  88. item = array[index];
  89. if (isScalar(item)) {
  90. continue;
  91. }
  92. bestMatch = findMatchingObject(item, index, fuzzyOriginals);
  93. if (!keyScores[bestMatch.key] || bestMatch.score > keyScores[bestMatch.key].score) {
  94. keyScores[bestMatch.key] = {
  95. score: bestMatch.score,
  96. index: index
  97. };
  98. }
  99. }
  100. for (key in keyScores) {
  101. match = keyScores[key];
  102. fuzzyMatches[match.index] = key;
  103. }
  104. }
  105. results = [];
  106. for (index = l = 0, len1 = array.length; l < len1; index = ++l) {
  107. item = array[index];
  108. if (isScalar(item)) {
  109. results.push(item);
  110. } else {
  111. key = fuzzyMatches[index] || "__$!SCALAR" + originals.__next++;
  112. originals[key] = item;
  113. results.push(key);
  114. }
  115. }
  116. return results;
  117. };
  118. isScalarized = function(item, originals) {
  119. return (typeof item === 'string') && (item in originals);
  120. };
  121. descalarize = function(item, originals) {
  122. if (isScalarized(item, originals)) {
  123. return originals[item];
  124. } else {
  125. return item;
  126. }
  127. };
  128. arrayDiff = function(obj1, obj2, options) {
  129. 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;
  130. if (options == null) {
  131. options = {};
  132. }
  133. originals1 = {
  134. __next: 1
  135. };
  136. seq1 = scalarize(obj1, originals1);
  137. originals2 = {
  138. __next: originals1.__next
  139. };
  140. seq2 = scalarize(obj2, originals2, originals1);
  141. opcodes = new SequenceMatcher(null, seq1, seq2).getOpcodes();
  142. result = [];
  143. score = 0;
  144. allEqual = true;
  145. for (k = 0, len = opcodes.length; k < len; k++) {
  146. ref = opcodes[k], op = ref[0], i1 = ref[1], i2 = ref[2], j1 = ref[3], j2 = ref[4];
  147. if (!(op === 'equal' || (options.keysOnly && op === 'replace'))) {
  148. allEqual = false;
  149. }
  150. switch (op) {
  151. case 'equal':
  152. for (i = l = ref1 = i1, ref2 = i2; ref1 <= ref2 ? l < ref2 : l > ref2; i = ref1 <= ref2 ? ++l : --l) {
  153. item = seq1[i];
  154. if (isScalarized(item, originals1)) {
  155. if (!isScalarized(item, originals2)) {
  156. throw new AssertionError("internal bug: isScalarized(item, originals1) != isScalarized(item, originals2) for item " + (JSON.stringify(item)));
  157. }
  158. item1 = descalarize(item, originals1);
  159. item2 = descalarize(item, originals2);
  160. change = diff(item1, item2, options);
  161. if (change) {
  162. result.push(['~', change]);
  163. allEqual = false;
  164. } else {
  165. result.push([' ']);
  166. }
  167. } else {
  168. result.push([' ', item]);
  169. }
  170. score += 10;
  171. }
  172. break;
  173. case 'delete':
  174. for (i = m = ref3 = i1, ref4 = i2; ref3 <= ref4 ? m < ref4 : m > ref4; i = ref3 <= ref4 ? ++m : --m) {
  175. result.push(['-', descalarize(seq1[i], originals1)]);
  176. score -= 5;
  177. }
  178. break;
  179. case 'insert':
  180. for (j = n = ref5 = j1, ref6 = j2; ref5 <= ref6 ? n < ref6 : n > ref6; j = ref5 <= ref6 ? ++n : --n) {
  181. result.push(['+', descalarize(seq2[j], originals2)]);
  182. score -= 5;
  183. }
  184. break;
  185. case 'replace':
  186. if (!options.keysOnly) {
  187. for (i = o = ref7 = i1, ref8 = i2; ref7 <= ref8 ? o < ref8 : o > ref8; i = ref7 <= ref8 ? ++o : --o) {
  188. result.push(['-', descalarize(seq1[i], originals1)]);
  189. score -= 5;
  190. }
  191. for (j = p = ref9 = j1, ref10 = j2; ref9 <= ref10 ? p < ref10 : p > ref10; j = ref9 <= ref10 ? ++p : --p) {
  192. result.push(['+', descalarize(seq2[j], originals2)]);
  193. score -= 5;
  194. }
  195. } else {
  196. for (i = q = ref11 = i1, ref12 = i2; ref11 <= ref12 ? q < ref12 : q > ref12; i = ref11 <= ref12 ? ++q : --q) {
  197. change = diff(descalarize(seq1[i], originals1), descalarize(seq2[i - i1 + j1], originals2), options);
  198. if (change) {
  199. result.push(['~', change]);
  200. allEqual = false;
  201. } else {
  202. result.push([' ']);
  203. }
  204. }
  205. }
  206. }
  207. }
  208. if (allEqual || (opcodes.length === 0)) {
  209. result = void 0;
  210. score = 100;
  211. } else {
  212. score = Math.max(0, score);
  213. }
  214. return [score, result];
  215. };
  216. diffWithScore = function(obj1, obj2, options) {
  217. var type1, type2;
  218. if (options == null) {
  219. options = {};
  220. }
  221. type1 = extendedTypeOf(obj1);
  222. type2 = extendedTypeOf(obj2);
  223. if (type1 === type2) {
  224. switch (type1) {
  225. case 'object':
  226. return objectDiff(obj1, obj2, options);
  227. case 'array':
  228. return arrayDiff(obj1, obj2, options);
  229. }
  230. }
  231. if (!options.keysOnly) {
  232. if (obj1 !== obj2) {
  233. return [
  234. 0, {
  235. __old: obj1,
  236. __new: obj2
  237. }
  238. ];
  239. } else {
  240. return [100, void 0];
  241. }
  242. } else {
  243. return [100, void 0];
  244. }
  245. };
  246. diff = function(obj1, obj2, options) {
  247. var change, ref, score;
  248. if (options == null) {
  249. options = {};
  250. }
  251. ref = diffWithScore(obj1, obj2, options), score = ref[0], change = ref[1];
  252. return change;
  253. };
  254. diffScore = function(obj1, obj2, options) {
  255. var change, ref, score;
  256. if (options == null) {
  257. options = {};
  258. }
  259. ref = diffWithScore(obj1, obj2, options), score = ref[0], change = ref[1];
  260. return score;
  261. };
  262. diffString = function(obj1, obj2, colorizeOptions, diffOptions) {
  263. if (diffOptions == null) {
  264. diffOptions = {};
  265. }
  266. return colorize(diff(obj1, obj2, diffOptions), colorizeOptions);
  267. };
  268. module.exports = {
  269. diff: diff,
  270. diffString: diffString
  271. };
  272. }).call(this);