ข้ามไปเนื้อหาหลัก

✓ เสร็จแล้ว

JSON Diff Visualizer

เว็บ tool สำหรับเปรียบ JSON สอง version แบบ side-by-side พร้อม highlight การเปลี่ยนแปลงแบบ nested

· อ่านประมาณ 2 นาที

สารบัญ

ปัญหาที่แก้

เมื่อ API response เปลี่ยน หรือ config เก่ากับใหม่ต่างกัน ต้องการเห็นความต่างชัดๆ แบบ nested โดยไม่ต้องใช้ jq หรือ diff ใน terminal


ฟีเจอร์

  • วางหรือพิมพ์ JSON ทั้งสองฝั่งได้เลย
  • แสดงความต่างเป็น tree — ไม่ใช่แค่ text diff
  • เขียว = เพิ่มใหม่, แดง = ลบออก, เหลือง = เปลี่ยนค่า
  • คลิก node เพื่อ expand/collapse nested objects
  • copy path ของ key ที่เปลี่ยนแปลง (เช่น user.address.city)
  • แสดง diff stats: N added, M removed, K changed

Stack

  • Astro (static, island)
  • TypeScript — diff algorithm
  • ไม่มี library diff — เขียน recursive diff เอง

Diff Algorithm

type DiffResult =
  | { type: 'unchanged'; value: unknown }
  | { type: 'added'; value: unknown }
  | { type: 'removed'; value: unknown }
  | { type: 'changed'; from: unknown; to: unknown }
  | { type: 'object'; children: Record<string, DiffResult> }
  | { type: 'array'; children: DiffResult[] };

function diffJson(left: unknown, right: unknown): DiffResult {
  if (left === right) return { type: 'unchanged', value: left };

  if (isPlainObject(left) && isPlainObject(right)) {
    const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
    const children: Record<string, DiffResult> = {};

    for (const key of keys) {
      if (!(key in left))  children[key] = { type: 'added', value: right[key] };
      else if (!(key in right)) children[key] = { type: 'removed', value: left[key] };
      else children[key] = diffJson(left[key], right[key]);
    }

    return { type: 'object', children };
  }

  if (Array.isArray(left) && Array.isArray(right)) {
    const children = Array.from(
      { length: Math.max(left.length, right.length) },
      (_, i) => {
        if (i >= left.length)  return { type: 'added',   value: right[i] };
        if (i >= right.length) return { type: 'removed', value: left[i]  };
        return diffJson(left[i], right[i]);
      }
    );
    return { type: 'array', children };
  }

  return { type: 'changed', from: left, to: right };
}

สิ่งที่เรียนรู้

  • เขียน recursive tree comparison ที่ handle nested objects/arrays ได้ถูกต้อง
  • Render tree ที่ collapsible โดยไม่ใช้ framework (Vanilla JS + custom element)
  • Handle edge case: null vs undefined, empty array vs empty object, number 0 vs false

ลิ้งค์

เว็บ tool พร้อมใช้งานทั้งหมดเป็น Astro static page — ทำงานได้ 100% ฝั่ง client ไม่มี server ไม่มีข้อมูล upload ออกไปไหน