Skip to content

Commit

Permalink
Merge branch 'master' into docs-additionalItems-clarification
Browse files Browse the repository at this point in the history
  • Loading branch information
jasoniangreen authored Jun 19, 2024
2 parents df756d1 + 8bccdc4 commit c2e6c10
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 23 deletions.
4 changes: 2 additions & 2 deletions docs/json-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ The value of the keyword should be a number. The data to be valid should be a mu

### `maxLength` / `minLength`

::: warning [Grapheme clusters](https://www.unicode.org/reports/tr29/tr29-17.html#Grapheme_Cluster_Boundaries) will count as multiple characters
Certain charsets have characters that are made up of multiple unicode characters. These "grapheme clusters" are counted as multiple characters.
::: warning Grapheme clusters will count as multiple characters
Certain charsets have characters that are made up of multiple Unicode code points. These [grapheme clusters](https://www.unicode.org/reports/tr29/tr29-17.html#Grapheme_Cluster_Boundaries) are counted as multiple in length calculations.
:::

The value of the keywords should be a number. The data to be valid should have length satisfying this rule. Unicode pairs are counted as a single character.
Expand Down
2 changes: 1 addition & 1 deletion docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ Include human-readable messages in errors. `true` by default. `false` can be pas

### uriResolver

By default `uriResolver` is undefined and relies on the embedded uriResolver [uri-js](https://github.com/garycourt/uri-js). Pass an object that satisfies the interface [UriResolver](https://github.com/ajv-validator/ajv/blob/master/lib/types/index.ts) to be used in replacement. One alternative is [fast-uri](https://github.com/fastify/fast-uri).
By default `uriResolver` is undefined and relies on the embedded uriResolver [fast-uri](https://github.com/fastify/fast-uri). Pass an object that satisfies the interface [UriResolver](https://github.com/ajv-validator/ajv/blob/master/lib/types/index.ts) to be used in replacement. One alternative is [uri-js](https://github.com/garycourt/uri-js).

### code <Badge text="v7" />

Expand Down
4 changes: 2 additions & 2 deletions docs/strict-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ By default Ajv fails schema compilation when unknown keywords are used. Users ca
ajv.addKeyword("allowedKeyword")
```

or
or use the convenience method `addVocabulary` for multiple keywords

```javascript
ajv.addVocabulary(["allowed1", "allowed2"])
ajv.addVocabulary(["allowed1", "allowed2"]) // simply calls addKeyword multiple times
```

#### Ignored "additionalItems" keyword
Expand Down
1 change: 1 addition & 0 deletions lib/compile/codegen/code.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export abstract class _CodeOrName {
abstract readonly str: string
abstract readonly names: UsedNames
Expand Down
4 changes: 2 additions & 2 deletions lib/compile/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import N from "./names"
import {LocalRefs, getFullPath, _getFullPath, inlineRef, normalizeId, resolveUrl} from "./resolve"
import {schemaHasRulesButRef, unescapeFragment} from "./util"
import {validateFunctionCode} from "./validate"
import * as URI from "uri-js"
import {URIComponent} from "fast-uri"
import {JSONType} from "./rules"

export type SchemaRefs = {
Expand Down Expand Up @@ -295,7 +295,7 @@ const PREVENT_SCOPE_CHANGE = new Set([

function getJsonPointer(
this: Ajv,
parsedRef: URI.URIComponents,
parsedRef: URIComponent,
{baseId, schema, root}: SchemaEnv
): SchemaEnv | undefined {
if (parsedRef.fragment?.[0] !== "/") return
Expand Down
4 changes: 2 additions & 2 deletions lib/compile/resolve.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {AnySchema, AnySchemaObject, UriResolver} from "../types"
import type Ajv from "../ajv"
import type {URIComponents} from "uri-js"
import type {URIComponent} from "fast-uri"
import {eachItem} from "./util"
import * as equal from "fast-deep-equal"
import * as traverse from "json-schema-traverse"
Expand Down Expand Up @@ -73,7 +73,7 @@ export function getFullPath(resolver: UriResolver, id = "", normalize?: boolean)
return _getFullPath(resolver, p)
}

export function _getFullPath(resolver: UriResolver, p: URIComponents): string {
export function _getFullPath(resolver: UriResolver, p: URIComponent): string {
const serialized = resolver.serialize(p)
return serialized.split("#")[0] + "#"
}
Expand Down
2 changes: 1 addition & 1 deletion lib/runtime/uri.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as uri from "uri-js"
import * as uri from "fast-uri"

type URI = typeof uri & {code: string}
;(uri as URI).code = 'require("ajv/dist/runtime/uri").default'
Expand Down
6 changes: 3 additions & 3 deletions lib/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as URI from "uri-js"
import {URIComponent} from "fast-uri"
import type {CodeGen, Code, Name, ScopeValueSets, ValueScopeName} from "../compile/codegen"
import type {SchemaEnv, SchemaCxt, SchemaObjCxt} from "../compile"
import type {JSONType} from "../compile/rules"
Expand Down Expand Up @@ -238,7 +238,7 @@ export interface RegExpLike {
}

export interface UriResolver {
parse(uri: string): URI.URIComponents
parse(uri: string): URIComponent
resolve(base: string, path: string): string
serialize(component: URI.URIComponents): string
serialize(component: URIComponent): string
}
5 changes: 4 additions & 1 deletion lib/vocabularies/discriminator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {KeywordCxt} from "../../compile/validate"
import {_, getProperty, Name} from "../../compile/codegen"
import {DiscrError, DiscrErrorObj} from "../discriminator/types"
import {resolveRef, SchemaEnv} from "../../compile"
import MissingRefError from "../../compile/ref_error"
import {schemaHasRulesButRef} from "../../compile/util"

export type DiscriminatorError = DiscrErrorObj<DiscrError.Tag> | DiscrErrorObj<DiscrError.Mapping>
Expand Down Expand Up @@ -66,8 +67,10 @@ const def: CodeKeywordDefinition = {
for (let i = 0; i < oneOf.length; i++) {
let sch = oneOf[i]
if (sch?.$ref && !schemaHasRulesButRef(sch, it.self.RULES)) {
sch = resolveRef.call(it.self, it.schemaEnv.root, it.baseId, sch?.$ref)
const ref = sch.$ref
sch = resolveRef.call(it.self, it.schemaEnv.root, it.baseId, ref)
if (sch instanceof SchemaEnv) sch = sch.schema
if (sch === undefined) throw new MissingRefError(it.opts.uriResolver, it.baseId, ref)
}
const propSch = sch?.properties?.[tagName]
if (typeof propSch != "object") {
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ajv",
"version": "8.13.0",
"version": "8.16.0",
"description": "Another JSON Schema Validator",
"main": "dist/ajv.js",
"types": "dist/ajv.d.ts",
Expand Down Expand Up @@ -59,9 +59,9 @@
"runkitExampleFilename": ".runkit_example.js",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^2.4.0",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.4.1"
"require-from-string": "^2.0.2"
},
"devDependencies": {
"@ajv-validator/config": "^0.5.0",
Expand All @@ -83,7 +83,6 @@
"dayjs-plugin-utc": "^0.1.2",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"fast-uri": "^2.3.0",
"glob": "^10.3.10",
"husky": "^9.0.11",
"if-node-version": "^1.1.1",
Expand All @@ -104,7 +103,8 @@
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.9.2",
"tsify": "^5.0.4",
"typescript": "5.3.3"
"typescript": "5.3.3",
"uri-js": "^4.4.1"
},
"collective": {
"type": "opencollective",
Expand Down
61 changes: 61 additions & 0 deletions spec/discriminator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,67 @@ describe("discriminator keyword", function () {
})
})

describe("schema with external $refs", () => {
const schemas = {
main: {
type: "object",
discriminator: {propertyName: "foo"},
required: ["foo"],
oneOf: [
{
$ref: "schema1",
},
{
$ref: "schema2",
},
],
},
schema1: {
type: "object",
properties: {
foo: {const: "x"},
},
},
schema2: {
type: "object",
properties: {
foo: {enum: ["y", "z"]},
},
},
}

const data = {foo: "x"}
const badData = {foo: "w"}

it("compile should resolve each $ref to a schema that was added with addSchema", () => {
const opts = {
discriminator: true,
}
const ajv = new _Ajv(opts)
ajv.addSchema(schemas.main, "https://host/main")
ajv.addSchema(schemas.schema1, "https://host/schema1")
ajv.addSchema(schemas.schema2, "https://host/schema2")

const validate = ajv.compile({$ref: "https://host/main"})
assert.strictEqual(validate(data), true)
assert.strictEqual(validate(badData), false)
})
it("compileAsync should loadSchema each $ref", async () => {
const opts = {
discriminator: true,
loadSchema(url) {
if (!url.startsWith("https://host/")) return undefined
const name = url.substring("https://host/".length)
return schemas[name]
},
}
const ajv = new _Ajv(opts)
const validate = await ajv.compileAsync({$ref: "https://host/main"})
assert.strictEqual(validate(data), true)
assert.strictEqual(validate(badData), false)
})
})

describe("validation with deeply referenced schemas", () => {
const schema = [
{
Expand Down
8 changes: 4 additions & 4 deletions spec/resolve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import _Ajv from "./ajv"
import type {AnyValidateFunction} from "../dist/types"
import type MissingRefError from "../dist/compile/ref_error"
import chai from "./chai"
import * as fastUri from "fast-uri"
import * as uriJs from "uri-js"
const should = chai.should()

const uriResolvers = [undefined, fastUri]
const uriResolvers = [undefined, uriJs]

uriResolvers.forEach((resolver) => {
let describeTitle: string
if (resolver !== undefined) {
describeTitle = "fast-uri resolver"
} else {
describeTitle = "uri-js resolver"
} else {
describeTitle = "fast-uri resolver"
}
describe(describeTitle, () => {
describe("resolve", () => {
Expand Down

0 comments on commit c2e6c10

Please sign in to comment.