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

Коротко: выбирайте редактор по сценарию — 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());
}
}),
],
});
Четыре момента, которые стоит отметить:
json()даёт подсветку синтаксиса и сопоставление скобок — не пишите своё;jsonParseLinter()создаёт маркеры ошибок с точностью до строки и столбца; сочетайте его сlintGutter(), чтобы показывать значки рядом с номерами строк;updateListenerобязательно должен быть с debounce; вызовJSON.parseна ста тысячах строк при каждом нажатии клавиши заметно подвесит интерфейс;- Большим документам нужны оптимизации помимо
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. Советы по отладке
- Используйте
jq -eкак утверждение: код выхода равен 1, когда результат выражения —falseилиnull, поэтому его можно сразу ставить в скрипты как проверку; jq 'paths'перечисляет все пути, давая быстрый обзор структуры незнакомого документа;jq '.. | objects | keys'находит все когда-либо встречавшиеся имена ключей — удобно для охоты за несогласованным написанием;- Форматируйте перед сравнением в редакторе: неформатированный 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.