{"id":83,"date":"2026-03-18T12:41:04","date_gmt":"2026-03-18T12:41:04","guid":{"rendered":"https:\/\/tools.sanepo.com\/?post_type=tool&#038;p=83"},"modified":"2026-03-18T12:41:05","modified_gmt":"2026-03-18T12:41:05","slug":"json-diff-tool","status":"publish","type":"tool","link":"https:\/\/tools.sanepo.com\/hi\/features\/json-diff-tool\/","title":{"rendered":"Free Advanced JSON Diff Tool \u2013 Compare &amp; Analyze JSON Online"},"content":{"rendered":"\n<div id=\"wpnt-json-diff\">\n    <!-- Header -->\n    <div class=\"wpnt-header\">\n        <h3>Sanepo Tools &#8211; JSON Diff<\/h3>\n        <p>Advanced JSON comparison tool. Deep compare, validate, and analyze structures instantly.<\/p>\n        <span class=\"wpnt-privacy-badge\">\ud83d\udd12 100% Secure Local Processing<\/span>\n    <\/div>\n\n    <!-- Advanced Settings Grid -->\n    <div class=\"wpnt-settings-panel\">\n        <div class=\"wpnt-label\">Comparison Settings<\/div>\n        <div class=\"wpnt-settings-grid\">\n            <label class=\"wpnt-checkbox-label\" title=\"Check exact data types (e.g., 1 vs '1')\">\n                <input type=\"checkbox\" id=\"setting-strict\" checked>\n                <span class=\"wpnt-checkbox-custom\"><\/span>\n                Strict Type Checking\n            <\/label>\n            <label class=\"wpnt-checkbox-label\" title=\"Ignore uppercase\/lowercase differences in strings\">\n                <input type=\"checkbox\" id=\"setting-ignore-case\">\n                <span class=\"wpnt-checkbox-custom\"><\/span>\n                Ignore Case (Strings)\n            <\/label>\n        <\/div>\n    <\/div>\n\n    <!-- Input Section -->\n    <div class=\"wpnt-json-inputs\">\n        <!-- Original JSON -->\n        <div class=\"wpnt-input-group\">\n            <div class=\"wpnt-toolbar\">\n                <span class=\"wpnt-toolbar-title\">Original JSON<\/span>\n                <div class=\"wpnt-toolbar-actions\">\n                    <button class=\"wpnt-btn wpnt-btn-tiny\" id=\"btn-sample-left\">Sample<\/button>\n                    <button class=\"wpnt-btn wpnt-btn-tiny wpnt-btn-danger\" id=\"btn-clear-left\">Clear<\/button>\n                    <button class=\"wpnt-btn wpnt-btn-tiny wpnt-btn-accent\" id=\"btn-format-left\">Format<\/button>\n                <\/div>\n            <\/div>\n            <textarea id=\"json-left\" placeholder='{\"example\": \"Paste original JSON here...\"}' spellcheck=\"false\"><\/textarea>\n            <div id=\"error-left\" class=\"wpnt-error-msg\"><\/div>\n        <\/div>\n\n        <!-- Swap Button -->\n        <div class=\"wpnt-swap-container\">\n            <button class=\"wpnt-btn-icon\" id=\"btn-swap\" title=\"Swap JSONs\">\n                <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m3 16 4 4 4-4\"\/><path d=\"M7 20V4\"\/><path d=\"m21 8-4-4-4 4\"\/><path d=\"M17 4v16\"\/><\/svg>\n            <\/button>\n        <\/div>\n\n        <!-- Modified JSON -->\n        <div class=\"wpnt-input-group\">\n            <div class=\"wpnt-toolbar\">\n                <span class=\"wpnt-toolbar-title\">Modified JSON<\/span>\n                <div class=\"wpnt-toolbar-actions\">\n                    <button class=\"wpnt-btn wpnt-btn-tiny\" id=\"btn-sample-right\">Sample<\/button>\n                    <button class=\"wpnt-btn wpnt-btn-tiny wpnt-btn-danger\" id=\"btn-clear-right\">Clear<\/button>\n                    <button class=\"wpnt-btn wpnt-btn-tiny wpnt-btn-accent\" id=\"btn-format-right\">Format<\/button>\n                <\/div>\n            <\/div>\n            <textarea id=\"json-right\" placeholder='{\"example\": \"Paste modified JSON here...\"}' spellcheck=\"false\"><\/textarea>\n            <div id=\"error-right\" class=\"wpnt-error-msg\"><\/div>\n        <\/div>\n    <\/div>\n\n    <!-- Action Button -->\n    <button id=\"btn-compare\" class=\"wpnt-btn wpnt-btn-main\">\n        <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M16 3h5v5\"\/><path d=\"M8 3H3v5\"\/><path d=\"M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3\"\/><path d=\"m15 9 6-6\"\/><\/svg>\n        Execute Deep Compare\n    <\/button>\n\n    <!-- Results Section -->\n    <div id=\"diff-results\" class=\"wpnt-results\">\n        <div class=\"wpnt-results-header\">\n            <div>\n                <div class=\"wpnt-label\">Comparison Result<\/div>\n                <div class=\"wpnt-legend\">\n                    <span class=\"legend-item legend-added\">Added<\/span>\n                    <span class=\"legend-item legend-removed\">Removed<\/span>\n                    <span class=\"legend-item legend-changed\">Changed<\/span>\n                    <span class=\"legend-item legend-unchanged\">Unchanged<\/span>\n                <\/div>\n            <\/div>\n            <div class=\"wpnt-results-actions\">\n                <button class=\"wpnt-btn wpnt-btn-tiny\" id=\"btn-expand-all\">Expand All<\/button>\n                <button class=\"wpnt-btn wpnt-btn-tiny\" id=\"btn-collapse-all\">Collapse All<\/button>\n                <button class=\"wpnt-btn wpnt-btn-tiny wpnt-btn-accent\" id=\"btn-copy-diff\">Copy Text<\/button>\n            <\/div>\n        <\/div>\n        \n        <div class=\"wpnt-diff-viewer-wrapper\">\n            <div id=\"diff-viewer\" class=\"wpnt-diff-viewer\"><\/div>\n        <\/div>\n    <\/div>\n\n    <style>\n        @import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap');\n\n        \/* CSS Variables Default *\/\n        #wpnt-json-diff {\n            --bg-primary: #ffffff;\n            --bg-secondary: #f8fafc;\n            --border-color: #e2e8f0;\n            --accent-color: #4361ee;\n            --accent-hover: #3a56d4;\n            --glass-bg: rgba(255, 255, 255, 0.85);\n            --card-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n            --transition: all 0.2s ease;\n            \n            --wpnt-success: #10b981;\n            --wpnt-danger: #ef4444;\n            --wpnt-warning: #f59e0b;\n            --wpnt-radius-lg: 16px;\n            --wpnt-radius-md: 12px;\n            --wpnt-radius-sm: 8px;\n            \n            --diff-added-bg: rgba(16, 185, 129, 0.12);\n            --diff-added-text: #059669;\n            --diff-removed-bg: rgba(239, 68, 68, 0.12);\n            --diff-removed-text: #dc2626;\n            --diff-changed-bg: rgba(245, 158, 11, 0.12);\n            --diff-changed-text: #d97706;\n            --diff-unchanged-text: #64748b;\n            --diff-key-color: #0f172a;\n            \n            --text-main: #1e293b;\n            \n            font-family: 'Inter', sans-serif;\n            color: var(--text-main) !important;\n            width: 100%;\n            margin: 30px auto;\n            background: transparent;\n            border: none;\n            border-radius: 0;\n            box-shadow: none;\n            padding: 0;\n            box-sizing: border-box;\n            line-height: 1.5;\n        }\n\n        #wpnt-json-diff * { box-sizing: border-box; }\n\n        \/* Sinkronisasi Dark Mode dengan Class Website (Prioritas Utama) *\/\n        html.dark #wpnt-json-diff,\n        body.dark #wpnt-json-diff,\n        body.dark-mode #wpnt-json-diff,\n        [data-theme=\"dark\"] #wpnt-json-diff {\n            --bg-primary: #0f172a;\n            --bg-secondary: #1e293b;\n            --border-color: #334155;\n            --glass-bg: rgba(15, 23, 42, 0.7);\n            --text-main: #f1f5f9;\n            \n            --diff-added-bg: rgba(16, 185, 129, 0.2);\n            --diff-added-text: #34d399;\n            --diff-removed-bg: rgba(239, 68, 68, 0.2);\n            --diff-removed-text: #f87171;\n            --diff-changed-bg: rgba(245, 158, 11, 0.2);\n            --diff-changed-text: #fbbf24;\n            --diff-unchanged-text: #94a3b8;\n            --diff-key-color: #e2e8f0;\n        }\n\n        \/* Fallback OS Dark Mode HANYA jika website tidak diset manual ke Light Mode *\/\n        @media (prefers-color-scheme: dark) {\n            html:not(.light):not([data-theme=\"light\"]) #wpnt-json-diff {\n                --bg-primary: #0f172a;\n                --bg-secondary: #1e293b;\n                --border-color: #334155;\n                --glass-bg: rgba(15, 23, 42, 0.7);\n                --text-main: #f1f5f9;\n                \n                --diff-added-bg: rgba(16, 185, 129, 0.2);\n                --diff-added-text: #34d399;\n                --diff-removed-bg: rgba(239, 68, 68, 0.2);\n                --diff-removed-text: #f87171;\n                --diff-changed-bg: rgba(245, 158, 11, 0.2);\n                --diff-changed-text: #fbbf24;\n                --diff-unchanged-text: #94a3b8;\n                --diff-key-color: #e2e8f0;\n            }\n        }\n\n        \/* Basic Elements *\/\n        #wpnt-json-diff .wpnt-header { text-align: center; margin-bottom: 24px; }\n        #wpnt-json-diff h3 { margin: 0 0 8px 0; font-size: 1.75rem; font-weight: 700; letter-spacing: -0.025em; }\n        #wpnt-json-diff p { margin: 0; font-size: 0.95rem; opacity: 0.8; }\n        #wpnt-json-diff .wpnt-privacy-badge {\n            display: inline-block; background: rgba(16, 185, 129, 0.1); color: var(--wpnt-success);\n            border: 1px solid rgba(16, 185, 129, 0.2); padding: 6px 12px; border-radius: 20px;\n            font-size: 0.8rem; font-weight: 600; margin-top: 12px;\n        }\n\n        #wpnt-json-diff .wpnt-label {\n            font-weight: 700; font-size: 0.8rem; text-transform: uppercase;\n            letter-spacing: 0.05em; opacity: 0.7; margin-bottom: 8px;\n        }\n\n        \/* Settings Panel *\/\n        #wpnt-json-diff .wpnt-settings-panel {\n            background-color: var(--bg-primary) !important;\n            color: var(--text-main) !important;\n            padding: 16px 20px; border-radius: var(--wpnt-radius-md);\n            border: 1px solid var(--border-color); margin-bottom: 24px; box-shadow: var(--card-shadow);\n        }\n        #wpnt-json-diff .wpnt-settings-grid {\n            display: flex; gap: 24px; flex-wrap: wrap;\n        }\n        #wpnt-json-diff .wpnt-checkbox-label {\n            display: flex; align-items: center; gap: 8px; font-size: 0.9rem;\n            cursor: pointer; user-select: none; font-weight: 500;\n        }\n        #wpnt-json-diff .wpnt-checkbox-label input { display: none; }\n        #wpnt-json-diff .wpnt-checkbox-custom {\n            width: 18px; height: 18px; border: 2px solid var(--border-color);\n            border-radius: 4px; display: inline-flex; align-items: center; justify-content: center;\n            transition: var(--transition); background-color: var(--bg-primary) !important;\n        }\n        #wpnt-json-diff .wpnt-checkbox-label input:checked + .wpnt-checkbox-custom {\n            background-color: var(--accent-color) !important; border-color: var(--accent-color);\n        }\n        #wpnt-json-diff .wpnt-checkbox-label input:checked + .wpnt-checkbox-custom::after {\n            content: \"\u2713\"; color: white; font-size: 12px; font-weight: bold;\n        }\n\n        \/* Layout Grid untuk Input *\/\n        #wpnt-json-diff .wpnt-json-inputs {\n            display: grid; grid-template-columns: 1fr auto 1fr; gap: 16px;\n            align-items: stretch; margin-bottom: 24px;\n        }\n        #wpnt-json-diff .wpnt-input-group { display: flex; flex-direction: column; width: 100%; box-shadow: var(--card-shadow); border-radius: var(--wpnt-radius-md); background-color: var(--bg-primary); }\n\n        \/* Toolbar *\/\n        #wpnt-json-diff .wpnt-toolbar {\n            display: flex; justify-content: space-between; align-items: center;\n            background-color: var(--bg-secondary) !important;\n            color: var(--text-main) !important;\n            padding: 8px 12px;\n            border: 1px solid var(--border-color); border-bottom: none;\n            border-radius: var(--wpnt-radius-md) var(--wpnt-radius-md) 0 0;\n        }\n        #wpnt-json-diff .wpnt-toolbar-title { font-weight: 600; font-size: 0.85rem; }\n        #wpnt-json-diff .wpnt-toolbar-actions { display: flex; gap: 6px; }\n\n        \/* Textareas *\/\n        #wpnt-json-diff textarea {\n            width: 100%; flex-grow: 1; min-height: 350px; padding: 16px;\n            border-radius: 0 0 var(--wpnt-radius-md) var(--wpnt-radius-md);\n            border: 1px solid var(--border-color); \n            background-color: var(--bg-primary) !important;\n            color: var(--text-main) !important;\n            font-family: 'Fira Code', monospace;\n            font-size: 0.85rem; resize: vertical; outline: none; line-height: 1.5;\n        }\n        #wpnt-json-diff textarea:focus {\n            border-color: var(--accent-color); z-index: 1; position: relative;\n        }\n\n        #wpnt-json-diff .wpnt-error-msg {\n            color: var(--wpnt-danger); font-size: 0.8rem; font-weight: 500;\n            margin-top: 8px; min-height: 20px;\n        }\n\n        \/* Buttons *\/\n        #wpnt-json-diff .wpnt-btn {\n            background: var(--bg-primary); color: var(--accent-color);\n            border: 1px solid var(--border-color); border-radius: var(--wpnt-radius-sm);\n            cursor: pointer; font-weight: 500; display: inline-flex;\n            align-items: center; justify-content: center; gap: 8px; transition: var(--transition);\n        }\n        #wpnt-json-diff .wpnt-btn:hover { border-color: var(--accent-color); }\n        \n        #wpnt-json-diff .wpnt-btn-tiny { padding: 4px 10px; font-size: 0.75rem; }\n        #wpnt-json-diff .wpnt-btn-danger:hover { background: var(--wpnt-danger); color: white; border-color: var(--wpnt-danger); }\n        #wpnt-json-diff .wpnt-btn-accent { background: rgba(67, 97, 238, 0.1); border-color: transparent; }\n        #wpnt-json-diff .wpnt-btn-accent:hover { background: var(--accent-color); color: white; }\n        \n        #wpnt-json-diff .wpnt-btn-main {\n            background: var(--accent-color); color: #ffffff; padding: 16px 24px;\n            width: 100%; font-size: 1.1rem; font-weight: 600; border: none;\n            box-shadow: var(--card-shadow);\n        }\n        #wpnt-json-diff .wpnt-btn-main:hover {\n            background: var(--accent-hover); transform: translateY(-2px);\n            box-shadow: 0 4px 12px rgba(67, 97, 238, 0.25);\n        }\n\n        #wpnt-json-diff .wpnt-btn-icon {\n            background-color: var(--bg-primary) !important; color: var(--accent-color);\n            border: 1px solid var(--border-color); border-radius: 50%;\n            width: 48px; height: 48px; display: flex; align-items: center;\n            justify-content: center; cursor: pointer; box-shadow: var(--card-shadow);\n            margin-top: 30px; \/* offset for toolbar *\/\n        }\n        #wpnt-json-diff .wpnt-btn-icon:hover { transform: translateY(-2px); border-color: var(--accent-color); }\n\n        \/* Results & Diff Viewer *\/\n        #wpnt-json-diff .wpnt-results {\n            display: none; margin-top: 32px; \n            background-color: var(--bg-primary) !important;\n            color: var(--text-main) !important;\n            border-radius: var(--wpnt-radius-md); border: 1px solid var(--border-color);\n            overflow: hidden; box-shadow: var(--card-shadow);\n        }\n        #wpnt-json-diff .wpnt-results-header {\n            padding: 20px 24px; border-bottom: 1px solid var(--border-color);\n            display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 16px;\n        }\n        #wpnt-json-diff .wpnt-results-actions { display: flex; gap: 8px; }\n\n        #wpnt-json-diff .wpnt-legend { display: flex; gap: 12px; flex-wrap: wrap; }\n        #wpnt-json-diff .legend-item { font-size: 0.75rem; font-weight: 600; padding: 4px 10px; border-radius: 4px; }\n        #wpnt-json-diff .legend-added { background: var(--diff-added-bg); color: var(--diff-added-text); }\n        #wpnt-json-diff .legend-removed { background: var(--diff-removed-bg); color: var(--diff-removed-text); }\n        #wpnt-json-diff .legend-changed { background: var(--diff-changed-bg); color: var(--diff-changed-text); }\n        #wpnt-json-diff .legend-unchanged { color: var(--diff-unchanged-text); border: 1px solid var(--border-color); }\n\n        \/* Advanced Tree Viewer CSS *\/\n        #wpnt-json-diff .wpnt-diff-viewer-wrapper { padding: 20px; background-color: var(--bg-primary) !important; overflow-x: auto; }\n        #wpnt-json-diff .wpnt-diff-viewer {\n            font-family: 'Fira Code', monospace; font-size: 0.85rem; line-height: 1.6;\n        }\n\n        \/* Details & Summary Styling for Collapsible Nodes *\/\n        #wpnt-json-diff details { padding-left: 20px; position: relative; }\n        #wpnt-json-diff summary {\n            display: block; cursor: pointer; position: relative; margin-left: -20px; padding-left: 20px; outline: none;\n        }\n        #wpnt-json-diff summary::-webkit-details-marker { display: none; } \/* Hide default arrow *\/\n        #wpnt-json-diff summary::before {\n            content: '\u25b6'; position: absolute; left: 4px; top: 0; font-size: 0.7rem;\n            color: var(--accent-color); transition: transform 0.2s; opacity: 0.7;\n        }\n        #wpnt-json-diff details[open] > summary::before { transform: rotate(90deg); }\n        #wpnt-json-diff summary:hover::before { opacity: 1; }\n\n        \/* Lines *\/\n        #wpnt-json-diff .diff-line { display: block; padding: 0 4px; border-radius: 2px; position: relative; }\n        #wpnt-json-diff .diff-line.added { background: var(--diff-added-bg); }\n        #wpnt-json-diff .diff-line.removed { background: var(--diff-removed-bg); }\n        #wpnt-json-diff .diff-line.changed { background: var(--diff-changed-bg); }\n        \n        #wpnt-json-diff .diff-line::before {\n            content: ''; position: absolute; left: -16px; width: 12px; text-align: right;\n            font-weight: bold; font-size: 0.8rem; top: 0;\n        }\n        #wpnt-json-diff .diff-line.added::before { content: '+'; color: var(--diff-added-text); }\n        #wpnt-json-diff .diff-line.removed::before { content: '-'; color: var(--diff-removed-text); }\n        #wpnt-json-diff .diff-line.changed::before { content: '~'; color: var(--diff-changed-text); }\n\n        \/* Value Coloring *\/\n        #wpnt-json-diff .diff-key { color: var(--diff-key-color); font-weight: 600; }\n        #wpnt-json-diff .diff-val-string { color: #16a34a; }\n        #wpnt-json-diff .diff-val-number { color: #ea580c; }\n        #wpnt-json-diff .diff-val-boolean { color: #2563eb; font-weight: 600;}\n        #wpnt-json-diff .diff-val-null { color: #94a3b8; font-style: italic;}\n        \n        #wpnt-json-diff .diff-val-added { color: var(--diff-added-text); font-weight: 600; }\n        #wpnt-json-diff .diff-val-removed { color: var(--diff-removed-text); text-decoration: line-through; margin-right: 8px; opacity: 0.8;}\n        #wpnt-json-diff .diff-val-changed { color: var(--diff-changed-text); font-weight: 600; }\n        #wpnt-json-diff .diff-bracket { color: var(--diff-unchanged-text); font-weight: bold;}\n\n        \/* Dark Mode Syntax Adjustment *\/\n        @media (prefers-color-scheme: dark) {\n            #wpnt-json-diff .diff-val-string { color: #4ade80; }\n            #wpnt-json-diff .diff-val-number { color: #fb923c; }\n            #wpnt-json-diff .diff-val-boolean { color: #60a5fa; }\n        }\n\n        \/* Responsiveness *\/\n        @media (max-width: 850px) {\n            #wpnt-json-diff { padding: 10px 0; }\n            #wpnt-json-diff .wpnt-json-inputs { grid-template-columns: 1fr; }\n            #wpnt-json-diff .wpnt-swap-container {\n                display: flex; justify-content: center; transform: rotate(90deg); margin: -8px 0;\n            }\n            #wpnt-json-diff textarea { min-height: 250px; }\n        }\n    <\/style>\n\n    <script>\n        \/**\n         * WP-NanoTech Advanced JSON Diff Logic\n         * Features: Collapsible Tree, Type Checking, Case Ignoring, Sample Data.\n         *\/\n        (() => {\n            \/\/ DOM Elements\n            const elLeft = document.getElementById('json-left');\n            const elRight = document.getElementById('json-right');\n            const errLeft = document.getElementById('error-left');\n            const errRight = document.getElementById('error-right');\n            const btnCompare = document.getElementById('btn-compare');\n            const btnSwap = document.getElementById('btn-swap');\n            const diffResults = document.getElementById('diff-results');\n            const diffViewer = document.getElementById('diff-viewer');\n\n            \/\/ Sample Data\n            const sampleOriginal = {\n                \"project\": \"Sanepo Tools\",\n                \"version\": 1.0,\n                \"status\": \"active\",\n                \"features\": [\"format\", \"compare\"],\n                \"settings\": { \"theme\": \"light\", \"notifications\": true },\n                \"metadata\": null\n            };\n            const sampleModified = {\n                \"project\": \"Sanepo Tools PRO\",\n                \"version\": \"1.1\",\n                \"status\": \"active\",\n                \"features\": [\"format\", \"compare\", \"tree-view\"],\n                \"settings\": { \"theme\": \"dark\", \"autoSave\": true },\n                \"author\": \"WP-NanoTech\"\n            };\n\n            \/\/ Toolbar Actions\n            document.getElementById('btn-sample-left').addEventListener('click', () => { elLeft.value = JSON.stringify(sampleOriginal, null, 2); errLeft.textContent='';});\n            document.getElementById('btn-sample-right').addEventListener('click', () => { elRight.value = JSON.stringify(sampleModified, null, 2); errRight.textContent=''; });\n            document.getElementById('btn-clear-left').addEventListener('click', () => { elLeft.value = ''; errLeft.textContent=''; });\n            document.getElementById('btn-clear-right').addEventListener('click', () => { elRight.value = ''; errRight.textContent=''; });\n\n            \/\/ Format & Validate\n            const formatAndValidateJSON = (textareaEl, errorEl) => {\n                const rawVal = textareaEl.value.trim();\n                errorEl.textContent = '';\n                if (!rawVal) return null;\n                try {\n                    const parsed = JSON.parse(rawVal);\n                    textareaEl.value = JSON.stringify(parsed, null, 2);\n                    return parsed;\n                } catch (e) {\n                    errorEl.textContent = \"Invalid JSON: \" + e.message;\n                    return null;\n                }\n            };\n\n            document.getElementById('btn-format-left').addEventListener('click', () => formatAndValidateJSON(elLeft, errLeft));\n            document.getElementById('btn-format-right').addEventListener('click', () => formatAndValidateJSON(elRight, errRight));\n\n            btnSwap.addEventListener('click', () => {\n                const temp = elLeft.value; elLeft.value = elRight.value; elRight.value = temp;\n                errLeft.textContent = ''; errRight.textContent = '';\n            });\n\n            \/\/ Tree View Actions\n            document.getElementById('btn-expand-all').addEventListener('click', () => {\n                document.querySelectorAll('#diff-viewer details').forEach(d => d.setAttribute('open', 'true'));\n            });\n            document.getElementById('btn-collapse-all').addEventListener('click', () => {\n                document.querySelectorAll('#diff-viewer details').forEach(d => d.removeAttribute('open'));\n            });\n            document.getElementById('btn-copy-diff').addEventListener('click', function() {\n                \/\/ Copy plain text by stripping HTML tags\n                const plainText = diffViewer.innerText;\n                navigator.clipboard.writeText(plainText).then(() => {\n                    const originalText = this.innerText;\n                    this.innerText = 'Copied!';\n                    setTimeout(() => this.innerText = originalText, 2000);\n                });\n            });\n\n            \/\/ Syntax Highlighting Helper\n            const highlightVal = (val) => {\n                if (typeof val === 'string') return `<span class=\"diff-val-string\">\"${val}\"<\/span>`;\n                if (typeof val === 'number') return `<span class=\"diff-val-number\">${val}<\/span>`;\n                if (typeof val === 'boolean') return `<span class=\"diff-val-boolean\">${val}<\/span>`;\n                if (val === null) return `<span class=\"diff-val-null\">null<\/span>`;\n                return val;\n            };\n\n            \/\/ Raw formatting for changed\/removed rendering\n            const formatRaw = (val) => {\n                if (typeof val === 'string') return `\"${val}\"`;\n                if (val === null) return 'null';\n                if (typeof val === 'object') return JSON.stringify(val);\n                return val;\n            };\n\n            \/\/ Deep Compare Logic\n            const deepCompare = (obj1, obj2, isStrict, ignoreCase) => {\n                const isObj = (val) => val !== null && typeof val === 'object';\n                \n                if (!isObj(obj1) || !isObj(obj2)) {\n                    \/\/ Primitive comparison based on settings\n                    let v1 = obj1; let v2 = obj2;\n                    if (ignoreCase && typeof v1 === 'string' && typeof v2 === 'string') {\n                        v1 = v1.toLowerCase(); v2 = v2.toLowerCase();\n                    }\n                    const isEqual = isStrict ? v1 === v2 : v1 == v2;\n\n                    if (isEqual) return { type: 'unchanged', value: obj1 };\n                    return { type: 'changed', oldVal: obj1, newVal: obj2 };\n                }\n\n                const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);\n                const result = Array.isArray(obj1) && Array.isArray(obj2) ? [] : {};\n                let hasChanges = false;\n\n                keys.forEach(key => {\n                    const has1 = obj1.hasOwnProperty(key);\n                    const has2 = obj2.hasOwnProperty(key);\n\n                    if (has1 && !has2) {\n                        result[key] = { type: 'removed', value: obj1[key] };\n                        hasChanges = true;\n                    } else if (!has1 && has2) {\n                        result[key] = { type: 'added', value: obj2[key] };\n                        hasChanges = true;\n                    } else {\n                        const comp = deepCompare(obj1[key], obj2[key], isStrict, ignoreCase);\n                        result[key] = comp;\n                        if (comp.type !== 'unchanged') hasChanges = true;\n                    }\n                });\n\n                \/\/ Return nested object wrapper\n                return { type: 'nested', value: result, isArray: Array.isArray(result), hasChanges: hasChanges };\n            };\n\n            \/\/ HTML Generator for Diff Tree\n            const renderDiffTreeHTML = (diffData, keyName = null, isLast = true) => {\n                let html = '';\n                const comma = isLast ? '' : ',';\n                const keyStr = keyName !== null ? `<span class=\"diff-key\">\"${keyName}\"<\/span>: ` : '';\n\n                if (diffData.type === 'unchanged') {\n                    html += `<div class=\"diff-line\">${keyStr}${highlightVal(diffData.value)}${comma}<\/div>`;\n                } else if (diffData.type === 'added') {\n                    html += `<div class=\"diff-line added\">${keyStr}<span class=\"diff-val-added\">${formatRaw(diffData.value)}<\/span>${comma}<\/div>`;\n                } else if (diffData.type === 'removed') {\n                    html += `<div class=\"diff-line removed\">${keyStr}<span class=\"diff-val-removed\">${formatRaw(diffData.value)}<\/span>${comma}<\/div>`;\n                } else if (diffData.type === 'changed') {\n                    html += `<div class=\"diff-line changed\">${keyStr}<span class=\"diff-val-removed\">${formatRaw(diffData.oldVal)}<\/span><span class=\"diff-val-changed\">${formatRaw(diffData.newVal)}<\/span>${comma}<\/div>`;\n                } else if (diffData.type === 'nested') {\n                    const openBracket = diffData.isArray ? '[' : '{';\n                    const closeBracket = diffData.isArray ? ']' : '}';\n                    const objKeys = Object.keys(diffData.value);\n                    \n                    if (objKeys.length === 0) {\n                        \/\/ Empty object\/array\n                        html += `<div class=\"diff-line\">${keyStr}<span class=\"diff-bracket\">${openBracket}${closeBracket}<\/span>${comma}<\/div>`;\n                    } else {\n                        \/\/ Use <details> for collapsible hierarchy. Auto-open if it has changes inside.\n                        const openAttr = diffData.hasChanges ? 'open' : '';\n                        html += `<details ${openAttr}>`;\n                        html += `<summary class=\"diff-line\">${keyStr}<span class=\"diff-bracket\">${openBracket}<\/span><\/summary>`;\n                        \n                        objKeys.forEach((k, index) => {\n                            const isLastChild = index === objKeys.length - 1;\n                            html += renderDiffTreeHTML(diffData.value[k], diffData.isArray ? null : k, isLastChild);\n                        });\n                        \n                        html += `<div class=\"diff-line\"><span class=\"diff-bracket\">${closeBracket}<\/span>${comma}<\/div>`;\n                        html += `<\/details>`;\n                    }\n                }\n                return html;\n            };\n\n            \/\/ Compare Execution\n            btnCompare.addEventListener('click', () => {\n                const objLeft = formatAndValidateJSON(elLeft, errLeft);\n                const objRight = formatAndValidateJSON(elRight, errRight);\n                \n                if (!objLeft || !objRight) {\n                    diffResults.style.display = 'none';\n                    return;\n                }\n\n                \/\/ Get Settings\n                const isStrict = document.getElementById('setting-strict').checked;\n                const ignoreCase = document.getElementById('setting-ignore-case').checked;\n\n                \/\/ Perform Diff\n                const diffData = deepCompare(objLeft, objRight, isStrict, ignoreCase);\n                \n                \/\/ Root is always a nested object\/array\n                let outputHtml = renderDiffTreeHTML(diffData, null, true);\n\n                diffViewer.innerHTML = outputHtml;\n                diffResults.style.display = 'block';\n\n                \/\/ Ensure parent <details> of root is not collapsible\n                const rootDetails = diffViewer.querySelector('details');\n                if(rootDetails) {\n                    rootDetails.setAttribute('open', 'true');\n                    \/\/ Optional: remove summary arrow for root if you want it permanently open\n                    rootDetails.querySelector('summary').style.pointerEvents = 'none';\n                    rootDetails.querySelector('summary').style.marginLeft = '0';\n                    rootDetails.querySelector('summary').style.paddingLeft = '0';\n                    rootDetails.querySelector('summary').style.listStyle = 'none';\n                }\n\n                diffResults.scrollIntoView({ behavior: 'smooth', block: 'start' });\n            });\n\n        })();\n    <\/script>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Sanepo Tools &#8211; JSON Diff Advanced JSON comparison tool. Deep compare, validate, and analyze structures instantly. \ud83d\udd12 100% Secure Local Processing Comparison Settings Strict Type Checking Ignore Case (Strings) Original JSON Sample Clear Format Modified JSON Sample Clear Format Execute Deep Compare Comparison Result Added Removed Changed Unchanged Expand All Collapse All Copy Text<\/p>\n","protected":false},"featured_media":0,"template":"","meta":[],"class_list":["post-83","tool","type-tool","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/tools.sanepo.com\/hi\/wp-json\/wp\/v2\/tool\/83","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tools.sanepo.com\/hi\/wp-json\/wp\/v2\/tool"}],"about":[{"href":"https:\/\/tools.sanepo.com\/hi\/wp-json\/wp\/v2\/types\/tool"}],"wp:attachment":[{"href":"https:\/\/tools.sanepo.com\/hi\/wp-json\/wp\/v2\/media?parent=83"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}