Skip to content
Назад к блогу
Руководства

От JSON5 к JSONC: руководство по более лояльному формату JSON

Различия JSON5 и JSONC, форматирование конфигов с комментариями и интеграция форматтеров в CI-пайплайн — с реальными примерами кода.

9 мин чтения

Когда строгий JSON заставляет вас отлаживать код глубоко за полночь из-за одной пропущенной запятой, пора познакомиться с его более лояльными собратьями — JSON5 и JSON with Comments (JSONC).

Что такое JSON5?

JSON5 — это расширение JSON, заимствующее возможности из ECMAScript 5.1: ключи без кавычек, замыкающие запятые, строки в одинарных кавычках, комментарии и шестнадцатеричные числа. Формат поддерживается сообществом и предназначен для того, чтобы конфигурационные файлы, написанные вручную, были читабельнее и прощали мелкие ошибки в большей степени, чем строгий JSON.

Что такое JSONC?

JSONC (JSON with Comments) — минимальное расширение стандартного JSON, добавляющее поддержку однострочных (//) и многострочных (/* */) комментариев. Допустимы ли в нём замыкающие запятые, зависит от парсера. JSONC используется как нативный формат настроек VS Code, файла tsconfig.json и других конфигурационных файлов TypeScript.

Зачем нужен «лояльный» JSON

  • Узкие места читаемости: стандартный JSON запрещает комментарии, замыкающие запятые, одинарные кавычки и так далее, что мешает ясности в конфигах и демонстрационных файлах.
  • Боль командной работы: гигантские JSON-файлы без подсказок поддерживать тяжело, и одно мелкое изменение может сломать всё.
  • Реалии DevOps: Kubernetes и CI/CD-пайплайны часто на лету объединяют или генерируют JSON; лояльный синтаксис резко сокращает ручные правки.

JSON5 и JSONC — обзор

ВозможностьJSON (RFC 8259)JSONCJSON5
Комментарии // и /* */НетДаДа
Замыкающие запятыеНетЗависит от парсера (см. ниже)Да, одна на объект или массив
Ключи без кавычекНетНетДа
Строки в одинарных кавычкахНетНетДа
Перенос строкового литерала на новую строку (экранированный перевод строки)НетНетДа
Шестнадцатеричные числа (0x1F)НетНетДа
.5, 5., ведущий +НетНетДа
Infinity, NaNНетНетДа
Двоичные числа (0b101)НетНетНет
СпецификацияRFC 8259 / ECMA-404Формального стандарта нет; на практике формат определяют VS Code и jsonc-parserСпецификация JSON5 1.0.0
Читается встроенными JSON.parse / json.loadsДаНетНет

Источники: спецификация JSON5, документация VS Code по JSON и RFC 8259. Строку про двоичные числа мы проверили сами: JSON5.parse('{a: 0b101}') с json5 2.2.3 завершается ошибкой JSON5: invalid character 'b' at 1:6.

Одной фразой: JSON5 ощущается как литерал JavaScript-объекта, а JSONC — это обычный JSON, который терпит комментарии: ключи и строки в нём по-прежнему берутся в двойные кавычки.

Замыкающие запятые в JSONC зависят от парсера

Официальной спецификации у JSONC нет. Microsoft неформально ввела формат для конфигурационных файлов VS Code и выпустила вместе с ним jsonc-parser. Черновик сообщества на jsonc.org пытается формализовать JSONC, но и там сказано лишь, что парсеры «MAY support trailing commas» (могут поддерживать замыкающие запятые). На практике инструменты ведут себя по-разному:

Парсер или инструментЗамыкающая запятаяИсточник
VS Code, режим JSON with CommentsПринимается, но с предупреждениемДокументация VS Code
jsonc-parser 3.3.1, параметры по умолчаниюОтмечается ошибками PropertyNameExpected / ValueExpected, но значение всё равно возвращаетсяЗапуск ниже
jsonc-parser 3.3.1, allowTrailingComma: trueПринимаетсяЗапуск ниже
TypeScript 5.9.3 (tsc -p)ПринимаетсяЗапуск на примере tsconfig.json ниже
Deno (deno.jsonc)ПринимаетсяДокументация Deno по конфигурации

Если файл должен читаться любым парсером JSONC, обходитесь без замыкающих запятых.

Примеры синтаксиса

Чистый JSON (строгий)

{
  "name": "Go Tools",
  "features": ["Base64", "JSON Formatter"]
}

Пример JSON5

Файл config.json5:

// конфиг для разработки
{
  name: 'go-tools',
  port: 0x1F90,       // 8080 в шестнадцатеричной записи
  tags: ['json', 'json5',],
}

Пример JSONC

Файл tsconfig.json:

{
  // строгая проверка типов
  "compilerOptions": {
    "strict": true,
    "target": "ES2022", /* современный синтаксис на выходе */
  },
  "include": ["src"],
}

Как определить формат файла

По одному расширению этого не понять: файл .json вполне может разбираться как JSONC или JSON5. Сверьтесь с таблицей, а затем с документацией инструмента, который читает файл.

ФайлФорматПримечаниеИсточник
tsconfig.json, jsconfig.json, tsconfig.*.jsonJSONCVS Code открывает их в режиме JSONC; tsc 5.9.3 принимает комментарии и замыкающие запятыеИсходный код VS Code (typescript-basics), наш запуск
.vscode/settings.json, tasks.json, launch.jsonJSONCПеречислены в документации как файлы JSON with CommentsДокументация VS Code
devcontainer.jsonJSONCСпецификация называет его «a JSON with Comments file» (файл формата JSON with Comments)Спецификация Dev Container
deno.jsoncJSONC«with deno.jsonc you can add comments and trailing commas» (в deno.jsonc можно добавлять комментарии и замыкающие запятые)Документация Deno
babel.config.json, .babelrc.jsonJSON5, несмотря на расширение .jsonBabel разбирает их как JSON5; VS Code подсвечивает их как JSONCДокументация Babel, исходный код VS Code
renovate.json5, .renovaterc.json5JSON5renovate.json тоже принимает JSONCДокументация Renovate
Любой файл *.json5JSON5——
package.jsonСтрогий JSONnpm: «It must be actual JSON, not just a JavaScript object literal.» (это должен быть настоящий JSON, а не просто литерал JavaScript-объекта)Документация npm, наш запуск

Файл babel.config.json5 Babel не ищет: расширения .json5 нет среди документированных. Как JSON5 он читает именно варианты с расширением .json.

Сообщения об ошибках — дословно

Мы передали каждой среде выполнения два небольших файла. В comment.json есть комментарий:

{
  // порт dev-сервера
  "port": 8080
}

В trailing.json — замыкающая запятая:

{
  "port": 8080,
}

Node.js 26.10.0, JSON.parse (Chrome Headless Shell 156 выдаёт тот же текст, поскольку оба работают на V8):

comment.json  -> SyntaxError: Expected property name or '}' in JSON at position 4 (line 2 column 3)
trailing.json -> SyntaxError: Expected double-quoted property name in JSON at position 18 (line 3 column 1)

Python 3.13.5, json.loads:

comment.json  -> json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)
trailing.json -> json.decoder.JSONDecodeError: Illegal trailing comma before end of object: line 2 column 15 (char 16)

jq 1.7:

comment.json  -> jq: parse error: Invalid numeric literal at line 2, column 5
trailing.json -> jq: parse error: Expected another key-value pair at line 3, column 1

npm 11.19.1, со строкой // comment в package.json:

npm error code EJSONPARSE
npm error JSON.parse Invalid package.json: JSONParseError: Expected property name or '}' in JSON at position 4 (line 2 column 3) while parsing near "{\n  // comment\n  \"name\":..."
npm error JSON.parse Failed to parse JSON data.
npm error JSON.parse Note: package.json must be actual JSON, not just JavaScript.

Как их читать:

  • position 4 (line 2 column 3) указывает на первый / комментария. Если ошибка приходится на начало строки, которая начинается с // или /*, перед вами почти наверняка JSONC или JSON5.
  • На замыкающей запятой V8 и Python указывают на разные места. V8 сообщает о закрывающей } (строка 3), а Python 3.13.5 — о самой запятой (строка 2, столбец 15). В других версиях формулировки могут отличаться; текст выше — ровно то, что вывели эти версии.
  • Если в сообщении процитирован невидимый символ, как в выводе Node 26 Unexpected token '', "{}" is not valid JSON (в обоих местах внутри кавычек на самом деле стоит невидимый U+FEFF), скорее всего, файл начинается не с комментария, а с невидимой метки порядка байтов (BOM). Подробнее — в статье UTF-8 BOM и ошибки JSON.parse.

Конвертация JSONC и JSON5 в стандартный JSON

При конвертации пропадают все комментарии: в JSON для них просто нет места. Поэтому исходником остаётся файл с комментариями, а .json на выходе стоит считать сгенерированным артефактом.

Node.js: из JSON5 в JSON с помощью json5

// json5-to-json.mjs (установка: npm install json5)
import { readFileSync, writeFileSync } from 'node:fs';
import JSON5 from 'json5';

const data = JSON5.parse(readFileSync('config.json5', 'utf8'));
writeFileSync('config.json', JSON.stringify(data, null, 2) + '\n');

Если запустить скрипт с json5 2.2.3 на примере JSON5 выше, config.json получится таким:

{
  "name": "go-tools",
  "port": 8080,
  "tags": [
    "json",
    "json5"
  ]
}

Node.js: из JSONC в JSON с помощью jsonc-parser

jsonc-parser — парсер JSON с комментариями от Microsoft. Его parse() не выбрасывает исключений при синтаксических ошибках: проблемы он складывает в массив errors и всё равно возвращает значение, насколько удалось его разобрать. Поэтому массив нужно проверять самостоятельно:

// jsonc-to-json.mjs (установка: npm install jsonc-parser)
import { readFileSync } from 'node:fs';
import { parse, printParseErrorCode } from 'jsonc-parser';

const errors = [];
const data = parse(readFileSync('tsconfig.json', 'utf8'), errors, {
  allowTrailingComma: true,
});
if (errors.length > 0) {
  for (const e of errors) console.error(printParseErrorCode(e.error), 'at offset', e.offset);
  process.exit(1);
}
console.log(JSON.stringify(data, null, 2));

С jsonc-parser 3.3.1 и примером tsconfig.json выше скрипт выводит чистый JSON и завершается с кодом 0. Без allowTrailingComma: true тот же файл даёт ошибки PropertyNameExpected и ValueExpected на }, которая стоит сразу после каждой замыкающей запятой.

Python: пакет json5

В модуле json из стандартной библиотеки нет опции для комментариев. Пакет json5 читает JSON5, а значит, и JSONC: комментарии и замыкающие запятые в JSON5 допустимы.

# установка: pip install json5
import json

import json5

with open("tsconfig.json", encoding="utf-8") as f:
    data = json5.load(f)

print(json.dumps(data, indent=2, ensure_ascii=False))

Проверено на Python 3.13.5 и json5 0.17.3: скрипт выводит тот же JSON, что и версия для Node.

Командная строка: CLI json5

В npm-пакет json5 входит CLI, который конвертирует файл в JSON и проверяет синтаксис. JSONC-файлы он тоже читает:

npx json5 config.json5                      # компактный JSON в stdout
npx json5 -s 2 -o config.json config.json5  # с отступами, запись в файл
npx json5 -v tsconfig.json                  # только проверка; код выхода 1 при синтаксической ошибке

Поскольку с -v команда при синтаксической ошибке завершается с кодом 1, её можно в том же виде использовать как шаг CI, который проверяет JSON5- и JSONC-файлы, отредактированные вручную.

jq здесь не поможет: как видно выше, jq 1.7 останавливается на первом же комментарии.

Осторожно с Infinity и NaN

JSON5 допускает Infinity и NaN, но в JSON их записать нельзя, и в двух языках это решается по-разному:

JSON.stringify(JSON5.parse('{a: Infinity, b: NaN}'));
// '{"a":null,"b":null}'  (молча превращается в null)
json.dumps(json5.loads('{a: Infinity, b: NaN}'))
# '{"a": Infinity, "b": NaN}'  (такой вывод не является валидным JSON)
json.dumps(json5.loads('{a: Infinity}'), allow_nan=False)
# ValueError: Out of range float values are not JSON compliant: inf

Если в JSON5-файле могут встретиться эти значения, в Python передавайте allow_nan=False или проверяйте их наличие до конвертации. Строки JSON5 в одинарных кавычках, содержащие " или обратные слеши, JSON.stringify экранирует заново. Правила описаны в руководстве по экранированию строк JSON.

Проверка получившегося JSON

После конвертации вставьте результат в форматировщик JSON, чтобы проверить его и привести к читаемому виду (pretty-print). Инструмент работает в браузере.

Учтите: форматировщик принимает только строгий JSON. Он разбирает ввод браузерным JSON.parse, поэтому JSONC- или JSON5-файл, вставленный как есть, выдаст синтаксическую ошибку с номером строки и столбца, на которых остановился разбор. Сначала конвертируйте, потом проверяйте.

Когда JSONC и JSON5 не подходят

  • Payload в API и обмен данными. В RFC 8259 сказано, что генератор JSON «MUST strictly conform to the JSON grammar» (обязан строго соответствовать грамматике JSON). На принимающей стороне обычно стоит JSON.parse или json.loads, и оба отвергают комментарии.
  • package.json. npm требует строгий JSON. Достаточно одного комментария, чтобы команды npm вроде npm run падали с EJSONPARSE.
  • Файлы, которые читают инструменты вне вашего контроля. require('./tsconfig.json') в Node использует строгий парсер JSON и падает на tsconfig с комментариями (SyntaxError: …tsconfig.json: Expected property name or '}' in JSON at position 4). Любому скрипту, который читает JSONC-файл, нужен парсер JSONC.
  • Файл .json, который незаметно стал JSONC. Документация Renovate рекомендует файл .jsonc вместо .json с комментариями, поскольку последний «can cause issues with editors and syntax highlighting» (может вызывать проблемы с редакторами и подсветкой синтаксиса). Явное расширение сразу сообщает любому инструменту, чего ожидать.

Если формат конфигурации выбирается с нуля и комментарии нужны везде, присмотритесь к TOML и YAML: они поддерживают комментарии нативно. Сравнение — в статье TOML vs JSON vs YAML.

Реальные конфигурационные файлы

JSON5 и JSONC уже широко используются в конфигурационных файлах, с которыми вы сталкиваетесь ежедневно. Ниже — конкретные примеры:

TypeScript (tsconfig.json — JSONC)

{
  // Строгий режим ловит больше ошибок на этапе компиляции
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "outDir": "./dist",
    // Алиасы путей делают импорты чище
    "paths": {
      "@/*": ["./src/*"],
      "@tests/*": ["./tests/*"],
    },
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"],
}

tsconfig.json в TypeScript нативно использует JSONC — комментарии и замыкающие запятые работают «из коробки». Это один из самых распространённых JSONC-файлов в любом JavaScript- или TypeScript-проекте.

Babel (babel.config.json — JSON5)

Babel разбирает babel.config.json и .babelrc.json как JSON5, поэтому ключи без кавычек и одинарные кавычки там работают.

{
  // Одинарные кавычки и ключи без кавычек делают конфиг читабельнее
  presets: [
    ['@babel/preset-env', {
      targets: '> 0.25%, not dead',
      modules: false,  // Отдадим модули сборщику
    }],
  ],
  plugins: [
    '@babel/plugin-transform-runtime',
  ],
}

Настройки рабочей области VS Code (.vscode/settings.json — JSONC)

{
  // Настройки редактора
  "editor.fontSize": 14,
  "editor.tabSize": 2,
  "editor.formatOnSave": true,

  // Переопределения по языку
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
  },
}

Практические советы и оговорки

1. Конвертируйте перед продакшеном

Браузеры по-прежнему требуют строгий JSON для JSON.parse. Конвертируйте конфиги на этапе сборки, как показано выше в разделе о конвертации в стандартный JSON.

2. Безопасность и надёжность

Лояльность может скрывать «лишние» поля. Всегда валидируйте конфигурацию через JSON Schema или zod, прежде чем её применять. И при работе со snapshot-тестами помните: разница JSON5 / JSONC между запусками часто «шумит» на полях вроде timestamp, requestId и UUID — практические паттерны игнорирования таких полей разобраны в гайде по игнорированию timestamp и ID при JSON diff. Если в проекте параллельно лежат YAML-конфиги, особенно для Kubernetes — обратите внимание на «норвежскую проблему» YAML и различия JSON-YAML: безкавычные значения вроде no и off тихо превращаются в boolean.

// Проверяем форму конфига через zod после разбора
import { readFileSync } from 'node:fs';
import { z } from 'zod';
import JSON5 from 'json5';

const ConfigSchema = z.object({
  port: z.number().min(1).max(65535),
  host: z.string(),
  debug: z.boolean().default(false),
});

const raw = JSON5.parse(readFileSync('config.json5', 'utf8'));
const config = ConfigSchema.parse(raw); // Бросит ошибку при несоответствии

3. Командные соглашения

  • В README объявите, что *.json5 — только для конфигов; пакеты для релиза должны поставляться со строгим .json.
  • Стандартизируйте правила Prettier, чтобы избежать «шумных» диффов.
  • Используйте .editorconfig для согласованных отступов в JSON, JSON5 и JSONC.

4. Производительность

Разбор JSON5/JSONC добавляет зависимости и небольшой оверхед — приемлемо для CLI и dev-инструментов, но в продакшене всё нужно измерять. Для конфигурационных файлов, загружаемых один раз при старте, это незаметно. На горячих путях, где разбираются тысячи объектов в секунду, придерживайтесь строгого JSON.

Часто задаваемые вопросы

В чём разница между JSON5 и JSONC?

JSONC — это стандартный JSON плюс комментарии // и /* */; допустимы ли замыкающие запятые, зависит от парсера. JSON5 идёт дальше и добавляет синтаксис ES5.1: ключи без кавычек, одинарные кавычки, hex-числа, Infinity/NaN и замыкающие запятые. Корректный JSONC-файл обычно является и корректным JSON5, но не наоборот. Выбирайте JSONC для конфигов, где достаточно комментариев, и JSON5, когда нужен более богатый синтаксис.

Можно ли использовать JSON5 или JSONC в продакшен-API?

Нет — JSON5 и JSONC спроектированы для конфигурационных файлов, а не для обмена данными. В API следует использовать стандартный JSON (RFC 8259) для максимальной совместимости. Оставьте JSON5/JSONC для локальных конфигов вроде tsconfig.json, .vscode/settings.json или конфигурации окружения, где читаемость для человека важнее, чем удобство машины.

VS Code поддерживает JSON5 нативно?

Без расширений — нет. Встроенное расширение JSON в VS Code регистрирует такие языки, как json, jsonc и jsonl, но не json5, поэтому для подсветки файлов .json5 нужно расширение из маркетплейса. JSONC, напротив, поддерживается «из коробки»: настройки, tasks.json, launch.json и tsconfig.json открываются в режиме JSON with Comments.

Как конвертировать JSON5 в стандартный JSON?

Используйте npm-пакет json5: JSON5.parse() читает JSON5, затем JSON.stringify() выводит стандартный JSON. Для CLI: npx json5 < input.json5 > output.json. Комментарии при этом пропадают, а Infinity и NaN после JSON.stringify превращаются в null. Онлайн-инструменты, например наш JSON Formatter, помогут проверить корректность результата.

JSONC — это то же самое, что «JSON with Comments»?

Да — JSONC расшифровывается как «JSON with Comments»: так называется языковой режим VS Code, а jsonc — его идентификатор языка и расширение файлов. Формального стандарта нет, на jsonc.org опубликован черновик сообщества, основанный на том, что jsonc-parser принимает по умолчанию. К стандартному JSON формат добавляет комментарии // и /* */, а поддержка замыкающих запятых зависит от парсера. Парсеры удаляют комментарии до обработки, поэтому итоговая структура данных идентична стандартному JSON.

Подборка браузерных инструментов разработчика, включая кодирование Base64, генерацию хешей и конвертацию timestamp, разобрана в подборке базовых инструментов разработчика.

Итог

Поиск баланса между читаемостью и строгостью — классическая дилемма разработчика. JSON5 и JSONC улучшают опыт написания, и при правильно настроенном пайплайне сборки и валидации можно безопасно пользоваться преимуществами «лояльного JSON».

Источники

Теги: json json5 jsonc formatting developer-tools

Похожие статьи

Все статьи