multiconf
Version:
Work with JSON configs
282 lines (260 loc) • 7.46 kB
JavaScript
const assert = require('node:assert');
const test = require('node:test');
const JSONCParser = require('../lib/jsonc-parser');
test.describe('JSONCParser', () => {
test.describe('Basic JSONC parsing', () => {
test.it('should parse simple JSONC with single-line comments', () => {
const jsonc = `{
// This is a comment
"key": "value",
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, { key: 'value' });
});
test.it('should parse JSONC with multi-line comments', () => {
const jsonc = `{
/* This is a
multi-line comment */
"key": "value",
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, { key: 'value' });
});
test.it('should parse JSONC with trailing commas', () => {
const jsonc = `{
"key": "value",
"array": [1, 2, 3,],
"object": {
"nested": "value",
},
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
key: 'value',
array: [1, 2, 3],
object: { nested: 'value' },
});
});
});
test.describe('Complex JSONC cases', () => {
test.it('should handle nested comments', () => {
const jsonc = `{
/* Outer comment
/* Nested comment */
Still in outer comment */
"key": "value",
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, { key: 'value' });
});
test.it('should handle comments in strings', () => {
const jsonc = `{
"key": "value // not a comment",
"key2": "value /* still not a comment */",
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
key: 'value // not a comment',
key2: 'value /* still not a comment */',
});
});
test.it('should handle escaped quotes in strings', () => {
const jsonc = `{
"key": "value with \\"quotes\\"",
"key2": "value with \\\\" // comment
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
key: 'value with "quotes"',
key2: 'value with \\',
});
});
});
test.describe('Edge cases', () => {
test.it('should handle empty JSONC', () => {
const jsonc = '{}';
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {});
});
test.it('should handle JSONC with only comments', () => {
const jsonc = `{
// Only comments here
/* No actual data */
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {});
});
test.it('should handle JSONC with multiple trailing commas', () => {
const jsonc = `{
"array": [1, 2, 3,,,],
"object": {
"key": "value",,,,
},,,
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
array: [1, 2, 3],
object: { key: 'value' },
});
});
});
test.describe('Error handling', () => {
test.it('should throw TypeError for non-string input', () => {
assert.throws(
() => JSONCParser.parse(null),
{
name: 'TypeError',
message: 'Input must be a string',
},
);
});
test.it('should throw SyntaxError for invalid JSON after comment removal', () => {
const jsonc = `{
"key": "value"
// Missing closing brace
`;
assert.throws(
() => JSONCParser.parse(jsonc),
{
name: 'SyntaxError',
},
);
});
test.it('should throw SyntaxError for unclosed multi-line comment', () => {
const jsonc = `{
"key": "value"
/* Unclosed comment
}`;
assert.throws(
() => JSONCParser.parse(jsonc),
{
name: 'SyntaxError',
},
);
});
});
test.describe('Real-world examples', () => {
test.it('should parse VS Code settings-like JSONC', () => {
const jsonc = `{
// Editor settings
"editor.fontSize": 14,
"editor.tabSize": 2,
"editor.wordWrap": "on",
// Git settings
"git.enableSmartCommit": true,
"git.confirmSync": false,
// Terminal settings
"terminal.integrated.fontSize": 12,
"terminal.integrated.shell.osx": "/bin/zsh",
// Extensions
"extensions.ignoreRecommendations": false,
// Workbench
"workbench.colorTheme": "Default Dark+",
"workbench.iconTheme": "vs-seti",
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
'editor.fontSize': 14,
'editor.tabSize': 2,
'editor.wordWrap': 'on',
'git.enableSmartCommit': true,
'git.confirmSync': false,
'terminal.integrated.fontSize': 12,
'terminal.integrated.shell.osx': '/bin/zsh',
'extensions.ignoreRecommendations': false,
'workbench.colorTheme': 'Default Dark+',
'workbench.iconTheme': 'vs-seti',
});
});
test.it('should parse complex configuration with nested objects and arrays', () => {
const jsonc = `{
// Server configuration
"server": {
"host": "localhost",
"port": 8080,
"ssl": {
"enabled": true,
"cert": "/path/to/cert.pem",
"key": "/path/to/key.pem",
},
},
// Database configuration
"database": {
"type": "postgres",
"host": "db.example.com",
"port": 5432,
"credentials": {
"username": "admin",
"password": "secret",
},
"pool": {
"min": 2,
"max": 10,
},
},
// Feature flags
"features": [
"auth",
"logging",
"metrics",
"caching",
],
// Logging configuration
"logging": {
"level": "info",
"transports": [
{
"type": "console",
"format": "pretty",
},
{
"type": "file",
"path": "/var/log/app.log",
"maxSize": "100m",
},
],
},
}`;
const result = JSONCParser.parse(jsonc);
assert.deepStrictEqual(result, {
server: {
host: 'localhost',
port: 8080,
ssl: {
enabled: true,
cert: '/path/to/cert.pem',
key: '/path/to/key.pem',
},
},
database: {
type: 'postgres',
host: 'db.example.com',
port: 5432,
credentials: {
username: 'admin',
password: 'secret',
},
pool: {
min: 2,
max: 10,
},
},
features: ['auth', 'logging', 'metrics', 'caching'],
logging: {
level: 'info',
transports: [
{
type: 'console',
format: 'pretty',
},
{
type: 'file',
path: '/var/log/app.log',
maxSize: '100m',
},
],
},
});
});
});
});