diff --git a/package.json b/package.json index 1ac8acf..0e7b514 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "ajv": "^8.0.0", + "better-ajv-errors": "^0.7.0", "fast-json-patch": "^2.0.0", "glob": "^7.1.0", "js-yaml": "^3.14.0", diff --git a/src/commands/ajv.ts b/src/commands/ajv.ts index d06acb5..13609b4 100644 --- a/src/commands/ajv.ts +++ b/src/commands/ajv.ts @@ -84,7 +84,7 @@ export default function (argv: ParsedArgs): AjvCore { try { registerer = require("ts-node").register() - } catch (err) { + } catch (err: any) { /* istanbul ignore next */ if (err.code === "MODULE_NOT_FOUND") { throw new Error( diff --git a/src/commands/test.ts b/src/commands/test.ts index 87f95c8..fe64cd7 100644 --- a/src/commands/test.ts +++ b/src/commands/test.ts @@ -41,7 +41,7 @@ function execute(argv: ParsedArgs): boolean { const data = openFile(file, `data file ${file}`) const validData = validate(data) let errors - if (!validData) errors = logJSON(argv.errors, validate.errors, ajv) + if (!validData) errors = logJSON(argv.errors, validate.errors, ajv, data, argv.s) if (validData === shouldBeValid) { console.log(`${file} passed test`) diff --git a/src/commands/util.ts b/src/commands/util.ts index 42b4ed1..1a95b66 100644 --- a/src/commands/util.ts +++ b/src/commands/util.ts @@ -5,6 +5,7 @@ import * as fs from "fs" import * as yaml from "js-yaml" import * as JSON5 from "json5" import {AnyValidateFunction} from "ajv/dist/core" +import * as betterAjvErrors from "better-ajv-errors" export function getFiles(args: string | string[]): string[] { let files: string[] = [] @@ -51,7 +52,7 @@ export function openFile(filename: string, suffix: string): any { } catch (e) { json = require(file) } - } catch (err) { + } catch (err: any) { const msg: string = err.message console.error(`error: ${msg.replace(" module", " " + suffix)}`) process.exit(2) @@ -59,7 +60,7 @@ export function openFile(filename: string, suffix: string): any { return json } -export function logJSON(mode: string, data: any, ajv?: Ajv): string { +export function logJSON(mode: string, data: any, ajv?: Ajv, original?: any, schema?: any): string { switch (mode) { case "json": data = JSON.stringify(data, null, " ") @@ -72,6 +73,16 @@ export function logJSON(mode: string, data: any, ajv?: Ajv): string { break case "text": if (ajv) data = ajv.errorsText(data) + break + case "pretty": + if (original && schema) { + for (const error of data) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Workaround https://github.com/atlassian/better-ajv-errors/issues/90 + error.dataPath = error.instancePath + } + data = betterAjvErrors(JSON.stringify(schema), JSON.stringify(original), data) + } } return data } @@ -80,7 +91,7 @@ export function compile(ajv: Ajv, schemaFile: string): AnyValidateFunction { const schema = openFile(schemaFile, "schema") try { return ajv.compile(schema) - } catch (err) { + } catch (err: any) { console.error(`schema ${schemaFile} is invalid`) console.error(`error: ${err.message}`) process.exit(1) diff --git a/src/commands/validate.ts b/src/commands/validate.ts index 71788ab..21bc668 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -18,7 +18,7 @@ const cmd: Command = { r: {$ref: "#/$defs/stringOrArray"}, m: {$ref: "#/$defs/stringOrArray"}, c: {$ref: "#/$defs/stringOrArray"}, - errors: {enum: ["json", "line", "text", "js", "no"]}, + errors: {enum: ["json", "line", "text", "js", "no", "pretty"]}, changes: {enum: [true, "json", "line", "js"]}, spec: {enum: ["draft7", "draft2019", "draft2020", "jtd"]}, }, @@ -38,7 +38,7 @@ function execute(argv: ParsedArgs): boolean { function validateDataFile(file: string): boolean { const data = openFile(file, `data file ${file}`) let original - if (argv.changes) original = JSON.parse(JSON.stringify(data)) + if (argv.changes || argv.errors === "pretty") original = JSON.parse(JSON.stringify(data)) const validData = validate(data) as boolean if (validData) { @@ -54,7 +54,7 @@ function execute(argv: ParsedArgs): boolean { } } else { console.error(file, "invalid") - console.error(logJSON(argv.errors, validate.errors, ajv)) + console.error(logJSON(argv.errors, validate.errors, ajv, original, argv.s)) } return validData }