JSON Toolkit

Editor, Command Line และ Toolchain สำหรับ Automation

สรุปสำคัญ: Editor แก้ปัญหา "เห็นชัด แก้ไขถูก" ขณะที่ command line แก้ปัญหา "ทำทีละมาก ๆ และทำซ้ำได้" แต่ละฝ่ายมีเครื่องมือไม่กี่ตัวที่ยังใช้ได้ดีไปอีกทศวรรษ

ผู้เริ่มต้นอ่านประมาณ 10 นาทีเผยแพร่ 2026-10-30อัปเดต 2026-10-30
ภาพหน้าปก Editor, command line และ toolchain สำหรับ automation

สรุปสั้น: เลือก editor ตามสถานการณ์ — CodeMirror 6 สำหรับเว็บยูทิลิตี้และมือถือ ใช้ Monaco เฉพาะเมื่อต้องการประสบการณ์ IDE เต็มรูปแบบ; ปล่อยงานแบบทีละมาก ๆ ให้ jq พร้อมการตรวจสามชั้นใน CI สำหรับไวยากรณ์ โครงสร้าง และสไตล์ และส่งอาร์กิวเมนต์ด้วย jq --arg เสมอ

ยุคของการตรวจ JSON ด้วยมือควรจบไปแล้ว: อะไรที่เครื่องทำซ้ำได้ อย่าปล่อยให้ตาคนทำ

1. Editor ใน browser

1.1 การผสาน CodeMirror 6 แบบน้อยที่สุด

import { EditorView, basicSetup } from 'codemirror';
import { json, jsonParseLinter } from '@codemirror/lang-json';
import { linter, lintGutter } from '@codemirror/lint';

const view = new EditorView({
  parent: document.getElementById('editor')!,
  doc: '{"hello": "json"}',
  extensions: [
    basicSetup,
    json(),
    linter(jsonParseLinter()),
    lintGutter(),
    EditorView.updateListener.of((update) => {
      if (update.docChanged) {
        // Debounce before doing heavy work; do not format on every keystroke
        scheduleParse(update.state.doc.toString());
      }
    }),
  ],
});

จุดที่ควรสังเกตสี่ข้อ:

  1. json() ให้การไฮไลต์ไวยากรณ์และการจับคู่วงเล็บ — ไม่ต้องเขียนเอง;
  2. jsonParseLinter() สร้าง marker ของ error ระดับบรรทัด/คอลัมน์ ใช้ร่วมกับ lintGutter() เพื่อแสดงไอคอนข้างเลขบรรทัด;
  3. updateListener ต้องถูก debounce การเรียก JSON.parse กับข้อมูลแสนบรรทัดทุกครั้งที่กดคีย์จะเห็นความหน่วงชัดเจน;
  4. เอกสารขนาดใหญ่ต้องใช้เทคนิคเพิ่มประสิทธิภาพนอกเหนือจาก EditorView.lineWrapping เพื่อเลี่ยงการ render ทั้งหมดในครั้งเดียว (CodeMirror 6 render ตาม viewport เป็นค่าเริ่มต้น ซึ่งดีกว่าระบบเวอร์ชันเก่า)

1.2 Folding และ outline

CodeMirror 6 มี folding ในตัว ในสถานการณ์ JSON คุณมักพับตาม "object/array":

import { foldGutter, foldKeymap } from '@codemirror/language';
import { keymap } from '@codemirror/view';

ด้วย foldGutter() และ keymap.of(foldKeymap) ผู้ใช้สามารถย่อ array ยาว ๆ ได้ด้วยคีย์ลัด

1.3 เลือกระหว่าง CodeMirror กับ Monaco

มิติ CodeMirror 6 Monaco
ขนาด bundle เล็ก แยกโมดูลได้ ใหญ่ (หลาย MB)
มือถือ รองรับดี ประสบการณ์ปานกลาง
Language service ต้องสร้างเอง ครบครัน มีมาให้
ต้นทุนการปรับแต่ง ต่ำ ปานกลาง

เว็บยูทิลิตี้และมือถือเป็นหลัก → CodeMirror; ประสบการณ์ IDE เต็มรูปแบบ (หลายไฟล์, go-to-definition, completion) → Monaco

2. Command line: สูตร jq ความถี่สูงหกสูตร

jq ต่อ JSON เทียบได้กับ sed + awk ต่อข้อความ การเรียนเพียงส่วนเล็กของไวยากรณ์ก็ครอบคลุมความต้องการในชีวิตประจำวันแปดสิบเปอร์เซ็นต์

# 1. Pick fields (the most common)
jq '.data.items[].name' response.json

# 2. Filter + reshape
jq '.data.items[] | select(.price < 10) | {id, price}' response.json

# 3. Aggregates (length, sum, max)
jq '[.items[] | .price] | {count: length, total: add, max: max}' response.json

# 4. Group and aggregate
jq '[.items[]] | group_by(.category) | map({category: .[0].category, count: length})' response.json
# 5. Merge multiple files into an array
jq -s '.' part-*.json > merged.json

# 6. Process JSON Lines line by line
jq -c 'select(.level == "error")' app.jsonl

# Common output switches
jq -r '.data.name'      # Strip the quotes so it pipes cleanly into the shell
jq -c '.'               # Compact output, one line
jq --arg id "$ID" '.id == $id'   # Pass arguments safely, avoiding injection through concatenation

--arg สมควรได้รับการกล่าวถึงเป็นพิเศษ: การต่อตัวแปรเข้าใน expression โดยตรงจะพังทันทีเมื่อค่ามีเครื่องหมายคำพูด ขณะที่ --arg ให้ jq จัดการการ escape เอง

2.1 เครื่องมืออื่นโดยสรุป

เครื่องมือ จุดประสงค์ ในหนึ่งประโยค
yq แปลง YAML/JSON/XML ไวยากรณ์คล้าย jq เป็นม้าทำงานหนักของไฟล์กำหนดค่า
dasel query ข้ามรูปแบบ รองรับ JSON/YAML/TOML/XML/CSV
fx เรียกดู JSON แบบโต้ตอบ คลิกไปมาใน terminal เหมาะกับการสำรวจ
jless เรียกดูแบบแบ่งหน้าใน terminal เหมือน less มี folding และการค้นหา
gron แบน JSON เป็นบรรทัดที่ grep ได้ เครื่องมือเยี่ยมสำหรับหาว่า "ฟิลด์นี้อยู่ระดับไหน"
ajv-cli ตรวจ schema ตรวจไฟล์ JSON ใน CI

แนวคิดเบื้องหลัง gron น่าสนใจเป็นพิเศษ:

$ echo '{"a":{"b":[1,2]}}' | gron
json = {};
json.a = {};
json.a.b = [];
json.a.b[0] = 1;
json.a.b[1] = 2;

เมื่อแบนแล้ว grep สามารถระบุ path ได้ ซึ่งเร็วกว่าการขยายทีละระดับใน editor มาก

3. การตรวจสามชั้นใน CI

ชั้น เครื่องมือ ความล้มเหลวหมายถึงอะไร
ไวยากรณ์ JSON.parse / jq empty ไฟล์เองผิดรูป
โครงสร้าง ajv-cli + schema ฟิลด์หาย, ชนิดผิด
สไตล์ Prettier การจัดรูปแบบไม่สม่ำเสมอ, diff มีเสียงรบกวน
# Syntax: batch-validate every json file in the repository
find . -name '*.json' -not -path './node_modules/*' -print0 \
  | xargs -0 -n1 jq empty

# Structure: validate against a schema
npx ajv-cli validate -s schemas/order.json -d 'fixtures/orders/*.json' --strict=false

# Style: check only, do not modify
npx prettier --check "**/*.json"

คุณต้องมีทั้งสามชั้น เพราะข้อความ error ของแต่ละชั้นแตกต่างกันโดยสิ้นเชิง: jq empty บอกเพียง "บรรทัดไหนเสีย", ajv บอก "ฟิลด์ไหนละเมิด keyword ไหน" และ Prettier บอกเพียง "การจัดรูปแบบไม่สม่ำเสมอ"

4. pre-commit hook

# .husky/pre-commit example (excerpt)
npx lint-staged
{
  "lint-staged": {
    "*.json": ["prettier --write", "jq empty"]
  }
}

ระวังไฟล์กำหนดค่าของเครื่องมืออย่าง package.json และ tsconfig.json อย่าให้ Prettier จัดย่อหน้าใหม่ตามใจ — เครื่องมือบางตัวไวต่อการจัดรูปแบบ (JSON ที่ถูกต้องไม่ควรเป็นเช่นนั้น แต่ในทางปฏิบัติเคยเกิดปัญหา) คุณสามารถยกเว้นทีละไฟล์ได้

5. เคล็ดลับการ debug

  1. ใช้ jq -e เป็น assertion: exit code เป็น 1 เมื่อผลลัพธ์ของ expression เป็น false หรือ null จึงใส่ในสคริปต์เป็นการตรวจได้ทันที;
  2. jq 'paths' แสดง path ทั้งหมด ให้ภาพรวมอย่างเร็วของโครงสร้างเอกสารที่ไม่คุ้น;
  3. jq '.. | objects | keys' ค้นหาชื่อคีย์ทุกชื่อที่เคยปรากฏ เหมาะกับการตามล่าการเขียนที่ผิดรูปแบบ;
  4. จัดรูปแบบก่อนเปรียบเทียบใน editor: diff ที่ไม่จัดรูปแบบคือเสียงรบกวนล้วน ๆ การเปรียบเทียบเชิงโครงสร้างอย่าง /diff แม่นยำกว่า

6. รายการตรวจสอบ

  • [ ] marker ของ error ใน editor แม่นยำถึงบรรทัดและคอลัมน์ และการ parse ถูก debounce;
  • [ ] สคริปต์ของทีมส่งอาร์กิวเมนต์ด้วย jq --arg แทนการต่อสตริง;
  • [ ] CI มีการตรวจครบทั้งสามชั้น (ไวยากรณ์/โครงสร้าง/สไตล์);
  • [ ] pre-commit ประมวลผลเฉพาะไฟล์ที่ stage แล้ว การสแกนทั้งหมดจึงไม่ทำให้ commit ช้าลง;
  • [ ] เวอร์ชันของเครื่องมือถูกปักหมุดใน package.json หรือ .tool-versions

คำถามที่พบบ่อย

จะเลือกระหว่าง CodeMirror 6 กับ Monaco อย่างไร?

สำหรับเว็บยูทิลิตี้และมือถือ ให้เลือก CodeMirror 6: มันเล็ก แยกโมดูลได้ รองรับมือถือดี และการไฮไลต์ไวยากรณ์ การจับคู่วงเล็บ และ folding สามารถประกอบตามต้องการ ใช้ Monaco เฉพาะเมื่อต้องการประสบการณ์ IDE เต็มรูปแบบที่มีหลายไฟล์ go-to-definition และ completion — โดยมีต้นทุนเป็น bundle หลายเมกะไบต์และความพยายามในการปรับแต่งที่สูงขึ้น

ทำไม CI ต้องมีการตรวจไวยากรณ์ โครงสร้าง และสไตล์พร้อมกัน?

ทั้งสามชั้นรายงาน error ที่แตกต่างกันโดยสิ้นเชิง: jq empty บอกว่าบรรทัดไหนเสีย, ajv บอกว่าฟิลด์ไหนละเมิด keyword ไหน และ Prettier บอกเพียงว่าการจัดรูปแบบไม่สม่ำเสมอ การตัดชั้นใดออกจะทำให้ error ของชั้นอื่นถูกอ่านผิดได้ง่าย จึงควรเก็บทั้งสามชั้นและหยุดทันทีเมื่อชั้นใดล้มเหลว

ควรพึ่ง pre-commit แทนการตรวจใน CI หรือไม่?

ไม่ Hook ประมวลผลเฉพาะไฟล์ที่ stage ซึ่งให้ feedback ภายในหนึ่งนาที แต่ครอบคลุมทั้ง repository ไม่ได้ และครอบคลุมการเปลี่ยนแปลงที่ข้าม commit ไม่ได้ CI รับผิดชอบความครบถ้วน: เก็บ pre-commit ไว้บนไฟล์ที่ stage และปล่อยการสแกนทั้งหมดให้ CI