JSON Toolkit

Редакторы, командная строка и цепочки автоматизации

Главное: Редакторы решают задачу «увидеть ясно, править точно», а командная строка — «пакетно и воспроизводимо». У каждой стороны есть несколько инструментов, которые остаются полезными десятилетиями.

Начинающий~10 мин чтенияОпубликовано 2026-10-30Обновлено 2026-10-30
Обложка статьи о редакторах, командной строке и цепочках автоматизации

Коротко: выбирайте редактор по сценарию — CodeMirror 6 для утилитарных сайтов и мобильных устройств, Monaco только когда нужен полноценный опыт IDE; пакетную работу оставляйте jq плюс трём проверкам в CI для синтаксиса, структуры и стиля, и всегда передавайте аргументы через jq --arg.

Эпоха ручной проверки JSON должна была закончиться: всё, что машина может повторять, не оставляйте человеческим глазам.

1. Редакторы в браузере

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() создаёт маркеры ошибок с точностью до строки и столбца; сочетайте его с lintGutter(), чтобы показывать значки рядом с номерами строк;
  3. updateListener обязательно должен быть с debounce; вызов JSON.parse на ста тысячах строк при каждом нажатии клавиши заметно подвесит интерфейс;
  4. Большим документам нужны оптимизации помимо EditorView.lineWrapping, чтобы не отрисовывать всё сразу (CodeMirror 6 по умолчанию отрисовывает по области просмотра, что является улучшением по сравнению со старыми версиями).

1.2 Свёртывание и структура

В CodeMirror 6 есть встроенное свёртывание; в сценариях JSON обычно сворачивают по «объект/массив»:

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

С foldGutter() и keymap.of(foldKeymap) пользователи могут сворачивать длинные массивы горячей клавишей.

1.3 Выбор между CodeMirror и Monaco

Измерение CodeMirror 6 Monaco
Размер пакета Небольшой, модульный Большой (несколько МБ)
Мобильные устройства Хорошо поддерживается Посредственный опыт
Языковые службы Нужно строить самому Богатые, встроенные
Стоимость кастомизации Низкая Средняя

Утилитарные сайты и mobile-first → CodeMirror; полноценный опыт IDE (несколько файлов, переход к определению, автодополнение) → Monaco.

2. Командная строка: шесть частых рецептов 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 заслуживает отдельного упоминания: склейка переменной прямо в выражение ломается, как только значение содержит кавычки, а --arg позволяет jq самому обработать экранирование.

2.1 Другие инструменты с одного взгляда

Инструмент Назначение В одном предложении
yq Преобразование YAML/JSON/XML Синтаксис, похожий на jq, рабочая лошадка для конфигурационных файлов
dasel Единый запрос по разным форматам Поддерживает JSON/YAML/TOML/XML/CSV
fx Интерактивный просмотр JSON Перемещение по терминалу, хорошо для исследования
jless Постраничный просмотр в терминале Как less, со свёртыванием и поиском
gron Уплощение JSON в строки, пригодные для grep Отличный инструмент, чтобы понять, «на каком уровне лежит это поле»
ajv-cli Валидация схем Проверка 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 может найти путь, что гораздо быстрее, чем раскрывать уровни в редакторе.

3. Три слоя валидации в CI

Слой Инструмент Что означает сбой
Синтаксис JSON.parse / jq empty Сам файл повреждён
Структура ajv-cli + схема Отсутствующие поля, неверные типы
Стиль 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"

Нужны все три слоя, потому что их сообщения об ошибках совершенно разные: jq empty говорит только «какая строка сломана», ajv говорит «какое поле нарушает какое ключевое слово», а Prettier — только «форматирование несогласовано».

4. Хуки pre-commit

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

Будьте осторожны с конфигурационными файлами инструментов вроде package.json и tsconfig.json; не позволяйте Prettier переформатировать их бездумно — некоторые инструменты чувствительны к форматированию (допустимый JSON не должен таким быть, но на практике это создавало проблемы). Их можно исключить по отдельности.

5. Советы по отладке

  1. Используйте jq -e как утверждение: код выхода равен 1, когда результат выражения — false или null, поэтому его можно сразу ставить в скрипты как проверку;
  2. jq 'paths' перечисляет все пути, давая быстрый обзор структуры незнакомого документа;
  3. jq '.. | objects | keys' находит все когда-либо встречавшиеся имена ключей — удобно для охоты за несогласованным написанием;
  4. Форматируйте перед сравнением в редакторе: неформатированный diff — чистый шум; структурное сравнение вроде /diff точнее.

6. Чек-лист

  • [ ] Маркеры ошибок в редакторе точны до строки и столбца, а разбор снабжён debounce;
  • [ ] Командные скрипты передают аргументы через jq --arg, а не склейкой строк;
  • [ ] В CI есть все три слоя валидации (синтаксис/структура/стиль);
  • [ ] pre-commit обрабатывает только подготовленные файлы, чтобы полное сканирование не замедляло коммиты;
  • [ ] Версии инструментов закреплены в package.json или .tool-versions.

Вопросы и ответы

Как выбрать между CodeMirror 6 и Monaco?

Для утилитарных сайтов и мобильных устройств предпочитайте CodeMirror 6: он небольшой, модульный и хорошо поддерживается на мобильных, а подсветку синтаксиса, сопоставление скобок и свёртывание можно собирать по необходимости. К Monaco обращайтесь, только когда нужен полноценный опыт IDE с несколькими файлами, переходом к определению и автодополнением — ценой пакета в несколько мегабайт и более высокой стоимости кастомизации.

Почему в CI нужны проверки синтаксиса, структуры и стиля вместе?

Три слоя сообщают совершенно разные ошибки: jq empty говорит, какая строка сломана, ajv — какое поле нарушает какое ключевое слово, а Prettier — только что форматирование несогласовано. Если убрать один слой, ошибки остальных легко прочитать неправильно, поэтому держите все три и останавливайтесь, как только слой падает.

Можно ли вместо валидации в CI положиться на pre-commit?

Нет. Хуки обрабатывают только подготовленные файлы, что даёт обратную связь в течение минуты, но не может покрыть весь репозиторий или изменения, обошедшие коммит. CI отвечает за полноту: держите pre-commit на подготовленных файлах, а полное сканирование оставляйте CI.