Skip to main content

Parse JSON files containing C-style comments (// and /* */) while optionally preserving them

Project description

jsonclark - JSON Comments parsed with Lark

This library parses JSON files that contain C-style comments (// and /* */), which is useful commonly used in configuration files and other applications where comments enhance readability. Notable cases are VSCode and Zed editor.

✨ Features

  • Parses JSON with both single-line (//) and multi-line (/* */) comments.
  • Extract and preserve comments while parsing
  • Full JSON compatibility (objects, arrays, strings, numbers, booleans, null)
  • Built with Lark for reliable parsing
  • Comprehensive test coverage
  • CLI tool with support for yq expressions to modify JSON while preserving comments

⚠️ Disclaimer

AI-Generated Code: A significant portion of this codebase has been generated using AI code assistants (such as GitHub Copilot). While the code has been reviewed and tested, please be aware that parts of the implementation may have been initially generated by AI models. All functionality has been validated through comprehensive test coverage.

📦 Installation

pip install jsonclark

Or with development dependencies:

pip install "jsonclark[dev]"

Or run directly from git using uvx:

uvx --from git+https://github.com/D3f0/jsonclark@main jsonclark --help

🛠️ Command-Line Tool

After installing jsonclark, you can use the jsonclark command to pretty-print JSON files with support for comments, similar to Python's json.tool:

Usage

# Pretty-print JSON from stdin
cat config.jsonc | jsonclark

# Pretty-print with custom indentation
cat config.jsonc | jsonclark --indent 4

# Sort keys in output
cat config.jsonc | jsonclark --sort-keys

# Show extracted comments
cat config.jsonc | jsonclark --comments

# Pretty-print from file
jsonclark config.jsonc

# Apply yq expression to modify JSON (preserves comments for file input)
jsonclark --yq '.port = 9000' config.jsonc

# All options together
jsonclark --indent 4 --sort-keys --comments config.jsonc

Options

  • --indent INDENT: Number of spaces for indentation (default: 2)
  • --sort-keys: Sort dictionary keys in output
  • --comments: Show extracted comments in the output
  • --yq EXPRESSION: Apply a yq expression to modify the JSON. When used with file input, automatically creates a backup (file.bak) before modification.
  • --version: Show program version
  • --help: Show help message

🔧 Using yq for JSON Modification

The --yq flag allows you to apply yq expressions to modify your JSON while preserving comments (when operating on files). This is useful for CI/CD pipelines and configuration management.

📋 Requirements

The yq binary must be installed. Install it with:

On macOS:

brew install yq

From GitHub releases: Visit https://github.com/mikefarah/yq/releases

Using pip:

pip install yq

📝 Examples

# Modify a single key
jsonclark --yq '.port = 9000' config.jsonc

# Add a new key
jsonclark --yq '.debug = true' config.jsonc

# Delete a key
jsonclark --yq 'del(.deprecated_field)' config.jsonc

# Modify nested values
jsonclark --yq '.server.host = "0.0.0.0"' config.jsonc

# Work with stdin (output to stdout)
cat config.jsonc | jsonclark --yq '.version = "2.0"'

💾 Backup on File Modification

When --yq is used with file input, jsonclark automatically creates a backup file:

jsonclark --yq '.port = 9000' config.jsonc
# Creates: config.jsonc.bak (contains the original)
# Updates: config.jsonc (contains the modified version)

If yq is not installed, you'll see an error message with installation instructions.

🚀 Quick Start

Basic Usage

Parse JSON with comments using the load_json_with_comments() function:

from jsonclark import load_json_with_comments

json_text = """
{
    // User configuration
    "name": "John Doe",
    // Age in years
    "age": 30
}
"""

config = load_json_with_comments(json_text)
print(config)  # {'name': 'John Doe', 'age': 30}

Preserving Comments

If you want to extract comments separately, use load_json_preserving_comments():

from jsonclark import load_json_preserving_comments

json_text = """
// Configuration file
{
    // Database settings
    "database": "postgres"
}
"""

result = load_json_preserving_comments(json_text)
print(result["value"])      # {'database': 'postgres'}
print(result["comments"])   # ['Configuration file', 'Database settings']

💬 Comment Types

Line Comments

Use // for single-line comments:

{
    // This is a line comment
    "key": "value"
}

Block Comments

Use /* */ for multi-line comments:

{
    /*
     * This is a block comment
     * spanning multiple lines
     */
    "key": "value"
}

Mixed Comments

You can mix both types:

{
    // Line comment
    "setting1": "value1",
    /* Block comment */
    "setting2": "value2"
}

🔥 Advanced Usage

Using the Parser Class Directly

For more control, use the JSONWithCommentsParser class:

from jsonclark import JSONWithCommentsParser

parser = JSONWithCommentsParser()

# Parse and get result
result = parser.parse('// Comment\n{"key": "value"}')

# Parse and preserve comments
result = parser.parse_with_comments('// Comment\n{"key": "value"}')
print(result["value"])      # {'key': 'value'}
print(result["comments"])   # ['Comment']

Extracting Comments Only

If you only need to extract comments from JSON:

from jsonclark import JSONWithCommentsParser

text = '// Comment 1\n/* Comment 2 */\n{}'
comments = JSONWithCommentsParser._extract_comments(text)
print(comments)  # ['Comment 1', 'Comment 2']

🌍 Real-World Example

Here's a configuration file example:

from jsonclark import load_json_with_comments

config_text = """
{
    // Server configuration
    "server": {
        "host": "0.0.0.0",
        // HTTP port
        "port": 8080,
        /* SSL settings */
        "ssl": {
            "enabled": true,
            "certificate": "/etc/ssl/cert.pem"
        }
    },
    
    // Database connection
    "database": {
        "type": "postgresql",
        "host": "localhost",
        /* Connection pool size */
        "poolSize": 20
    }
}
"""

config = load_json_with_comments(config_text)

print(f"Server: {config['server']['host']}:{config['server']['port']}")
print(f"Database: {config['database']['type']}")
print(f"Pool Size: {config['database']['poolSize']}")

📊 Data Structures

JSONValue

Optional dataclass for representing JSON values with comment metadata:

from jsonclark import JSONValue

value = JSONValue(
    value={"key": "value"},
    comments_before=["Opening comment"],
    comments_after=["Closing comment"]
)

📚 API Reference

Functions

  • load_json_with_comments(text: str) -> Any

    • Parse JSON with comments and return the parsed Python object
    • Raises lark.exceptions.LarkError for invalid JSON
  • load_json_preserving_comments(text: str) -> dict[str, Any]

    • Parse JSON and return both value and comments
    • Returns {"value": parsed_object, "comments": [list_of_comments]}

Classes

  • JSONWithCommentsParser
    • Main parser class
    • Methods:
      • parse(text: str) -> Any - Parse JSON and return Python object
      • parse_with_comments(text: str) -> dict[str, Any] - Parse and preserve comments
      • _extract_comments(text: str) -> list[str] - Static method to extract comments

✅ Testing

With Nox (Multi-version Testing)

Test across Python 3.10 - 3.13 using nox:

# Install nox with uv support
pip install nox-uv

# Run tests on all Python versions
nox

# Test specific version
nox -s tests-3.13

# Run only parser tests
nox -s tests_parser-3.13

# Run only CLI tests
nox -s tests_cli-3.13

With Pytest

Run the comprehensive test suite:

pytest tests/ -v

All tests pass ✅

⚡ Limitations

  • Comments must follow C-style syntax (// and /* */)
  • Comments inside strings are preserved as part of the string value
  • The parser focuses on standard JSON data types (no trailing commas or unquoted keys)

📋 Requirements

  • Python >= 3.10
  • Lark >= 1.3.1

📄 License

MIT

🤝 Contributing

Contributions are welcome! Please ensure all tests pass before submitting a pull request.

pytest tests/test_parser.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jsonclark-0.2.2.tar.gz (14.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jsonclark-0.2.2-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file jsonclark-0.2.2.tar.gz.

File metadata

  • Download URL: jsonclark-0.2.2.tar.gz
  • Upload date:
  • Size: 14.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jsonclark-0.2.2.tar.gz
Algorithm Hash digest
SHA256 e9540b6a458c68eee093520afbf8de5ca69278e1c956fd687123e7a077eba066
MD5 1fb4fb37773267bbae3eedce54b1453a
BLAKE2b-256 885178d67e465f441806fa3041d61f576519fe3182f5b26f92e1b8e7bde94101

See more details on using hashes here.

File details

Details for the file jsonclark-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: jsonclark-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jsonclark-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6d36a717ba8396a0c4620896cebbca7db5bb18b585141a83a20eaefd5f1555ed
MD5 d1c187b677e5ae5f2bac5d23042f498a
BLAKE2b-256 0fb389e6996b412d1ba5f9d386b100e7fd3b73df4cd96c01f3a33b80398f6c97

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page