Description
Hi, we forked your library in order to make a React component based on it:
We made a couple of changes to the original library behavior in relation to elisions rendering you might be also interested in adding to back to your library:
-
Rendering elisions for objects the similar way they are rendered for arrays. For our use case we found it confusing that the untouched keys are just not showing up in the diff like they didn’t exist. And we though it would be very intuitive to render the placeholders/elisions for extra untouched fields the same way it’s already done for arrays.
We added an extra option
showElisionsForObjects
which is a boolean we keep turned on by default. Setting it tofalse
allows to use the original behavior of json-diff. -
Customizable elisions renderer. The “entries” word is hard-coded into the elision template. We though it would be nice to have it customizable in case anyone would need to add a localization other than English. So we added a generic way of customizing the elisions renderer by providing a renderer function.
Custom renderer takes the elisions counter value, and just forwarded
maxElisions
value for convenience which can be just ignored. It can return a list ofstring
s which will translate into multiple lines. Or just a singlestring
which will transform into a single line (the same can be achieved by providing a list of one singlestring
).renderElision?: (elisionCount: number, maxElisions: number) => string | string[];
Here is a patch with the essentials of the change (the patch has a couple of unrelated lines for the piece of React-related code, just ignore them): json-diff-react-elisions.patch.zip
The patch is produced by this command ran against https://github.com/relex/json-diff-react repo:
git diff 6246112 3077bf9 src/JsonDiff/Internal/json-diff.js src/JsonDiff/Internal/colorize.jsx src/JsonDiff/Internal/utils.ts
The patch contents:
diff --git a/src/JsonDiff/Internal/colorize.jsx b/src/JsonDiff/Internal/colorize.jsx
index 7ba5ccd..c29bc50 100644
--- a/src/JsonDiff/Internal/colorize.jsx
+++ b/src/JsonDiff/Internal/colorize.jsx
@@ -3,7 +3,7 @@
// The 'colorize' function was adapted from console rendering to browser
// rendering - it now returns a JSX.Element.
-import { extendedTypeOf } from './utils';
+import { extendedTypeOf, elisionMarker } from './utils';
import React from 'react';
const subcolorizeToCallback = function (options, key, diff, output, color, indent) {
@@ -11,14 +11,20 @@ const subcolorizeToCallback = function (options, key, diff, output, color, inden
const prefix = key ? `${key}: ` : '';
const subindent = indent + ' ';
+ const maxElisions = options.maxElisions === undefined ? Infinity : options.maxElisions;
+
+ const renderElision =
+ options.renderElision ??
+ ((n, max) => (n < max ? [...Array(n)].map(() => '...') : `... (${n} entries)`));
+
const outputElisions = (n) => {
- const maxElisions = options.maxElisions === undefined ? Infinity : options.maxElisions;
- if (n < maxElisions) {
- for (let i = 0; i < n; i++) {
- output(' ', subindent + '...');
- }
+ const elisions = renderElision(n, maxElisions);
+ if (typeof elisions === 'string') {
+ output(' ', subindent + elisions);
} else {
- output(' ', subindent + `... (${n} entries)`);
+ elisions.forEach((x) => {
+ output(' ', subindent + x);
+ });
}
};
@@ -29,9 +35,23 @@ const subcolorizeToCallback = function (options, key, diff, output, color, inden
return subcolorizeToCallback(options, key, diff.__new, output, '+', indent);
} else {
output(color, `${indent}${prefix}{`);
+
+ // Elisions are added in “json-diff” module depending on the option.
+ let elisionCount = 0;
+
for (const subkey of Object.keys(diff)) {
let m;
subvalue = diff[subkey];
+
+ // Handle elisions
+ if (subvalue === elisionMarker) {
+ elisionCount++;
+ continue;
+ } else if (elisionCount > 0) {
+ outputElisions(elisionCount);
+ elisionCount = 0;
+ }
+
if ((m = subkey.match(/^(.*)__deleted$/))) {
subcolorizeToCallback(options, m[1], subvalue, output, '-', subindent);
} else if ((m = subkey.match(/^(.*)__added$/))) {
@@ -40,6 +60,10 @@ const subcolorizeToCallback = function (options, key, diff, output, color, inden
subcolorizeToCallback(options, subkey, subvalue, output, color, subindent);
}
}
+
+ // Handle elisions
+ if (elisionCount > 0) outputElisions(elisionCount);
+
return output(color, `${indent}}`);
}
@@ -105,10 +129,10 @@ const colorizeToCallback = (diff, options, output) =>
export const colorize = function (diff, options = {}, customization) {
const output = [];
- let className;
- let style;
-
colorizeToCallback(diff, options, function (color, line) {
+ let className;
+ let style;
+
if (color === ' ') {
className = customization.unchangedClassName;
style = customization.unchangedLineStyle;
@@ -122,7 +146,7 @@ export const colorize = function (diff, options = {}, customization) {
let renderedLine = (
<div className={className} style={style} key={output.length}>
- {line + '\r\n'}
+ {line}
</div>
);
@@ -131,7 +155,7 @@ export const colorize = function (diff, options = {}, customization) {
return (
<div className={customization.frameClassName} style={customization.frameStyle}>
- <pre>{output}</pre>
+ {output}
</div>
);
};
diff --git a/src/JsonDiff/Internal/json-diff.js b/src/JsonDiff/Internal/json-diff.js
index f5037b8..39da9a5 100644
--- a/src/JsonDiff/Internal/json-diff.js
+++ b/src/JsonDiff/Internal/json-diff.js
@@ -1,13 +1,17 @@
// This is copied from 'json-diff' package ('lib/index.js') with minor
// modifications.
-import { extendedTypeOf } from './utils';
+import { extendedTypeOf, elisionMarker } from './utils';
import { SequenceMatcher } from '@ewoudenberg/difflib';
export default class JsonDiff {
constructor(options) {
options.outputKeys = options.outputKeys || [];
options.excludeKeys = options.excludeKeys || [];
+
+ // Rendering ”...” elisions in the same way as for arrays
+ options.showElisionsForObjects = options.showElisionsForObjects ?? true;
+
this.options = options;
}
@@ -55,6 +59,8 @@ export default class JsonDiff {
equal = false;
} else if (this.options.full || this.options.outputKeys.includes(key)) {
result[key] = value1;
+ } else if (this.options.showElisionsForObjects) {
+ result[key] = elisionMarker;
}
// console.log(`key ${key} change.score=${change.score} ${change.result}`)
score += Math.min(20, Math.max(-10, change.score / 5)); // BATMAN!
diff --git a/src/JsonDiff/Internal/utils.ts b/src/JsonDiff/Internal/utils.ts
index 29fba60..a9005b3 100644
--- a/src/JsonDiff/Internal/utils.ts
+++ b/src/JsonDiff/Internal/utils.ts
@@ -27,3 +27,11 @@ export const roundObj = function (data: any, precision: number) {
return data;
}
};
+
+// A hacky marker for “...” elisions for object keys.
+// This feature wasn’t present in the original “json-diff” library.
+// A unique identifier used as a value for the “elisioned” object keys.
+//
+// Read more about “Symbol”s here:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
+export const elisionMarker = Symbol('json-diff-react--elision-marker');