Skip to content

Commit

Permalink
ajv error object: rename dataPath -> instancePath (consistent with JTD)
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Mar 11, 2021
1 parent e3f729b commit 242631a
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 36 deletions.
6 changes: 3 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ The schemas compiled before the keyword is removed will continue to work without

Returns the text with all errors in a String.

Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that dataPaths are prefixed with, "data" by default).
Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that instancePath is prefixed with, "data" by default).

## Validation errors

Expand All @@ -336,14 +336,14 @@ Each error reported when validating against JSON Schema (also when validating ag
```typescript
interface ErrorObject {
keyword: string // validation keyword.
dataPath: string // JSON pointer to the part of the data that was validated (e.g., `"/prop/1/subProp"`).
instancePath: string // JSON pointer to the part of the data that was validated (e.g., `"/prop/1/subProp"`).
schemaPath: string // the path (JSON-pointer as a URI fragment) to the schema of the failing keyword.
// the object with the additional information about error that can be used to generate error messages
// (e.g., using [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package).
// See below for parameters set by all keywords.
params: object // type is defined by keyword value, see below
propertyName?: string // set for errors in `propertyNames` keyword schema.
// `dataPath` still points to the object in this case.
// `instancePath` still points to the object in this case.
message?: string // the standard error message (can be excluded with option `messages` set to false).
schema?: any // the schema of the keyword (added with `verbose` option).
parentSchema?: object // the schema containing the keyword (added with `verbose` option)
Expand Down
13 changes: 5 additions & 8 deletions lib/compile/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function extendErrors({
const err = gen.name("err")
gen.forRange("i", errsCount, N.errors, (i) => {
gen.const(err, _`${N.vErrors}[${i}]`)
gen.if(_`${err}.dataPath === undefined`, () =>
gen.assign(_`${err}.dataPath`, strConcat(N.dataPath, it.errorPath))
gen.if(_`${err}.instancePath === undefined`, () =>
gen.assign(_`${err}.instancePath`, strConcat(N.instancePath, it.errorPath))
)
gen.assign(_`${err}.schemaPath`, str`${it.errSchemaPath}/${keyword}`)
if (it.opts.verbose) {
Expand Down Expand Up @@ -115,8 +115,6 @@ const E = {
message: new Name("message"),
schema: new Name("schema"),
parentSchema: new Name("parentSchema"),
// JTD error properties
instancePath: new Name("instancePath"),
}

function errorObjectCode(
Expand Down Expand Up @@ -150,12 +148,11 @@ function errorObject(
return gen.object(...keyValues)
}

function errorDataPath({errorPath, opts}: SchemaCxt, {instancePath}: ErrorPaths): [Name, Code] {
const dataPathProp = opts.jtd && !opts.ajvErrors ? E.instancePath : N.dataPath
const dataPath = instancePath
function errorDataPath({errorPath}: SchemaCxt, {instancePath}: ErrorPaths): [Name, Code] {
const instPath = instancePath
? str`${errorPath}${getErrorPath(instancePath, Type.Str)}`
: errorPath
return [dataPathProp, strConcat(N.dataPath, dataPath)]
return [N.instancePath, strConcat(N.instancePath, instPath)]
}

function errorSchemaPath(
Expand Down
2 changes: 1 addition & 1 deletion lib/compile/names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const names = {
data: new Name("data"), // data passed to validation function
// args passed from referencing schema
valCxt: new Name("valCxt"), // validation/data context - should not be used directly, it is destructured to the names below
dataPath: new Name("dataPath"),
instancePath: new Name("instancePath"),
parentData: new Name("parentData"),
parentDataProperty: new Name("parentDataProperty"),
rootData: new Name("rootData"), // root data - same as the data passed to the first/top validation function
Expand Down
6 changes: 3 additions & 3 deletions lib/compile/validate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function validateFunction(
}

function destructureValCxt(opts: InstanceOptions): Code {
return _`{${N.dataPath}="", ${N.parentData}, ${N.parentDataProperty}, ${N.rootData}=${N.data}${
return _`{${N.instancePath}="", ${N.parentData}, ${N.parentDataProperty}, ${N.rootData}=${N.data}${
opts.dynamicRef ? _`, ${N.dynamicAnchors}={}` : nil
}}={}`
}
Expand All @@ -48,14 +48,14 @@ function destructureValCxtES5(gen: CodeGen, opts: InstanceOptions): void {
gen.if(
N.valCxt,
() => {
gen.var(N.dataPath, _`${N.valCxt}.${N.dataPath}`)
gen.var(N.instancePath, _`${N.valCxt}.${N.instancePath}`)
gen.var(N.parentData, _`${N.valCxt}.${N.parentData}`)
gen.var(N.parentDataProperty, _`${N.valCxt}.${N.parentDataProperty}`)
gen.var(N.rootData, _`${N.valCxt}.${N.rootData}`)
if (opts.dynamicRef) gen.var(N.dynamicAnchors, _`${N.valCxt}.${N.dynamicAnchors}`)
},
() => {
gen.var(N.dataPath, _`""`)
gen.var(N.instancePath, _`""`)
gen.var(N.parentData, _`undefined`)
gen.var(N.parentDataProperty, _`undefined`)
gen.var(N.rootData, N.data)
Expand Down
2 changes: 1 addition & 1 deletion lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ export default class Ajv {
): string {
if (!errors || errors.length === 0) return "No errors"
return errors
.map((e) => `${dataVar}${e.dataPath} ${e.message}`)
.map((e) => `${dataVar}${e.instancePath} ${e.message}`)
.reduce((text, msg) => text + separator + msg)
}

Expand Down
5 changes: 2 additions & 3 deletions lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface SourceCode {
}

export interface DataValidationCxt<T extends string | number = string | number> {
dataPath: string
instancePath: string
parentData: {[K in T]: any} // object or array
parentDataProperty: T // string or number
rootData: Record<string, any> | any[]
Expand Down Expand Up @@ -81,8 +81,7 @@ export type AnyValidateFunction<T = any> = ValidateFunction<T> | AsyncValidateFu

export interface ErrorObject<K extends string = string, P = Record<string, any>, S = unknown> {
keyword: K
dataPath: string
instancePath?: string
instancePath: string
schemaPath: string
params: P
// Added to validation errors of "propertyNames" keyword schema
Expand Down
2 changes: 1 addition & 1 deletion lib/vocabularies/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function callValidateCode(
): Code {
const dataAndSchema = passSchema ? _`${schemaCode}, ${data}, ${topSchemaRef}${schemaPath}` : data
const valCxt: [Name, Code | number][] = [
[N.dataPath, strConcat(N.dataPath, errorPath)],
[N.instancePath, strConcat(N.instancePath, errorPath)],
[N.parentData, it.parentData],
[N.parentDataProperty, it.parentDataProperty],
[N.rootData, N.rootData],
Expand Down
22 changes: 11 additions & 11 deletions spec/errors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe("Validation errors", () => {
})
}

it("error should include dataPath", () => {
it("error should include instancePath", () => {
const schema = {
properties: {
foo: {type: "number"},
Expand All @@ -38,7 +38,7 @@ describe("Validation errors", () => {
testSchema1(schema)
})

it('"refs" error should include dataPath', () => {
it('"refs" error should include instancePath', () => {
const schema = {
definitions: {
num: {type: "number"},
Expand All @@ -52,7 +52,7 @@ describe("Validation errors", () => {
})

describe('"additionalProperties" errors', () => {
it("should NOT include property in dataPath", () => {
it("should NOT include property in instancePath", () => {
testAdditional()
})

Expand Down Expand Up @@ -119,7 +119,7 @@ describe("Validation errors", () => {
})

describe('errors when "additionalProperties" is schema', () => {
it("should NOT include property in dataPath", () => {
it("should NOT include property in instancePath", () => {
testAdditionalIsSchema()
})

Expand Down Expand Up @@ -169,7 +169,7 @@ describe("Validation errors", () => {
})

describe('"required" errors', () => {
it("should NOT include missing property in dataPath", () => {
it("should NOT include missing property in instancePath", () => {
testRequired()
})

Expand Down Expand Up @@ -351,7 +351,7 @@ describe("Validation errors", () => {
})

describe('"dependencies" errors', () => {
it("should NOT include missing property in dataPath", () => {
it("should NOT include missing property in instancePath", () => {
testDependencies()
})

Expand Down Expand Up @@ -485,7 +485,7 @@ describe("Validation errors", () => {
return `should have required property '${prop}'`
}

it('"items" errors should include item index without quotes in dataPath (#48)', () => {
it('"items" errors should include item index without quotes in instancePath (#48)', () => {
const schema1 = {
$id: "schema1",
type: "array",
Expand Down Expand Up @@ -960,9 +960,9 @@ describe("Validation errors", () => {
testTypeError(0, _ajv.opts.jsPropertySyntax ? "[1]" : "/1")
if (expectedErrors === 2) testTypeError(1, _ajv.opts.jsPropertySyntax ? "[2]" : "/2")

function testTypeError(i, dataPath) {
function testTypeError(i, instancePath) {
const err = validate.errors?.[i]
shouldBeError(err, "type", "#/items/type", dataPath, "should be number")
shouldBeError(err, "type", "#/items/type", instancePath, "should be number")
}
})
})
Expand Down Expand Up @@ -1005,13 +1005,13 @@ describe("Validation errors", () => {
error,
keyword,
schemaPath,
dataPath,
instancePath,
message?: string,
params?: Record<string, any>
) {
error.keyword.should.equal(keyword)
error.schemaPath.should.equal(schemaPath)
error.dataPath.should.equal(dataPath)
error.instancePath.should.equal(instancePath)
error.message.should.be.a("string")
if (message !== undefined) error.message.should.equal(message)
if (params !== undefined) error.params.should.eql(params)
Expand Down
4 changes: 2 additions & 2 deletions spec/jtd-schema.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface JSONParseTestSuite {
}

interface JTDError {
instancePath?: string
instancePath: string
schemaPath: string
}

Expand Down Expand Up @@ -106,7 +106,7 @@ describe("JSON Type Definition", () => {
errors.sort(
(e1: JTDError, e2: JTDError) =>
e1.schemaPath.localeCompare(e2.schemaPath) ||
(e1.instancePath || "").localeCompare(e2.instancePath || "")
e1.instancePath.localeCompare(e2.instancePath)
)
}
return errors
Expand Down
6 changes: 3 additions & 3 deletions spec/keyword.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1006,13 +1006,13 @@ describe("User-defined keywords", () => {
})
}

function shouldBeRangeError(error, dataPath, schemaPath, comparison, limit, exclusive?: boolean) {
function shouldBeRangeError(error, instancePath, schemaPath, comparison, limit, exclusive?: boolean) {
delete error.schema
delete error.data
error.should.eql({
keyword: "x-range",
dataPath: dataPath,
schemaPath: schemaPath,
instancePath,
schemaPath,
message: "should be " + comparison + " " + limit,
params: {
comparison: comparison,
Expand Down

0 comments on commit 242631a

Please sign in to comment.