Skip to content
simonvanlierdePublic

About

Linter, fixer and formatter for JSON, JSONC, JWCC, JSON5 and JSON Lines: syntax errors, duplicate keys and dialect rules with exact positions, safe fixes, a formatter that keeps comments, JSON Schema checks, SARIF and JSON output. pre-commit hook, CLI, Rust library, GitHub Action and browser playground.

Topics

Resources

Code of conduct

Contributing

Security policy

Accessibility

Stars

1 star

Watchers

0 watching

Forks

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

240 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

jsonvet

CI codecov CodSpeed PyPI crates.io Marketplace License: MIT OpenSSF Scorecard OpenSSF Best Practices DOI

A linter and formatter for JSON, I-JSON, JSONC, HuJSON (JWCC), JSON5 and JSON Lines. It finds syntax errors and duplicate keys, and tells you the exact line and column:

config.json:4:5: error[duplicate-key] duplicate key $.server.port (first at 2:5)
package.json:2:14: error[syntax] missing `,`
events.jsonl:12:1: error[syntax] blank line; JSON Lines needs a value on every line

It replaces check-json5, a Python hook, and is up to 2,201 times faster than check-json5 1.4.1 on JSON5 files (figures).

Try it in your browser: the playground checks, fixes and formats the text you paste. Nothing to install, and the text stays on your machine.

  • Six dialects, one parser. Each file is checked in the dialect its extension implies.
  • Fixes. --fix repairs what has a safe fix, such as a stray byte order mark.
  • Formatting that keeps comments. jsonvet fmt lays out JSON, JSONC, JWCC, JSON5 and JSON Lines and leaves your comments where they are.
  • JSON Schema with positions. Each schema error points at its value's line and column. jsonvet never fetches anything from the network.
  • Fits CI. A pre-commit or prek hook, a GitHub Action, a command or a Rust library, with text, SARIF or JSON output.

Quick start

Pre-commit or prek hook

Add this to .pre-commit-config.yaml (for pre-commit or prek):

- repo: https://github.com/simonvanlierde/jsonvet
  rev: v3.3.1
  hooks:
    - id: jsonvet
    - id: jsonvet-format

jsonvet-format rewrites files, so a commit that changes one fails and you commit again. Add args: [--fix] to jsonvet to repair what has a safe fix (Fixing). Both hooks are in the same block, but each works alone.

It checks files by name: .json, .jsonc, .json5, .jsonl, .ndjson, .geojson, .jsonld, .hujson, .jwcc, .code-workspace, .code-snippets, .webmanifest and .babelrc.

Options go in args, such as args: [--strict, package.json] to hold package.json to strict JSON. The hook installs a prebuilt binary from PyPI, so you need no Rust.

GitHub Action

- uses: simonvanlierde/jsonvet@v3

The step fails when a file has an error, and each problem shows up as an annotation on the pull request. Before it installs jsonvet from PyPI, it checks that the wheel came from this repository's release workflow. Its inputs are in the reference.

The Action only checks. To check formatting too, add a step with run: uvx jsonvet fmt --check .. To see the problems in GitHub code scanning, set sarif: jsonvet.sarif and upload that file, as in this workflow.

Command line

uvx jsonvet config/*.json        # run it from PyPI without installing
uvx jsonvet .                    # check every JSON-like file under a folder
uvx jsonvet --fix .              # also fix what has a safe fix, in place
uvx jsonvet fmt .                # format the files, keeping their comments
uvx jsonvet fmt --check .        # list files that need formatting; exit 1 if any
pip install jsonvet              # install it as a Python package
cargo install jsonvet-cli        # build it from source
cargo binstall jsonvet-cli       # download the binary from the GitHub release

Each GitHub release also has the binary for Linux, macOS and Windows, with checksums and an SBOM (verifying a release). A folder stands for the JSON-like files under it, skipping hidden and ignored files, and - reads standard input. The reference covers --fix, and formatting covers jsonvet fmt. jsonvet --help lists every option, and the reference has the details.

Rust library

use jsonvet::{check, Config, Dialect};

let report = check("{\"a\": 1, \"a\": 2}", &Config::new(Dialect::Json));
for problem in report.problems() {
    let at = report.location(problem.offset());
    println!("{}:{}: {}[{}] {problem}", at.line, at.column, problem.severity(), problem.rule());
}

The API is on docs.rs.

Dialects

Dialect Adds to JSON Default for
json nothing (RFC 8259) none; choose it with --dialect or --strict
i-json stricter content (RFC 7493) none
jsonc // and /* */ comments .jsonc, .code-workspace, .code-snippets
jwcc comments and trailing commas (HuJSON) .hujson, .jwcc
json5 the JSON5 1.0.0 grammar .json, .json5, .geojson, .jsonld, .webmanifest, .babelrc
jsonl one JSON value per line (JSON Lines) .jsonl, .ndjson

Any other extension is checked as JSON5. .json defaults to JSON5 because most .json files that fail as JSON are config files with comments. To check a file as strict JSON, use --dialect json:package.json.

Rules

Rule Reports Default
syntax the first syntax error; checking stops there error
duplicate-key a key repeated in one object, with both positions and its path error
invalid-number a number a double cannot hold, or an integer past ±(2⁵³ − 1) error in i-json, off elsewhere
invalid-code-point a lone surrogate or a noncharacter in a string error in i-json, off elsewhere
byte-order-mark a byte order mark at the start of the file warning in json and i-json, error in jsonl
missing-final-newline a JSON Lines file that does not end with a newline warning in jsonl
mixed-line-endings a line ending that differs from the file's first one warning

Change a rule's severity with --error, --warn or --ignore. Warnings fail a run only past --max-warnings N.

Configuration

To keep settings out of the command line, put them in jsonvet.toml, or in a [tool.jsonvet] table in pyproject.toml:

rules = { byte-order-mark = "ignore", missing-final-newline = "error" }

# Checked in order; the last matching entry wins.
dialects = [
  { files = ".vscode/*.json", dialect = "jsonc" },
  { files = "package.json", dialect = "json" },
]

# Skipped when jsonvet walks a folder; files named on the command line are still checked.
exclude = ["node_modules", "tests/fixtures/*"]

# Used by `jsonvet fmt`.
[format]
indent = 4
width = 100

Each file takes the nearest config file in its folder or a parent, up to the repository root, so each package in a monorepo can have its own. Options on the command line win. The reference says where jsonvet looks and how globs match. Formatting lists the [format] settings and how .editorconfig fits in.

JSON Schema

--schema FILE checks each file against one JSON Schema, and reports each error at its value:

$ jsonvet --schema server.schema.json server.json5
server.json5:3:9: error[schema] "80" is not of type "integer" (at $.port)
server.json5:6:3: error[schema] Additional properties are not allowed ('debug' was unexpected) (at $.debug)

A config file can give files a schema, and so can a file's own $schema path:

schemas = [{ files = "config/server.json5", schema = "schemas/server.schema.json" }]
{ $schema: "../schemas/server.schema.json", port: 8080 }

Such a schema must stay inside the project. A $schema URL is skipped: jsonvet fetches nothing, so every $ref must point inside the schema file. Schema errors are always errors. The rules for schema paths and the limits are in the reference.

Coming from check-json5

Bump rev to the newest tag. The check-json5 hook id, the check-json5 command and --strict keep working through 3.x.

jsonvet gives the same pass or fail as 1.4.1, apart from a few edge cases. One change can fail a file that passed: .jsonc, .code-workspace and .code-snippets files are now checked as JSONC, and .hujson and .jwcc files as JWCC. To keep the old verdict, add --dialect json5:GLOB.

How it is tested

The tests run on Linux, macOS and Windows, with fuzzing, mutation testing and a comparison with check-json5 1.4.1. A conformance matrix runs the same files against 18 other parsers in four languages, and shows where each one disagrees with the expected verdict.

Development

You need Rust and just.

git submodule update --init --quiet
cargo test --workspace

See CONTRIBUTING.md for the full check and lint suite.

More

Found a file jsonvet gets wrong? Please open an issue with the file and the command. If it crashes or hangs jsonvet, report it privately as SECURITY.md says.

To cite jsonvet, use the DOI 10.5281/zenodo.23461825 or GitHub's "Cite this repository" button.

Credits and license

I (Simon van Lierde) started this as a fork of check-json5 by Ben Mares, which is based on the pre-commit-hooks repository by Anthony Sottile and contributors. It is MIT-licensed, like both of them.

About

Linter, fixer and formatter for JSON, JSONC, JWCC, JSON5 and JSON Lines: syntax errors, duplicate keys and dialect rules with exact positions, safe fixes, a formatter that keeps comments, JSON Schema checks, SARIF and JSON output. pre-commit hook, CLI, Rust library, GitHub Action and browser playground.

Topics

Resources

Code of conduct

Contributing

Security policy

Accessibility

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages