Skip to content

feat: add JSON Diff Viewer tool#35

Open
naowas wants to merge 2 commits intome-shaon:mainfrom
naowas:main
Open

feat: add JSON Diff Viewer tool#35
naowas wants to merge 2 commits intome-shaon:mainfrom
naowas:main

Conversation

@naowas
Copy link
Copy Markdown

@naowas naowas commented Mar 30, 2026

This PR features a new JSON Diff Viewer tool that enables users to compare two JSON objects (Original vs. Modified) and see differences in a clear, human-readable format.

Included:

  • New JSON Diff Viewer tool
  • JSON validation and error display
  • Compare action with easy-to-readable diff output (added/removed/changed)
  • Copy buttons, sample JSON, swap, etc.
2

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a JSON Diff Viewer tool, featuring a React-based UI for side-by-side comparisons and a utility for calculating structural differences in JSON data. The implementation includes support for identifying added, removed, and changed fields, along with comprehensive unit tests. Review feedback highlights opportunities to improve the user experience by handling empty inputs more gracefully, enhance maintainability by replacing magic numbers with constants, and simplify redundant logic in the path generation utility.

Comment on lines +110 to +124
try {
parsedOriginal = JSON.parse(originalInput);
setOriginalInput(JSON.stringify(parsedOriginal, null, 2));
} catch (error) {
setOriginalError(`Invalid JSON: ${getErrorMessage(error)}`);
validationFailed = true;
}

try {
parsedModified = JSON.parse(modifiedInput);
setModifiedInput(JSON.stringify(parsedModified, null, 2));
} catch (error) {
setModifiedError(`Invalid JSON: ${getErrorMessage(error)}`);
validationFailed = true;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

JSON.parse will throw an error for an empty string, which might not be the desired behavior if a user intentionally leaves an input blank. To improve the user experience, you could treat empty inputs as null (a valid JSON value) for the comparison. This avoids showing an error for an intentionally empty input field.

    try {
      if (originalInput.trim()) {
        parsedOriginal = JSON.parse(originalInput);
        setOriginalInput(JSON.stringify(parsedOriginal, null, 2));
      } else {
        parsedOriginal = null;
      }
    } catch (error) {
      setOriginalError(`Invalid JSON: ${getErrorMessage(error)}`);
      validationFailed = true;
    }

    try {
      if (modifiedInput.trim()) {
        parsedModified = JSON.parse(modifiedInput);
        setModifiedInput(JSON.stringify(parsedModified, null, 2));
      } else {
        parsedModified = null;
      }
    } catch (error) {
      setModifiedError(`Invalid JSON: ${getErrorMessage(error)}`);
      validationFailed = true;
    }

setTimeout(() => {
const result = diffJsonValues(parsedOriginal, parsedModified, {
includeUnchanged: true,
maxEntries: 10000,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The maxEntries limit is hardcoded as 10000. This "magic number" also appears in the truncation message on line 318. To improve maintainability and ensure consistency, it's best to define this value as a constant.

I recommend exporting a constant like MAX_DIFF_ENTRIES from src/utils/json-diff.ts and using it in this component for both the maxEntries option and the truncation message.


function appendPath(parent: string, segment: string): string {
if (parent === "$") {
return segment.startsWith("[") ? `$${segment}` : `$${segment}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ternary operator here is redundant because both branches evaluate to the same string '$${segment}'. This can be simplified to improve readability.

Suggested change
return segment.startsWith("[") ? `$${segment}` : `$${segment}`;
return `$${segment}`;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant