A resposta curta
Douglas Crockford, que especificou o JSON, removeu os comentários de propósito. A razão que ele declarou foi que as pessoas tinham começado a colocar diretivas de parsing neles, o que quebraria a interoperabilidade — a única propriedade pela qual o formato existe.
Então //, /* */ e # são todos erros de sintaxe, em qualquer parser conforme, em qualquer linguagem. Não há flag para ativá-los porque a gramática não tem produção nenhuma para eles.
O que acontece se você tentar
O erro quase nunca contém a palavra "comentário", e é por isso que isso confunde. O parser chega no / onde esperava uma vírgula ou uma chave de fechamento, e reporta isso.
| Escrito | Resultado |
|---|---|
// nota ou # nota | Erro de sintaxe |
/* nota */ | Erro de sintaxe |
{"port": 8080,} | Erro de sintaxe: vírgula final |
{'port': 8080} | Erro de sintaxe: aspas simples |
{port: 8080} | Erro de sintaxe: chave sem aspas |
Entrada
{
"port": 8080 // the port
}Erro
Expected ',' or '}' after property value in JSON at position 17 (line 2 column 16)
/. Nada na mensagem menciona comentários, então a reação usual é ir procurar uma vírgula faltando.JSON5 e JSONC
Existem dois superconjuntos, e a diferença importa na hora de escolher. Nenhum dos dois é JSON: um arquivo escrito em qualquer um deles será rejeitado pelo JSON.parse e por todo parser estrito.
- JSONC é JSON mais comentários e vírgulas finais. Nada além disso. É o que o VS Code usa para o
settings.jsone o que o compilador do TypeScript aceita notsconfig.json— e é por isso que ali os comentários funcionam e as pessoas concluem, com razão, que o JSON os permite. - JSON5 vai bem mais longe: chaves sem aspas, aspas simples, números hexadecimais, pontos decimais no início e no fim,
InfinityeNaN, strings multilinha. Está mais perto de um literal de objeto JavaScript do que de JSON. - Nenhum tem tipo de mídia registrado. Não existe
application/json5, então são formatos de arquivo para ferramentas que você controla, não formatos de transporte para uma API.
| Arquivo de config próprio | Requisição ou resposta de API | |
|---|---|---|
| JSON | Sim | Sim |
| JSONC | Se quem lê suportar | Não |
| JSON5 | Se quem lê suportar | Não |
As quatro alternativas
Ordenadas por confiabilidade. As duas primeiras estão bem; a terceira tem um custo real; a quarta é uma armadilha.
- 1. Use um formato que tenha comentários. Se o arquivo é configuração que uma pessoa mantém, YAML e TOML suportam comentários
#como parte da gramática. Isso é a solução, não um contorno: um arquivo de configuração não tem motivo para ser JSON. - 2. Remova os comentários antes de parsear. É o padrão para config no estilo JSONC: uma passada de limpeza e depois
JSON.parse. Use um parser JSONC de verdade e não uma expressão regular, porque uma regex vai destruir alegremente um//que apareça dentro de um valor de string, como uma URL. - 3. Uma chave acompanhante. JSON válido, e às vezes a única opção quando o arquivo precisa continuar estrito. O custo é que agora é dado: vai para os clientes, aparece nos diffs do objeto parseado, e qualquer schema com
additionalProperties: falsevai rejeitá-la. - 4. Não "comente" um bloco adicionando uma chave como `"_disabled"`. O bloco continua sendo parseado, continua ali, e a próxima pessoa não vai saber quais chaves aquele marcador cobria. Apague; o histórico está no controle de versão.
A abordagem da chave acompanhante
{
"_comment": "port must match the load balancer",
"port": 8080
}_comment agora é um campo dos seus dados, e um schema estrito vai rejeitá-lo.Converter para YAML pelos comentários
Se o objetivo é um arquivo de configuração que uma pessoa possa anotar, converter o JSON para YAML uma vez e depois adicionar os comentários à mão é o caminho limpo. A direção contrária é onde se perde algo, e vale a pena ver exatamente como.
- Comentários `#` de linha inteira são descartados. Comportamento correto: no JSON não há onde colocá-los.
- Um `#` no fim de um escalar sem aspas passa a fazer parte do valor. O
hostvoltou como"localhost # trailing comment". A própria especificação do YAML exige um espaço antes de um comentário em linha e o trata como comentário, então isso é uma limitação do conversor, não do YAML. Coloque o valor entre aspas ou o comentário em uma linha própria e o ciclo fica limpo. - Então trate a conversão como de mão única. Gere YAML a partir do JSON, anote o YAML e mantenha o YAML como fonte da verdade em vez de converter de ida e volta.
YAML com comentários
# the port the server binds to port: 8080 host: localhost # trailing comment features: # experimental, off by default - search - export
Convertido para JSON
{
"port": 8080,
"host": "localhost # trailing comment",
"features": [
"search",
"export"
]
}host.O que fazer
A decisão depende, na verdade, do que o arquivo é. Dados que se movem entre máquinas não precisam de comentários. Um arquivo que uma pessoa edita precisa, e esse arquivo não deveria ter sido JSON.
- Payloads de API: sem comentários, sem superconjuntos. Documente os campos em um schema ou na sua documentação de API, onde quem lê realmente vai olhar.
- Uma config lida por uma única ferramenta que você controla: JSONC se a ferramenta suportar; se não, limpar e depois parsear.
- Uma config que várias pessoas editam: mude para YAML ou TOML e pare de brigar com o formato.
- Qualquer coisa que você precise explicar no lugar: se a explicação importa o bastante para ser escrita, importa o bastante para ir em um
descriptiondo schema, que as ferramentas conseguem de fato mostrar a quem lê.
Experimente, ou continue lendo
- JSON para YAMLConverta uma vez e adicione os comentários que o YAML suporta nativamente.
- JSON vs YAMLEm qual dos dois o arquivo deveria estar desde o começo.
- Escape em JSONA outra regra que a especificação impõe e que surpreende as pessoas.
- Guia completo de JSONA gramática completa, na ordem em que você precisa dela.