Command line interface for [Ajv](https://github.com/ajv-validator/ajv), a JSON Schema validator.

This is a fork of the original [ajv-cli](https://github.com/ajv-validator/ajv-cli) 5 with many improvements (see below).

## Changes from ajv-cli 5

Notable changes from the original ajv-cli 5.

### New features

- A new human-friendly **error format `pretty`** that combines the source file location and JSON path of the invalid value, followed by a code span (a snippet of the validated file) with an in-place error message (see [Pretty format](#_pretty_format) in Examples).

- A new **error format `line`**: `<filepath>:<line>:<column> - <message>` (see [Line format](#_line_format) in Examples).

- Support for the [Code Climate Issue](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types) format compatible with the [Code Quality report](https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool) in GitLab CI (see [Code Climate format](#_code_climate_format) in Examples).

- A *validate* option `--merge-errors`, enabled by default, to merge related errors per instance path instead of reporting individual schema errors as returned by Ajv (see [JSON format without merging errors](#_json_format_without_merging_errors) in Examples).

- A *validate* option `--errors-location` to add the source location (filename, line and column number) of each invalid value to validation errors (see [JSON format with location](#_json_format_with_location) in Examples).

- A *compile* option `--code-esm` to export the validate function(s) as ECMAScript Modules (ESM) instead of CommonJS (see `code.esm` in Ajv options).

- Workaround to **fix incorrect `schemaPath`** in validation errors (see [src/ajv-schema-path-workaround.ts](src/ajv-schema-path-workaround.ts) and [ajv-validator/ajv#512](https://github.com/ajv-validator/ajv/issues/512)).

### (Breaking) Changes

- **`-d` option** has been replaced with positional arguments (`ajv validate -s <schema> <data-file>…​`).

- **`--no-<option>`** no longer works, boolean options can be disabled as `--<option>=false` or `--<option> false`.

- The `validate` command is no longer implicit, it must always be specified (e.g. `ajv validate [options]`, not `ajv [options]`).

- **Limited glob support** – The bloated [Glob](https://www.npmjs.com/package/glob) dependency has been replaced by [picomatch](https://www.npmjs.com/package/picomatch) and a custom implementation to traverse directories. However, it’s a simplified solution that does not support complex nested globs (e.g. `alpha/beta/*.{yml,d/**/*.yml}`).

- The **default error format** has been changed from `js` to `pretty`.

- The `line` format has been renamed to `json-oneline`.

- The `text` format for errors has been replaced by the `jsonpath` format.

- Only (structured) validation errors (see `--errors`) and changes (see `--changes`) are printed to **stdout**, all other messages are logged to **stderr**.

- **`--strict-schema`** is disabled by default\* (i.e. unknown keywords and formats are ignored) to comply with the JSON Schema specification.

- `ajv compile` prints the generated code to stdout instead of nowhere if the **`-o`** option is not specified.

- The default value of `--inline-refs` has been changed from `true` to `8` to speed up schema compilation (and validation).

- If `--spec` is not provided, it’s determined by the `$schema` URI in the first passed schema (`-s`). It will only fallback to `draft-07` if it’s not found.

- ajv-cli is now transpiled to **ECMAScript Modules** (ESM) instead of CommonJS.

### Removed features

- The **test** command (use `validate` instead).

- The **migrate** command.

- Support for loading schema and data files via `require` and omitting the `.json` extension in file paths.

- Support for loading custom keywords modules in **TypeScript**.

- Loading schemas and data in the **JSON5** format (CJSON is still supported).

## Install

### Using npm

``` sh
npm install --global @jirutka/ajv-cli
```

### Download from Releases

ajv-cli is also provided as a single JavaScript file with bundled dependencies, requiring only Node.js (version 20 or later) on the system.

``` sh
curl -LO  https://github.com/jirutka/ajv-cli/releases/download/v6.0.0/ajv.cjs
curl -fsSL https://github.com/jirutka/ajv-cli/releases/download/v6.0.0/checksums.txt | sha256sum -c --ignore-missing
install -D -m755 ajv.cjs /usr/local/bin/ajv
```

## Usage

Refer to `ajv validate --help` and `ajv compile --help`.

### Examples

#### Pretty format

    $ ajv validate -s schema.json data-invalid-1.yml

    --> data-invalid-1.yml:6:10
        #/www.encom.com/CNAME

        |   A: 1.2.3.4
        | www.encom.com:
        |   owners: flynnsam
      6 |   CNAME: [ encom.com ]
        |          ^^^^^^^^^^^^^ must be string or object
        | tron.encom.com:
        |   owners: [ flynnkev, bradlala ]
        |   A: 1.2.3.5

#### Line format

    $ ajv validate -s schema.json --errors=line data-invalid-1.yml

    data-invalid-1.yml:6:10 - must be string or object

#### JSON format

    $ ajv validate -s schema.json --errors=json data-invalid-1.yml

``` json
[
  {
    "message": "must be string or object",
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainObject/properties/CNAME/anyOf"
  }
]
```

#### JSON format with location

    $ ajv validate -s schema.json --errors=json --errors-location data-invalid-1.yml

``` json
[
  {
    "message": "must be string or object",
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainObject/properties/CNAME/anyOf",
    "instanceLocation": {
      "filename": "data-invalid-1.yml",
      "start": {
        "line": 6,
        "col": 10
      },
      "end": {
        "line": 6,
        "col": 23
      }
    }
  }
]
```

#### JSON format verbose

    $ ajv validate -s schema.json --errors=json --verbose data-invalid-1.yml

``` json
[
  {
    "message": "must be string or object",
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainObject/properties/CNAME/anyOf",
    "data": [
      "encom.com"
    ],
    "schema": [
      {
        "$ref": "#/$defs/DomainName"
      },
      {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "rdata"
        ],
        "properties": {
          "rdata": {
            "$ref": "#/$defs/DomainName"
          },
          "ttl": {
            "type": "number"
          }
        }
      }
    ],
    "parentSchema": {
      "anyOf": [
        {
          "$ref": "#/$defs/DomainName"
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "rdata"
          ],
          "properties": {
            "rdata": {
              "$ref": "#/$defs/DomainName"
            },
            "ttl": {
              "type": "number"
            }
          }
        }
      ]
    }
  }
]
```

#### JSON format without merging errors

    $ ajv validate -s schema.json --errors=json --merge-errors=false data-invalid-1.yml

``` json
[
  {
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainName/type",
    "keyword": "type",
    "params": {
      "type": "string"
    },
    "message": "must be string"
  },
  {
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainObject/properties/CNAME/anyOf/1/type",
    "keyword": "type",
    "params": {
      "type": "object"
    },
    "message": "must be object"
  },
  {
    "instancePath": "/www.encom.com/CNAME",
    "schemaPath": "#/$defs/DomainObject/properties/CNAME/anyOf",
    "keyword": "anyOf",
    "params": {},
    "message": "must match a schema in anyOf"
  }
]
```

#### Code Climate format

    $ ajv validate -s schema.json --errors=code-climate data-invalid-1.yml

``` json
[
  {
    "description": "[schema] #/www.encom.com/CNAME must be string or object",
    "check_name": "json-schema",
    "fingerprint": "344ef8205ab8c5dea3b0ebd537519dfb005c5f5c",
    "severity": "major",
    "location": {
      "path": "data-invalid-1.yml",
      "positions": {
        "begin": {
          "line": 6,
          "column": 10
        },
        "end": {
          "line": 6,
          "column": 23
        }
      }
    }
  }
]
```

## Credits

- This project is a fork of the original [ajv-cli](https://github.com/ajv-validator/ajv-cli) written by [Evgeny Poberezkin](https://github.com/epoberezkin).

- The code for merging related Ajv validation errors is taken from the [vscode-lintlens](https://github.com/ghmcadams/vscode-lintlens/tree/master/packages/simple-ajv-errors) project by [Gabriel McAdams](https://github.com/ghmcadams).

## License

This project is licensed under [MIT License](https://opensource.org/license/mit/).
