Editor, Command Line, dan Toolchain Otomasi
Intinya: Editor memecahkan masalah "lihat dengan jelas, edit dengan benar", sementara command line memecahkan "batch, dapat diulang". Masing-masing punya beberapa alat yang tetap berguna selama satu dekade.

Intinya: pilih editor berdasarkan skenario — CodeMirror 6 untuk situs utilitas dan mobile, Monaco hanya ketika Anda membutuhkan pengalaman IDE lengkap; serahkan pekerjaan batch kepada jq plus tiga pemeriksaan CI untuk sintaks, struktur, dan gaya, dan selalu teruskan argumen dengan jq --arg.
Era memeriksa JSON dengan tangan seharusnya sudah berakhir: apa pun yang dapat diulang oleh mesin, jangan serahkan kepada mata manusia.
1. Editor di peramban
1.1 Integrasi CodeMirror 6 minimal
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());
}
}),
],
});
Empat hal yang perlu diperhatikan:
json()menyediakan penyorotan sintaks dan pencocokan kurung — jangan menulis sendiri;jsonParseLinter()menghasilkan penanda error tingkat baris/kolom; pasangkan denganlintGutter()untuk menampilkan ikon di samping nomor baris;updateListenerharus di-debounce; memanggilJSON.parsepada seratus ribu baris di setiap ketukan tombol akan terasa lambat;- Dokumen besar membutuhkan optimasi di luar
EditorView.lineWrappingagar tidak merender seluruhnya sekaligus (CodeMirror 6 merender berdasarkan viewport secara bawaan, yang merupakan peningkatan dibanding versi lama).
1.2 Folding dan outline
CodeMirror 6 memiliki folding bawaan; dalam skenario JSON Anda biasanya melipat berdasarkan "objek/array":
import { foldGutter, foldKeymap } from '@codemirror/language';
import { keymap } from '@codemirror/view';
Dengan foldGutter() dan keymap.of(foldKeymap), pengguna dapat melipat array panjang dengan pintasan keyboard.
1.3 Memilih antara CodeMirror dan Monaco
| Dimensi | CodeMirror 6 | Monaco |
|---|---|---|
| Ukuran bundle | Kecil, modular | Besar (beberapa MB) |
| Mobile | Didukung dengan baik | Pengalaman biasa saja |
| Layanan bahasa | Harus dibuat sendiri | Kaya, sudah bawaan |
| Biaya kustomisasi | Rendah | Sedang |
Situs utilitas dan mobile-first → CodeMirror; pengalaman IDE lengkap (banyak file, go-to-definition, penyelesaian kode) → Monaco.
2. Command line: enam resep jq yang sering dipakai
jq bagi JSON seperti sed + awk bagi teks; mempelajari sedikit saja sintaksnya sudah mencakup delapan puluh persen kebutuhan sehari-hari.
# 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 layak mendapat perhatian khusus: menggabungkan variabel langsung ke dalam ekspresi akan rusak begitu nilainya mengandung tanda kutip, sedangkan --arg membiarkan jq menangani escaping-nya.
2.1 Alat lain sekilas
| Alat | Tujuan | Dalam satu kalimat |
|---|---|---|
yq |
Konversi YAML/JSON/XML | Sintaks mirip jq, andalan untuk file konfigurasi |
dasel |
Kueri terpadu lintas format | Mendukung JSON/YAML/TOML/XML/CSV |
fx |
Penjelajahan JSON interaktif | Klik-klik di terminal, bagus untuk eksplorasi |
jless |
Penjelajahan berhalaman di terminal | Seperti less, dengan folding dan pencarian |
gron |
Meratakan JSON menjadi baris yang bisa di-grep | Alat hebat untuk mencari tahu "field ini ada di level mana" |
ajv-cli |
Validasi Schema | Memvalidasi file JSON di CI |
Gagasan di balik gron sangat layak diketahui:
$ echo '{"a":{"b":[1,2]}}' | gron
json = {};
json.a = {};
json.a.b = [];
json.a.b[0] = 1;
json.a.b[1] = 2;
Setelah diratakan, grep dapat menemukan path, yang jauh lebih cepat daripada memperluas level demi level di editor.
3. Tiga lapisan validasi di CI
| Lapisan | Alat | Arti kegagalan |
|---|---|---|
| Sintaks | JSON.parse / jq empty |
File itu sendiri cacat |
| Struktur | ajv-cli + schema |
Field hilang, tipe salah |
| Gaya | Prettier | Format tidak konsisten, diff berisik |
# 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"
Anda membutuhkan ketiga lapisan, karena pesan errornya sepenuhnya berbeda:
jq empty hanya mengatakan "baris mana yang rusak", ajv mengatakan "field mana yang melanggar kata kunci mana", dan Prettier hanya mengatakan "formatnya tidak konsisten".
4. Hook pre-commit
# .husky/pre-commit example (excerpt)
npx lint-staged
{
"lint-staged": {
"*.json": ["prettier --write", "jq empty"]
}
}
Hati-hati dengan file konfigurasi alat seperti package.json dan tsconfig.json; jangan biarkan Prettier mengubah indentasinya begitu saja —
sebagian alat sensitif terhadap format (JSON yang valid seharusnya tidak, tetapi dalam praktiknya hal ini pernah menimbulkan masalah). Anda dapat mengecualikannya satu per satu.
5. Tips debugging
- Gunakan
jq -esebagai asersi: exit code bernilai 1 ketika hasil ekspresifalseataunull, sehingga dapat langsung dipakai di skrip sebagai pemeriksaan; jq 'paths'mencantumkan semua path, memberi Anda gambaran cepat tentang struktur dokumen yang asing;jq '.. | objects | keys'menemukan setiap nama kunci yang pernah muncul, berguna untuk memburu penulisan yang tidak konsisten;- Format dulu sebelum membandingkan di editor: diff yang tidak diformat adalah kebisingan murni; perbandingan struktural seperti
/difflebih akurat.
6. Checklist
- [ ] Penanda error editor presisi hingga baris dan kolom, dan parsing di-debounce;
- [ ] Skrip tim meneruskan argumen dengan
jq --argalih-alih menggabungkan string; - [ ] CI memiliki ketiga lapisan validasi (sintaks/struktur/gaya);
- [ ] pre-commit hanya memproses file yang di-stage, agar pemindaian penuh tidak memperlambat commit;
- [ ] Versi alat dipatok di
package.jsonatau.tool-versions.
FAQ
Bagaimana memilih antara CodeMirror 6 dan Monaco?
Untuk situs utilitas dan mobile, pilih CodeMirror 6: ukurannya kecil, modular, dan didukung baik di mobile, serta penyorotan sintaks, pencocokan kurung, dan folding dapat disusun sesuai kebutuhan. Gunakan Monaco hanya ketika Anda membutuhkan pengalaman IDE lengkap dengan banyak file, go-to-definition, dan penyelesaian kode — dengan konsekuensi bundle beberapa megabyte dan usaha kustomisasi lebih tinggi.
Mengapa CI membutuhkan pemeriksaan sintaks, struktur, dan gaya sekaligus?
Ketiga lapisan melaporkan error yang sepenuhnya berbeda: jq empty mengatakan baris mana yang rusak, ajv mengatakan field mana yang melanggar kata kunci mana, dan Prettier hanya mengatakan formatnya tidak konsisten. Menghilangkan satu lapisan membuat error lapisan lain mudah disalahpahami, jadi pertahankan ketiganya dan hentikan segera setelah satu lapisan gagal.
Haruskah saya mengandalkan pre-commit alih-alih memvalidasi di CI?
Tidak. Hook hanya memproses file yang di-stage, yang memberi umpan balik dalam satu menit tetapi tidak dapat mencakup seluruh repositori atau perubahan yang melewati commit. CI bertanggung jawab atas kelengkapan: biarkan pre-commit menangani file yang di-stage dan serahkan pemindaian penuh kepada CI.