JSON Toolkit

JSON5 e JSONC: JSON com comentários

Resumo: Os dois dialetos existem porque configuração escrita por humanos precisa de comentários e vírgulas finais, mas a sintaxe e o alcance no ecossistema diferem, então escolher errado trava sua cadeia de ferramentas.

Iniciante~10 min de leituraPublicado em 2026-10-30Atualizado em 2026-10-30
Capa de JSON5 e JSONC, JSON com comentários

Resumo da ópera: use JSONC para comentários dentro da configuração do VS Code e do TypeScript, use JSON5 quando precisar da sintaxe de literal ES5.1 mais ampla, como aspas simples ou chaves sem aspas, e mantenha as APIs públicas em JSON padrão.

O JSON padrão não permite comentários, então toda equipe os escreve discretamente mesmo assim — até que um dia o build quebra. Em vez de fazer isso em segredo, escolha um dialeto adequado.

1. Os dois dialetos têm motivações diferentes

  • JSONC (JSON with Comments): JSON padrão mais comentários e vírgulas finais, com quase nenhuma outra mudança de sintaxe. É o padrão de fato do ecossistema do VS Code — settings.json, tsconfig.json e .eslintrc.json todos o usam.
  • JSON5: bem mais ambicioso, alinhado diretamente com o literal de objeto ES5.1 — aspas simples, chaves sem aspas, hexadecimal, Infinity/NaN, continuação de linha com barra invertida e sinais + à frente.

Uma frase para distingui-los: JSONC só deixa a escrita confortável; JSON5 permite escrever um arquivo de configuração como se fosse JavaScript.

2. Tabela comparativa de sintaxe

Recurso JSON padrão JSONC JSON5
Comentários // /* */ ✗ ✓ ✓
Vírgulas finais ✗ ✓ ✓
Strings com aspas simples ✗ ✗ ✓
Chaves sem aspas ✗ ✗ ✓
Números hexadecimais ✗ ✗ ✓
Ponto decimal no início/fim .5 5. ✗ ✗ ✓
Números começando com + ✗ ✗ ✓
Infinity / NaN ✗ ✗ ✓
Continuação com \ no fim da linha ✗ ✗ ✓
Strings multilinha ✗ ✗ ✓ (implementadas por continuação)
Valor de nível superior arbitrário ✓ ✓ ✓

A especificação completa do JSON5 não passa de uma página; o pacote json5 é mantido pela comunidade há muito tempo, e navegadores e Node se comportam de forma idêntica.

3. Análise: duas APIs, dois tipos de capacidade de posicionamento

3.1 JSON5: análise simples do documento inteiro

import JSON5 from 'json5';

const config = JSON5.parse(`
{
  // porta do serviço
  port: 8080,
  host: '0.0.0.0',
  features: ['json5', 'jsonc',],
  retries: 0x10,
}
`);

console.log(config.port, config.retries); // 8080 16

JSON5.parse retorna um objeto simples sem informação de offset — porque não é voltado a cenários de edição, apenas a "ler configuração".

3.2 JSONC: uma árvore de sintaxe com offsets

O valor do jsonc-parser não está na análise, mas na edição. Ele oferece três camadas de API:

API Finalidade Uso típico
parse Analisar em uma árvore carregando offset/length Realce de sintaxe, dobramento, navegação
visit Travessia em profundidade; o callback recebe o caminho do nó Inspeção no estilo JSONPath
modify + applyEdits Produzir uma edição mínima de texto e aplicá-la ao texto original Mudar um valor mantendo comentários
import { parseTree, findNodeAtLocation, modify, applyEdits } from 'jsonc-parser';

const text = `{
  // configuração de porta
  "server": {
    "port": 8080 // 80 em produção
  }
}`;

const tree = parseTree(text);
const portNode = findNodeAtLocation(tree!, ['server', 'port']);
console.log(portNode?.offset, portNode?.length);

const edits = modify(text, ['server', 'port'], 3000, {
  formattingOptions: { insertSpaces: true, tabSize: 2 },
});
console.log(applyEdits(text, edits));

A saída mantém os comentários originais e substitui apenas os três caracteres de 8080:

{
  // configuração de porta
  "server": {
    "port": 3000 // 80 em produção
  }
}

Isso é exatamente o que "editar configuração com expressões regulares" não consegue fazer: um regex não sabe qual 8080 mudar nem que o 8080 dentro de uma string precisa ficar intocado.

3.3 Mensagens de erro precisam carregar offsets

Os códigos de erro do jsonc-parser são valores de enum; os comuns são:

Código de erro Significado
InvalidSymbol Apareceu um caractere que não deveria estar ali
PropertyNameExpected Esperava um nome de chave
ColonExpected Esperava dois-pontos
CommaExpected Esperava vírgula
CloseBraceExpected O objeto não foi fechado
UnexpectedEndOfComment O comentário não foi fechado
InvalidEscapeCharacter Escape inválido

Uma vez convertido offset em linha e coluna, o editor consegue desenhar a marca ondulada exatamente na posição problemática.

4. Quando usar qual

Cenário Recomendação Motivo
Corpos de requisição/resposta de APIs públicas JSON padrão Dialetos não são suportados por clientes generalistas
package.json, composer.json JSON padrão Gerenciadores de pacotes só entendem JSON padrão
tsconfig.json, .vscode/settings.json JSONC Padrão do ecossistema, suportado nativamente pela cadeia de ferramentas
Configuração de aplicação (precisa de comentários) JSONC ou YAML Comentários precisam ser preservados enquanto ferramentas ainda conseguem ler e gravar
Precisar de Infinity, hexadecimal, literais complexos JSON5 O maior poder de expressão
Troca de dados, logs, caches Delimitado por linha ou JSON padrão Streaming e universalidade são necessários

Regra geral: se o arquivo será lido por uma "ferramenta não humana", prefira JSON padrão; só considere um dialeto quando tiver certeza de que ele é lido apenas pelo seu próprio código.

5. Três tipos de risco que os dialetos introduzem

5.1 Transbordo do requisito

Quando outra ferramenta lê um arquivo de configuração JSON5 e chama JSON.parse, ela quebra de vez. O sintoma típico é "funciona bem localmente, falha no Docker" — porque o container executa um caminho de leitura diferente.

Contramedida: adicione ao repositório uma verificação de CI que liste explicitamente quais arquivos podem usar um dialeto; todo o resto é validado como JSON padrão.

5.2 Surpresas em torno da inferência de tipo

JSON5 permite chaves sem aspas e aspas simples, mas não permite trazer construções literais como datas ou expressões regulares — ele continua sendo um formato de dados, não avaliação JavaScript. Pessoas já presumiram que JSON5 conseguiria expressar new Date() só para ver a análise falhar. JSON5 não é eval.

5.3 Comentários descartados silenciosamente

Nem JSON5.stringify nem JSON.stringify preservam comentários. Então "ler, ajustar um valor, gravar de volta" perde todos os comentários. Quando comentários precisam sobreviver, as únicas opções são a API de edição do jsonc-parser ou uma biblioteca YAML que suporte preservação de comentários.

6. Recomendações práticas

  • [ ] Mantenha uma tabela "tipo de arquivo → formato" na documentação da equipe para que ninguém improvise;
  • [ ] Envolva a leitura de configuração em um único loadConfig() que decide internamente qual analisador usar, para que o código de negócio nunca chame JSON.parse diretamente;
  • [ ] Ao modificar programaticamente uma configuração com comentários, use modify + applyEdits; nunca reescreva o arquivo inteiro;
  • [ ] Valide também arquivos de dialeto no CI (jsonc-parser para JSONC, JSON5.parse para JSON5), caso contrário erros de sintaxe só aparecem em tempo de execução;
  • [ ] Use JSON padrão para interfaces públicas, chaves de cache e payloads de fila de mensagens.

Perguntas frequentes

Como devo escolher entre JSON5 e JSONC?

Escolha pelo runtime em vez de pela contagem de sintaxe: VS Code, TypeScript e ESLint leem JSONC por padrão, então JSONC dá a melhor compatibilidade; recorra ao JSON5 apenas quando precisar da sintaxe de literal ES5.1 mais ampla, como aspas simples, chaves sem aspas ou Infinity. Nenhum dos dialetos é adequado para respostas de APIs públicas.

Por que um analisador JSON padrão não consegue ler JSONC diretamente?

JSONC permite comentários e vírgulas finais, enquanto JSON.parse aceita apenas JSON da RFC 8259 e lança erro em ambos. Ler JSONC exige um analisador como jsonc-parser, ou remover os comentários antes de entregar o texto a um analisador padrão.

Os comentários em JSONC devem sobreviver a edições no arquivo?

Sim, mas apenas por uma API de edição. modify e applyEdits do jsonc-parser mudam o nó alvo preservando os demais comentários; analisar em um objeto e serializar descarta todos os comentários.