Code Monkey home page Code Monkey logo

better-ajv-errors's Introduction

better-ajv-errors

JSON Schema validation for Human πŸ‘¨β€πŸŽ€

Main goal of this library is to provide relevant error messages like the following:

Installation

$ npm i better-ajv-errors
$ # Or
$ yarn add better-ajv-errors

Also make sure that you installed ajv package to validate data against JSON schemas.

Usage

First, you need to validate your payload with ajv. If it's invalid then you can pass validate.errors object into better-ajv-errors.

import Ajv from 'ajv';
import betterAjvErrors from 'better-ajv-errors';
// const Ajv = require('ajv');
// const betterAjvErrors = require('better-ajv-errors').default;
// Or
// const { default: betterAjvErrors } = require('better-ajv-errors');

// You need to pass `{ jsonPointers: true }` for older versions of ajv
const ajv = new Ajv();

// Load schema and data
const schema = ...;
const data = ...;

const validate = ajv.compile(schema);
const valid = validate(data);

if (!valid) {
  const output = betterAjvErrors(schema, data, validate.errors);
  console.log(output);
}

API

betterAjvErrors(schema, data, errors, [options])

Returns formatted validation error to print in console. See options.format for further details.

schema

Type: Object

The JSON Schema you used for validation with ajv

data

Type: Object

The JSON payload you validate against using ajv

errors

Type: Array

Array of ajv validation errors

options

Type: Object

format

Type: string
Default: cli
Values: cli js

Use default cli output format if you want to print beautiful validation errors like following:

Or, use js if you are planning to use this with some API. Your output will look like following:

[
  {
    start: { line: 6, column: 15, offset: 70 },
    end: { line: 6, column: 26, offset: 81 },
    error:
      '/content/0/type should be equal to one of the allowed values: panel, paragraph, ...',
    suggestion: 'Did you mean paragraph?',
  },
];
indent

Type: number null
Default: null

If you have an unindented JSON payload and you want the error output indented.

This option have no effect when using the json option.

json

Type: string null
Default: null

Raw JSON payload used when formatting codeframe. Gives accurate line and column listings.

better-ajv-errors's People

Contributors

1999 avatar acheronfail avatar alecmev avatar atlastong avatar dependabot[bot] avatar ext avatar github-actions[bot] avatar lahmatiy avatar mikeralphson avatar p0lip avatar queengooborg avatar renovate-bot avatar rjatkins avatar supertong avatar thinkscape avatar torifat avatar tylermarien avatar wjrjerome avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

better-ajv-errors's Issues

Reporting a vulnerability

Hello!

I hope you are doing well!

We are a security research team. Our tool automatically detected a vulnerability in this repository. We want to disclose it responsibly. GitHub has a feature called Private vulnerability reporting, which enables security research to privately disclose a vulnerability. Unfortunately, it is not enabled for this repository.

Can you enable it, so that we can report it?

Thanks in advance!

PS: you can read about how to enable private vulnerability reporting here: https://docs.github.com/en/code-security/security-advisories/repository-security-advisories/configuring-private-vulnerability-reporting-for-a-repository

allErrors support

Hi there!

It's late, so my code fu may just be failing me, but it seems like better-ajv-errors can't really handle allErrors: true. Here's the result of emitting both the better-ajv-errors output and the native ajv.errors data:

$ node test/test-json.js
# better-ajv-errors:
REQUIRED should have required property 'phase'
> 1 | [{"aliases":["Development meetings","Development meetings"],"budgetHours":-100,"fakeProperty":"foo"}]
    |  ^ ☹️  phase is missing here!

# native ajv.errors:
[ { keyword: 'additionalProperties',
    dataPath: '/0',
    schemaPath: '#/items/additionalProperties',
    params: { additionalProperty: 'fakeProperty' },
    message: 'should NOT have additional properties' },
  { keyword: 'required',
    dataPath: '/0',
    schemaPath: '#/items/required',
    params: { missingProperty: 'summary' },
    message: 'should have required property \'summary\'' },
  { keyword: 'uniqueItems',
    dataPath: '/0/aliases',
    schemaPath: '#/items/properties/aliases/uniqueItems',
    params: { i: 0, j: 1 },
    message: 'should NOT have duplicate items (items ## 1 and 0 are identical)' },
  { keyword: 'required',
    dataPath: '/0',
    schemaPath: '#/items/required',
    params: { missingProperty: 'phase' },
    message: 'should have required property \'phase\'' },
  { keyword: 'minimum',
    dataPath: '/0/budgetHours',
    schemaPath: '#/items/properties/budgetHours/minimum',
    params: { comparison: '>=', limit: 0, exclusive: false },
    message: 'should be >= 0' } ]

See that better-ajv-errors only remarks on a single error, while the error object contains multiple examples?

Here's my setup:

const schema = require('./schema.json');
const Ajv = require('ajv');
const betterAjvErrors = require('better-ajv-errors');
const data = require('./data-invalid.json');

const ajValidator = Ajv({allErrors: true, jsonPointers: true});

const validate = ajValidator.compile(schema);
const valid = validate(data);

if (!valid) {
  const output = betterAjvErrors(schema, data, validate.errors);
  console.log(output);
  console.log(validate.errors)
}

No error returned on invalid type

When passing an invalid type error in to the betterAjvErrors functions, I am given a result that has zero formatted errors. See the example below

Example

import ajv from 'ajv';
import betterAjvErrors from 'better-ajv-errors';

const schema = {
    type: 'object',
    properties: {
        'remove-files': {
            type: 'array',
            items: {
                type: 'string'
            }
        }
    },
    additionalProperties: false
};

const input = {
    'remove-files': 'not an array'
};

const validate = new ajv().compile(schema);
validate(input);

const errorMessage = betterAjvErrors(schema, input, validate.errors)
console.log(errorMessage);

Output

Number of errors: 1
Formatted message: 

Not sure if this is an issue or if I am doing something wrong, but I'm at a loss for why this is the output.

Error: Couldn't find property ~1 of ...

When ajv returns JsonPointers containing ~0 or ~1 replacements (for ~ and /), better-ajv-errors seems to fail to be able to find the cause of the error:

Couldn't find property ~1 of /paths/~1/GET
Error: Couldn't find property ~1 of /paths/~1/GET
    at pointers.reduce (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/json/get-meta-from-path.js:15:19)
    at Array.reduce (<anonymous>)
    at getMetaFromPath (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/json/get-meta-from-path.js:9:19)
    at AdditionalPropValidationError.getLocation (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/validation-errors/base.js:20:47)
    at AdditionalPropValidationError.getCodeFrame (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/validation-errors/base.js:28:64)
    at AdditionalPropValidationError.print (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/validation-errors/additional-prop.js:25:31)
    at customErrorToText (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/index.js:21:44)
    at Array.map (<anonymous>)
    at exports.default (/home/mike/nodejs/oas-kit/packages/oas-validator/node_modules/better-ajv-errors/lib/modern/index.js:31:25)
    at schemaValidate (/home/mike/nodejs/oas-kit/packages/oas-validator/index.js:1306:30)

Drop support for node < 8

This package has runtime dependencies on both @babel/runtime and core-js due to the legacy build needed for ancient unmaintained node versions. Node 8 ends it support at 2019-12-31 and to me it makes little sense to support even older versions.

To me this is an issue because it pulls those packages as a indirect dependency for my library which has absolutely no need for it and I'd like to keep the amount of dependencies as low as possible.

If you agree with this I would gladly write a PR myself.

Error when data value is undefined

Our code:

betterAjvErrors(
    lightdashDbtYamlSchema,
    schemaFile,
    validate.errors || [],
    { indent: 2 },
);

Values:

schemaFile is undefined

validate.errors is

[
  {
    instancePath: '',
    schemaPath: '#/type',
    keyword: 'type',
    params: { type: 'object' },
    message: 'must be object'
  }
]

Error:

e TypeError: Cannot read properties of undefined (reading 'charAt')
    at next (/Users/joserego/Documents/lightdash/node_modules/@humanwhocodes/momoa/api.js:235:22)
    at tokenize (/Users/joserego/Documents/lightdash/node_modules/@humanwhocodes/momoa/api.js:491:13)
    at parse (/Users/joserego/Documents/lightdash/node_modules/@humanwhocodes/momoa/api.js:726:20)
    at Object.src_default (/Users/joserego/Documents/lightdash/packages/cli/node_modules/better-ajv-errors/lib/cjs/index.js:31:42)
    at /Users/joserego/Documents/lightdash/packages/cli/dist/dbt/schema.js:55:49
    at Generator.next (<anonymous>)
    at fulfilled (/Users/joserego/Documents/lightdash/packages/cli/dist/dbt/schema.js:24:58)

Workaround

By making sure the data defaults to an empty string or an empty object or null.

betterAjvErrors(
    lightdashDbtYamlSchema,
    schemaFile || '',
    validate.errors || [],
    { indent: 2 },
);

And with this get the proper error:

TYPE must be object

> 1 | ""
    | ^^ πŸ‘ˆπŸ½  type must be object

Solution:

better-ajv-errors could make sure data can't be undefined.
Or support undefined and have an appropriate message.

Feature request: Filter out 'shadowing' errors, for the humans

Hi there πŸ‘‹. Awesome repo you've got here!

We at the stryker mutation testing team have been looking into validation with ajv. We've come to the same conclusion, error messages directly from AJV are not really designed for humans. We're thinking of using better-ajv-errors.

However, we're also thinking of filtering out what I call 'shadowing' errors.

A shadowing error is an error that results logically from another error. Some examples:

[
  { // This is a useless error for a human
   keyword: 'type',
   dataPath: '.mutator',
   params: { type: 'string' },
   // [...]
 },
 { // => This is the most specific error. This is for humans!
   keyword: 'required',
   dataPath: '.mutator',
   params: { missingProperty: 'name' },
   // [...]
 },
 { // This is a useless error for a human
   keyword: 'oneOf',
   dataPath: '.mutator',
   params: { passingSchemas: null },
   [...]
 }
]

Or:

[
  { // This is a useless error for a human
   keyword: 'type',
   dataPath: '.logLevel',
   params: { type: 'string' },
   // [...]
 },
 { // => This is the most specific error. This is for humans!
   keyword: 'enum',
   dataPath: '.logLevel',
   params: { allowedValues: ['info', 'warn'] },
   // [...]
 },
]

A first draft of the filtering is created here:

https://github.com/stryker-mutator/stryker/blob/627d2f7e403042845bcece73c838c9447bbf522c/packages/core/src/config/validationErrors.ts#L55-L74

Do you think this filtering is useful for other projects as well? Should it be added to better-ajv-errors? Maybe as an option? Or do you want to keep it separate?

I would be willing to prepare it in a PR if you agree that this is a feature useful for all humans, nut just mutant-killing humans πŸ˜‰.

TypeError: Cannot read property 'match' of undefined

Hi all, I'm suffering an issue while trying to show validate a JSON file. The below are my model, schema, and script files.

Here is my TS interface file (model.ts)

export interface Model {
	readonly defaultRowAction?: DefaultRowAction;
}

export interface DefaultRowAction {
	readonly custom: boolean;
	readonly event: string;
}

The schema is generated by ts-json-schema-generator package (schema.json)

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/Model",
  "definitions": {
    "Model": {
      "type": "object",
      "properties": {
        "defaultRowAction": {
          "$ref": "#/definitions/DefaultRowAction"
        }
      },
      "additionalProperties": false
    },
    "DefaultRowAction": {
      "type": "object",
      "properties": {
        "custom": {
          "type": "boolean"
        },
        "event": {
          "type": "string"
        }
      },
      "required": [
        "custom",
        "event"
      ],
      "additionalProperties": false
    }
  }
}

My testing JSON file (model.json):

{
  "defaultRowAction" : {
    "custom" : false
  }
}

The scripting (index.js):

const Ajv = require("ajv");
const betterAjvErrors = require("better-ajv-errors");

const model = require("./model.json");
const schema = require("./schema.json");

const isValid = new Ajv().compile(schema);
if (!isValid(model)) {
	console.log(betterAjvErrors(schema, model, isValid.errors));
}

The output errors:

node index.js
PATH/node_modules/better-ajv-errors/lib/modern/helpers.js:26
    const paths = dataPath === '' ? [''] : dataPath.match(JSON_POINTERS_REGEX);
                                                    ^

TypeError: Cannot read property 'match' of undefined
    at PATH/node_modules/better-ajv-errors/lib/modern/helpers.js:26:53
    at Array.forEach (<anonymous>)
    at makeTree (PATH/node_modules/better-ajv-errors/lib/modern/helpers.js:21:13)
    at _default (PATH/node_modules/better-ajv-errors/lib/modern/helpers.js:116:16)
    at _default (PATH/node_modules/better-ajv-errors/lib/modern/index.js:27:45)
    at Object.<anonymous> (PATH/scripts/index.js:9:14)
    at Module._compile (internal/modules/cjs/loader.js:1068:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
    at Module.load (internal/modules/cjs/loader.js:933:32)
    at Function.Module._load (internal/modules/cjs/loader.js:774:14)

The environment and package versions:

MacOS darwin x86_64
Node: 14.17.0
Npm: 6.14.13
ajv: 8.6.2
better-ajv-errors: 0.7.0
ts-json-schema-generator: 0.95.0

Return mode should show column number for non-changed string

Curently return mode JSON.stringifies the incoming object plus adds new lines to it and final row/column are within stringified object. It would be great if the actual error position is calculated in original (stringified) document without new lines

Installation with npm (as per README) fails due to yarn dependency

npm WARN prepublish-on-install As of npm@5, `prepublish` scripts are deprecated.
npm WARN prepublish-on-install Use `prepare` for build steps and `prepublishOnly` for upload-only.
npm WARN prepublish-on-install See the deprecation note in `npm help scripts` for more information.

> [email protected] prepublish /home/mike/nodejs/better-ajv-errors
> yarn build

sh: 1: yarn: not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! [email protected] prepublish: `yarn build`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the [email protected] prepublish script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/mike/.npm/_logs/2019-01-04T08_51_41_056Z-debug.log

It appears build can be run with npx babel -f .babelrc

Don't run levenshtein if value in data is empty

ENUM should be equal to one of the allowed values
(wrap-right, center, wrap-left, wide, full-width)

 3β”‚   "type": "doc",
 4β”‚   "content": [
 5β”‚     {
 6β”‚       "type": "mediaSingle",
 7β”‚       "attrs": {
 8β”‚         "layout": ""
  〉
  〉         ☝🏽  Did you mean wide here?
  〉
 9β”‚       },
10β”‚       "content": [
11β”‚         {
12β”‚           "type": "media",
13β”‚           "attrs": {

Implement support for oneOf

Here is my schema:

{
"oneOf": [
        {
            "properties": {
                "target": { "$ref": "#/definitions/target" }
            },
            "required": ["target"]
        },
        {
            "properties": {
                "sql": { "$ref": "#/definitions/sql" }
            },
            "required": ["sql"]
        },
    ]
}

If my input has neither sql nor target, the error output is the following:

[{"start":{"line":1,"column":1,"offset":0},"error":" should have required property 'sql'","path":""}]

For the reference, here is the error output from Ajv:

[{"keyword":"required","dataPath":"","schemaPath":"#/oneOf/0/required","params":{"missingProperty":"target"},"message":"should have required property 'target'"},{"keyword":"required","dataPath":"","schemaPath":"#/oneOf/1/required","params":{"missingProperty":"sql"},"message":"should have required property 'sql'"},{"keyword":"oneOf","dataPath":"","schemaPath":"#/oneOf","params":{"passingSchemas":null},"message":"should match exactly one schema in oneOf"}]

I was expecting something like:

[{"start":{"line":1,"column":1,"offset":0},"error":" must have either 'sql' or 'target'","path":""}]

Import fails for ESM

I am unable to use better-ajv-errors >= 1.0.0 from an ESM project. I have attempted the import on Node 12 and 16 and both fail in the same manner. I checked and the "type" property is not set in the package.json which causes the initial error, but even when set, the import fails due to the lack of file extensions on the imports in the "esm" directory of the module.

I use ESM import exclusively in the project I am working on and have not encountered this with another NPM Module.

(node:41937) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)

/Users/aaron/Scitara/Projects/services/node_modules/better-ajv-errors/lib/esm/index.js:1
import { parse } from "@humanwhocodes/momoa";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1031:15)
    at Module._compile (node:internal/modules/cjs/loader:1065:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:190:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15)
    at async formattedImport (/Users/aaron/Scitara/Projects/services/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
    at async Object.exports.requireOrImport (/Users/aaron/Scitara/Projects/services/node_modules/mocha/lib/nodejs/esm-utils.js:48:32)
    at async Object.exports.loadFilesAsync (/Users/aaron/Scitara/Projects/services/node_modules/mocha/lib/nodejs/esm-utils.js:88:20)
    at async singleRun (/Users/aaron/Scitara/Projects/services/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at async Object.exports.handler (/Users/aaron/Scitara/Projects/services/node_modules/mocha/lib/cli/run.js:374:5)

Compatibility with fastify

This is an amazing library and I had been using it in my CLI applications, however does anyone know how to use this within a fastify application?

What is the status of this project? Is it being actively maintained?

Hi @torifat,

first of all a big thanks for this useful library. We've been using it in some business projects together with AJV and it was very handy for us.

I've seen that the last release was quite a while ago und that there are some pending PRs. So I wanted to check in on the state of the project.

  • Can we assume that there is active maintenance for this lib?
  • If you personally cannot continue, will there be any other Atlassian dev which carries on the support?
  • Can we get "relatively short term" fixes to support AJV in v8?

Thanks in advance for your answer.

All the best,
Robert

AJV Version 8.0.5 TypeError: Cannot read property 'match' of undefined

AJV Version 8.0.5

Repro:

import * as schema from "./validation.schema.json";
import Ajv, { Options } from "ajv";
import betterAjvErrors from "better-ajv-errors";
import { ISchema, schemas } from "./SchemaDefinition";

const validator = new Ajv({ jsonPointers: true } as Options);
validator.compile(schema);

export const validatePacket = <T extends keyof typeof schemas>(
    data: unknown,
    schemaKeyRef: T
): data is ISchema[T] => {
    validator.validate(schemaKeyRef as string, data);
    if (validator.errors) {
        try {
            const output = betterAjvErrors(schema, data, validator.errors);
            console.log(output);
        } catch (e) {
            console.log(e);
        }
    }
    return Boolean(validator.errors) === false;
};
TypeError: Cannot read property 'match' of undefined
    at /app/node_modules/better-ajv-errors/lib/modern/helpers.js:26:53
    at Array.forEach (<anonymous>)
    at makeTree (/app/node_modules/better-ajv-errors/lib/modern/helpers.js:21:13)
    at _default (/app/node_modules/better-ajv-errors/lib/modern/helpers.js:116:16)
    at Object._default [as default] (/app/node_modules/better-ajv-errors/lib/modern/index.js:27:45)

Misleading error when describing deeply nested `anyOf` failure

See minimal, verifiable test case, below.

Briefly, the case below is failing due to the type of the defaultConfigPath property being incorrect (boolean instead of string).

Expected Result:

I would expect to see an error message along the lines of "'defaultConfigPath' must be a string, not a boolean" in this case. Or at least an error that summarizes the errors for each of the anyOf item failure conditions.

Actual Result:

BAE describes the error for the second anyOf condition, but not the first:

CleanShot 2022-06-24 at 16 31 06@2x

Editorial:

If BAE has to choose just one of many errors passed to it, would it make sense to select error with the deepest schemaPath? Or maybe instancePath? Intuition tells me that the "deeper" an error is within a data structure, the more likely it is to be something the user can meaningfully act upon.

[
  {
    //  This is the error I would most expect/like to see in this case
    instancePath: '/processor/defaultConfigPath',
    schemaPath: '#/properties/processor/anyOf/0/properties/defaultConfigPath/type',
    keyword: 'type',
    params: { type: 'string' },
    message: 'must be string'
  },
  {
    // This error, while technically correct, isn't all that relevant since the data doesn't
    // match any properties in this sub-schema
    instancePath: '/processor',
    schemaPath: '#/properties/processor/anyOf/1/required',
    keyword: 'required',
    params: { missingProperty: 'defaultConfigPackageKey' },
    message: "must have required property 'defaultConfigPackageKey'"
  },
  {
    // This error is least likely to be meaningful.  And fixing one of the above errors will fix this error. 
    instancePath: '/processor',
    schemaPath: '#/properties/processor/anyOf',
    keyword: 'anyOf',
    params: {},
    message: 'must match a schema in anyOf'
  }
]

Minimal, stand-alone test case

#!/usr/bin/env node

import Ajv from 'ajv';
import betterAjvErrors from 'better-ajv-errors';

const SCHEMA = {
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
  properties: {
    processor: {
      anyOf: [
        {
          additionalProperties: false,
          type: 'object',
          properties: {
            defaultConfig: {
              type: 'object',
              properties: {},
              additionalProperties: true
            },
            defaultConfigPath: {
              type: 'string'
            }
          },
          required: ['defaultConfigPath']
        },
        {
          additionalProperties: false,
          type: 'object',
          properties: {
            defaultConfigPackageKey: {
              type: 'string'
            }
          },
          required: ['defaultConfigPackageKey']
        }
      ]
    }
  }
};

const DATA_TO_VALIDATE = `{
  "stuff": "... we don't care about",
  "processor":{
    "defaultConfigPath": true
  }
}`;

const validate = new Ajv().compile(SCHEMA)

const data = JSON.parse(DATA_TO_VALIDATE);
if (!validate(data) && validate.errors) {
  console.log(
    betterAjvErrors(validate.schema, data, validate.errors, { json: DATA_TO_VALIDATE })
  );
}

Add YAML support

First off, thanks for this polished library.

Since YAML is compatible with JSON, it would be nice if there was an option to use YAML for the error visualization, i.e. instead of this:

  4 |   "content": [
  5 |     {
> 6 |       "type": "paragarph",
    |               ^^^^^^^^^^^
  7 |       "content": [
  8 |         {
  9 |           "type": "text",

Show this:

  4 |   content:
> 5 |     - type: paragarph
    |             ^^^^^^^^^
  6 |       content:
  7 |         - type: text

Errors with different path got overwritten

When there are errors of more than one different paths in ajv error list, the helpers.makeTree function will overwrite the previous errors in the path with the new one in the reduce function:

paths &&
      paths.reduce((obj, path, i) => {
        obj.children[path] = obj.children[path] || { children: {}, errors: [] };
        if (i === paths.length - 1) {
          obj.children[path].errors.push(ajvError);
        }
        return obj.children[path];
      }, root);

Is this an intended design?

Issue:- process is not defined

Hello Team.
Please help

1st issue
TS Error
Object literal may only specify known properties, and 'jsonPointers' does not exist in type 'Options'

2nd issue
ReferenceError: process is not defined
at eval (index.js?9eb4:8)
at ./node_modules/@babel/highlight/node_modules/chalk/index.js (main.js:74)

Code:-
import betterAjvErrors from '@sidvind/better-ajv-errors';
const ajv = new Ajv({ jsonPointers: true });
const validate = ajv.compile(schema);
validate(schemaObject);
const errors = validate.errors;
console.log('better errors', betterAjvErrors(schema, schemaObject, errors));

"split of undefined" at import

Hello,

I got a "split of undefined" at import, without doing anything else, locally (snowpack) and on codesandbox (parcel):

Reproducible here :
https://codesandbox.io/s/flamboyant-star-j26ye?file=/src/index.js

Works ( removed better-ajv-errors )

import "./styles.css";
import Ajv from 'ajv';
// import betterAjvErrors from 'better-ajv-errors';
const ajv = new Ajv({ jsonPointers: true });
const validate = ajv.compile({type:'number'});
const valid = validate(2);
document.getElementById("app").innerHTML = `
 N errors : ${ valid?0:valid.errors.length}
`;

Does not work

import "./styles.css";
import Ajv from 'ajv';
import betterAjvErrors from 'better-ajv-errors';
const ajv = new Ajv({ jsonPointers: true });
const validate = ajv.compile({type:'number'});
const valid = validate(2);
document.getElementById("app").innerHTML = `
 N errors : ${ valid?0:valid.errors.length}
`;

Error:
image

Have a nice day !

Missing end-position in error-object

the start.line and start.column were included. The end.properties not.
the schemaPath-prop was eaten too ?

The option format='js'seems to be quite unusable ?

More readable errors for patterns

Hi,

I'm struggling with patterns usage and proper error display.

I would like to validate a range of number values, something like 1024-2048, and I have a pattern to express allowed number values (values between 1024 and 49151) :
pattern: "^(102[4-9]|10[3-9][0-9]|1[1-9][0-9]{2}|[2-9][0-9]{3}|[1-3][0-9]{4}|4[0-8][0-9]{3}|490[0-9]{2}|491[0-4][0-9]|4915[01])-(102[4-9]|10[3-9][0-9]|1[1-9][0-9]{2}|[2-9][0-9]{3}|[1-3][0-9]{4}|4[0-8][0-9]{3}|490[0-9]{2}|491[0-4][0-9]|4915[01])$"

But the output for user is displayed as:

07:43:09.693Z - error: PATTERN should match pattern "^(102[4-9]|10[3-9][0-9]|1[1-9][0-9]{2}|[2-9][0-9]{3}|[1-3][0-9]{4}|4[0-8][0-9]{3}|490[0-9]{2}|491[0-4][0-9]|4915[01])-(102[4-9]|10[3-9][0-9]|1[1-9][0-9]{2}|[2-9][0-9]{3}|[1-3][0-9]{4}|4[0-8][0-9]{3}|490[0-9]{2}|491[0-4][0-9]|4915[01])$"
> 4 |   "ports": "3000-302"

which is valid, but not readable to understand what is a valid input.

I would like to know if there is a way to force a message when an error occurs, for instance to use a description instead of the pattern value, or if any other mechanism exists to provide a more readable output without the need to put logic from error report ?

Thanks for your help !

Tests are failing

Hi,

I tried to run the unit tests and they fail on both Linux and Windows.

Is this a known issue?

Doesn't work for this case

{
  "type": "doc",
  "content": [
    {
      "type": "table",
      "content": [
        {
          "type": "tableRow",
          "content": [
            {
              "type": "tableCell",
              "content": []
            }
          ]
        }
      ]
    }
  ],
  "version": 1
}
[ { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'additionalProperties',
    dataPath: '/content/0',
    schemaPath: '#/definitions/rule_node/additionalProperties',
    params: { additionalProperty: 'content' },
    message: 'should NOT have additional properties' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/content/0/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'minItems',
    dataPath: '/content/0/content/0/content/0/content',
    schemaPath: '#/minItems',
    params: { limit: 1 },
    message: 'should NOT have less than 1 items' },
  { keyword: 'anyOf',
    dataPath: '/content/0/content/0/content',
    schemaPath: '#/properties/content/anyOf',
    params: {},
    message: 'should match some schema in anyOf' },
  { keyword: 'additionalProperties',
    dataPath: '/content/0',
    schemaPath: '#/definitions/applicationCard_node/additionalProperties',
    params: { additionalProperty: 'content' },
    message: 'should NOT have additional properties' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'additionalProperties',
    dataPath: '/content/0',
    schemaPath: '#/definitions/extension_node/additionalProperties',
    params: { additionalProperty: 'content' },
    message: 'should NOT have additional properties' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'enum',
    dataPath: '/content/0/type',
    schemaPath: '#/properties/type/enum',
    params: { allowedValues: [Array] },
    message: 'should be equal to one of the allowed values' },
  { keyword: 'anyOf',
    dataPath: '/content/0',
    schemaPath: '#/items/anyOf',
    params: {},
    message: 'should match some schema in anyOf' } ]

Consider making it compatible with browsers

Hi, I like this package a lot but I've seen there are many dependencies that while they may be compatible with a browser through Browserify or similar, it makes the package unnecessarily big for such environment.

Have you considered making a lightweight browser-compatible version?

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update actions/setup-node action to v4
  • chore(deps): update codecov/codecov-action action to v4
  • chore(deps): update dependency eslint to v9
  • chore(deps): update dependency eslint-plugin-jest to v28
  • chore(deps): update dependency husky to v9
  • chore(deps): update github/codeql-action action to v3
  • πŸ” Create all rate-limited PRs at once πŸ”

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/codeql-analysis.yml
  • actions/checkout v3
  • github/codeql-action v2
  • github/codeql-action v2
  • github/codeql-action v2
.github/workflows/dependabot.yml
  • actions/checkout v3
  • actions/setup-node v3
.github/workflows/main.yml
  • actions/checkout v3
  • actions/setup-node v3
  • codecov/codecov-action v3
  • actions/checkout v3
  • actions/setup-node v3
.github/workflows/release.yml
  • actions/checkout v3
  • actions/setup-node v3
npm
package.json
  • @babel/code-frame ^7.16.0
  • @humanwhocodes/momoa ^2.0.2
  • jsonpointer ^5.0.0
  • @changesets/cli ^2.18.1
  • @changesets/write ^0.1.6
  • ajv ^8.8.2
  • esbuild ^0.14.0
  • esbuild-jest ^0.5.0
  • eslint ^8.3.0
  • eslint-config-prettier ^8.3.0
  • eslint-plugin-jest ^26.0.0
  • eslint-plugin-prettier ^4.0.0
  • fast-glob ^3.2.7
  • flow-bin ^0.176.0
  • git-format-staged ^3.0.0
  • husky ^7.0.0
  • is-ci ^3.0.1
  • jest ^28.0.0
  • jest-fixtures ^0.6.0
  • prettier ^2.5.0
  • svg-term-cli ^2.1.1
  • tsd ^0.20.0
  • ajv 4.11.8 - 8
  • node >= 12.13.0

  • Check this box to trigger a request for Renovate to run again on this repository

Missing dependency: babel-runtime ?

lib/legacy/index.js requires babel-runtime/core-js/json/stringify but babel-runtime is not listed as a direct dependency in package.json meaning packages using this package fail.

Showing wrong error for missing property

Schema

{
  "type": "object",
  "properties": {
    "type": { "enum": ["mediaSingle"] },
    "content": {
      "type": "array",
      "items": { "$ref": "#/definitions/media_node" },
      "minItems": 1,
      "maxItems": 1
    },
    "attrs": {
      "type": "object",
      "properties": {
        "layout": {
          "enum": ["wrap-right", "center", "wrap-left", "wide", "full-width"]
        }
      },
      "required": ["layout"],
      "additionalProperties": false
    }
  },
  "required": ["type", "content", "attrs"],
  "additionalProperties": false
}

Data

{
  "version": 1,
  "type": "doc",
  "content": [
    {
      "type": "mediaSingle",
      "content": [
        {
          "type": "media",
          "attrs": {
            "type": "file",
            "id": "1234",
            "collection": "SampleCollection"
          }
        }
      ]
    }
  ]
}
ENUM should be equal to one of the allowed values
(panel, paragraph, blockquote, orderedList, bulletList, heading, mediaGroup, table, decisionList, taskList, bodiedExtension, codeBlock)

 1β”‚ {
 2β”‚   "version": 1,
 3β”‚   "type": "doc",
 4β”‚   "content": [
 5β”‚     {
 6β”‚       "type": "mediaSingle",
  〉
  〉       ☝🏽  Unexpected value here
  〉
 7β”‚       "content": [
 8β”‚         {
 9β”‚           "type": "media",
10β”‚           "attrs": {
11β”‚             "type": "file",

Export ES6 modules

This is actually not an issue, but a feature request:
Currently, you're exporting CJS modules plus Typescript's specific "export equals" syntax in the type definition. You're shipping two flavors (legacy and modern) already, but babel turns your ES6 exports (in ./src) to CJS exports in ./dist/modern. Otherwise, I'd suggest adding a note to the Readme that you'd need to activate the esModuleInterop Typescript flag.

I'm happy to contribute a PR if you want.

Emoji's are not displayed properly in all terminals

e.g. Hyper on Windows can't properly display emoji by default. It would be nice to have the option to disable full utf8 output or provide custom 'icon' characters to use instead of the default emoji.

image

Would love to make a PR for this, if this is something you'd like to have as part of this lib.

Localization

Was glancing around and didn't notice support for localization.

Did I overlook it or are there plans to add support for localization in the future?

P.S. Thanks for all the work you put into this =)

Show actual incorrect constant rather than "const must be equal to constant"

I know we are using the raw message and just passing it along:

engines: {
  type: 'object',
  properties: {
    node: {
      const: '>=18.12.0',
    },
  },
  required: ['node'],
},
  33 |   "engines": {
> 34 |     "node": ">=18.12.1"
     |             ^^^^^^^^^^^ πŸ‘ˆπŸ½  const must be equal to constant
  35 |   },

but I wonder if we could do better. We already know the constant value from the schema, could we not include that in the error message? Or is that outside the scope of this project?

Misleading information example

Example input:

{
  "version": 1,
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "test"
        }
      ]
    },
    {
      "type": "mediaSingle",
      "attrs": {
        "layout": "wide"
      },
      "content": [
        {
          "type": "media",
          "attrs": {
            "id": "cfb55f7b-68be-42ac-9930-216f754805a1",
            "type": "file",
            "collection": "",
            "occurrenceKey": null,
            "width": null
          }
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": " "
        }
      ]
    }
  ]
}

and the error message is

{
    "message": "Document field document JSON doesn't comply with Atlassian Document Format Full",
    "meta": {
        "errors": [
            {
                "start": {
                    "line": 1,
                    "column": 109,
                    "offset": 108
                },
                "end": {
                    "line": 1,
                    "column": 122,
                    "offset": 121
                },
                "error": "/content/1/type should be equal to one of the allowed values: orderedList, heading, panel, table, decisionList, taskList, bodiedExtension, codeBlock",
                "suggestion": "Did you mean heading?"
            }
        ]
    },
    "status": 400
}

But the error was actually inside the mediaNode under mediaSingle.

Integration with ajv-errors (or otherwise support custom error messages)

I am an owner of the MDN browser-compat-data project, and we use ajv with better-ajv-errors. As indicated in mdn/browser-compat-data#3256, we are wanting to use ajv-errors for custom errors to better represent the situation where a subfeature contains invalid characters (which is caught by additionalProperties: false). Doing a quick experiment, however, I found that it seems that better-ajv-errors doesn't get along with ajv-errors. It seems that ajv-errors replaces the error type for some odd reason.

It would be really wonderful to see support included so we can use both at the same time. Happy to spend time to do this one!

Feature: Option to include data path in CLI output

Data paths are great when working with big, repeating or complex responses, but at the moment these paths are not included in the CLI output. It would also be very useful if you don't have the indent option set.

I'd like to have an option to enable data path output in the CLI mode. It might look something like.

const output = betterAjvErrors(schema, response.body, ajv.errors, {
    indent: 2,
    dataPath: true,
});
console.log(output);
     Error: FORMAT should match format "date-time"

   5 |         "foo": "624050509",
   6 |         "bar": "04",
>  7 |         "baz": "not-a-date-time",
     |                ^^^^^^^^^^^^^^^^^ πŸ‘ˆπŸ½  format should match format "date-time"
   8 |         "lorum": "@",
   9 |         "ipsum": "some string",
  10 |         "razz": 100797.51,

     @ /a/long/path/9/with/2/big/21/arrays/baz

And sure, the example above is a really extreme example, and if your API looks like this you have bigger problems. But these things exist in the wild, so I'd like to at least be able to test them with some ease. This feature would contribute to this.

I'm willing to implement this myself if someone can tell me where to start :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.