Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow integer in number subschema with strictTypes #1938

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/compile/validate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ function checkContextTypes(it: SchemaObjCxt, types: JSONType[]): void {
strictTypesError(it, `type "${t}" not allowed by context "${it.dataTypes.join(",")}"`)
}
})
it.dataTypes = it.dataTypes.filter((t) => includesType(types, t))
it.dataTypes = it.dataTypes.filter((t) => includesType([...types, "number"], t))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this is the offending line, just not sure if this is the optimal solution.

In my example from the issue, it.dataTypes === ['number'] and types === ['integer']

The existing logic would filter dataTypes down to an empty array, then throw on error on keywords like maximum without a type.

It is filtered because includesType does not detect any overlap, and would (by intentional design) only allow number in the base type.

includesType(['number'], 'integer') === true
includesType(['integer'], 'number') === false

My solution is to simply append number to the type array, to effectively allow the second case to be true as well.

Intuitively it seems like an overly broad solution, as number is not a valid type for every other type, and we still want to prevent number inside an integer.

However the lines just before this are performing that validation/filtering, so I'm pretty sure at this point both type arrays are are length <= 1.

If there is a better way to write this, or perhaps another way to attack this let me know!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's indeed more tricky than that... updated!

}

function checkMultipleTypes(it: SchemaObjCxt, ts: JSONType[]): void {
Expand Down
103 changes: 103 additions & 0 deletions spec/issues/1935_integer_narrowing_subschema.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import _Ajv from "../ajv"
import Ajv from "ajv"

describe("issue 1935: integer valid type in number sub-schema", () => {
let ajv: Ajv
before(() => {
ajv = new _Ajv({strict: true})
})

it("should allow integer in `if`", () => {
ajv.compile({
type: "number",
if: {
type: "integer",
maximum: 5,
},
else: {
minimum: 10,
},
})
})

it("should allow integer in `then`", () => {
ajv.compile({
type: "number",
if: {
multipleOf: 2,
},
then: {
type: "integer",
minimum: 10,
},
})
})

it("should allow integer in `else`", () => {
ajv.compile({
type: "number",
if: {
maximum: 5,
},
else: {
type: "integer",
minimum: 10,
},
})
})

it("should allow integer in `allOf`", () => {
ajv.compile({
type: "number",
allOf: [
{
type: "integer",
minimum: 10,
},
{
multipleOf: 2,
},
],
})
})

it("should allow integer in `oneOf`", () => {
ajv.compile({
type: "number",
oneOf: [
{
type: "integer",
minimum: 10,
},
{
multipleOf: 2,
},
],
})
})

it("should allow integer in `anyOf`", () => {
ajv.compile({
type: "number",
oneOf: [
{
type: "integer",
minimum: 10,
},
{
multipleOf: 2,
},
],
})
})

it("should allow integer in `not`", () => {
ajv.compile({
type: "number",
not: {
type: "integer",
minimum: 10,
},
})
})
})