JSON5 و JSONC: JSON با کامنت
جمعبندی: هر دو گویش وجود دارند چون پیکربندی دستنویس انسان به کامنت و ویرگول انتهایی نیاز دارد، اما نحو و دامنه اکوسیستمشان متفاوت است، پس انتخاب اشتباه زنجیره ابزارتان را قفل میکند.

جمعبندی: برای کامنت در پیکربندی VS Code و TypeScript از JSONC استفاده کنید، وقتی به نحو گستردهتر literal در ES5.1 مانند تکگیومه یا کلید بیگیومه نیاز دارید از JSON5، و APIهای عمومی را روی JSON استاندارد نگه دارید.
JSON استاندارد کامنت را مجاز نمیداند، پس هر تیمی بیصدا مینویسدشان — تا روزی که ساخت میشکند. بهجای پنهانی انجام دادن، گویش درستی انتخاب کنید.
۱. دو گویش انگیزههای متفاوت دارند
- JSONC (JSON با Comments): JSON استاندارد بهعلاوه کامنت و ویرگول انتهایی، با تقریباً هیچ تغییر نحوی دیگر. استاندارد عملی اکوسیستم VS Code است —
settings.json،tsconfig.jsonو.eslintrc.jsonهمه از آن استفاده میکنند. - JSON5: بسیار جاهطلبتر، مستقیماً همتراز با object literal ES5.1 — تکگیومه، کلید بیگیومه، هگزادسیمال،
Infinity/NaN، ادامه خط با backslash و علامت+ابتدایی.
یک جمله برای تشخیصشان: JSONC فقط نوشتن را راحت میکند؛ JSON5 اجازه میدهد فایل پیکربندی را مثل جاوااسکریپت بنویسید.
۲. جدول مقایسه نحو
| ویژگی | JSON استاندارد | JSONC | JSON5 |
|---|---|---|---|
کامنت // /* */ |
✗ | ✓ | ✓ |
| ویرگول انتهایی | ✗ | ✓ | ✓ |
| رشتههای تکگیومه | ✗ | ✗ | ✓ |
| کلیدهای بیگیومه | ✗ | ✗ | ✓ |
| عدد هگزادسیمال | ✗ | ✗ | ✓ |
نقطه اعشار ابتدایی/انتهایی .5 5. |
✗ | ✗ | ✓ |
عددهای شروعشده با + |
✗ | ✗ | ✓ |
Infinity / NaN |
✗ | ✗ | ✓ |
ادامه \ در پایان خط |
✗ | ✗ | ✓ |
| رشتههای چندخطی | ✗ | ✗ | ✓ (از طریق ادامه پیادهسازی میشود) |
| مقدار دلخواه در سطح بالا | ✓ | ✓ | ✓ |
مشخصات کامل JSON5 تقریباً بیش از یک صفحه نیست؛ بسته json5 مدتها توسط جامعه نگهداری شده و مرورگرها و Node یکسان رفتار میکنند.
۳. تجزیه: دو API، دو نوع توانایی موقعیتیابی
۳.۱ JSON5: تجزیه ساده کل سند
import JSON5 from 'json5';
const config = JSON5.parse(`
{
// service port
port: 8080,
host: '0.0.0.0',
features: ['json5', 'jsonc',],
retries: 0x10,
}
`);
console.log(config.port, config.retries); // 8080 16
JSON5.parse یک شیء ساده بدون اطلاعات offset برمیگرداند — چون هدفش سناریوهای ویرایش نیست، فقط «خواندن پیکربندی».
۳.۲ JSONC: درخت نحوی با offset
ارزش jsonc-parser در تجزیه نیست، در ویرایش است. سه لایه API ارائه میدهد:
| API | هدف | استفاده معمول |
|---|---|---|
parse |
تجزیه به درختی حامل offset/length |
هایلایت نحوی، جمعشدن، پیمایش |
visit |
پیمایش عمق-اول؛ callback مسیر گره را میگیرد | بازرسی شبیه JSONPath |
modify + applyEdits |
تولید ویرایش متنی حداقلی، سپس اعمال به متن اصلی | تغییر یک مقدار با حفظ کامنت |
import { parseTree, findNodeAtLocation, modify, applyEdits } from 'jsonc-parser';
const text = `{
// port configuration
"server": {
"port": 8080 // 80 in production
}
}`;
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));
خروجی کامنتهای اصلی را نگه میدارد و فقط سه نویسه 8080 را جایگزین میکند:
{
// port configuration
"server": {
"port": 3000 // 80 in production
}
}
دقیقاً همان کاری که «ویرایش پیکربندی با عبارت باقاعده» نمیتواند: regex نمیداند کدام 8080 را تغییر دهد و نمیداند 8080 داخل رشته باید دستنخورده بماند.
۳.۳ پیامهای خطا باید offset حمل کنند
کدهای خطای jsonc-parser مقادیر enum هستند؛ رایجترینها:
| کد خطا | معنا |
|---|---|
InvalidSymbol |
نویسهای ظاهر شد که نباید آنجا باشد |
PropertyNameExpected |
نام کلید انتظار میرفت |
ColonExpected |
دونقطه انتظار میرفت |
CommaExpected |
ویرگول انتظار میرفت |
CloseBraceExpected |
شیء بسته نشد |
UnexpectedEndOfComment |
کامنت بسته نشد |
InvalidEscapeCharacter |
escape نامعتبر |
وقتی offset به خط و ستون تبدیل شود، ویرایشگر میتواند موج خطا را دقیقاً روی موقعیت خطادار بکشد.
۴. چه زمانی کدام
| سناریو | توصیه | دلیل |
|---|---|---|
| بدنه درخواست/پاسخ API عمومی | JSON استاندارد | گویشها توسط کلاینتهای عمومی پشتیبانی نمیشوند |
package.json، composer.json |
JSON استاندارد | مدیران بسته فقط JSON استاندارد میفهمند |
tsconfig.json، .vscode/settings.json |
JSONC | پیشفرض اکوسیستم، بومی پشتیبانیشده توسط زنجیره ابزار |
| پیکربندی برنامه (کامنت لازم دارد) | JSONC یا YAML | کامنت باید حفظ شود در حالی که ابزارها همچنان میتوانند بخوانند و بنویسند |
نیاز به Infinity، هگزادسیمال، literalهای پیچیده |
JSON5 | قویترین توان بیان |
| تبادل داده، لاگ، کش | JSON خطمحدود یا استاندارد | جریان و همهجاگیری لازم است |
قاعده سرانگشتی: اگر فایل توسط «ابزار غیرانسانی» خوانده میشود، JSON استاندارد را ترجیح دهید؛ گویش را فقط وقتی در نظر بگیرید که مطمئنید تنها کد خودتان میخواندش.
۵. سه نوع ریسکی که گویشها وارد میکنند
۵.۱ سرریز نیاز
وقتی ابزاری دیگر فایل پیکربندی JSON5 را میخواند و JSON.parse صدا میزند، کاملاً از کار میافتد. نشانه معمول «محلی خوب کار میکند، روی Docker شکست میخورد» است — چون کانتینر مسیر خواندن متفاوتی اجرا میکند.
مقابله: به مخزن یک بررسی CI اضافه کنید که صریحاً فهرست کند کدام فایلها مجاز به استفاده از گویشاند؛ بقیه بهعنوان JSON استاندارد اعتبارسنجی میشوند.
۵.۲ غافلگیریهای استنتاج نوع
JSON5 کلید بیگیومه و تکگیومه را مجاز میداند، اما اجازه نمیدهد ساختارهای literal مانند تاریخ یا عبارت باقاعده بیاورید — همچنان قالب داده است، نه ارزیابی جاوااسکریپت.
مردم فرض کردهاند JSON5 میتواند new Date() را بیان کند و فقط شکست تجزیه دیدهاند. JSON5 همان eval نیست.
۵.۳ حذف بیصدای کامنتها
نه JSON5.stringify و نه JSON.stringify کامنت را حفظ نمیکنند. پس «بخوان، مقداری را تغییر بده، برگردان» همه کامنتها را از دست میدهد.
وقتی کامنت باید باقی بماند، تنها گزینهها API ویرایش jsonc-parser یا کتابخانه YAML با پشتیبانی حفظ کامنت هستند.
۶. توصیههای عملی
- [ ] جدول «نوع فایل → قالب» را در مستندات تیم نگه دارید تا کسی بداههپردازی نکند؛
- [ ] خواندن پیکربندی را در یک
loadConfig()واحد بپیچید که در داخل تصمیم میگیرد از کدام پارسر استفاده کند، تا کد کسبوکار هرگزJSON.parseرا مستقیم صدا نزند؛ - [ ] هنگام تغییر برنامهای پیکربندی دارای کامنت، از
modify+applyEditsاستفاده کنید؛ هرگز کل فایل را بازنویسی نکنید؛ - [ ] فایلهای گویش را در CI هم اعتبارسنجی کنید (
jsonc-parserبرای JSONC،JSON5.parseبرای JSON5)، وگرنه خطاهای نحوی فقط در زمان اجرا ظاهر میشوند؛ - [ ] برای رابطهای عمومی، کلیدهای کش و payloadهای صف پیام از JSON استاندارد استفاده کنید.
پرسشهای متداول
چگونه بین JSON5 و JSONC انتخاب کنم؟
بر اساس زمان اجرا انتخاب کنید نه تعداد نحو: VS Code، TypeScript و ESLint بهصورت پیشفرض JSONC میخوانند، پس JSONC بهترین سازگاری را میدهد؛ تنها وقتی به نحو گستردهتر literal در ES5.1 نیاز دارید، مانند تکگیومه، کلید بیگیومه یا Infinity، به JSON5 بروید. هیچ کدام برای پاسخ API عمومی مناسب نیست.
چرا پارسر استاندارد JSON نمیتواند JSONC را مستقیم بخواند؟
JSONC کامنت و ویرگول انتهایی را مجاز میداند، در حالی که JSON.parse فقط JSON مطابق RFC 8259 میپذیرد و روی هر یک خطا میدهد. خواندن JSONC به پارسری مانند jsonc-parser نیاز دارد، یا حذف کامنتها پیش از دادن متن به پارسر استاندارد.
آیا کامنتهای JSONC باید پس از ویرایش فایل باقی بمانند؟
بله، اما فقط از طریق API ویرایش. modify و applyEdits در jsonc-parser گره هدف را تغییر میدهند در حالی که بقیه کامنتها را حفظ میکنند؛ تجزیه به شیء و stringify کردن همه کامنتها را حذف میکند.