= Ajv CLI
:npm-name: @jirutka/ajv-cli
:gh-name: jirutka/ajv-cli
:version: 6.0.0
:releases-uri: https://github.com/{gh-name}/releases/download/v{version}

ifdef::env-github[]
image:https://github.com/{gh-name}/workflows/CI/badge.svg[Build Status, link=https://github.com/{gh-name}/actions?query=workflow%3A%22CI%22]
image:https://img.shields.io/npm/v/{npm-name}.svg[npm Version, link="https://www.npmjs.org/package/{npm-name}"]
endif::env-github[]

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

This is a fork of the original https://github.com/ajv-validator/ajv-cli[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>> in Examples).

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

* Support for the https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types[Code Climate Issue] format compatible with the https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool[Code Quality report] in GitLab CI (see <<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>> 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>> 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 link:src/ajv-schema-path-workaround.ts[] and https://github.com/ajv-validator/ajv/issues/512[ajv-validator/ajv#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 https://www.npmjs.com/package/glob[Glob] dependency has been replaced by https://www.npmjs.com/package/picomatch[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

[source, sh, subs="+attributes"]
npm install --global {npm-name}


=== 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.

[source, sh, subs="+attributes"]
curl -LO  {releases-uri}/ajv.cjs
curl -fsSL {releases-uri}/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

[source, subs="+quotes"]
$ 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

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=line* data-invalid-1.yml

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


==== JSON format

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=json* data-invalid-1.yml

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


==== JSON format with location

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=json --errors-location* data-invalid-1.yml

[source, 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

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=json --verbose* data-invalid-1.yml

[source, 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

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=json --merge-errors=false* data-invalid-1.yml

[source, 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

[source, subs="+quotes"]
$ ajv validate -s schema.json *--errors=code-climate* data-invalid-1.yml

[source, 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 https://github.com/ajv-validator/ajv-cli[ajv-cli] written by https://github.com/epoberezkin[Evgeny Poberezkin].
* The code for merging related Ajv validation errors is taken from the https://github.com/ghmcadams/vscode-lintlens/tree/master/packages/simple-ajv-errors[vscode-lintlens] project by https://github.com/ghmcadams[Gabriel McAdams].


== License

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