Editores, linha de comando e cadeias de automação
Resumo: Editores resolvem "ver com clareza, editar corretamente", enquanto a linha de comando resolve "em lote, repetível". Cada lado tem algumas ferramentas que continuam úteis por uma década.

Resumo da ópera: escolha o editor por cenário — CodeMirror 6 para sites utilitários e mobile, Monaco só quando precisar da experiência completa de IDE; deixe o trabalho em lote para o jq mais três verificações no CI para sintaxe, estrutura e estilo, e sempre passe argumentos com jq --arg.
A era de verificar JSON à mão já deveria ter acabado: tudo o que uma máquina consegue repetir, não deixe para os olhos humanos.
1. Editores no navegador
1.1 Integração mínima do 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) {
// Aplique debounce antes de fazer trabalho pesado; não formate a cada tecla
scheduleParse(update.state.doc.toString());
}
}),
],
});
Quatro pontos a observar:
json()fornece realce de sintaxe e correspondência de colchetes — não escreva o seu próprio;jsonParseLinter()produz marcadores de erro em nível de linha/coluna; combine-o comlintGutter()para mostrar ícones ao lado dos números de linha;- O
updateListenerprecisa de debounce; chamarJSON.parseem cem mil linhas a cada tecla vai travar visivelmente; - Documentos grandes precisam de otimizações além de
EditorView.lineWrappingpara evitar renderizar tudo de uma vez (o CodeMirror 6 renderiza por viewport por padrão, o que é uma melhoria em relação a versões antigas).
1.2 Dobramento e sumários
O CodeMirror 6 tem dobramento embutido; em cenários JSON você normalmente dobra por "objeto/array":
import { foldGutter, foldKeymap } from '@codemirror/language';
import { keymap } from '@codemirror/view';
Com foldGutter() e keymap.of(foldKeymap), os usuários podem recolher arrays longos com um atalho de teclado.
1.3 Escolhendo entre CodeMirror e Monaco
| Dimensão | CodeMirror 6 | Monaco |
|---|---|---|
| Tamanho do bundle | Pequeno, modular | Grande (vários MB) |
| Mobile | Bem suportado | Experiência medíocre |
| Serviços de linguagem | Você precisa construir os seus | Ricos, embutidos |
| Custo de personalização | Baixo | Médio |
Sites utilitários e mobile-first → CodeMirror; experiência completa de IDE (vários arquivos, ir para definição, autocompletar) → Monaco.
2. Linha de comando: seis receitas de jq de alta frequência
jq é para JSON o que sed + awk são para texto; aprender só uma pequena parte da sua sintaxe cobre oitenta por cento das necessidades do dia a dia.
# 1. Selecionar campos (o mais comum)
jq '.data.items[].name' response.json
# 2. Filtrar + remodelar
jq '.data.items[] | select(.price < 10) | {id, price}' response.json
# 3. Agregações (comprimento, soma, máximo)
jq '[.items[] | .price] | {count: length, total: add, max: max}' response.json
# 4. Agrupar e agregar
jq '[.items[]] | group_by(.category) | map({category: .[0].category, count: length})' response.json
# 5. Mesclar vários arquivos em um array
jq -s '.' part-*.json > merged.json
# 6. Processar JSON Lines linha a linha
jq -c 'select(.level == "error")' app.jsonl
# Chaves de saída comuns
jq -r '.data.name' # Remove as aspas para o resultado entrar limpo no shell
jq -c '.' # Saída compacta, uma linha
jq --arg id "$ID" '.id == $id' # Passe argumentos com segurança, evitando injeção por concatenação
--arg merece menção especial: concatenar uma variável diretamente em uma expressão quebra assim que o valor contém aspas, enquanto --arg deixa o jq cuidar do escaping.
2.1 Outras ferramentas em resumo
| Ferramenta | Finalidade | Em uma frase |
|---|---|---|
yq |
Conversão YAML/JSON/XML | Sintaxe parecida com jq, o cavalo de batalha para arquivos de configuração |
dasel |
Consulta unificada entre formatos | Suporta JSON/YAML/TOML/XML/CSV |
fx |
Navegação interativa em JSON | Clique pelo terminal, bom para explorar |
jless |
Navegação paginada no terminal | Como less, com dobramento e busca |
gron |
Achatar JSON em linhas grepáveis | Ótima ferramenta para descobrir "em que nível está este campo" |
ajv-cli |
Validação de schema | Validar arquivos JSON no CI |
A ideia por trás do gron vale especialmente a pena conhecer:
$ echo '{"a":{"b":[1,2]}}' | gron
json = {};
json.a = {};
json.a.b = [];
json.a.b[0] = 1;
json.a.b[1] = 2;
Uma vez achatado, o grep consegue localizar o caminho, o que é bem mais rápido do que expandir nível por nível em um editor.
3. Três camadas de validação no CI
| Camada | Ferramenta | O que uma falha significa |
|---|---|---|
| Sintaxe | JSON.parse / jq empty |
O arquivo em si está malformado |
| Estrutura | ajv-cli + schema |
Campos ausentes, tipos errados |
| Estilo | Prettier | Formatação inconsistente, diffs barulhentos |
# Sintaxe: valide em lote todos os arquivos json do repositório
find . -name '*.json' -not -path './node_modules/*' -print0 \
| xargs -0 -n1 jq empty
# Estrutura: valide contra um schema
npx ajv-cli validate -s schemas/order.json -d 'fixtures/orders/*.json' --strict=false
# Estilo: apenas verificar, sem modificar
npx prettier --check "**/*.json"
Você precisa das três camadas, porque as mensagens de erro são completamente diferentes:
o jq empty só diz "qual linha está quebrada", o ajv diz "qual campo viola qual palavra-chave" e o Prettier só diz "a formatação está inconsistente".
4. Hooks de pre-commit
# Exemplo de .husky/pre-commit (trecho)
npx lint-staged
{
"lint-staged": {
"*.json": ["prettier --write", "jq empty"]
}
}
Cuidado com arquivos de configuração de ferramentas como package.json e tsconfig.json; não deixe o Prettier reindentá-los de qualquer jeito —
algumas ferramentas são sensíveis à formatação (JSON válido não deveria ser, mas na prática isso já causou problemas). Você pode excluí-los individualmente.
5. Dicas de depuração
- Use
jq -ecomo asserção: o código de saída é 1 quando o resultado da expressão éfalseounull, então ele pode entrar direto em scripts como verificação; jq 'paths'lista todos os caminhos, dando uma visão rápida da estrutura de um documento desconhecido;jq '.. | objects | keys'encontra todo nome de chave que já apareceu, o que é prático para caçar grafias inconsistentes;- Formate antes de comparar no editor: um diff sem formatação é puro ruído; uma comparação estrutural como
/diffé mais precisa.
6. Lista de verificação
- [ ] Os marcadores de erro do editor são precisos em linha e coluna, e a análise tem debounce;
- [ ] Os scripts da equipe passam argumentos com
jq --argem vez de concatenar strings; - [ ] O CI tem as três camadas de validação (sintaxe/estrutura/estilo);
- [ ] O pre-commit processa apenas arquivos preparados, para que uma varredura completa não atrase os commits;
- [ ] As versões das ferramentas estão fixadas em
package.jsonou.tool-versions.
Perguntas frequentes
Como escolho entre CodeMirror 6 e Monaco?
Para sites utilitários e mobile, prefira CodeMirror 6: é pequeno, modular e bem suportado em mobile, e realce de sintaxe, correspondência de colchetes e dobramento podem ser compostos conforme a necessidade. Recorra ao Monaco apenas quando precisar da experiência completa de IDE com vários arquivos, ir para definição e autocompletar — ao custo de um bundle de vários megabytes e maior esforço de personalização.
Por que o CI precisa de verificações de sintaxe, estrutura e estilo juntas?
As três camadas relatam erros completamente diferentes: o jq empty diz qual linha está quebrada, o ajv diz qual campo viola qual palavra-chave e o Prettier só diz que a formatação está inconsistente. Remover uma camada faz os erros das outras ficarem fáceis de mal interpretar, então mantenha as três e pare assim que uma camada falhar.
Devo confiar no pre-commit em vez de validar no CI?
Não. Os hooks processam apenas arquivos preparados, o que dá feedback em um minuto mas não cobre o repositório inteiro nem alterações que contornam o commit. O CI é responsável pela completude: mantenha o pre-commit nos arquivos preparados e deixe as varreduras completas para o CI.